Fix how switch-in effects are played out after multiple faints in the same turn (#4864)
* Multiple switch-ins after fainting * empty new lines * Fix failing tests
This commit is contained in:
parent
a8ae1a0342
commit
f2e8482488
13 changed files with 84 additions and 48 deletions
|
@ -5509,6 +5509,7 @@ BattleScript_HandleFaintedMonLoop::
|
|||
switchineffects BS_FAINTED_MULTIPLE_1
|
||||
jumpifbytenotequal gBattlerFainted, gBattlersCount, BattleScript_HandleFaintedMonLoop
|
||||
BattleScript_HandleFaintedMonMultipleEnd::
|
||||
switchineffects BS_FAINTED_MULTIPLE_2
|
||||
end2
|
||||
|
||||
BattleScript_LocalTrainerBattleWon::
|
||||
|
|
|
@ -662,7 +662,11 @@ struct BattleStruct
|
|||
u16 abilityPreventingSwitchout;
|
||||
u8 hpScale;
|
||||
u16 synchronizeMoveEffect;
|
||||
bool8 anyMonHasTransformed;
|
||||
u8 anyMonHasTransformed:1; // Only used in battle_tv.c
|
||||
u8 multipleSwitchInBattlers:4; // One bit per battler
|
||||
u8 multipleSwitchInState:2;
|
||||
u8 multipleSwitchInCursor:3;
|
||||
u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT];
|
||||
void (*savedCallback)(void);
|
||||
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
|
||||
u16 chosenItem[MAX_BATTLERS_COUNT];
|
||||
|
|
|
@ -4633,7 +4633,7 @@ bool32 NoAliveMonsForEitherParty(void)
|
|||
return (NoAliveMonsForPlayer() || NoAliveMonsForOpponent());
|
||||
}
|
||||
|
||||
// For battles that aren't BATTLE_TYPE_LINK or BATTLE_TYPE_RECORDED_LINK or double trainer battles, the only thing this
|
||||
// For battles that aren't BATTLE_TYPE_LINK or BATTLE_TYPE_RECORDED_LINK or trainer battles, the only thing this
|
||||
// command does is check whether the player has won/lost by totaling each team's HP. It then
|
||||
// sets gBattleOutcome accordingly, if necessary.
|
||||
static void Cmd_checkteamslost(void)
|
||||
|
@ -4650,15 +4650,11 @@ static void Cmd_checkteamslost(void)
|
|||
gBattleOutcome |= B_OUTCOME_WON;
|
||||
|
||||
// Fair switching - everyone has to switch in most at the same time, without knowing which pokemon the other trainer selected.
|
||||
// In vanilla Emerald this was only used for link battles, in expansion it's also used for regular trainers in double battles.
|
||||
// In vanilla Emerald this was only used for link battles, in expansion it's also used for regular trainer battles.
|
||||
// For battles that haven't ended, count number of empty battler spots
|
||||
// In multi battles, jump to pointer if more than 1 spot empty
|
||||
// In non-multi battles, jump to pointer if 1 spot is missing on both sides
|
||||
if (gBattleOutcome == 0
|
||||
&& (((gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)))
|
||||
|| ((gBattleTypeFlags & BATTLE_TYPE_TRAINER) && (gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
)
|
||||
)
|
||||
if (gBattleOutcome == 0 && (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_TRAINER)))
|
||||
{
|
||||
s32 i, emptyPlayerSpots, emptyOpponentSpots;
|
||||
|
||||
|
@ -7148,13 +7144,8 @@ bool32 DoSwitchInAbilities(u32 battler)
|
|||
|| AbilityBattleEffects(ABILITYEFFECT_TRACE2, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
static void Cmd_switchineffects(void)
|
||||
static void UpdateSentMonFlags(u32 battler)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
|
||||
s32 i;
|
||||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
UpdateSentPokesToOpponentValue(battler);
|
||||
|
||||
gHitMarker &= ~HITMARKER_FAINTED(battler);
|
||||
|
@ -7162,7 +7153,11 @@ static void Cmd_switchineffects(void)
|
|||
|
||||
if (!BattlerHasAi(battler))
|
||||
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[battler]];
|
||||
}
|
||||
|
||||
static bool32 DoSwitchInEffectsForBattler(u32 battler)
|
||||
{
|
||||
u32 i;
|
||||
// Neutralizing Gas announces itself before hazards
|
||||
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS && gSpecialStatuses[battler].announceNeutralizingGas == 0)
|
||||
{
|
||||
|
@ -7280,7 +7275,7 @@ static void Cmd_switchineffects(void)
|
|||
BattleScriptPushCursor();
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_HP_TRAP;
|
||||
gBattlescriptCurrInstr = BattleScript_HealReplacementZMove;
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7295,9 +7290,9 @@ static void Cmd_switchineffects(void)
|
|||
gDisableStructs[battler].truantSwitchInHack = 0;
|
||||
|
||||
if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE))
|
||||
return;
|
||||
return TRUE;
|
||||
else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
gDisableStructs[battler].stickyWebDone = FALSE;
|
||||
gDisableStructs[battler].spikesDone = FALSE;
|
||||
|
@ -7313,22 +7308,68 @@ static void Cmd_switchineffects(void)
|
|||
gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp;
|
||||
}
|
||||
|
||||
if (cmd->battler == BS_FAINTED_MULTIPLE_1)
|
||||
{
|
||||
u32 hitmarkerFaintBits = gHitMarker >> 28;
|
||||
|
||||
gBattlerFainted++;
|
||||
while (1)
|
||||
{
|
||||
if (hitmarkerFaintBits & gBitTable[gBattlerFainted] && !(gAbsentBattlerFlags & gBitTable[gBattlerFainted]))
|
||||
break;
|
||||
if (gBattlerFainted >= gBattlersCount)
|
||||
break;
|
||||
gBattlerFainted++;
|
||||
}
|
||||
}
|
||||
gBattleStruct->forcedSwitch &= ~(gBitTable[battler]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE; // Effect's script plays.
|
||||
}
|
||||
|
||||
static void Cmd_switchineffects(void)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
u32 i, battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
switch (cmd->battler)
|
||||
{
|
||||
// Multiple mons fainted and are being switched-in. Their abilities/hazards will play according to speed ties.
|
||||
case BS_FAINTED_MULTIPLE_1: // Saves the battlers.
|
||||
gBattleStruct->multipleSwitchInBattlers |= gBitTable[battler];
|
||||
UpdateSentMonFlags(battler);
|
||||
|
||||
// Increment fainted battler.
|
||||
do
|
||||
{
|
||||
gBattlerFainted++;
|
||||
if (gBattlerFainted >= gBattlersCount)
|
||||
break;
|
||||
if (gHitMarker & HITMARKER_FAINTED(gBattlerFainted) && !(gAbsentBattlerFlags & gBitTable[gBattlerFainted]))
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
return;
|
||||
case BS_FAINTED_MULTIPLE_2: // Plays hazards/abilities.
|
||||
switch (gBattleStruct->multipleSwitchInState)
|
||||
{
|
||||
case 0: // Sort battlers by speed
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
gBattleStruct->multipleSwitchInSortedBattlers[i] = i;
|
||||
SortBattlersBySpeed(gBattleStruct->multipleSwitchInSortedBattlers, FALSE);
|
||||
gBattleStruct->multipleSwitchInState++;
|
||||
gBattleStruct->multipleSwitchInCursor = 0;
|
||||
// Loop through all available battlers
|
||||
case 1:
|
||||
for (; gBattleStruct->multipleSwitchInCursor < gBattlersCount; gBattleStruct->multipleSwitchInCursor++)
|
||||
{
|
||||
gBattlerFainted = gBattleStruct->multipleSwitchInSortedBattlers[gBattleStruct->multipleSwitchInCursor];
|
||||
if (gBattleStruct->multipleSwitchInBattlers & gBitTable[gBattlerFainted])
|
||||
{
|
||||
if (DoSwitchInEffectsForBattler(gBattlerFainted))
|
||||
return;
|
||||
}
|
||||
}
|
||||
// All battlers done, end
|
||||
gBattleStruct->multipleSwitchInBattlers = 0;
|
||||
gBattleStruct->multipleSwitchInState = 0;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UpdateSentMonFlags(battler);
|
||||
if (!DoSwitchInEffectsForBattler(battler))
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler
|
|||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent);
|
||||
// Everyone faints.
|
||||
MESSAGE("Go! Chi-Yu!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN);
|
||||
MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!");
|
||||
MESSAGE("2 sent out Wobbuffet!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Download raises Sp.Attack if enemy has lower Sp. Def than De
|
|||
SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet", s16 damagePhysical, s16 damageSpecial)
|
||||
{
|
||||
u32 ability;
|
||||
KNOWN_FAILING;
|
||||
|
||||
PARAMETRIZE { ability = ABILITY_TRACE; }
|
||||
PARAMETRIZE { ability = ABILITY_DOWNLOAD; }
|
||||
GIVEN {
|
||||
|
|
|
@ -59,7 +59,6 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16
|
|||
|
||||
DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double battle")
|
||||
{
|
||||
KNOWN_FAILING;
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
|
|
|
@ -94,7 +94,6 @@ SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are
|
|||
|
||||
SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Player")
|
||||
{
|
||||
KNOWN_FAILING; // Explosion causes the ability to wait
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1);}
|
||||
|
|
|
@ -63,8 +63,6 @@ SINGLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO swi
|
|||
{
|
||||
u32 spdPlayer, spdOpponent;
|
||||
|
||||
KNOWN_FAILING;
|
||||
|
||||
PARAMETRIZE { spdPlayer = 5; spdOpponent = 1; }
|
||||
PARAMETRIZE { spdOpponent = 5; spdPlayer = 1; }
|
||||
|
||||
|
@ -92,8 +90,6 @@ DOUBLE_BATTLE_TEST("Switch-in abilities trigger in Speed Order after post-KO swi
|
|||
{
|
||||
u32 spdPlayer1, spdPlayer2, spdOpponent1, spdOpponent2;
|
||||
|
||||
KNOWN_FAILING;
|
||||
|
||||
PARAMETRIZE { spdPlayer1 = 5; spdPlayer2 = 4; spdOpponent1 = 3; spdOpponent2 = 2; }
|
||||
PARAMETRIZE { spdPlayer1 = 2; spdPlayer2 = 3; spdOpponent1 = 4; spdOpponent2 = 5; }
|
||||
PARAMETRIZE { spdPlayer1 = 4; spdPlayer2 = 3; spdOpponent1 = 5; spdOpponent2 = 2; }
|
||||
|
|
|
@ -32,7 +32,6 @@ SINGLE_BATTLE_TEST("Sword of Ruin reduces Defense if opposing mon's ability does
|
|||
|
||||
SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battlers fainted - Player")
|
||||
{
|
||||
KNOWN_FAILING; // Explosion causes the ability to wait
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1);}
|
||||
|
|
|
@ -32,7 +32,6 @@ SINGLE_BATTLE_TEST("Tablets of Ruin reduces Attack if opposing mon's ability doe
|
|||
|
||||
SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battlers fainted - Player")
|
||||
{
|
||||
KNOWN_FAILING; // Explosion causes the ability to wait
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1);}
|
||||
|
|
|
@ -32,7 +32,6 @@ SINGLE_BATTLE_TEST("Vessel of Ruin reduces Sp. Atk if opposing mon's ability doe
|
|||
|
||||
SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battlers fainted - Player")
|
||||
{
|
||||
KNOWN_FAILING; // Explosion causes the ability to wait
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(1);}
|
||||
|
|
|
@ -138,7 +138,6 @@ SINGLE_BATTLE_TEST("Imposter doesn't apply the heroic transformation message whe
|
|||
|
||||
SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers fainted - Player")
|
||||
{
|
||||
KNOWN_FAILING; // Explosion causes the ability to wait
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||
PLAYER(SPECIES_PALAFIN_ZERO);
|
||||
|
|
|
@ -56,7 +56,7 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
|||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||
OPPONENT(SPECIES_ALAKAZAM) {Speed(100);}
|
||||
} WHEN {
|
||||
TURN { MOVE(playerRight, MOVE_STICKY_WEB); MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(opponentRight, 3); }
|
||||
TURN {}
|
||||
|
@ -65,13 +65,13 @@ DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explos
|
|||
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("2 sent out Alakazam!");
|
||||
MESSAGE("Foe Alakazam was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Alakazam's Speed fell!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
MESSAGE("2 sent out Wynaut!");
|
||||
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
MESSAGE("Foe Wynaut's Speed fell!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue