From 64428427319e91dc831442553540b06a041db4dd Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Tue, 6 Feb 2018 13:44:43 +1300 Subject: [PATCH] added one-line option for standard creature specialty; also fixes bug for creatures where upgrades have different attack/defense --- config/heroes/castle.json | 31 +------------ config/schemas/hero.json | 5 ++- lib/CHeroHandler.cpp | 94 +++++++++++++++++++++++++++------------ 3 files changed, 70 insertions(+), 60 deletions(-) diff --git a/config/heroes/castle.json b/config/heroes/castle.json index d97da972a..f574eb3d3 100644 --- a/config/heroes/castle.json +++ b/config/heroes/castle.json @@ -75,36 +75,7 @@ { "skill" : "armorer", "level": "basic" } ], "specialty" : { - "base" : { - "limiters" : [ - { - "parameters" : [ "griffin", true ], - "type" : "CREATURE_TYPE_LIMITER" - } - ] - }, - "bonuses" : { - "attack" : { - "subtype" : "primSkill.attack", - "type" : "PRIMARY_SKILL", - "updater" : { - "parameters" : [ 8, 3 ], - "type" : "GROWS_WITH_LEVEL" - } - }, - "defence" : { - "subtype" : "primSkill.defence", - "type" : "PRIMARY_SKILL", - "updater" : { - "parameters" : [ 8, 3 ], - "type" : "GROWS_WITH_LEVEL" - } - }, - "speed" : { - "type" : "STACKS_SPEED", - "val" : 1 - } - } + "creature" : "griffin" } }, "sylvia": diff --git a/config/schemas/hero.json b/config/schemas/hero.json index 30735c1b9..d88163dc6 100644 --- a/config/schemas/hero.json +++ b/config/schemas/hero.json @@ -140,7 +140,6 @@ "type" : "object", "description": "Description of hero specialty using bonus system", "additionalProperties" : false, - "required" : [ "bonuses" ], "properties" : { "base" : { "type" : "object", @@ -150,6 +149,10 @@ "type" : "object", "description" : "Set of bonuses", "additionalProperties" : { "$ref" : "vcmi:bonus" } + }, + "creature" : { + "type" : "string", + "description" : "Name of base creature to grant standard specialty to." } } } diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index b128376ec..decb72116 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -379,6 +379,43 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node) } } +// add standard creature specialty to result +void AddSpecialtyForCreature(int creatureID, std::shared_ptr bonus, std::vector> &result) +{ + const CCreature &specBaseCreature = *VLC->creh->creatures[creatureID]; //base creature in which we have specialty + + bonus->limiter.reset(new CCreatureTypeLimiter(specBaseCreature, true)); + bonus->type = Bonus::STACKS_SPEED; + bonus->valType = Bonus::ADDITIVE_VALUE; + bonus->val = 1; + result.push_back(bonus); + + // attack and defense may differ for upgraded creatures => separate bonuses + std::vector specTargets; + specTargets.push_back(creatureID); + specTargets.insert(specTargets.end(), specBaseCreature.upgrades.begin(), specBaseCreature.upgrades.end()); + + for(int cid : specTargets) + { + const CCreature &specCreature = *VLC->creh->creatures[cid]; + bonus = std::make_shared(*bonus); + bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, false)); + bonus->type = Bonus::PRIMARY_SKILL; + bonus->val = 0; + + int stepSize = specCreature.level ? specCreature.level : 5; + + bonus->subtype = PrimarySkill::ATTACK; + bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize)); + result.push_back(bonus); + + bonus = std::make_shared(*bonus); + bonus->subtype = PrimarySkill::DEFENSE; + bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefence(false), stepSize)); + result.push_back(bonus); + } +} + // convert deprecated format std::vector> SpecialtyInfoToBonuses(const SSpecialtyInfo & spec, int sid) { @@ -393,29 +430,7 @@ std::vector> SpecialtyInfoToBonuses(const SSpecialtyInfo switch (spec.type) { case 1: //creature specialty - { - const CCreature &specCreature = *VLC->creh->creatures[spec.additionalinfo]; //creature in which we have specialty - bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, true)); - - bonus->type = Bonus::STACKS_SPEED; - bonus->valType = Bonus::ADDITIVE_VALUE; - bonus->val = 1; - result.push_back(bonus); - - bonus = std::make_shared(*bonus); - bonus->type = Bonus::PRIMARY_SKILL; - bonus->val = 0; - int stepSize = specCreature.level ? specCreature.level : 5; - - bonus->subtype = PrimarySkill::ATTACK; - bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getAttack(false), stepSize)); - result.push_back(bonus); - - bonus = std::make_shared(*bonus); - bonus->subtype = PrimarySkill::DEFENSE; - bonus->updater.reset(new GrowsWithLevelUpdater(specCreature.getDefence(false), stepSize)); - result.push_back(bonus); - } + AddSpecialtyForCreature(spec.additionalinfo, bonus, result); break; case 2: //secondary skill bonus->type = Bonus::SECONDARY_SKILL_PREMY; @@ -585,9 +600,16 @@ void CHeroHandler::beforeValidate(JsonNode & object) const JsonNode & base = specialtyNode["base"]; if(!base.isNull()) { - JsonMap & bonuses = specialtyNode["bonuses"].Struct(); - for(std::pair keyValue : bonuses) - JsonUtils::inherit(bonuses[keyValue.first], base); + if(specialtyNode["bonuses"].isNull()) + { + logMod->warn("specialty has base without bonuses"); + } + else + { + JsonMap & bonuses = specialtyNode["bonuses"].Struct(); + for(std::pair keyValue : bonuses) + JsonUtils::inherit(bonuses[keyValue.first], base); + } } } } @@ -635,9 +657,23 @@ void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node) } else if(specialtyNode.getType() == JsonNode::JsonType::DATA_STRUCT) { - //proper new format - for(auto keyValue : specialtyNode["bonuses"].Struct()) - hero->specialty.push_back(prepSpec(JsonUtils::parseBonus(keyValue.second))); + //creature specialty - alias for simplicity + if(!specialtyNode["creature"].isNull()) + { + VLC->modh->identifiers.requestIdentifier("creature", specialtyNode["creature"], [hero](si32 creature) { + // use legacy format for delayed conversion (must have all creature data loaded, also for upgrades) + SSpecialtyInfo spec; + spec.type = 1; + spec.additionalinfo = creature; + hero->specDeprecated.push_back(spec); + }); + } + if(!specialtyNode["bonuses"].isNull()) + { + //proper new format + for(auto keyValue : specialtyNode["bonuses"].Struct()) + hero->specialty.push_back(prepSpec(JsonUtils::parseBonus(keyValue.second))); + } } }