diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 1568bcfb97..017f4a62db 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -10496,7 +10496,7 @@ BattleScript_DamageNonTypesLoopIncrement:: jumpifbytenotequal gBattleCommunication, gBattlersCount, BattleScript_DamageNonTypesLoop BattleScript_DamageNonTypesContinuesEnd:: bicword gHitMarker, HITMARKER_SKIP_DMG_TRACK | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE - return + end2 BattleScript_EffectTryReducePP:: tryspiteppreduce BattleScript_MoveEnd diff --git a/include/battle.h b/include/battle.h index 3e20ee565c..6a1772090c 100644 --- a/include/battle.h +++ b/include/battle.h @@ -533,7 +533,6 @@ struct DynamaxData u16 baseMove[MAX_BATTLERS_COUNT]; // base move of Max Move u16 lastUsedBaseMove; u16 levelUpHP; - u16 opponentBaseForm; // changedSpecies isn't used for opposing Pokemon }; struct StolenItem @@ -660,7 +659,7 @@ struct BattleStruct bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once. u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. u16 moveEffect2; // For Knock Off - u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon. + u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon. u8 quickClawBattlerId; struct StolenItem itemStolen[PARTY_SIZE]; // Player's team that had items stolen (two bytes per party member) u8 blunderPolicy:1; // should blunder policy activate diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index fe679957dc..1fd19a3238 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -64,6 +64,7 @@ void PrepareBattlerForDynamax(u16 battlerId); u16 GetNonDynamaxHP(u16 battlerId); u16 GetNonDynamaxMaxHP(u16 battlerId); void UndoDynamax(u16 battlerId); +bool32 IsMoveBlockedByMaxGuard(u16 move); bool32 IsMoveBlockedByDynamax(u16 move); bool32 ShouldUseMaxMove(u16 battlerId, u16 baseMove); diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index 261703f81a..75f03d7f77 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -243,6 +243,25 @@ void UndoDynamax(u16 battlerId) TryBattleFormChange(battlerId, FORM_CHANGE_END_BATTLE); } +// Certain moves are blocked by Max Guard that normally ignore protection. +bool32 IsMoveBlockedByMaxGuard(u16 move) +{ + switch (move) + { + case MOVE_BLOCK: + case MOVE_FLOWER_SHIELD: + case MOVE_GEAR_UP: + case MOVE_MAGNETIC_FLUX: + case MOVE_PHANTOM_FORCE: + case MOVE_PSYCH_UP: + case MOVE_SHADOW_FORCE: + case MOVE_TEATIME: + case MOVE_TRANSFORM: + return TRUE; + } + return FALSE; +} + // Weight-based moves (and some other moves in Raids) are blocked by Dynamax. bool32 IsMoveBlockedByDynamax(u16 move) { diff --git a/src/battle_main.c b/src/battle_main.c index ffb1fd3908..f108a28f5f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5265,7 +5265,7 @@ static void HandleEndTurn_FinishBattle(void) changedForm = TryFormChange(i, B_SIDE_PLAYER, FORM_CHANGE_END_BATTLE); // Clear original species field - gBattleStruct->changedSpecies[i] = SPECIES_NONE; + gBattleStruct->changedSpecies[B_SIDE_PLAYER][i] = SPECIES_NONE; #if B_RECALCULATE_STATS >= GEN_5 // Recalculate the stats of every party member before the end diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 8855124dfd..194fa858e6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10615,7 +10615,7 @@ static void Cmd_various(void) { gBattleStruct->battleBondTransformed[GET_BATTLER_SIDE2(gBattlerAttacker)] |= gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]; PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerAttacker].species); - gBattleStruct->changedSpecies[gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species; + gBattleStruct->changedSpecies[B_SIDE_PLAYER][gBattlerPartyIndexes[gBattlerAttacker]] = gBattleMons[gBattlerAttacker].species; gBattleMons[gBattlerAttacker].species = SPECIES_GRENINJA_ASH; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_BattleBondActivatesOnMoveEndAttacker; diff --git a/src/battle_util.c b/src/battle_util.c index d24e03941f..0d9b87e012 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8268,6 +8268,10 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) && (!gProtectStructs[battlerId].maxGuarded || gBattleMoves[move].argument == MAX_EFFECT_BYPASS_PROTECT)) return FALSE; + + // Max Guard is silly about the moves it blocks, including Teatime. + if (gProtectStructs[battlerId].maxGuarded && IsMoveBlockedByMaxGuard(move)) + return TRUE; if (move == MOVE_TEATIME) return FALSE; @@ -8275,7 +8279,8 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) // Protective Pads doesn't stop Unseen Fist from bypassing Protect effects, so IsMoveMakingContact() isn't used here. // This means extra logic is needed to handle Shell Side Arm. if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNSEEN_FIST - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT || (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gBattleStruct->swapDamageCategory))) + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT || (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gBattleStruct->swapDamageCategory)) + && !gProtectStructs[battlerId].maxGuarded) // Max Guard cannot be bypassed by Unseen Fist return FALSE; else if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED)) return FALSE; @@ -10265,13 +10270,9 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); if (targetSpecies != SPECIES_NONE) { - // Saves the original species on the first form change for the player. - if (side == B_SIDE_PLAYER && gBattleStruct->changedSpecies[monId] == SPECIES_NONE) - gBattleStruct->changedSpecies[monId] = gBattleMons[battlerId].species; - - // Saves the original species for Gigantamax forms for the opponent. - if (side == B_SIDE_OPPONENT && gBattleStruct->dynamax.opponentBaseForm == SPECIES_NONE) - gBattleStruct->dynamax.opponentBaseForm = gBattleMons[battlerId].species; + // Saves the original species on the first form change. + if (gBattleStruct->changedSpecies[side][monId] == SPECIES_NONE) + gBattleStruct->changedSpecies[side][monId] = gBattleMons[battlerId].species; TryToSetBattleFormChangeMoves(&party[monId], method); SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); @@ -10279,8 +10280,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) RecalcBattlerStats(battlerId, &party[monId]); return TRUE; } - else if (gBattleStruct->changedSpecies[monId] != SPECIES_NONE - || gBattleStruct->dynamax.opponentBaseForm != SPECIES_NONE) + else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE) { bool8 restoreSpecies = FALSE; @@ -10300,10 +10300,7 @@ bool32 TryBattleFormChange(u8 battlerId, u16 method) { // Reverts the original species TryToSetBattleFormChangeMoves(&party[monId], method); - if (side == B_SIDE_PLAYER) - SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[monId]); - else - SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->dynamax.opponentBaseForm); + SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]); RecalcBattlerStats(battlerId, &party[monId]); return TRUE; } diff --git a/src/pokemon.c b/src/pokemon.c index 49dce5e202..70c83d3b73 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -8720,7 +8720,7 @@ bool32 TryFormChange(u32 monId, u32 side, u16 method) targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); if (targetSpecies == SPECIES_NONE && gBattleStruct != NULL) - targetSpecies = gBattleStruct->changedSpecies[monId]; + targetSpecies = gBattleStruct->changedSpecies[side][monId]; if (targetSpecies != SPECIES_NONE) { diff --git a/test/dynamax.c b/test/dynamax.c index 8891f76a57..b48da3738d 100644 --- a/test/dynamax.c +++ b/test/dynamax.c @@ -1,15 +1,6 @@ #include "global.h" #include "test_battle.h" -// TODO: -// ========== -// TEST: Max Guard protects against Transform, Block (not Mean Look), Flower Shield, Gear Up, and so on (see Bulba). -// TEST: Imprison doesn't stop Max Moves. (YES!) -// TEST: Max Moves change type as you'd expect with Normalize, Weather Ball, etc. (YES!) -// TEST: You use Struggle while Dynamaxed if out of PP. (YES!) -// Dynamax should not reset Speed Swap, Soak, or anything else from form changing. (NO) -// Max Moves cannot be used against allies. (NO) - // ============= DYNAMAX AND MAX MOVE INTERACTIONS =================== SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x") {