Fix order of failure for spread moves (#9472)
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:
Alex 2026-03-08 17:14:49 +01:00 committed by GitHub
parent abac8874d8
commit 8e89d71b52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 12 deletions

View File

@ -427,5 +427,6 @@ void TryUpdateEvolutionTracker(enum EvolutionConditions evolutionCondition, u32
bool32 CanUseMoveConsecutively(enum BattlerId battler);
void TryResetConsecutiveUseCounter(enum BattlerId battler);
void SetOrClearRageVolatile(void);
enum BattlerId GetTargetBySlot(enum BattlerId battlerAtk, enum BattlerId battlerDef);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -1707,9 +1707,13 @@ static enum CancelerResult CancelerTargetFailure(struct BattleContext *ctx)
ctx->updateFlags = TRUE;
ctx->runScript = TRUE;
while (gBattleStruct->eventState.atkCancelerBattler < gBattlersCount)
while (gBattleStruct->eventState.atkCancelerBattler < MAX_BATTLERS_COUNT)
{
ctx->battlerDef = gBattleStruct->eventState.atkCancelerBattler++;
ctx->battlerDef = GetTargetBySlot(ctx->battlerAtk, gBattleStruct->eventState.atkCancelerBattler);
gBattleStruct->eventState.atkCancelerBattler++;
if (!IsDoubleBattle() && ctx->battlerDef >= gBattlersCount)
continue;
if (ShouldSkipFailureCheckOnBattler(ctx->battlerAtk, ctx->battlerDef, FALSE))
continue;

View File

@ -6382,19 +6382,13 @@ static void Cmd_futuresighttargetfailure(void)
static u32 GetPossibleNextTarget(u32 currTarget)
{
u32 i = 0;
const u8 targetOrder[MAX_BATTLERS_COUNT] = {
gBattlerAttacker,
BATTLE_PARTNER(gBattlerAttacker),
LEFT_FOE(gBattlerAttacker),
RIGHT_FOE(gBattlerAttacker),
};
// currTarget allows for a starting point without relying on values for previous targets being set
if (currTarget != MAX_BATTLERS_COUNT)
{
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
if (targetOrder[i] == currTarget)
if (GetTargetBySlot(gBattlerAttacker, i) == currTarget)
break;
}
i++; // next target after finding currTarget
@ -6402,7 +6396,8 @@ static u32 GetPossibleNextTarget(u32 currTarget)
while (i < MAX_BATTLERS_COUNT)
{
enum BattlerId battler = targetOrder[i++];
enum BattlerId battler = GetTargetBySlot(gBattlerAttacker, i);
i++;
if (!IsBattlerAlive(battler))
continue;

View File

@ -10957,3 +10957,21 @@ void SetOrClearRageVolatile(void)
else
gBattleMons[gBattlerAttacker].volatiles.rage = FALSE;
}
enum BattlerId GetTargetBySlot(enum BattlerId battlerAtk, enum BattlerId battlerDef)
{
switch (battlerDef)
{
case B_BATTLER_0:
return battlerAtk;
case B_BATTLER_1:
return BATTLE_PARTNER(battlerAtk);
case B_BATTLER_2:
return LEFT_FOE(battlerAtk);
case B_BATTLER_3:
return RIGHT_FOE(battlerAtk);
default:
errorf("Illegal battler");
return B_BATTLER_0;
}
}

View File

@ -41,9 +41,9 @@ DOUBLE_BATTLE_TEST("Synchronoise will fail if there is no corresponding typing o
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
MESSAGE("Wobbuffet used Synchronoise!");
MESSAGE("It doesn't affect the opposing Bulbasaur…");
MESSAGE("It doesn't affect Bulbasaur…");
MESSAGE("It doesn't affect the opposing Bulbasaur…");
MESSAGE("It doesn't affect the opposing Bulbasaur…");
NOT MESSAGE("But it failed!");
}
}
@ -108,8 +108,8 @@ DOUBLE_BATTLE_TEST("Synchronoise will fail for a typeless user even if a target
} SCENE {
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, playerLeft);
MESSAGE("Arcanine used Synchronoise!");
MESSAGE("It doesn't affect the opposing Arcanine…");
MESSAGE("It doesn't affect Wobbuffet…");
MESSAGE("It doesn't affect the opposing Arcanine…");
MESSAGE("It doesn't affect the opposing Wobbuffet…");
NOT MESSAGE("But it failed!");
}

View File

@ -474,3 +474,22 @@ DOUBLE_BATTLE_TEST("Spread Moves: AOE ground type move vs Levitate and Air Ballo
HP_BAR(playerRight);
}
}
DOUBLE_BATTLE_TEST("Spread Moves: Earthquake fails in order of ally, left foe, right foe")
{
GIVEN {
ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == TARGET_FOES_AND_ALLY);
ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
PLAYER(SPECIES_FLYGON) { Speed(1); Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_FLYGON) { Speed(2); Ability(ABILITY_LEVITATE); }
OPPONENT(SPECIES_FLYGON) { Speed(3); Ability(ABILITY_LEVITATE); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_EARTHQUAKE); }
} SCENE {
ABILITY_POPUP(playerRight, ABILITY_LEVITATE);
ABILITY_POPUP(opponentLeft, ABILITY_LEVITATE);
ABILITY_POPUP(opponentRight, ABILITY_LEVITATE);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, playerLeft);
}
}