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:
parent
98218adea5
commit
7e9a15c20b
@ -123,6 +123,10 @@
|
||||
"type":"string",
|
||||
"description": "sourceType"
|
||||
},
|
||||
"targetSourceType": {
|
||||
"type":"string",
|
||||
"description": "targetSourceType"
|
||||
},
|
||||
"stacking" : {
|
||||
"type" : "string",
|
||||
"description" : "stacking"
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user