Fix Shell Trap being delayed after a spread move hit (#10682)

Co-authored-by: PhallenTree <168426989+PhallenTree@users.noreply.github.com>
This commit is contained in:
Enrico Drago
2026-08-22 19:01:43 +02:00
committed by GitHub
parent 79f5e11746
commit 26bf3fdcb5
5 changed files with 59 additions and 18 deletions

View File

@@ -407,7 +407,7 @@ void SetStartingStatus(enum StartingStatus status);
void ResetStartingStatuses(void);
bool32 IsUsableWhileAsleepEffect(enum BattleMoveEffects effect);
void SetWrapTurns(enum BattlerId battler, enum HoldEffect holdEffect);
bool32 ChangeOrderTargetAfterAttacker(void);
bool32 ChangeOrderTargetAfterAttacker(enum BattlerId battlerDef);
void TryUpdateEvolutionTracker(enum EvolutionConditions evolutionCondition, u32 upAmount, enum Move usedMove);
bool32 CanUseMoveConsecutively(enum BattlerId battler);
void TryResetConsecutiveUseCounter(enum BattlerId battler);

View File

@@ -3697,6 +3697,8 @@ static enum MoveEndResult MoveEndAbilityEffectFoesFainted(struct BattleCalcValue
static enum MoveEndResult MoveEndShellTrap(struct BattleCalcValues *cv)
{
u32 shellTrapBattlerMask = 0;
for (enum BattlerId battlerDef = 0; battlerDef < gBattlersCount; battlerDef++)
{
if (battlerDef == cv->battlerAtk || IsBattlerAlly(battlerDef, cv->battlerAtk))
@@ -3709,11 +3711,28 @@ static enum MoveEndResult MoveEndShellTrap(struct BattleCalcValues *cv)
&& gProtectStructs[battlerDef].physicalBattlerId == cv->battlerAtk)
{
gProtectStructs[battlerDef].shellTrap = TRUE;
if (IsDoubleBattle()) // Change move order in double battles, so the hit mon with shell trap moves immediately after being hit.
ChangeOrderTargetAfterAttacker(); // In what order should 2 targets move that will activate a trap?
shellTrapBattlerMask |= 1u << battlerDef;
}
}
if (IsDoubleBattle() && shellTrapBattlerMask != 0)
{
enum BattlerId shellTrapBattlers[MAX_BATTLERS_COUNT];
u32 numShellTrapBattlers = 0;
for (u32 i = 0; i < gBattlersCount; i++)
{
enum BattlerId battler = gBattlersBySpeed[i];
if (shellTrapBattlerMask & (1u << battler))
shellTrapBattlers[numShellTrapBattlers++] = battler;
}
// Each reorder inserts the battler immediately after the attacker, so use reverse turn order to keep faster battlers first.
while (numShellTrapBattlers != 0)
ChangeOrderTargetAfterAttacker(shellTrapBattlers[--numShellTrapBattlers]);
}
gBattleScripting.moveendState++;
return MOVEEND_RESULT_CONTINUE;
}
@@ -4381,7 +4400,7 @@ static enum MoveEndResult MoveEndPursuitNextAction(struct BattleCalcValues *cv)
u32 storedTarget = gBattlerTarget;
if (SetTargetToNextPursuiter(gBattlerTarget))
{
ChangeOrderTargetAfterAttacker();
ChangeOrderTargetAfterAttacker(gBattlerTarget);
gBattleStruct->moveTarget[gBattlerTarget] = storedTarget;
gBattlerTarget = storedTarget;
}

View File

@@ -8468,7 +8468,7 @@ static void Cmd_jumpifnopursuitswitchdmg(void)
if (SetTargetToNextPursuiter(gBattlerAttacker))
{
ChangeOrderTargetAfterAttacker();
ChangeOrderTargetAfterAttacker(gBattlerTarget);
gBattleStruct->battlerState[gBattlerAttacker].pursuitTarget = TRUE;
gBattleStruct->pursuitStoredSwitch = gBattleStruct->monToSwitchIntoId[gBattlerAttacker];
gSpecialStatuses[gBattlerAttacker].queuedSwitch = NO_QUEUED_SWITCH; // Don't send out replacement before Pursuits
@@ -13251,7 +13251,7 @@ void BS_PowerTrick(void)
void BS_TryAfterYou(void)
{
NATIVE_ARGS(const u8 *failInstr);
if (ChangeOrderTargetAfterAttacker())
if (ChangeOrderTargetAfterAttacker(gBattlerTarget))
{
gSpecialStatuses[gBattlerTarget].afterYou = 1;
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@@ -10819,13 +10819,13 @@ void SetWrapTurns(enum BattlerId battler, enum HoldEffect holdEffect)
}
// Return True if the order was changed, and false if the order was not changed(for example because the target would move after the attacker anyway).
bool32 ChangeOrderTargetAfterAttacker(void)
bool32 ChangeOrderTargetAfterAttacker(enum BattlerId battlerDef)
{
u32 i;
u8 data[MAX_BATTLERS_COUNT];
u8 actionsData[MAX_BATTLERS_COUNT];
u32 attackerTurnOrderNum = GetBattlerTurnOrderNum(gBattlerAttacker);
u32 targetTurnOrderNum = GetBattlerTurnOrderNum(gBattlerTarget);
u32 targetTurnOrderNum = GetBattlerTurnOrderNum(battlerDef);
if (attackerTurnOrderNum > targetTurnOrderNum)
return FALSE;
@@ -10839,14 +10839,14 @@ bool32 ChangeOrderTargetAfterAttacker(void)
}
if (attackerTurnOrderNum == 0 && targetTurnOrderNum == 2)
{
gBattlerByTurnOrder[1] = gBattlerTarget;
gBattlerByTurnOrder[1] = battlerDef;
gActionsByTurnOrder[1] = actionsData[2];
gBattlerByTurnOrder[2] = data[1];
gActionsByTurnOrder[2] = actionsData[1];
}
else if (attackerTurnOrderNum == 0 && targetTurnOrderNum == 3)
{
gBattlerByTurnOrder[1] = gBattlerTarget;
gBattlerByTurnOrder[1] = battlerDef;
gActionsByTurnOrder[1] = actionsData[3];
gBattlerByTurnOrder[2] = data[1];
gActionsByTurnOrder[2] = actionsData[1];
@@ -10855,7 +10855,7 @@ bool32 ChangeOrderTargetAfterAttacker(void)
}
else // attackerTurnOrderNum == 1, targetTurnOrderNum == 3
{
gBattlerByTurnOrder[2] = gBattlerTarget;
gBattlerByTurnOrder[2] = battlerDef;
gActionsByTurnOrder[2] = actionsData[3];
gBattlerByTurnOrder[3] = data[2];
gActionsByTurnOrder[3] = actionsData[2];

View File

@@ -280,14 +280,15 @@ DOUBLE_BATTLE_TEST("Shell Trap does not trigger when hit into Substitute")
}
}
DOUBLE_BATTLE_TEST("Shell Trap activates on both opposing Targets")
DOUBLE_BATTLE_TEST("Shell Trap activates for both opposing targets in speed order")
{
GIVEN {
ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == TARGET_FOES_AND_ALLY);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WYNAUT) { Speed(1); }
PLAYER(SPECIES_WOBBUFFET) { Speed(2); }
OPPONENT(SPECIES_WYNAUT) { Speed(4); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(3); }
} WHEN {
TURN {
MOVE(playerLeft, MOVE_SHELL_TRAP);
@@ -296,9 +297,30 @@ DOUBLE_BATTLE_TEST("Shell Trap activates on both opposing Targets")
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponentLeft);
// Order might be incorrect compared to vanilla
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerLeft);
}
}
DOUBLE_BATTLE_TEST("Shell Trap activates immediately after its user is hit by a spread move")
{
GIVEN {
ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == TARGET_FOES_AND_ALLY);
ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET) { Speed(3); }
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(4); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
} WHEN {
TURN {
MOVE(opponentLeft, MOVE_EARTHQUAKE);
MOVE(playerRight, MOVE_SHELL_TRAP);
}
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SHELL_TRAP_SETUP, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
}
}