From 7d70222770ebcbd7225511641cffca8a7df159f9 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Mon, 20 Mar 2023 16:40:05 -0700 Subject: [PATCH] added most Dynamax immunities/interactions + tests + fixed some move selection bugs --- asm/macros/battle_script.inc | 5 + data/battle_scripts_1.s | 28 +++ include/battle.h | 3 +- include/battle_dynamax.h | 10 +- include/battle_scripts.h | 1 + include/constants/battle.h | 3 + include/constants/battle_script_commands.h | 3 +- include/constants/battle_string_ids.h | 3 +- src/battle_controller_player.c | 7 + src/battle_dynamax.c | 34 ++- src/battle_main.c | 6 +- src/battle_message.c | 2 + src/battle_script_commands.c | 109 ++++++--- src/battle_util.c | 25 +- src/data/battle_moves.h | 102 ++++----- test/dynamax.c | 252 ++++++++++++++++----- 16 files changed, 432 insertions(+), 161 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 08e3e37ed6..40bf528337 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2257,6 +2257,11 @@ various 0, VARIOUS_UPDATE_DYNAMAX .endm + .macro jumpiftargetdynamaxed, ptr:req + various 0, VARIOUS_JUMP_IF_TARGET_DYNAMAXED + .4byte \ptr + .endm + @ Tries to increase or decrease a battler's stat's stat stage by a specified amount. If impossible, jumps to \script. .macro modifybattlerstatstage battler:req, stat:req, mode:req, amount:req, script:req, animation:req, customString diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 902a993f1f..76bdffc22f 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2156,10 +2156,14 @@ BattleScript_EffectHitSwitchTarget: moveendall jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted + jumpiftargetdynamaxed BattleScript_HitSwitchTargetDynamaxed tryhitswitchtarget BattleScript_MoveEnd forcerandomswitch BattleScript_HitSwitchTargetForceRandomSwitchFailed goto BattleScript_MoveEnd +BattleScript_HitSwitchTargetDynamaxed: + printstring STRINGID_MOVEBLOCKEDBYDYNAMAX + waitmessage B_WAIT_TIME_LONG BattleScript_HitSwitchTargetForceRandomSwitchFailed: hitswitchtargetfailed setbyte sSWITCH_CASE, B_SWITCH_NORMAL @@ -3753,11 +3757,17 @@ BattleScript_EffectRoar:: jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted + jumpiftargetdynamaxed BattleScript_RoarBlockedByDynamax accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON accuracycheck BattleScript_MoveMissedPause, ACC_CURR_MOVE jumpifbattletype BATTLE_TYPE_ARENA, BattleScript_ButItFailed forcerandomswitch BattleScript_ButItFailed +BattleScript_RoarBlockedByDynamax: + printstring STRINGID_MOVEBLOCKEDBYDYNAMAX + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + BattleScript_EffectMultiHit:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE @@ -10215,6 +10225,7 @@ BattleScript_RedCardActivates:: swapattackerwithtarget jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_ROOTED, BattleScript_RedCardIngrain jumpifability BS_EFFECT_BATTLER, ABILITY_SUCTION_CUPS, BattleScript_RedCardSuctionCups + jumpiftargetdynamaxed BattleScript_RedCardDynamaxed setbyte sSWITCH_CASE, B_SWITCH_RED_CARD forcerandomswitch BattleScript_RedCardEnd @ changes the current battle script. the rest happens in BattleScript_RoarSuccessSwitch_Ret, if switch is successful @@ -10232,6 +10243,12 @@ BattleScript_RedCardSuctionCups: removeitem BS_SCRIPTING swapattackerwithtarget return +BattleScript_RedCardDynamaxed: + printstring STRINGID_MOVEBLOCKEDBYDYNAMAX + waitmessage B_WAIT_TIME_LONG + removeitem BS_SCRIPTING + swapattackerwithtarget + return BattleScript_EjectButtonActivates:: makevisible BS_ATTACKER @@ -10632,6 +10649,17 @@ BattleScript_DynamaxEnds:: waitanimation end2 +BattleScript_MoveBlockedByDynamax:: + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + attackstring + pause B_WAIT_TIME_SHORT + ppreduce + jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd + printstring STRINGID_MOVEBLOCKEDBYDYNAMAX + waitmessage B_WAIT_TIME_LONG + orword gHitMarker, HITMARKER_STRING_PRINTED + goto BattleScript_MoveEnd + BattleScript_PokemonCantUseTheMove:: attackstring ppreduce diff --git a/include/battle.h b/include/battle.h index 09e1b2cdb5..5366ce75e9 100644 --- a/include/battle.h +++ b/include/battle.h @@ -530,7 +530,8 @@ struct DynamaxData u8 usingMaxMove[MAX_BATTLERS_COUNT]; u8 activeSplit; u8 splits[MAX_BATTLERS_COUNT]; - u8 moveSlot[MAX_BATTLERS_COUNT]; // move slot of Max Move, used for Spite, TODO: Copycat, Encore, Grudge + u16 baseMove[MAX_BATTLERS_COUNT]; // base move of Max Move + u16 lastUsedBaseMove; }; struct StolenItem diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index 3854d4c032..1d6d8cd807 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -56,15 +56,17 @@ enum MaxMoveEffect MAX_EFFECT_BYPASS_PROTECT, }; -bool8 IsDynamaxed(u16 battlerId); -bool8 CanDynamax(u16 battlerId); +bool32 IsDynamaxed(u16 battlerId); +bool32 CanDynamax(u16 battlerId); void ApplyDynamaxHPMultiplier(u16 battlerId, struct Pokemon* mon); void PrepareBattlerForDynamax(u16 battlerId); void UndoDynamax(u16 battlerId); -bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove); +bool32 IsMoveBlockedByDynamax(u16 move); + +bool32 ShouldUseMaxMove(u16 battlerId, u16 baseMove); u16 GetMaxMove(u16 battlerId, u16 baseMove); u8 GetMaxMovePower(u16 move); -bool8 IsMaxMove(u16 move); +bool32 IsMaxMove(u16 move); const u8 *GetMaxMoveName(u16 move); void ChooseDamageNonTypesString(u8 type); u32 GetMaxMoveStatusEffect(u16 move); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 7252ffebd1..70acc0824a 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -495,5 +495,6 @@ extern const u8 BattleScript_EffectRecycleBerriesAllies[]; // dynamax and max raids extern const u8 BattleScript_DynamaxBegins[]; extern const u8 BattleScript_DynamaxEnds[]; +extern const u8 BattleScript_MoveBlockedByDynamax[]; #endif // GUARD_BATTLE_SCRIPTS_H \ No newline at end of file diff --git a/include/constants/battle.h b/include/constants/battle.h index 5504a0647d..d281494cb7 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -495,4 +495,7 @@ #define PARENTAL_BOND_2ND_HIT 1 #define PARENTAL_BOND_OFF 0 +// Constants for Torment +#define PERMANENT_TORMENT 0xF + #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 507702cfaa..7b827afd58 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -267,7 +267,8 @@ #define VARIOUS_TRY_SET_STATUS2 175 #define VARIOUS_TRY_HEAL_SIXTH_HP 176 #define VARIOUS_TRY_RECYCLE_BERRY 177 -#define VARIOUS_UPDATE_DYNAMAX 178 +#define VARIOUS_UPDATE_DYNAMAX 178 +#define VARIOUS_JUMP_IF_TARGET_DYNAMAXED 179 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 6855f5ec05..a7d5c7c287 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -658,8 +658,9 @@ #define STRINGID_PKMNBURNINGUP 656 #define STRINGID_TEAMSURROUNDEDBYROCKS 657 #define STRINGID_PKMNHURTBYROCKSTHROWN 658 +#define STRINGID_MOVEBLOCKEDBYDYNAMAX 659 -#define BATTLESTRINGS_COUNT 659 +#define BATTLESTRINGS_COUNT 660 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 2824944896..22f0c5c81a 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -632,6 +632,13 @@ static void HandleInputChooseMove(void) moveTarget = MOVE_TARGET_SELECTED; //damaging z moves always have selected target } + // Status moves turn into Max Guard when Dynamaxed, targets user. + if ((IsDynamaxed(gActiveBattler) || gBattleStruct->dynamax.playerSelect) + && gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].split == SPLIT_STATUS) + { + moveTarget = MOVE_TARGET_USER; + } + if (moveTarget & MOVE_TARGET_USER) gMultiUsePlayerCursor = gActiveBattler; else diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index 29419e2f64..7d84872544 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -92,7 +92,7 @@ static void SpriteCb_DynamaxTrigger(struct Sprite *); static void SpriteCb_DynamaxIndicator(struct Sprite *); // Returns whether a battler is Dynamaxed. -bool8 IsDynamaxed(u16 battlerId) +bool32 IsDynamaxed(u16 battlerId) { u8 side = GetBattlerSide(battlerId); if (gBattleStruct->dynamax.dynamaxed[battlerId] @@ -102,13 +102,17 @@ bool8 IsDynamaxed(u16 battlerId) } // Returns whether a battler can Dynamax. -bool8 CanDynamax(u16 battlerId) +bool32 CanDynamax(u16 battlerId) { // TODO: Requires Dynamax Band if not in a Max Raid (as well as special flag). + u16 species = gBattleMons[battlerId].species; if (!gBattleStruct->dynamax.alreadyDynamaxed[GetBattlerSide(battlerId)] && !gBattleStruct->dynamax.dynamaxed[battlerId] && !gBattleStruct->dynamax.dynamaxed[BATTLE_PARTNER(battlerId)] - && !gBattleStruct->dynamax.toDynamax[BATTLE_PARTNER(battlerId)]) + && !gBattleStruct->dynamax.toDynamax[BATTLE_PARTNER(battlerId)] + && species != SPECIES_ZACIAN && species != SPECIES_ZACIAN_CROWNED_SWORD + && species != SPECIES_ZAMAZENTA && species != SPECIES_ZAMAZENTA_CROWNED_SHIELD + && species != SPECIES_ETERNATUS && species != SPECIES_ETERNATUS_ETERNAMAX) return TRUE; return FALSE; } @@ -138,6 +142,13 @@ void PrepareBattlerForDynamax(u16 battlerId) gBattleStruct->dynamax.dynamaxed[battlerId] = TRUE; gBattleStruct->dynamax.dynamaxTurns[battlerId] = DYNAMAX_TURNS; + // Substitute is removed upon Dynamaxing. + gBattleMons[battlerId].status2 &= ~STATUS2_SUBSTITUTE; + ClearBehindSubstituteBit(battlerId); + + // Choiced Moves are reset upon Dynamaxing. + gBattleStruct->choicedMove[battlerId] = MOVE_NONE; + // Try Gigantamax form change. newSpecies = GetBattleFormChangeTargetSpecies(battlerId, FORM_CHANGE_BATTLE_GIGANTAMAX); if (newSpecies != SPECIES_NONE) @@ -156,8 +167,21 @@ void UndoDynamax(u16 battlerId) TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_SWITCH); // TODO: maybe nicer way to do this? } +// Weight-based moves (and some other moves in Raids) are blocked by Dynamax. +bool32 IsMoveBlockedByDynamax(u16 move) +{ + // TODO: Raid moves + switch (gBattleMoves[move].effect) + { + case EFFECT_HEAT_CRASH: + case EFFECT_LOW_KICK: + return TRUE; + } + return FALSE; +} + // Returns whether a move should be converted into a Max Move. -bool8 ShouldUseMaxMove(u16 battlerId, u16 baseMove) +bool32 ShouldUseMaxMove(u16 battlerId, u16 baseMove) { // TODO: Raids //if (IsRaidBoss(battlerId)) @@ -257,7 +281,7 @@ u8 GetMaxMovePower(u16 move) } // Returns whether a move is a Max Move or not. -bool8 IsMaxMove(u16 move) +bool32 IsMaxMove(u16 move) { return move >= FIRST_MAX_MOVE && move <= LAST_MAX_MOVE; } diff --git a/src/battle_main.c b/src/battle_main.c index 8c4e1118e2..56fe1e5fac 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4156,6 +4156,8 @@ static void HandleTurnActionSelectionState(void) } gBattleStruct->mega.toEvolve &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))]); + gBattleStruct->dynamax.toDynamax[gActiveBattler] = FALSE; + gBattleStruct->dynamax.usingMaxMove[gActiveBattler] = FALSE; gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))] = MOVE_NONE; BtlController_EmitEndBounceEffect(BUFFER_A); MarkBattlerForControllerExec(gActiveBattler); @@ -4251,7 +4253,7 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->dynamax.toDynamax[gActiveBattler] = TRUE; if (ShouldUseMaxMove(gActiveBattler, gChosenMoveByBattler[gActiveBattler])) // max move check { - gBattleStruct->dynamax.moveSlot[gActiveBattler] = gBattleStruct->chosenMovePositions[gActiveBattler]; + gBattleStruct->dynamax.baseMove[gActiveBattler] = gBattleMons[gActiveBattler].moves[gBattleStruct->chosenMovePositions[gActiveBattler]]; gBattleStruct->dynamax.usingMaxMove[gActiveBattler] = TRUE; } gBattleCommunication[gActiveBattler]++; @@ -4520,7 +4522,7 @@ u32 GetBattlerTotalSpeedStat(u8 battlerId) speed /= 2; else if (holdEffect == HOLD_EFFECT_IRON_BALL) speed /= 2; - else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF) + else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF && !IsDynamaxed(battlerId)) speed = (speed * 150) / 100; else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battlerId].species == SPECIES_DITTO && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED)) speed *= 2; diff --git a/src/battle_message.c b/src/battle_message.c index 49c88cc0c4..ec6a2dffdc 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -793,9 +793,11 @@ static const u8 sText_TeamSurroundedByRocks[] = _("{B_DEF_TEAM1} team was surrou static const u8 sText_PkmnHurtByRocksThrown[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt by\nrocks thrown out by G-Max Volcalith!"); static const u8 sText_CouldntFullyProtect[] = _("{B_DEF_NAME_WITH_PREFIX} couldn't fully protect\nitself and got hurt!"); static const u8 sText_StockpiledEffectWoreOff[] = _("{B_ATK_NAME_WITH_PREFIX}'s stockpiled\neffect wore off!"); +static const u8 sText_MoveBlockedByDynamax[] = _("The move was blocked by\nthe power of Dynamax!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_MOVEBLOCKEDBYDYNAMAX - BATTLESTRINGS_TABLE_START] = sText_MoveBlockedByDynamax, [STRINGID_STOCKPILEDEFFECTWOREOFF - BATTLESTRINGS_TABLE_START] = sText_StockpiledEffectWoreOff, [STRINGID_COULDNTFULLYPROTECT - BATTLESTRINGS_TABLE_START] = sText_CouldntFullyProtect, [STRINGID_PKMNHURTBYROCKSTHROWN - BATTLESTRINGS_TABLE_START] = sText_PkmnHurtByRocksThrown, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2a75e34e81..8b969a6589 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -971,7 +971,7 @@ static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / #define FORBIDDEN_INSTRUCT (1 << 5) #define FORBIDDEN_PARENTAL_BOND (1 << 6) -static const u8 sForbiddenMoves[MOVES_COUNT] = +static const u8 sForbiddenMoves[MOVES_COUNT_DYNAMAX] = { [MOVE_NONE] = 0xFF, // Can't use a non-move lol [MOVE_STRUGGLE] = 0xFF, // Neither Struggle @@ -1481,6 +1481,14 @@ static void Cmd_attackcanceler(void) } } + // Weight-based moves are blocked by Dynamax. + if (IsDynamaxed(gBattlerTarget) && IsMoveBlockedByDynamax(gCurrentMove)) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax; + return; + } + if (gBattleOutcome != 0) { gCurrentActionFuncId = B_ACTION_FINISHED; @@ -3234,26 +3242,20 @@ void SetMoveEffect(bool32 primary, u32 certain) } break; case MOVE_EFFECT_FLINCH: - if (battlerAbility == ABILITY_INNER_FOCUS) + if (battlerAbility == ABILITY_INNER_FOCUS + && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { - if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN) - { - gLastUsedAbility = ABILITY_INNER_FOCUS; - gBattlerAbility = gEffectBattler; - RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); - gBattlescriptCurrInstr = BattleScript_FlinchPrevention; - } - else - { - gBattlescriptCurrInstr++; - } + gLastUsedAbility = ABILITY_INNER_FOCUS; + gBattlerAbility = gEffectBattler; + RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS); + gBattlescriptCurrInstr = BattleScript_FlinchPrevention; } - else + else if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber + && !IsDynamaxed(gEffectBattler)) { - if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber) - gBattleMons[gEffectBattler].status2 |= sStatusFlagsForMoveEffects[gBattleScripting.moveEffect]; - gBattlescriptCurrInstr++; + gBattleMons[gEffectBattler].status2 |= sStatusFlagsForMoveEffects[gBattleScripting.moveEffect]; } + gBattlescriptCurrInstr++; break; case MOVE_EFFECT_UPROAR: if (!(gBattleMons[gEffectBattler].status2 & STATUS2_UPROAR)) @@ -3893,7 +3895,8 @@ static void Cmd_tryfaintmon(void) gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL); gSideTimers[1].retaliateTimer = 2; } - if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBattlerAttacker].hp != 0) + if ((gHitMarker & HITMARKER_DESTINYBOND) && gBattleMons[gBattlerAttacker].hp != 0 + && !IsDynamaxed(gBattlerAttacker)) { gHitMarker &= ~HITMARKER_DESTINYBOND; BattleScriptPush(gBattlescriptCurrInstr); @@ -5785,6 +5788,8 @@ static void Cmd_moveend(void) { gLastPrintedMoves[gBattlerAttacker] = gChosenMove; gLastUsedMove = gCurrentMove; + if (IsMaxMove(gCurrentMove)) + gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMove[gBattlerAttacker]; } } if (!(gAbsentBattlerFlags & gBitTable[gBattlerAttacker]) @@ -9629,7 +9634,8 @@ static void Cmd_various(void) } else { - if (gBattleMons[gBattlerTarget].ability == gBattleMons[gBattlerAttacker].ability) + if (gBattleMons[gBattlerTarget].ability == gBattleMons[gBattlerAttacker].ability + || IsDynamaxed(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -9932,7 +9938,10 @@ static void Cmd_various(void) } else { - gCalledMove = gLastUsedMove; + if (IsMaxMove(gLastUsedMove)) + gCalledMove = gBattleStruct->dynamax.lastUsedBaseMove; + else + gCalledMove = gLastUsedMove; gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gBattlescriptCurrInstr = cmd->nextInstr; @@ -9943,7 +9952,8 @@ static void Cmd_various(void) { VARIOUS_ARGS(const u8 *failInstr); if ((sForbiddenMoves[gLastMoves[gBattlerTarget]] & FORBIDDEN_INSTRUCT) - || gLastMoves[gBattlerTarget] == 0xFFFF) + || gLastMoves[gBattlerTarget] == 0xFFFF + || IsDynamaxed(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -11340,6 +11350,15 @@ static void Cmd_various(void) UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HP_BOTH); break; } + case VARIOUS_JUMP_IF_TARGET_DYNAMAXED: + { + VARIOUS_ARGS(const u8 *jumpInstr); + if (IsDynamaxed(gBattlerTarget)) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; + return; + } } // End of switch (cmd->id) gBattlescriptCurrInstr = cmd->nextInstr; @@ -12682,6 +12701,15 @@ static void Cmd_tryKO(void) u32 holdEffect = GetBattlerHoldEffect(gBattlerTarget, TRUE); u16 targetAbility = GetBattlerAbility(gBattlerTarget); + // Dynamaxed Pokemon cannot be hit by OHKO moves. + if (IsDynamaxed(gBattlerTarget)) + { + gMoveResultFlags |= MOVE_RESULT_MISSED; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_KO_UNAFFECTED; + gBattlescriptCurrInstr = cmd->failInstr; + return; + } + gPotentialItemEffectBattler = gBattlerTarget; if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(gBattlerTarget)) @@ -13234,10 +13262,21 @@ static void Cmd_trysetencore(void) s32 i; - for (i = 0; i < MAX_MON_MOVES; i++) + if (IsMaxMove(gLastMoves[gBattlerTarget]) && !IsDynamaxed(gBattlerTarget)) { - if (gBattleMons[gBattlerTarget].moves[i] == gLastMoves[gBattlerTarget]) - break; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBattleMons[gBattlerTarget].moves[i] == gBattleStruct->dynamax.baseMove[gBattlerTarget]) + break; + } + } + else + { + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBattleMons[gBattlerTarget].moves[i] == gLastMoves[gBattlerTarget]) + break; + } } if (gLastMoves[gBattlerTarget] == MOVE_NONE @@ -13541,11 +13580,21 @@ static void Cmd_tryspiteppreduce(void) // Get move slot to reduce PP. if (IsMaxMove(gLastMoves[gBattlerTarget])) - i = gBattleStruct->dynamax.moveSlot[gBattlerTarget]; - else + { for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBattleStruct->dynamax.baseMove[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i]) + break; + } + } + else + { + for (i = 0; i < MAX_MON_MOVES; i++) + { if (gLastMoves[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i]) break; + } + } #if B_CAN_SPITE_FAIL <= GEN_3 if (i != MAX_MON_MOVES && gBattleMons[gBattlerTarget].pp[i] > 1) @@ -14459,15 +14508,15 @@ static void Cmd_settorment(void) { CMD_ARGS(const u8 *failInstr); - if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT) + if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT + || IsDynamaxed(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } else { - // TODO: Torment does not affect Dynamaxed Pokemon and prints a failure string. gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; - gDisableStructs[gBattlerTarget].tormentTimer = 0xF; // permanent + gDisableStructs[gBattlerTarget].tormentTimer = PERMANENT_TORMENT; // permanent gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -14845,7 +14894,7 @@ static void Cmd_tryswapabilities(void) } else { - if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + if (gMoveResultFlags & MOVE_RESULT_NO_EFFECT || IsDynamaxed(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } diff --git a/src/battle_util.c b/src/battle_util.c index eeb0f58af5..385c2bdb04 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1890,7 +1890,7 @@ u8 TrySetCantSelectMoveBattleScript(void) } gPotentialItemEffectBattler = gActiveBattler; - if (HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) + if (!gBattleStruct->dynamax.playerSelect && (holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) { gCurrentMove = *choicedMove; gLastUsedItem = gBattleMons[gActiveBattler].item; @@ -1920,7 +1920,7 @@ u8 TrySetCantSelectMoveBattleScript(void) limitations++; } } - if ((GetBattlerAbility(gActiveBattler) == ABILITY_GORILLA_TACTICS) && *choicedMove != MOVE_NONE + if (!gBattleStruct->dynamax.playerSelect && (GetBattlerAbility(gActiveBattler) == ABILITY_GORILLA_TACTICS) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) { gCurrentMove = *choicedMove; @@ -3209,7 +3209,7 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_TORMENT: - if (gDisableStructs[gActiveBattler].tormentTimer <= 4 + if (gDisableStructs[gActiveBattler].tormentTimer != PERMANENT_TORMENT && --gDisableStructs[gActiveBattler].tormentTimer == 0) { gBattleMons[gActiveBattler].status2 &= ~STATUS2_TORMENT; @@ -5425,6 +5425,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && IsBattlerAlive(gBattlerAttacker) && !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL) && gBattleMons[gBattlerAttacker].pp[gChosenMovePos] != 0 + && !IsDynamaxed(gBattlerAttacker) // TODO: Max Moves don't make contact, useless? && (Random() % 3) == 0) { gDisableStructs[gBattlerAttacker].disabledMove = gChosenMove; @@ -5475,7 +5476,8 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) + && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && !IsDynamaxed(gBattlerTarget)) { switch (gBattleMons[gBattlerAttacker].ability) { @@ -8252,11 +8254,10 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) return FALSE; } - // Z-Moves and Max Moves bypass protection (except Max Guard for Max Moves). - if ((IsMaxMove(move) - && !(gProtectStructs[battlerId].maxGuarded - && gBattleMoves[move].argument != MAX_EFFECT_BYPASS_PROTECT)) - || gBattleStruct->zmove.active) + // Z-Moves and Max Moves bypass protection (except Max Guard). + if ((IsMaxMove(move) || gBattleStruct->zmove.active) + && (!gProtectStructs[battlerId].maxGuarded + || gBattleMoves[move].argument == MAX_EFFECT_BYPASS_PROTECT)) return FALSE; if (move == MOVE_TEATIME) @@ -8728,10 +8729,8 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) MulModifier(&basePower, UQ_4_12(1.5)); break; case EFFECT_DYNAMAX_DOUBLE_DMG: - #ifdef B_DYNAMAX if (IsDynamaxed(battlerDef)) basePower *= 2; - #endif break; case EFFECT_HIDDEN_POWER: { @@ -9362,11 +9361,11 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b MulModifier(&modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_CHOICE_BAND: - if (IS_MOVE_PHYSICAL(move)) + if (IS_MOVE_PHYSICAL(move) && !IsDynamaxed(battlerAtk)) MulModifier(&modifier, UQ_4_12(1.5)); break; case HOLD_EFFECT_CHOICE_SPECS: - if (IS_MOVE_SPECIAL(move)) + if (IS_MOVE_SPECIAL(move) && !IsDynamaxed(battlerAtk)) MulModifier(&modifier, UQ_4_12(1.5)); break; } diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 99f4440009..eaba69d357 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -14111,7 +14111,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_SUN, }, @@ -14126,7 +14126,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_SP_ATK, }, @@ -14141,7 +14141,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_ELECTRIC_TERRAIN, }, @@ -14156,7 +14156,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_SPEED, }, @@ -14171,7 +14171,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_ATTACK, }, @@ -14186,7 +14186,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_DEFENSE, }, @@ -14201,7 +14201,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_HAIL, }, @@ -14216,7 +14216,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_SP_ATK, }, @@ -14231,7 +14231,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAIN, }, @@ -14246,7 +14246,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_SPEED, }, @@ -14261,7 +14261,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_MISTY_TERRAIN, }, @@ -14276,7 +14276,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_ATTACK, }, @@ -14291,7 +14291,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_PSYCHIC_TERRAIN, }, @@ -14306,7 +14306,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_SANDSTORM, }, @@ -14321,7 +14321,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_SP_DEF, }, @@ -14336,7 +14336,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_SP_DEF, }, @@ -14351,7 +14351,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_GRASSY_TERRAIN, }, @@ -14366,7 +14366,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RAISE_TEAM_DEFENSE, }, @@ -14381,7 +14381,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_VINE_LASH, }, @@ -14396,7 +14396,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_WILDFIRE, }, @@ -14411,7 +14411,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_CANNONADE, }, @@ -14426,7 +14426,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_EFFECT_SPORE_FOES, }, @@ -14441,7 +14441,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_PARALYZE_FOES, }, @@ -14456,7 +14456,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_CONFUSE_FOES_PAY_DAY, }, @@ -14471,7 +14471,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_CRIT_PLUS, }, @@ -14486,7 +14486,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_MEAN_LOOK, }, @@ -14501,7 +14501,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_SPEED_2_FOES, }, @@ -14516,7 +14516,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_AURORA_VEIL, }, @@ -14531,7 +14531,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_INFATUATE_FOES, }, @@ -14546,7 +14546,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_RECYCLE_BERRIES, }, @@ -14561,7 +14561,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_POISON_FOES, }, @@ -14576,7 +14576,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_TORMENT_FOES, }, @@ -14591,7 +14591,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_TARGET_ABILITY_IGNORED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_TARGET_ABILITY_IGNORED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_FIXED_POWER, //EFFECT TODO }, @@ -14606,7 +14606,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_TARGET_ABILITY_IGNORED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_TARGET_ABILITY_IGNORED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_FIXED_POWER, //EFFECT TODO }, @@ -14621,7 +14621,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = FLAG_TARGET_ABILITY_IGNORED, + .flags = FLAG_PROTECT_AFFECTED | FLAG_TARGET_ABILITY_IGNORED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_FIXED_POWER, //EFFECT TODO }, @@ -14636,7 +14636,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_DEFOG, }, @@ -14651,7 +14651,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_GRAVITY, }, @@ -14666,7 +14666,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_STEALTH_ROCK, }, @@ -14681,7 +14681,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_VOLCALITH, }, @@ -14696,7 +14696,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_LOWER_EVASIVENESS_FOES, }, @@ -14711,7 +14711,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_AROMATHERAPY, }, @@ -14726,7 +14726,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_SANDBLAST_FOES, }, @@ -14741,7 +14741,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_POISON_PARALYZE_FOES, }, @@ -14756,7 +14756,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_FIRE_SPIN_FOES, }, @@ -14771,7 +14771,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_CONFUSE_FOES, }, @@ -14787,7 +14787,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_YAWN_FOE, }, @@ -14802,7 +14802,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_HEAL_TEAM, }, @@ -14817,7 +14817,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_STEELSURGE, }, @@ -14832,7 +14832,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_SPITE, }, @@ -14847,7 +14847,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_BYPASS_PROTECT, //EFFECT TODO }, @@ -14862,7 +14862,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .secondaryEffectChance = 100, .target = MOVE_TARGET_SELECTED, .priority = 0, - .flags = 0, + .flags = FLAG_PROTECT_AFFECTED, .split = SPLIT_PHYSICAL, .argument = MAX_EFFECT_BYPASS_PROTECT, //EFFECT TODO }, diff --git a/test/dynamax.c b/test/dynamax.c index fee7336be6..31434c50fc 100644 --- a/test/dynamax.c +++ b/test/dynamax.c @@ -2,19 +2,12 @@ #include "test_battle.h" // TODO: -// Max Moves cannot miss. // Max Guard protects against Transform, Block (not Mean Look), Flower Shield, Gear Up, and so on (see Bulba). -// Max Moves penetrate Protect, but not Max Guard. -// Feint damages through Max Guard, but doesn't break it. -// You can ignore the effect of Encore / Disable with Max Moves. -// You can Encore the base move of a Max Move after Dynamax, but not Disable or Instruct. // Imprison doesn't stop Max Moves. -// Copycat copies the base move of a Max Move (even Trick Room!). -// Assault Vest prevents the use of Max Guard; so does Taunt. // Max Moves change type as you'd expect with Normalize, Weather Ball, etc. -// Dynamax Cannon and such do double damage on Dynamaxed opponents. +// (Unrelated) Refactor code to remove dynamax.usingMaxMove? -// DYNAMAX FEATURES +// ============= DYNAMAX AND MAX MOVE INTERACTIONS =================== SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x") { GIVEN { // TODO: Dynamax level @@ -56,7 +49,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched") { - KNOWN_FAILING; GIVEN { ASSUME(gBattleMoves[MOVE_FAKE_OUT].effect == EFFECT_FAKE_OUT); PLAYER(SPECIES_WOBBUFFET); @@ -69,47 +61,45 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched") } } +// Message is "Steelix shook its head. It seems like it can't use this move..."? SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by weight-based moves") { - // Message is "Steelix shook its head. It seems like it can't use this move..."? - KNOWN_FAILING; GIVEN { ASSUME(gBattleMoves[MOVE_HEAVY_SLAM].effect == EFFECT_HEAT_CRASH); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_HEAVY_SLAM); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_HEAVY_SLAM); } } SCENE { - MESSAGE("Foe Wobbuffet used Heavy Slam!"); - MESSAGE("Wobbuffet is unaffected!"); MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Foe Wobbuffet used Heavy Slam!"); + MESSAGE("The move was blocked by the power of Dynamax!"); + NONE_OF { HP_BAR(player); } } } SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by OHKO moves") { - KNOWN_FAILING; GIVEN { ASSUME(gBattleMoves[MOVE_FISSURE].effect == EFFECT_OHKO); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_MACHAMP) { Ability(ABILITY_NO_GUARD); } } WHEN { - TURN { MOVE(opponent, MOVE_FISSURE); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_FISSURE); } } SCENE { - MESSAGE("Foe Wobbuffet used Fissure!"); + MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Foe Machamp used Fissure!"); MESSAGE("Wobbuffet is unaffected!"); NONE_OF { HP_BAR(player); } - MESSAGE("Wobbuffet used Max Strike!"); } } // can't be used at all in Raid, see "Documenting Dynamax" SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Destiny Bond") { - KNOWN_FAILING; GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { TURN { MOVE(opponent, MOVE_DESTINY_BOND); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } } SCENE { @@ -122,10 +112,9 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Destiny Bond SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are affected by Grudge") { - KNOWN_FAILING; GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { TURN { MOVE(opponent, MOVE_GRUDGE); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } } SCENE { @@ -138,28 +127,32 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are affected by Grudge") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by phazing moves, but still take damage") { - KNOWN_FAILING; GIVEN { ASSUME(gBattleMoves[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(gBattleMoves[MOVE_WHIRLWIND].effect == EFFECT_ROAR); PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_DRAGON_TAIL); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } - TURN {} + TURN { MOVE(opponent, MOVE_WHIRLWIND); MOVE(player, MOVE_TACKLE); } } SCENE { MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("Foe Wobbuffet used Dragon Tail!"); - MESSAGE("The move was blocked by the power of Dynamax!"); HP_BAR(player); - MESSAGE("Wobbuffet used Max Guard!"); + MESSAGE("The move was blocked by the power of Dynamax!"); + MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Foe Wobbuffet used Whirlwind!"); + MESSAGE("The move was blocked by the power of Dynamax!"); } } SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Red Card") { - KNOWN_FAILING; GIVEN { + ASSUME(gItems[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, dynamax: TRUE); MOVE(opponent, MOVE_CELEBRATE); } @@ -175,12 +168,12 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Red Card") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can be switched out by Eject Button") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } } SCENE { MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("Foe Wobbuffet used Tackle!"); @@ -191,27 +184,25 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can be switched out by Eject But } } -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot have their ability swapped with another Pokemon") +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot have their ability swapped to another Pokemon's") { - KNOWN_FAILING; GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); - PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + PLAYER(SPECIES_MILTANK) { Ability(ABILITY_SCRAPPY); } OPPONENT(SPECIES_RUNERIGUS) { Ability(ABILITY_WANDERING_SPIRIT); } } WHEN { TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_SKILL_SWAP); } } SCENE { - MESSAGE("Wobbuffet used Max Strike!"); - MESSAGE("Foe Wobbuffet used Skill Swap!"); + MESSAGE("Miltank used Max Strike!"); + MESSAGE("Foe Runerigus used Skill Swap!"); MESSAGE("But it failed!"); } FINALLY { - EXPECT_EQ(player->ability, ABILITY_SHADOW_TAG); + EXPECT_EQ(player->ability, ABILITY_SCRAPPY); } } -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their ability changed") +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their ability changed or suppressed") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } OPPONENT(SPECIES_WOBBUFFET); @@ -228,7 +219,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their ability changed") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Encore") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -241,10 +231,28 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Encore") } } -// TODO: Test Cursed Body, too. +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can be encored immediately after reverting") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; + } WHEN { + TURN { MOVE(player, MOVE_ARM_THRUST, dynamax: TRUE); } + TURN { MOVE(player, MOVE_ARM_THRUST); } + TURN { MOVE(player, MOVE_ARM_THRUST); } + TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("Foe Wobbuffet used Encore!"); + MESSAGE("Wobbuffet used Arm Thrust!"); + } +} + +// Max Moves don't make contact, so Cursed Body doesn't need to be tested? Implemented a check anyway SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon's Max Moves cannot be disabled") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -259,17 +267,19 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon's Max Moves cannot be disabled") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have base moves disabled on their first turn") { - KNOWN_FAILING; GIVEN { ASSUME(B_DISABLE_TURNS >= GEN_5); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_TACKLE); } TURN { MOVE(opponent, MOVE_DISABLE); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } TURN {} TURN {} - TURN {} // TODO: Tackle should still be disabled. + TURN { MOVE(player, MOVE_TACKLE, allowed: FALSE); MOVE(player, MOVE_CELEBRATE); } } SCENE { + MESSAGE("Foe Wobbuffet used Celebrate!"); + MESSAGE("Wobbuffet used Tackle!"); MESSAGE("Foe Wobbuffet used Disable!"); MESSAGE("Wobbuffet's Tackle was disabled!"); MESSAGE("Wobbuffet used Max Strike!"); @@ -278,7 +288,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have base moves disabled on SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Torment") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -294,7 +303,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Torment") // This is true for all item-removing moves. SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not immune to Knock Off") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POTION); } OPPONENT(SPECIES_WOBBUFFET); @@ -303,13 +311,12 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not immune to Knock Off") } SCENE { MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("Foe Wobbuffet used Knock Off!"); - MESSAGE("Wobbuffet's Potion was knocked off!"); + MESSAGE("Foe Wobbuffet knocked off Wobbuffet's Potion!"); } } SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon lose their substitutes") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -318,14 +325,153 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon lose their substitutes") TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_TACKLE); } } SCENE { MESSAGE("Wobbuffet used Substitute!"); - MESSAGE("Wobbuffet set up a substitute!"); + MESSAGE("Wobbuffet made a SUBSTITUTE!"); MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("Foe Wobbuffet used Tackle!"); HP_BAR(player); } } -// ============= MAX MOVE EFFECTS =================== +DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their base moves copied by Copycat") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_TRICK_ROOM, dynamax: TRUE, target: opponentLeft); MOVE(playerRight, MOVE_COPYCAT, target: opponentLeft); } + } SCENE { + MESSAGE("Wobbuffet used Max Guard!"); + MESSAGE("Wynaut used Trick Room!"); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon take double damage from Dynamax Cannon", s16 damage) +{ + bool32 dynamaxed; + PARAMETRIZE { dynamaxed = FALSE; } + PARAMETRIZE { dynamaxed = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, dynamax: dynamaxed); MOVE(opponent, MOVE_DYNAMAX_CANNON); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves deal 1/4 damage through protect", s16 damage) +{ + bool32 protected; + KNOWN_FAILING; // rounding error? also messages are wonky + PARAMETRIZE { protected = FALSE; } + PARAMETRIZE { protected = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (protected) + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_PROTECT); } + else + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.25), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves don't bypass Max Guard") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); MOVE(opponent, MOVE_PROTECT, dynamax: TRUE); } + } SCENE { + NONE_OF { HP_BAR(opponent); } + } +} + +DOUBLE_BATTLE_TEST("(DYNAMAX) Feint bypasses Max Guard but doesn't break it") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_PROTECT, dynamax: TRUE); + MOVE(opponentLeft, MOVE_FEINT, target: playerLeft); + MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); + } + } SCENE { + MESSAGE("Wobbuffet used Max Guard!"); + MESSAGE("Foe Wobbuffet used Feint!"); + HP_BAR(playerLeft); + MESSAGE("Foe Wynaut used Tackle!"); + NONE_OF { HP_BAR(playerLeft); } + } +} + +DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Instruct") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE, dynamax: TRUE, target: opponentLeft); + MOVE(playerRight, MOVE_INSTRUCT, target: playerLeft); + } + } SCENE { + MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Wynaut used Instruct!"); + MESSAGE("But it failed!"); + } +} + +// Move selection tests can't be simulated :( +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Choice items", s16 damage) +{ + u16 item; + PARAMETRIZE { item = ITEM_CHOICE_BAND; } + PARAMETRIZE { item = ITEM_NONE; } + GIVEN { + ASSUME(gItems[ITEM_CHOICE_BAND].holdEffect == HOLD_EFFECT_CHOICE_BAND); + PLAYER(SPECIES_WOBBUFFET) { Item(item); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Max Strike!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot use Max Guard while holding Assault Vest") +{ + GIVEN { + ASSUME(gItems[ITEM_ASSAULT_VEST].holdEffect == HOLD_EFFECT_ASSAULT_VEST); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_ASSAULT_VEST); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(player, MOVE_PROTECT, allowed: FALSE); MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Wobbuffet used Max Strike!"); + } +} + +// ============= MAX MOVE EFFECTS ========================================== SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") { GIVEN {