From 7e9a15c20bdd892485aba689f7c51c2bea262fc7 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Wed, 15 Feb 2023 22:19:35 +0300 Subject: [PATCH] vcmi: add PERCENT_TO_TARGET_SOURCE value type It will break saves!!! Added a new value type to bonuses which allows to add percentage only to one foreign bonus source, for example, to add percentage to all bonuses from secondary skills from hero special. --- config/schemas/bonus.json | 4 ++ lib/HeroBonus.cpp | 96 ++++++++++++++++++++++----------------- lib/HeroBonus.h | 4 ++ lib/JsonNode.cpp | 4 ++ 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/config/schemas/bonus.json b/config/schemas/bonus.json index 901fbd25e..4fd8ffe99 100644 --- a/config/schemas/bonus.json +++ b/config/schemas/bonus.json @@ -123,6 +123,10 @@ "type":"string", "description": "sourceType" }, + "targetSourceType": { + "type":"string", + "description": "targetSourceType" + }, "stacking" : { "type" : "string", "description" : "stacking" diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 78eeec51d..cee1fe415 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -452,73 +452,74 @@ void BonusList::stackBonuses() int BonusList::totalValue() const { - std::array , Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {}; - int base = 0; - int percentToBase = 0; - int percentToAll = 0; - int additive = 0; - int indepMax = 0; + struct BonusCollection + { + int base = 0; + int percentToBase = 0; + int percentToAll = 0; + int additive = 0; + int percentToSource; + int indepMin = std::numeric_limits::max(); + int indepMax = std::numeric_limits::min(); + }; + + auto percent = [](int base, int percent) -> int {return (base * (100 + percent)) / 100; }; + std::array sources = {}; + BonusCollection any; bool hasIndepMax = false; - int indepMin = 0; bool hasIndepMin = false; - int modifiedBase = 0; for(std::shared_ptr b : bonuses) { switch(b->valType) { case Bonus::BASE_NUMBER: - sources[b->source].first += b->val; + sources[b->source].base += b->val; break; case Bonus::PERCENT_TO_ALL: - percentToAll += b->val; + sources[b->source].percentToAll += b->val; break; case Bonus::PERCENT_TO_BASE: - percentToBase += b->val; + sources[b->source].percentToBase += b->val; break; case Bonus::PERCENT_TO_SOURCE: - sources[b->source].second += b->val; + sources[b->source].percentToSource += b->val; + break; + case Bonus::PERCENT_TO_TARGET_TYPE: + sources[b->targetSourceType].percentToSource += b->val; break; case Bonus::ADDITIVE_VALUE: - additive += b->val; + sources[b->source].additive += b->val; break; case Bonus::INDEPENDENT_MAX: - if (!hasIndepMax) - { - indepMax = b->val; - hasIndepMax = true; - } - else - { - vstd::amax(indepMax, b->val); - } + hasIndepMax = true; + vstd::amax(sources[b->source].indepMax, b->val); break; case Bonus::INDEPENDENT_MIN: - if (!hasIndepMin) - { - indepMin = b->val; - hasIndepMin = true; - } - else - { - vstd::amin(indepMin, b->val); - } + hasIndepMin = true; + vstd::amin(sources[b->source].indepMin, b->val); break; } } for(auto src : sources) { - base += src.first; - modifiedBase += src.first + (src.first * src.second) / 100; + any.base += percent(src.base ,src.percentToSource); + any.percentToBase += percent(src.percentToBase, src.percentToSource); + any.percentToAll += percent(src.percentToAll, src.percentToSource); + any.additive += percent(src.additive, src.percentToSource); + if(hasIndepMin) + vstd::amin(any.indepMin, percent(src.indepMin, src.percentToSource)); + if(hasIndepMax) + vstd::amax(any.indepMax, percent(src.indepMin, src.percentToSource)); } - modifiedBase += (base * percentToBase) / 100; - modifiedBase += additive; - int valFirst = (modifiedBase * (100 + percentToAll)) / 100; + any.base = percent(any.base, any.percentToBase); + any.base += any.additive; + auto valFirst = percent(any.base ,any.percentToAll); if(hasIndepMin && hasIndepMax) - assert(indepMin < indepMax); + assert(any.indepMin < any.indepMax); - const int notIndepBonuses = (int)boost::count_if(bonuses, [](const std::shared_ptr& b) + const int notIndepBonuses = (int)std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr& b) { return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN; }); @@ -526,16 +527,16 @@ int BonusList::totalValue() const if (hasIndepMax) { if(notIndepBonuses) - vstd::amax(valFirst, indepMax); + vstd::amax(valFirst, any.indepMax); else - valFirst = indepMax; + valFirst = any.indepMax; } if (hasIndepMin) { if(notIndepBonuses) - vstd::amin(valFirst, indepMin); + vstd::amin(valFirst, any.indepMin); else - valFirst = indepMin; + valFirst = any.indepMin; } return valFirst; @@ -1719,6 +1720,8 @@ JsonNode Bonus::toJsonNode() const root["turns"].Integer() = turnsRemain; if(source != OTHER) root["sourceType"].String() = vstd::findKey(bonusSourceMap, source); + if(targetSourceType != OTHER) + root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType); if(sid != 0) root["sourceID"].Integer() = sid; if(val != 0) @@ -1778,6 +1781,7 @@ Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si3 valType = ADDITIVE_VALUE; effectRange = NO_LIMIT; boost::algorithm::trim(description); + targetSourceType = OTHER; } Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType) @@ -1785,6 +1789,7 @@ Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si3 { turnsRemain = 0; effectRange = NO_LIMIT; + targetSourceType = OTHER; } Bonus::Bonus() @@ -1799,6 +1804,7 @@ Bonus::Bonus() val = 0; source = OTHER; sid = 0; + targetSourceType = OTHER; } std::shared_ptr Bonus::addPropagator(TPropagatorPtr Propagator) @@ -1833,6 +1839,12 @@ namespace Selector return ssourceType; } + DLL_LINKAGE CSelectFieldEqual & targetSourceType() + { + static CSelectFieldEqual ssourceType(&Bonus::targetSourceType); + return ssourceType; + } + DLL_LINKAGE CSelectFieldEqual & effectRange() { static CSelectFieldEqual seffectRange(&Bonus::effectRange); diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index bb10cd6f3..f59664971 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -365,6 +365,7 @@ public: BONUS_VALUE(PERCENT_TO_ALL)\ BONUS_VALUE(PERCENT_TO_BASE)\ BONUS_VALUE(PERCENT_TO_SOURCE) /*Adds value only to bonuses with same source*/\ + BONUS_VALUE(PERCENT_TO_TARGET_TYPE) /*Adds value only to bonuses with SourceType target*/\ BONUS_VALUE(INDEPENDENT_MAX) /*used for SPELL bonus */\ BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY bonus @@ -421,6 +422,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this TBonusSubtype subtype; //-1 if not applicable - 4 bytes BonusSource source;//source type" uses BonusSource values - what gave that bonus + BonusSource targetSourceType;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE. si32 val; ui32 sid; //source id: id of object/artifact/spell ValueType valType; @@ -458,6 +460,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this h & propagator; h & updater; h & propagationUpdater; + h & targetSourceType; } template @@ -1176,6 +1179,7 @@ namespace Selector extern DLL_LINKAGE CSelectFieldEqual & subtype(); extern DLL_LINKAGE CSelectFieldEqual & info(); extern DLL_LINKAGE CSelectFieldEqual & sourceType(); + extern DLL_LINKAGE CSelectFieldEqual & targetSourceType(); extern DLL_LINKAGE CSelectFieldEqual & effectRange(); extern DLL_LINKAGE CWillLastTurns turns; extern DLL_LINKAGE CWillLastDays days; diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index 8f8d04f1d..dcfd88e4b 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -849,6 +849,10 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) if (!value->isNull()) b->source = static_cast(parseByMap(bonusSourceMap, value, "source type ")); + value = &ability["targetSourceType"]; + if (!value->isNull()) + b->targetSourceType = static_cast(parseByMap(bonusSourceMap, value, "target type ")); + value = &ability["limiters"]; if (!value->isNull()) b->limiter = parseLimiter(*value);