206 lines
7.7 KiB
C#
206 lines
7.7 KiB
C#
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Dynamic.ScriptHandling;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
|
using PkmnLib.Static;
|
|
using PkmnLib.Static.Moves;
|
|
using PkmnLib.Static.Species;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="MagnetRise"/> move script and its <see cref="MagnetRiseEffect"/> volatile.
|
|
/// Gen VII Bulbapedia behavior: "The user becomes immune to Ground-type attacks for five turns." "Magnet Rise
|
|
/// fails if the user is under the effects of Ingrain", "If the user is holding an Iron Ball, Magnet Rise can
|
|
/// still be used, but the user remains on the ground", and (Generation V onwards) "If used again, Magnet Rise
|
|
/// fails."
|
|
/// The Ground immunity itself is implemented by the <see cref="MagnetRiseEffect"/> volatile; the move script
|
|
/// is responsible for applying that volatile to the user.
|
|
/// </summary>
|
|
public class MagnetRiseTests
|
|
{
|
|
/// <summary>
|
|
/// Creates a fully mocked test setup for Magnet Rise tests. The user gets a real
|
|
/// <see cref="ScriptSet"/> as its volatile set, so the applied effect can be inspected.
|
|
/// </summary>
|
|
private static (MagnetRise script, IExecutingMove move, IPokemon target, IPokemon user, IScriptSet userVolatile,
|
|
IHitData hitData) CreateTestSetup()
|
|
{
|
|
var script = new MagnetRise();
|
|
var move = Substitute.For<IExecutingMove>();
|
|
var target = Substitute.For<IPokemon>();
|
|
var hitData = Substitute.For<IHitData>();
|
|
move.GetHitData(target, 0).Returns(hitData);
|
|
|
|
var user = Substitute.For<IPokemon>();
|
|
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
|
user.ActiveAbility.Returns((IAbility?)null);
|
|
var userVolatile = new ScriptSet(user);
|
|
user.Volatile.Returns(userVolatile);
|
|
move.User.Returns(user);
|
|
|
|
return (script, move, target, user, userVolatile, hitData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper that checks whether the hit was failed.
|
|
/// </summary>
|
|
private static bool HitWasFailed(IHitData hitData) =>
|
|
hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail");
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The user becomes immune to Ground-type attacks for five turns."
|
|
/// The move script applies the <see cref="MagnetRiseEffect"/> volatile, which implements the immunity,
|
|
/// to the user, and the move does not fail.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_MoveUsed_AddsMagnetRiseEffectToUserVolatile()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _, userVolatile, hitData) = CreateTestSetup();
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(userVolatile.Get<MagnetRiseEffect>()).IsNotNull();
|
|
await Assert.That(HitWasFailed(hitData)).IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Magnet Rise fails if the user is under the effects of Ingrain". When the user has the
|
|
/// <see cref="IngrainEffect"/> volatile, the hit is failed and no <see cref="MagnetRiseEffect"/> is
|
|
/// applied.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_UserUnderIngrain_MoveFails()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user, userVolatile, hitData) = CreateTestSetup();
|
|
userVolatile.Add(new IngrainEffect(user));
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(HitWasFailed(hitData)).IsTrue();
|
|
await Assert.That(userVolatile.Contains("magnet_rise")).IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia (Generation V onwards): "If used again, Magnet Rise fails." Using the move while its
|
|
/// effect is already active must fail the hit.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_UsedWhileAlreadyActive_MoveFails()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _, _, hitData) = CreateTestSetup();
|
|
|
|
// Act - second use while the effect is active
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(HitWasFailed(hitData)).IsTrue();
|
|
}
|
|
|
|
// ----- MagnetRiseEffect behavior (the volatile the move applies) -----
|
|
|
|
/// <summary>
|
|
/// Creates an incoming executing move of the given type, aimed at the given target.
|
|
/// </summary>
|
|
private static IExecutingMove CreateIncomingMove(string moveType)
|
|
{
|
|
var move = Substitute.For<IExecutingMove>();
|
|
var moveData = Substitute.For<IMoveData>();
|
|
moveData.MoveType.Returns(new TypeIdentifier(5, moveType));
|
|
move.UseMove.Returns(moveData);
|
|
return move;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The user becomes immune to Ground-type attacks for five turns." While the effect is
|
|
/// active, the effectiveness of incoming Ground-type moves against the user becomes 0.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeEffectiveness_IncomingGroundMove_UserIsImmune()
|
|
{
|
|
// Arrange
|
|
var effect = new MagnetRiseEffect();
|
|
var incomingMove = CreateIncomingMove("ground");
|
|
var owner = Substitute.For<IPokemon>();
|
|
var effectiveness = 1.0f;
|
|
|
|
// Act
|
|
effect.ChangeEffectiveness(incomingMove, owner, 0, ref effectiveness);
|
|
|
|
// Assert
|
|
await Assert.That(effectiveness).IsEqualTo(0.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: the user only becomes "immune to Ground-type attacks"; moves of other types are
|
|
/// unaffected by Magnet Rise.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeEffectiveness_IncomingNonGroundMove_EffectivenessUnchanged()
|
|
{
|
|
// Arrange
|
|
var effect = new MagnetRiseEffect();
|
|
var incomingMove = CreateIncomingMove("rock");
|
|
var owner = Substitute.For<IPokemon>();
|
|
var effectiveness = 2.0f;
|
|
|
|
// Act
|
|
effect.ChangeEffectiveness(incomingMove, owner, 0, ref effectiveness);
|
|
|
|
// Assert
|
|
await Assert.That(effectiveness).IsEqualTo(2.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "If the user is holding an Iron Ball, Magnet Rise can still be used, but the user remains
|
|
/// on the ground until the item is removed from the user." A user holding an Iron Ball is not immune to
|
|
/// Ground-type moves despite the active effect.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeEffectiveness_OwnerHoldingIronBall_GroundMovesStillHit()
|
|
{
|
|
// Arrange
|
|
var effect = new MagnetRiseEffect();
|
|
var incomingMove = CreateIncomingMove("ground");
|
|
var owner = Substitute.For<IPokemon>();
|
|
owner.HasHeldItem("iron_ball").Returns(true);
|
|
incomingMove.User.Returns(owner);
|
|
var effectiveness = 1.0f;
|
|
|
|
// Act
|
|
effect.ChangeEffectiveness(incomingMove, owner, 0, ref effectiveness);
|
|
|
|
// Assert
|
|
await Assert.That(effectiveness).IsEqualTo(1.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The user becomes immune to Ground-type attacks for five turns." The turn Magnet Rise is
|
|
/// used counts as the first turn, so after five end-of-turn ticks the effect must have removed itself
|
|
/// from the user.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnEndTurn_AfterFiveEndOfTurns_EffectHasEnded()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user, userVolatile, _) = CreateTestSetup();
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
var effect = userVolatile.Get<MagnetRiseEffect>()!;
|
|
var battle = Substitute.For<IBattle>();
|
|
|
|
// Act - five end-of-turn ticks, the duration of the effect
|
|
for (var i = 0; i < 5; i++)
|
|
effect.OnEndTurn(user, battle);
|
|
|
|
// Assert
|
|
await Assert.That(userVolatile.Contains("magnet_rise")).IsFalse();
|
|
}
|
|
} |