diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index de8d68cb51..63118da4a3 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3042,6 +3042,67 @@ static void SetNonVolatileStatus(u32 effectBattler, enum MoveEffect effect, cons gBattleStruct->poisonPuppeteerConfusion = TRUE; } +static inline bool32 IgnoreTargetingForMoveEffect(enum MoveEffect moveEffect) // Currently only used to determine move effects which happen even if the move's defined effectbattler is fainted +{ + switch (moveEffect) + { + case MOVE_EFFECT_PAYDAY: + case MOVE_EFFECT_BUG_BITE: + case MOVE_EFFECT_FLAME_BURST: + case MOVE_EFFECT_STEALTH_ROCK: + case MOVE_EFFECT_STEELSURGE: + case MOVE_EFFECT_SUN: + case MOVE_EFFECT_RAIN: + case MOVE_EFFECT_SANDSTORM: + case MOVE_EFFECT_HAIL: + case MOVE_EFFECT_MISTY_TERRAIN: + case MOVE_EFFECT_GRASSY_TERRAIN: + case MOVE_EFFECT_ELECTRIC_TERRAIN: + case MOVE_EFFECT_PSYCHIC_TERRAIN: + case MOVE_EFFECT_DEFOG: + case MOVE_EFFECT_REFLECT: + case MOVE_EFFECT_LIGHT_SCREEN: + case MOVE_EFFECT_AURORA_VEIL: + case MOVE_EFFECT_GRAVITY: + case MOVE_EFFECT_HEAL_TEAM: + case MOVE_EFFECT_AROMATHERAPY: + case MOVE_EFFECT_RECYCLE_BERRIES: + case MOVE_EFFECT_ION_DELUGE: + case MOVE_EFFECT_HAZE: + case MOVE_EFFECT_RAISE_TEAM_ATTACK: + case MOVE_EFFECT_RAISE_TEAM_DEFENSE: + case MOVE_EFFECT_RAISE_TEAM_SPEED: + case MOVE_EFFECT_RAISE_TEAM_SP_ATK: + case MOVE_EFFECT_RAISE_TEAM_SP_DEF: + case MOVE_EFFECT_CRIT_PLUS_SIDE: + case MOVE_EFFECT_LOWER_ATTACK_SIDE: + case MOVE_EFFECT_LOWER_DEFENSE_SIDE: + case MOVE_EFFECT_LOWER_SPEED_SIDE: + case MOVE_EFFECT_LOWER_SP_ATK_SIDE: + case MOVE_EFFECT_LOWER_SP_DEF_SIDE: + case MOVE_EFFECT_LOWER_SPEED_2_SIDE: + case MOVE_EFFECT_LOWER_EVASIVENESS_SIDE: + case MOVE_EFFECT_VINE_LASH: + case MOVE_EFFECT_WILDFIRE: + case MOVE_EFFECT_CANNONADE: + case MOVE_EFFECT_VOLCALITH: + case MOVE_EFFECT_PREVENT_ESCAPE_SIDE: + case MOVE_EFFECT_SANDBLAST_SIDE: + case MOVE_EFFECT_FIRE_SPIN_SIDE: + case MOVE_EFFECT_PARALYZE_SIDE: + case MOVE_EFFECT_POISON_SIDE: + case MOVE_EFFECT_CONFUSE_PAY_DAY_SIDE: + case MOVE_EFFECT_POISON_PARALYZE_SIDE: + case MOVE_EFFECT_EFFECT_SPORE_SIDE: + case MOVE_EFFECT_INFATUATE_SIDE: + case MOVE_EFFECT_CONFUSE_SIDE: + case MOVE_EFFECT_TORMENT_SIDE: + return TRUE; + default: + return FALSE; + } +} + // To avoid confusion the arguments are naned battler/effectBattler since they can be different from gBattlerAttacker/gBattlerTarget void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, const u8 *battleScript, enum SetMoveEffectFlags effectFlags) { @@ -3052,7 +3113,6 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); union StatChangeFlags flags = {0}; u32 battlerAbility; - bool32 activateAfterFaint = FALSE; // NULL move effect if (moveEffect == MOVE_EFFECT_NONE) @@ -3065,19 +3125,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c gBattlescriptCurrInstr = battleScript; return; } - - switch (moveEffect) // Set move effects which happen later on - { - case MOVE_EFFECT_STEALTH_ROCK: - case MOVE_EFFECT_PAYDAY: - case MOVE_EFFECT_BUG_BITE: - case MOVE_EFFECT_FLAME_BURST: - activateAfterFaint = TRUE; - break; - default: - break; - } - + gBattleScripting.battler = battler; gEffectBattler = effectBattler; battlerAbility = GetBattlerAbility(gEffectBattler); @@ -3088,7 +3136,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c && IsSheerForceAffected(gCurrentMove, GetBattlerAbility(battler)) && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE)) moveEffect = MOVE_EFFECT_NONE; - else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) + else if (!IsBattlerAlive(gEffectBattler) && !IgnoreTargetingForMoveEffect(moveEffect)) moveEffect = MOVE_EFFECT_NONE; else if (DoesSubstituteBlockMove(gBattlerAttacker, gEffectBattler, gCurrentMove) && !affectsUser) moveEffect = MOVE_EFFECT_NONE; diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index 787682417f..2323469d3a 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -997,6 +997,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Volt Crash paralyzes both opponents") TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); } } SCENE { MESSAGE("Pikachu used G-Max Volt Crash!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_VOLT_CRASH, playerLeft); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft); MESSAGE("The opposing Wobbuffet is paralyzed, so it may be unable to move!"); STATUS_ICON(opponentLeft, paralysis: TRUE); @@ -1309,6 +1310,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of th PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH); GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_REPLENISH, MOVE_EFFECT_RECYCLE_BERRIES)); + ASSUME(GetItemHoldEffect(ITEM_APICOT_BERRY) == HOLD_EFFECT_SP_DEFENSE_UP); PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); } PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); } @@ -1321,12 +1323,14 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of th TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); } } SCENE { // turn 1 + MESSAGE("Using Apicot Berry, the Sp. Def of Snorlax rose!"); MESSAGE("Using Apicot Berry, the Sp. Def of Munchlax rose!"); MESSAGE("Using Apicot Berry, the Sp. Def of the opposing Wobbuffet rose!"); MESSAGE("Using Apicot Berry, the Sp. Def of the opposing Wobbuffet rose!"); // turn 2 MESSAGE("Snorlax used G-Max Replenish!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_REPLENISH, playerLeft); MESSAGE("Snorlax found one Apicot Berry!"); MESSAGE("Munchlax found one Apicot Berry!"); } @@ -1369,6 +1373,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Finale heals allies by 1/6 of their health") TURN { MOVE(playerLeft, MOVE_MOONBLAST, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); } } SCENE { MESSAGE("Alcremie used G-Max Finale!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_FINALE, playerLeft); HP_BAR(playerLeft, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); } THEN { @@ -1710,5 +1715,81 @@ DOUBLE_BATTLE_TEST("Dynamax stat raising moves don't make stat-changing abilitie } } +DOUBLE_BATTLE_TEST("Dynamax: G-Max Finale heals allies by 1/6 of their health, even if it faints the foe") +{ + s16 damage1, damage2; + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_FINALE, MOVE_EFFECT_HEAL_TEAM)); + PLAYER(SPECIES_ALCREMIE) { HP(1); GigantamaxFactor(TRUE); } + PLAYER(SPECIES_MILCERY) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MOONBLAST, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2); } + } SCENE { + MESSAGE("Alcremie used G-Max Finale!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_FINALE, playerLeft); + HP_BAR(playerLeft, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } THEN { + EXPECT_MUL_EQ(-damage1, Q_4_12(6), playerLeft->maxHP); // heals based on Dynamax HP. Appears to have a problem with milcery in this case!? + } +} + +DOUBLE_BATTLE_TEST("Dynamax: G-Max Replenish recycles allies' berries 50\% of the time, even if it faints the foe") +{ + PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH); + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_REPLENISH, MOVE_EFFECT_RECYCLE_BERRIES)); + ASSUME(GetItemHoldEffect(ITEM_APICOT_BERRY) == HOLD_EFFECT_SP_DEFENSE_UP); + PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); } + PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_STUFF_CHEEKS); \ + MOVE(playerRight, MOVE_STUFF_CHEEKS); \ + MOVE(opponentLeft, MOVE_CELEBRATE); \ + MOVE(opponentRight, MOVE_CELEBRATE); } + TURN { MOVE(playerLeft, MOVE_SCRATCH, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2);} + } SCENE { + // turn 1 + MESSAGE("Using Apicot Berry, the Sp. Def of Snorlax rose!"); + MESSAGE("Using Apicot Berry, the Sp. Def of Munchlax rose!"); + // turn 2 + MESSAGE("Snorlax used G-Max Replenish!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_REPLENISH, playerLeft); + MESSAGE("Snorlax found one Apicot Berry!"); + MESSAGE("Munchlax found one Apicot Berry!"); + } +} + +DOUBLE_BATTLE_TEST("Dynamax: G-Max Volt Crash paralyzes other opponent even if its target faints") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_VOLT_CRASH, MOVE_EFFECT_PARALYZE_SIDE)); + PLAYER(SPECIES_PIKACHU) { GigantamaxFactor(TRUE); } + PLAYER(SPECIES_PICHU); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponentLeft, 2); } + } SCENE { + MESSAGE("Pikachu used G-Max Volt Crash!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_VOLT_CRASH, playerLeft); + NONE_OF { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft); + STATUS_ICON(opponentLeft, paralysis: TRUE); + } + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentRight); + MESSAGE("The opposing Wynaut is paralyzed, so it may be unable to move!"); + STATUS_ICON(opponentRight, paralysis: TRUE); + } +} + TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-lowering Max Moves, without showing a message") TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message")