using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile; using PkmnLib.Static.Moves; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Bulbapedia: "When two allies attempt to use Fire Pledge and either Water Pledge or Grass Pledge on the /// same turn, the ally moving first will not itself use a move, but instead the ally moving second will use /// a combined attack with a power of 150 and an additional effect immediately after it". /// public class FirePledgeTests { /// /// Creates a move choice for a Pokémon on the given side, using a move with the given name. /// The choice gets a real as its volatile set, so combination markers can be /// added to and read from it. /// private static IMoveChoice CreateQueuedChoice(string moveName, byte sideIndex) { var choice = Substitute.For(); choice.GetScripts().Returns(_ => new ScriptIterator(new List>())); var pokemon = Substitute.For(); var battleData = Substitute.For(); battleData.SideIndex.Returns(sideIndex); pokemon.BattleData.Returns(battleData); choice.User.Returns(pokemon); var moveData = Substitute.For(); moveData.Name.Returns(new StringKey(moveName)); var learnedMove = Substitute.For(); learnedMove.MoveData.Returns(moveData); choice.ChosenMove.Returns(learnedMove); var choiceVolatile = new ScriptSet(choice); choice.Volatile.Returns(choiceVolatile); return choice; } /// /// Creates a fully mocked test setup for Fire Pledge tests. The user is on side 0. /// private static (FirePledge script, IExecutingMove move, IMoveChoice ownChoice) CreateTestSetup( BattleChoiceQueue? queue) { var script = new FirePledge(); var move = Substitute.For(); var battle = Substitute.For(); battle.ChoiceQueue.Returns(queue); move.Battle.Returns(battle); var user = Substitute.For(); var userBattleData = Substitute.For(); userBattleData.SideIndex.Returns((byte)0); user.BattleData.Returns(userBattleData); move.User.Returns(user); var ownChoice = CreateQueuedChoice("fire_pledge", 0); move.MoveChoice.Returns(ownChoice); return (script, move, ownChoice); } /// /// Bulbapedia: "the ally moving first will not itself use a move". /// An ally on the same side still has Water Pledge queued, so this Fire Pledge is stopped. /// [Test] public async Task StopBeforeMove_AllyWaterPledgeQueued_StopsMove() { // Arrange var allyChoice = CreateQueuedChoice("water_pledge", 0); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsTrue(); } /// /// Bulbapedia: "If Fire Pledge and Water Pledge are used in the same turn, the ally moving second will /// use Water Pledge with a power of 150, and create a rainbow on the user's side of the field for four /// turns." /// The queued ally choice is marked with the volatile that implements /// the combined move. /// [Test] public async Task StopBeforeMove_AllyWaterPledgeQueued_MarksAllyChoiceAsCombinedFireWaterPledge() { // Arrange var allyChoice = CreateQueuedChoice("water_pledge", 0); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(allyChoice.Volatile.Contains()).IsTrue(); } /// /// Bulbapedia: "the ally moving first will not itself use a move". /// An ally on the same side still has Grass Pledge queued, so this Fire Pledge is stopped. /// [Test] public async Task StopBeforeMove_AllyGrassPledgeQueued_StopsMove() { // Arrange var allyChoice = CreateQueuedChoice("grass_pledge", 0); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsTrue(); } /// /// Bulbapedia: "If Fire Pledge and Grass Pledge are used in the same turn, the ally moving second will /// use Fire Pledge with a power of 150, and create a sea of fire on the target's side of the field for /// four turns." /// The queued ally choice is marked with the volatile that implements /// the combined move. /// [Test] public async Task StopBeforeMove_AllyGrassPledgeQueued_MarksAllyChoiceAsCombinedFireGrassPledge() { // Arrange var allyChoice = CreateQueuedChoice("grass_pledge", 0); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(allyChoice.Volatile.Contains()).IsTrue(); } /// /// Bulbapedia: the combination only happens when allies use "Fire Pledge and either Water Pledge or /// Grass Pledge on the same turn". /// No Pledge move is queued by an ally, so Fire Pledge executes normally. /// [Test] public async Task StopBeforeMove_NoPledgeMoveQueued_DoesNotStop() { // Arrange var allyChoice = CreateQueuedChoice("tackle", 0); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsFalse(); } /// /// Bulbapedia: "When two allies attempt to use Fire Pledge and either Water Pledge or Grass Pledge on /// the same turn" — a Pledge move queued by an opponent does not combine. /// [Test] public async Task StopBeforeMove_OpponentWaterPledgeQueued_DoesNotStop() { // Arrange var opponentChoice = CreateQueuedChoice("water_pledge", 1); var (script, move, _) = CreateTestSetup(new BattleChoiceQueue([opponentChoice])); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsFalse(); await Assert.That(opponentChoice.Volatile.Contains()).IsFalse(); } /// /// Bulbapedia: "the ally moving second will use Fire Pledge with a power of 150". /// When this Fire Pledge choice is itself the combined move of Grass Pledge and Fire Pledge (marked /// with ), it must execute instead of deferring again. /// [Test] public async Task StopBeforeMove_ChoiceIsCombinedFireGrassPledge_DoesNotStop() { // Arrange var allyChoice = CreateQueuedChoice("grass_pledge", 0); var (script, move, ownChoice) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); ownChoice.Volatile.Add(new FireGrassPledgeMove()); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsFalse(); await Assert.That(allyChoice.Volatile.Contains()).IsFalse(); } /// /// Bulbapedia: "the ally moving second will use Water Pledge with a power of 150". /// When this choice is the combined move of Fire Pledge and Water Pledge (marked with /// ), it must execute instead of deferring again. /// [Test] public async Task StopBeforeMove_ChoiceIsCombinedFireWaterPledge_DoesNotStop() { // Arrange var allyChoice = CreateQueuedChoice("water_pledge", 0); var (script, move, ownChoice) = CreateTestSetup(new BattleChoiceQueue([allyChoice])); ownChoice.Volatile.Add(new FireWaterPledgeMove()); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsFalse(); await Assert.That(allyChoice.Volatile.Contains()).IsFalse(); } /// /// Technical test: when the battle has no active choice queue, the move executes normally without /// throwing. /// [Test] public async Task StopBeforeMove_NullChoiceQueue_DoesNotStop() { // Arrange var (script, move, _) = CreateTestSetup(null); var stop = false; // Act script.StopBeforeMove(move, ref stop); // Assert await Assert.That(stop).IsFalse(); } }