From d44eff4e0c9857e1e8158414ca14addd9d04ccd0 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 3 Mar 2025 14:56:08 -0500 Subject: [PATCH] fix red card overwriting gBattlerAttacker causing subsequent MOVEEND cases checking attacker not to trigger properly --- asm/macros/battle_script.inc | 4 +++ data/battle_scripts_1.s | 17 +++++----- include/battle.h | 1 + src/battle_script_commands.c | 15 +++++++++ test/battle/hold_effect/red_card.c | 54 ++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 9 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index a169b3580b..e50cbcbe43 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2376,6 +2376,10 @@ callnative BS_SwapStats .byte \stat .endm + + .macro restoresavedmove + callnative BS_RestoreSavedMove + .endm @ helpful macros .macro setstatchanger stat:req, stages:req, down:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 748fa2c5be..aaa03f0ac6 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6045,6 +6045,8 @@ BattleScript_RoarSuccessSwitch:: BattleScript_RoarSuccessSwitch_Ret: swapattackerwithtarget @ continuation of RedCardActivates restoretarget + restoreattacker + restoresavedmove setbyte sSWITCH_CASE, B_SWITCH_NORMAL return @@ -9519,6 +9521,8 @@ BattleScript_RedCardActivationNoSwitch:: waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING restoretarget + restoreattacker + restoresavedmove return BattleScript_RedCardActivates:: @@ -9537,22 +9541,17 @@ BattleScript_RedCardEnd: return BattleScript_RedCardIngrain: printstring STRINGID_PKMNANCHOREDITSELF +BattleScript_RedCardIngrainContinue: waitmessage B_WAIT_TIME_LONG removeitem BS_SCRIPTING restoretarget return BattleScript_RedCardSuctionCups: - printstring STRINGID_PKMNANCHORSITSELFWITH - waitmessage B_WAIT_TIME_LONG - removeitem BS_SCRIPTING - restoretarget - return + printstring STRINGID_PKMNANCHORSITSELFWITH + goto BattleScript_RedCardIngrainContinue BattleScript_RedCardDynamaxed: printstring STRINGID_MOVEBLOCKEDBYDYNAMAX - waitmessage B_WAIT_TIME_LONG - removeitem BS_SCRIPTING - restoretarget - return + goto BattleScript_RedCardIngrainContinue BattleScript_EjectButtonActivates:: makevisible BS_ATTACKER diff --git a/include/battle.h b/include/battle.h index 27227544d9..c9517b9b71 100644 --- a/include/battle.h +++ b/include/battle.h @@ -836,6 +836,7 @@ struct BattleStruct struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; u8 embodyAspectBoost[NUM_BATTLE_SIDES]; + u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index be57f4ae18..331ff44ff2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7075,6 +7075,8 @@ static void Cmd_moveend(void) { gLastUsedItem = gBattleMons[battler].item; SaveBattlerTarget(battler); // save battler with red card + SaveBattlerAttacker(gBattlerAttacker); + gBattleStruct->savedMove = gCurrentMove; gBattleScripting.battler = battler; gEffectBattler = gBattlerAttacker; gBattleStruct->redCardActivates = TRUE; @@ -18637,3 +18639,16 @@ void BS_SetSteelsurge(void) gBattlescriptCurrInstr = cmd->nextInstr; } } + +void BS_RestoreSavedMove(void) +{ + NATIVE_ARGS(); + + if (gBattleStruct->savedMove == MOVE_NONE) + DebugPrintfLevel(MGBA_LOG_WARN, "restoresavedmove was called with no move saved!"); + + gCurrentMove = gBattleStruct->savedMove; + gBattleStruct->savedMove = MOVE_NONE; + gBattlescriptCurrInstr = cmd->nextInstr; +} + diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index 88b208cf50..80595b5b65 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -520,3 +520,57 @@ SINGLE_BATTLE_TEST("Red Card activates before Eject Pack") ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); } } + +DOUBLE_BATTLE_TEST("Dancer still activates after Red Card") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) ; + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + PLAYER(SPECIES_CHANSEY); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_BULBASAUR); + OPPONENT(SPECIES_SHUCKLE); + } WHEN { + TURN { MOVE(playerLeft, MOVE_FIERY_DANCE, target: opponentLeft); } + } SCENE { + MESSAGE("Wobbuffet 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("Chansey was dragged out!"); + // Dancer + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerRight); + HP_BAR(opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Red Card: Dancer still activate after Red Card even if blocked by Suction Cups") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SUCTION_CUPS); } + PLAYER(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } + PLAYER(SPECIES_CHANSEY); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_BULBASAUR); + OPPONENT(SPECIES_SHUCKLE); + } WHEN { + TURN { MOVE(playerLeft, MOVE_FIERY_DANCE, target: opponentLeft); } + } SCENE { + MESSAGE("Wobbuffet 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!"); + NOT MESSAGE("Chansey was dragged out!"); + // Dancer + ABILITY_POPUP(playerRight, ABILITY_DANCER); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FIERY_DANCE, playerRight); + HP_BAR(opponentLeft); + } +} +