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

* Fix Quash + After You and Quash configs

* Add tests
This commit is contained in:
PhallenTree 2024-09-18 23:10:29 +01:00 committed by GitHub
parent ac2b41ae71
commit 76656e85c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 163 additions and 21 deletions

View File

@ -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.

View File

@ -8929,9 +8929,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++)
{
@ -8944,8 +8945,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)
{
@ -17110,7 +17109,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))
@ -17121,19 +17120,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;
}
for (i = 0; i < gBattlersCount - 1; i++)
{
s32 j;
for (j = i + 1; j < gBattlersCount; j++)
// 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++)
{
if (!gProtectStructs[i].quash
&& !gProtectStructs[j].quash
&& GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1)
SwapTurnOrder(i, j);
SwapTurnOrder(i, j);
j++;
}
}
else
{
// 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++)
{
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;

View File

@ -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); }
@ -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);
}
}

View File

@ -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
}
}