using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
///
/// Tests for the move script.
/// Gen VII Bulbapedia behavior: "Last Resort will fail unless the Pokémon has used all of its other moves
/// at least once while on the field. Using a move before switching out and back in does not count towards
/// being able to use Last Resort. Last Resort will fail if it is the only move the user knows".
///
public class LastResortTests
{
///
/// Creates a mocked with the given move name.
///
private static ILearnedMove CreateLearnedMove(string name)
{
var moveData = Substitute.For();
moveData.Name.Returns(new StringKey(name));
moveData.SecondaryEffect.Returns((ISecondaryEffect?)null);
var learnedMove = Substitute.For();
learnedMove.MoveData.Returns(moveData);
return learnedMove;
}
///
/// Creates a mocked user in battle that knows the given moves.
///
private static IBattlePokemon CreateUser(params ILearnedMove?[] moves)
{
var user = Substitute.For();
user.Moves.Returns(moves);
var battle = Substitute.For();
user.Battle.Returns(battle);
return user;
}
///
/// Sets the battle's previous turn choices, one inner array per turn (oldest first).
///
private static void SetPreviousTurns(IBattlePokemon user, params ITurnChoice[][] turns)
{
user.Battle.PreviousTurnChoices.Returns(turns.Select(IReadOnlyList (t) => t).ToList());
}
///
/// Runs for the user selecting the given Last Resort
/// move and returns whether the selection was prevented.
///
private static bool RunPreventMoveSelection(IBattlePokemon user, ILearnedMove lastResort)
{
var script = new LastResort();
var choice = new MoveChoice(user, lastResort, 0, 0);
var prevent = false;
script.PreventMoveSelection(choice, ref prevent);
return prevent;
}
///
/// Bulbapedia: "Last Resort will fail unless the Pokémon has used all of its other moves at least once
/// while on the field." — with every other move used, selecting Last Resort is allowed.
///
[Test]
public async Task PreventMoveSelection_AllOtherMovesUsedOnField_SelectionAllowed()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var growl = CreateLearnedMove("growl");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, growl, lastResort);
SetPreviousTurns(user, [new MoveChoice(user, tackle, 0, 0)], [new MoveChoice(user, growl, 0, 0)]);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsFalse();
}
///
/// Bulbapedia: "Last Resort will fail unless the Pokémon has used all of its other moves at least once
/// while on the field." — with one of the other moves never used, the selection is prevented.
///
[Test]
public async Task PreventMoveSelection_NotAllOtherMovesUsed_SelectionPrevented()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var growl = CreateLearnedMove("growl");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, growl, lastResort);
SetPreviousTurns(user, [new MoveChoice(user, tackle, 0, 0)]);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsTrue();
}
///
/// Bulbapedia: Last Resort fails "unless the Pokémon has used all of its other moves at least once" —
/// with no moves used at all (e.g. the first turn), the selection is prevented.
///
[Test]
public async Task PreventMoveSelection_NoMovesUsedYet_SelectionPrevented()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, lastResort);
SetPreviousTurns(user);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsTrue();
}
///
/// Bulbapedia: "Last Resort will fail if it is the only move the user knows".
///
[Test]
public async Task PreventMoveSelection_LastResortOnlyKnownMove_SelectionPrevented()
{
// Arrange
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(lastResort, null, null, null);
SetPreviousTurns(user);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsTrue();
}
///
/// Bulbapedia: "Using a move before switching out and back in does not count towards being able to use
/// Last Resort." — a move used only before the user was switched back in does not enable Last Resort.
///
[Test]
public async Task PreventMoveSelection_MoveOnlyUsedBeforeSwitchingOut_SelectionPrevented()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, lastResort);
var ally = Substitute.For();
SetPreviousTurns(user, [new MoveChoice(user, tackle, 0, 0)], [new SwitchChoice(user, ally)],
[new SwitchChoice(ally, user)]);
// The user re-entered the field during turn 3, after all three recorded turns' choices were made.
user.SwitchInTurn.Returns(3u);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsTrue();
}
///
/// Bulbapedia: "A move will still count as used for Last Resort even if it would have no effect, so for
/// example, using Snore when the user is awake or a move missing due to accuracy or evasion." — a failed
/// move choice still counts as used.
///
[Test]
public async Task PreventMoveSelection_OtherMoveFailed_SelectionAllowed()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, lastResort);
var failedTackle = new MoveChoice(user, tackle, 0, 0);
failedTackle.Fail();
SetPreviousTurns(user, [failedTackle]);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsFalse();
}
///
/// Bulbapedia: the requirement is that "the Pokémon has used all of its other moves" — a move used by a
/// different Pokémon does not count for the user.
///
[Test]
public async Task PreventMoveSelection_MoveUsedByAnotherPokemon_SelectionPrevented()
{
// Arrange
var tackle = CreateLearnedMove("tackle");
var lastResort = CreateLearnedMove("last_resort");
var user = CreateUser(tackle, lastResort);
var other = Substitute.For();
SetPreviousTurns(user, [new MoveChoice(other, tackle, 0, 0)]);
// Act
var prevent = RunPreventMoveSelection(user, lastResort);
// Assert
await Assert.That(prevent).IsTrue();
}
}