Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Quash implementation, adds After You and Quash missing configs + tests #5400

Merged
merged 2 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/config/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@
#define B_HEAL_BELL_SOUNDPROOF GEN_LATEST // In Gen5, Heal Bell affects all mons with Soundproof. In Gen6-8 it affects inactive mons, but not battlers. In Gen9 it always affects the user.
#define B_CHARGE GEN_LATEST // In Gen8-, Charge status is lost regardless of the typing of the next move.
#define B_POWDER_RAIN GEN_LATEST // In Gen7+, Powder doesn't damage the user of a Fire type move in heavy rain.
#define B_AFTER_YOU_TURN_ORDER GEN_LATEST // In Gen8+, After You doesn't fail if the turn order wouldn't change after use.
#define B_QUASH_TURN_ORDER GEN_LATEST // In Gen8+, Quash-affected battlers move according to speed order. Before Gen8, Quash-affected battlers move in the order they were affected by Quash.

// Ability settings
#define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters.
Expand Down
37 changes: 23 additions & 14 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -8931,9 +8931,10 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
u8 data[MAX_BATTLERS_COUNT];
u8 actionsData[MAX_BATTLERS_COUNT];

if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)
|| GetBattlerTurnOrderNum(gBattlerAttacker) + 1 == GetBattlerTurnOrderNum(gBattlerTarget))
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
return FALSE;
if (GetBattlerTurnOrderNum(gBattlerAttacker) + 1 == GetBattlerTurnOrderNum(gBattlerTarget))
return B_AFTER_YOU_TURN_ORDER >= GEN_8;

for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
Expand All @@ -8946,8 +8947,6 @@ static bool32 ChangeOrderTargetAfterAttacker(void)
gActionsByTurnOrder[1] = actionsData[2];
gBattlerByTurnOrder[2] = data[1];
gActionsByTurnOrder[2] = actionsData[1];
gBattlerByTurnOrder[3] = data[3];
gActionsByTurnOrder[3] = actionsData[3];
}
else if (GetBattlerTurnOrderNum(gBattlerAttacker) == 0 && GetBattlerTurnOrderNum(gBattlerTarget) == 3)
{
Expand Down Expand Up @@ -17112,7 +17111,7 @@ void BS_TryActivateGulpMissile(void)
void BS_TryQuash(void)
{
NATIVE_ARGS(const u8 *failInstr);
u32 i;
u32 i, j;

// It's true if foe is faster, has a bigger priority, or switches
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
Expand All @@ -17123,19 +17122,29 @@ void BS_TryQuash(void)

// If the above condition is not true, it means we are faster than the foe, so we can set the quash bit
gProtectStructs[gBattlerTarget].quash = TRUE;
for (i = 0; i < gBattlersCount; i++)

if (B_QUASH_TURN_ORDER < GEN_8)
{
gBattlerByTurnOrder[i] = i;
// Gen 7- config makes target go last so that the order of quash targets is kept for the correct turn order
j = GetBattlerTurnOrderNum(gBattlerTarget);
for (i = j + 1; i < gBattlersCount; i++)
{
SwapTurnOrder(i, j);
j++;
}
}
for (i = 0; i < gBattlersCount - 1; i++)
else
{
s32 j;
for (j = i + 1; j < gBattlersCount; j++)
// Gen 8+ config only alters Turn Order of battlers affected by Quash, dynamic speed should handle the rest
for (i = gCurrentTurnActionNumber + 1; i < gBattlersCount - 1; i++)
{
if (!gProtectStructs[i].quash
&& !gProtectStructs[j].quash
&& GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1)
SwapTurnOrder(i, j);
for (j = i + 1; j < gBattlersCount; j++)
{
u32 battler1 = gBattlerByTurnOrder[i], battler2 = gBattlerByTurnOrder[j];
if ((gProtectStructs[battler1].quash || gProtectStructs[battler2].quash)
&& GetWhichBattlerFaster(battler1, battler2, FALSE) == -1)
SwapTurnOrder(i, j);
}
}
}
gBattlescriptCurrInstr = cmd->nextInstr;
Expand Down
49 changes: 46 additions & 3 deletions test/battle/move_effect/after_you.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ DOUBLE_BATTLE_TEST("After You does nothing if the target has already moved")
}
}

DOUBLE_BATTLE_TEST("After You calculates correct targets if only one pokemon is left on the opposing side")
DOUBLE_BATTLE_TEST("After You calculates correct turn order if only one pokemon is left on the opposing side")
{
GIVEN {
PLAYER(SPECIES_GRENINJA) { Speed(120); }
Expand Down Expand Up @@ -86,5 +86,48 @@ DOUBLE_BATTLE_TEST("After You calculates correct targets if only one pokemon is
}
}

TO_DO_BATTLE_TEST("After You doesn't fail if the turner remains the same after After You (Gen8+)");
TO_DO_BATTLE_TEST("After You ignores the effects of Quash");
DOUBLE_BATTLE_TEST("After You doesn't fail if the turn order remains the same after After You (Gen8+)")
{
GIVEN {
ASSUME(B_AFTER_YOU_TURN_ORDER >= GEN_8);
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
PLAYER(SPECIES_WYNAUT) { Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
OPPONENT(SPECIES_WYNAUT) { Speed(3); }
} WHEN {
TURN {
MOVE(playerLeft, MOVE_CELEBRATE);
MOVE(playerRight, MOVE_CELEBRATE);
MOVE(opponentLeft, MOVE_CELEBRATE);
MOVE(opponentRight, MOVE_AFTER_YOU, target: opponentLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_AFTER_YOU, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
}
}

DOUBLE_BATTLE_TEST("After You ignores the effects of Quash")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_QUASH].effect == EFFECT_QUASH);
PLAYER(SPECIES_WOBBUFFET) { Speed(4); }
PLAYER(SPECIES_WYNAUT) { Speed(1); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); }
OPPONENT(SPECIES_WYNAUT) { Speed(3); }
} WHEN {
TURN {
MOVE(playerLeft, MOVE_QUASH, target: opponentLeft);
MOVE(playerRight, MOVE_CELEBRATE);
MOVE(opponentLeft, MOVE_CELEBRATE);
MOVE(opponentRight, MOVE_AFTER_YOU, target: opponentLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_AFTER_YOU, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
}
}
92 changes: 90 additions & 2 deletions test/battle/move_effect/quash.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,102 @@ DOUBLE_BATTLE_TEST("Quash is not affected by dynamic speed")
PLAYER(SPECIES_WOBBUFFET) { Speed(30); }
OPPONENT(SPECIES_TORCHIC) { Speed(50); }
OPPONENT(SPECIES_TREECKO) { Speed(40); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_QUASH, target: opponentLeft);
MOVE(opponentRight, MOVE_TAILWIND);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TAILWIND, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
}
}

DOUBLE_BATTLE_TEST("Quash calculates correct turn order if only one pokemon is left on the opposing side")
{
GIVEN {
PLAYER(SPECIES_GRENINJA) { Speed(120); }
PLAYER(SPECIES_REGIROCK) { Speed(100); }
OPPONENT(SPECIES_PIDGEOT) { Speed(10); }
OPPONENT(SPECIES_DRAGONITE) { Speed(60); }
} WHEN {
TURN {
MOVE(playerLeft, MOVE_QUASH, target: playerRight);
MOVE(playerRight, MOVE_STONE_EDGE, target: opponentLeft);
MOVE(opponentRight, MOVE_CELEBRATE);
}
TURN {
MOVE(playerLeft, MOVE_QUASH, target: playerRight);
MOVE(playerRight, MOVE_STONE_EDGE, target: opponentRight);
MOVE(opponentRight, MOVE_CELEBRATE);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_EDGE, playerRight);
HP_BAR(opponentLeft);
MESSAGE("Foe Pidgeot fainted!");

ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_EDGE, playerRight);
HP_BAR(opponentRight);
}
}

DOUBLE_BATTLE_TEST("Quash-affected targets move from fastest to slowest (Gen 8+) or from first affected battler to last (Gen 7-)")
{
u32 speedLeft, speedRight;

PARAMETRIZE { speedLeft = 60; speedRight = 50; }
PARAMETRIZE { speedLeft = 50; speedRight = 60; }
GIVEN {
PLAYER(SPECIES_VOLBEAT) { Speed(10); Ability(ABILITY_PRANKSTER); }
PLAYER(SPECIES_WOBBUFFET) { Speed(70); }
OPPONENT(SPECIES_TORCHIC) { Speed(speedLeft); }
OPPONENT(SPECIES_TREECKO) { Speed(speedRight); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_QUASH, target: opponentRight);
MOVE(playerRight, MOVE_QUASH, target: opponentLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerRight);
if (B_QUASH_TURN_ORDER < GEN_8) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
}
else if (speedLeft > speedRight) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
}
else {
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft);
}
}
}

DOUBLE_BATTLE_TEST("Quash-affected mon that acted early via After You is not affected by dynamic speed")
{
GIVEN {
ASSUME(B_RECALC_TURN_AFTER_ACTIONS >= GEN_8);
ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND);
ASSUME(gMovesInfo[MOVE_AFTER_YOU].effect == EFFECT_AFTER_YOU);
PLAYER(SPECIES_VOLBEAT) { Speed(20); Ability(ABILITY_PRANKSTER); }
PLAYER(SPECIES_WOBBUFFET) { Speed(30); }
OPPONENT(SPECIES_TORCHIC) { Speed(10); }
OPPONENT(SPECIES_TREECKO) { Speed(40); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_QUASH, target: opponentLeft);
MOVE(opponentRight, MOVE_AFTER_YOU, target: opponentLeft);
MOVE(opponentLeft, MOVE_TAILWIND);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_AFTER_YOU, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TAILWIND, opponentLeft);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight); // this is the relevant part, testing if quash affected battler becomes last to move causing playerRight to not move
}
}
Loading