218 lines
8.0 KiB
C#
218 lines
8.0 KiB
C#
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Dynamic.Models.Choices;
|
|
using PkmnLib.Dynamic.ScriptHandling;
|
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="DoublePowerIfTargetDamagedInTurn"/> script, which implements Assurance (and
|
|
/// the other moves whose power doubles when the target was already damaged this turn, such as Avalanche
|
|
/// and Revenge). Behavior is verified against the Bulbapedia page for Assurance:
|
|
/// "Assurance inflicts damage and will deal double damage if the target has already received damage on
|
|
/// the turn it is used."
|
|
/// </summary>
|
|
public class DoublePowerIfTargetDamagedInTurnTests
|
|
{
|
|
/// <summary>
|
|
/// Creates a fully mocked test setup where the target sits on side 0 whose volatile scripts are a
|
|
/// real <see cref="ScriptSet"/>.
|
|
/// </summary>
|
|
private static (DoublePowerIfTargetDamagedInTurn script, IExecutingMove move, IPokemon target, ScriptSet sideScripts
|
|
) CreateTestSetup()
|
|
{
|
|
var script = new DoublePowerIfTargetDamagedInTurn();
|
|
var move = Substitute.For<IExecutingMove>();
|
|
|
|
var side = Substitute.For<IBattleSide>();
|
|
var sideScripts = new ScriptSet(side);
|
|
side.VolatileScripts.Returns(sideScripts);
|
|
side.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
|
var battle = Substitute.For<IBattle>();
|
|
battle.Sides.Returns(new[] { side });
|
|
|
|
var user = Substitute.For<IPokemon>();
|
|
var userBattleData = Substitute.For<IPokemonBattleData>();
|
|
userBattleData.Battle.Returns(battle);
|
|
user.BattleData.Returns(userBattleData);
|
|
move.User.Returns(user);
|
|
|
|
var target = Substitute.For<IPokemon>();
|
|
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
|
targetBattleData.Battle.Returns(battle);
|
|
targetBattleData.SideIndex.Returns((byte)0);
|
|
target.BattleData.Returns(targetBattleData);
|
|
|
|
return (script, move, target, sideScripts);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "will deal double damage if the target has already received damage on the turn it is
|
|
/// used." Before the turn starts, a tracking script is placed on the targeted side to record which
|
|
/// Pokémon take damage this turn.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnBeforeTurnStart_MoveChoice_AddsTrackingDataToTargetSide()
|
|
{
|
|
// Arrange
|
|
var (script, move, _, sideScripts) = CreateTestSetup();
|
|
var user = move.User;
|
|
var choice = Substitute.For<IMoveChoice>();
|
|
choice.User.Returns(user);
|
|
choice.TargetSide.Returns((byte)0);
|
|
|
|
// Act
|
|
script.OnBeforeTurnStart(choice);
|
|
|
|
// Assert
|
|
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<DoublePowerIfTargetDamagedInTurnData>()))
|
|
.IsTrue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: a non-move turn choice (e.g. a switch) does not place the tracking script.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnBeforeTurnStart_NonMoveChoice_DoesNotAddTrackingData()
|
|
{
|
|
// Arrange
|
|
var (script, _, _, sideScripts) = CreateTestSetup();
|
|
var choice = Substitute.For<ITurnChoice>();
|
|
|
|
// Act
|
|
script.OnBeforeTurnStart(choice);
|
|
|
|
// Assert
|
|
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<DoublePowerIfTargetDamagedInTurnData>()))
|
|
.IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "will deal double damage if the target has already received damage on the turn it is
|
|
/// used." When the tracking data recorded the target as hit this turn, the base power doubles.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeBasePower_TargetDamagedThisTurn_BasePowerDoubles()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, sideScripts) = CreateTestSetup();
|
|
var data = new DoublePowerIfTargetDamagedInTurnData();
|
|
sideScripts.Add(data);
|
|
data.OnDamage(target, DamageSource.MoveDamage, 100, 80);
|
|
ushort basePower = 60;
|
|
|
|
// Act
|
|
script.ChangeBasePower(move, target, 0, ref basePower);
|
|
|
|
// Assert
|
|
await Assert.That(basePower).IsEqualTo((ushort)120);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: the power only doubles "if the target has already received damage on the turn it is
|
|
/// used." An undamaged target takes regular base power.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeBasePower_TargetNotDamagedThisTurn_BasePowerUnchanged()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, sideScripts) = CreateTestSetup();
|
|
sideScripts.Add(new DoublePowerIfTargetDamagedInTurnData());
|
|
ushort basePower = 60;
|
|
|
|
// Act
|
|
script.ChangeBasePower(move, target, 0, ref basePower);
|
|
|
|
// Assert
|
|
await Assert.That(basePower).IsEqualTo((ushort)60);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: only damage to the target itself counts. Damage recorded for a different Pokémon on
|
|
/// the same side does not double the power against this target.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeBasePower_OtherPokemonDamagedThisTurn_BasePowerUnchanged()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, sideScripts) = CreateTestSetup();
|
|
var data = new DoublePowerIfTargetDamagedInTurnData();
|
|
sideScripts.Add(data);
|
|
data.OnDamage(Substitute.For<IPokemon>(), DamageSource.MoveDamage, 100, 80);
|
|
ushort basePower = 60;
|
|
|
|
// Act
|
|
script.ChangeBasePower(move, target, 0, ref basePower);
|
|
|
|
// Assert
|
|
await Assert.That(basePower).IsEqualTo((ushort)60);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "This includes self-inflicted and indirect damage, such as damage from a Life Orb,
|
|
/// recoil, crash damage, or hurting itself in confusion." Any damage source recorded by the tracking
|
|
/// data counts.
|
|
/// </summary>
|
|
[Test, Arguments(DamageSource.Misc), Arguments(DamageSource.Confusion)]
|
|
public async Task ChangeBasePower_TargetTookIndirectDamage_BasePowerDoubles(DamageSource source)
|
|
{
|
|
// Arrange
|
|
var (script, move, target, sideScripts) = CreateTestSetup();
|
|
var data = new DoublePowerIfTargetDamagedInTurnData();
|
|
sideScripts.Add(data);
|
|
data.OnDamage(target, source, 100, 90);
|
|
ushort basePower = 60;
|
|
|
|
// Act
|
|
script.ChangeBasePower(move, target, 0, ref basePower);
|
|
|
|
// Assert
|
|
await Assert.That(basePower).IsEqualTo((ushort)120);
|
|
}
|
|
|
|
/// <summary>
|
|
/// The damage tracking only spans a single turn: at the end of the turn the tracking data removes
|
|
/// itself, so damage from a previous turn cannot double the power.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnEndTurn_TurnEnds_TrackingDataRemovesItself()
|
|
{
|
|
// Arrange
|
|
var (_, _, _, sideScripts) = CreateTestSetup();
|
|
var data = new DoublePowerIfTargetDamagedInTurnData();
|
|
sideScripts.Add(data);
|
|
var battle = Substitute.For<IBattle>();
|
|
|
|
// Act
|
|
data.OnEndTurn(Substitute.For<IBattleSide>(), battle);
|
|
|
|
// Assert
|
|
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<DoublePowerIfTargetDamagedInTurnData>()))
|
|
.IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: without battle data on the user (outside of battle) the base power is unchanged
|
|
/// and nothing throws.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeBasePower_UserHasNoBattleData_BasePowerUnchanged()
|
|
{
|
|
// Arrange
|
|
var script = new DoublePowerIfTargetDamagedInTurn();
|
|
var move = Substitute.For<IExecutingMove>();
|
|
var user = Substitute.For<IPokemon>();
|
|
user.BattleData.Returns((IPokemonBattleData?)null);
|
|
move.User.Returns(user);
|
|
var target = Substitute.For<IPokemon>();
|
|
ushort basePower = 60;
|
|
|
|
// Act
|
|
script.ChangeBasePower(move, target, 0, ref basePower);
|
|
|
|
// Assert
|
|
await Assert.That(basePower).IsEqualTo((ushort)60);
|
|
}
|
|
} |