From 71609a404dc065d583a74371ef1821985a5e27db Mon Sep 17 00:00:00 2001 From: GGbond Date: Wed, 31 Dec 2025 00:47:33 +0800 Subject: [PATCH 1/3] Add tests for abilities that affect weather (#8709) --- src/battle_util.c | 5 +- test/battle/ability/delta_stream.c | 44 ++++- test/battle/ability/desolate_land.c | 89 +++++++-- test/battle/ability/drizzle.c | 81 ++++++++ test/battle/ability/orichalcum_pulse.c | 111 ++++++++++- test/battle/ability/primordial_sea.c | 89 +++++++-- test/battle/ability/sand_spit.c | 75 ++++++- test/battle/ability/sand_stream.c | 81 +++++++- test/battle/ability/snow_warning.c | 132 +++++++++++-- test/battle/weather/strong_winds.c | 260 +++++++++++++++++++++++-- 10 files changed, 911 insertions(+), 56 deletions(-) diff --git a/src/battle_util.c b/src/battle_util.c index 46347b7028..7209ae17c8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7834,8 +7834,9 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) } break; case ABILITY_ORICHALCUM_PULSE: - if ((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect() && IsBattleMovePhysical(move)) - modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333)); + if ((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect() && IsBattleMovePhysical(move) + && ctx->holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA) + modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333)); break; case ABILITY_HADRON_ENGINE: if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IsBattleMoveSpecial(move)) diff --git a/test/battle/ability/delta_stream.c b/test/battle/ability/delta_stream.c index a2202d64c0..0ea7429ff4 100644 --- a/test/battle/ability/delta_stream.c +++ b/test/battle/ability/delta_stream.c @@ -5,5 +5,45 @@ //TO_DO_BATTLE_TEST("Delta Stream doesn't activate if is sent-out in a rotated-out position (Rotation)") //TO_DO_BATTLE_TEST("Delta Stream doesn't activate if is rotated-in (Rotation)") -TO_DO_BATTLE_TEST("Delta Stream doesn't activate if there's already strong winds") -TO_DO_BATTLE_TEST("Strong winds continue as long as there's a Pokémon with Delta Stream on the field") // Doesn't need to be the original mon +DOUBLE_BATTLE_TEST("Delta Stream doesn't activate if there's already strong winds") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(playerLeft, 2); } + } SCENE { + ABILITY_POPUP(opponentLeft, ABILITY_DELTA_STREAM); + MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Rayquaza"); + NONE_OF { + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); + } + } +} + +DOUBLE_BATTLE_TEST("Strong winds continue as long as there's a Pokémon with Delta Stream on the field") +{ + GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); HP(1); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); SEND_OUT(playerLeft, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); + HP_BAR(playerLeft, hp: 0); + MESSAGE("Rayquaza fainted!"); + SEND_IN_MESSAGE("Wobbuffet"); + NOT MESSAGE("The mysterious strong winds have dissipated!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); + } +} diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index d9f1e3924a..3d19f4490d 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -99,14 +99,81 @@ SINGLE_BATTLE_TEST("Desolate Land is removed immediately if user faints") } } -TO_DO_BATTLE_TEST("Desolate Land makes Sunny Day fail") -TO_DO_BATTLE_TEST("Desolate Land makes Rain Dance fail") -TO_DO_BATTLE_TEST("Desolate Land makes Sandstorm fail") -TO_DO_BATTLE_TEST("Desolate Land makes Hail fail") -TO_DO_BATTLE_TEST("Desolate Land makes Snowscape fail") // Extrapolation -TO_DO_BATTLE_TEST("Desolate Land makes Drought fail to activate") -TO_DO_BATTLE_TEST("Desolate Land makes Drizzle fail to activate") -TO_DO_BATTLE_TEST("Desolate Land makes Sand Stream fail to activate") -TO_DO_BATTLE_TEST("Desolate Land makes Snow Warning fail to activate") -TO_DO_BATTLE_TEST("Desolate Land can be replaced by Delta Stream") -TO_DO_BATTLE_TEST("Desolate Land can be replaced by Primordial Sea") +SINGLE_BATTLE_TEST("Desolate Land blocks weather-setting moves") +{ + u16 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_SANDSTORM; } + PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_SUN_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Desolate Land prevents other weather abilities") +{ + u16 ability, species; + PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } + PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } + PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } + PARAMETRIZE { ability = ABILITY_SNOW_WARNING; species = SPECIES_ABOMASNOW; } + + GIVEN { + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ability); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_SUN_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Desolate Land can be replaced by Delta Stream") +{ + GIVEN { + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); + MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); + } +} + +SINGLE_BATTLE_TEST("Desolate Land can be replaced by Primordial Sea") +{ + GIVEN { + PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); + MESSAGE("A heavy rain began to fall!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); + } +} diff --git a/test/battle/ability/drizzle.c b/test/battle/ability/drizzle.c index fd56704830..8e6f7876c9 100644 --- a/test/battle/ability/drizzle.c +++ b/test/battle/ability/drizzle.c @@ -22,3 +22,84 @@ SINGLE_BATTLE_TEST("Drizzle summons rain", s16 damage) EXPECT_MUL_EQ(results[1].damage, Q_4_12(1.5), results[0].damage); } } + +SINGLE_BATTLE_TEST("Drizzle sets up rain for 5 turns (Gen6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRIZZLE); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("The rain stopped."); + } +} + +SINGLE_BATTLE_TEST("Drizzle sets up rain for 8 turns with Damp Rock (Gen6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); Item(ITEM_DAMP_ROCK); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRIZZLE); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("The rain stopped."); + } +} + +SINGLE_BATTLE_TEST("Drizzle sets up permanent rain (Gen3-5)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_3); + PLAYER(SPECIES_POLITOED) { Moves(MOVE_CELEBRATE); Ability(ABILITY_DRIZZLE); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRIZZLE); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + MESSAGE("Rain continues to fall."); + NOT MESSAGE("The rain stopped."); + } +} diff --git a/test/battle/ability/orichalcum_pulse.c b/test/battle/ability/orichalcum_pulse.c index 295e0db23c..62509ce0c6 100644 --- a/test/battle/ability/orichalcum_pulse.c +++ b/test/battle/ability/orichalcum_pulse.c @@ -1,5 +1,112 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Orichalcum Pulse sets up sun for 5 turns"); -TO_DO_BATTLE_TEST("Orichalcum Pulse boosts the Pokémon's Attack by 33% in sun, even if it's holding an Utility Umbrella"); +SINGLE_BATTLE_TEST("Orichalcum Pulse sets up sun for 5 turns") +{ + GIVEN { + PLAYER(SPECIES_KORAIDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_ORICHALCUM_PULSE); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ORICHALCUM_PULSE); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight faded."); + } +} + +SINGLE_BATTLE_TEST("Orichalcum Pulse sets up sun for 8 turns with Heat Rock") +{ + GIVEN { + PLAYER(SPECIES_KORAIDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_ORICHALCUM_PULSE); Item(ITEM_HEAT_ROCK); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ORICHALCUM_PULSE); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight is strong."); + MESSAGE("The sunlight faded."); + } +} + +SINGLE_BATTLE_TEST("Orichalcum Pulse boosts physical moves by 33% in sun", s16 damage) +{ + u16 setupMove; + PARAMETRIZE { setupMove = MOVE_CELEBRATE; } + PARAMETRIZE { setupMove = MOVE_RAIN_DANCE; } + + GIVEN { + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_KORAIDON) { Ability(ABILITY_ORICHALCUM_PULSE); Moves(MOVE_SCRATCH); Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_RAIN_DANCE, MOVE_CELEBRATE); Speed(10); } + } WHEN { + TURN { MOVE(opponent, setupMove); MOVE(player, MOVE_SCRATCH); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ORICHALCUM_PULSE); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(1.3333), results[0].damage); + } +} + +SINGLE_BATTLE_TEST("Orichalcum Pulse boost applies even if the target holds Utility Umbrella", s16 damage) +{ + u16 targetItem; + PARAMETRIZE { targetItem = ITEM_NONE; } + PARAMETRIZE { targetItem = ITEM_UTILITY_UMBRELLA; } + + GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_KORAIDON) { Ability(ABILITY_ORICHALCUM_PULSE); Moves(MOVE_SCRATCH); Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); Speed(10); Item(targetItem); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_SCRATCH); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ORICHALCUM_PULSE); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Orichalcum Pulse does not boost physical moves if holder has Utility Umbrella", s16 damage) +{ + u16 holdItem; + PARAMETRIZE { holdItem = ITEM_NONE; } + PARAMETRIZE { holdItem = ITEM_UTILITY_UMBRELLA; } + + GIVEN { + ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_KORAIDON) { Ability(ABILITY_ORICHALCUM_PULSE); Moves(MOVE_SCRATCH); Speed(5); Item(holdItem); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_SCRATCH); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ORICHALCUM_PULSE); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(1.3333), results[0].damage); + } +} diff --git a/test/battle/ability/primordial_sea.c b/test/battle/ability/primordial_sea.c index f24219f263..a34eb97b5c 100644 --- a/test/battle/ability/primordial_sea.c +++ b/test/battle/ability/primordial_sea.c @@ -65,14 +65,81 @@ SINGLE_BATTLE_TEST("Primordial Sea does not block a move if Pokémon is asleep a } } -TO_DO_BATTLE_TEST("Primordial Sea makes Sunny Day fail") -TO_DO_BATTLE_TEST("Primordial Sea makes Rain Dance fail") -TO_DO_BATTLE_TEST("Primordial Sea makes Sandstorm fail") -TO_DO_BATTLE_TEST("Primordial Sea makes Hail fail") -TO_DO_BATTLE_TEST("Primordial Sea makes Snowscape fail") // Extrapolation -TO_DO_BATTLE_TEST("Primordial Sea makes Drought fail to activate") -TO_DO_BATTLE_TEST("Primordial Sea makes Drizzle fail to activate") -TO_DO_BATTLE_TEST("Primordial Sea makes Sand Stream fail to activate") -TO_DO_BATTLE_TEST("Primordial Sea makes Snow Warning fail to activate") -TO_DO_BATTLE_TEST("Primordial Sea can be replaced by Delta Stream") -TO_DO_BATTLE_TEST("Primordial Sea can be replaced by Desolate Land") +SINGLE_BATTLE_TEST("Primordial Sea blocks weather-setting moves") +{ + u16 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_SANDSTORM; } + PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primordial Sea prevents other weather abilities") +{ + u16 ability, species; + PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } + PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } + PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } + PARAMETRIZE { ability = ABILITY_SNOW_WARNING; species = SPECIES_ABOMASNOW; } + + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ability); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Primordial Sea can be replaced by Delta Stream") +{ + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); + MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); + } +} + +SINGLE_BATTLE_TEST("Primordial Sea can be replaced by Desolate Land") +{ + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND); + MESSAGE("The sunlight turned extremely harsh!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_SUN_PRIMAL); + } +} diff --git a/test/battle/ability/sand_spit.c b/test/battle/ability/sand_spit.c index c2128f65de..cb97179443 100644 --- a/test/battle/ability/sand_spit.c +++ b/test/battle/ability/sand_spit.c @@ -1,4 +1,77 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Sand Spit (Ability) test titles") +SINGLE_BATTLE_TEST("Sand Spit sets up sandstorm for 5 turns when hit") +{ + GIVEN { + PLAYER(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_SPIT); } + OPPONENT(SPECIES_LANDORUS) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("The opposing Landorus used Tackle!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_SAND_SPIT); + MESSAGE("A sandstorm kicked up!"); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm subsided."); + } +} + +SINGLE_BATTLE_TEST("Sand Spit sets up sandstorm for 8 turns when hit with Smooth Rock") +{ + GIVEN { + PLAYER(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_SPIT); Item(ITEM_SMOOTH_ROCK); } + OPPONENT(SPECIES_LANDORUS) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("The opposing Landorus used Tackle!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_SAND_SPIT); + MESSAGE("A sandstorm kicked up!"); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm subsided."); + } +} + +SINGLE_BATTLE_TEST("Sand Spit triggers even if the user is knocked out by the hit") +{ + GIVEN { + PLAYER(SPECIES_SANDSLASH) { Ability(ABILITY_SAND_SPIT); HP(1); Speed(1); } + PLAYER(SPECIES_LANDORUS) { Moves(MOVE_CELEBRATE); Speed(5); } + OPPONENT(SPECIES_LANDORUS) { Moves(MOVE_TACKLE, MOVE_CELEBRATE); Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + MESSAGE("The opposing Landorus used Tackle!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_SAND_SPIT); + MESSAGE("A sandstorm kicked up!"); + MESSAGE("The sandstorm is raging."); + MESSAGE("The opposing Landorus used Celebrate!"); + MESSAGE("Landorus used Celebrate!"); + MESSAGE("The sandstorm is raging."); + } +} diff --git a/test/battle/ability/sand_stream.c b/test/battle/ability/sand_stream.c index 6cd1b06eb4..a1b9464c2a 100644 --- a/test/battle/ability/sand_stream.c +++ b/test/battle/ability/sand_stream.c @@ -1,4 +1,83 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Sand Stream (Ability) test titles") +SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 5 turns (Gen6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); } + OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SAND_STREAM); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm subsided."); + } +} + +SINGLE_BATTLE_TEST("Sand Stream sets up sandstorm for 8 turns with Smooth Rock (Gen6+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); Item(ITEM_SMOOTH_ROCK); } + OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SAND_STREAM); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm subsided."); + } +} + +SINGLE_BATTLE_TEST("Sand Stream sets up permanent sandstorm (Gen3-5)") +{ + GIVEN { + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_3); + PLAYER(SPECIES_HIPPOWDON) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SAND_STREAM); } + OPPONENT(SPECIES_SANDSLASH) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SAND_STREAM); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + MESSAGE("The sandstorm is raging."); + NOT MESSAGE("The sandstorm subsided."); + } +} diff --git a/test/battle/ability/snow_warning.c b/test/battle/ability/snow_warning.c index bffee14e49..bfb27c5f49 100644 --- a/test/battle/ability/snow_warning.c +++ b/test/battle/ability/snow_warning.c @@ -1,30 +1,138 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Snow Warning summons hail (Gen4-8)") +SINGLE_BATTLE_TEST("Snow Warning sets up hail for 5 turns (Gen6-8)") { GIVEN { WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8); - PLAYER(SPECIES_ABOMASNOW) { Ability(ABILITY_SNOW_WARNING); } - OPPONENT(SPECIES_WOBBUFFET); + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } } WHEN { - TURN {} + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { - MESSAGE("It started to hail!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HAIL_CONTINUES); + ABILITY_POPUP(player, ABILITY_SNOW_WARNING); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail stopped."); } } -SINGLE_BATTLE_TEST("Snow Warning summons snow (Gen9+)") +SINGLE_BATTLE_TEST("Snow Warning sets up hail for 8 turns with Icy Rock (Gen6-8)") +{ + GIVEN { + WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8); + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_6); + PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); Item(ITEM_ICY_ROCK); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SNOW_WARNING); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail stopped."); + } +} + +SINGLE_BATTLE_TEST("Snow Warning sets up permanent hail (Gen4-5)") +{ + GIVEN { + WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_8); + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_5); + PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SNOW_WARNING); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + MESSAGE("The hail is crashing down."); + NOT MESSAGE("The hail stopped."); + } +} + +SINGLE_BATTLE_TEST("Snow Warning sets up snow for 5 turns (Gen9+)") { GIVEN { WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_9); - PLAYER(SPECIES_ABOMASNOW) { Ability(ABILITY_SNOW_WARNING); } - OPPONENT(SPECIES_WOBBUFFET); + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_9); + PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } } WHEN { - TURN {} + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { - MESSAGE("It started to snow!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SNOW_CONTINUES); + ABILITY_POPUP(player, ABILITY_SNOW_WARNING); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("The snow stopped."); + } +} + +SINGLE_BATTLE_TEST("Snow Warning sets up snow for 8 turns with Icy Rock (Gen9+)") +{ + GIVEN { + WITH_CONFIG(CONFIG_SNOW_WARNING, GEN_9); + WITH_CONFIG(CONFIG_ABILITY_WEATHER, GEN_9); + PLAYER(SPECIES_ABOMASNOW) { Moves(MOVE_CELEBRATE); Ability(ABILITY_SNOW_WARNING); Item(ITEM_ICY_ROCK); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_SNOW_WARNING); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("Snow continues to fall."); + MESSAGE("The snow stopped."); } } diff --git a/test/battle/weather/strong_winds.c b/test/battle/weather/strong_winds.c index 26b0a51d0d..f319a7a229 100644 --- a/test/battle/weather/strong_winds.c +++ b/test/battle/weather/strong_winds.c @@ -1,17 +1,249 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") // Electric, Ice, Rock -TO_DO_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle") // Bug, Fighting, Grass -TO_DO_BATTLE_TEST("Strong winds don't affect Stealth Rock's damage") -TO_DO_BATTLE_TEST("Strong winds makes Sunny Day fail") -TO_DO_BATTLE_TEST("Strong winds makes Rain Dance fail") -TO_DO_BATTLE_TEST("Strong winds makes Sandstorm fail") -TO_DO_BATTLE_TEST("Strong winds makes Hail fail") -TO_DO_BATTLE_TEST("Strong winds makes Snowscape fail") // Extrapolation -TO_DO_BATTLE_TEST("Strong winds makes Drought fail to activate") -TO_DO_BATTLE_TEST("Strong winds makes Drizzle fail to activate") -TO_DO_BATTLE_TEST("Strong winds makes Sand Stream fail to activate") -TO_DO_BATTLE_TEST("Strong winds makes Snow Warning fail to activate") -TO_DO_BATTLE_TEST("Strong winds can be replaced by Desolate Land") -TO_DO_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") // Electric, Ice, Rock +{ + u16 move; + bool32 targetPlayer; + + PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = TRUE; } + PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = TRUE; } + PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = TRUE; } + PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = FALSE; } + PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = FALSE; } + PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = FALSE; } + + GIVEN { + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); + ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_PIDGEY); + OPPONENT(SPECIES_PIDGEY); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (targetPlayer) + TURN { MOVE(opponentLeft, move, target: playerRight); } + else + TURN { MOVE(playerRight, move, target: opponentLeft); } + } SCENE { + if (targetPlayer) { + if (move == MOVE_THUNDER_SHOCK) + MESSAGE("The opposing Pidgey used Thunder Shock!"); + else if (move == MOVE_ICE_BEAM) + MESSAGE("The opposing Pidgey used Ice Beam!"); + else + MESSAGE("The opposing Pidgey used Rock Throw!"); + MESSAGE("The mysterious strong winds weakened the attack!"); + ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft); + } else { + if (move == MOVE_THUNDER_SHOCK) + MESSAGE("Pidgey used Thunder Shock!"); + else if (move == MOVE_ICE_BEAM) + MESSAGE("Pidgey used Ice Beam!"); + else + MESSAGE("Pidgey used Rock Throw!"); + MESSAGE("The mysterious strong winds weakened the attack!"); + ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + } + } +} + +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle", s16 damagePlayer, s16 damageOpponent) // Bug, Fighting, Grass +{ + u16 move; + bool32 strongWinds; + + PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = FALSE; } + PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = TRUE; } + PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = FALSE; } + PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = TRUE; } + PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = FALSE; } + PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = TRUE; } + + GIVEN { + FLAG_SET(B_FLAG_INVERSE_BATTLE); + ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); + ASSUME(GetMoveType(MOVE_KARATE_CHOP) == TYPE_FIGHTING); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); + ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); + if (strongWinds) + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + else + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_TORNADUS); + OPPONENT(SPECIES_TORNADUS); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(opponentLeft, move, target: playerRight); + MOVE(playerRight, move, target: opponentLeft); + } + } SCENE { + HP_BAR(playerRight, captureDamage: &results[i].damagePlayer); + HP_BAR(opponentLeft, captureDamage: &results[i].damageOpponent); + } FINALLY { + EXPECT_GT(results[0].damagePlayer, results[1].damagePlayer); + EXPECT_GT(results[0].damageOpponent, results[1].damageOpponent); + EXPECT_GT(results[2].damagePlayer, results[3].damagePlayer); + EXPECT_GT(results[2].damageOpponent, results[3].damageOpponent); + EXPECT_GT(results[4].damagePlayer, results[5].damagePlayer); + EXPECT_GT(results[4].damageOpponent, results[5].damageOpponent); + } +} + +SINGLE_BATTLE_TEST("Strong winds prevent Weakness Policy from activating on Flying-type weaknesses") +{ + GIVEN { + ASSUME(GetItemHoldEffect(ITEM_WEAKNESS_POLICY) == HOLD_EFFECT_WEAKNESS_POLICY); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK); } + OPPONENT(SPECIES_PIDGEY) { Item(ITEM_WEAKNESS_POLICY); } + } WHEN { + TURN { MOVE(player, MOVE_THUNDER_SHOCK); } + } SCENE { + MESSAGE("Rayquaza used Thunder Shock!"); + MESSAGE("The mysterious strong winds weakened the attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_SHOCK, player); + HP_BAR(opponent); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + } +} + +SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active") +{ + GIVEN { + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK, MOVE_CELEBRATE); } + OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); + MESSAGE("Rayquaza used Celebrate!"); + MESSAGE("The opposing Pidgey used Celebrate!"); + } +} + +SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active in Inverse Battle") +{ + GIVEN { + FLAG_SET(B_FLAG_INVERSE_BATTLE); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); + ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_VINE_WHIP, MOVE_CELEBRATE); } + OPPONENT(SPECIES_TORNADUS) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); + MESSAGE("Rayquaza used Celebrate!"); + MESSAGE("The opposing Tornadus used Celebrate!"); + } +} + +SINGLE_BATTLE_TEST("Strong winds don't affect Stealth Rock's damage") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_PIDGEY); + OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { SWITCH(player, 1); } + } SCENE { + s32 maxHP = GetMonData(&PLAYER_PARTY[1], MON_DATA_MAX_HP); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + HP_BAR(player, damage: maxHP / 4); + } +} + +SINGLE_BATTLE_TEST("Strong winds block weather-setting moves") +{ + u16 move; + PARAMETRIZE { move = MOVE_SUNNY_DAY; } + PARAMETRIZE { move = MOVE_RAIN_DANCE; } + PARAMETRIZE { move = MOVE_SANDSTORM; } + PARAMETRIZE { move = MOVE_HAIL; } + PARAMETRIZE { move = MOVE_SNOWSCAPE; } + + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); + } +} + +SINGLE_BATTLE_TEST("Strong winds prevent other weather abilities") +{ + u16 ability, species; + PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } + PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } + PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } + PARAMETRIZE { ability = ABILITY_SNOW_WARNING; species = SPECIES_ABOMASNOW; } + + GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ability); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); + } +} + +SINGLE_BATTLE_TEST("Strong winds can be replaced by Desolate Land") +{ + GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND); + MESSAGE("The sunlight turned extremely harsh!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_SUN_PRIMAL); + } +} + +SINGLE_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") +{ + GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); + MESSAGE("A heavy rain began to fall!"); + } THEN { + EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); + } +} From c0d4f0e45f9f4708fa5f5c371cb6adf132d38ba4 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Wed, 31 Dec 2025 01:13:23 +0100 Subject: [PATCH 2/3] Use release instead of LTO in CI (#8706) Co-authored-by: Hedara --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da1a943e83..bb069cf6c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,11 +31,11 @@ jobs: env: COMPARE: 0 run: make -j${nproc} -O all - - - name: LTO + + - name: Release run: | make tidy - make -j${nproc} LTO=1 + make -j${nproc} release # make tidy to purge previous build - name: Test From cd0834237bbfbebb502e01a8072d54cd248c088a Mon Sep 17 00:00:00 2001 From: Kildemal <206095739+izrofid@users.noreply.github.com> Date: Wed, 31 Dec 2025 20:07:16 +0530 Subject: [PATCH 3/3] Add some missing tests for heatproof, thick fat and grudge (#8705) --- test/battle/ability/heatproof.c | 50 +++++- test/battle/ability/thick_fat.c | 37 ++++- test/battle/move_effect/grudge.c | 264 +++++++++++++++++++++++++++++-- 3 files changed, 340 insertions(+), 11 deletions(-) diff --git a/test/battle/ability/heatproof.c b/test/battle/ability/heatproof.c index 7f1d772bb7..154569fd2a 100644 --- a/test/battle/ability/heatproof.c +++ b/test/battle/ability/heatproof.c @@ -1,4 +1,52 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Heatproof (Ability) test titles") +ASSUMPTIONS +{ + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); +} + +SINGLE_BATTLE_TEST("Heatproof halves damage from fire type moves") +{ + s16 damage[2]; + GIVEN { + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_BRONZONG) { Ability(ABILITY_HEATPROOF); } + } + WHEN { + TURN { MOVE(player, MOVE_EMBER); } + TURN { MOVE(player, MOVE_WORRY_SEED); } + TURN { MOVE(player, MOVE_EMBER); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WORRY_SEED, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[1]); + EXPECT_MUL_EQ(damage[0], Q_4_12(2), damage[1]); + } +} + +SINGLE_BATTLE_TEST("Heatproof halves the damage done by burn from 1/8th to 1/16th (Gen1-6) or 1/16th to 1/32nd (Gen 7+)") +{ + u32 config, burnRate; + + PARAMETRIZE { config = GEN_7; burnRate = 32; } + PARAMETRIZE { config = GEN_6; burnRate = 16; } + + GIVEN { + WITH_CONFIG(CONFIG_BURN_DAMAGE, config); + PLAYER (SPECIES_BRONZONG) { Ability(ABILITY_HEATPROOF); Status1(STATUS1_BURN); } + OPPONENT (SPECIES_WOBBUFFET); + } + WHEN { + TURN {} + } + SCENE { + s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); + HP_BAR(player, damage: maxHP / burnRate); + } +} + diff --git a/test/battle/ability/thick_fat.c b/test/battle/ability/thick_fat.c index bcc4c9487c..ce13d12982 100644 --- a/test/battle/ability/thick_fat.c +++ b/test/battle/ability/thick_fat.c @@ -1,4 +1,39 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Thick Fat (Ability) test titles") +ASSUMPTIONS +{ + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_POWDER_SNOW) == TYPE_ICE); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_OVERWRITE_ABILITY); +} + +SINGLE_BATTLE_TEST("Thick Fat halves damage from fire and ice type moves", s16 damage[2]) +{ + u16 move; + + PARAMETRIZE { move = MOVE_POWDER_SNOW; } + PARAMETRIZE { move = MOVE_EMBER; } + + GIVEN { + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_SNORLAX) { Ability(ABILITY_THICK_FAT); } + } + WHEN { + TURN { MOVE(player, move); } + TURN { MOVE(player, MOVE_WORRY_SEED); } + TURN { MOVE(player, move); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &results[i].damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WORRY_SEED, player); + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent, captureDamage: &results[i].damage[1]); + } + FINALLY { + EXPECT_MUL_EQ(results[0].damage[0], Q_4_12(2), results[0].damage[1]); + EXPECT_MUL_EQ(results[1].damage[0], Q_4_12(2), results[1].damage[1]); + } +} + diff --git a/test/battle/move_effect/grudge.c b/test/battle/move_effect/grudge.c index 2b74a3b05a..9d381ad833 100644 --- a/test/battle/move_effect/grudge.c +++ b/test/battle/move_effect/grudge.c @@ -50,12 +50,258 @@ SINGLE_BATTLE_TEST("Grudge does not deplete PP of a Z-Move") } } -TO_DO_BATTLE_TEST("Grudge depletes all PP from a Max Move's base move") -TO_DO_BATTLE_TEST("Grudge does not activate for Struggle") -TO_DO_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Move"); -TO_DO_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Sleep"); -TO_DO_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Paralysis"); -TO_DO_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Flinching"); -TO_DO_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Sandstorm"); -TO_DO_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Leech Seed"); -TO_DO_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Future Sight"); +SINGLE_BATTLE_TEST("Grudge depletes all PP from a Max Move's base move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); Item(ITEM_LAGGING_TAIL); } + } WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_SCRATCH, gimmick: GIMMICK_DYNAMAX); SEND_OUT(player, 1); } + } SCENE { + MESSAGE("Wobbuffet used Grudge!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + MESSAGE("The opposing Wobbuffet used Max Strike!"); + MESSAGE("Wobbuffet fainted!"); + MESSAGE("The opposing Wobbuffet's Scratch lost all its PP due to the grudge!"); + } THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_EQ(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge does not activate for Struggle") +{ + GIVEN { + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_STRUGGLE, MOVE_POUND, MOVE_SURF); }; + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_STRUGGLE); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Struggle lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Move") +{ + GIVEN { + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_POUND, MOVE_SURF); }; + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_SCRATCH); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Scratch lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Sleep") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(gMovesInfo[SanitizeMoveId(MOVE_SPORE)].argument.nonVolatileStatus == MOVE_EFFECT_SLEEP); + PLAYER (SPECIES_WOBBUFFET) { HP(1);} + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_VITAL_THROW, MOVE_SPORE, MOVE_SURF); } + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_SPORE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_VITAL_THROW); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); + MESSAGE("Wobbuffet fell asleep!"); + STATUS_ICON(player, sleep: TRUE); + MESSAGE("Wobbuffet is fast asleep."); + ANIMATION(ANIM_TYPE_MOVE, MOVE_VITAL_THROW, opponent); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Scratch lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Paralysis") +{ + PASSES_RANDOMLY(25, 100, RNG_PARALYSIS); + GIVEN { + ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(gMovesInfo[SanitizeMoveId(MOVE_STUN_SPORE)].argument.nonVolatileStatus == MOVE_EFFECT_PARALYSIS); + ASSUME(GetMovePriority(MOVE_VITAL_THROW) == -1); + PLAYER (SPECIES_WOBBUFFET) { HP(1);} + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_VITAL_THROW, MOVE_STUN_SPORE, MOVE_SURF); };\ + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_STUN_SPORE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_VITAL_THROW); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, opponent); + MESSAGE("Wobbuffet is paralyzed, so it may be unable to move!"); + STATUS_ICON(player, paralysis: TRUE); + MESSAGE("Wobbuffet couldn't move because it's paralyzed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_VITAL_THROW, opponent); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Scratch lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect disappears if the user takes a new turn - Flinching") +{ + PASSES_RANDOMLY(10, 100, RNG_HOLD_EFFECT_FLINCH); + GIVEN { + ASSUME(GetMoveEffect(MOVE_FALSE_SWIPE) == EFFECT_FALSE_SWIPE); + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_FALSE_SWIPE, MOVE_SURF); Item(ITEM_KINGS_ROCK); } + } + WHEN { + TURN { SWITCH(opponent, 1); MOVE(player, MOVE_GRUDGE); } + TURN { MOVE(opponent, MOVE_FALSE_SWIPE); MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(opponent, MOVE_SCRATCH); MOVE(player, MOVE_CELEBRATE); SEND_OUT(player, 1); } + } + SCENE { + SEND_IN_MESSAGE("Wobbuffet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FALSE_SWIPE, opponent); + MESSAGE("Wobbuffet flinched and couldn't move!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Scratch lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Sandstorm") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_SANDSTORM, MOVE_SURF); } + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_SANDSTORM); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SANDSTORM, opponent); + MESSAGE("The sandstorm is raging."); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SANDSTORM_CONTINUES); + MESSAGE("Wobbuffet is buffeted by the sandstorm!"); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Sandstorm lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Leech Seed") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED); + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_LEECH_SEED, MOVE_SURF); } + } + WHEN { + TURN { MOVE(player, MOVE_GRUDGE); MOVE(opponent, MOVE_LEECH_SEED); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_LEECH_SEED, opponent); + MESSAGE("Wobbuffet was seeded!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, player); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Leech Seed lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} + +SINGLE_BATTLE_TEST("Grudge's effect doesn't trigger on indirect damage - Future Sight") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT); + PLAYER (SPECIES_WOBBUFFET) { HP(1); } + PLAYER (SPECIES_WOBBUFFET); + OPPONENT (SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_FUTURE_SIGHT, MOVE_SURF); } + } + WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN {} + TURN { MOVE(player, MOVE_GRUDGE); SEND_OUT(player, 1); } + } + SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("The opposing Wobbuffet foresaw an attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GRUDGE, player); + MESSAGE("Wobbuffet took the Future Sight attack!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FUTURE_SIGHT_HIT); + MESSAGE("Wobbuffet fainted!"); + NOT MESSAGE("The opposing Wobbuffet's Future Sight lost all its PP due to the grudge!"); + } + THEN { + EXPECT_GT(opponent->pp[0], 0); + EXPECT_GT(opponent->pp[1], 0); + EXPECT_GT(opponent->pp[2], 0); + EXPECT_GT(opponent->pp[3], 0); + } +} +