浏览代码

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.
Konstantin 2 年之前
父节点
当前提交
7e9a15c20b
共有 4 个文件被更改,包括 66 次插入42 次删除
  1. 4 0
      config/schemas/bonus.json
  2. 54 42
      lib/HeroBonus.cpp
  3. 4 0
      lib/HeroBonus.h
  4. 4 0
      lib/JsonNode.cpp

+ 4 - 0
config/schemas/bonus.json

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

+ 54 - 42
lib/HeroBonus.cpp

@@ -452,73 +452,74 @@ void BonusList::stackBonuses()
 
 
 int BonusList::totalValue() const
 int BonusList::totalValue() const
 {
 {
-	std::array <std::pair<int, int>, 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<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;
 	bool hasIndepMax = false;
-	int indepMin = 0;
 	bool hasIndepMin = false;
 	bool hasIndepMin = false;
-	int modifiedBase = 0;
 
 
 	for(std::shared_ptr<Bonus> b : bonuses)
 	for(std::shared_ptr<Bonus> b : bonuses)
 	{
 	{
 		switch(b->valType)
 		switch(b->valType)
 		{
 		{
 		case Bonus::BASE_NUMBER:
 		case Bonus::BASE_NUMBER:
-			sources[b->source].first += b->val;
+			sources[b->source].base += b->val;
 			break;
 			break;
 		case Bonus::PERCENT_TO_ALL:
 		case Bonus::PERCENT_TO_ALL:
-			percentToAll += b->val;
+			sources[b->source].percentToAll += b->val;
 			break;
 			break;
 		case Bonus::PERCENT_TO_BASE:
 		case Bonus::PERCENT_TO_BASE:
-			percentToBase += b->val;
+			sources[b->source].percentToBase += b->val;
 			break;
 			break;
 		case Bonus::PERCENT_TO_SOURCE:
 		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;
 			break;
 		case Bonus::ADDITIVE_VALUE:
 		case Bonus::ADDITIVE_VALUE:
-			additive += b->val;
+			sources[b->source].additive += b->val;
 			break;
 			break;
 		case Bonus::INDEPENDENT_MAX:
 		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;
 			break;
 		case Bonus::INDEPENDENT_MIN:
 		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;
 			break;
 		}
 		}
 	}
 	}
 	for(auto src : sources)
 	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)
 	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;
 		return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
 	});
 	});
@@ -526,16 +527,16 @@ int BonusList::totalValue() const
 	if (hasIndepMax)
 	if (hasIndepMax)
 	{
 	{
 		if(notIndepBonuses)
 		if(notIndepBonuses)
-			vstd::amax(valFirst, indepMax);
+			vstd::amax(valFirst, any.indepMax);
 		else
 		else
-			valFirst = indepMax;
+			valFirst = any.indepMax;
 	}
 	}
 	if (hasIndepMin)
 	if (hasIndepMin)
 	{
 	{
 		if(notIndepBonuses)
 		if(notIndepBonuses)
-			vstd::amin(valFirst, indepMin);
+			vstd::amin(valFirst, any.indepMin);
 		else
 		else
-			valFirst = indepMin;
+			valFirst = any.indepMin;
 	}
 	}
 
 
 	return valFirst;
 	return valFirst;
@@ -1719,6 +1720,8 @@ JsonNode Bonus::toJsonNode() const
 		root["turns"].Integer() = turnsRemain;
 		root["turns"].Integer() = turnsRemain;
 	if(source != OTHER)
 	if(source != OTHER)
 		root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
 		root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
+	if(targetSourceType != OTHER)
+		root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
 	if(sid != 0)
 	if(sid != 0)
 		root["sourceID"].Integer() = sid;
 		root["sourceID"].Integer() = sid;
 	if(val != 0)
 	if(val != 0)
