From ae2d5f7d1e2e9ed8d045c7cb3c48a91283116abb Mon Sep 17 00:00:00 2001 From: Shae <85393060+ShaeTsuPog@users.noreply.github.com> Date: Tue, 2 May 2023 11:08:05 -0700 Subject: [PATCH] Weather related Ability tests, fix for Leaf Guard not preventing Rest. (#2957) --- data/battle_scripts_1.s | 9 +++ include/config/battle.h | 1 + test/ability_dry_skin.c | 114 ++++++++++++++++++++++++++++++++++++ test/ability_hydration.c | 16 +++++ test/ability_ice_body.c | 30 ++++++++++ test/ability_leaf_guard.c | 95 ++++++++++++++++++++++++++++++ test/ability_rain_dish.c | 18 ++++++ test/ability_sand_veil.c | 4 +- test/ability_snow_cloak.c | 29 +++++++++ test/ability_water_absorb.c | 2 +- 10 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 test/ability_dry_skin.c create mode 100644 test/ability_hydration.c create mode 100644 test/ability_ice_body.c create mode 100644 test/ability_leaf_guard.c create mode 100644 test/ability_rain_dish.c create mode 100644 test/ability_snow_cloak.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 4f41d154e..575c88939 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3984,6 +3984,9 @@ BattleScript_EffectRest:: jumpifuproarwakes BattleScript_RestCantSleep jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_InsomniaProtects jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects +.if B_LEAF_GUARD_PREVENTS_REST >= GEN_5 + jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest +.endif trysetrest BattleScript_AlreadyAtFullHp pause B_WAIT_TIME_SHORT printfromtable gRestUsedStringIds @@ -4005,6 +4008,12 @@ BattleScript_RestIsAlreadyAsleep:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd +BattleScript_LeafGuardPreventsRest:: + pause B_WAIT_TIME_SHORT + printstring STRINGID_BUTITFAILED + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + BattleScript_EffectOHKO:: attackcanceler attackstring diff --git a/include/config/battle.h b/include/config/battle.h index da58c8bbf..6a6a829d6 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -120,6 +120,7 @@ #define B_SYMBIOSIS_GEMS GEN_LATEST // In Gen7+, Symbiosis passes an item after a gem-boosted attack. Previously, items are passed before the gem-boosted attack hits, making the item effect apply. #define B_CHECK_IF_CHARGED_UP TRUE // If set to TRUE, certain abilities such as Electromorphosis WILL check if the STATUS3_CHARGED_UP status flag is applied. #define B_ABSORBING_ABILITY_STRING GEN_LATEST // In Gen5+, the abilities that absorb moves of a certain type use a generic string for stat increases and decreases. +#define B_LEAF_GUARD_PREVENTS_REST GEN_LATEST // In Gen5+, Leaf Guard prevents the use of Rest in harsh sunlight. // Item settings #define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/test/ability_dry_skin.c b/test/ability_dry_skin.c new file mode 100644 index 000000000..6c28d0c42 --- /dev/null +++ b/test/ability_dry_skin.c @@ -0,0 +1,114 @@ +#include "global.h" +#include "test_battle.h" + +#define TEST_MAX_HP (200) + +SINGLE_BATTLE_TEST("Dry Skin causes 1/8th Max HP damage in Sun") +{ + GIVEN { + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player, damage: TEST_MAX_HP / 8); + MESSAGE("The Parasect's Dry Skin takes its toll!"); + } +} + +SINGLE_BATTLE_TEST("Dry Skin heals 1/8th Max HP in Rain") +{ + GIVEN { + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + MESSAGE("Parasect's Dry Skin restored its HP a little!"); + HP_BAR(player, hp: TEST_MAX_HP / 8 + 100); + } +} + +SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%", s16 damage) +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_EMBER].type == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); }; + } WHEN { + TURN {MOVE(player, MOVE_EMBER); } + } SCENE { + MESSAGE("Wobbuffet used Ember!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.25), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Dry Skin heals 25% when hit by water type moves") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_BUBBLE].type == TYPE_WATER); + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_BUBBLE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player, hp: TEST_MAX_HP / 4 + 100); + MESSAGE("Parasect restored HP using its Dry Skin!"); + } +} + +SINGLE_BATTLE_TEST("Dry Skin does not activate if protected") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_BUBBLE].type == TYPE_WATER); + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PROTECT); MOVE(opponent, MOVE_BUBBLE); } + } SCENE { + NONE_OF { ABILITY_POPUP(player, ABILITY_DRY_SKIN); HP_BAR(player); MESSAGE("Parasect restored HP using its Dry Skin!"); } + } +} + +SINGLE_BATTLE_TEST("Dry Skin is only triggered once on multi strike moves") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_WATER_SHURIKEN].type == TYPE_WATER); + ASSUME(gBattleMoves[MOVE_WATER_SHURIKEN].effect == EFFECT_MULTI_HIT); + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_WATER_SHURIKEN); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player, hp: TEST_MAX_HP / 4 + 100); + MESSAGE("Parasect restored HP using its Dry Skin!"); + } +} + +SINGLE_BATTLE_TEST("Dry Skin prevents Absorb Bulb and Luminous Moss from activating") +{ + u32 item; + PARAMETRIZE { item = ITEM_ABSORB_BULB; } + PARAMETRIZE { item = ITEM_LUMINOUS_MOSS; } + GIVEN { + ASSUME(gBattleMoves[MOVE_BUBBLE].type == TYPE_WATER); + PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(TEST_MAX_HP); Item(item); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_BUBBLE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DRY_SKIN); + HP_BAR(player, hp: TEST_MAX_HP / 4 + 100); + MESSAGE("Parasect restored HP using its Dry Skin!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } + } +} diff --git a/test/ability_hydration.c b/test/ability_hydration.c new file mode 100644 index 000000000..45689b212 --- /dev/null +++ b/test/ability_hydration.c @@ -0,0 +1,16 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Hydration cures non-volatile Status conditions if it is raining") +{ + GIVEN { + PLAYER(SPECIES_VAPOREON) { Ability(ABILITY_HYDRATION); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAIN_DANCE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_HYDRATION); + MESSAGE("Vaporeon's Hydration cured its burn problem!"); + STATUS_ICON(player, none: TRUE); + } +} diff --git a/test/ability_ice_body.c b/test/ability_ice_body.c new file mode 100644 index 000000000..b28c5ef0a --- /dev/null +++ b/test/ability_ice_body.c @@ -0,0 +1,30 @@ +#include "global.h" +#include "test_battle.h" + +#define TEST_MAX_HP (100) + +SINGLE_BATTLE_TEST("Ice Body prevents damage from hail") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GLALIE) { Ability(ABILITY_ICE_BODY); }; + } WHEN { + TURN { MOVE(player, MOVE_HAIL); MOVE(opponent, MOVE_SKILL_SWAP); } + } SCENE { + NONE_OF { HP_BAR(player); } + } +} + +SINGLE_BATTLE_TEST("Ice Body recovers 1/16th of Max HP in hail.") +{ + GIVEN { + PLAYER(SPECIES_GLALIE) { Ability(ABILITY_ICE_BODY); HP(1); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_HAIL); } + } SCENE { + ABILITY_POPUP(player, ABILITY_ICE_BODY); + MESSAGE("Glalie's Ice Body healed it a little bit!"); + HP_BAR(player, hp: TEST_MAX_HP / 16 + 1); + } +} diff --git a/test/ability_leaf_guard.c b/test/ability_leaf_guard.c new file mode 100644 index 000000000..a4c83c485 --- /dev/null +++ b/test/ability_leaf_guard.c @@ -0,0 +1,95 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Leaf Guard prevents non-volatile status conditions in sun") +{ + u32 move; + PARAMETRIZE { move = MOVE_WILL_O_WISP; } + PARAMETRIZE { move = MOVE_HYPNOSIS; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; } + PARAMETRIZE { move = MOVE_TOXIC; } + PARAMETRIZE { move = MOVE_POWDER_SNOW; } + GIVEN { + ASSUME(gBattleMoves[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); + ASSUME(gBattleMoves[MOVE_HYPNOSIS].effect == EFFECT_SLEEP); + ASSUME(gBattleMoves[MOVE_THUNDER_WAVE].effect == EFFECT_PARALYZE); + ASSUME(gBattleMoves[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(gBattleMoves[MOVE_POWDER_SNOW].effect == EFFECT_FREEZE_HIT); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, move); } + } SCENE { + switch (move) + { + case MOVE_WILL_O_WISP: + MESSAGE("Foe Wobbuffet used Will-o-Wisp!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_WILL_O_WISP, opponent); + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + break; + case MOVE_HYPNOSIS: + MESSAGE("Foe Wobbuffet used Hypnosis!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HYPNOSIS, opponent); + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + break; + case MOVE_THUNDER_WAVE: + MESSAGE("Foe Wobbuffet used Thunder Wave!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_WAVE, opponent); + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + break; + case MOVE_TOXIC: + MESSAGE("Foe Wobbuffet used Toxic!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, opponent); + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + break; + case MOVE_POWDER_SNOW: + MESSAGE("Foe Wobbuffet used Powder Snow!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER_SNOW, opponent); + MESSAGE("It's super effective!"); + break; + } + NONE_OF {STATUS_ICON(player, status1: TRUE);} + } +} + +SINGLE_BATTLE_TEST("Leaf Guard prevents status conditions from Flame Orb and Toxic Orb") +{ + u32 item; + PARAMETRIZE { item = ITEM_FLAME_ORB; } + PARAMETRIZE { item = ITEM_TOXIC_ORB; } + GIVEN { + ASSUME(gItems[ITEM_FLAME_ORB].holdEffect == HOLD_EFFECT_FLAME_ORB); + ASSUME(gItems[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB); + PLAYER(SPECIES_LEAFEON) {Ability(ABILITY_LEAF_GUARD); Item(item); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + if (item == ITEM_FLAME_ORB) { + NONE_OF { MESSAGE("Leafeon was burned!"); STATUS_ICON(player, burn: TRUE);} + } + else { + NONE_OF { MESSAGE("Leafeon is badly poisoned!"); STATUS_ICON(player, poison: TRUE);} + } + } +} + +SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun") +{ + GIVEN { + ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); + ASSUME(gBattleMoves[MOVE_REST].effect == EFFECT_REST); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } + } SCENE { + MESSAGE("But it failed!"); + NOT STATUS_ICON(player, sleep: TRUE); + NONE_OF {HP_BAR(player);} + } +} diff --git a/test/ability_rain_dish.c b/test/ability_rain_dish.c new file mode 100644 index 000000000..f9a457d4a --- /dev/null +++ b/test/ability_rain_dish.c @@ -0,0 +1,18 @@ +#include "global.h" +#include "test_battle.h" + +#define TEST_MAX_HP (100) + +SINGLE_BATTLE_TEST("Rain Dish recovers 1/16th of Max HP in Rain") +{ + GIVEN { + PLAYER(SPECIES_LUDICOLO) { Ability(ABILITY_RAIN_DISH); HP(1); MaxHP(TEST_MAX_HP); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_RAIN_DANCE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_RAIN_DISH); + MESSAGE("Ludicolo's Rain Dish restored its HP a little!"); + HP_BAR(player, hp: TEST_MAX_HP / 16 + 1); + } +} diff --git a/test/ability_sand_veil.c b/test/ability_sand_veil.c index 5514f27c0..ec7c17f8e 100644 --- a/test/ability_sand_veil.c +++ b/test/ability_sand_veil.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Sand Veil prevents damage from sandstorm") { GIVEN { - PLAYER(SPECIES_SANDSHREW) { Ability(ABILITY_SAND_VEIL); }; + PLAYER(SPECIES_CACNEA) { Ability(ABILITY_SAND_VEIL); }; OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_SANDSTORM); } @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Sand Veil prevents damage from sandstorm") } } -SINGLE_BATTLE_TEST("Sand Veil reduces accuracy during sandstorm") +SINGLE_BATTLE_TEST("Sand Veil increases evasion during sandstorm") { PASSES_RANDOMLY(4, 5, RNG_ACCURACY); GIVEN { diff --git a/test/ability_snow_cloak.c b/test/ability_snow_cloak.c new file mode 100644 index 000000000..1f47eb94b --- /dev/null +++ b/test/ability_snow_cloak.c @@ -0,0 +1,29 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Snow Cloak prevents damage from hail") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GLACEON) { Ability(ABILITY_SNOW_CLOAK); }; + } WHEN { + TURN { MOVE(player, MOVE_HAIL); MOVE(opponent, MOVE_SKILL_SWAP); } + } SCENE { + NONE_OF { HP_BAR(player); } + } +} + +SINGLE_BATTLE_TEST("Snow Cloak increases evasion during hail") +{ + PASSES_RANDOMLY(4, 5, RNG_ACCURACY); + GIVEN { + ASSUME(gBattleMoves[MOVE_POUND].accuracy == 100); + PLAYER(SPECIES_GLACEON) { Ability(ABILITY_SNOW_CLOAK); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_HAIL); } + TURN { MOVE(opponent, MOVE_POUND); } + } SCENE { + HP_BAR(player); + } +} diff --git a/test/ability_water_absorb.c b/test/ability_water_absorb.c index aaaa149ac..7d6274836 100644 --- a/test/ability_water_absorb.c +++ b/test/ability_water_absorb.c @@ -63,7 +63,7 @@ SINGLE_BATTLE_TEST("Water Absorb is only triggered once on multi strike moves") } } -SINGLE_BATTLE_TEST("Water Absorb prevents Items from activating") +SINGLE_BATTLE_TEST("Water Absorb prevents Absorb Bulb and Luminous Moss from activating") { u32 item; PARAMETRIZE { item = ITEM_ABSORB_BULB; }