Fixes Neutralizing Gas displaying message when exiting with multiple users (#8318)

This commit is contained in:
PhallenTree 2025-11-21 18:58:02 +00:00 committed by GitHub
parent 7229305ff9
commit 65a5d1e7d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 129 additions and 68 deletions

View File

@ -1924,8 +1924,8 @@
1:
.endm
.macro jumpifabilitycantbesuppressed battler:req, jumpInstr:req
callnative BS_JumpIfAbilityCantBeSuppressed
.macro jumpifabilitycantbereactivated battler:req, jumpInstr:req
callnative BS_JumpIfAbilityCantBeReactivated
.byte \battler
.4byte \jumpInstr
.endm

View File

@ -9296,8 +9296,7 @@ BattleScript_NeutralizingGasExits::
setbyte gBattlerAttacker, 0
BattleScript_NeutralizingGasExitsLoop:
copyarraywithindex gBattlerTarget, gBattlerByTurnOrder, gBattlerAttacker, 1
jumpifabilitycantbesuppressed BS_TARGET, BattleScript_NeutralizingGasExitsLoopIncrement
jumpifability BS_TARGET, ABILITY_IMPOSTER, BattleScript_NeutralizingGasExitsLoopIncrement @ Imposter only activates when first entering the field
jumpifabilitycantbereactivated BS_TARGET, BattleScript_NeutralizingGasExitsLoopIncrement
saveattacker
switchinabilities BS_TARGET
restoreattacker

View File

@ -3861,8 +3861,13 @@ static void TryDoEventsBeforeFirstTurn(void)
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_NEUTRALIZING_GAS:
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
return;
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, i, 0, 0, 0) != 0)
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES:

View File

