From b671adf85f3e0af3f2efd3c477fcb3440cbcc68b Mon Sep 17 00:00:00 2001 From: GGbond Date: Sun, 11 Jan 2026 23:02:41 +0800 Subject: [PATCH] Fixes Nightmare not affecting Comatose and adds various missing tests (#8859) --- data/battle_scripts_1.s | 4 +- src/battle_ai_switch_items.c | 2 +- src/battle_ai_util.c | 6 +- src/battle_end_turn.c | 2 +- src/battle_main.c | 2 +- src/battle_util.c | 6 +- test/battle/ability/anticipation.c | 12 +- test/battle/ability/arena_trap.c | 146 +++++++- test/battle/ability/chlorophyll.c | 1 + test/battle/ability/comatose.c | 92 ++++- test/battle/ability/contrary.c | 20 +- test/battle/ability/costar.c | 59 +++- test/battle/ability/cud_chew.c | 26 +- test/battle/ability/cursed_body.c | 46 ++- test/battle/ability/dancer.c | 470 ++++++++++++++++++++++++-- test/battle/ability/dazzling.c | 156 ++++++++- test/battle/ability/disguise.c | 19 +- test/battle/ability/dry_skin.c | 46 ++- test/battle/ability/flower_gift.c | 40 ++- test/battle/ability/flower_veil.c | 20 +- test/battle/ability/protosynthesis.c | 1 + test/battle/ability/swift_swim.c | 57 +++- test/battle/hold_effect/cure_status.c | 24 +- test/battle/move_effect/hydro_steam.c | 1 + test/battle/move_effect/mist.c | 40 ++- test/battle/move_effect/nightmare.c | 38 ++- test/battle/move_effect/purify.c | 36 +- test/battle/move_effect/synthesis.c | 1 + 28 files changed, 1295 insertions(+), 78 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index b7abe25190..6b4b18f48a 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3336,9 +3336,9 @@ BattleScript_EffectMeanLook:: accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifvolatile BS_TARGET, VOLATILE_ESCAPE_PREVENTION, BattleScript_ButItFailed jumpifsubstituteblocks BattleScript_ButItFailed -.if B_GHOSTS_ESCAPE >= GEN_6 + jumpifgenconfiglowerthan CONFIG_GHOSTS_ESCAPE, GEN_6, BattleScript_EffectMeanLookGen5 jumpiftype BS_TARGET, TYPE_GHOST, BattleScript_ButItFailed -.endif +BattleScript_EffectMeanLookGen5: attackanimation waitanimation seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_PREVENT_ESCAPE diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 80d05b12df..d1daded86e 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -2045,7 +2045,7 @@ static s32 GetMaxPriorityDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposi static bool32 CanAbilityTrapOpponent(enum Ability ability, u32 opponent) { - if ((B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST))) + if ((GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(opponent, TYPE_GHOST))) return FALSE; else if (ability == ABILITY_SHADOW_TAG) { diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9e728d5213..2420cd4328 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -474,7 +474,7 @@ bool32 AI_CanBattlerEscape(u32 battler) { enum HoldEffect holdEffect = gAiLogicData->holdEffects[battler]; - if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; if (holdEffect == HOLD_EFFECT_SHED_SHELL) return TRUE; @@ -3091,7 +3091,9 @@ static u32 GetLeechSeedDamage(u32 battler) static u32 GetNightmareDamage(u32 battlerId) { u32 damage = 0; - if (gBattleMons[battlerId].volatiles.nightmare && gBattleMons[battlerId].status1 & STATUS1_SLEEP) + if (gBattleMons[battlerId].volatiles.nightmare + && ((gBattleMons[battlerId].status1 & STATUS1_SLEEP) + || gAiLogicData->abilities[battlerId] == ABILITY_COMATOSE)) { damage = GetNonDynamaxMaxHP(battlerId) / 4; if (damage == 0) diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index 2e6c7159ee..096b307b8b 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -574,7 +574,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { - if (gBattleMons[battler].status1 & STATUS1_SLEEP) + if (gBattleMons[battler].status1 & STATUS1_SLEEP || GetBattlerAbility(battler) == ABILITY_COMATOSE) { SetPassiveDamageAmount(battler, GetNonDynamaxMaxHP(battler) / 4); BattleScriptExecute(BattleScript_NightmareTurnDmg); diff --git a/src/battle_main.c b/src/battle_main.c index c54323c826..c823f61634 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4106,7 +4106,7 @@ u8 IsRunningFromBattleImpossible(u32 battler) if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN) return BATTLE_RUN_SUCCESS; - if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return BATTLE_RUN_SUCCESS; if (gBattleTypeFlags & BATTLE_TYPE_LINK) return BATTLE_RUN_SUCCESS; diff --git a/src/battle_util.c b/src/battle_util.c index 5493354f0c..10c80a4130 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -695,7 +695,7 @@ bool32 TryRunFromBattle(u32 battler) gProtectStructs[battler].fleeType = FLEE_ITEM; effect++; } - else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + else if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) { effect++; } @@ -5804,7 +5804,7 @@ u32 IsAbilityOnFieldExcept(u32 battler, enum Ability ability) u32 IsAbilityPreventingEscape(u32 battler) { - if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return 0; bool32 isBattlerGrounded = IsBattlerGrounded(battler, GetBattlerAbility(battler), GetBattlerHoldEffect(battler)); @@ -5832,7 +5832,7 @@ bool32 CanBattlerEscape(u32 battler) // no ability check { if (gBattleStruct->battlerState[battler].commanderSpecies != SPECIES_NONE) return FALSE; - else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + else if (GetConfig(CONFIG_GHOSTS_ESCAPE) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; else if (gBattleMons[battler].volatiles.escapePrevention) return FALSE; diff --git a/test/battle/ability/anticipation.c b/test/battle/ability/anticipation.c index d23cb0c6a5..c20153b1ea 100644 --- a/test/battle/ability/anticipation.c +++ b/test/battle/ability/anticipation.c @@ -75,12 +75,16 @@ SINGLE_BATTLE_TEST("Anticipation doesn't consider Scrappy into their effectivene ASSUME(GetMoveType(MOVE_CLOSE_COMBAT) == TYPE_FIGHTING); ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 0) == TYPE_STEEL); ASSUME(GetSpeciesType(SPECIES_DOUBLADE, 1) == TYPE_GHOST); - PLAYER(SPECIES_DOUBLADE) { Ability(ABILITY_ANTICIPATION); } - OPPONENT(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_CELEBRATE); } + PLAYER(SPECIES_WORMADAM_TRASH) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_SKILL_SWAP, MOVE_CELEBRATE); } + PLAYER(SPECIES_KANGASKHAN) { Ability(ABILITY_SCRAPPY); Moves(MOVE_CLOSE_COMBAT, MOVE_CELEBRATE); } + OPPONENT(SPECIES_DOUBLADE) { Ability(ABILITY_NO_GUARD); Moves(MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN {} + TURN { MOVE(player, MOVE_SKILL_SWAP, target: opponent); MOVE(opponent, MOVE_CELEBRATE); } + TURN { SWITCH(player, 1); SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } } SCENE { - NOT ABILITY_POPUP(player, ABILITY_ANTICIPATION); + NOT ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); } } diff --git a/test/battle/ability/arena_trap.c b/test/battle/ability/arena_trap.c index ef0d5b7d8c..0412b8f359 100644 --- a/test/battle/ability/arena_trap.c +++ b/test/battle/ability/arena_trap.c @@ -1,11 +1,141 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Arena Trap prevents grounded adjacent opponents from switching out"); -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs if the Pokémon is switched in the same turn the opponent decided to switch out"); -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs via moves that switch out"); // Baton Pass, U-Turn, Volt Switch, Flip Turn, Parting Shot -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs via Shed Shell, but not via Teleport"); -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs via Run Away"); -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs via Smoke Ball"); -TO_DO_BATTLE_TEST("Arena Trap prevents switch outs from Ghost-type Pokémon (Gen3-5)"); -TO_DO_BATTLE_TEST("Arena Trap doesn't prevent switch outs from Ghost-type Pokémon (Gen6+)"); +SINGLE_BATTLE_TEST("Arena Trap prevents grounded adjacent opponents from switching out") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } THEN { + u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + u32 trapper = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + EXPECT_EQ(IsAbilityPreventingEscape(battler), trapper + 1); + } +} + +SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs if the Pokémon is switched in the same turn the opponent decided to switch out") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WYNAUT) { Speed(10); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); Speed(5); } + } WHEN { + TURN { SWITCH(player, 1); SWITCH(opponent, 1); } + } SCENE { + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Wynaut"); + } THEN { + EXPECT_EQ(player->species, SPECIES_WYNAUT); + EXPECT_EQ(opponent->species, SPECIES_DIGLETT); + } +} + +SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs via moves that switch out") +{ + u16 move, effect; + PARAMETRIZE { move = MOVE_BATON_PASS; effect = EFFECT_BATON_PASS; } + PARAMETRIZE { move = MOVE_U_TURN; effect = EFFECT_HIT_ESCAPE; } + PARAMETRIZE { move = MOVE_VOLT_SWITCH; effect = EFFECT_HIT_ESCAPE; } + PARAMETRIZE { move = MOVE_FLIP_TURN; effect = EFFECT_HIT_ESCAPE; } + PARAMETRIZE { move = MOVE_PARTING_SHOT; effect = EFFECT_PARTING_SHOT; } + PARAMETRIZE { move = MOVE_TELEPORT; effect = EFFECT_TELEPORT; } + PARAMETRIZE { move = MOVE_SHED_TAIL; effect = EFFECT_SHED_TAIL; } + PARAMETRIZE { move = MOVE_CHILLY_RECEPTION; effect = EFFECT_CHILLY_RECEPTION; } + GIVEN { + ASSUME(GetMoveEffect(move) == effect); + ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK); + WITH_CONFIG(CONFIG_TELEPORT_BEHAVIOR, GEN_8); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + if (move == MOVE_VOLT_SWITCH) + TURN { MOVE(player, MOVE_SOAK); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, move); SEND_OUT(player, 1); } + } SCENE { + if (move == MOVE_VOLT_SWITCH) + ANIMATION(ANIM_TYPE_MOVE, MOVE_SOAK, player); + ANIMATION(ANIM_TYPE_MOVE, move, player); + SEND_IN_MESSAGE("Wynaut"); + } +} + +SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs via Shed Shell") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_SHED_SHELL].holdEffect == HOLD_EFFECT_SHED_SHELL); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHED_SHELL); } // Grounded + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Wynaut"); + } +} + +WILD_BATTLE_TEST("Arena Trap prevents switching but Run Away allows fleeing") +{ + GIVEN { + PLAYER(SPECIES_RATTATA) { Ability(ABILITY_RUN_AWAY); } + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } THEN { + u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + u32 trapper = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + EXPECT_EQ(IsAbilityPreventingEscape(battler), trapper + 1); + EXPECT_EQ(IsRunningFromBattleImpossible(battler), BATTLE_RUN_SUCCESS); + } +} + +WILD_BATTLE_TEST("Arena Trap prevents switching but Smoke Ball allows fleeing") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_SMOKE_BALL].holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SMOKE_BALL); } + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } THEN { + u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + u32 trapper = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + EXPECT_EQ(IsAbilityPreventingEscape(battler), trapper + 1); + EXPECT_EQ(IsRunningFromBattleImpossible(battler), BATTLE_RUN_SUCCESS); + } +} + +SINGLE_BATTLE_TEST("Arena Trap prevents switch outs from Ghost-type Pokémon (Gen3-5)") +{ + GIVEN { + ASSUME(GetSpeciesType(SPECIES_SHUPPET, 0) == TYPE_GHOST); + WITH_CONFIG(CONFIG_GHOSTS_ESCAPE, GEN_5); + PLAYER(SPECIES_SHUPPET); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } THEN { + u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + u32 trapper = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + EXPECT_EQ(IsAbilityPreventingEscape(battler), trapper + 1); + } +} + +SINGLE_BATTLE_TEST("Arena Trap doesn't prevent switch outs from Ghost-type Pokémon (Gen6+)") +{ + GIVEN { + ASSUME(GetSpeciesType(SPECIES_SHUPPET, 0) == TYPE_GHOST); + WITH_CONFIG(CONFIG_GHOSTS_ESCAPE, GEN_6); + PLAYER(SPECIES_SHUPPET); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } THEN { + u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + EXPECT_EQ(IsAbilityPreventingEscape(battler), 0); + } +} diff --git a/test/battle/ability/chlorophyll.c b/test/battle/ability/chlorophyll.c index 84546dbe4c..66f7b9ccc9 100644 --- a/test/battle/ability/chlorophyll.c +++ b/test/battle/ability/chlorophyll.c @@ -36,6 +36,7 @@ SINGLE_BATTLE_TEST("Chlorophyll doesn't double speed if Cloud Nine/Air Lock is o SINGLE_BATTLE_TEST("Chlorophyll doesn't double speed if they have an Utility Umbrella") { GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); PLAYER(SPECIES_VENUSAUR) { Ability(ABILITY_CHLOROPHYLL); Speed(100); Item(ITEM_UTILITY_UMBRELLA); } OPPONENT(SPECIES_WOBBUFFET) { Speed(199); } } WHEN { diff --git a/test/battle/ability/comatose.c b/test/battle/ability/comatose.c index c049d5624d..3d20df3449 100644 --- a/test/battle/ability/comatose.c +++ b/test/battle/ability/comatose.c @@ -88,7 +88,91 @@ SINGLE_BATTLE_TEST("Comatose Pokémon don't get poisoned by Toxic Spikes on swit } } -TO_DO_BATTLE_TEST("Comatose makes Rest fail") -TO_DO_BATTLE_TEST("Comatose isn't affected by Mold Breaker, Turboblaze or Teravolt") -TO_DO_BATTLE_TEST("Comatose isn't affected by Poison Touch + Sunsteel Strike") -TO_DO_BATTLE_TEST("Comatose boosts Dream Ball's multiplier") +SINGLE_BATTLE_TEST("Comatose makes Rest fail") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); + PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); HP(1); MaxHP(100); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + HP_BAR(player); + } + } THEN { + EXPECT_EQ(player->hp, 1); + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Comatose isn't affected by Mold Breaker, Turboblaze or Teravolt") +{ + enum Ability ability; + u16 species; + + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; species = SPECIES_PINSIR; } + PARAMETRIZE { ability = ABILITY_TURBOBLAZE; species = SPECIES_RESHIRAM; } + PARAMETRIZE { ability = ABILITY_TERAVOLT; species = SPECIES_ZEKROM; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_TOXIC) == MOVE_EFFECT_TOXIC); + PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_TOXIC); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, opponent); + ABILITY_POPUP(player, ABILITY_COMATOSE); + MESSAGE("It doesn't affect Komala…"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Comatose isn't affected by Poison Touch + Sunsteel Strike") +{ + GIVEN { + ASSUME(MoveIgnoresTargetAbility(MOVE_SUNSTEEL_STRIKE)); + ASSUME(MoveMakesContact(MOVE_SUNSTEEL_STRIKE)); + PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); } + OPPONENT(SPECIES_CROAGUNK) { Ability(ABILITY_POISON_TOUCH); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUNSTEEL_STRIKE, WITH_RNG(RNG_POISON_TOUCH, 1)); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNSTEEL_STRIKE, opponent); + HP_BAR(player); + NOT STATUS_ICON(player, poison: TRUE); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +WILD_BATTLE_TEST("Comatose boosts Dream Ball's multiplier") +{ + enum Ability ability; + u16 species; + bool32 shouldCatch; + const u16 rng = 50000; + + PARAMETRIZE { species = SPECIES_KOMALA; ability = ABILITY_COMATOSE; shouldCatch = TRUE; } + PARAMETRIZE { species = SPECIES_MIMIKYU; ability = ABILITY_DISGUISE; shouldCatch = FALSE; } + + GIVEN { + ASSUME(B_DREAM_BALL_MODIFIER >= GEN_8); + ASSUME(gSpeciesInfo[species].catchRate == 45); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); MaxHP(100); HP(1); } + } WHEN { + TURN { USE_ITEM(player, ITEM_DREAM_BALL, WITH_RNG(RNG_BALLTHROW_SHAKE, rng)); } + } SCENE { + ANIMATION(ANIM_TYPE_SPECIAL, B_ANIM_BALL_THROW, player); + } THEN { + if (shouldCatch) + EXPECT_EQ(gBattleResults.caughtMonSpecies, species); + else + EXPECT_EQ(gBattleResults.caughtMonSpecies, SPECIES_NONE); + } +} diff --git a/test/battle/ability/contrary.c b/test/battle/ability/contrary.c index 577affeecb..5cc0c2ad3f 100644 --- a/test/battle/ability/contrary.c +++ b/test/battle/ability/contrary.c @@ -269,4 +269,22 @@ AI_SINGLE_BATTLE_TEST("AI sees Contrary-effected moves correctly in MoveEffectIn } } -TO_DO_BATTLE_TEST("Contrary does not invert stat changes that have been Baton-passed") +SINGLE_BATTLE_TEST("Contrary does not invert stat changes that have been Baton-passed") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); } + } WHEN { + TURN { MOVE(opponent, MOVE_SWORDS_DANCE); } + TURN { MOVE(opponent, MOVE_BATON_PASS); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, opponent); + MESSAGE("2 sent out Snivy!"); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} diff --git a/test/battle/ability/costar.c b/test/battle/ability/costar.c index bc06ac26a7..09a6de4e9a 100644 --- a/test/battle/ability/costar.c +++ b/test/battle/ability/costar.c @@ -119,5 +119,60 @@ DOUBLE_BATTLE_TEST("Costar copies an ally's Dragon Cheer critical hit boost") } // Copy from Ruin ability tests -TO_DO_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Player"); -TO_DO_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Opponent"); +DOUBLE_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } + PLAYER(SPECIES_FLAMIGO) { Ability(ABILITY_COSTAR); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_EXPLOSION); + SEND_OUT(playerLeft, 2); + SEND_OUT(opponentLeft, 2); + SEND_OUT(playerRight, 3); + SEND_OUT(opponentRight, 3); + } + } SCENE { + MESSAGE("The opposing Wobbuffet used Explosion!"); + ABILITY_POPUP(playerLeft, ABILITY_INTREPID_SWORD); + MESSAGE("Zacian's Intrepid Sword raised its Attack!"); + ABILITY_POPUP(playerRight, ABILITY_COSTAR); + MESSAGE("Flamigo copied Zacian's stat changes!"); + } +} + +DOUBLE_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } + OPPONENT(SPECIES_FLAMIGO) { Ability(ABILITY_COSTAR); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_EXPLOSION); + SEND_OUT(playerLeft, 2); + SEND_OUT(opponentLeft, 2); + SEND_OUT(playerRight, 3); + SEND_OUT(opponentRight, 3); + } + } SCENE { + MESSAGE("Wobbuffet used Explosion!"); + ABILITY_POPUP(opponentLeft, ABILITY_INTREPID_SWORD); + MESSAGE("The opposing Zacian's Intrepid Sword raised its Attack!"); + ABILITY_POPUP(opponentRight, ABILITY_COSTAR); + MESSAGE("The opposing Flamigo copied the opposing Zacian's stat changes!"); + } +} diff --git a/test/battle/ability/cud_chew.c b/test/battle/ability/cud_chew.c index 809d9f1d7c..9f7c3902a9 100644 --- a/test/battle/ability/cud_chew.c +++ b/test/battle/ability/cud_chew.c @@ -48,4 +48,28 @@ SINGLE_BATTLE_TEST("Cud Chew will activate Oran Berry effect again on the next t } } -TO_DO_BATTLE_TEST("Cud Chew will activate Lum Berry effect again on the next turn") +SINGLE_BATTLE_TEST("Cud Chew will activate Lum Berry effect again on the next turn") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); + ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_THUNDER_WAVE) == MOVE_EFFECT_PARALYSIS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_TAUROS_PALDEA_COMBAT) { Ability(ABILITY_CUD_CHEW); Item(ITEM_LUM_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_THUNDER_WAVE); } + TURN { MOVE(player, MOVE_THUNDER_WAVE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + STATUS_ICON(opponent, paralysis: FALSE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + ABILITY_POPUP(opponent, ABILITY_CUD_CHEW); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + STATUS_ICON(opponent, paralysis: FALSE); + } +} diff --git a/test/battle/ability/cursed_body.c b/test/battle/ability/cursed_body.c index b3bc886a3d..82d2606ef1 100644 --- a/test/battle/ability/cursed_body.c +++ b/test/battle/ability/cursed_body.c @@ -87,6 +87,46 @@ SINGLE_BATTLE_TEST("Cursed Body does not stop a multistrike move mid-execution") } } -TO_DO_BATTLE_TEST("Cursed Body disables the move that called another move instead of the called move") -TO_DO_BATTLE_TEST("Cursed Body disables damaging Z-Moves, but not the base move") // Rotom Powers can restore Z-Moves -TO_DO_BATTLE_TEST("Cursed Body disables the base move of a status Z-Move") +SINGLE_BATTLE_TEST("Cursed Body disables the move that called another move instead of the called move") +{ + PASSES_RANDOMLY(3, 10, RNG_CURSED_BODY); + GIVEN { + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); + ASSUME(GetMoveType(MOVE_SHADOW_BALL) == TYPE_GHOST); + ASSUME(IsMoveSleepTalkBanned(MOVE_FLY)); + ASSUME(IsMoveSleepTalkBanned(MOVE_DIG)); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_SHADOW_BALL, MOVE_FLY, MOVE_DIG); } + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_SLEEP_TALK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SLEEP_TALK, player); + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Sleep Talk was disabled by the opposing Frillish's Cursed Body!"); + } THEN { + EXPECT_EQ(gDisableStructs[B_POSITION_PLAYER_LEFT].disabledMove, MOVE_SLEEP_TALK); + } +} + +SINGLE_BATTLE_TEST("Cursed Body disables the base move of a status Z-Move") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_NATURE_POWER) == EFFECT_NATURE_POWER); + ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } + OPPONENT(SPECIES_FRILLISH) { Ability(ABILITY_CURSED_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_NATURE_POWER, gimmick: GIMMICK_Z_MOVE, WITH_RNG(RNG_CURSED_BODY, 1)); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, player); + HP_BAR(opponent); + ABILITY_POPUP(opponent, ABILITY_CURSED_BODY); + MESSAGE("Wobbuffet's Nature Power was disabled by the opposing Frillish's Cursed Body!"); + } THEN { + EXPECT_EQ(gDisableStructs[B_POSITION_PLAYER_LEFT].disabledMove, MOVE_NATURE_POWER); + } +} + +TO_DO_BATTLE_TEST("Cursed Body disables damaging Z-Moves, but not the base move") diff --git a/test/battle/ability/dancer.c b/test/battle/ability/dancer.c index 2fb870ea51..075a3e46a5 100644 --- a/test/battle/ability/dancer.c +++ b/test/battle/ability/dancer.c @@ -1,5 +1,6 @@ #include "global.h" #include "test/battle.h" +#include "constants/battle_z_move_effects.h" SINGLE_BATTLE_TEST("Dancer can copy a dance move immediately after it was used and allow the user of Dancer to still use its move") { @@ -79,8 +80,59 @@ DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest") } } -TO_DO_BATTLE_TEST("Dancer triggers from slowest to fastest during Trick Room") -TO_DO_BATTLE_TEST("Dancer triggering ignores Lagging Tail") +DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest during Trick Room") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + PLAYER(SPECIES_WOBBUFFET) { Speed(1); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(5); } + } WHEN { + TURN { MOVE(playerRight, MOVE_TRICK_ROOM); } + TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK_ROOM, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + ABILITY_POPUP(opponentRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + ABILITY_POPUP(playerLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Dancer triggering ignores Lagging Tail") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(gItemsInfo[ITEM_LAGGING_TAIL].holdEffect == HOLD_EFFECT_LAGGING_TAIL); + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); Item(ITEM_LAGGING_TAIL); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(5); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } + } WHEN { + TURN { MOVE(playerRight, MOVE_DRAGON_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + ABILITY_POPUP(playerLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + ABILITY_POPUP(opponentRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } +} SINGLE_BATTLE_TEST("Dancer doesn't trigger if the original user flinches") { @@ -194,8 +246,54 @@ DOUBLE_BATTLE_TEST("Dancer doesn't trigger on a snatched move") } } -TO_DO_BATTLE_TEST("Dancer-called moves can be snatched") -TO_DO_BATTLE_TEST("Dancer-called moves can be reflected by Magic Bounce/Coat") +DOUBLE_BATTLE_TEST("Dancer doesn't trigger when an ally snatches the move") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_SNATCH) == EFFECT_SNATCH); + ASSUME(MoveCanBeSnatched(MOVE_DRAGON_DANCE)); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SNATCH); MOVE(playerRight, MOVE_DRAGON_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SNATCH, playerLeft); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + NONE_OF { + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Dancer-called moves can be reflected by Magic Bounce") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_FEATHER_DANCE)); + PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + } WHEN { + TURN { MOVE(player, MOVE_FEATHER_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FEATHER_DANCE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ABILITY_POPUP(player, ABILITY_MAGIC_BOUNCE); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FEATHER_DANCE, opponent); + MESSAGE("The opposing Oricorio's Feather Dance was bounced back by Espeon's Magic Bounce!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FEATHER_DANCE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 4); + } +} DOUBLE_BATTLE_TEST("Dancer triggers on Instructed dance moves") { @@ -252,8 +350,61 @@ DOUBLE_BATTLE_TEST("Dancer-called move doesn't update move to be Instructed") } } -TO_DO_BATTLE_TEST("Dancer-called moves doesn't update move to be called by Mimick") -TO_DO_BATTLE_TEST("Dancer-called moves doesn't update move to be called by Mirror Move") +DOUBLE_BATTLE_TEST("Dancer-called moves do not update move to be called by Mimic") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_MIMIC) == EFFECT_MIMIC); + PLAYER(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(50); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); + MOVE(playerRight, MOVE_DRAGON_DANCE); + MOVE(playerLeft, MOVE_MIMIC, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIMIC, playerLeft); + MESSAGE("Wobbuffet learned Scratch!"); + NOT MESSAGE("Wobbuffet learned Dragon Dance!"); + } +} + +DOUBLE_BATTLE_TEST("Dancer-called moves doesn't update move to be called by Mirror Move") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_MIRROR_MOVE) == EFFECT_MIRROR_MOVE); + PLAYER(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(50); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); MOVE(playerRight, MOVE_DRAGON_DANCE); } + TURN { MOVE(playerLeft, MOVE_MIRROR_MOVE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, playerRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + ABILITY_POPUP(opponentLeft, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("Wobbuffet used Mirror Move!"); + MESSAGE("Wobbuffet used Scratch!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, playerLeft); + NOT MESSAGE("Wobbuffet used Dragon Dance!"); + } +} DOUBLE_BATTLE_TEST("Dancer doesn't call a move that didn't execute due to Powder") { @@ -306,7 +457,7 @@ DOUBLE_BATTLE_TEST("Dancer still activates after Red Card") DOUBLE_BATTLE_TEST("Dancer still activate after Red Card even if blocked by Suction Cups") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SUCTION_CUPS); } + PLAYER(SPECIES_OCTILLERY) { Ability(ABILITY_SUCTION_CUPS); } PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } PLAYER(SPECIES_CHANSEY); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } @@ -315,13 +466,13 @@ DOUBLE_BATTLE_TEST("Dancer still activate after Red Card even if blocked by Suct } WHEN { TURN { MOVE(playerLeft, MOVE_FIERY_DANCE, target: opponentLeft); } } SCENE { - MESSAGE("Wobbuffet used Fiery Dance!"); + MESSAGE("Octillery used Fiery Dance!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerLeft); HP_BAR(opponentLeft); // red card trigger ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); - MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!"); - MESSAGE("Wobbuffet anchors itself with Suction Cups!"); + MESSAGE("The opposing Wobbuffet held up its Red Card against Octillery!"); + MESSAGE("Octillery anchors itself with Suction Cups!"); NOT MESSAGE("Chansey was dragged out!"); // Dancer ABILITY_POPUP(playerRight, ABILITY_DANCER); @@ -364,15 +515,292 @@ DOUBLE_BATTLE_TEST("Dancer correctly restores move targets") } } -TO_DO_BATTLE_TEST("Dancer-called damaging moves are considered for Counter/Mirror Coat/Metal Burst") +DOUBLE_BATTLE_TEST("Dancer-called damaging moves are considered for Counter/Mirror Coat/Metal Burst") +{ + u32 danceMove, retaliateMove; -TO_DO_BATTLE_TEST("Dancer copies a status Z-Move's base move without gaining an additional Z-Power effect") -TO_DO_BATTLE_TEST("Dancer user may hit itself in confusion instead of copying a move if it's confused") -TO_DO_BATTLE_TEST("Dancer tries to copy a move but fails if it's being forced into a different move - Rampage move") // Test with Petal Dance, Thrash -TO_DO_BATTLE_TEST("Dancer tries to copy a move but fails if it's being forced into a different move - Rollout") -TO_DO_BATTLE_TEST("Dancer tries to copy a move but fails if it's being forced into a different move - Choice items") -TO_DO_BATTLE_TEST("Dancer tries to copy a move but fails if it's being forced into a different move - Encore") -TO_DO_BATTLE_TEST("Dancer tries to copy a status move but fails if it's under Taunt's effect") -TO_DO_BATTLE_TEST("Dancer can still copy status moves if the user is holding an Assault Vest") -TO_DO_BATTLE_TEST("Dancer copies Lunar Dance after the original user faints, but before the replacement is sent out") -TO_DO_BATTLE_TEST("Dancer doesn't activate Feather Dance if it was reflected by Magic Bounce/Coat") + PARAMETRIZE { danceMove = MOVE_AQUA_STEP; retaliateMove = MOVE_COUNTER; } + PARAMETRIZE { danceMove = MOVE_FIERY_DANCE; retaliateMove = MOVE_MIRROR_COAT; } + PARAMETRIZE { danceMove = MOVE_FIERY_DANCE; retaliateMove = MOVE_METAL_BURST; } + + GIVEN { + ASSUME(IsDanceMove(danceMove)); + if (retaliateMove == MOVE_COUNTER) + ASSUME(GetMoveCategory(danceMove) == DAMAGE_CATEGORY_PHYSICAL); + else if (retaliateMove == MOVE_MIRROR_COAT) + ASSUME(GetMoveCategory(danceMove) == DAMAGE_CATEGORY_SPECIAL); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(playerLeft, danceMove, target: opponentLeft); MOVE(opponentLeft, retaliateMove); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, danceMove, playerLeft); + HP_BAR(opponentLeft); + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, danceMove, playerRight); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, retaliateMove, opponentLeft); + HP_BAR(playerRight); + NOT HP_BAR(playerLeft); + } +} + +SINGLE_BATTLE_TEST("Dancer copies a status Z-Move's base move without gaining an additional Z-Power effect") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2); + ASSUME(GetMoveZEffect(MOVE_SWORDS_DANCE) == Z_EFFECT_RESET_STATS); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + } WHEN { + TURN { MOVE(player, MOVE_SCREECH); } + TURN { MOVE(player, MOVE_SWORDS_DANCE, gimmick: GIMMICK_Z_MOVE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ZMOVE_ACTIVATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 2); + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Dancer user may hit itself in confusion instead of copying a move if it's confused") +{ + u32 genConfig, pctChance; + + PARAMETRIZE { genConfig = GEN_6; pctChance = 50; } + PARAMETRIZE { genConfig = GEN_7; pctChance = 33; } + PASSES_RANDOMLY(pctChance, 100, RNG_CONFUSION); + GIVEN { + WITH_CONFIG(CONFIG_CONFUSION_SELF_DMG_CHANCE, genConfig); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + } WHEN { + TURN { MOVE(player, MOVE_CONFUSE_RAY); } + TURN { MOVE(player, MOVE_DRAGON_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, player); + MESSAGE("The opposing Oricorio became confused!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + MESSAGE("The opposing Oricorio is confused!"); + MESSAGE("It hurt itself in its confusion!"); + HP_BAR(opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } + } +} + +SINGLE_BATTLE_TEST("Dancer can still copy a move even if it's being forced into a different move - Rampage move") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(IsDanceMove(MOVE_PETAL_DANCE)); + ASSUME(MoveHasAdditionalEffectSelf(MOVE_PETAL_DANCE, MOVE_EFFECT_THRASH)); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_PETAL_DANCE); } + TURN { MOVE(player, MOVE_SWORDS_DANCE); FORCED_MOVE(opponent); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Dancer can still copy a move even if it's being forced into a different move - Rollout") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetMoveEffect(MOVE_ROLLOUT) == EFFECT_ROLLOUT); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_ROLLOUT); } + TURN { MOVE(player, MOVE_SWORDS_DANCE); FORCED_MOVE(opponent); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROLLOUT, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Dancer can still copy a move even if it's being forced into a different move - Choice items") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetItemHoldEffect(ITEM_CHOICE_BAND) == HOLD_EFFECT_CHOICE_BAND); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); Item(ITEM_CHOICE_BAND); } + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_SWORDS_DANCE); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Dancer can still copy a move even if it's being forced into a different move - Encore") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_ENCORE, target: opponent); MOVE(opponent, MOVE_SCRATCH); } + TURN { MOVE(player, MOVE_SWORDS_DANCE); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, player); + MESSAGE("The opposing Oricorio must do an encore!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Dancer tries to copy a status move but fails if it's under Taunt's effect") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); } + } WHEN { + TURN { MOVE(player, MOVE_TAUNT); } + TURN { MOVE(player, MOVE_SWORDS_DANCE); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Dancer can still copy status moves if the user is holding an Assault Vest") +{ + GIVEN { + ASSUME(IsDanceMove(MOVE_SWORDS_DANCE)); + ASSUME(GetItemHoldEffect(ITEM_ASSAULT_VEST) == HOLD_EFFECT_ASSAULT_VEST); + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(10); Item(ITEM_ASSAULT_VEST); } + } WHEN { + TURN { MOVE(player, MOVE_SWORDS_DANCE); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ABILITY_POPUP(opponent, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} + +DOUBLE_BATTLE_TEST("Dancer copies Lunar Dance after the original user faints, but before the replacement is sent out") +{ + GIVEN { + WITH_CONFIG(CONFIG_HEALING_WISH_SWITCH, GEN_7); + ASSUME(GetMoveEffect(MOVE_LUNAR_DANCE) == EFFECT_LUNAR_DANCE); + PLAYER(SPECIES_WOBBUFFET) { Speed(50); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } + PLAYER(SPECIES_WYNAUT) { Speed(5); } + PLAYER(SPECIES_CHANSEY) { Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_LUNAR_DANCE); SEND_OUT(playerLeft, 2); SEND_OUT(playerRight, 3); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LUNAR_DANCE, playerLeft); + HP_BAR(playerLeft, hp: 0); + MESSAGE("Wobbuffet fainted!"); + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_LUNAR_DANCE, playerRight); + HP_BAR(playerRight, hp: 0); + MESSAGE("Oricorio fainted!"); + SEND_IN_MESSAGE("Wynaut"); + SEND_IN_MESSAGE("Chansey"); + } +} + +DOUBLE_BATTLE_TEST("Dancer doesn't activate Feather Dance if it was reflected by Magic Bounce/Coat") +{ + bool32 useMagicCoat; + + PARAMETRIZE { useMagicCoat = FALSE; } + PARAMETRIZE { useMagicCoat = TRUE; } + GIVEN { + ASSUME(IsDanceMove(MOVE_FEATHER_DANCE)); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + PLAYER(SPECIES_WOBBUFFET) { Speed(10); } + if (useMagicCoat) + OPPONENT(SPECIES_WOBBUFFET) { Speed(30); } + else + OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); Speed(30); } + OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(5); } + } WHEN { + if (useMagicCoat) + TURN { MOVE(opponentLeft, MOVE_MAGIC_COAT); MOVE(playerLeft, MOVE_FEATHER_DANCE, target: opponentLeft); } + else + TURN { MOVE(playerLeft, MOVE_FEATHER_DANCE, target: opponentLeft); } + } SCENE { + if (useMagicCoat) + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, opponentLeft); + else + ABILITY_POPUP(opponentLeft, ABILITY_MAGIC_BOUNCE); + NONE_OF { + ABILITY_POPUP(opponentRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FEATHER_DANCE, opponentRight); + } + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 2); + } +} diff --git a/test/battle/ability/dazzling.c b/test/battle/ability/dazzling.c index e5dd6bb37d..f54f024452 100644 --- a/test/battle/ability/dazzling.c +++ b/test/battle/ability/dazzling.c @@ -1,5 +1,6 @@ #include "global.h" #include "test/battle.h" +#include "constants/battle_z_move_effects.h" ASSUMPTIONS { @@ -124,11 +125,154 @@ SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail prevent Protean act // Listed on Bulbapedia as "Moves that target all Pokémon (except Perish Song, Flower Shield, and Rototiller)," // Despite the fact that there's only 2 remaining moves from that list, being Haze and Teatime -TO_DO_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block Haze") -TO_DO_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block Teatime") +SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block Haze") +{ + u32 species; + enum Ability ability; -TO_DO_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block a move's Z-Status effect") // Z-Baby-Doll eyes increases Def but doesn't reduce Atk -TO_DO_BATTLE_TEST("Mold Breaker ignores Dazzling, Queenly Majesty and Armor Tail") -TO_DO_BATTLE_TEST("Instruct-called moves keep their priority, which is considered for Dazzling, Queenly Majesty and Armor Tail") + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } -TO_DO_BATTLE_TEST(" Dazzling, Queenly Majesty and Armor Tail do not block high-priority moves called by other moves") // Metronome, Assist, Nature Power, etc. + GIVEN { + ASSUME(GetMoveEffect(MOVE_HAZE) == EFFECT_HAZE); + PLAYER(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SWORDS_DANCE); } + TURN { MOVE(player, MOVE_HAZE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HAZE, player); + NOT ABILITY_POPUP(opponent, ability); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block Teatime") +{ + u32 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_TEATIME) == EFFECT_TEATIME); + ASSUME(GetItemHoldEffect(ITEM_ORAN_BERRY) == HOLD_EFFECT_RESTORE_HP); + PLAYER(SPECIES_MURKROW) { Ability(ABILITY_PRANKSTER); Item(ITEM_ORAN_BERRY); HP(1); MaxHP(100); } + OPPONENT(species) { Ability(ability); Item(ITEM_ORAN_BERRY); HP(1); MaxHP(100); } + } WHEN { + TURN { MOVE(player, MOVE_TEATIME); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TEATIME, player); + NOT ABILITY_POPUP(opponent, ability); + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + EXPECT_EQ(opponent->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block a move's Z-Status effect") +{ + u32 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + ASSUME(GetMoveZEffect(MOVE_BABY_DOLL_EYES) == Z_EFFECT_DEF_UP_1); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FAIRIUM_Z); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_BABY_DOLL_EYES, gimmick: GIMMICK_Z_MOVE); } + } SCENE { + ABILITY_POPUP(opponent, ability); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_BABY_DOLL_EYES, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Mold Breaker ignores Dazzling, Queenly Majesty and Armor Tail") +{ + u32 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_QUICK_ATTACK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player); + HP_BAR(opponent); + NOT ABILITY_POPUP(opponent, ability); + } +} + +DOUBLE_BATTLE_TEST("Instruct-called moves keep their priority, which is considered for Dazzling, Queenly Majesty and Armor Tail") +{ + u32 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT); + ASSUME(GetItemHoldEffect(ITEM_EJECT_BUTTON) == HOLD_EFFECT_EJECT_BUTTON); + PLAYER(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_BUTTON); Speed(20); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } + OPPONENT(species) { Ability(ability); Speed(15); } + } WHEN { + TURN { MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); MOVE(playerLeft, MOVE_INSTRUCT, target: playerRight); SEND_OUT(opponentLeft, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, playerRight); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponentLeft); + MESSAGE("The opposing Wobbuffet is switched out with the Eject Button!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft); + ABILITY_POPUP(opponentLeft, ability); + MESSAGE("Wobbuffet cannot use Quick Attack!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, playerRight); + } +} + +SINGLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail do not block high-priority moves called by other moves") +{ + u32 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; } + PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; } + PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_METRONOME) == EFFECT_METRONOME); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_METRONOME, WITH_RNG(RNG_METRONOME, MOVE_QUICK_ATTACK)); } + } SCENE { + MESSAGE("Wobbuffet used Metronome!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_METRONOME, player); + MESSAGE("Waggling a finger let it use Quick Attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player); + HP_BAR(opponent); + NOT ABILITY_POPUP(opponent, ability); + } +} diff --git a/test/battle/ability/disguise.c b/test/battle/ability/disguise.c index 24a6a2d5ce..a874ec254c 100644 --- a/test/battle/ability/disguise.c +++ b/test/battle/ability/disguise.c @@ -104,7 +104,24 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu takes damage from secondary damage without } } -TO_DO_BATTLE_TEST("Disguised Mimikyu takes damage from secondary damage without breaking the disguise - Weather") +SINGLE_BATTLE_TEST("Disguised Mimikyu takes damage from secondary damage without breaking the disguise - Weather") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + ASSUME(GetSpeciesType(SPECIES_GEODUDE, 0) == TYPE_ROCK || GetSpeciesType(SPECIES_GEODUDE, 1) == TYPE_ROCK); + PLAYER(SPECIES_GEODUDE); + PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } + OPPONENT(SPECIES_GEODUDE); + } WHEN { + TURN { MOVE(opponent, MOVE_SANDSTORM); } + TURN { SWITCH(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SANDSTORM, opponent); + HP_BAR(player); + } THEN { + EXPECT_EQ(player->species, SPECIES_MIMIKYU_DISGUISED); + } +} SINGLE_BATTLE_TEST("Disguised Mimikyu takes damage from Rocky Helmet without breaking the disguise") { diff --git a/test/battle/ability/dry_skin.c b/test/battle/ability/dry_skin.c index aab5658618..7de0f82acf 100644 --- a/test/battle/ability/dry_skin.c +++ b/test/battle/ability/dry_skin.c @@ -15,7 +15,28 @@ SINGLE_BATTLE_TEST("Dry Skin causes 1/8th Max HP damage in Sun") } } -TO_DO_BATTLE_TEST("Dry Skin doesn't get damaged in Sun if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Dry Skin doesn't get damaged in Sun if Cloud Nine/Air Lock is on the field") +{ + u16 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + + GIVEN { + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); + NONE_OF { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player); + MESSAGE("Parasect's Dry Skin takes its toll!"); + } + } +} SINGLE_BATTLE_TEST("Dry Skin heals 1/8th Max HP in Rain") { @@ -31,7 +52,28 @@ SINGLE_BATTLE_TEST("Dry Skin heals 1/8th Max HP in Rain") } } -TO_DO_BATTLE_TEST("Dry Skin doesn't heal in Rain if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Dry Skin doesn't heal in Rain if Cloud Nine/Air Lock is on the field") +{ + u16 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + + GIVEN { + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + NONE_OF { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player); + MESSAGE("Parasect's Dry Skin restored its HP a little!"); + } + } +} SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%", s16 damage) { diff --git a/test/battle/ability/flower_gift.c b/test/battle/ability/flower_gift.c index 30cc7926e5..8e5f9faca0 100644 --- a/test/battle/ability/flower_gift.c +++ b/test/battle/ability/flower_gift.c @@ -17,7 +17,28 @@ SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim in harsh sunlight") } } -TO_DO_BATTLE_TEST("Flower Gift doesn't transform Cherrim if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Flower Gift doesn't transform Cherrim if Cloud Nine/Air Lock is on the field") +{ + u32 species = 0; + enum Ability ability = 0; + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + GIVEN { + PLAYER(SPECIES_CHERRIM_OVERCAST) { Ability(ABILITY_FLOWER_GIFT); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent); + NONE_OF { + ABILITY_POPUP(player, ABILITY_FLOWER_GIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Cherrim transformed!"); + } + } THEN { + EXPECT_EQ(player->species, SPECIES_CHERRIM_OVERCAST); + } +} SINGLE_BATTLE_TEST("Flower Gift transforms Cherrim back to normal when weather changes") { @@ -219,4 +240,19 @@ DOUBLE_BATTLE_TEST("Flower Gift reverts Cherrim back after Teraform Zero clears } } -TO_DO_BATTLE_TEST("Flower Gift does not transform Cherrim back to normal when suppressed if Cherrim is Dynamaxed"); +SINGLE_BATTLE_TEST("Flower Gift does not transform Cherrim back to normal when suppressed if Cherrim is Dynamaxed") +{ + GIVEN { + ASSUME(B_WEATHER_FORMS >= GEN_5); + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + PLAYER(SPECIES_CHERRIM_OVERCAST) { Ability(ABILITY_FLOWER_GIFT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + TURN { MOVE(player, MOVE_SCRATCH, gimmick: GIMMICK_DYNAMAX); } + TURN { MOVE(opponent, MOVE_GASTRO_ACID); } + } SCENE { + } THEN { + EXPECT_EQ(player->species, SPECIES_CHERRIM_SUNSHINE); + } +} diff --git a/test/battle/ability/flower_veil.c b/test/battle/ability/flower_veil.c index 78d15df1bd..69a31958e1 100644 --- a/test/battle/ability/flower_veil.c +++ b/test/battle/ability/flower_veil.c @@ -63,4 +63,22 @@ DOUBLE_BATTLE_TEST("Flower Veil prevents status on allied Grass-types - left tar } } -TO_DO_BATTLE_TEST("Flower Veil's stat reduction protection considers Contrary") // Eg. If a move would reduce stats due to Contrary, it will be protected by Mist. +DOUBLE_BATTLE_TEST("Flower Veil's stat reduction protection considers Contrary") // Eg. If a move would reduce stats due to Contrary, it will be protected by Mist. +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SWAGGER) == EFFECT_SWAGGER); + ASSUME(GetSpeciesType(SPECIES_SNIVY, 0) == TYPE_GRASS || GetSpeciesType(SPECIES_SNIVY, 1) == TYPE_GRASS); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_COMFEY) { Ability(ABILITY_FLOWER_VEIL); } + OPPONENT(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SWAGGER, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWAGGER, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_FLOWER_VEIL); + MESSAGE("The opposing Snivy surrounded itself with a veil of petals!"); + } THEN { + EXPECT_EQ(opponentRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c index aca8e6fbf9..28188bcf11 100644 --- a/test/battle/ability/protosynthesis.c +++ b/test/battle/ability/protosynthesis.c @@ -173,6 +173,7 @@ SINGLE_BATTLE_TEST("Protosynthesis doesn't activate for a transformed battler") SINGLE_BATTLE_TEST("Protosynthesis activates even if the Pokémon is holding an Utility Umbrella") { GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); PLAYER(SPECIES_GREAT_TUSK) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_UTILITY_UMBRELLA); } OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); } } WHEN { diff --git a/test/battle/ability/swift_swim.c b/test/battle/ability/swift_swim.c index 4282ac2741..eacbccfdeb 100644 --- a/test/battle/ability/swift_swim.c +++ b/test/battle/ability/swift_swim.c @@ -1,6 +1,57 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Swift Swim doubles speed if it's raining"); -TO_DO_BATTLE_TEST("Swift Swim doesn't double speed if Cloud Nine/Air Lock is on the field"); -TO_DO_BATTLE_TEST("Swift Swim doesn't double speed if they have an Utility Umbrella"); +SINGLE_BATTLE_TEST("Swift Swim doubles speed if it's raining") +{ + GIVEN { + PLAYER(SPECIES_LUDICOLO) { Ability(ABILITY_SWIFT_SWIM); Speed(100); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(199); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } +} + +SINGLE_BATTLE_TEST("Swift Swim doesn't double speed if Cloud Nine/Air Lock is on the field") +{ + u16 species; + enum Ability ability; + + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + + GIVEN { + PLAYER(SPECIES_LUDICOLO) { Ability(ABILITY_SWIFT_SWIM); Speed(100); } + OPPONENT(species) { Speed(199); Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} + +SINGLE_BATTLE_TEST("Swift Swim doesn't double speed if they have an Utility Umbrella") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); + PLAYER(SPECIES_LUDICOLO) { Ability(ABILITY_SWIFT_SWIM); Speed(100); Item(ITEM_UTILITY_UMBRELLA); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(199); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_RAIN_DANCE); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} diff --git a/test/battle/hold_effect/cure_status.c b/test/battle/hold_effect/cure_status.c index 0318d3991a..bffe041372 100644 --- a/test/battle/hold_effect/cure_status.c +++ b/test/battle/hold_effect/cure_status.c @@ -135,7 +135,26 @@ SINGLE_BATTLE_TEST("Chesto Berry cures sleep when Yawn takes effect") } } -TO_DO_BATTLE_TEST("Chesto and Lum Berries don't trigger if the holder has Comatose") +SINGLE_BATTLE_TEST("Chesto and Lum Berries don't trigger if the holder has Comatose") +{ + u16 item; + + PARAMETRIZE { item = ITEM_CHESTO_BERRY; } + PARAMETRIZE { item = ITEM_LUM_BERRY; } + + GIVEN { + ASSUME(gItemsInfo[ITEM_CHESTO_BERRY].holdEffect == HOLD_EFFECT_CURE_SLP); + ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); Item(item); } + } WHEN { + TURN { } + } SCENE { + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + } THEN { + EXPECT_EQ(opponent->item, item); + } +} SINGLE_BATTLE_TEST("Cheri and Lum Berries cure paralysis") { @@ -181,8 +200,7 @@ SINGLE_BATTLE_TEST("Perism and Lum Berries cure confusion") SINGLE_BATTLE_TEST("Berry hold effect cures status if a Pokémon enters a battle") { - u16 status; - u16 item; + u16 status, item; PARAMETRIZE { status = STATUS1_BURN; item = ITEM_RAWST_BERRY; } PARAMETRIZE { status = STATUS1_FREEZE; item = ITEM_ASPEAR_BERRY; } diff --git a/test/battle/move_effect/hydro_steam.c b/test/battle/move_effect/hydro_steam.c index 781e083af4..ff1407a0e7 100644 --- a/test/battle/move_effect/hydro_steam.c +++ b/test/battle/move_effect/hydro_steam.c @@ -35,6 +35,7 @@ SINGLE_BATTLE_TEST("Hydro Steam is affected by Utility Umbrella", s16 damage) PARAMETRIZE { itemPlayer = ITEM_NONE; itemOpponent = ITEM_UTILITY_UMBRELLA; } PARAMETRIZE { itemPlayer = ITEM_UTILITY_UMBRELLA; itemOpponent = ITEM_UTILITY_UMBRELLA; } GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); PLAYER(SPECIES_WOBBUFFET) { Item(itemPlayer); } OPPONENT(SPECIES_WOBBUFFET) { Item(itemOpponent); } } WHEN { diff --git a/test/battle/move_effect/mist.c b/test/battle/move_effect/mist.c index dedf84cebc..fe37255eb8 100644 --- a/test/battle/move_effect/mist.c +++ b/test/battle/move_effect/mist.c @@ -1,6 +1,42 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Mist (Move Effect) test titles") +SINGLE_BATTLE_TEST("Mist prevents stat reductions from opposing moves") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_MIST) == EFFECT_MIST); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + PLAYER(SPECIES_WOBBUFFET) { Speed(20); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(player, MOVE_MIST); MOVE(opponent, MOVE_GROWL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, player); + MESSAGE("Your team became shrouded in mist!"); + MESSAGE("The opposing Wobbuffet used Growl!"); + MESSAGE("Wobbuffet is protected by the mist!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} -TO_DO_BATTLE_TEST("Mist's protection considers Contrary") // Eg. If a move would reduce stats due to Contrary, it will be protected by Mist. +SINGLE_BATTLE_TEST("Mist's protection considers Contrary") // Eg. If a move would reduce stats due to Contrary, it will be protected by Mist. +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_MIST) == EFFECT_MIST); + ASSUME(GetMoveEffect(MOVE_SWAGGER) == EFFECT_SWAGGER); + PLAYER(SPECIES_SNIVY) { Ability(ABILITY_CONTRARY); Speed(20); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(player, MOVE_MIST); MOVE(opponent, MOVE_SWAGGER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, player); + MESSAGE("Your team became shrouded in mist!"); + MESSAGE("The opposing Wobbuffet used Swagger!"); + MESSAGE("Snivy is protected by the mist!"); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player); + MESSAGE("Snivy became confused!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/move_effect/nightmare.c b/test/battle/move_effect/nightmare.c index 4cf051ba7d..43f4cb4431 100644 --- a/test/battle/move_effect/nightmare.c +++ b/test/battle/move_effect/nightmare.c @@ -1,6 +1,40 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Nightmare (Move Effect) test titles") +SINGLE_BATTLE_TEST("Nightmare damages sleeping targets at end of turn") +{ + s16 damage; -TO_DO_BATTLE_TEST("Nightmare affects Pokémon with Comatose") + GIVEN { + ASSUME(GetMoveEffect(MOVE_NIGHTMARE) == EFFECT_NIGHTMARE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP_TURN(2)); MaxHP(160); HP(160); } + } WHEN { + TURN { MOVE(player, MOVE_NIGHTMARE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_NIGHTMARE, player); + MESSAGE("The opposing Wobbuffet began having a nightmare!"); + HP_BAR(opponent, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, 40); + } +} + +SINGLE_BATTLE_TEST("Nightmare affects Pokémon with Comatose") +{ + s16 damage; + + GIVEN { + ASSUME(GetMoveEffect(MOVE_NIGHTMARE) == EFFECT_NIGHTMARE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); MaxHP(160); HP(160); } + } WHEN { + TURN { MOVE(player, MOVE_NIGHTMARE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_NIGHTMARE, player); + MESSAGE("The opposing Komala began having a nightmare!"); + HP_BAR(opponent, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, 40); + } +} diff --git a/test/battle/move_effect/purify.c b/test/battle/move_effect/purify.c index 425d0a99a9..13d1a6e746 100644 --- a/test/battle/move_effect/purify.c +++ b/test/battle/move_effect/purify.c @@ -62,5 +62,37 @@ AI_DOUBLE_BATTLE_TEST("AI does not use Purify to heal an ally with Guts") } } -TO_DO_BATTLE_TEST("TODO: Write Purify (Move Effect) test titles") -TO_DO_BATTLE_TEST("Purify doesn't heal HP if the target has Comatose") +SINGLE_BATTLE_TEST("Purify cures the target's status and heals the user") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PURIFY) == EFFECT_PURIFY); + PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); } + } WHEN { + TURN { MOVE(player, MOVE_PURIFY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PURIFY, player); + STATUS_ICON(opponent, none: TRUE); + HP_BAR(player); + } THEN { + EXPECT_EQ(player->hp, player->maxHP); + EXPECT_EQ(opponent->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Purify doesn't heal HP if the target has Comatose") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PURIFY) == EFFECT_PURIFY); + PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); } + OPPONENT(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); } + } WHEN { + TURN { MOVE(player, MOVE_PURIFY); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_PURIFY, player); + MESSAGE("But it failed!"); + NOT HP_BAR(player); + } THEN { + EXPECT_EQ(player->hp, 50); + } +} diff --git a/test/battle/move_effect/synthesis.c b/test/battle/move_effect/synthesis.c index a33b586927..5245ab9b38 100644 --- a/test/battle/move_effect/synthesis.c +++ b/test/battle/move_effect/synthesis.c @@ -56,6 +56,7 @@ SINGLE_BATTLE_TEST("Synthesis recovers regular amount in sandstorm if holding ut PARAMETRIZE { item = ITEM_LIFE_ORB; } PARAMETRIZE { item = ITEM_UTILITY_UMBRELLA; } GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(400); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN {