diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index b524104a36..673f3ef963 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -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 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 7fcf186910..56bb8fb63e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -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 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f0957241ca..caafa7f303 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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) diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 51f3438952..1e13d62eb8 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -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, diff --git a/test/battle/move_effects_combined/toxic_thread.c b/test/battle/move_effects_combined/toxic_thread.c index c946619cd8..ec27f46365 100644 --- a/test/battle/move_effects_combined/toxic_thread.c +++ b/test/battle/move_effects_combined/toxic_thread.c @@ -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); + } +}