using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Dynamic.ScriptHandling.Registry; using PkmnLib.Plugin.Gen7.Scripts.Battle; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static; using PkmnLib.Static.Moves; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script and its attached . /// Gen VII Bulbapedia behavior: "Mud Sport now reduces the base power of Electric-type moves by 67% /// (approximated as a factor of 1352/4096) on both sides in battle." and (Generations VI and VII): /// "Mud Sport is now active for five turns, even if the user switches out." /// public class MudSportTests { /// /// Creates a fully mocked test setup where the battle has a real as its volatile /// script set. /// private static (MudSport script, IExecutingMove move, IPokemon target, IBattle battle, IScriptSet battleVolatile) CreateTestSetup() { var script = new MudSport(); var move = Substitute.For(); var target = Substitute.For(); var battle = Substitute.For(); battle.GetScripts().Returns(_ => new ScriptIterator(Array.Empty>())); IScriptSet battleVolatile = new ScriptSet(battle); battle.Volatile.Returns(battleVolatile); var battleData = Substitute.For(); battleData.Battle.Returns(battle); var user = Substitute.For(); user.BattleData.Returns(battleData); move.User.Returns(user); return (script, move, target, battle, battleVolatile); } /// /// Creates a mocked executing move whose used move has the given type name. /// private static IExecutingMove CreateExecutingMoveOfType(string typeName) { var executingMove = Substitute.For(); var moveData = Substitute.For(); moveData.MoveType.Returns(new TypeIdentifier(1, typeName)); executingMove.UseMove.Returns(moveData); return executingMove; } /// /// Bulbapedia: Mud Sport reduces the base power of Electric-type moves "on both sides in battle" — using /// the move puts the on the battle's volatile scripts so it affects the whole /// field, "even if the user switches out". /// [Test] public async Task OnSecondaryEffect_AddsMudSportEffectToBattleVolatile() { // Arrange var (script, move, target, _, battleVolatile) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(battleVolatile.Contains(ScriptUtils.ResolveName())).IsTrue(); } /// /// Technical test: without battle data on the user (outside of battle) the secondary effect does nothing /// and does not throw. /// [Test] public void OnSecondaryEffect_UserHasNoBattleData_DoesNotThrow() { // Arrange var script = new MudSport(); var move = Substitute.For(); var target = Substitute.For(); var user = Substitute.For(); user.BattleData.Returns((IPokemonBattleData?)null); move.User.Returns(user); // Act & Assert - should not throw script.OnSecondaryEffect(move, target, 0); } /// /// Bulbapedia: "Mud Sport now reduces the base power of Electric-type moves by 67% (approximated as a /// factor of 1352/4096) on both sides in battle." /// [Test, Arguments((ushort)100, (ushort)33), Arguments((ushort)4096, (ushort)1352)] public async Task ChangeBasePower_ElectricMove_PowerReducedBySixtySevenPercent(ushort basePower, ushort expectedPower) { // Arrange var effect = new MudSportEffect(); var electricMove = CreateExecutingMoveOfType("electric"); var target = Substitute.For(); // Act effect.ChangeBasePower(electricMove, target, 0, ref basePower); // Assert await Assert.That(basePower).IsEqualTo(expectedPower); } /// /// Bulbapedia: Mud Sport only "reduces the base power of Electric-type moves" — moves of other types are /// unaffected. /// [Test] public async Task ChangeBasePower_NonElectricMove_PowerUnchanged() { // Arrange var effect = new MudSportEffect(); var fireMove = CreateExecutingMoveOfType("fire"); var target = Substitute.For(); ushort basePower = 100; // Act effect.ChangeBasePower(fireMove, target, 0, ref basePower); // Assert await Assert.That(basePower).IsEqualTo((ushort)100); } /// /// Bulbapedia: "Mud Sport is now active for five turns" — after four end-of-turn ticks the /// is still on the battle. /// [Test] public async Task OnEndTurn_FourTurns_EffectRemains() { // Arrange var (script, move, target, battle, battleVolatile) = CreateTestSetup(); script.OnSecondaryEffect(move, target, 0); var effect = battleVolatile.Get()!; // Act for (var turn = 0; turn < 4; turn++) effect.OnEndTurn(battle, battle); // Assert await Assert.That(battleVolatile.Contains(ScriptUtils.ResolveName())).IsTrue(); } /// /// Bulbapedia: "Mud Sport is now active for five turns" — after the fifth end-of-turn tick the /// removes itself. /// [Test] public async Task OnEndTurn_FiveTurns_EffectRemovesItself() { // Arrange var (script, move, target, battle, battleVolatile) = CreateTestSetup(); script.OnSecondaryEffect(move, target, 0); var effect = battleVolatile.Get()!; // Act for (var turn = 0; turn < 5; turn++) effect.OnEndTurn(battle, battle); // Assert await Assert.That(battleVolatile.Contains(ScriptUtils.ResolveName())).IsFalse(); } }