mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
@@ -116,9 +116,9 @@ ui32 CGHeroInstance::getTileMovementCost(const TerrainTile & dest, const Terrain
|
||||
return static_cast<ui32>(ret);
|
||||
}
|
||||
|
||||
FactionID CGHeroInstance::getFaction() const
|
||||
FactionID CGHeroInstance::getFactionID() const
|
||||
{
|
||||
return FactionID(type->heroClass->faction);
|
||||
return getHeroClass()->faction;
|
||||
}
|
||||
|
||||
const IBonusBearer* CGHeroInstance::getBonusBearer() const
|
||||
@@ -229,10 +229,10 @@ bool CGHeroInstance::canLearnSkill(const SecondarySkill & which) const
|
||||
if (getSecSkillLevel(which) > 0)
|
||||
return false;
|
||||
|
||||
if (type->heroClass->secSkillProbability.count(which) == 0)
|
||||
if (getHeroClass()->secSkillProbability.count(which) == 0)
|
||||
return false;
|
||||
|
||||
if (type->heroClass->secSkillProbability.at(which) == 0)
|
||||
if (getHeroClass()->secSkillProbability.at(which) == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -282,7 +282,6 @@ int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti)
|
||||
|
||||
CGHeroInstance::CGHeroInstance(IGameCallback * cb)
|
||||
: CArmedInstance(cb),
|
||||
type(nullptr),
|
||||
tacticFormationEnabled(false),
|
||||
inTownGarrison(false),
|
||||
moveDir(4),
|
||||
@@ -303,14 +302,30 @@ PlayerColor CGHeroInstance::getOwner() const
|
||||
return tempOwner;
|
||||
}
|
||||
|
||||
HeroTypeID CGHeroInstance::getHeroType() const
|
||||
const CHeroClass * CGHeroInstance::getHeroClass() const
|
||||
{
|
||||
return getHeroType()->heroClass;
|
||||
}
|
||||
|
||||
HeroClassID CGHeroInstance::getHeroClassID() const
|
||||
{
|
||||
return getHeroType()->heroClass->getId();
|
||||
}
|
||||
|
||||
const CHero * CGHeroInstance::getHeroType() const
|
||||
{
|
||||
return getHeroTypeID().toHeroType();
|
||||
}
|
||||
|
||||
HeroTypeID CGHeroInstance::getHeroTypeID() const
|
||||
{
|
||||
if (ID == Obj::RANDOM_HERO)
|
||||
return HeroTypeID::NONE;
|
||||
return HeroTypeID(getObjTypeIndex().getNum());
|
||||
}
|
||||
|
||||
void CGHeroInstance::setHeroType(HeroTypeID heroType)
|
||||
{
|
||||
assert(type == nullptr);
|
||||
subID = heroType;
|
||||
}
|
||||
|
||||
@@ -323,16 +338,14 @@ void CGHeroInstance::initHero(vstd::RNG & rand, const HeroTypeID & SUBID)
|
||||
void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
{
|
||||
assert(validTypes(true));
|
||||
if(!type)
|
||||
type = getHeroType().toHeroType();
|
||||
|
||||
|
||||
if (ID == Obj::HERO)
|
||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
|
||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, getHeroClass()->getIndex())->getTemplates().front();
|
||||
|
||||
if(!vstd::contains(spells, SpellID::PRESET))
|
||||
{
|
||||
// hero starts with default spells
|
||||
for(const auto & spellID : type->spells)
|
||||
for(const auto & spellID : getHeroType()->spells)
|
||||
spells.insert(spellID);
|
||||
}
|
||||
else //remove placeholder
|
||||
@@ -341,7 +354,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
if(!vstd::contains(spells, SpellID::SPELLBOOK_PRESET))
|
||||
{
|
||||
// hero starts with default spellbook presence status
|
||||
if(!getArt(ArtifactPosition::SPELLBOOK) && type->haveSpellBook)
|
||||
if(!getArt(ArtifactPosition::SPELLBOOK) && getHeroType()->haveSpellBook)
|
||||
{
|
||||
auto artifact = ArtifactUtils::createArtifact(ArtifactID::SPELLBOOK);
|
||||
putArtifact(ArtifactPosition::SPELLBOOK, artifact);
|
||||
@@ -360,14 +373,14 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
{
|
||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||
{
|
||||
pushPrimSkill(static_cast<PrimarySkill>(g), type->heroClass->primarySkillInitial[g]);
|
||||
pushPrimSkill(static_cast<PrimarySkill>(g), getHeroClass()->primarySkillInitial[g]);
|
||||
}
|
||||
}
|
||||
if(secSkills.size() == 1 && secSkills[0] == std::pair<SecondarySkill,ui8>(SecondarySkill::NONE, -1)) //set secondary skills to default
|
||||
secSkills = type->secSkillsInit;
|
||||
secSkills = getHeroType()->secSkillsInit;
|
||||
|
||||
if (gender == EHeroGender::DEFAULT)
|
||||
gender = type->gender;
|
||||
gender = getHeroType()->gender;
|
||||
|
||||
setFormation(EArmyFormation::LOOSE);
|
||||
if (!stacksCount()) //standard army//initial army
|
||||
@@ -403,9 +416,9 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
addNewBonus(bonus);
|
||||
}
|
||||
|
||||
if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && type->heroClass->commander.hasValue())
|
||||
if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && getHeroClass()->commander.hasValue())
|
||||
{
|
||||
commander = new CCommanderInstance(type->heroClass->commander);
|
||||
commander = new CCommanderInstance(getHeroClass()->commander);
|
||||
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
|
||||
commander->giveStackExp (exp); //after our exp is set
|
||||
}
|
||||
@@ -413,7 +426,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||
skillsInfo = SecondarySkillsInfo();
|
||||
|
||||
//copy active (probably growing) bonuses from hero prototype to hero object
|
||||
for(const std::shared_ptr<Bonus> & b : type->specialty)
|
||||
for(const std::shared_ptr<Bonus> & b : getHeroType()->specialty)
|
||||
addNewBonus(b);
|
||||
|
||||
//initialize bonuses
|
||||
@@ -433,14 +446,14 @@ void CGHeroInstance::initArmy(vstd::RNG & rand, IArmyDescriptor * dst)
|
||||
auto stacksCountChances = cb->getSettings().getVector(EGameSettings::HEROES_STARTING_STACKS_CHANCES);
|
||||
int stacksCountInitRandomNumber = rand.nextInt(1, 100);
|
||||
|
||||
size_t maxStacksCount = std::min(stacksCountChances.size(), type->initialArmy.size());
|
||||
size_t maxStacksCount = std::min(stacksCountChances.size(), getHeroType()->initialArmy.size());
|
||||
|
||||
for(int stackNo=0; stackNo < maxStacksCount; stackNo++)
|
||||
{
|
||||
if (stacksCountInitRandomNumber > stacksCountChances[stackNo])
|
||||
continue;
|
||||
|
||||
auto & stack = type->initialArmy[stackNo];
|
||||
auto & stack = getHeroType()->initialArmy[stackNo];
|
||||
|
||||
int count = rand.nextInt(stack.minAmount, stack.maxAmount);
|
||||
|
||||
@@ -588,11 +601,11 @@ std::string CGHeroInstance::getMovementPointsTextIfOwner(PlayerColor player) con
|
||||
|
||||
ui8 CGHeroInstance::maxlevelsToMagicSchool() const
|
||||
{
|
||||
return type->heroClass->isMagicHero() ? 3 : 4;
|
||||
return getHeroClass()->isMagicHero() ? 3 : 4;
|
||||
}
|
||||
ui8 CGHeroInstance::maxlevelsToWisdom() const
|
||||
{
|
||||
return type->heroClass->isMagicHero() ? 3 : 6;
|
||||
return getHeroClass()->isMagicHero() ? 3 : 6;
|
||||
}
|
||||
|
||||
CGHeroInstance::SecondarySkillsInfo::SecondarySkillsInfo():
|
||||
@@ -617,11 +630,8 @@ void CGHeroInstance::pickRandomObject(vstd::RNG & rand)
|
||||
{
|
||||
ID = Obj::HERO;
|
||||
subID = cb->gameState()->pickNextHeroType(getOwner());
|
||||
type = getHeroType().toHeroType();
|
||||
randomizeArmy(type->heroClass->faction);
|
||||
randomizeArmy(getHeroClass()->faction);
|
||||
}
|
||||
else
|
||||
type = getHeroType().toHeroType();
|
||||
|
||||
auto oldSubID = subID;
|
||||
|
||||
@@ -629,7 +639,7 @@ void CGHeroInstance::pickRandomObject(vstd::RNG & rand)
|
||||
// after setType subID used to store unique hero identify id. Check issue 2277 for details
|
||||
// exclude prisons which should use appearance as set in map, via map editor or RMG
|
||||
if (ID != Obj::PRISON)
|
||||
setType(ID, type->heroClass->getIndex());
|
||||
setType(ID, getHeroClass()->getIndex());
|
||||
|
||||
this->subID = oldSubID;
|
||||
}
|
||||
@@ -1064,7 +1074,7 @@ si32 CGHeroInstance::getManaNewTurn() const
|
||||
|
||||
BoatId CGHeroInstance::getBoatType() const
|
||||
{
|
||||
return BoatId(VLC->townh->getById(type->heroClass->faction)->getBoatType());
|
||||
return BoatId(VLC->townh->getById(getHeroClass()->faction)->getBoatType());
|
||||
}
|
||||
|
||||
void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const
|
||||
@@ -1103,7 +1113,7 @@ void CGHeroInstance::pushPrimSkill( PrimarySkill which, int val )
|
||||
|
||||
EAlignment CGHeroInstance::getAlignment() const
|
||||
{
|
||||
return type->heroClass->getAlignment();
|
||||
return getHeroClass()->getAlignment();
|
||||
}
|
||||
|
||||
void CGHeroInstance::initExp(vstd::RNG & rand)
|
||||
@@ -1127,12 +1137,12 @@ HeroTypeID CGHeroInstance::getPortraitSource() const
|
||||
if (customPortraitSource.isValid())
|
||||
return customPortraitSource;
|
||||
else
|
||||
return getHeroType();
|
||||
return getHeroTypeID();
|
||||
}
|
||||
|
||||
int32_t CGHeroInstance::getIconIndex() const
|
||||
{
|
||||
return VLC->heroTypes()->getById(getPortraitSource())->getIconIndex();
|
||||
return getPortraitSource().toEntity(VLC)->getIconIndex();
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::getNameTranslated() const
|
||||
@@ -1149,15 +1159,15 @@ std::string CGHeroInstance::getClassNameTextID() const
|
||||
{
|
||||
if (isCampaignGem())
|
||||
return "core.genrltxt.735";
|
||||
return type->heroClass->getNameTextID();
|
||||
return getHeroClass()->getNameTextID();
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::getNameTextID() const
|
||||
{
|
||||
if (!nameCustomTextId.empty())
|
||||
return nameCustomTextId;
|
||||
if (type)
|
||||
return type->getNameTextID();
|
||||
if (getHeroTypeID().hasValue())
|
||||
return getHeroType()->getNameTextID();
|
||||
|
||||
// FIXME: called by logging from some specialties (mods?) before type is set on deserialization
|
||||
// assert(0);
|
||||
@@ -1173,8 +1183,8 @@ std::string CGHeroInstance::getBiographyTextID() const
|
||||
{
|
||||
if (!biographyCustomTextId.empty())
|
||||
return biographyCustomTextId;
|
||||
if (type)
|
||||
return type->getBiographyTextID();
|
||||
if (getHeroTypeID().hasValue())
|
||||
return getHeroType()->getBiographyTextID();
|
||||
|
||||
return ""; //for random hero
|
||||
}
|
||||
@@ -1372,11 +1382,11 @@ std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills(vs
|
||||
SecondarySkill selection;
|
||||
|
||||
if (selectWisdom)
|
||||
selection = type->heroClass->chooseSecSkill(intersect(options, wisdomList), rand);
|
||||
selection = getHeroClass()->chooseSecSkill(intersect(options, wisdomList), rand);
|
||||
else if (selectSchool)
|
||||
selection = type->heroClass->chooseSecSkill(intersect(options, schoolList), rand);
|
||||
selection = getHeroClass()->chooseSecSkill(intersect(options, schoolList), rand);
|
||||
else
|
||||
selection = type->heroClass->chooseSecSkill(options, rand);
|
||||
selection = getHeroClass()->chooseSecSkill(options, rand);
|
||||
|
||||
skills.push_back(selection);
|
||||
options.erase(selection);
|
||||
@@ -1407,7 +1417,7 @@ PrimarySkill CGHeroInstance::nextPrimarySkill(vstd::RNG & rand) const
|
||||
{
|
||||
assert(gainsLevel());
|
||||
const auto isLowLevelHero = level < GameConstants::HERO_HIGH_LEVEL;
|
||||
const auto & skillChances = isLowLevelHero ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
|
||||
const auto & skillChances = isLowLevelHero ? getHeroClass()->primarySkillLowLevel : getHeroClass()->primarySkillHighLevel;
|
||||
|
||||
if (isCampaignYog())
|
||||
{
|
||||
@@ -1537,35 +1547,25 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, BonusSubtypeID
|
||||
if (visionsMultiplier > 0)
|
||||
vstd::amax(visionsRange, 3); //minimum range is 3 tiles, but only if VISIONS bonus present
|
||||
|
||||
const int distance = static_cast<int>(target->pos.dist2d(visitablePos()));
|
||||
const int distance = static_cast<int>(target->anchorPos().dist2d(visitablePos()));
|
||||
|
||||
//logGlobal->debug(boost::str(boost::format("Visions: dist %d, mult %d, range %d") % distance % visionsMultiplier % visionsRange));
|
||||
|
||||
return (distance < visionsRange) && (target->pos.z == pos.z);
|
||||
return (distance < visionsRange) && (target->anchorPos().z == anchorPos().z);
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::getHeroTypeName() const
|
||||
{
|
||||
if(ID == Obj::HERO || ID == Obj::PRISON)
|
||||
{
|
||||
if(type)
|
||||
{
|
||||
return type->getJsonKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
return getHeroType().toEntity(VLC)->getJsonKey();
|
||||
}
|
||||
}
|
||||
return getHeroType()->getJsonKey();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void CGHeroInstance::afterAddToMap(CMap * map)
|
||||
{
|
||||
if(ID != Obj::PRISON)
|
||||
{
|
||||
map->heroesOnMap.emplace_back(this);
|
||||
}
|
||||
}
|
||||
void CGHeroInstance::afterRemoveFromMap(CMap* map)
|
||||
{
|
||||
@@ -1752,8 +1752,7 @@ void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
if(!appearance)
|
||||
{
|
||||
// crossoverDeserialize
|
||||
type = getHeroType().toHeroType();
|
||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
|
||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, getHeroClassID())->getTemplates().front();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1840,7 +1839,7 @@ bool CGHeroInstance::isCampaignYog() const
|
||||
if (!boost::starts_with(campaign, "DATA/YOG")) // "Birth of a Barbarian"
|
||||
return false;
|
||||
|
||||
if (getHeroType() != HeroTypeID::SOLMYR) // Yog (based on Solmyr)
|
||||
if (getHeroTypeID() != HeroTypeID::SOLMYR) // Yog (based on Solmyr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -1858,7 +1857,7 @@ bool CGHeroInstance::isCampaignGem() const
|
||||
if (!boost::starts_with(campaign, "DATA/GEM") && !boost::starts_with(campaign, "DATA/FINAL")) // "New Beginning" and "Unholy Alliance"
|
||||
return false;
|
||||
|
||||
if (getHeroType() != HeroTypeID::GEM) // Yog (based on Solmyr)
|
||||
if (getHeroTypeID() != HeroTypeID::GEM) // Yog (based on Solmyr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user