diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 438159350..57df1b4a2 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3853,6 +3853,7 @@ BattleScript_EffectRest:: jumpifuproarwakes BattleScript_RestCantSleep jumpifability BS_TARGET, ABILITY_INSOMNIA, BattleScript_InsomniaProtects jumpifability BS_TARGET, ABILITY_VITAL_SPIRIT, BattleScript_InsomniaProtects + jumpifability BS_ATTACKER, ABILITY_PURIFYING_SALT, BattleScript_InsomniaProtects .if B_LEAF_GUARD_PREVENTS_REST >= GEN_5 jumpifleafguardprotected BS_TARGET, BattleScript_LeafGuardPreventsRest .endif diff --git a/include/random.h b/include/random.h index db1dea398..af3d7c75e 100644 --- a/include/random.h +++ b/include/random.h @@ -92,6 +92,7 @@ enum RandomTag RNG_TRI_ATTACK, RNG_TRIPLE_ARROWS_DEFENSE_DOWN, RNG_TRIPLE_ARROWS_FLINCH, + RNG_QUICK_DRAW, }; #define RandomWeighted(tag, ...) \ diff --git a/src/battle_main.c b/src/battle_main.c index 8461873f0..0e8812395 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4745,7 +4745,7 @@ u32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov // Battler 1 // Quick Draw - if (!ignoreChosenMoves && ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && Random() % 100 < 30) + if (!ignoreChosenMoves && ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && RandomPercentage(RNG_QUICK_DRAW, 30)) gProtectStructs[battler1].quickDraw = TRUE; // Quick Claw and Custap Berry if (!gProtectStructs[battler1].quickDraw @@ -4755,7 +4755,7 @@ u32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov // Battler 2 // Quick Draw - if (!ignoreChosenMoves && ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && Random() % 100 < 30) + if (!ignoreChosenMoves && ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && RandomPercentage(RNG_QUICK_DRAW, 30)) gProtectStructs[battler2].quickDraw = TRUE; // Quick Claw and Custap Berry if (!gProtectStructs[battler2].quickDraw diff --git a/test/battle/ability/beast_boost.c b/test/battle/ability/beast_boost.c new file mode 100644 index 000000000..da63bf9c4 --- /dev/null +++ b/test/battle/ability/beast_boost.c @@ -0,0 +1,43 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_7_POKEMON == TRUE); // Because only Ultra Beasts have this ability +} + +SINGLE_BATTLE_TEST("Beast Boost boosts the most proficient stat when knocking out a target") +{ + u8 stats[] = {1, 1, 1, 1, 1}; + PARAMETRIZE { stats[0] = 255; } + PARAMETRIZE { stats[1] = 255; } + PARAMETRIZE { stats[2] = 255; } + PARAMETRIZE { stats[3] = 255; } + PARAMETRIZE { stats[4] = 255; } + GIVEN { + PLAYER(SPECIES_NIHILEGO) { Ability(ABILITY_BEAST_BOOST); Attack(stats[0]); Defense(stats[1]); SpAttack(stats[2]); SpDefense(stats[3]); Speed(stats[4]); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); SEND_OUT(opponent, 1); } + } SCENE { + ABILITY_POPUP(player, ABILITY_BEAST_BOOST); + switch(i) { + case 0: + MESSAGE("Nihilego's Beast Boost raised its Attack!"); + break; + case 1: + MESSAGE("Nihilego's Beast Boost raised its Defense!"); + break; + case 2: + MESSAGE("Nihilego's Beast Boost raised its Sp. Atk!"); + break; + case 3: + MESSAGE("Nihilego's Beast Boost raised its Sp. Def!"); + break; + case 4: + MESSAGE("Nihilego's Beast Boost raised its Speed!"); + break; + } + } +} diff --git a/test/battle/ability/ice_scales.c b/test/battle/ability/ice_scales.c new file mode 100644 index 000000000..2bbe7dab0 --- /dev/null +++ b/test/battle/ability/ice_scales.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_8_POKEMON == TRUE); // Because only Frosmoth can have this ability. +} + +SINGLE_BATTLE_TEST("Ice Scales halves the damage from special moves", s16 damage) +{ + u32 move; + u16 ability; + PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_PSYCHIC; } + PARAMETRIZE { ability = ABILITY_ICE_SCALES; move = MOVE_PSYCHIC; } + PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_PSYSHOCK; } + PARAMETRIZE { ability = ABILITY_ICE_SCALES; move = MOVE_PSYSHOCK; } + PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_TACKLE; } + PARAMETRIZE { ability = ABILITY_ICE_SCALES; move = MOVE_TACKLE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_PSYCHIC].split == SPLIT_SPECIAL); + ASSUME(gBattleMoves[MOVE_PSYSHOCK].split == SPLIT_SPECIAL); + ASSUME(gBattleMoves[MOVE_PSYSHOCK].effect == EFFECT_PSYSHOCK); + ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_FROSMOTH) { Ability(ability); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage); // Ice Scales halves the damage of Psychic + EXPECT_MUL_EQ(results[2].damage, UQ_4_12(0.5), results[3].damage); // Ice Scales halves the damage of Psyshock, even if it targets Defense + EXPECT_EQ(results[4].damage, results[5].damage); // Ice Scales doesn't affect the damage of physical moves + } +} diff --git a/test/battle/ability/leaf_guard.c b/test/battle/ability/leaf_guard.c index 2c052b5a6..66eb6fc18 100644 --- a/test/battle/ability/leaf_guard.c +++ b/test/battle/ability/leaf_guard.c @@ -4,11 +4,12 @@ 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; } + u16 status; + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; } + PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } GIVEN { ASSUME(gBattleMoves[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); ASSUME(gBattleMoves[MOVE_HYPNOSIS].effect == EFFECT_SLEEP); @@ -20,39 +21,14 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents non-volatile status conditions in sun") } 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; + if (move != MOVE_POWDER_SNOW) { + NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + } else { + NOT ABILITY_POPUP(player, ABILITY_LEAF_GUARD); } - NONE_OF { STATUS_ICON(player, status1: TRUE); } + NOT STATUS_ICON(player, status); } } diff --git a/test/battle/ability/neuroforce.c b/test/battle/ability/neuroforce.c new file mode 100644 index 000000000..df15bd451 --- /dev/null +++ b/test/battle/ability/neuroforce.c @@ -0,0 +1,30 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_7_POKEMON == TRUE); // Because only Necrozma can have this ability. +} + +SINGLE_BATTLE_TEST("Neuroforce increases the strength of super-effective moves by 25%", s16 damage) +{ + u32 move; + u16 ability; + PARAMETRIZE { ability = ABILITY_NEUROFORCE; move = MOVE_SHADOW_BALL; } + PARAMETRIZE { ability = ABILITY_KLUTZ; move = MOVE_SHADOW_BALL; } + PARAMETRIZE { ability = ABILITY_NEUROFORCE; move = MOVE_TACKLE; } + PARAMETRIZE { ability = ABILITY_KLUTZ; move = MOVE_TACKLE; } + GIVEN { + ASSUME(gBattleMoves[MOVE_SHADOW_BALL].type == TYPE_GHOST); + ASSUME(gBattleMoves[MOVE_TACKLE].type == TYPE_NORMAL); + PLAYER(SPECIES_NECROZMA_ULTRA) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, UQ_4_12(1.25), results[0].damage); // Neuroforce boosts the power of super-effective moves + EXPECT_EQ(results[2].damage, results[3].damage); // Neuroforce doesn't boost the power of other moves + } +} diff --git a/test/battle/ability/purifying_salt.c b/test/battle/ability/purifying_salt.c new file mode 100644 index 000000000..0a53dbc61 --- /dev/null +++ b/test/battle/ability/purifying_salt.c @@ -0,0 +1,65 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Purifying Salt halves damage from Ghost-type moves", s16 damage) +{ + u16 ability; + PARAMETRIZE { ability = ABILITY_STURDY; } + PARAMETRIZE { ability = ABILITY_PURIFYING_SALT; } + GIVEN { + ASSUME(gBattleMoves[MOVE_SHADOW_BALL].type == TYPE_GHOST); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SHADOW_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Purifying Salt makes Rest fail") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_PURIFYING_SALT); HP(1); MaxHP(100);} + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REST); } + } SCENE { + NONE_OF { + MESSAGE("Wobbuffet went to sleep!"); + } + } +} + +SINGLE_BATTLE_TEST("Purifying Salt grants immunity to status effects") +{ + u32 move; + u16 status; + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; } + PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } + 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_WOBBUFFET) { Ability(ABILITY_PURIFYING_SALT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + if (move != MOVE_POWDER_SNOW) { + NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); + ABILITY_POPUP(player, ABILITY_PURIFYING_SALT); + MESSAGE("It doesn't affect Wobbuffet…"); + } else { + NOT ABILITY_POPUP(player, ABILITY_PURIFYING_SALT); + } + NOT STATUS_ICON(player, status); + } +} diff --git a/test/battle/ability/quick_draw.c b/test/battle/ability/quick_draw.c new file mode 100644 index 000000000..7dd918e5d --- /dev/null +++ b/test/battle/ability/quick_draw.c @@ -0,0 +1,17 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Quick Draw has a 30% chance of going first") +{ + PASSES_RANDOMLY(3, 10, RNG_QUICK_DRAW); + GIVEN { + PLAYER(SPECIES_SLOWBRO_GALARIAN) { Ability(ABILITY_QUICK_DRAW); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_QUICK_DRAW); + MESSAGE("Slowbro used Tackle!"); + MESSAGE("Foe Wobbuffet used Celebrate!"); + } +} diff --git a/test/battle/ability/sharpness.c b/test/battle/ability/sharpness.c new file mode 100644 index 000000000..6360c4f8b --- /dev/null +++ b/test/battle/ability/sharpness.c @@ -0,0 +1,29 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(P_GEN_4_POKEMON == TRUE); // Because no