From edb196e8514f5d54565c2224c0813441c049d17a Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Wed, 2 Apr 2025 14:28:53 +0200 Subject: [PATCH 1/3] Fixes Red Card against Dynamaxed mons (#6526) --- asm/macros/battle_script.inc | 4 ---- data/battle_scripts_1.s | 1 - include/battle.h | 3 +-- src/battle_script_commands.c | 18 +++++------------- test/battle/gimmick/dynamax.c | 22 ++-------------------- test/battle/hold_effect/red_card.c | 20 +++++++++++++++++++- 6 files changed, 27 insertions(+), 41 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index f3d8f5000f..e386c389c9 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1747,10 +1747,6 @@ .byte \battler .endm - .macro hitswitchtargetfailed - callnative BS_HitSwitchTargetFailed - .endm - .macro tryrevivalblessing, failInstr:req callnative BS_TryRevivalBlessing .4byte \failInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 8ae63d6164..f843cbd654 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1824,7 +1824,6 @@ BattleScript_HitSwitchTargetDynamaxed:: printstring STRINGID_MOVEBLOCKEDBYDYNAMAX waitmessage B_WAIT_TIME_LONG BattleScript_HitSwitchTargetForceRandomSwitchFailed: - hitswitchtargetfailed setbyte sSWITCH_CASE, B_SWITCH_NORMAL return diff --git a/include/battle.h b/include/battle.h index cdb21340b1..30e7a13158 100644 --- a/include/battle.h +++ b/include/battle.h @@ -788,14 +788,13 @@ struct BattleStruct // When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without. u8 attackerBeforeBounce:2; u8 beatUpSlot:3; - u8 hitSwitchTargetFailed:1; + u8 pledgeMove:1; u8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects. u8 spriteIgnore0Hp:1; u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party. u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; - u8 pledgeMove:1; u8 isSkyBattle:1; s32 aiDelayTimer; // Counts number of frames AI takes to choose an action. s32 aiDelayFrames; // Number of frames it took to choose an action. diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9e74b65391..3a2690fb55 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7173,9 +7173,7 @@ static void Cmd_moveend(void) if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_RED_CARD) redCardBattlers |= (1u << i); } - if (redCardBattlers - && (moveEffect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed) - && IsBattlerAlive(gBattlerAttacker)) + if (redCardBattlers && IsBattlerAlive(gBattlerAttacker)) { // Since we check if battler was damaged, we don't need to check move result. // In fact, doing so actually prevents multi-target moves from activating red card properly @@ -7190,7 +7188,8 @@ static void Cmd_moveend(void) && IsBattlerAlive(battler) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && IsBattlerTurnDamaged(battler) - && CanBattlerSwitch(gBattlerAttacker)) + && CanBattlerSwitch(gBattlerAttacker) + && !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battler))) { effect = TRUE; gBattleScripting.moveendState = MOVEEND_OPPORTUNIST; @@ -7204,7 +7203,8 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection BattleScriptPushCursor(); if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE - || GetBattlerAbility(gBattlerAttacker) == ABILITY_GUARD_DOG) + || GetBattlerAbility(gBattlerAttacker) == ABILITY_GUARD_DOG + || GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) gBattlescriptCurrInstr = BattleScript_RedCardActivationNoSwitch; else gBattlescriptCurrInstr = BattleScript_RedCardActivates; @@ -7379,7 +7379,6 @@ static void Cmd_moveend(void) gSpecialStatuses[gBattlerTarget].berryReduced = FALSE; gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE; gBattleScripting.moveEffect = 0; - gBattleStruct->hitSwitchTargetFailed = FALSE; gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->categoryOverride = FALSE; @@ -18275,13 +18274,6 @@ void BS_StoreHealingWish(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_HitSwitchTargetFailed(void) -{ - NATIVE_ARGS(); - gBattleStruct->hitSwitchTargetFailed = TRUE; - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_TryRevivalBlessing(void) { NATIVE_ARGS(const u8 *failInstr); diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index ea8957e474..988f19581d 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -243,25 +243,6 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamaxed Pokemon are not affected by phazing moves } } -SINGLE_BATTLE_TEST("Dynamax: Dynamaxed Pokemon are not affected by Red Card") -{ - GIVEN { - ASSUME(gItemsInfo[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WYNAUT); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } - } WHEN { - TURN { MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); MOVE(opponent, MOVE_CELEBRATE); } - } SCENE { - MESSAGE("Wobbuffet used Max Strike!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); - MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!"); - MESSAGE("The move was blocked by the power of Dynamax!"); - } THEN { - EXPECT_EQ(opponent->item, ITEM_NONE); - } -} - SINGLE_BATTLE_TEST("Dynamax: Dynamaxed Pokemon can be switched out by Eject Button") { GIVEN { @@ -1625,9 +1606,10 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamax is reverted before switch out") } } -SINGLE_BATTLE_TEST("Dynamax: Destiny Bond if a dynamaxed battler is present on field") +SINGLE_BATTLE_TEST("Dynamax: Destiny Bond fails if a dynamaxed battler is present on field") { GIVEN { + ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index 8513e795b9..e7a32e3534 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -497,7 +497,25 @@ SINGLE_BATTLE_TEST("Red Card prevents Emergency Exit activation when triggered") } } -TO_DO_BATTLE_TEST("Red Card activates but fails if the attacker has Dynamaxed"); +SINGLE_BATTLE_TEST("Red Card activates and is consumed but fails if the attacker is Dynamaxed") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + } WHEN { + TURN { + MOVE(opponent, MOVE_TACKLE); + MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); + } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("The opposing Wobbuffet held up its Red Card against Wobbuffet!"); + NOT MESSAGE("Wobbuffet is switched out with the Eject Button!"); + } THEN { + EXPECT_EQ(opponent->item, ITEM_NONE); + } +} SINGLE_BATTLE_TEST("Red Card activates before Eject Pack") { From ff8bf967d479894f81ee9a1e8facb760af133d67 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Wed, 2 Apr 2025 23:44:09 +0200 Subject: [PATCH 2/3] Added AI switch display to the battle debug (#6529) Co-authored-by: Hedara --- src/battle_debug.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/battle_debug.c b/src/battle_debug.c index e82f7a90df..2dae24293d 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -421,6 +421,7 @@ static const u8 sText_SubstituteHp[] = _("Substitute HP"); static const u8 sText_InLove[] = _("In Love"); static const u8 sText_Unknown[] = _("Unknown"); static const u8 sText_EmptyString[] = _(""); +static const u8 sText_IsSwitching[] = _("Switching to "); static const struct BitfieldInfo sStatus1Bitfield[] = { @@ -979,6 +980,14 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) } } + if (AI_DATA->shouldSwitch & (1u << data->aiBattlerId)) + { + u32 switchMon = GetMonData(&gEnemyParty[AI_DATA->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES); + + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, sText_IsSwitching, 74, 64, 0, NULL); + AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, gSpeciesInfo[switchMon].speciesName, 74 + 68, 64, 0, NULL); + } + CopyWindowToVram(data->aiMovesWindowId, COPYWIN_FULL); Free(text); } From 1e38c369128d7c1d270ac33ac9c0afafbfa3664c Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Wed, 2 Apr 2025 23:51:45 +0200 Subject: [PATCH 3/3] Fixes transformed mon being able to use tera on Terapagos (#6528) --- src/battle_terastal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 2c140414db..0c29d20f27 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -62,7 +62,10 @@ void ApplyBattlerVisualsForTeraAnim(u32 battler) bool32 CanTerastallize(u32 battler) { u32 holdEffect = GetBattlerHoldEffect(battler, FALSE); - + + if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS) + return FALSE; + // Prevents Zigzagoon from terastalizing in vanilla. if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && GetBattlerSide(battler) == B_SIDE_OPPONENT) return FALSE;