using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.Models.Choices; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static.Species; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: "Core Enforcer deals damage. If the target has already used a move or had /// a Bag item used on it by its Trainer in the same turn, Core Enforcer also suppresses the target's /// Ability while it remains in battle." /// public class CoreEnforcerTests { private static (CoreEnforcer script, IExecutingMove move, IMoveChoice currentChoice, IPokemon target, IHitData hitData, IBattle battle) CreateTestSetup() { var script = new CoreEnforcer(); var battle = Substitute.For(); var battleData = Substitute.For(); battleData.Battle.Returns(battle); var target = Substitute.For(); target.BattleData.Returns(battleData); var currentChoice = Substitute.For(); var move = Substitute.For(); move.MoveChoice.Returns(currentChoice); var hitData = Substitute.For(); move.GetHitData(target, 0).Returns(hitData); return (script, move, currentChoice, target, hitData, battle); } private static void SetTurnChoices(IBattle battle, params ITurnChoice[] choices) { battle.PreviousTurnChoices.Returns(new List> { choices }); } /// /// Bulbapedia: "If the target has already used a move [...] in the same turn, Core Enforcer also /// suppresses the target's Ability while it remains in battle." /// [Test] public void OnSecondaryEffect_TargetMovedEarlierInTurn_SuppressesTargetAbility() { // Arrange var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup(); var targetChoice = Substitute.For(); targetChoice.User.Returns(target); SetTurnChoices(battle, targetChoice, currentChoice); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.Received(1).SuppressAbility(); hitData.DidNotReceive().Fail(); } /// /// Bulbapedia: the suppression also happens if the target "had a Bag item used on it by its Trainer in /// the same turn". /// [Test] public void OnSecondaryEffect_ItemUsedEarlierInTurn_SuppressesTargetAbility() { // Arrange var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup(); var itemChoice = Substitute.For(); itemChoice.User.Returns(target); SetTurnChoices(battle, itemChoice, currentChoice); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.Received(1).SuppressAbility(); hitData.DidNotReceive().Fail(); } /// /// Bulbapedia: the Ability is only suppressed "If the target has already used a move [...] in the same /// turn" — when Core Enforcer strikes before the target has acted, no suppression happens. /// [Test] public void OnSecondaryEffect_TargetActsLaterInTurn_DoesNotSuppressAbility() { // Arrange var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup(); var targetChoice = Substitute.For(); targetChoice.User.Returns(target); SetTurnChoices(battle, currentChoice, targetChoice); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.DidNotReceive().SuppressAbility(); hitData.Received(1).Fail(); } /// /// Bulbapedia: suppression requires the target to have already acted — as the very first action of the /// turn, Core Enforcer never suppresses. /// [Test] public void OnSecondaryEffect_CoreEnforcerIsFirstActionOfTurn_DoesNotSuppressAbility() { // Arrange var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup(); SetTurnChoices(battle, currentChoice); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.DidNotReceive().SuppressAbility(); hitData.Received(1).Fail(); } /// /// Technical test: a target without battle data (not in battle) is left untouched. /// [Test] public void OnSecondaryEffect_TargetHasNoBattleData_DoesNothing() { // Arrange var (script, move, _, target, hitData, _) = CreateTestSetup(); target.BattleData.Returns((IPokemonBattleData?)null); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.DidNotReceive().SuppressAbility(); hitData.DidNotReceive().Fail(); } /// /// Bulbapedia: the condition is that "the target has already used a move" — an action by a different /// Pokémon (e.g. the user's ally in a Double Battle) does not count as the target having acted. /// [Test] public void OnSecondaryEffect_OnlyOtherPokemonActedEarlier_DoesNotSuppressAbility() { // Arrange var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup(); var allyChoice = Substitute.For(); allyChoice.User.Returns(Substitute.For()); SetTurnChoices(battle, allyChoice, currentChoice); // Act script.OnSecondaryEffect(move, target, 0); // Assert target.DidNotReceive().SuppressAbility(); hitData.Received(1).Fail(); } /// /// Bulbapedia: "The move cannot suppress certain signature abilities including Multitype, Stance /// Change, Schooling, Comatose, Shields Down, Disguise, RKS System, Battle Bond, Power Construct". /// The script requests the suppression unconditionally; refuses /// it when is false, so these abilities must carry that flag in the /// Gen7 data. /// [Test, Arguments("multitype"), Arguments("stance_change"), Arguments("schooling"), Arguments("comatose"), Arguments("shields_down"), Arguments("disguise"), Arguments("rks_system"), Arguments("battle_bond"), Arguments("power_construct")] public async Task OnSecondaryEffect_UnsuppressableAbility_IsProtectedByAbilityData(string abilityName) { // Arrange var library = LibraryHelpers.LoadLibrary(); // Assert await Assert.That(library.StaticLibrary.Abilities.TryGet(new StringKey(abilityName), out var ability)).IsTrue(); await Assert.That(ability!.CanBeChanged).IsFalse(); } }