using Outnumbered.Domain; using Xunit; namespace Outnumbered.Tests; // CombatResolver's pure reactive-sustain amounts (the engine does the HP/armor writes; these own the numbers). Expected // ints are hand-known, exercising the (int)Math.Round (banker's, ToEven) rounding + the LifestealMinHeal floor. public class CombatAmountsTests { // LifestealHeal = max(minHeal, (int)Round(dmgHealth * pct/100 * critMult)). [Theory] [InlineData(100, 10, 1.0, 2, 10)] // clean [InlineData(100, 10, 1.5, 2, 15)] // crit multiplier [InlineData(10, 25, 1.0, 2, 2)] // 2.5 -> ToEven -> 2 [InlineData(30, 25, 1.0, 2, 8)] // 7.5 -> ToEven -> 8 [InlineData(4, 25, 1.0, 2, 2)] // 1.0 -> 1, but minHeal floor binds -> 2 [InlineData(0, 10, 1.0, 2, 2)] // 0 -> floor binds public void LifestealHeal_matches(double dmgHealth, double pct, double critMult, int minHeal, int expected) => Assert.Equal(expected, CombatResolver.LifestealHeal(dmgHealth, pct, critMult, minHeal)); [Fact] public void LifestealHeal_accepts_fractional_thorns_input() { // The thorns-reflect path passes a FLOAT dmgHealth (no pre-truncation) with critMult 1.0. 33.6*10/100 = 3.36 -> 3. Assert.Equal(3, CombatResolver.LifestealHeal(33.6, 10, 1.0, 2)); } // ArmorLifestealGain = (int)Round(dmgHealth * pct/100 * critMult). No floor. [Theory] [InlineData(100, 10, 1.0, 10)] [InlineData(10, 25, 1.0, 2)] // 2.5 -> 2 [InlineData(30, 25, 1.0, 8)] // 7.5 -> 8 [InlineData(0, 10, 1.0, 0)] // no floor -> 0 public void ArmorLifestealGain_matches(double dmgHealth, double pct, double critMult, int expected) => Assert.Equal(expected, CombatResolver.ArmorLifestealGain(dmgHealth, pct, critMult)); // ThornsReflect = (dmgHealth + dmgArmor) * pct/100 (a double). The caller deals it FLAT — no build/handicap re-applied — // so the bot eats exactly this off the damage ACTUALLY taken (handicap already baked into dmg*). [Theory] [InlineData(50, 30, 10, 8.0)] [InlineData(100, 0, 5, 5.0)] [InlineData(250, 0, 10, 25.0)] // the 5x-handicap example: take 250, reflect 10% = 25 [InlineData(0, 0, 10, 0.0)] public void ThornsReflect_matches(int dmgHealth, int dmgArmor, double pct, double expected) => T.Close(expected, CombatResolver.ThornsReflect(dmgHealth, dmgArmor, pct)); }