@@ -1778,6 +1781,7 @@ Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si3
 	valType = ADDITIVE_VALUE;
 	valType = ADDITIVE_VALUE;
 	effectRange = NO_LIMIT;
 	effectRange = NO_LIMIT;
 	boost::algorithm::trim(description);
 	boost::algorithm::trim(description);
+	targetSourceType = OTHER;
 }
 }
 
 
 Bonus::Bonus(Bonus::BonusDuration Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, ValueType ValType)
 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;
 	turnsRemain = 0;
 	effectRange = NO_LIMIT;
 	effectRange = NO_LIMIT;
+	targetSourceType = OTHER;
 }
 }
 
 
 Bonus::Bonus()
 Bonus::Bonus()
@@ -1799,6 +1804,7 @@ Bonus::Bonus()
 	val = 0;
 	val = 0;
 	source = OTHER;
 	source = OTHER;
 	sid = 0;
 	sid = 0;
+	targetSourceType = OTHER;
 }
 }
 
 
 std::shared_ptr<Bonus> Bonus::addPropagator(TPropagatorPtr Propagator)
 std::shared_ptr<Bonus> Bonus::addPropagator(TPropagatorPtr Propagator)
@@ -1833,6 +1839,12 @@ namespace Selector
 		return ssourceType;
 		return ssourceType;
 	}
 	}
 
 
+	DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType()
+	{
+		static CSelectFieldEqual<Bonus::BonusSource> ssourceType(&Bonus::targetSourceType);
+		return ssourceType;
+	}
+
 	DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange()
 	DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange()
 	{
 	{
 		static CSelectFieldEqual<Bonus::LimitEffect> seffectRange(&Bonus::effectRange);
 		static CSelectFieldEqual<Bonus::LimitEffect> seffectRange(&Bonus::effectRange);

+ 4 - 0
lib/HeroBonus.h

@@ -365,6 +365,7 @@ public:
 	BONUS_VALUE(PERCENT_TO_ALL)\
 	BONUS_VALUE(PERCENT_TO_ALL)\
 	BONUS_VALUE(PERCENT_TO_BASE)\
 	BONUS_VALUE(PERCENT_TO_BASE)\
 	BONUS_VALUE(PERCENT_TO_SOURCE) /*Adds value only to bonuses with same source*/\
 	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_MAX) /*used for SPELL bonus */\
 	BONUS_VALUE(INDEPENDENT_MIN) //used for SECONDARY_SKILL_PREMY 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
 	TBonusSubtype subtype; //-1 if not applicable - 4 bytes
 
 
 	BonusSource source;//source type" uses BonusSource values - what gave that bonus
 	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;
 	si32 val;
 	ui32 sid; //source id: id of object/artifact/spell
 	ui32 sid; //source id: id of object/artifact/spell
 	ValueType valType;
 	ValueType valType;
@@ -458,6 +460,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 		h & propagator;
 		h & propagator;
 		h & updater;
 		h & updater;
 		h & propagationUpdater;
 		h & propagationUpdater;
+		h & targetSourceType;
 	}
 	}
 
 
 	template <typename Ptr>
 	template <typename Ptr>
@@ -1176,6 +1179,7 @@ namespace Selector
 	extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
 	extern DLL_LINKAGE CSelectFieldEqual<TBonusSubtype> & subtype();
 	extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
 	extern DLL_LINKAGE CSelectFieldEqual<CAddInfo> & info();
 	extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType();
 	extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & sourceType();
+	extern DLL_LINKAGE CSelectFieldEqual<Bonus::BonusSource> & targetSourceType();
 	extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange();
 	extern DLL_LINKAGE CSelectFieldEqual<Bonus::LimitEffect> & effectRange();
 	extern DLL_LINKAGE CWillLastTurns turns;
 	extern DLL_LINKAGE CWillLastTurns turns;
 	extern DLL_LINKAGE CWillLastDays days;
 	extern DLL_LINKAGE CWillLastDays days;

+ 4 - 0
lib/JsonNode.cpp

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