1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

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.
This commit is contained in:
Konstantin 2023-02-15 22:19:35 +03:00
parent 98218adea5
commit 7e9a15c20b
4 changed files with 66 additions and 42 deletions

View File

@ -123,6 +123,10 @@
"type":"string",
"description": "sourceType"
},
"targetSourceType": {
"type":"string",
"description": "targetSourceType"
},
"stacking" : {
"type" : "string",
"description" : "stacking"

View File

@ -452,73 +452,74 @@ void BonusList::stackBonuses()
int BonusList::totalValue() const
{
std::array <std::pair<int, int>, Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {};
struct BonusCollection
{
int base = 0;
int percentToBase = 0;
int percentToAll = 0;
int additive = 0;
int indepMax = 0;
int percentToSource;
int indepMin = std::numeric_limits<int>::max();
int indepMax = std::numeric_limits<int>::min();
};
auto percent = [](int base, int percent) -> int {return (base * (100 + percent)) / 100; };
std::array <BonusCollection, Bonus::BonusSource::NUM_BONUS_SOURCE> sources = {};
BonusCollection any;
bool hasIndepMax = false;
int indepMin = 0;
bool hasIndepMin = false;
int modifiedBase = 0;
for(std::shared_ptr<Bonus> 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);
}
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);
}
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<Bonus>& b)
const int notIndepBonuses = (int)std::count_if(bonuses.cbegin(), bonuses.cend(), [](const std::shared_ptr<Bonus>& 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> Bonus::addPropagator(TPropagatorPtr Propagator)
@ -1833,6 +1839,12 @@ namespace Selector
return ssourceType;
}
DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType()
{
static CSelectFieldEqual<Bonus::BonusSource> ssourceType(&Bonus::targetSourceType);
return ssourceType;
}
DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange()
{
static CSelectFieldEqual<Bonus::LimitEffect> seffectRange(&Bonus::effectRange);

View File

@ -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<Bonus>
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<Bonus>
h & propagator;
h & updater;
h & propagationUpdater;
h & targetSourceType;
}
template <typename Ptr>
@ -1176,6 +1179,7 @@ namespace Selector
extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType();
extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType();
extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange();
extern DLL_LINKAGE CWillLastTurns turns;
extern DLL_LINKAGE CWillLastDays days;

View File

@ -849,6 +849,10 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b)
if (!value->isNull())
b->source = static_cast<Bonus::BonusSource>(parseByMap(bonusSourceMap, value, "source type "));
value = &ability["targetSourceType"];
if (!value->isNull())
b->targetSourceType = static_cast<Bonus::BonusSource>(parseByMap(bonusSourceMap, value, "target type "));
value = &ability["limiters"];
if (!value->isNull())
b->limiter = parseLimiter(*value);