diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h index 88584e9978..381c77ca13 100644 --- a/include/constants/generational_changes.h +++ b/include/constants/generational_changes.h @@ -47,6 +47,7 @@ enum GenConfigTag GEN_CONFIG_TOXIC_NEVER_MISS, GEN_CONFIG_PARALYZE_ELECTRIC, GEN_CONFIG_BADGE_BOOST, + GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, GEN_CONFIG_COUNT }; diff --git a/include/generational_changes.h b/include/generational_changes.h index e8b701d096..0068d74428 100644 --- a/include/generational_changes.h +++ b/include/generational_changes.h @@ -49,7 +49,8 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] = [GEN_CONFIG_OBLIVIOUS_TAUNT] = B_OBLIVIOUS_TAUNT, [GEN_CONFIG_TOXIC_NEVER_MISS] = B_TOXIC_NEVER_MISS, [GEN_CONFIG_PARALYZE_ELECTRIC] = B_PARALYZE_ELECTRIC, - [GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST + [GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST, + [GEN_CONFIG_LEAF_GUARD_PREVENTS_REST] = B_LEAF_GUARD_PREVENTS_REST, }; #if TESTING diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a98e023ff6..8674d34e2d 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -18279,7 +18279,7 @@ void BS_JumpIfAbilityPreventsRest(void) NATIVE_ARGS(u8 battler, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); u32 ability = GetBattlerAbility(battler); - if (B_LEAF_GUARD_PREVENTS_REST >= GEN_5 && IsLeafGuardProtected(battler, ability)) + if (GetGenConfig(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST) >= GEN_5 && IsLeafGuardProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; else if (IsShieldsDownProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; diff --git a/test/battle/ability/bad_dreams.c b/test/battle/ability/bad_dreams.c index 491d5a91a2..cb724e2411 100644 --- a/test/battle/ability/bad_dreams.c +++ b/test/battle/ability/bad_dreams.c @@ -35,7 +35,21 @@ SINGLE_BATTLE_TEST("Bad Dreams causes the sleeping enemy Pokemon to lose 1/8 of } } -TO_DO_BATTLE_TEST("Bad Dreams affects Pokémon with Comatose") +SINGLE_BATTLE_TEST("Bad Dreams causes Pokémon with Comatose to lose 1/8 of HP") +{ + GIVEN { + PLAYER(SPECIES_DARKRAI); + OPPONENT(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); } + } WHEN { + TURN {;} + } SCENE { + ABILITY_POPUP(player, ABILITY_BAD_DREAMS); + MESSAGE("The opposing Komala is tormented!"); + HP_BAR(opponent); + } THEN { + EXPECT_EQ(opponent->hp, opponent->maxHP - opponent->maxHP / 8); + } +} DOUBLE_BATTLE_TEST("Bad Dreams does not activate if only the partner Pokemon is sleeping") { diff --git a/test/battle/ability/leaf_guard.c b/test/battle/ability/leaf_guard.c index 94785bd29b..182f07787b 100644 --- a/test/battle/ability/leaf_guard.c +++ b/test/battle/ability/leaf_guard.c @@ -31,7 +31,41 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents non-volatile status conditions in sun") } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent non-volatile status conditions if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent non-volatile status conditions if Cloud Nine/Air Lock is on the field") +{ + u32 move, species, ability; + u16 status; + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + // PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } // Pointless since you can't freeze in sunlight anyway + GIVEN { + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_WILL_O_WISP) == MOVE_EFFECT_BURN); + ASSUME(GetMoveEffect(MOVE_HYPNOSIS) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_HYPNOSIS) == MOVE_EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_THUNDER_WAVE) == MOVE_EFFECT_PARALYSIS); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_TOXIC) == MOVE_EFFECT_TOXIC); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + NONE_OF { + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + } + STATUS_ICON(player, status); + } +} SINGLE_BATTLE_TEST("Leaf Guard prevents status conditions from Flame Orb and Toxic Orb") { @@ -50,29 +84,82 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents status conditions from Flame Orb and Tox NONE_OF { MESSAGE("Leafeon was burned!"); STATUS_ICON(player, burn: TRUE); } } else { - NONE_OF { MESSAGE("Leafeon was badly poisoned!"); STATUS_ICON(player, poison: TRUE); } + NONE_OF { MESSAGE("Leafeon was badly poisoned!"); STATUS_ICON(player, badPoison: TRUE); } } } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent status conditions from Flame Orb and Toxic Orb if Cloud Nine/Air Lock is on the field"); - -SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun") +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent status conditions from Flame Orb and Toxic Orb if Cloud Nine/Air Lock is on the field") { + u32 item, species, ability; + PARAMETRIZE { item = ITEM_FLAME_ORB; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { item = ITEM_TOXIC_ORB; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { item = ITEM_FLAME_ORB; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { item = ITEM_TOXIC_ORB; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { - ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); + ASSUME(gItemsInfo[ITEM_FLAME_ORB].holdEffect == HOLD_EFFECT_FLAME_ORB); + ASSUME(gItemsInfo[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); Item(item); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + if (item == ITEM_FLAME_ORB) { + MESSAGE("Leafeon was burned!"); + STATUS_ICON(player, burn: TRUE); + } + else { + MESSAGE("Leafeon was badly poisoned!"); + STATUS_ICON(player, badPoison: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun (Gen 5+)") +{ + u32 gen; + PARAMETRIZE { gen = GEN_4; } + PARAMETRIZE { gen = GEN_5; } + GIVEN { + WITH_CONFIG(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, gen); ASSUME(GetMoveEffect(MOVE_REST) == 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!"); - NONE_OF { + if (gen >= GEN_5) { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + STATUS_ICON(player, sleep: TRUE); + HP_BAR(player); + } + } + else { STATUS_ICON(player, sleep: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); HP_BAR(player); } } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent Rest if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent Rest if Cloud Nine/Air Lock is on the field") +{ + u32 species, ability; + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + GIVEN { + WITH_CONFIG(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, GEN_5); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } + } SCENE { + STATUS_ICON(player, sleep: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + HP_BAR(player); + } +} diff --git a/test/battle/move_effect/brine.c b/test/battle/move_effect/brine.c index 9165257859..5f1504437d 100644 --- a/test/battle/move_effect/brine.c +++ b/test/battle/move_effect/brine.c @@ -1,4 +1,25 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Brine's power doubles if the target is at 50% or below max HP"); +SINGLE_BATTLE_TEST("Brine's power doubles if the target is at 50% or below max HP", s16 damage) +{ + bool32 halfHP; + PARAMETRIZE { halfHP = FALSE; } + PARAMETRIZE { halfHP = TRUE; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_BRINE) == EFFECT_BRINE); + PLAYER(SPECIES_SQUIRTLE); + OPPONENT(SPECIES_BLISSEY){ + if (halfHP) { + HP((GetMonData(&OPPONENT_PARTY[0], MON_DATA_MAX_HP) / 2) - 1); + } + } + } WHEN { + TURN { MOVE(player, MOVE_BRINE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BRINE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} diff --git a/test/battle/move_effect/rest.c b/test/battle/move_effect/rest.c index fcf2b15567..af1fb19c8c 100644 --- a/test/battle/move_effect/rest.c +++ b/test/battle/move_effect/rest.c @@ -35,22 +35,6 @@ SINGLE_BATTLE_TEST("Rest fails if the user is at full HP") } } -SINGLE_BATTLE_TEST("Rest fails if the user is protected by Leaf Guard") -{ - GIVEN { - ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); - ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); - PLAYER(SPECIES_CHIKORITA) { Ability(ABILITY_LEAF_GUARD); HP(1); } - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } - } SCENE { - NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); - } THEN { - EXPECT(!(player->status1 & STATUS1_SLEEP)); - } -} - SINGLE_BATTLE_TEST("Rest fails if the user is protected by Shields Down") { GIVEN { diff --git a/test/battle/move_effect/return.c b/test/battle/move_effect/return.c index 2a2614200d..2727b1b46e 100644 --- a/test/battle/move_effect/return.c +++ b/test/battle/move_effect/return.c @@ -1,6 +1,46 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Return's power increases the higher friendship of the user is") +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_RETURN) == EFFECT_RETURN); +} + +SINGLE_BATTLE_TEST("Return's power increases the higher friendship of the user is", s16 damage) +{ + u32 friendship; + PARAMETRIZE { friendship = 0; } + PARAMETRIZE { friendship = 100; } + PARAMETRIZE { friendship = 200; } + PARAMETRIZE { friendship = 255; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Friendship(friendship); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RETURN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RETURN, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } THEN { + if (i > 0) + EXPECT_GT(results[i].damage, results[i-1].damage); + } +} + TO_DO_BATTLE_TEST("Return does 0 damage at min Friendship (Gen2)") -TO_DO_BATTLE_TEST("Return does 1 damage at min Friendship (Gen3+)") + +SINGLE_BATTLE_TEST("Return does 1 damage at min Friendship (Gen3+)") +{ + s16 damage; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Friendship(0); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RETURN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RETURN, player); + HP_BAR(opponent, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, 1); + } +}