Fixes Toxic Thread animation not being played at the right time (#7247)

Co-authored-by: hedara90 <90hedara@gmail.com>
This commit is contained in:
Alex 2025-06-30 21:41:29 +02:00 committed by GitHub
parent 46d4b7c8c9
commit 5451e40830
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 96 additions and 21 deletions

View File

@ -834,8 +834,10 @@
.4byte \failInstr
.endm
.macro unused_0x94
.macro checknonvolatiletrigger nonVolatile:req, failInstr:req
.byte 0x94
.2byte \nonVolatile
.4byte \failInstr
.endm
.macro copybidedmg

View File

@ -1836,20 +1836,20 @@ BattleScript_EffectToxicThread::
setstatchanger STAT_SPEED, 1, TRUE
attackcanceler
jumpifsubstituteblocks BattleScript_FailedFromAtkString
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_SPEED, MIN_STAT_STAGE, BattleScript_ToxicThreadWorks
jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_FailedFromAtkString
checknonvolatiletrigger MOVE_EFFECT_POISON, BattleScript_EffectStatDownFromAccCheck
BattleScript_ToxicThreadWorks:
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
attackanimation
waitanimation
setstatchanger STAT_SPEED, 1, TRUE
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_ToxicThreadTryPsn
jumpifbyte CMP_LESS_THAN, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_ToxicThreadDoAnim
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_FELL_EMPTY, BattleScript_ToxicThreadTryPsn
pause B_WAIT_TIME_SHORT
goto BattleScript_ToxicThreadPrintString
BattleScript_ToxicThreadDoAnim::
attackanimation
waitanimation
setgraphicalstatchangevalues
playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
BattleScript_ToxicThreadPrintString::
@ -3144,6 +3144,7 @@ BattleScript_EffectEvasionDown::
BattleScript_EffectStatDown:
attackcanceler
jumpifsubstituteblocks BattleScript_FailedFromAtkString
BattleScript_EffectStatDownFromAccCheck:
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
BattleScript_StatDownFromAttackString:
attackstring

View File

@ -496,7 +496,7 @@ static void Cmd_tryconversiontypechange(void);
static void Cmd_givepaydaymoney(void);
static void Cmd_setlightscreen(void);
static void Cmd_tryKO(void);
static void Cmd_unused_0x94(void);
static void Cmd_checknonvolatiletrigger(void);
static void Cmd_copybidedmg(void);
static void Cmd_unused_96(void);
static void Cmd_tryinfatuating(void);
@ -755,7 +755,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_givepaydaymoney, //0x91
Cmd_setlightscreen, //0x92
Cmd_tryKO, //0x93
Cmd_unused_0x94, //0x94
Cmd_checknonvolatiletrigger, //0x94
Cmd_copybidedmg, //0x95
Cmd_unused_96, //0x96
Cmd_tryinfatuating, //0x97
@ -12594,12 +12594,13 @@ static void Cmd_trynonvolatilestatus(void)
CMD_ARGS();
bool32 canInflictStatus = TRUE;
if (!CanSetNonVolatileStatus(gBattlerAttacker,
gBattlerTarget,
GetBattlerAbility(gBattlerAttacker),
GetBattlerAbility(gBattlerTarget),
GetMoveNonVolatileStatus(gCurrentMove),
STATUS_RUN_SCRIPT))
if (!CanSetNonVolatileStatus(
gBattlerAttacker,
gBattlerTarget,
GetBattlerAbility(gBattlerAttacker),
GetBattlerAbility(gBattlerTarget),
GetMoveNonVolatileStatus(gCurrentMove),
STATUS_RUN_SCRIPT))
canInflictStatus = FALSE;
if (canInflictStatus && DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
@ -13048,8 +13049,22 @@ static void Cmd_tryKO(void)
#undef FOCUS_BANDED
#undef AFFECTION_ENDURED
static void Cmd_unused_0x94(void)
static void Cmd_checknonvolatiletrigger(void)
{
CMD_ARGS(u16 nonVolatile, const u8 *failInstr);
if (!CanSetNonVolatileStatus(
gBattlerAttacker,
gBattlerTarget,
GetBattlerAbility(gBattlerAttacker),
GetBattlerAbility(gBattlerTarget),
cmd->nonVolatile,
STATUS_CHECK_TRIGGER))
gBattlescriptCurrInstr = cmd->failInstr;
else if (DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
gBattlescriptCurrInstr = cmd->failInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void Cmd_copybidedmg(void)

View File

@ -2866,7 +2866,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
"Minimizes the user's size to\n"
#if B_MINIMIZE_EVASION >= GEN_5
"sharply raise evasiveness."),
#else
#else
"raise evasiveness."),
#endif
.effect = EFFECT_MINIMIZE,
@ -3704,7 +3704,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.description = COMPOUND_STRING(
#if B_UPDATED_MOVE_DATA >= GEN_5
"Envelops the foes in a toxic\n"
#else
#else
"Envelops the foe in a toxic\n"
#endif
"gas that may poison."),
@ -6053,7 +6053,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
"User spins and removes some\n"
#if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8
"effects, while upping speed."),
#else
#else
"effects."),
#endif
.effect = EFFECT_RAPID_SPIN,
@ -6280,7 +6280,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
#else
"The type and effectiveness\n"
"vary with the user."),
#endif
#endif
.power = B_HIDDEN_POWER_DMG >= GEN_6 ? 60 : 1,
.effect = EFFECT_HIDDEN_POWER,
.type = TYPE_NORMAL,
@ -9621,7 +9621,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
"Whips up a breeze, doubling\n"
#if B_TAILWIND_TURNS >= GEN_5
"ally Speed for 4 turns."),
#else
#else
"ally Speed for 3 turns."),
#endif
.effect = EFFECT_TAILWIND,

