From 38221b9de512f29cfe6b1c70e73e90265573d724 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Fri, 17 Oct 2025 19:40:37 +0100 Subject: [PATCH] Fixes Shields Down incorrectly preventing status on Minior Core form (#7968) --- asm/macros/battle_script.inc | 4 +- data/battle_scripts_1.s | 6 +- src/battle_script_commands.c | 12 ++- src/battle_util.c | 6 +- test/battle/ability/flower_veil.c | 4 +- test/battle/ability/shields_down.c | 26 +++++++ test/battle/move_effect/rest.c | 117 +++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 16 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 547e4d6e3f..5ccaf2ea50 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2405,8 +2405,8 @@ .4byte \jumpInstr .endm - .macro jumpifleafguardprotected battler:req, jumpInstr:req - callnative BS_JumpIfLeafGuardProtected + .macro jumpifabilitypreventsrest battler:req, jumpInstr:req + callnative BS_JumpIfAbilityPreventsRest .byte \battler .4byte \jumpInstr .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3cf1f53fec..db4f7e65e3 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3186,9 +3186,7 @@ BattleScript_EffectRest:: jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_InsomniaProtects jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects jumpifability BS_ATTACKER, ABILITY_PURIFYING_SALT, BattleScript_InsomniaProtects -.if B_LEAF_GUARD_PREVENTS_REST >= GEN_5 - jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest -.endif + jumpifabilitypreventsrest BS_TARGET, BattleScript_AbilityPreventsRest trysetrest BattleScript_AlreadyAtFullHp pause B_WAIT_TIME_SHORT printfromtable gRestUsedStringIds @@ -3210,7 +3208,7 @@ BattleScript_RestIsAlreadyAsleep:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_LeafGuardPreventsRest:: +BattleScript_AbilityPreventsRest:: pause B_WAIT_TIME_SHORT printstring STRINGID_BUTITFAILED waitmessage B_WAIT_TIME_LONG diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e6c4a4adb4..c9b64ffea2 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -18243,19 +18243,17 @@ void BS_JumpIfSpecies(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfLeafGuardProtected(void) +void BS_JumpIfAbilityPreventsRest(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (IsLeafGuardProtected(battler, GetBattlerAbility(battler))) - { - gBattlerAbility = battler; + u32 ability = GetBattlerAbility(battler); + if (B_LEAF_GUARD_PREVENTS_REST >= GEN_5 && IsLeafGuardProtected(battler, ability)) + gBattlescriptCurrInstr = cmd->jumpInstr; + else if (IsShieldsDownProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; - } else - { gBattlescriptCurrInstr = cmd->nextInstr; - } } void BS_SetAttackerToStickyWebUser(void) diff --git a/src/battle_util.c b/src/battle_util.c index abf61c1d58..42329b5495 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5713,7 +5713,6 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u // Checks that apply to all non volatile statuses if (abilityDef == ABILITY_COMATOSE - || abilityDef == ABILITY_SHIELDS_DOWN || abilityDef == ABILITY_PURIFYING_SALT) { abilityAffected = TRUE; @@ -5728,6 +5727,11 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u abilityAffected = TRUE; battleScript = BattleScript_AbilityProtectsDoesntAffect; } + else if (IsShieldsDownProtected(battlerDef, abilityDef)) + { + abilityAffected = TRUE; + battleScript = BattleScript_AbilityProtectsDoesntAffect; + } else if ((sideBattler = IsFlowerVeilProtected(battlerDef))) { abilityAffected = TRUE; diff --git a/test/battle/ability/flower_veil.c b/test/battle/ability/flower_veil.c index cb72cd33ae..78d15df1bd 100644 --- a/test/battle/ability/flower_veil.c +++ b/test/battle/ability/flower_veil.c @@ -15,7 +15,7 @@ ASSUMPTIONS ASSUME(GetMoveNonVolatileStatus(MOVE_HYPNOSIS) == MOVE_EFFECT_SLEEP); } -DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - right target") +DOUBLE_BATTLE_TEST("Flower Veil prevents status on allied Grass-types - right target") { u32 move; @@ -39,7 +39,7 @@ DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - right tar } } -DOUBLE_BATTLE_TEST("Flower Veil prevents Toxic bad poison on partner - left target") +DOUBLE_BATTLE_TEST("Flower Veil prevents status on allied Grass-types - left target") { u32 move; diff --git a/test/battle/ability/shields_down.c b/test/battle/ability/shields_down.c index f9def2991d..5c46a8d589 100644 --- a/test/battle/ability/shields_down.c +++ b/test/battle/ability/shields_down.c @@ -32,3 +32,29 @@ SINGLE_BATTLE_TEST("Minior Core transforms into Minior Meteor on switch-in if it EXPECT_EQ(opponent->species, SPECIES_MINIOR_METEOR); } } + +SINGLE_BATTLE_TEST("Shields Down protects Minior Meteor from status conditions") +{ + u32 species, hp; + PARAMETRIZE { species = SPECIES_MINIOR_METEOR; hp = 300; } + PARAMETRIZE { species = SPECIES_MINIOR_CORE; hp = 100; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_WILL_O_WISP) == MOVE_EFFECT_BURN); + PLAYER(SPECIES_WYNAUT); + OPPONENT(species) { Ability(ABILITY_SHIELDS_DOWN); HP(hp); MaxHP(300); } + } WHEN { + TURN { MOVE(player, MOVE_WILL_O_WISP); } + } SCENE { + if (species == SPECIES_MINIOR_METEOR) + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_WILL_O_WISP, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_WILL_O_WISP, player); + } THEN { + if (species == SPECIES_MINIOR_METEOR) + EXPECT_EQ(opponent->status1, STATUS1_NONE); + else + EXPECT(opponent->status1 & STATUS1_BURN); + } +} diff --git a/test/battle/move_effect/rest.c b/test/battle/move_effect/rest.c index 4d0d85b560..fcf2b15567 100644 --- a/test/battle/move_effect/rest.c +++ b/test/battle/move_effect/rest.c @@ -1,4 +1,121 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); +} + +SINGLE_BATTLE_TEST("Rest causes the user to fall asleep and restores HP to full") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(player->status1 & STATUS1_SLEEP); + EXPECT_EQ(player->hp, player->maxHP); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is at full HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(300); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Leaf Guard") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); + ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); + PLAYER(SPECIES_CHIKORITA) { Ability(ABILITY_LEAF_GUARD); HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Shields Down") +{ + GIVEN { + PLAYER(SPECIES_MINIOR_METEOR) { Ability(ABILITY_SHIELDS_DOWN); HP(299); MaxHP(300); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest fails if the user is protected by Electric/Misty Terrain") +{ + u32 move; + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_MISTY_TERRAIN; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_MISTY_TERRAIN) == EFFECT_MISTY_TERRAIN); + ASSUME(GetSpeciesType(SPECIES_WYNAUT, 0) != TYPE_FLYING && GetSpeciesType(SPECIES_WYNAUT, 1) != TYPE_FLYING); + PLAYER(SPECIES_WYNAUT) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_REST); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(!(player->status1 & STATUS1_SLEEP)); + } +} + +SINGLE_BATTLE_TEST("Rest doesn't fail if the user is protected by Safeguard") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SAFEGUARD) == EFFECT_SAFEGUARD); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAFEGUARD); } + TURN { MOVE(player, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + } THEN { + EXPECT(player->status1 & STATUS1_SLEEP); + } +} + +DOUBLE_BATTLE_TEST("Rest doesn't fail if the user is protected by Flower Veil") +{ + GIVEN { + ASSUME(GetSpeciesType(SPECIES_CHIKORITA, 0) == TYPE_GRASS || GetSpeciesType(SPECIES_CHIKORITA, 1) == TYPE_GRASS); + PLAYER(SPECIES_CHIKORITA) { HP(1); } + PLAYER(SPECIES_FLORGES) { Ability(ABILITY_FLOWER_VEIL); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_REST); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, playerLeft); + } THEN { + EXPECT(playerLeft->status1 & STATUS1_SLEEP); + } +} + TO_DO_BATTLE_TEST("TODO: Write Rest (Move Effect) test titles")