From a943d2cb123c54d78095f0226e0684e6ccb807a1 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Thu, 2 Mar 2023 00:54:10 +0300 Subject: [PATCH] vcmi: add sourceType to HasAnotherBonusLimiter Now we can filter bonuses by sourceType, hence, checking, for example, specific secondary skills. Also fix archery artifacts working without Archery skill. --- config/artifacts.json | 45 ++++++++++++++++++++++++++++++++++++++++--- lib/HeroBonus.cpp | 29 +++++++++++++++++++++++----- lib/HeroBonus.h | 10 ++++++++++ lib/JsonNode.cpp | 28 +++++++++++++++++++++++++-- 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/config/artifacts.json b/config/artifacts.json index e028a28d1..7f4ae3165 100644 --- a/config/artifacts.json +++ b/config/artifacts.json @@ -915,7 +915,20 @@ "subtype" : "skill.archery", "type" : "SECONDARY_SKILL_PREMY", "val" : 5, - "valueType" : "ADDITIVE_VALUE" + "valueType" : "ADDITIVE_VALUE", + "limiters" : [ + { + "type" : "HAS_ANOTHER_BONUS_LIMITER", + "parameters" : [ + "PERCENTAGE_DAMAGE_BOOST", + 1, + { + "type" : "SECONDARY_SKILL", + "id" : "skill.archery" + } + ] + } + ] } ], "index" : 60, @@ -928,7 +941,20 @@ "subtype" : "skill.archery", "type" : "SECONDARY_SKILL_PREMY", "val" : 10, - "valueType" : "ADDITIVE_VALUE" + "valueType" : "ADDITIVE_VALUE", + "limiters" : [ + { + "type" : "HAS_ANOTHER_BONUS_LIMITER", + "parameters" : [ + "PERCENTAGE_DAMAGE_BOOST", + 1, + { + "type" : "SECONDARY_SKILL", + "id" : "skill.archery" + } + ] + } + ] } ], "index" : 61, @@ -941,7 +967,20 @@ "subtype" : "skill.archery", "type" : "SECONDARY_SKILL_PREMY", "val" : 15, - "valueType" : "ADDITIVE_VALUE" + "valueType" : "ADDITIVE_VALUE", + "limiters" : [ + { + "type" : "HAS_ANOTHER_BONUS_LIMITER", + "parameters" : [ + "PERCENTAGE_DAMAGE_BOOST", + 1, + { + "type" : "SECONDARY_SKILL", + "id" : "skill.archery" + } + ] + } + ] } ], "index" : 62, diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index cee1fe415..5f9da31dc 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -2044,20 +2044,36 @@ JsonNode CCreatureTypeLimiter::toJsonNode() const } HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus ) - : type(bonus), subtype(0), isSubtypeRelevant(false) + : type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false) { } HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus, TBonusSubtype _subtype ) - : type(bonus), subtype(_subtype), isSubtypeRelevant(true) + : type(bonus), subtype(_subtype), isSubtypeRelevant(true), isSourceRelevant(false), isSourceIDRelevant(false) +{ +} + +HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src) + : type(bonus), source(src), isSubtypeRelevant(false), isSourceRelevant(true), isSourceIDRelevant(false) +{ +} + +HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src) + : type(bonus), subtype(_subtype), isSubtypeRelevant(true), source(src), isSourceRelevant(true), isSourceIDRelevant(false) { } int HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const { - CSelector mySelector = isSubtypeRelevant - ? Selector::typeSubtype(type, subtype) - : Selector::type()(type); + //TODO: proper selector config with parsing of JSON + auto mySelector = Selector::type()(type); + + if(isSubtypeRelevant) + mySelector = mySelector.And(Selector::subtype()(subtype)); + if(isSourceRelevant && isSourceIDRelevant) + mySelector = mySelector.And(Selector::source(source, sid)); + else if (isSourceRelevant) + mySelector = mySelector.And(Selector::sourceTypeSel(source)); //if we have a bonus of required type accepted, limiter should accept also this bonus if(context.alreadyAccepted.getFirst(mySelector)) @@ -2092,11 +2108,14 @@ JsonNode HasAnotherBonusLimiter::toJsonNode() const { JsonNode root(JsonNode::JsonType::DATA_STRUCT); std::string typeName = vstd::findKey(bonusNameMap, type); + auto sourceTypeName = vstd::findKey(bonusSourceMap, source); root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER"; root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName)); if(isSubtypeRelevant) root["parameters"].Vector().push_back(JsonUtils::intNode(subtype)); + if(isSourceRelevant) + root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName)); return root; } diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index f59664971..68a794d70 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -1052,10 +1052,16 @@ class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nod public: Bonus::BonusType type; TBonusSubtype subtype; + Bonus::BonusSource source; + si32 sid; bool isSubtypeRelevant; //check for subtype only if this is true + bool isSourceRelevant; //check for bonus source only if this is true + bool isSourceIDRelevant; //check for bonus source only if this is true HasAnotherBonusLimiter(Bonus::BonusType bonus = Bonus::NONE); HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype); + HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src); + HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src); int limit(const BonusLimitationContext &context) const override; virtual std::string toString() const override; @@ -1067,6 +1073,10 @@ public: h & type; h & subtype; h & isSubtypeRelevant; + h & source; + h & isSourceRelevant; + h & sid; + h & isSourceIDRelevant; } }; diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index dcfd88e4b..aa2a17c0e 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -708,10 +708,34 @@ std::shared_ptr JsonUtils::parseLimiter(const JsonNode & limiter) { std::shared_ptr bonusLimiter = std::make_shared(); bonusLimiter->type = it->second; + auto findSource = [&](const JsonNode & parameter) + { + if(parameter.getType() == JsonNode::JsonType::DATA_STRUCT) + { + auto sourceIt = bonusSourceMap.find(parameter["type"].String()); + if(sourceIt != bonusSourceMap.end()) + { + bonusLimiter->source = sourceIt->second; + bonusLimiter->isSourceRelevant = true; + if(!parameter["id"].isNull()) { + resolveIdentifier(parameter["id"], bonusLimiter->sid); + bonusLimiter->isSourceIDRelevant = true; + } + } + } + return false; + }; if(parameters.size() > 1) { - resolveIdentifier(parameters[1], bonusLimiter->subtype); - bonusLimiter->isSubtypeRelevant = true; + if(findSource(parameters[1]) && parameters.size() == 2) + return bonusLimiter; + else + { + resolveIdentifier(parameters[1], bonusLimiter->subtype); + bonusLimiter->isSubtypeRelevant = true; + if(parameters.size() > 2) + findSource(parameters[2]); + } } return bonusLimiter; }