View File

@ -25,7 +25,6 @@ SINGLE_BATTLE_TEST("Toxic Thread both reduces speed and inflicts Poison")
SINGLE_BATTLE_TEST("Toxic Thread still inflicts Poison if speed can't go lower")
{
KNOWN_FAILING; // #7243
GIVEN {
ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2);
PLAYER(SPECIES_WOBBUFFET);
@ -53,7 +52,6 @@ SINGLE_BATTLE_TEST("Toxic Thread still inflicts Poison if speed can't go lower")
SINGLE_BATTLE_TEST("Toxic Thread still inflicts Poison if speed can't be lowered")
{
KNOWN_FAILING; // #7243
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_REGICE) { Ability(ABILITY_CLEAR_BODY); }
@ -106,3 +104,62 @@ SINGLE_BATTLE_TEST("Toxic Thread still lowers speed if the target is already Poi
EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1);
}
}
SINGLE_BATTLE_TEST("Toxic Thread fails if speed can't be lowered and status can't be inflicted")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_POISON_POWDER) == MOVE_EFFECT_POISON);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_POISON_POWDER); }
TURN { MOVE(player, MOVE_TOXIC_THREAD); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_POWDER, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_THREAD, player);
}
}
SINGLE_BATTLE_TEST("Toxic Thread fails if speed can't be lowered due to Clear Body and status can't be inflicted")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_POISON_POWDER) == MOVE_EFFECT_POISON);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_REGICE) { Ability(ABILITY_CLEAR_BODY); }
} WHEN {
TURN { MOVE(player, MOVE_POISON_POWDER); }
TURN { MOVE(player, MOVE_TOXIC_THREAD); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_POWDER, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_THREAD, player);
}
}
SINGLE_BATTLE_TEST("Toxic Thread fails if speed can't be lowered and target is a poison type")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_NON_VOLATILE_STATUS);
ASSUME(GetMoveNonVolatileStatus(MOVE_POISON_POWDER) == MOVE_EFFECT_POISON);
ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_POISON || gSpeciesInfo[SPECIES_ODDISH].types[1] == TYPE_POISON);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ODDISH);
} WHEN {
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_SCARY_FACE); }
TURN { MOVE(player, MOVE_TOXIC_THREAD); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCARY_FACE, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_THREAD, player);
}
}