205 lines
7.2 KiB
C#
205 lines
7.2 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="Assist"/> move script.
|
|
/// Gen VII Bulbapedia behavior: "The Assist user executes a move that is randomly selected from all the
|
|
/// eligible moves known by other Pokémon in the same party. If the same move is known by multiple Pokémon,
|
|
/// each of them counts [...]. Assist can call a move that currently has no PP or is known by a fainted
|
|
/// Pokémon. [...] If the other Pokémon in the user's party do not know any eligible moves, Assist fails."
|
|
/// </summary>
|
|
public class AssistTests
|
|
{
|
|
private static IPokemon CreatePokemonWithMoves(params string[] moveNames)
|
|
{
|
|
var pokemon = Substitute.For<IPokemon>();
|
|
var moves = moveNames.Select(name =>
|
|
{
|
|
var learned = Substitute.For<ILearnedMove>();
|
|
var data = Substitute.For<IMoveData>();
|
|
data.Name.Returns(new StringKey(name));
|
|
learned.MoveData.Returns(data);
|
|
return (ILearnedMove?)learned;
|
|
}).ToArray();
|
|
pokemon.Moves.Returns(moves);
|
|
return pokemon;
|
|
}
|
|
|
|
private static (Assist script, IMoveChoice choice, IPokemon user, IBattleRandom random) CreateTestSetup(
|
|
params IPokemon?[] otherPartyMembers)
|
|
{
|
|
var script = new Assist();
|
|
var user = CreatePokemonWithMoves("tackle");
|
|
|
|
var members = new List<IPokemon?> { user };
|
|
members.AddRange(otherPartyMembers);
|
|
|
|
var party = Substitute.For<IPokemonParty>();
|
|
party.GetEnumerator().Returns(_ => members.GetEnumerator());
|
|
var battleParty = Substitute.For<IBattleParty>();
|
|
battleParty.Party.Returns(party);
|
|
|
|
var random = Substitute.For<IBattleRandom>();
|
|
var battle = Substitute.For<IBattle>();
|
|
battle.Parties.Returns(new[] { battleParty });
|
|
battle.Random.Returns(random);
|
|
var battleData = Substitute.For<IPokemonBattleData>();
|
|
battleData.Battle.Returns(battle);
|
|
user.BattleData.Returns(battleData);
|
|
|
|
var choice = Substitute.For<IMoveChoice>();
|
|
choice.User.Returns(user);
|
|
|
|
return (script, choice, user, random);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The Assist user executes a move that is randomly selected from all the eligible moves known
|
|
/// by other Pokémon in the same party."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_AllyKnowsEligibleMove_SelectsThatMove()
|
|
{
|
|
// Arrange
|
|
var (script, choice, _, random) = CreateTestSetup(CreatePokemonWithMoves("growl"));
|
|
random.GetInt(Arg.Any<int>()).Returns(0);
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("growl"));
|
|
choice.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "If the other Pokémon in the user's party do not know any eligible moves, Assist fails."
|
|
/// The user's own moves are not eligible: with no other party members, the move fails even though the
|
|
/// user itself knows a copyable move.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_NoOtherPartyMembers_Fails()
|
|
{
|
|
// Arrange
|
|
var (script, choice, _, _) = CreateTestSetup();
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
choice.Received(1).Fail();
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("assist"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia lists moves that Assist cannot call (e.g. Protect, Counter, moves with a semi-invulnerable
|
|
/// turn). An ally that only knows ineligible moves provides no options, so Assist fails.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_AllyOnlyKnowsIneligibleMoves_Fails()
|
|
{
|
|
// Arrange
|
|
var (script, choice, _, _) = CreateTestSetup(CreatePokemonWithMoves("protect", "counter", "dig"));
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
choice.Received(1).Fail();
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("assist"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "If the same move is known by multiple Pokémon, each of them counts and therefore the move
|
|
/// is more likely to be called." Two allies knowing Tackle plus one knowing Growl yields three entries in
|
|
/// the random selection pool.
|
|
/// </summary>
|
|
[Test]
|
|
public void ChangeMove_SameMoveKnownByMultipleAllies_EachCounts()
|
|
{
|
|
// Arrange
|
|
var (script, choice, _, random) = CreateTestSetup(CreatePokemonWithMoves("pound"),
|
|
CreatePokemonWithMoves("pound"), CreatePokemonWithMoves("growl"));
|
|
random.GetInt(Arg.Any<int>()).Returns(0);
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert - the selection pool contains three moves (pound twice, growl once)
|
|
random.Received(1).GetInt(3);
|
|
choice.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Assist can call a move that [...] is known by a fainted Pokémon."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_AllyIsFainted_MoveStillEligible()
|
|
{
|
|
// Arrange
|
|
var faintedAlly = CreatePokemonWithMoves("growl");
|
|
faintedAlly.IsUsable.Returns(false);
|
|
var (script, choice, _, random) = CreateTestSetup(faintedAlly);
|
|
random.GetInt(Arg.Any<int>()).Returns(0);
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("growl"));
|
|
choice.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Assist can call a move that currently has no PP".
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_AllyMoveHasNoPp_MoveStillEligible()
|
|
{
|
|
// Arrange
|
|
var ally = CreatePokemonWithMoves("growl");
|
|
ally.Moves[0]!.CurrentPp.Returns((byte)0);
|
|
var (script, choice, _, random) = CreateTestSetup(ally);
|
|
random.GetInt(Arg.Any<int>()).Returns(0);
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("growl"));
|
|
choice.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: outside of battle (no battle data) the script returns without failing the choice.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_NoBattleData_DoesNothing()
|
|
{
|
|
// Arrange
|
|
var script = new Assist();
|
|
var user = Substitute.For<IPokemon>();
|
|
user.BattleData.Returns((IPokemonBattleData?)null);
|
|
var choice = Substitute.For<IMoveChoice>();
|
|
choice.User.Returns(user);
|
|
StringKey moveName = "assist";
|
|
|
|
// Act
|
|
script.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
choice.DidNotReceive().Fail();
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("assist"));
|
|
}
|
|
} |