Fixes plasma fists and several let's go and max move effects which should occur even when fainting a foe (#9262)
Some checks are pending
CI / build (push) Waiting to run
CI / docs_validate (push) Waiting to run
CI / allcontributors (push) Waiting to run
Docs / deploy (push) Waiting to run

This commit is contained in:
luuma 2026-02-25 20:46:22 +00:00 committed by GitHub
parent 9e3d7db43f
commit cabbc632fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 144 additions and 15 deletions

View File

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

View File

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