Fixes Ice Spinner and Steel Roller (#7259)

This commit is contained in:
Alex 2025-07-01 16:39:22 +02:00 committed by GitHub
parent 5451e40830
commit 89b1a45536
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 275 additions and 231 deletions

View File

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

View File

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

View File

@ -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[];

View File

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

View File

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

View File

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

0
remove_terrain.log Normal file
View File

View File

@ -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],

View File

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

View File

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

View File

@ -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] =

View File

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

View File

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

View File

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

View File

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

View File

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