@ -4244,14 +4244,17 @@ static void Cmd_tryfaintmon(void)
}
else
{
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS
if (gDisableStructs[battler].neutralizingGas
&& !(gAbsentBattlerFlags & (1u << battler))
&& !IsBattlerAlive(battler))
{
gBattleMons[battler].ability = ABILITY_NONE;
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
gDisableStructs[battler].neutralizingGas = FALSE;
if (!IsNeutralizingGasOnField())
{
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
}
if (cmd->battler == BS_ATTACKER)
{
@ -13424,44 +13427,46 @@ static void Cmd_switchoutabilities(void)
CMD_ARGS(u8 battler);
u32 battler = GetBattlerForBattleScript(cmd->battler);
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS)
if (gDisableStructs[battler].neutralizingGas)
{
gBattleMons[battler].ability = ABILITY_NONE;
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
gDisableStructs[battler].neutralizingGas = FALSE;
if (!IsNeutralizingGasOnField())
{
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
}
else
switch (GetBattlerAbility(battler))
{
switch (GetBattlerAbility(battler))
{
case ABILITY_NATURAL_CURE:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
case ABILITY_NATURAL_CURE:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
gBattleMons[battler].status1 = 0;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE,
1u << gBattleStruct->battlerPartyIndexes[battler],
sizeof(gBattleMons[battler].status1),
&gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
break;
case ABILITY_REGENERATOR:
{
u32 regenerate = GetNonDynamaxMaxHP(battler) / 3;
regenerate += gBattleMons[battler].hp;
if (regenerate > gBattleMons[battler].maxHP)
regenerate = gBattleMons[battler].maxHP;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE,
1u << gBattleStruct->battlerPartyIndexes[battler],
sizeof(regenerate),
&regenerate);
MarkBattlerForControllerExec(battler);
break;
}
}
gBattlescriptCurrInstr = cmd->nextInstr;
gBattleMons[battler].status1 = 0;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE,
1u << gBattleStruct->battlerPartyIndexes[battler],
sizeof(gBattleMons[battler].status1),
&gBattleMons[battler].status1);
MarkBattlerForControllerExec(battler);
break;
case ABILITY_REGENERATOR:
{
u32 regenerate = GetNonDynamaxMaxHP(battler) / 3;
regenerate += gBattleMons[battler].hp;
if (regenerate > gBattleMons[battler].maxHP)
regenerate = gBattleMons[battler].maxHP;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HP_BATTLE,
1u << gBattleStruct->battlerPartyIndexes[battler],
sizeof(regenerate),
&regenerate);
MarkBattlerForControllerExec(battler);
break;
}
}
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void Cmd_jumpifhasnohp(void)
@ -16797,15 +16802,27 @@ void BS_TryBoosterEnergy(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_JumpIfAbilityCantBeSuppressed(void)
void BS_JumpIfAbilityCantBeReactivated(void)
{
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
u32 battler = GetBattlerForBattleScript(cmd->battler);
u32 ability = gBattleMons[battler].ability;
if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed)
switch (ability)
{
case ABILITY_IMPOSTER:
case ABILITY_NEUTRALIZING_GAS:
case ABILITY_AIR_LOCK:
case ABILITY_CLOUD_NINE:
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
break;
default:
if (gAbilitiesInfo[ability].cantBeSuppressed)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
break;
}
}
void BS_TryActivateAbilityShield(void)
@ -18245,13 +18262,16 @@ void BS_TryEndNeutralizingGas(void)
if (gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved)
{
gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = FALSE;
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
}
else
{
gBattlescriptCurrInstr = cmd->nextInstr;
gDisableStructs[gBattlerTarget].neutralizingGas = FALSE;
if (!IsNeutralizingGasOnField())
{
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
}
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_GetRototillerTargets(void)

View File

@ -5170,19 +5170,13 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITYEFFECT_NEUTRALIZINGGAS:
// Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards
for (i = 0; i < gBattlersCount; i++)
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[battler].neutralizingGas)
{
if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[i].neutralizingGas)
{
gDisableStructs[i].neutralizingGas = TRUE;
gBattlerAbility = i;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
if (effect != 0)
break;
gDisableStructs[battler].neutralizingGas = TRUE;
gBattlerAbility = battler;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITYEFFECT_ON_WEATHER: // For ability effects that activate when the battle weather changes.
@ -5295,7 +5289,7 @@ bool32 IsNeutralizingGasOnField(void)
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerAlive(i) && gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !gBattleMons[i].volatiles.gastroAcid)
if (gDisableStructs[i].neutralizingGas && !gBattleMons[i].volatiles.gastroAcid)
return TRUE;
}
@ -5371,7 +5365,7 @@ u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityS
if (!hasAbilityShield
&& IsNeutralizingGasOnField()
&& gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS)
&& !gDisableStructs[battler].neutralizingGas)
return ABILITY_NONE;
if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield, ignoreMoldBreaker))

View File

@ -310,3 +310,46 @@ SINGLE_BATTLE_TEST("Neutralizing Gas exiting the field does not activate Imposte
NOT ABILITY_POPUP(player, ABILITY_IMPOSTER);
}
}
SINGLE_BATTLE_TEST("Neutralizing Gas exiting the field does not activate Air Lock/Cloud Nine but their effects are kept")
{
u32 species, ability;
PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; }
PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(species) { Ability(ability); }
OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
OPPONENT(SPECIES_LUDICOLO) { Ability(ABILITY_RAIN_DISH); }
} WHEN {
TURN { SWITCH(player, 1); SWITCH(opponent, 1); }
TURN { MOVE(player, MOVE_RAIN_DANCE); }
} SCENE {
NOT ABILITY_POPUP(player, ABILITY_AIR_LOCK);
MESSAGE("The effects of the neutralizing gas wore off!");
NOT ABILITY_POPUP(player, ABILITY_AIR_LOCK);
ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, player);
NOT ABILITY_POPUP(opponent, ABILITY_RAIN_DISH);
}
}
SINGLE_BATTLE_TEST("Neutralizing Gas only displays exiting message for the last user leaving the field")
{
GIVEN {
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { SWITCH(player, 1); SWITCH(opponent, 1); }
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
ABILITY_POPUP(opponent, ABILITY_NEUTRALIZING_GAS);
SEND_IN_MESSAGE("Wobbuffet");
MESSAGE("The effects of the neutralizing gas wore off!");
NOT MESSAGE("The effects of the neutralizing gas wore off!");
}
}