cs2-outnumbered/Outnumbered.Tests/CombatAmountsTests.cs
Kamal Tufekcic d701598350
All checks were successful
CI / build (push) Successful in 32s
CI / release (push) Successful in 32s
CI / lint (push) Successful in 30s
initial commit
2026-07-05 13:28:35 +03:00

46 lines
2.3 KiB
C#

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));
}