mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Merge pull request #1790 from IvanSavenko/creature_specialty_loading_refactoring
Refactoring of hero specialty loading code
This commit is contained in:
@@ -504,182 +504,60 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add standard creature specialty to result
|
/// creates standard H3 hero specialty for creatures
|
||||||
void AddSpecialtyForCreature(int creatureID, std::shared_ptr<Bonus> bonus, std::vector<std::shared_ptr<Bonus>> &result)
|
static std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID baseCreatureID)
|
||||||
{
|
{
|
||||||
const CCreature &specBaseCreature = *VLC->creh->objects[creatureID]; //base creature in which we have specialty
|
std::vector<std::shared_ptr<Bonus>> result;
|
||||||
|
std::set<CreatureID> targets;
|
||||||
|
targets.insert(baseCreatureID);
|
||||||
|
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specBaseCreature, true));
|
// go through entire upgrade chain and collect all creatures to which baseCreatureID can be upgraded
|
||||||
bonus->type = Bonus::STACKS_SPEED;
|
for (;;)
|
||||||
bonus->valType = Bonus::ADDITIVE_VALUE;
|
{
|
||||||
bonus->val = 1;
|
std::set<CreatureID> oldTargets = targets;
|
||||||
result.push_back(bonus);
|
|
||||||
|
|
||||||
// attack and defense may differ for upgraded creatures => separate bonuses
|
for (auto const & upgradeSourceID : oldTargets)
|
||||||
std::vector<int> specTargets;
|
{
|
||||||
specTargets.push_back(creatureID);
|
const CCreature * upgradeSource = VLC->creh->objects[upgradeSourceID];
|
||||||
specTargets.insert(specTargets.end(), specBaseCreature.upgrades.begin(), specBaseCreature.upgrades.end());
|
targets.insert(upgradeSource->upgrades.begin(), upgradeSource->upgrades.end());
|
||||||
|
}
|
||||||
|
|
||||||
for(int cid : specTargets)
|
if (oldTargets.size() == targets.size())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(CreatureID cid : targets)
|
||||||
{
|
{
|
||||||
const CCreature &specCreature = *VLC->creh->objects[cid];
|
const CCreature &specCreature = *VLC->creh->objects[cid];
|
||||||
bonus = std::make_shared<Bonus>(*bonus);
|
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
|
||||||
bonus->type = Bonus::PRIMARY_SKILL;
|
|
||||||
bonus->val = 0;
|
|
||||||
|
|
||||||
int stepSize = specCreature.level ? specCreature.level : 5;
|
int stepSize = specCreature.level ? specCreature.level : 5;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
|
bonus->type = Bonus::STACKS_SPEED;
|
||||||
|
bonus->val = 1;
|
||||||
|
result.push_back(bonus);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
|
bonus->type = Bonus::PRIMARY_SKILL;
|
||||||
bonus->subtype = PrimarySkill::ATTACK;
|
bonus->subtype = PrimarySkill::ATTACK;
|
||||||
|
bonus->val = 0;
|
||||||
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize));
|
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize));
|
||||||
result.push_back(bonus);
|
result.push_back(bonus);
|
||||||
|
}
|
||||||
|
|
||||||
bonus = std::make_shared<Bonus>(*bonus);
|
{
|
||||||
|
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
||||||
|
bonus->type = Bonus::PRIMARY_SKILL;
|
||||||
bonus->subtype = PrimarySkill::DEFENSE;
|
bonus->subtype = PrimarySkill::DEFENSE;
|
||||||
|
bonus->val = 0;
|
||||||
|
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false));
|
||||||
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefense(false), stepSize));
|
bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefense(false), stepSize));
|
||||||
result.push_back(bonus);
|
result.push_back(bonus);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// convert deprecated format
|
|
||||||
std::vector<std::shared_ptr<Bonus>> SpecialtyInfoToBonuses(const SSpecialtyInfo & spec, int sid)
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<Bonus>> result;
|
|
||||||
|
|
||||||
std::shared_ptr<Bonus> bonus = std::make_shared<Bonus>();
|
|
||||||
bonus->duration = Bonus::PERMANENT;
|
|
||||||
bonus->source = Bonus::HERO_SPECIAL;
|
|
||||||
bonus->sid = sid;
|
|
||||||
bonus->val = spec.val;
|
|
||||||
|
|
||||||
switch (spec.type)
|
|
||||||
{
|
|
||||||
case 1: //creature specialty
|
|
||||||
AddSpecialtyForCreature(spec.additionalinfo, bonus, result);
|
|
||||||
break;
|
|
||||||
case 2: //secondary skill
|
|
||||||
{
|
|
||||||
auto params = BonusParams("SECONDARY_SKILL_PREMY", "", spec.subtype);
|
|
||||||
bonus->type = params.type;
|
|
||||||
if(params.subtypeRelevant)
|
|
||||||
bonus->subtype = params.subtype;
|
|
||||||
bonus->valType = Bonus::PERCENT_TO_TARGET_TYPE;
|
|
||||||
bonus->targetSourceType = Bonus::SECONDARY_SKILL;
|
|
||||||
bonus->updater.reset(new TimesHeroLevelUpdater());
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3: //spell damage bonus, level dependent but calculated elsewhere
|
|
||||||
bonus->type = Bonus::SPECIAL_SPELL_LEV;
|
|
||||||
bonus->subtype = spec.subtype;
|
|
||||||
bonus->updater.reset(new TimesHeroLevelUpdater());
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 4: //creature stat boost
|
|
||||||
switch (spec.subtype)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
bonus->type = Bonus::PRIMARY_SKILL;
|
|
||||||
bonus->subtype = PrimarySkill::ATTACK;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
bonus->type = Bonus::PRIMARY_SKILL;
|
|
||||||
bonus->subtype = PrimarySkill::DEFENSE;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
bonus->type = Bonus::CREATURE_DAMAGE;
|
|
||||||
bonus->subtype = 0; //both min and max
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
bonus->type = Bonus::STACK_HEALTH;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
bonus->type = Bonus::STACKS_SPEED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logMod->warn("Unknown subtype for specialty 4");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
bonus->valType = Bonus::ADDITIVE_VALUE;
|
|
||||||
bonus->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->objects[spec.additionalinfo], true));
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 5: //spell damage bonus in percent
|
|
||||||
bonus->type = Bonus::SPECIFIC_SPELL_DAMAGE;
|
|
||||||
bonus->valType = Bonus::BASE_NUMBER; //current spell system is screwed
|
|
||||||
bonus->subtype = spec.subtype; //spell id
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 6: //damage bonus for bless (Adela)
|
|
||||||
{
|
|
||||||
auto limiter = std::make_shared<HasAnotherBonusLimiter>(Bonus::GENERAL_DAMAGE_PREMY,Bonus::SPELL_EFFECT);
|
|
||||||
limiter->sid = spec.subtype; //spell id if you ever wanted to use it otherwise
|
|
||||||
limiter->isSourceIDRelevant = true;
|
|
||||||
bonus->type = Bonus::GENERAL_DAMAGE_PREMY;
|
|
||||||
bonus->updater.reset(new TimesHeroLevelUpdater());
|
|
||||||
bonus->addLimiter(limiter);
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 7: //maxed mastery for spell
|
|
||||||
bonus->type = Bonus::SPELL;
|
|
||||||
bonus->subtype = spec.subtype; //spell id
|
|
||||||
bonus->val = 3; //to match MAXED_SPELL
|
|
||||||
bonus->valType = Bonus::INDEPENDENT_MAX;
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 8: //peculiar spells - enchantments
|
|
||||||
bonus->type = Bonus::SPECIAL_PECULIAR_ENCHANT;
|
|
||||||
bonus->subtype = spec.subtype; //spell id
|
|
||||||
bonus->additionalInfo = spec.additionalinfo; //0, 1 for Coronius
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 9: //upgrade creatures
|
|
||||||
{
|
|
||||||
const auto &creatures = VLC->creh->objects;
|
|
||||||
bonus->type = Bonus::SPECIAL_UPGRADE;
|
|
||||||
bonus->subtype = spec.subtype; //base id
|
|
||||||
bonus->additionalInfo = spec.additionalinfo; //target id
|
|
||||||
result.push_back(bonus);
|
|
||||||
//propagate for regular upgrades of base creature
|
|
||||||
for(const auto & cre_id : creatures[spec.subtype]->upgrades)
|
|
||||||
{
|
|
||||||
std::shared_ptr<Bonus> upgradeUpgradedVersion = std::make_shared<Bonus>(*bonus);
|
|
||||||
upgradeUpgradedVersion->subtype = cre_id;
|
|
||||||
result.push_back(upgradeUpgradedVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 10: //resource generation
|
|
||||||
bonus->type = Bonus::GENERATE_RESOURCE;
|
|
||||||
bonus->subtype = spec.subtype;
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 11: //starting skill with mastery (Adrienne)
|
|
||||||
logMod->warn("Secondary skill mastery is no longer supported as specialty.");
|
|
||||||
break;
|
|
||||||
case 12: //army speed
|
|
||||||
bonus->type = Bonus::STACKS_SPEED;
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
case 13: //Dragon bonuses (Mutare)
|
|
||||||
bonus->type = Bonus::PRIMARY_SKILL;
|
|
||||||
bonus->valType = Bonus::ADDITIVE_VALUE;
|
|
||||||
switch(spec.subtype)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
bonus->subtype = PrimarySkill::ATTACK;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
bonus->subtype = PrimarySkill::DEFENSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bonus->limiter.reset(new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
|
|
||||||
result.push_back(bonus);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
logMod->warn("Unknown hero specialty %d", spec.type);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -708,41 +586,51 @@ void CHeroHandler::beforeValidate(JsonNode & object)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node) const
|
void CHeroHandler::afterLoadFinalization()
|
||||||
|
{
|
||||||
|
for (auto const & functor : callAfterLoadFinalization)
|
||||||
|
functor();
|
||||||
|
|
||||||
|
callAfterLoadFinalization.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node)
|
||||||
{
|
{
|
||||||
int sid = hero->ID.getNum();
|
|
||||||
auto prepSpec = [=](std::shared_ptr<Bonus> bonus)
|
auto prepSpec = [=](std::shared_ptr<Bonus> bonus)
|
||||||
{
|
{
|
||||||
bonus->duration = Bonus::PERMANENT;
|
bonus->duration = Bonus::PERMANENT;
|
||||||
bonus->source = Bonus::HERO_SPECIAL;
|
bonus->source = Bonus::HERO_SPECIAL;
|
||||||
bonus->sid = sid;
|
bonus->sid = hero->getIndex();
|
||||||
return bonus;
|
return bonus;
|
||||||
};
|
};
|
||||||
|
|
||||||
//new format, using bonus system
|
//new format, using bonus system
|
||||||
const JsonNode & specialtyNode = node["specialty"];
|
const JsonNode & specialtyNode = node["specialty"];
|
||||||
if(specialtyNode.getType() == JsonNode::JsonType::DATA_STRUCT)
|
if(specialtyNode.getType() != JsonNode::JsonType::DATA_STRUCT)
|
||||||
{
|
{
|
||||||
|
logMod->error("Unsupported speciality format for hero %s!", hero->getNameTranslated());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//creature specialty - alias for simplicity
|
//creature specialty - alias for simplicity
|
||||||
if(!specialtyNode["creature"].isNull())
|
if(!specialtyNode["creature"].isNull())
|
||||||
{
|
{
|
||||||
VLC->modh->identifiers.requestIdentifier("creature", specialtyNode["creature"], [hero](si32 creature) {
|
JsonNode creatureNode = specialtyNode["creature"];
|
||||||
// use legacy format for delayed conversion (must have all creature data loaded, also for upgrades)
|
|
||||||
SSpecialtyInfo spec{};
|
std::function<void()> specialtyLoader = [creatureNode, hero, prepSpec]
|
||||||
spec.type = 1;
|
|
||||||
spec.additionalinfo = creature;
|
|
||||||
hero->specDeprecated.push_back(spec);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if(!specialtyNode["bonuses"].isNull())
|
|
||||||
{
|
{
|
||||||
//proper new format
|
VLC->modh->identifiers.requestIdentifier("creature", creatureNode, [hero, prepSpec](si32 creature)
|
||||||
|
{
|
||||||
|
for (const auto & bonus : createCreatureSpecialty(CreatureID(creature)))
|
||||||
|
hero->specialty.push_back(prepSpec(bonus));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
callAfterLoadFinalization.push_back(specialtyLoader);
|
||||||
|
}
|
||||||
|
|
||||||
for(const auto & keyValue : specialtyNode["bonuses"].Struct())
|
for(const auto & keyValue : specialtyNode["bonuses"].Struct())
|
||||||
hero->specialty.push_back(prepSpec(JsonUtils::parseBonus(keyValue.second)));
|
hero->specialty.push_back(prepSpec(JsonUtils::parseBonus(keyValue.second)));
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
logMod->error("Unsupported speciality format for hero %s!", hero->getNameTranslated());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHeroHandler::loadExperience()
|
void CHeroHandler::loadExperience()
|
||||||
@@ -848,64 +736,6 @@ void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNod
|
|||||||
registerObject(scope, "hero", name, object->getIndex());
|
registerObject(scope, "hero", name, object->getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHeroHandler::afterLoadFinalization()
|
|
||||||
{
|
|
||||||
for(auto & hero : objects)
|
|
||||||
{
|
|
||||||
for(const auto & bonus : hero->specialty)
|
|
||||||
{
|
|
||||||
bonus->sid = hero->getIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!hero->specDeprecated.empty())
|
|
||||||
{
|
|
||||||
logMod->debug("Converting specialty format for hero %s(%s)", hero->getNameTranslated(), FactionID::encode(hero->heroClass->faction));
|
|
||||||
std::vector<std::shared_ptr<Bonus>> convertedBonuses;
|
|
||||||
for(const SSpecialtyInfo & spec : hero->specDeprecated)
|
|
||||||
{
|
|
||||||
for(const std::shared_ptr<Bonus> & b : SpecialtyInfoToBonuses(spec, hero->ID.getNum()))
|
|
||||||
convertedBonuses.push_back(b);
|
|
||||||
}
|
|
||||||
hero->specDeprecated.clear();
|
|
||||||
// store and create json for logging
|
|
||||||
std::vector<JsonNode> specVec;
|
|
||||||
std::vector<std::string> specNames;
|
|
||||||
for(const std::shared_ptr<Bonus> & bonus : convertedBonuses)
|
|
||||||
{
|
|
||||||
hero->specialty.push_back(bonus);
|
|
||||||
specVec.push_back(bonus->toJsonNode());
|
|
||||||
// find fitting & unique bonus name
|
|
||||||
std::string bonusName = bonus->nameForBonus();
|
|
||||||
if(vstd::contains(specNames, bonusName))
|
|
||||||
{
|
|
||||||
int suffix = 2;
|
|
||||||
while(vstd::contains(specNames, bonusName + std::to_string(suffix)))
|
|
||||||
suffix++;
|
|
||||||
bonusName += std::to_string(suffix);
|
|
||||||
}
|
|
||||||
specNames.push_back(bonusName);
|
|
||||||
}
|
|
||||||
// log new format for easy copy-and-paste
|
|
||||||
JsonNode specNode(JsonNode::JsonType::DATA_STRUCT);
|
|
||||||
if(specVec.size() > 1)
|
|
||||||
{
|
|
||||||
JsonNode base = JsonUtils::intersect(specVec);
|
|
||||||
if(base.containsBaseData())
|
|
||||||
{
|
|
||||||
specNode["base"] = base;
|
|
||||||
for(JsonNode & node : specVec)
|
|
||||||
node = JsonUtils::difference(node, base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add json for bonuses
|
|
||||||
specNode["bonuses"].Struct();
|
|
||||||
for(int i = 0; i < specVec.size(); i++)
|
|
||||||
specNode["bonuses"][specNames[i]] = specVec[i];
|
|
||||||
logMod->trace("\"specialty\" : %s", specNode.toJson(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui32 CHeroHandler::level (ui64 experience) const
|
ui32 CHeroHandler::level (ui64 experience) const
|
||||||
{
|
{
|
||||||
return static_cast<ui32>(boost::range::upper_bound(expPerLevel, experience) - std::begin(expPerLevel));
|
return static_cast<ui32>(boost::range::upper_bound(expPerLevel, experience) - std::begin(expPerLevel));
|
||||||
|
@@ -29,21 +29,6 @@ class CRandomGenerator;
|
|||||||
class JsonSerializeFormat;
|
class JsonSerializeFormat;
|
||||||
class BattleField;
|
class BattleField;
|
||||||
|
|
||||||
struct SSpecialtyInfo
|
|
||||||
{
|
|
||||||
si32 type;
|
|
||||||
si32 val;
|
|
||||||
si32 subtype;
|
|
||||||
si32 additionalinfo;
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
|
||||||
{
|
|
||||||
h & type;
|
|
||||||
h & val;
|
|
||||||
h & subtype;
|
|
||||||
h & additionalinfo;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class DLL_LINKAGE CHero : public HeroType
|
class DLL_LINKAGE CHero : public HeroType
|
||||||
{
|
{
|
||||||
friend class CHeroHandler;
|
friend class CHeroHandler;
|
||||||
@@ -72,7 +57,6 @@ public:
|
|||||||
|
|
||||||
CHeroClass * heroClass{};
|
CHeroClass * heroClass{};
|
||||||
std::vector<std::pair<SecondarySkill, ui8> > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert)
|
std::vector<std::pair<SecondarySkill, ui8> > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert)
|
||||||
std::vector<SSpecialtyInfo> specDeprecated;
|
|
||||||
BonusList specialty;
|
BonusList specialty;
|
||||||
std::set<SpellID> spells;
|
std::set<SpellID> spells;
|
||||||
bool haveSpellBook = false;
|
bool haveSpellBook = false;
|
||||||
@@ -132,9 +116,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert deprecated format
|
|
||||||
std::vector<std::shared_ptr<Bonus>> SpecialtyInfoToBonuses(const SSpecialtyInfo & spec, int sid = 0);
|
|
||||||
|
|
||||||
class DLL_LINKAGE CHeroClass : public HeroClass
|
class DLL_LINKAGE CHeroClass : public HeroClass
|
||||||
{
|
{
|
||||||
friend class CHeroClassHandler;
|
friend class CHeroClassHandler;
|
||||||
@@ -251,10 +232,12 @@ class DLL_LINKAGE CHeroHandler : public CHandlerBase<HeroTypeID, HeroType, CHero
|
|||||||
/// helpers for loading to avoid huge load functions
|
/// helpers for loading to avoid huge load functions
|
||||||
void loadHeroArmy(CHero * hero, const JsonNode & node) const;
|
void loadHeroArmy(CHero * hero, const JsonNode & node) const;
|
||||||
void loadHeroSkills(CHero * hero, const JsonNode & node) const;
|
void loadHeroSkills(CHero * hero, const JsonNode & node) const;
|
||||||
void loadHeroSpecialty(CHero * hero, const JsonNode & node) const;
|
void loadHeroSpecialty(CHero * hero, const JsonNode & node);
|
||||||
|
|
||||||
void loadExperience();
|
void loadExperience();
|
||||||
|
|
||||||
|
std::vector<std::function<void()>> callAfterLoadFinalization;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CHeroClassHandler classes;
|
CHeroClassHandler classes;
|
||||||
|
|
||||||
|
@@ -1047,7 +1047,7 @@ public:
|
|||||||
bool includeUpgrades = false;
|
bool includeUpgrades = false;
|
||||||
|
|
||||||
CCreatureTypeLimiter() = default;
|
CCreatureTypeLimiter() = default;
|
||||||
CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades = true);
|
CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades);
|
||||||
void setCreature(const CreatureID & id);
|
void setCreature(const CreatureID & id);
|
||||||
|
|
||||||
int limit(const BonusLimitationContext &context) const override;
|
int limit(const BonusLimitationContext &context) const override;
|
||||||
|
@@ -510,9 +510,6 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
|
|||||||
//copy active (probably growing) bonuses from hero prototype to hero object
|
//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 : type->specialty)
|
||||||
addNewBonus(b);
|
addNewBonus(b);
|
||||||
for(SSpecialtyInfo & spec : type->specDeprecated)
|
|
||||||
for(const std::shared_ptr<Bonus> & b : SpecialtyInfoToBonuses(spec, type->getIndex()))
|
|
||||||
addNewBonus(b);
|
|
||||||
|
|
||||||
//initialize bonuses
|
//initialize bonuses
|
||||||
recreateSecondarySkillsBonuses();
|
recreateSecondarySkillsBonuses();
|
||||||
|
Reference in New Issue
Block a user