198 lines
7.1 KiB
C#
198 lines
7.1 KiB
C#
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Dynamic.ScriptHandling;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Abilities;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Static.Species;
|
|
using PkmnLib.Static.Utils;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="DreamEater"/> move script.
|
|
/// Gen VII Bulbapedia behavior: "Dream Eater only works if the target is asleep; otherwise, it does
|
|
/// nothing", and "50% of the damage dealt to the target is restored to the user as HP".
|
|
/// </summary>
|
|
public class DreamEaterTests
|
|
{
|
|
/// <summary>
|
|
/// Creates a fully mocked test setup for Dream Eater tests.
|
|
/// </summary>
|
|
private static (DreamEater script, IExecutingMove move, IPokemon target, IPokemon user) CreateTestSetup(uint damage,
|
|
bool holdsBigRoot = false, Script[]? targetScripts = null)
|
|
{
|
|
var script = new DreamEater();
|
|
var move = Substitute.For<IExecutingMove>();
|
|
var target = Substitute.For<IPokemon>();
|
|
var hitData = Substitute.For<IHitData>();
|
|
hitData.Damage.Returns(damage);
|
|
move.GetHitData(target, 0).Returns(hitData);
|
|
|
|
// RunScriptHook iterates the target's scripts; give the mock a real iterator so the
|
|
// hook pass runs (empty unless the test attaches scripts such as Liquid Ooze).
|
|
var containers = (targetScripts ?? []).Select(IEnumerable<ScriptContainer> (s) => new ScriptContainer(s))
|
|
.ToArray();
|
|
target.GetScripts().Returns(_ => new ScriptIterator(containers));
|
|
|
|
var user = Substitute.For<IPokemon>();
|
|
if (holdsBigRoot)
|
|
user.HasHeldItem("big_root").Returns(true);
|
|
move.User.Returns(user);
|
|
|
|
return (script, move, target, user);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper to extract the heal amount from the user's received Heal calls.
|
|
/// </summary>
|
|
private static uint? GetHealAmount(IPokemon user)
|
|
{
|
|
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Heal");
|
|
return call != null ? (uint)call.GetArguments()[0]! : null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Dream Eater only works if the target is asleep; otherwise, it does nothing."
|
|
/// The outgoing hit is blocked when the target does not have the sleep status.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task BlockOutgoingHit_TargetNotAsleep_BlocksHit()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _) = CreateTestSetup(100);
|
|
target.HasStatus(new StringKey("asleep")).Returns(false);
|
|
var block = false;
|
|
|
|
// Act
|
|
script.BlockOutgoingHit(move, target, 0, ref block);
|
|
|
|
// Assert
|
|
await Assert.That(block).IsTrue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Dream Eater only works if the target is asleep". A sleeping target can be hit.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task BlockOutgoingHit_TargetAsleep_DoesNotBlockHit()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _) = CreateTestSetup(100);
|
|
target.HasStatus(new StringKey("asleep")).Returns(true);
|
|
var block = false;
|
|
|
|
// Act
|
|
script.BlockOutgoingHit(move, target, 0, ref block);
|
|
|
|
// Assert
|
|
await Assert.That(block).IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Dream Eater also affects targets with the Comatose Ability, which act as though they
|
|
/// are asleep without the status condition."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task BlockOutgoingHit_TargetHasComatose_DoesNotBlockHit()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _) = CreateTestSetup(100);
|
|
target.HasStatus(new StringKey("asleep")).Returns(false);
|
|
var comatose = Substitute.For<IAbility>();
|
|
comatose.Name.Returns(new StringKey("comatose"));
|
|
target.ActiveAbility.Returns(comatose);
|
|
var block = false;
|
|
|
|
// Act
|
|
script.BlockOutgoingHit(move, target, 0, ref block);
|
|
|
|
// Assert
|
|
await Assert.That(block).IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "50% of the damage dealt to the target is restored to the user as HP".
|
|
/// </summary>
|
|
[Test, Arguments(100u, 50u), Arguments(200u, 100u), Arguments(51u, 25u), Arguments(99u, 49u)]
|
|
public async Task OnSecondaryEffect_DamageDealt_UserHealsHalfOfDamage(uint damage, uint expectedHeal)
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user) = CreateTestSetup(damage);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(GetHealAmount(user)!.Value).IsEqualTo(expectedHeal);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "if the attack deals 1 HP of damage, 1 HP will be restored to the user."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_DamageOfOne_HealsAtLeastOneHp()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user) = CreateTestSetup(1);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(GetHealAmount(user)!.Value).IsEqualTo(1u);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "If the user is holding a Big Root, the HP restored is increased by 30% (making the
|
|
/// restored HP 65% of the damage dealt)."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_UserHoldingBigRoot_HealIncreasedByThirtyPercent()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user) = CreateTestSetup(100, true);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert - 65% of 100 damage
|
|
await Assert.That(GetHealAmount(user)!.Value).IsEqualTo(65u);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "When used on a Pokémon with the Liquid Ooze Ability, the user will lose the amount of
|
|
/// HP it would have gained instead."
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_TargetHasLiquidOoze_UserLosesHpInsteadOfHealing()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user) = CreateTestSetup(100, targetScripts: [new LiquidOoze()]);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert - user takes the 50 HP it would have gained, and is not healed
|
|
var damageCall = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
|
await Assert.That(damageCall).IsNotNull();
|
|
await Assert.That((uint)damageCall!.GetArguments()[0]!).IsEqualTo(50u);
|
|
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Heal")).IsFalse();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "the user will lose the amount of HP it would have gained instead." The HP loss caused
|
|
/// by Liquid Ooze is indirect damage, not move damage.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_TargetHasLiquidOoze_UsesMiscDamageSource()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, user) = CreateTestSetup(100, targetScripts: [new LiquidOoze()]);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
var damageCall = user.ReceivedCalls().First(c => c.GetMethodInfo().Name == "Damage");
|
|
await Assert.That((DamageSource)damageCall.GetArguments()[1]!).IsEqualTo(DamageSource.Misc);
|
|
}
|
|
} |