From 609754f0f654b1881214fb65fafce390560049d3 Mon Sep 17 00:00:00 2001 From: sneed <56992013+Sneed69@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:13:44 +0300 Subject: [PATCH] Add RandomChance macro and ability trigger chance config (#4829) * RandomChance macro, contact ability chance config * Unify config, add shed skin --- include/config/battle.h | 3 + include/random.h | 11 +++- src/battle_script_commands.c | 2 +- src/battle_util.c | 101 +++++++++++++++++------------ test/battle/ability/cute_charm.c | 19 ++++++ test/battle/ability/effect_spore.c | 90 +++++++++++++++++++++++++ test/battle/ability/flame_body.c | 18 +++++ test/battle/ability/poison_point.c | 19 ++++++ test/battle/ability/shed_skin.c | 19 ++++++ test/battle/ability/static.c | 18 +++++ test/battle/crit_chance.c | 36 +++++----- 11 files changed, 274 insertions(+), 62 deletions(-) create mode 100644 test/battle/ability/effect_spore.c create mode 100644 test/battle/ability/shed_skin.c diff --git a/include/config/battle.h b/include/config/battle.h index 1af7e0c68a..113c1201b6 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -147,6 +147,9 @@ #define B_INTREPID_SWORD GEN_LATEST // In Gen9+, Intrepid Sword raises Attack by one stage only once per Battle. #define B_DAUNTLESS_SHIELD GEN_LATEST // In Gen9+, Dauntless Shield raises Defense by one stage only once per Battle. #define B_DISGUISE_HP_LOSS GEN_LATEST // In Gen8+, when a Disguised Mimikyu's Disguise is busted, upon changing to its Busted Form it loses HP equal to 1/8 of its maximum HP. +#define B_ABILITY_TRIGGER_CHANCE GEN_LATEST // In Gen3, Shed Skin, Cute Charm, Flame Body, Static and Poison Point have a 1/3 chance to trigger. In Gen 4+ it's 30%. + // In Gen3, Effect Spore has a 10% chance to sleep, poison or paralyze, with an equal chance. + // In Gen4, it's 30%. In Gen5+ it has 11% to sleep, 9% chance to poison and 10% chance to paralyze. // 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/include/random.h b/include/random.h index 709f28cb9e..3aeb1879d8 100644 --- a/include/random.h +++ b/include/random.h @@ -144,13 +144,16 @@ static inline void Shuffle(void *data, size_t n, size_t size) * probability. The array must be known at compile-time (e.g. a global * const array). * - * RandomPercentage(tag, t) returns FALSE with probability (1-t)/100, + * RandomPercentage(tag, t) returns FALSE with probability 1-t/100, * and TRUE with probability t/100. * * RandomWeighted(tag, w0, w1, ... wN) returns a number from 0 to N * inclusive. The return value is proportional to the weights, e.g. * RandomWeighted(..., 1, 1) returns 50% 0s and 50% 1s. - * RandomWeighted(..., 2, 1) returns 2/3 0s and 1/3 1s. */ + * RandomWeighted(..., 2, 1) returns 2/3 0s and 1/3 1s. + * + * RandomChance(tag, successes, total) returns FALSE with probability + * 1-successes/total, and TRUE with probability successes/total. */ enum RandomTag { @@ -161,6 +164,7 @@ enum RandomTag RNG_CUTE_CHARM, RNG_DAMAGE_MODIFIER, RNG_DIRE_CLAW, + RNG_EFFECT_SPORE, RNG_FLAME_BODY, RNG_FORCE_RANDOM_SWITCH, RNG_FROZEN, @@ -179,6 +183,7 @@ enum RandomTag RNG_SECONDARY_EFFECT, RNG_SECONDARY_EFFECT_2, RNG_SECONDARY_EFFECT_3, + RNG_SHED_SKIN, RNG_SLEEP_TURNS, RNG_SPEED_TIE, RNG_STATIC, @@ -202,6 +207,8 @@ enum RandomTag RandomWeightedArray(tag, sum, ARRAY_COUNT(weights), weights); \ }) +#define RandomChance(tag, successes, total) (RandomWeighted(tag, total - successes, successes)) + #define RandomPercentage(tag, t) \ ({ \ u32 r; \ diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index a0de481b27..ef2dda5da6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1943,7 +1943,7 @@ static void Cmd_critcalc(void) else if (critChance == -2) gIsCriticalHit = TRUE; else - gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitOdds[critChance] - 1, 1); + gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, sCriticalHitOdds[critChance]); // Counter for EVO_CRITICAL_HITS. partySlot = gBattlerPartyIndexes[gBattlerAttacker]; diff --git a/src/battle_util.c b/src/battle_util.c index 9fc6e9fe5f..1ff9f7b18f 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4861,7 +4861,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_SHED_SKIN: - if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0) + if ((gBattleMons[battler].status1 & STATUS1_ANY) + && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_SHED_SKIN, 30) : RandomChance(RNG_SHED_SKIN, 1, 3))) { ABILITY_HEAL_MON_STATUS: if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON)) @@ -5502,24 +5503,38 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_EFFECT_SPORE: - if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS) + if ((!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS) || B_POWDER_GRASS < GEN_6) && GetBattlerAbility(gBattlerAttacker) != ABILITY_OVERCOAT && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) { - i = Random() % 3; - if (i == 0) + u32 poison, paralysis, sleep; + + if (B_ABILITY_TRIGGER_CHANCE >= GEN_5) + { + poison = 9; + paralysis = 19; + } + else + { + poison = 10; + paralysis = 20; + } + sleep = 30; + + i = RandomUniform(RNG_EFFECT_SPORE, 0, B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? 99 : 299); + if (i < poison) goto POISON_POINT; - if (i == 1) + if (i < paralysis) goto STATIC; // Sleep - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + if (i < sleep + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED && CanSleep(gBattlerAttacker) && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) - && (Random() % 3) == 0) + && IsMoveMakingContact(move, gBattlerAttacker)) { gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_SLEEP; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); @@ -5530,42 +5545,46 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } } break; - POISON_POINT: case ABILITY_POISON_POINT: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && IsBattlerAlive(gBattlerAttacker) - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && CanBePoisoned(gBattlerTarget, gBattlerAttacker) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) - && RandomWeighted(RNG_POISON_POINT, 2, 1)) + if (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_POISON_POINT, 30) : RandomChance(RNG_POISON_POINT, 1, 3)) { - gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; - PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; - effect++; + POISON_POINT: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && IsBattlerAlive(gBattlerAttacker) + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && CanBePoisoned(gBattlerTarget, gBattlerAttacker) + && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS + && IsMoveMakingContact(move, gBattlerAttacker)) + { + gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON; + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; + gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; + effect++; + } } break; - STATIC: case ABILITY_STATIC: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && IsBattlerAlive(gBattlerAttacker) - && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && TARGET_TURN_DAMAGED - && CanBeParalyzed(gBattlerAttacker) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS - && IsMoveMakingContact(move, gBattlerAttacker) - && RandomWeighted(RNG_STATIC, 2, 1)) + if (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_STATIC, 30) : RandomChance(RNG_STATIC, 1, 3)) { - gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; - PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; - gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; - effect++; + STATIC: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && IsBattlerAlive(gBattlerAttacker) + && !gProtectStructs[gBattlerAttacker].confusionSelfDmg + && TARGET_TURN_DAMAGED + && CanBeParalyzed(gBattlerAttacker) + && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS + && IsMoveMakingContact(move, gBattlerAttacker)) + { + gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS; + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; + gHitMarker |= HITMARKER_STATUS_ABILITY_EFFECT; + effect++; + } } break; case ABILITY_FLAME_BODY: @@ -5576,7 +5595,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && (IsMoveMakingContact(move, gBattlerAttacker)) && TARGET_TURN_DAMAGED && CanBeBurned(gBattlerAttacker) - && RandomWeighted(RNG_FLAME_BODY, 2, 1)) + && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_FLAME_BODY, 30) : RandomChance(RNG_FLAME_BODY, 1, 3))) { gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); @@ -5592,7 +5611,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED && IsBattlerAlive(gBattlerTarget) - && RandomWeighted(RNG_CUTE_CHARM, 2, 1) + && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_CUTE_CHARM, 30) : RandomChance(RNG_CUTE_CHARM, 1, 3)) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) && AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget) && GetBattlerAbility(gBattlerAttacker) != ABILITY_OBLIVIOUS @@ -5826,7 +5845,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerTarget) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && RandomWeighted(RNG_STENCH, 9, 1) + && RandomChance(RNG_STENCH, 1, 10) && TARGET_TURN_DAMAGED && !MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_FLINCH)) { diff --git a/test/battle/ability/cute_charm.c b/test/battle/ability/cute_charm.c index af9815e750..06eb4cf842 100644 --- a/test/battle/ability/cute_charm.c +++ b/test/battle/ability/cute_charm.c @@ -45,3 +45,22 @@ SINGLE_BATTLE_TEST("Cute Charm cannot infatuate same gender") ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); } } + +SINGLE_BATTLE_TEST("Cute Charm triggers 30% of the time") +{ + PASSES_RANDOMLY(3, 10, RNG_CUTE_CHARM); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); } + OPPONENT(SPECIES_CLEFAIRY) { Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_CUTE_CHARM); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_INFATUATION, player); + MESSAGE("Foe Clefairy's Cute Charm infatuated Wobbuffet!"); + MESSAGE("Wobbuffet is in love with Foe Clefairy!"); + } +} diff --git a/test/battle/ability/effect_spore.c b/test/battle/ability/effect_spore.c new file mode 100644 index 0000000000..107cd08675 --- /dev/null +++ b/test/battle/ability/effect_spore.c @@ -0,0 +1,90 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Effect Spore only inflicts status on contact") +{ + u32 move; + + PARAMETRIZE { move = MOVE_TACKLE; } + PARAMETRIZE { move = MOVE_SWIFT; } + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } + } WHEN { + TURN { MOVE(player, move, WITH_RNG(RNG_EFFECT_SPORE, 1)); } + TURN {} + } SCENE { + if (gMovesInfo[move].makesContact) { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + MESSAGE("Wobbuffet was poisoned by Foe Breloom's Effect Spore!"); + STATUS_ICON(player, poison: TRUE); + } else { + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + MESSAGE("Wobbuffet was poisoned by Foe Breloom's Effect Spore!"); + STATUS_ICON(player, poison: TRUE); + } + } + } +} + +SINGLE_BATTLE_TEST("Effect Spore causes poison 9% of the time") +{ + PASSES_RANDOMLY(9, 100, RNG_EFFECT_SPORE); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN {} + } SCENE { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + MESSAGE("Wobbuffet was poisoned by Foe Breloom's Effect Spore!"); + STATUS_ICON(player, poison: TRUE); + } +} + +SINGLE_BATTLE_TEST("Effect Spore causes paralysis 10% of the time") +{ + PASSES_RANDOMLY(10, 100, RNG_EFFECT_SPORE); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN {} + } SCENE { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, player); + MESSAGE("Foe Breloom's Effect Spore paralyzed Wobbuffet! It may be unable to move!"); + STATUS_ICON(player, paralysis: TRUE); + } +} + +SINGLE_BATTLE_TEST("Effect Spore causes sleep 11% of the time") +{ + PASSES_RANDOMLY(11, 100, RNG_EFFECT_SPORE); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN {} + } SCENE { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); + MESSAGE("Foe Breloom's Effect Spore made Wobbuffet sleep!"); + STATUS_ICON(player, sleep: TRUE); + } +} diff --git a/test/battle/ability/flame_body.c b/test/battle/ability/flame_body.c index 84d2cd48f2..f44fb91724 100644 --- a/test/battle/ability/flame_body.c +++ b/test/battle/ability/flame_body.c @@ -29,3 +29,21 @@ SINGLE_BATTLE_TEST("Flame Body inflicts burn on contact") } } } + +SINGLE_BATTLE_TEST("Flame Body triggers 30% of the time") +{ + PASSES_RANDOMLY(3, 10, RNG_FLAME_BODY); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_MAGMAR) { Ability(ABILITY_FLAME_BODY); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_FLAME_BODY); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, player); + MESSAGE("Foe Magmar's Flame Body burned Wobbuffet!"); + STATUS_ICON(player, burn: TRUE); + } +} diff --git a/test/battle/ability/poison_point.c b/test/battle/ability/poison_point.c index bd713fa2fc..26c9c72968 100644 --- a/test/battle/ability/poison_point.c +++ b/test/battle/ability/poison_point.c @@ -30,3 +30,22 @@ SINGLE_BATTLE_TEST("Poison Point inflicts poison on contact") } } } + +SINGLE_BATTLE_TEST("Poison Point triggers 30% of the time") +{ + PASSES_RANDOMLY(3, 10, RNG_POISON_POINT); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_NIDORAN_M) { Ability(ABILITY_POISON_POINT); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + TURN {} + } SCENE { + ABILITY_POPUP(opponent, ABILITY_POISON_POINT); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); + MESSAGE("Wobbuffet was poisoned by Foe Nidoran♂'s Poison Point!"); + STATUS_ICON(player, poison: TRUE); + } +} diff --git a/test/battle/ability/shed_skin.c b/test/battle/ability/shed_skin.c new file mode 100644 index 0000000000..d3030b9baf --- /dev/null +++ b/test/battle/ability/shed_skin.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Shed Skin triggers 30% of the time") +{ + PASSES_RANDOMLY(3, 10, RNG_SHED_SKIN); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ARBOK) { Status1(STATUS1_POISON); Ability(ABILITY_SHED_SKIN); } + } WHEN { + TURN; + } SCENE { + ABILITY_POPUP(opponent, ABILITY_SHED_SKIN); + MESSAGE("Foe Arbok's Shed Skin cured its poison problem!"); + STATUS_ICON(opponent, poison: FALSE); + } +} diff --git a/test/battle/ability/static.c b/test/battle/ability/static.c index 0f1b4f816f..2e74db3e14 100644 --- a/test/battle/ability/static.c +++ b/test/battle/ability/static.c @@ -29,3 +29,21 @@ SINGLE_BATTLE_TEST("Static inflicts paralysis on contact") } } } + +SINGLE_BATTLE_TEST("Static triggers 30% of the time") +{ + PASSES_RANDOMLY(3, 10, RNG_STATIC); + GIVEN { + ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_STATIC); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_STATIC); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, player); + MESSAGE("Foe Pikachu's Static paralyzed Wobbuffet! It may be unable to move!"); + STATUS_ICON(player, paralysis: TRUE); + } +} diff --git a/test/battle/crit_chance.c b/test/battle/crit_chance.c index 4964767e8e..d4c8e2b1a0 100644 --- a/test/battle/crit_chance.c +++ b/test/battle/crit_chance.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(B_CRIT_CHANCE >= GEN_7); } -SINGLE_BATTLE_TEST("Side effected by Lucky Chant blocks critical hits") +SINGLE_BATTLE_TEST("Crit Chance: Side effected by Lucky Chant blocks critical hits") { GIVEN { ASSUME(gMovesInfo[MOVE_LUCKY_CHANT].effect == EFFECT_LUCKY_CHANT); @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Side effected by Lucky Chant blocks critical hits") } } -SINGLE_BATTLE_TEST("Battle Armor and Shell Armor block critical hits") +SINGLE_BATTLE_TEST("Crit Chance: Battle Armor and Shell Armor block critical hits") { u32 species; u32 ability; @@ -39,7 +39,7 @@ SINGLE_BATTLE_TEST("Battle Armor and Shell Armor block critical hits") } } -SINGLE_BATTLE_TEST("Flag ignoresTargetAbility ignores Battle Armor and Shell Armor") +SINGLE_BATTLE_TEST("Crit Chance: Flag ignoresTargetAbility ignores Battle Armor and Shell Armor") { u32 species; u32 ability; @@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Flag ignoresTargetAbility ignores Battle Armor and Shell Arm } } -SINGLE_BATTLE_TEST("Mold Breaker, Teravolt and Turboblaze ignore Battle Armor and Shell Armor") +SINGLE_BATTLE_TEST("Crit Chance: Mold Breaker, Teravolt and Turboblaze ignore Battle Armor and Shell Armor") { u32 j; static const u32 pokemonPlayer[][2] = @@ -102,7 +102,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt and Turboblaze ignore Battle Armor an } } -SINGLE_BATTLE_TEST("User effected by Laser Focus causes moves to result in a critical hit") +SINGLE_BATTLE_TEST("Crit Chance: User effected by Laser Focus causes moves to result in a critical hit") { GIVEN { ASSUME(gMovesInfo[MOVE_LASER_FOCUS].effect == EFFECT_LASER_FOCUS); @@ -118,7 +118,7 @@ SINGLE_BATTLE_TEST("User effected by Laser Focus causes moves to result in a cri } } -SINGLE_BATTLE_TEST("If the target is poisoned the ability Merciless causes a move to result in a critical hit") +SINGLE_BATTLE_TEST("Crit Chance: If the target is poisoned the ability Merciless causes a move to result in a critical hit") { GIVEN { PLAYER(SPECIES_MAREANIE) { Ability(ABILITY_MERCILESS); } @@ -131,7 +131,7 @@ SINGLE_BATTLE_TEST("If the target is poisoned the ability Merciless causes a mov } } -SINGLE_BATTLE_TEST("Focus Energy increases the user's critical hit ratio by two stage") +SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases the user's critical hit ratio by two stage") { PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { @@ -148,7 +148,7 @@ SINGLE_BATTLE_TEST("Focus Energy increases the user's critical hit ratio by two } } -SINGLE_BATTLE_TEST("High crit rate increases the critical hit ratio by one stage") +SINGLE_BATTLE_TEST("Crit Chance: High crit rate increases the critical hit ratio by one stage") { PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { @@ -163,7 +163,7 @@ SINGLE_BATTLE_TEST("High crit rate increases the critical hit ratio by one stage } } -SINGLE_BATTLE_TEST("Super Luck increases the critical hit ratio by one stage") +SINGLE_BATTLE_TEST("Crit Chance: Super Luck increases the critical hit ratio by one stage") { PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { @@ -177,7 +177,7 @@ SINGLE_BATTLE_TEST("Super Luck increases the critical hit ratio by one stage") } } -SINGLE_BATTLE_TEST("Scope Lens increases the critical hit ratio by one stage") +SINGLE_BATTLE_TEST("Crit Chance: Scope Lens increases the critical hit ratio by one stage") { PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { @@ -192,7 +192,7 @@ SINGLE_BATTLE_TEST("Scope Lens increases the critical hit ratio by one stage") } } -SINGLE_BATTLE_TEST("High crit rate, Super Luck and Scope Lens cause the move to result in a critical hit") +SINGLE_BATTLE_TEST("Crit Chance: High crit rate, Super Luck and Scope Lens cause the move to result in a critical hit") { GIVEN { ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); @@ -207,7 +207,7 @@ SINGLE_BATTLE_TEST("High crit rate, Super Luck and Scope Lens cause the move to } } -SINGLE_BATTLE_TEST("Signature items Leek and Lucky Punch increase the critical hit ratio by 2 stages") +SINGLE_BATTLE_TEST("Crit Chance: Signature items Leek and Lucky Punch increase the critical hit ratio by 2 stages") { u32 species; u32 item; @@ -232,7 +232,7 @@ SINGLE_BATTLE_TEST("Signature items Leek and Lucky Punch increase the critical h } } -SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stages") +SINGLE_BATTLE_TEST("Crit Chance: Dire Hit increases a battler's critical hit chance by 2 stages") { PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { @@ -250,7 +250,7 @@ SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stag } } -SINGLE_BATTLE_TEST("Focus Energy increases critical hit ratio by two") +SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases critical hit ratio by two") { PASSES_RANDOMLY(8, 8, RNG_CRITICAL_HIT); GIVEN { @@ -269,7 +269,7 @@ SINGLE_BATTLE_TEST("Focus Energy increases critical hit ratio by two") } } -SINGLE_BATTLE_TEST("Dragon Cheer fails in a single battle") +SINGLE_BATTLE_TEST("Crit Chance: Dragon Cheer fails in a single battle") { GIVEN { ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER); @@ -282,7 +282,7 @@ SINGLE_BATTLE_TEST("Dragon Cheer fails in a single battle") } } -DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by one on non Dragon types") +DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer increases critical hit ratio by one on non Dragon types") { PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { @@ -302,7 +302,7 @@ DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by one on non Drag } } -DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by two on Dragon types") +DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer increases critical hit ratio by two on Dragon types") { PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { @@ -322,7 +322,7 @@ DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by two on Dragon t } } -DOUBLE_BATTLE_TEST("Dragon Cheer fails if critical hit stage was already increased by Focus Energy") +DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer fails if critical hit stage was already increased by Focus Energy") { GIVEN { ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);