From 89b1a45536936f7abe1b897b3e05a221eb5bd381 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 1 Jul 2025 16:39:22 +0200 Subject: [PATCH] Fixes Ice Spinner and Steel Roller (#7259) --- asm/macros/battle_script.inc | 10 +- data/battle_scripts_1.s | 34 ++--- include/battle_scripts.h | 4 +- include/constants/battle_move_effects.h | 4 +- include/constants/battle_script_commands.h | 8 +- include/move.h | 5 + remove_terrain.log | 0 src/battle_ai_util.c | 6 +- src/battle_script_commands.c | 75 ++++------- src/data/battle_move_effects.h | 16 ++- src/data/moves_info.h | 13 +- test/battle/gimmick/zmove.c | 4 +- test/battle/move_animations/all_anims.c | 4 +- .../move_effect/hit_set_remove_terrain.c | 126 ------------------ test/battle/move_effect/ice_spinner.c | 122 +++++++++++++++++ test/battle/move_effect/steel_roller.c | 75 +++++++++++ 16 files changed, 275 insertions(+), 231 deletions(-) create mode 100644 remove_terrain.log create mode 100644 test/battle/move_effect/ice_spinner.c create mode 100644 test/battle/move_effect/steel_roller.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 673f3ef963..02546d2f8a 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1529,14 +1529,8 @@ .4byte \jumpInstr .endm - .macro jumpifmovepropertyargument argument:req, jumpInstr:req - callnative BS_JumpIfMovePropertyArgument - .byte \argument - .4byte \jumpInstr - .endm - - .macro setremoveterrain failInstr:req - callnative BS_SetRemoveTerrain + .macro setterrain failInstr:req + callnative BS_SetTerrain .4byte \failInstr .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 56bb8fb63e..e32dfd2859 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2248,7 +2248,7 @@ BattleScript_EffectPsychicTerrain:: attackcanceler attackstring ppreduce - setremoveterrain BattleScript_ButItFailed + setterrain BattleScript_ButItFailed attackanimation waitanimation printfromtable gTerrainStringIds @@ -9303,12 +9303,11 @@ BattleScript_ExtremeEvoboostSpDef:: BattleScript_ExtremeEvoboostEnd:: goto BattleScript_MoveEnd -BattleScript_EffectHitSetRemoveTerrain:: +BattleScript_EffectHitSetTerrain:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce - jumpifmovepropertyargument ARG_TRY_REMOVE_TERRAIN_FAIL, BattleScript_RemoveTerrain critcalc damagecalc adjustdamage @@ -9323,7 +9322,7 @@ BattleScript_EffectHitSetRemoveTerrain:: waitmessage B_WAIT_TIME_LONG resultmessage waitmessage B_WAIT_TIME_LONG - setremoveterrain BattleScript_TryFaint + setterrain BattleScript_TryFaint playanimation BS_ATTACKER, B_ANIM_RESTORE_BG printfromtable gTerrainStringIds waitmessage B_WAIT_TIME_LONG @@ -9331,30 +9330,17 @@ BattleScript_TryFaint: tryfaintmon BS_TARGET goto BattleScript_MoveEnd -BattleScript_RemoveTerrain: - jumpifterrainaffected BS_TARGET, STATUS_FIELD_TERRAIN_ANY, BattleScript_RemoveTerrain_Cont - goto BattleScript_ButItFailed -BattleScript_RemoveTerrain_Cont: - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG +BattleScript_EffectSteelRoller:: + attackcanceler + jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_FailedFromAtkString + goto BattleScript_HitFromAccCheck + +BattleScript_RemoveTerrain:: removeterrain playanimation BS_ATTACKER, B_ANIM_RESTORE_BG printfromtable gTerrainStringIds waitmessage B_WAIT_TIME_LONG - tryfaintmon BS_TARGET - goto BattleScript_MoveEnd + return BattleScript_Pickpocket:: call BattleScript_AbilityPopUp diff --git a/include/battle_scripts.h b/include/battle_scripts.h index de3e876aa2..cd88a120a5 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -292,6 +292,7 @@ extern const u8 BattleScript_CursedBodyActivates[]; extern const u8 BattleScript_MummyActivates[]; extern const u8 BattleScript_WeakArmorActivates[]; extern const u8 BattleScript_FellStingerRaisesStat[]; +extern const u8 BattleScript_RemoveTerrain[]; extern const u8 BattleScript_SnowWarningActivatesHail[]; extern const u8 BattleScript_SnowWarningActivatesSnow[]; extern const u8 BattleScript_PickupActivates[]; @@ -339,6 +340,7 @@ extern const u8 BattleScript_GrassySurgeActivates[]; extern const u8 BattleScript_MistySurgeActivates[]; extern const u8 BattleScript_ElectricSurgeActivates[]; extern const u8 BattleScript_EffectSpectralThief[]; +extern const u8 BattleScript_EffectSteelRoller[]; extern const u8 BattleScript_StatUpMsg[]; extern const u8 BattleScript_AbilityRaisesDefenderStat[]; extern const u8 BattleScript_PowderMoveNoEffect[]; @@ -842,7 +844,7 @@ extern const u8 BattleScript_EffectSkyDrop[]; extern const u8 BattleScript_EffectMeteorBeam[]; extern const u8 BattleScript_EffectCourtChange[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; -extern const u8 BattleScript_EffectHitSetRemoveTerrain[]; +extern const u8 BattleScript_EffectHitSetTerrain[]; extern const u8 BattleScript_EffectDarkVoid[]; extern const u8 BattleScript_EffectVictoryDance[]; extern const u8 BattleScript_EffectTeatime[]; diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index d081d3a163..e21387c2af 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -310,7 +310,7 @@ enum BattleMoveEffects EFFECT_MIND_BLOWN, // Same as EFFECT_MAX_HP_50_RECOIL but is cancelled by Damp EFFECT_CHLOROBLAST, // Same effect as EFFECT_MAX_HP_50_RECOIL but follows the same rules as EFFECT_RECOIL EFFECT_EXTREME_EVOBOOST, - EFFECT_HIT_SET_REMOVE_TERRAIN, + EFFECT_HIT_SET_TERRAIN, EFFECT_DARK_VOID, EFFECT_VICTORY_DANCE, EFFECT_TEATIME, @@ -349,6 +349,8 @@ enum BattleMoveEffects EFFECT_SPECTRAL_THIEF, EFFECT_RECOIL, EFFECT_SMACK_DOWN, + EFFECT_ICE_SPINNER, // Removes terrain unless attacker is removed from field either by fainting or ejected out + EFFECT_STEEL_ROLLER, // Will fail if there is no terrain up but removes it regardless if attacker is removed from field or not NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 2b0287be40..1da5f3b134 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -243,7 +243,7 @@ enum CmdVarious #define PARTY_SCREEN_OPTIONAL (1 << 7) // Flag for first argument to openpartyscreen -// cases for Cmd_moveend +// cases for Cmd_moveend - Order matters! enum MoveEndEffects { MOVEEND_SUM_DAMAGE, @@ -283,6 +283,7 @@ enum MoveEndEffects MOVEEND_HIT_ESCAPE, MOVEEND_OPPORTUNIST, // Occurs after other stat change items/abilities to try and copy the boosts MOVEEND_PICKPOCKET, + MOVEEND_REMOVE_TERRAIN, MOVEEND_WHITE_HERB, MOVEEND_CHANGED_ITEMS, MOVEEND_SAME_MOVE_TURNS, @@ -297,9 +298,4 @@ enum MoveEndEffects #define B_SWITCH_HIT 1 // dragon tail, circle throw #define B_SWITCH_RED_CARD 2 -// Argument labels for EFFECT_HIT_SET_REMOVE_TERRAIN -#define ARG_SET_PSYCHIC_TERRAIN 0 -#define ARG_TRY_REMOVE_TERRAIN_HIT 1 -#define ARG_TRY_REMOVE_TERRAIN_FAIL 2 - #endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H diff --git a/include/move.h b/include/move.h index 16ede9d809..52d4d0f072 100644 --- a/include/move.h +++ b/include/move.h @@ -498,6 +498,11 @@ static inline u32 GetMoveProtectMethod(u32 moveId) return gMovesInfo[SanitizeMoveId(moveId)].argument.protectMethod; } +static inline u32 GetMoveTerrainFlag(u32 moveId) +{ + return gMovesInfo[SanitizeMoveId(moveId)].argument.moveProperty; +} + static inline u32 GetMoveEffectArg_Status(u32 moveId) { return gMovesInfo[SanitizeMoveId(moveId)].argument.status; diff --git a/remove_terrain.log b/remove_terrain.log new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 93801927bd..2d7136eefc 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -548,8 +548,8 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy if (!IS_BATTLER_OF_TYPE(battlerAtk, GetMoveArgType(move))) return TRUE; break; - case EFFECT_HIT_SET_REMOVE_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && GetMoveEffectArg_MoveProperty(move) == ARG_TRY_REMOVE_TERRAIN_FAIL) + case EFFECT_STEEL_ROLLER: + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) return TRUE; break; case EFFECT_POLTERGEIST: @@ -827,7 +827,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u simDamage.median = ApplyModifiersAfterDmgRoll(simDamage.median, &damageCalcData, effectivenessMultiplier, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]); - + simDamage.maximum = GetDamageByRollType(damage, DMG_ROLL_HIGHEST); simDamage.maximum = ApplyModifiersAfterDmgRoll(simDamage.maximum, &damageCalcData, effectivenessMultiplier, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index caafa7f303..a1d29bc696 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7363,6 +7363,24 @@ static void Cmd_moveend(void) else gBattleScripting.moveendState++; break; + case MOVEEND_REMOVE_TERRAIN: + if (GetMoveEffect(gChosenMove) == EFFECT_STEEL_ROLLER // Steel Roller has to check the chosen move, Otherwise it would fail in certain cases + && IsBattlerTurnDamaged(gBattlerTarget)) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RemoveTerrain; + effect = TRUE; + } + else if (moveEffect == EFFECT_ICE_SPINNER + && IsBattlerAlive(gBattlerAttacker) + && IsBattlerTurnDamaged(gBattlerTarget)) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_RemoveTerrain; + effect = TRUE; + } + gBattleScripting.moveendState++; + break; case MOVEEND_SYMBIOSIS: for (i = 0; i < gBattlersCount; i++) { @@ -17281,17 +17299,7 @@ void BS_ApplySaltCure(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfMovePropertyArgument(void) -{ - NATIVE_ARGS(u8 argument, const u8 *jumpInstr); - - if (GetMoveEffectArg_MoveProperty(gCurrentMove) == cmd->argument) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; -} - -void BS_SetRemoveTerrain(void) +void BS_SetTerrain(void) { NATIVE_ARGS(const u8 *jumpInstr); u32 statusFlag = 0; @@ -17314,48 +17322,19 @@ void BS_SetRemoveTerrain(void) statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; - case EFFECT_HIT_SET_REMOVE_TERRAIN: - switch (GetMoveEffectArg_MoveProperty(gCurrentMove)) - { - case ARG_SET_PSYCHIC_TERRAIN: // Genesis Supernova - statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; - break; - case ARG_TRY_REMOVE_TERRAIN_HIT: // Splintered Stormshards - case ARG_TRY_REMOVE_TERRAIN_FAIL: // Steel Roller - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)) - { - // No terrain to remove, jump to battle script pointer. - gBattlescriptCurrInstr = cmd->jumpInstr; - } - else - { - // Remove all terrains. - RemoveAllTerrains(); - gBattlescriptCurrInstr = cmd->nextInstr; - } - return; - default: - break; - } + case EFFECT_HIT_SET_TERRAIN: + statusFlag = GetMoveTerrainFlag(gCurrentMove); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; default: break; } + enum ItemHoldEffect atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - if (gFieldStatuses & statusFlag || statusFlag == 0) - { - gBattlescriptCurrInstr = cmd->jumpInstr; - } - else - { - enum ItemHoldEffect atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - - gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; - gFieldStatuses |= statusFlag; - gFieldTimers.terrainTimer = gBattleTurnCounter + (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; - gBattlescriptCurrInstr = cmd->nextInstr; - } + gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; + gFieldStatuses |= statusFlag; + gFieldTimers.terrainTimer = gBattleTurnCounter + (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; + gBattlescriptCurrInstr = cmd->nextInstr; } void BS_JumpIfTerrainAffected(void) diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index dfca0c5232..08d8123296 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1978,9 +1978,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_HIT_SET_REMOVE_TERRAIN] = + [EFFECT_HIT_SET_TERRAIN] = { - .battleScript = BattleScript_EffectHitSetRemoveTerrain, + .battleScript = BattleScript_EffectHitSetTerrain, .battleTvScore = 0, // TODO: Assign points }, @@ -2218,4 +2218,16 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_ICE_SPINNER] = + { + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, + + [EFFECT_STEEL_ROLLER] = + { + .battleScript = BattleScript_EffectSteelRoller, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 1e13d62eb8..c0e44cf4df 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -18444,7 +18444,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Destroys terrain. Fails if\n" "ground isn't terrain."), - .effect = EFFECT_HIT_SET_REMOVE_TERRAIN, + .effect = EFFECT_STEEL_ROLLER, .power = 130, .type = TYPE_STEEL, .accuracy = 100, @@ -18453,7 +18453,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_FAIL }, // Remove a field terrain if there is one and hit, otherwise fail. .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -19879,7 +19878,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Ice-covered feet hit a foe\n" "and destroy the terrain."), - .effect = EFFECT_HIT_SET_REMOVE_TERRAIN, + .effect = EFFECT_ICE_SPINNER, .power = 80, .type = TYPE_ICE, .accuracy = 100, @@ -19888,7 +19887,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_HIT }, // Remove the active field terrain if there is one. .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, .battleAnimScript = gBattleAnimMove_IceSpinner, }, @@ -21520,7 +21518,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Mew attacks with full force.\n" "Psychically charges terrain."), - .effect = EFFECT_HIT_SET_REMOVE_TERRAIN, + .effect = EFFECT_HIT_SET_TERRAIN, .power = 185, .type = TYPE_PSYCHIC, .accuracy = 0, @@ -21528,7 +21526,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = { .moveProperty = ARG_SET_PSYCHIC_TERRAIN }, // Set Psychic Terrain. If there's a different field terrain active, overwrite it. + .argument = { .moveProperty = STATUS_FIELD_PSYCHIC_TERRAIN }, .battleAnimScript = gBattleAnimMove_GenesisSupernova, }, [MOVE_SINISTER_ARROW_RAID] = @@ -21585,7 +21583,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Lycanroc attacks with full\n" "force. Removes all terrain."), - .effect = EFFECT_HIT_SET_REMOVE_TERRAIN, + .effect = EFFECT_ICE_SPINNER, .power = 190, .type = TYPE_ROCK, .accuracy = 0, @@ -21593,7 +21591,6 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_HIT }, // Remove the active field terrain if there is one. .battleAnimScript = gBattleAnimMove_SplinteredStormshards, }, [MOVE_LETS_SNUGGLE_FOREVER] = diff --git a/test/battle/gimmick/zmove.c b/test/battle/gimmick/zmove.c index fd5635d3fc..058d59c620 100644 --- a/test/battle/gimmick/zmove.c +++ b/test/battle/gimmick/zmove.c @@ -578,7 +578,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Extreme Evoboost boosts all the user's stats by two SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") { GIVEN { - ASSUME(GetMoveEffect(MOVE_GENESIS_SUPERNOVA) == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_GENESIS_SUPERNOVA) == EFFECT_HIT_SET_TERRAIN); PLAYER(SPECIES_MEW) { Item(ITEM_MEWNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -595,7 +595,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") SINGLE_BATTLE_TEST("(Z-MOVE) Splintered Stormshards removes terrain") { GIVEN { - ASSUME(GetMoveEffect(MOVE_SPLINTERED_STORMSHARDS) == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_SPLINTERED_STORMSHARDS) == EFFECT_ICE_SPINNER); PLAYER(SPECIES_LYCANROC_DUSK) { Item(ITEM_LYCANIUM_Z); } OPPONENT(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); HP(1000); MaxHP(1000); } } WHEN { diff --git a/test/battle/move_animations/all_anims.c b/test/battle/move_animations/all_anims.c index 778b407937..a994bab63f 100644 --- a/test/battle/move_animations/all_anims.c +++ b/test/battle/move_animations/all_anims.c @@ -152,7 +152,7 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP { // Has to be hailing TURN { MOVE(attacker, MOVE_HAIL); } } - else if (gMovesInfo[move].effect == EFFECT_HIT_SET_REMOVE_TERRAIN && gMovesInfo[move].argument.moveProperty == ARG_TRY_REMOVE_TERRAIN_FAIL) + else if (gMovesInfo[move].effect == EFFECT_STEEL_ROLLER) { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } @@ -281,7 +281,7 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP { // Has to be hailing TURN { MOVE(attacker, MOVE_HAIL); } } - else if (gMovesInfo[move].effect == EFFECT_HIT_SET_REMOVE_TERRAIN && gMovesInfo[move].argument.moveProperty == ARG_TRY_REMOVE_TERRAIN_FAIL) + else if (gMovesInfo[move].effect == EFFECT_STEEL_ROLLER) { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } diff --git a/test/battle/move_effect/hit_set_remove_terrain.c b/test/battle/move_effect/hit_set_remove_terrain.c index 9b9180d6e4..e69de29bb2 100644 --- a/test/battle/move_effect/hit_set_remove_terrain.c +++ b/test/battle/move_effect/hit_set_remove_terrain.c @@ -1,126 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); - ASSUME(GetMoveEffect(MOVE_PSYCHIC_TERRAIN) == EFFECT_PSYCHIC_TERRAIN); - ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN); - ASSUME(GetMoveEffect(MOVE_MISTY_TERRAIN) == EFFECT_MISTY_TERRAIN); - ASSUME(GetMoveEffect(MOVE_STEEL_ROLLER) == EFFECT_HIT_SET_REMOVE_TERRAIN); - ASSUME(GetMoveEffect(MOVE_ICE_SPINNER) == EFFECT_HIT_SET_REMOVE_TERRAIN); -} - -SINGLE_BATTLE_TEST("Steel Roller and Ice Spinner can remove a terrain from the field") -{ - u32 j; - static const u16 terrainMoves[] = - { - MOVE_ELECTRIC_TERRAIN, - MOVE_PSYCHIC_TERRAIN, - MOVE_GRASSY_TERRAIN, - MOVE_MISTY_TERRAIN, - }; - - u16 terrainMove = MOVE_NONE; - u16 removeTerrainMove = MOVE_NONE; - - for (j = 0; j < ARRAY_COUNT(terrainMoves); j++) - { - PARAMETRIZE { removeTerrainMove = MOVE_STEEL_ROLLER; terrainMove = terrainMoves[j]; } - PARAMETRIZE { removeTerrainMove = MOVE_ICE_SPINNER; terrainMove = terrainMoves[j]; } - } - - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, terrainMove); MOVE(player, removeTerrainMove); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, terrainMove, opponent); - ANIMATION(ANIM_TYPE_MOVE, removeTerrainMove, player); - switch (terrainMove) - { - case MOVE_ELECTRIC_TERRAIN: - MESSAGE("The electricity disappeared from the battlefield."); - break; - case MOVE_PSYCHIC_TERRAIN: - MESSAGE("The weirdness disappeared from the battlefield!"); - break; - case MOVE_GRASSY_TERRAIN: - MESSAGE("The grass disappeared from the battlefield."); - break; - case MOVE_MISTY_TERRAIN: - MESSAGE("The mist disappeared from the battlefield."); - break; - } - } -} - -SINGLE_BATTLE_TEST("Steel Roller fails if there is no terrain on the field") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_STEEL_ROLLER); } - } SCENE { - NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_ROLLER, player); - MESSAGE("But it failed!"); - } -} - -SINGLE_BATTLE_TEST("Ice Spinner doesn't fail if there is no terrain on the field") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_ICE_SPINNER); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_SPINNER, player); - NOT MESSAGE("But it failed!"); - } -} - -AI_SINGLE_BATTLE_TEST("AI will not choose Steel Roller if it might fail") -{ - u32 move; - - PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } - PARAMETRIZE { move = MOVE_NONE; } - - GIVEN { - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STEEL_ROLLER, MOVE_ICE_SHARD); } - } WHEN { - if (move == MOVE_ELECTRIC_TERRAIN) { - TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } - TURN { EXPECT_MOVE(opponent, MOVE_STEEL_ROLLER); } - } else { - TURN { EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } - } - } -} - -AI_SINGLE_BATTLE_TEST("AI will can choose Ice Spinner regardless if there is a terrain or not") -{ - u32 move; - - PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } - PARAMETRIZE { move = MOVE_NONE; } - - GIVEN { - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_ICE_SPINNER, MOVE_ICE_SHARD); } - } WHEN { - if (move == MOVE_ELECTRIC_TERRAIN) { - TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } - TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } - } else { - TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } - } - } -} diff --git a/test/battle/move_effect/ice_spinner.c b/test/battle/move_effect/ice_spinner.c new file mode 100644 index 0000000000..44ce21eb4f --- /dev/null +++ b/test/battle/move_effect/ice_spinner.c @@ -0,0 +1,122 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_ICE_SPINNER) == EFFECT_ICE_SPINNER); +} + +SINGLE_BATTLE_TEST("Ice Spinner and Steel Roller remove a terrain from field") +{ + u32 j; + static const u16 terrainMoves[] = + { + MOVE_ELECTRIC_TERRAIN, + MOVE_PSYCHIC_TERRAIN, + MOVE_GRASSY_TERRAIN, + MOVE_MISTY_TERRAIN, + }; + + u16 terrainMove = MOVE_NONE; + u16 removeTerrainMove = MOVE_NONE; + + for (j = 0; j < ARRAY_COUNT(terrainMoves); j++) + { + PARAMETRIZE { removeTerrainMove = MOVE_STEEL_ROLLER; terrainMove = terrainMoves[j]; } + PARAMETRIZE { removeTerrainMove = MOVE_ICE_SPINNER; terrainMove = terrainMoves[j]; } + } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_PSYCHIC_TERRAIN) == EFFECT_PSYCHIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN); + ASSUME(GetMoveEffect(MOVE_MISTY_TERRAIN) == EFFECT_MISTY_TERRAIN); + ASSUME(GetMoveEffect(MOVE_STEEL_ROLLER) == EFFECT_STEEL_ROLLER); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, terrainMove); MOVE(player, removeTerrainMove); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, terrainMove, opponent); + ANIMATION(ANIM_TYPE_MOVE, removeTerrainMove, player); + switch (terrainMove) + { + case MOVE_ELECTRIC_TERRAIN: + MESSAGE("The electricity disappeared from the battlefield."); + break; + case MOVE_PSYCHIC_TERRAIN: + MESSAGE("The weirdness disappeared from the battlefield!"); + break; + case MOVE_GRASSY_TERRAIN: + MESSAGE("The grass disappeared from the battlefield."); + break; + case MOVE_MISTY_TERRAIN: + MESSAGE("The mist disappeared from the battlefield."); + break; + } + } +} + +SINGLE_BATTLE_TEST("Ice Spinner fails to remove terrain if user faints during attack execution") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_ICE_SPINNER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_SPINNER, opponent); + NOT MESSAGE("The electricity disappeared from the battlefield."); + } +} + +SINGLE_BATTLE_TEST("Ice Spinner will not be remove Terrain if user is switched out due to Red Card") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_ICE_SPINNER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_SPINNER, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + NOT MESSAGE("The electricity disappeared from the battlefield."); + } +} + +SINGLE_BATTLE_TEST("Ice Spinner doesn't fail if there is no terrain on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ICE_SPINNER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_SPINNER, player); + NOT MESSAGE("But it failed!"); + } +} + +AI_SINGLE_BATTLE_TEST("Ice Spinner can be chosen by AI regardless if there is a terrain or not") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_ICE_SPINNER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } + } +} diff --git a/test/battle/move_effect/steel_roller.c b/test/battle/move_effect/steel_roller.c new file mode 100644 index 0000000000..4b658a6124 --- /dev/null +++ b/test/battle/move_effect/steel_roller.c @@ -0,0 +1,75 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_STEEL_ROLLER) == EFFECT_STEEL_ROLLER); +} + +// Covered in ice_spinner.c +// SINGLE_BATTLE_TEST("Ice Spinner and Steel Roller remove a terrain from field") + +SINGLE_BATTLE_TEST("Steel Roller removes Terrain even if user faints during attack execution") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_STEEL_ROLLER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_ROLLER, opponent); + MESSAGE("The electricity disappeared from the battlefield."); + } +} + +SINGLE_BATTLE_TEST("Steel Roller removes Terrain if user is switched out due to Red Card") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_STEEL_ROLLER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_ROLLER, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("The electricity disappeared from the battlefield."); + } +} + +SINGLE_BATTLE_TEST("Steel Roller will fail if there is no Terrain") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_STEEL_ROLLER); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_ROLLER, opponent); + MESSAGE("The opposing Wobbuffet used Steel Roller!"); + MESSAGE("But it failed!"); + } +} + +AI_SINGLE_BATTLE_TEST("Steel Roller wont be chosen by AI if there is no terrain on the field") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STEEL_ROLLER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + TURN { EXPECT_MOVE(opponent, MOVE_STEEL_ROLLER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + } + } +}