Browse Source

Fix handling of bonuses with negative values

Ivan Savenko 3 months ago
parent
commit
d1f9c497a3
4 changed files with 19 additions and 6 deletions
  1. 10 4
      Global.h
  2. 2 1
      docs/modders/Bonus/Bonus_Updaters.md
  3. 4 1
      lib/bonuses/BonusList.cpp
  4. 3 0
      lib/bonuses/Updaters.h

+ 10 - 4
Global.h

@@ -712,13 +712,16 @@ namespace vstd
 		return a + (b - a) * f;
 	}
 
-	/// Divides dividend by divisor and rounds result up
+	/// Divides dividend by divisor and rounds result away from zero
 	/// For use with integer-only arithmetic
 	template<typename Integer1, typename Integer2>
 	Integer1 divideAndCeil(const Integer1 & dividend, const Integer2 & divisor)
 	{
 		static_assert(std::is_integral_v<Integer1> && std::is_integral_v<Integer2>, "This function should only be used with integral types");
-		return (dividend + divisor - 1) / divisor;
+		if (dividend >= 0)
+			return (dividend + divisor - 1) / divisor;
+		else
+			return (dividend - divisor + 1) / divisor;
 	}
 
 	/// Divides dividend by divisor and rounds result to nearest
@@ -727,10 +730,13 @@ namespace vstd
 	Integer1 divideAndRound(const Integer1 & dividend, const Integer2 & divisor)
 	{
 		static_assert(std::is_integral_v<Integer1> && std::is_integral_v<Integer2>, "This function should only be used with integral types");
-		return (dividend + divisor / 2 - 1) / divisor;
+		if (dividend >= 0)
+			return (dividend + divisor / 2 - 1) / divisor;
+		else
+			return (dividend - divisor / 2 + 1) / divisor;
 	}
 
-	/// Divides dividend by divisor and rounds result down
+	/// Divides dividend by divisor and rounds result towards zero
 	/// For use with integer-only arithmetic
 	template<typename Integer1, typename Integer2>
 	Integer1 divideAndFloor(const Integer1 & dividend, const Integer2 & divisor)

+ 2 - 1
docs/modders/Bonus/Bonus_Updaters.md

@@ -112,8 +112,9 @@ Example of long form with custom parameters:
 Effect: Updates val to `val = clamp(val * floor(stackSize / stepSize), minimum, maximum)`, where stackSize is total number of creatures in hero army that fulful filter
 
 Parameters:
+
 - `minimum`: minimum possible value of the bonus value. Unlimited by default
-- `minimum`: maximum possible value of the bonus value. Unlimited by default
+- `maximum`: maximum possible value of the bonus value. Unlimited by default
 - `stepSize`: number of units needed to increase updater multiplier by 1
 - `filteredCreature`: identifier of specific unit to filter
 - `filteredLevel`: level of units that need to be counted. Redundant if `filteredCreature` is used

+ 4 - 1
lib/bonuses/BonusList.cpp

@@ -70,7 +70,10 @@ int BonusList::totalValue(int baseValue) const
 	};
 
 	auto applyPercentageRoundUp = [](int base, int percent) -> int {
-		return (static_cast<int64_t>(base) * (100 + percent) + 99) / 100;
+		if (base >= 0)
+			return (static_cast<int64_t>(base) * (100 + percent) + 99) / 100;
+		else
+			return (static_cast<int64_t>(base) * (100 + percent) - 99) / 100;
 	};
 
 	auto applyPercentageRoundDown = [](int base, int percent) -> int {

+ 3 - 0
lib/bonuses/Updaters.h

@@ -134,6 +134,9 @@ public:
 		h & minimum;
 		h & maximum;
 		h & stepSize;
+		h & filteredLevel;
+		h & filteredCreature;
+		h & filteredFaction;
 	}
 };