added most Dynamax immunities/interactions + tests + fixed some move selection bugs

This commit is contained in:
AgustinGDLV 2023-03-20 16:40:05 -07:00
parent 4c28b6384f
commit 7d70222770
16 changed files with 432 additions and 161 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
},

View File

@ -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 {