diff --git a/PkmnLib.Static/StatisticSet.cs b/PkmnLib.Static/StatisticSet.cs index 18e044a..b94e5db 100644 --- a/PkmnLib.Static/StatisticSet.cs +++ b/PkmnLib.Static/StatisticSet.cs @@ -312,7 +312,7 @@ public abstract record ClampedStatisticSet : StatisticSet where T : struct var current = GetStatistic(stat); var newValue = Subtract(current, value); if (newValue.CompareTo(Min) < 0) - value = Add(Min, current); + value = Subtract(current, Min); if (value.CompareTo(default) == 0) return false; return base.DecreaseStatistic(stat, value); diff --git a/PkmnLib.Tests/Dynamic/PokemonStatBoostTests.cs b/PkmnLib.Tests/Dynamic/PokemonStatBoostTests.cs new file mode 100644 index 0000000..dd0a664 --- /dev/null +++ b/PkmnLib.Tests/Dynamic/PokemonStatBoostTests.cs @@ -0,0 +1,105 @@ +using PkmnLib.Dynamic.Libraries; +using PkmnLib.Dynamic.Models; +using PkmnLib.Static; +using PkmnLib.Static.Species; +using PkmnLib.Tests.Integration; + +namespace PkmnLib.Tests.Dynamic; + +public class PokemonStatBoostTests +{ + private static IPokemon CreatePokemon() + { + var library = LibraryHelpers.LoadLibrary(); + if (!library.StaticLibrary.Species.TryGet("bulbasaur", out var species)) + throw new InvalidOperationException("Failed to load bulbasaur species."); + return new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex + { + Index = 0, + IsHidden = false, + }, 50, 0, Gender.Male, 0, "hardy"); + } + + [Test] + public async Task ChangeStatBoost_IncreasesStatBoost() + { + var pokemon = CreatePokemon(); + + var changed = pokemon.ChangeStatBoost(Statistic.Attack, 2, true, false); + + await Assert.That(changed).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo((sbyte)2); + } + + [Test] + public async Task ChangeStatBoost_DecreasesStatBoost() + { + var pokemon = CreatePokemon(); + + var changed = pokemon.ChangeStatBoost(Statistic.Attack, -2, true, false); + + await Assert.That(changed).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo((sbyte)-2); + } + + [Test] + public async Task ChangeStatBoost_ReturnsFalseWhenChangeIsZero() + { + var pokemon = CreatePokemon(); + + var changed = pokemon.ChangeStatBoost(Statistic.Attack, 0, true, false); + + await Assert.That(changed).IsFalse(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo((sbyte)0); + } + + [Test] + public async Task ChangeStatBoost_ReturnsFalseWhenMaxCapReached() + { + var pokemon = CreatePokemon(); + + // Raise the stat boost all the way to the maximum of +6. + var raised = pokemon.ChangeStatBoost(Statistic.Attack, StatBoostStatisticSet.MaxStatBoost, true, false); + await Assert.That(raised).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo(StatBoostStatisticSet.MaxStatBoost); + + // The cap has been reached, so a further increase should do nothing and report failure. + var changed = pokemon.ChangeStatBoost(Statistic.Attack, 1, true, false); + + await Assert.That(changed).IsFalse(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo(StatBoostStatisticSet.MaxStatBoost); + } + + [Test] + public async Task ChangeStatBoost_ReturnsFalseWhenMinCapReached() + { + var pokemon = CreatePokemon(); + + // Lower the stat boost all the way to the minimum of -6. + var lowered = pokemon.ChangeStatBoost(Statistic.Attack, StatBoostStatisticSet.MinStatBoost, true, false); + await Assert.That(lowered).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo(StatBoostStatisticSet.MinStatBoost); + + // The floor has been reached, so a further decrease should do nothing and report failure. + var changed = pokemon.ChangeStatBoost(Statistic.Attack, -1, true, false); + + await Assert.That(changed).IsFalse(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo(StatBoostStatisticSet.MinStatBoost); + } + + [Test] + public async Task ChangeStatBoost_ClampsToCapButStillReportsChangeWhenPartiallyApplied() + { + var pokemon = CreatePokemon(); + + // Raise to +5, one below the cap. + await Assert.That(pokemon.ChangeStatBoost(Statistic.Attack, 5, true, false)).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo((sbyte)5); + + // Asking for +4 can only apply +1 before hitting the cap. Since a change is still made, it reports success. + var changed = pokemon.ChangeStatBoost(Statistic.Attack, 4, true, false); + + await Assert.That(changed).IsTrue(); + await Assert.That(pokemon.StatBoost.Attack).IsEqualTo(StatBoostStatisticSet.MaxStatBoost); + } +} \ No newline at end of file