This commit is contained in:
158
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/LockOnTests.cs
Normal file
158
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/LockOnTests.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the <see cref="LockOn"/> move script and its volatile effect script
|
||||
/// <see cref="LockOnEffect"/>.
|
||||
/// Gen VII Bulbapedia behavior: "After the user has used Lock-On and until its effect ends (see table
|
||||
/// below), any accuracy check it makes against the same target will succeed; this means moves will not
|
||||
/// miss, even if the target is in the semi-invulnerable turn of a move such as Dig or Fly.", where the
|
||||
/// effect expires at the end of the next turn.
|
||||
/// </summary>
|
||||
public class LockOnTests
|
||||
{
|
||||
private static (LockOn script, IExecutingMove move, IPokemon user, IPokemon target, ScriptSet targetVolatile)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new LockOn();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
// Use a real script set so the volatile script added by Lock-On can be inspected afterwards, and so
|
||||
// that Script.RemoveSelf calls can be observed through IScriptSet.Contains.
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
|
||||
return (script, move, user, target, targetVolatile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "any accuracy check it makes against the same target will succeed" — the engine runs
|
||||
/// <see cref="IScriptChangeIncomingAccuracy"/> (which <see cref="LockOnEffect"/> implements) over the
|
||||
/// <em>defending</em> Pokémon's scripts, so the effect must be placed on the target for the guarantee
|
||||
/// to ever apply.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_Hit_AddsLockOnEffectToTarget()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, target, targetVolatile) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<LockOnEffect>())).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "moves will not miss" — an accuracy check by the Pokémon that placed the Lock-On against
|
||||
/// the locked-on target resolves to 255, which the accuracy calculation treats as a guaranteed hit.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeIncomingAccuracy_AttackByLockOnUser_AccuracyGuaranteed()
|
||||
{
|
||||
// Arrange
|
||||
var placer = Substitute.For<IPokemon>();
|
||||
var effect = new LockOnEffect(placer);
|
||||
var attack = Substitute.For<IExecutingMove>();
|
||||
attack.User.Returns(placer);
|
||||
var accuracy = 90;
|
||||
|
||||
// Act
|
||||
effect.ChangeIncomingAccuracy(attack, Substitute.For<IPokemon>(), 0, ref accuracy);
|
||||
|
||||
// Assert
|
||||
await Assert.That(accuracy).IsGreaterThanOrEqualTo(255);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: it is the accuracy checks of "the user" of Lock-On that are guaranteed — a move used by
|
||||
/// any other Pokémon against the locked-on target is not affected.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeIncomingAccuracy_AttackByOtherPokemon_AccuracyUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var placer = Substitute.For<IPokemon>();
|
||||
var effect = new LockOnEffect(placer);
|
||||
var attack = Substitute.For<IExecutingMove>();
|
||||
attack.User.Returns(Substitute.For<IPokemon>());
|
||||
var accuracy = 90;
|
||||
|
||||
// Act
|
||||
effect.ChangeIncomingAccuracy(attack, Substitute.For<IPokemon>(), 0, ref accuracy);
|
||||
|
||||
// Assert
|
||||
await Assert.That(accuracy).IsEqualTo(90);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "After the user has used Lock-On [...] any accuracy check it makes against the same
|
||||
/// target will succeed" — the effect applied by the move must record the move's <em>user</em> as the
|
||||
/// placer, so that that user's subsequent accuracy checks against the target are the guaranteed ones.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_AppliedEffect_GuaranteesUsersAccuracyAgainstTarget()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, target, targetVolatile) = CreateTestSetup();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
await Assert.That(targetVolatile.TryGet<LockOnEffect>(out var effect)).IsTrue();
|
||||
|
||||
// Act - the placer attacks the locked-on target
|
||||
var accuracy = 90;
|
||||
effect!.ChangeIncomingAccuracy(move, target, 0, ref accuracy);
|
||||
|
||||
// Assert
|
||||
await Assert.That(accuracy).IsGreaterThanOrEqualTo(255);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the effect expires at the end of the next turn — at the end of the turn Lock-On was
|
||||
/// used the effect must still be active, so that the move used on the following turn cannot miss.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnEndTurn_EndOfTurnUsed_EffectStillActive()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, target, targetVolatile) = CreateTestSetup();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
await Assert.That(targetVolatile.TryGet<LockOnEffect>(out var effect)).IsTrue();
|
||||
|
||||
// Act - the end of the turn Lock-On was used
|
||||
effect!.OnEndTurn(Substitute.For<IScriptSource>(), Substitute.For<IBattle>());
|
||||
|
||||
// Assert
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<LockOnEffect>())).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the effect expires at the end of the next turn — after two end-of-turns the effect is
|
||||
/// gone.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnEndTurn_EndOfNextTurn_EffectExpires()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, target, targetVolatile) = CreateTestSetup();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
await Assert.That(targetVolatile.TryGet<LockOnEffect>(out var effect)).IsTrue();
|
||||
|
||||
// Act - end of the turn Lock-On was used, and end of the next turn
|
||||
effect!.OnEndTurn(Substitute.For<IScriptSource>(), Substitute.For<IBattle>());
|
||||
effect.OnEndTurn(Substitute.For<IScriptSource>(), Substitute.For<IBattle>());
|
||||
|
||||
// Assert
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<LockOnEffect>())).IsFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user