Added test support for 5 battle configs (#5914)

Co-authored-by: sbird <sbird@no.tld>
Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
Eduardo Quezada 2025-02-09 18:29:23 -03:00 committed by GitHub
parent d510a3957d
commit 99cb40d896
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 562 additions and 409 deletions

View File

@ -22,8 +22,7 @@ struct PickupItem
u8 percentage[10];
};
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk);
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility);
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk);
s32 GetCritHitOdds(s32 critChanceIndex);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
u8 GetBattlerTurnOrderNum(u8 battlerId);

View File

@ -89,6 +89,7 @@
#define B_CHARGE_SPDEF_RAISE GEN_LATEST // In Gen5+, Charge raises the user's Special Defense by 1 stage.
#define B_MINIMIZE_EVASION GEN_LATEST // In Gen5+, Minimize raises evasion by 2 stages instead of 1.
#define B_GROWTH_STAT_RAISE GEN_LATEST // In Gen5+, Growth raises Attack in addition to Special Attack by 1 stage each. Under the effects of the sun, it raises them by 2 stages each instead.
#define B_FOCUS_ENERGY_CRIT_RATIO GEN_LATEST // In Gen3+, Focus Energy increases critical hit ratio by 2 instead of 1.
// Other move settings
#define B_INCINERATE_GEMS GEN_LATEST // In Gen6+, Incinerate can destroy Gems.

View File

@ -3,6 +3,12 @@
enum GenConfigTag
{
GEN_CONFIG_CRIT_CHANCE,
GEN_CONFIG_CRIT_MULTIPLIER,
GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO,
GEN_CONFIG_PARALYSIS_SPEED,
GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE,
GEN_CONFIG_MULTI_HIT_CHANCE,
GEN_CONFIG_GALE_WINGS,
GEN_CONFIG_COUNT
};

View File

@ -6,7 +6,13 @@
static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
{
[GEN_CONFIG_GALE_WINGS] = B_GALE_WINGS,
[GEN_CONFIG_CRIT_CHANCE] = B_CRIT_CHANCE,
[GEN_CONFIG_CRIT_MULTIPLIER] = B_CRIT_MULTIPLIER,
[GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO] = B_FOCUS_ENERGY_CRIT_RATIO,
[GEN_CONFIG_PARALYSIS_SPEED] = B_PARALYSIS_SPEED,
[GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE] = B_CONFUSION_SELF_DMG_CHANCE,
[GEN_CONFIG_MULTI_HIT_CHANCE] = B_MULTI_HIT_CHANCE,
[GEN_CONFIG_GALE_WINGS] = B_GALE_WINGS,
};
#if TESTING

View File

@ -676,7 +676,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
damageCalcData.randomFactor = FALSE;
damageCalcData.updateFlags = FALSE;
critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]);
critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]);
if (critChanceIndex > 1) // Consider crit damage only if a move has at least +2 crit chance
{
damageCalcData.isCrit = FALSE;

View File

@ -4827,7 +4827,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect)
// paralysis drop
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS && ability != ABILITY_QUICK_FEET)
speed /= B_PARALYSIS_SPEED >= GEN_7 ? 2 : 4;
speed /= GetGenConfig(GEN_CONFIG_PARALYSIS_SPEED) >= GEN_7 ? 2 : 4;
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SWAMP)
speed /= 4;

View File

@ -6,8 +6,6 @@
#include "battle_ai_util.h"
#include "battle_scripts.h"
#include "battle_z_move.h"
#include "constants/moves.h"
#include "constants/abilities.h"
#include "item.h"
#include "util.h"
#include "pokemon.h"
@ -47,6 +45,7 @@
#include "pokenav.h"
#include "menu_specialized.h"
#include "data.h"
#include "generational_changes.h"
#include "constants/abilities.h"
#include "constants/battle_anim.h"
#include "constants/battle_move_effects.h"
@ -1819,16 +1818,19 @@ static void Cmd_ppreduce(void)
}
// The chance is 1/N for each stage.
static const u32 sGen7CriticalHitOdds[] = {24, 8, 2, 1, 1};
static const u32 sGen6CriticalHitOdds[] = {16, 8, 2, 1, 1};
static const u32 sCriticalHitOdds[] = {16, 8, 4, 3, 2}; // Gens 2,3,4,5
static const u32 sGen7CriticalHitOdds[] = {24, 8, 2, 1, 1}; // 1/X
static const u32 sGen6CriticalHitOdds[] = {16, 8, 2, 1, 1}; // 1/X
static const u32 sCriticalHitOdds[] = {16, 8, 4, 3, 2}; // 1/X, Gens 3,4,5
static const u32 sGen2CriticalHitOdds[] = {17, 32, 64, 85, 128}; // X/256
static inline u32 GetCriticalHitOdds(u32 critChance)
{
if (B_CRIT_CHANCE >= GEN_7)
if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) >= GEN_7)
return sGen7CriticalHitOdds[critChance];
if (B_CRIT_CHANCE == GEN_6)
if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_6)
return sGen6CriticalHitOdds[critChance];
if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_2)
return sGen2CriticalHitOdds[critChance];
return sCriticalHitOdds[critChance];
}
@ -1870,7 +1872,7 @@ static inline u32 GetHoldEffectCritChanceIncrease(u32 battler, u32 holdEffect)
#define CRITICAL_HIT_BLOCKED -1
#define CRITICAL_HIT_ALWAYS -2
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
{
s32 critChance = 0;
@ -1913,75 +1915,51 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec
return critChance;
}
#undef CRITICAL_HIT_BLOCKED
#undef CRITICAL_HIT_ALWAYS
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility)
{
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
return CalcCritChanceStageArgs(battlerAtk, battlerDef, move, recordAbility, abilityAtk, abilityDef, holdEffectAtk);
}
// Bulbapedia: https://bulbapedia.bulbagarden.net/wiki/Critical_hit#Generation_I
// Crit chance = Threshold / 256, Threshold maximum of 255
// Threshold = Base Speed / 2
// High crit move = 8 * (Base Speed / 2)
// Focus Energy = 4 * (Base Speed / 2)
s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility)
s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
{
// Vanilla
u32 focusEnergyScaler = 4;
u32 highCritRatioScaler = 8;
// Not vanilla
u32 superLuckScaler = 4;
u32 scopeLensScaler = 4;
u32 luckyPunchScaler = 8;
u32 farfetchdLeekScaler = 8;
s32 critChance = 0;
s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage;
s32 bonusCritStage = gBattleStruct->bonusCritStages[battlerAtk]; // G-Max Chi Strike
u32 abilityAtk = GetBattlerAbility(battlerAtk);
u32 abilityDef = GetBattlerAbility(battlerDef);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
u32 holdEffectCritStage = GetHoldEffectCritChanceIncrease(battlerAtk, holdEffectAtk);
u16 baseSpeed = gSpeciesInfo[gBattleMons[battlerAtk].species].baseSpeed;
critChance = baseSpeed / 2;
// Crit scaling
if (moveCritStage > 0)
critChance = critChance * highCritRatioScaler * moveCritStage;
critChance *= 8 * moveCritStage;
if (bonusCritStage > 0)
critChance = critChance * bonusCritStage;
critChance *= bonusCritStage;
if ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY_ANY) != 0)
critChance = critChance * focusEnergyScaler;
if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY)
critChance *= 4;
else if (gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER)
critChance *= 2;
if (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
critChance = critChance * scopeLensScaler;
else if (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY)
critChance = critChance * luckyPunchScaler;
else if (IsBattlerLeekAffected(battlerAtk, holdEffectAtk))
critChance = critChance * farfetchdLeekScaler;
if (holdEffectCritStage > 0)
critChance *= 4 * holdEffectCritStage;
if (abilityAtk == ABILITY_SUPER_LUCK)
critChance = critChance * superLuckScaler;
critChance *= 4;
if (critChance > 255)
critChance = 255;
// Prevented crits
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT)
critChance = -1;
critChance = CRITICAL_HIT_BLOCKED;
else if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{
if (recordAbility)
RecordAbilityBattle(battlerDef, abilityDef);
critChance = -1;
critChance = CRITICAL_HIT_BLOCKED;
}
// Guaranteed crits
@ -1989,7 +1967,7 @@ s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec
|| gMovesInfo[move].alwaysCriticalHit == TRUE
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY))
{
critChance = -2;
critChance = CRITICAL_HIT_ALWAYS;
}
return critChance;
@ -2002,6 +1980,8 @@ s32 GetCritHitOdds(s32 critChanceIndex)
else
return GetCriticalHitOdds(critChanceIndex);
}
#undef CRITICAL_HIT_BLOCKED
#undef CRITICAL_HIT_ALWAYS
static void Cmd_critcalc(void)
{
@ -2009,11 +1989,14 @@ static void Cmd_critcalc(void)
u16 partySlot;
s32 critChance;
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
if (B_CRIT_CHANCE == GEN_1)
critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1)
critChance = CalcCritChanceStageGen1(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE, abilityAtk, abilityDef, holdEffectAtk);
else
critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE, abilityAtk, abilityDef, holdEffectAtk);
gPotentialItemEffectBattler = gBattlerAttacker;
@ -2025,14 +2008,10 @@ static void Cmd_critcalc(void)
gIsCriticalHit = TRUE;
else
{
if (B_CRIT_CHANCE == GEN_1)
{
u8 critRoll = RandomUniform(RNG_CRITICAL_HIT, 1, 256);
if (critRoll <= critChance)
gIsCriticalHit = 1;
else
gIsCriticalHit = 0;
}
if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1)
gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, critChance, 256);
else if (GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_2)
gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, GetCriticalHitOdds(critChance), 256);
else
gIsCriticalHit = RandomChance(RNG_CRITICAL_HIT, 1, GetCriticalHitOdds(critChance));
}
@ -12604,7 +12583,10 @@ static void Cmd_setfocusenergy(void)
}
else
{
gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY;
if (GetGenConfig(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3)
gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY;
else
gBattleMons[battler].status2 |= STATUS2_DRAGON_CHEER;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED;
}
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -9,6 +9,7 @@
#include "battle_setup.h"
#include "battle_z_move.h"
#include "battle_gimmick.h"
#include "generational_changes.h"
#include "party_menu.h"
#include "pokemon.h"
#include "international_string_util.h"
@ -3468,7 +3469,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType)
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION)
{
// confusion dmg
if (RandomPercentage(RNG_CONFUSION, (B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50)))
if (RandomPercentage(RNG_CONFUSION, (GetGenConfig(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50)))
{
gBattleCommunication[MULTISTRING_CHOOSER] = TRUE;
gBattlerTarget = gBattlerAttacker;
@ -10086,7 +10087,7 @@ static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageCalculationData *
static inline uq4_12_t GetCriticalModifier(bool32 isCrit)
{
if (isCrit)
return B_CRIT_MULTIPLIER >= GEN_6 ? UQ_4_12(1.5) : UQ_4_12(2.0);
return GetGenConfig(GEN_CONFIG_CRIT_MULTIPLIER) >= GEN_6 ? UQ_4_12(1.5) : UQ_4_12(2.0);
return UQ_4_12(1.0);
}
@ -11672,7 +11673,7 @@ static void SetRandomMultiHitCounter()
{
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE)
gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 5);
else if (B_MULTI_HIT_CHANCE >= GEN_5)
else if (GetGenConfig(GEN_CONFIG_MULTI_HIT_CHANCE) >= GEN_5)
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 7, 7, 3, 3); // 35%: 2 hits, 35%: 3 hits, 15% 4 hits, 15% 5 hits.
else
gMultiHitCounter = RandomWeighted(RNG_HITS, 0, 0, 3, 3, 1, 1); // 37.5%: 2 hits, 37.5%: 3 hits, 12.5% 4 hits, 12.5% 5 hits.

View File

@ -0,0 +1,49 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Battle Armor and Shell Armor block critical hits")
{
u32 species;
u32 ability;
PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; }
PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NOT MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Mold Breaker, Teravolt and Turboblaze ignore Battle Armor and Shell Armor")
{
u32 j;
u32 species1, species2, ability1, ability2;
static const u32 breakerData[][2] =
{
{SPECIES_PINSIR, ABILITY_MOLD_BREAKER},
{SPECIES_ZEKROM, ABILITY_TERAVOLT},
{SPECIES_RESHIRAM, ABILITY_TURBOBLAZE},
};
for (j = 0; j < ARRAY_COUNT(breakerData); j++)
{
PARAMETRIZE { species1 = breakerData[j][0]; ability1 = breakerData[j][1]; species2 = SPECIES_KINGLER; ability2 = ABILITY_SHELL_ARMOR; }
PARAMETRIZE { species1 = breakerData[j][0]; ability1 = breakerData[j][1]; species2 = SPECIES_ARMALDO; ability2 = ABILITY_BATTLE_ARMOR; }
}
GIVEN {
PLAYER(species1) { Ability(ability1); }
OPPONENT(species2) { Ability(ability2); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Inner Focus prevents flinching")
}
}
SINGLE_BATTLE_TEST("Inner Focus is ignored by Mold Breaker")
SINGLE_BATTLE_TEST("Mold Breaker ignores Inner Focus")
{
GIVEN {
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); };

View File

@ -0,0 +1,16 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Merciless causes a move to result in a critical hit if the target is poisoned")
{
PASSES_RANDOMLY(1, 1, RNG_CRITICAL_HIT);
GIVEN {
PLAYER(SPECIES_MAREANIE) { Ability(ABILITY_MERCILESS); }
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the user")
}
}
SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker")
SINGLE_BATTLE_TEST("Mold Breaker ignores Own Tempo")
{
KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef
GIVEN {
@ -73,7 +73,7 @@ SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker")
}
}
SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mold Breaker")
SINGLE_BATTLE_TEST("Mold Breaker does not prevent Own Tempo from curing confusion right after")
{
KNOWN_FAILING;
GIVEN {

View File

@ -131,12 +131,15 @@ SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod
}
}
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit twice 35% of the time")
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit twice 37.5/35% of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 3; trials = 8; } // 37.5%
PARAMETRIZE { genConfig = GEN_5; passes = 7; trials = 20; } // 35%
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -157,12 +160,15 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
}
}
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit thrice 35% of the time")
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit thrice 37.5/35% of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 3; trials = 8; } // 37.5%
PARAMETRIZE { genConfig = GEN_5; passes = 7; trials = 20; } // 35%
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -184,12 +190,15 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
}
}
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit four times 15% of the time")
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit four times 12.5/15% of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 1; trials = 8; } // 12.5%
PARAMETRIZE { genConfig = GEN_5; passes = 3; trials = 20; } // 15%
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }
@ -212,12 +221,15 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil
}
}
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit five times 15% of the time")
SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they still hit five times 12.5/15% of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 1; trials = 8; } // 12.5%
PARAMETRIZE { genConfig = GEN_5; passes = 3; trials = 20; } // 15%
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS);
ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); }

View File

@ -0,0 +1,4 @@
#include "global.h"
#include "test/battle.h"
// Tests for Shell Armor are handled in test/battle/ability/battle_armor.c

View File

@ -0,0 +1,25 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Super Luck increases the critical hit ratio by 1 stage")
{
u32 j, genConfig = 0, passes = 0, trials = 0;
PARAMETRIZE { genConfig = GEN_1; passes = 5; trials = 32; } // ~15.6% with Togepi's base speed
for (j = GEN_2; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; passes = 1; trials = 8; } // 12.5%
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(gSpeciesInfo[SPECIES_TOGEPI].baseSpeed == 20);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
PLAYER(SPECIES_TOGEPI) { Ability(ABILITY_SUPER_LUCK); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}
TO_DO_BATTLE_TEST("Super Luck increases the chances of wild Pokémon holding items (Gen8+)");

View File

@ -1,200 +1,41 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Crit Chance: Side effected by Lucky Chant blocks critical hits")
SINGLE_BATTLE_TEST("Critical hits without modifiers occur at different rates by generation")
{
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_1; passes = 1; trials = 16; } // 6.25% with Wobbuffet's base speed
PARAMETRIZE { genConfig = GEN_2; passes = 17; trials = 256; } // ~6.64%
for (u32 j = GEN_3; j <= GEN_6; j++)
PARAMETRIZE { genConfig = j; passes = 1, trials = 16; } // 6.25%
for (u32 j = GEN_7; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; passes = 1, trials = 24; } // ~4.17%
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(gMovesInfo[MOVE_LUCKY_CHANT].effect == EFFECT_LUCKY_CHANT);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseSpeed == 33);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_LUCKY_CHANT); MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NOT MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Battle Armor and Shell Armor block critical hits")
{
u32 species;
u32 ability;
PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; }
PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NOT MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Flag ignoresTargetAbility ignores Battle Armor and Shell Armor")
{
u32 species;
u32 ability;
PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; }
PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; }
GIVEN {
ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(player, MOVE_SUNSTEEL_STRIKE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNSTEEL_STRIKE, player);
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Mold Breaker, Teravolt and Turboblaze ignore Battle Armor and Shell Armor")
SINGLE_BATTLE_TEST("Crit Chance: Raising critical hit rate to 3 guarantees a critical hit (Gen 6+)")
{
u32 j;
static const u32 pokemonPlayer[][2] =
{
{SPECIES_PINSIR, ABILITY_MOLD_BREAKER},
{SPECIES_ZEKROM, ABILITY_TERAVOLT},
{SPECIES_KYUREM_WHITE, ABILITY_TURBOBLAZE},
};
u32 speciesPlayer;
u32 abilityPlayer;
u32 speciesOpponent;
u32 abilityOpponent;
for (j = 0; j < ARRAY_COUNT(pokemonPlayer); j++)
{
PARAMETRIZE {
speciesPlayer = pokemonPlayer[j][0];
abilityPlayer = pokemonPlayer[j][1];
speciesOpponent = SPECIES_KINGLER;
abilityOpponent = ABILITY_SHELL_ARMOR;
}
PARAMETRIZE {
speciesPlayer = pokemonPlayer[j][0];
abilityPlayer = pokemonPlayer[j][1];
speciesOpponent = SPECIES_ARMALDO;
abilityOpponent = ABILITY_BATTLE_ARMOR;
}
}
u32 genConfig = 0, passes, trials;
PARAMETRIZE { genConfig = GEN_1; passes = 255; trials = 256; } // ~99.6%
PARAMETRIZE { genConfig = GEN_2; passes = 85; trials = 256; } // ~33.2%
for (u32 j = GEN_3; j <= GEN_5; j++)
PARAMETRIZE { genConfig = j; passes = 1, trials = 3; } // ~33.3%
for (u32 j = GEN_6; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; passes = 1, trials = 1; } // 100%
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
PLAYER(speciesPlayer) { Ability(abilityPlayer); }
OPPONENT(speciesOpponent) { Ability(abilityOpponent); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("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);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_LASER_FOCUS); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASER_FOCUS, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("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); }
OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}
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 {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_ENERGY); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: High crit rate increases the critical hit ratio by one stage")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLASH, player);
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Super Luck increases the critical hit ratio by one stage")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
PLAYER(SPECIES_TOGEPI) { Ability(ABILITY_SUPER_LUCK); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Scope Lens increases the critical hit ratio by one stage")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gItemsInfo[ITEM_SCOPE_LENS].holdEffect == HOLD_EFFECT_SCOPE_LENS);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SCOPE_LENS); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("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(B_CRIT_CHANCE >= GEN_7);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gItemsInfo[ITEM_SCOPE_LENS].holdEffect == HOLD_EFFECT_SCOPE_LENS);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SUPER_LUCK); Item(ITEM_SCOPE_LENS); };
@ -206,68 +47,3 @@ SINGLE_BATTLE_TEST("Crit Chance: High crit rate, Super Luck and Scope Lens cause
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Signature items Leek and Lucky Punch increase the critical hit ratio by 2 stages")
{
u32 species;
u32 item;
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
PARAMETRIZE { species = SPECIES_FARFETCHD; item = ITEM_LEEK; }
PARAMETRIZE { species = SPECIES_FARFETCHD_GALAR; item = ITEM_LEEK; }
PARAMETRIZE { species = SPECIES_SIRFETCHD; item = ITEM_LEEK; }
PARAMETRIZE { species = SPECIES_CHANSEY; item = ITEM_LUCKY_PUNCH; }
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gItemsInfo[ITEM_LEEK].holdEffect == HOLD_EFFECT_LEEK);
ASSUME(gItemsInfo[ITEM_LUCKY_PUNCH].holdEffect == HOLD_EFFECT_LUCKY_PUNCH);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Item(item); }
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
MESSAGE("A critical hit!");
}
}
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 {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gItemsInfo[ITEM_DIRE_HIT].battleUsage == EFFECT_ITEM_SET_FOCUS_ENERGY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { USE_ITEM(player, ITEM_DIRE_HIT, partyIndex: 0); }
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
MESSAGE("Wobbuffet used the Dire Hit to get pumped!");
MESSAGE("Wobbuffet used Scratch!");
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases critical hit ratio by two")
{
PASSES_RANDOMLY(8, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_ENERGY); }
TURN { MOVE(player, MOVE_SLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
MESSAGE("Wobbuffet is getting pumped!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLASH, player);
MESSAGE("A critical hit!");
}
}

View File

@ -1421,7 +1421,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin
}
}
DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance")
DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance by 1 stage")
{
u32 j;
GIVEN {

View File

@ -518,10 +518,17 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Light That Burns the Sky uses the battler's highest
SINGLE_BATTLE_TEST("(Z-MOVE) 10,000,000 Volt Thunderbolt has an increased critical hit ratio")
{
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
u32 genConfig, chance;
PARAMETRIZE { genConfig = GEN_1; chance = 1; }
for (u32 j = GEN_2; j <= GEN_5; j++)
PARAMETRIZE { genConfig = j; chance = 4; }
for (u32 j = GEN_6; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; chance = 2; }
PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_6);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_10_000_000_VOLT_THUNDERBOLT].criticalHitStage == 2);
ASSUME(gSpeciesInfo[SPECIES_PIKACHU_PARTNER].baseSpeed == 90);
PLAYER(SPECIES_PIKACHU_PARTNER) { Item(ITEM_PIKASHUNIUM_Z); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -48,12 +48,17 @@ SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by two s
}
}
SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by two stages")
SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by 2 stages")
{
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
u32 genConfig = 0, chance;
for (u32 j = GEN_1; j <= GEN_5; j++)
PARAMETRIZE { genConfig = j; chance = 4; } // 25%
for (u32 j = GEN_6; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; chance = 2; } // 50%
PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0);
ASSUME(B_CRIT_CHANCE >= GEN_6);
PLAYER(SPECIES_WOBBUFFET) { MaxHP(160); HP(80); Item(ITEM_LANSAT_BERRY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -0,0 +1,36 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Leek increases critical hit ratio by 2 stages for the Farfetch'd Family")
{
u32 species, genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_1; passes = 15; trials = 16; species = SPECIES_FARFETCHD; } // ~93.8% with Farfetch'd's base speed
PARAMETRIZE { genConfig = GEN_1; passes = 27; trials = 32; species = SPECIES_FARFETCHD_GALAR; } // ~84.4% with Galarian Farfetch'd's base speed
PARAMETRIZE { genConfig = GEN_1; passes = 1; trials = 1; species = SPECIES_SIRFETCHD; } // 100% with Sirfetch'd's base speed
for (u32 j = GEN_2; j <= GEN_5; j++) {
PARAMETRIZE { genConfig = j; passes = 1; trials = 4; species = SPECIES_FARFETCHD; } // 25%
PARAMETRIZE { genConfig = j; passes = 1; trials = 4; species = SPECIES_FARFETCHD_GALAR; } // 25%
PARAMETRIZE { genConfig = j; passes = 1; trials = 4; species = SPECIES_SIRFETCHD; } // 25%
}
for (u32 j = GEN_6; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = j; passes = 1; trials = 2; species = SPECIES_FARFETCHD; } // 50%
PARAMETRIZE { genConfig = j; passes = 1; trials = 2; species = SPECIES_FARFETCHD_GALAR; } // 50%
PARAMETRIZE { genConfig = j; passes = 1; trials = 2; species = SPECIES_SIRFETCHD; } // 50%
}
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gSpeciesInfo[SPECIES_FARFETCHD].baseSpeed == 60);
ASSUME(gSpeciesInfo[SPECIES_FARFETCHD_GALAR].baseSpeed == 55);
ASSUME(gSpeciesInfo[SPECIES_SIRFETCHD].baseSpeed == 65);
ASSUME(gItemsInfo[ITEM_LEEK].holdEffect == HOLD_EFFECT_LEEK);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Item(ITEM_LEEK); }
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
MESSAGE("A critical hit!");
}
}

View File

@ -0,0 +1,25 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Lucky Punch increases critical hit ratio by 2 stages for Chansey")
{
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_1; passes = 25; trials = 32; } // ~78.1% with Chansey's base speed
for (u32 j = GEN_2; j <= GEN_5; j++)
PARAMETRIZE { genConfig = j; passes = 1; trials = 4; } // 25%
for (u32 j = GEN_6; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; passes = 1; trials = 2; } // 50%
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gItemsInfo[ITEM_LUCKY_PUNCH].holdEffect == HOLD_EFFECT_LUCKY_PUNCH);
ASSUME(gSpeciesInfo[SPECIES_CHANSEY].baseSpeed == 50);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_CHANSEY) { Item(ITEM_LUCKY_PUNCH); }
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
MESSAGE("A critical hit!");
}
}

View File

@ -0,0 +1,23 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Scope Lens increases the critical hit ratio by 1 stage")
{
u32 genConfig = 0, passes, trials;
PARAMETRIZE { genConfig = GEN_1; passes = 1; trials = 4; } // 25% with Wobbuffet's base speed
for (u32 j = GEN_2; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; passes = 1; trials = 8; } // 12.5%
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gItemsInfo[ITEM_SCOPE_LENS].holdEffect == HOLD_EFFECT_SCOPE_LENS);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseSpeed == 33);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SCOPE_LENS); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -0,0 +1,26 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stages")
{
u32 genConfig = 0, chance;
for (u32 j = GEN_1; j <= GEN_5; j++)
PARAMETRIZE { genConfig = j; chance = 4; } // 25%
for (u32 j = GEN_6; j <= GEN_9; j++)
PARAMETRIZE { genConfig = j; chance = 2; } // 50%
PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gItemsInfo[ITEM_DIRE_HIT].battleUsage == EFFECT_ITEM_SET_FOCUS_ENERGY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { USE_ITEM(player, ITEM_DIRE_HIT, partyIndex: 0); }
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
MESSAGE("Wobbuffet used the Dire Hit to get pumped!");
MESSAGE("Wobbuffet used Scratch!");
MESSAGE("A critical hit!");
}
}

View File

@ -134,42 +134,15 @@ DOUBLE_BATTLE_TEST("Turn order is determined randomly if priority and Speed tie
}
}
SINGLE_BATTLE_TEST("Critical hits occur at a 1/24 rate")
{
PASSES_RANDOMLY(1, 24, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SCRATCH); }
} SCENE {
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Slash's critical hits occur at a 1/8 rate")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SLASH); }
} SCENE {
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Critical hits deal 50% more damage", s16 damage)
SINGLE_BATTLE_TEST("Critical hits deal 100% (Gen 1-5) or 50% (Gen 6+) more damage", s16 damage)
{
bool32 criticalHit;
PARAMETRIZE { criticalHit = FALSE; }
PARAMETRIZE { criticalHit = TRUE; }
u32 genConfig;
PARAMETRIZE { criticalHit = FALSE; genConfig = GEN_5; }
PARAMETRIZE { criticalHit = TRUE; genConfig = GEN_5; }
PARAMETRIZE { criticalHit = TRUE; genConfig = GEN_6; }
GIVEN {
ASSUME(B_CRIT_MULTIPLIER >= GEN_6);
WITH_CONFIG(GEN_CONFIG_CRIT_MULTIPLIER, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -177,7 +150,8 @@ SINGLE_BATTLE_TEST("Critical hits deal 50% more damage", s16 damage)
} SCENE {
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage);
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[2].damage);
}
}

View File

@ -1,10 +1,14 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
}
SINGLE_BATTLE_TEST("Dragon Cheer fails in a single battle")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -14,43 +18,68 @@ 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("Dragon Cheer increases critical hit ratio by 1 on non-Dragon types")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
bool32 useDragonCheer = 0;
u32 genConfig = 0, chance = 0;
for (u32 j = GEN_1; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = j; useDragonCheer = FALSE; chance = j >= GEN_7 ? 24 : 16; } // 6.25% with Wobbuffet's base speed
PARAMETRIZE { genConfig = j; useDragonCheer = TRUE; chance = 8; } // 12.5% with Wobbuffet's base speed
}
PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
TURN {
if (useDragonCheer)
MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight);
MOVE(playerRight, MOVE_TACKLE, target: opponentLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Wynaut is getting pumped!");
if (useDragonCheer) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Wobbuffet is getting pumped!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
MESSAGE("A critical hit!");
}
}
DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by two on Dragon types")
DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by 2 on Dragon types")
{
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
bool32 useDragonCheer;
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_1; useDragonCheer = FALSE; passes = 25; trials = 256; } // ~9.77% with Dratini's base speed
PARAMETRIZE { genConfig = GEN_1; useDragonCheer = TRUE; passes = 25; trials = 64; } // ~39.06% with Dratini's base speed
for (u32 j = GEN_2; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = j; useDragonCheer = FALSE; passes = 1; trials = j >= GEN_7 ? 24 : 16; } // ~4.16%/6.25%
PARAMETRIZE { genConfig = j; useDragonCheer = TRUE; passes = 1; trials = j >= GEN_6 ? 2 : 4; } // 50%/25%
}
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
ASSUME(gSpeciesInfo[SPECIES_DRATINI].baseSpeed == 50);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DRATINI);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
TURN {
if (useDragonCheer)
MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight);
MOVE(playerRight, MOVE_TACKLE, target: opponentLeft);
}
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Dratini is getting pumped!");
if (useDragonCheer) {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Dratini is getting pumped!");
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
MESSAGE("A critical hit!");
}
@ -61,7 +90,6 @@ DOUBLE_BATTLE_TEST("Dragon Cheer fails if critical hit stage was already increas
GIVEN {
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -0,0 +1,41 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
}
SINGLE_BATTLE_TEST("Focus Energy increases the user's critical hit ratio by 1 stage (Gen 1-2) or 2 stages (Gen 3+)")
{
bool32 useFocusEnergy = 0;
u32 genConfig = 0, chance = 0;
for (u32 j = GEN_1; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = j; useFocusEnergy = FALSE; chance = j >= GEN_7 ? 24 : 16; } // ~4.16%/6.25% with Wobbuffet's base speed
PARAMETRIZE { genConfig = j; useFocusEnergy = TRUE;
if (j >= GEN_6)
chance = 2; // 50% / 25%
else if (j >= GEN_3)
chance = 4; // 25%
else
chance = 8; // 12.5% with Wobbuffet's base speed
}
}
PASSES_RANDOMLY(1, chance, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
WITH_CONFIG(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO, genConfig);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseSpeed == 33);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
if (useFocusEnergy)
TURN { MOVE(player, MOVE_FOCUS_ENERGY); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
if (useFocusEnergy)
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -0,0 +1,23 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gMovesInfo[MOVE_LASER_FOCUS].effect == EFFECT_LASER_FOCUS);
}
SINGLE_BATTLE_TEST("Laser Focus causes the user's move used on the next turn to result in a Critical Hit")
{
PASSES_RANDOMLY(1, 1, RNG_CRITICAL_HIT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_LASER_FOCUS); }
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_LASER_FOCUS, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -0,0 +1,16 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Lucky Chant prevents critical hits on the user's side")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_LUCKY_CHANT].effect == EFFECT_LUCKY_CHANT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_LUCKY_CHANT); MOVE(player, MOVE_TACKLE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NOT MESSAGE("A critical hit!");
}
}

View File

@ -25,12 +25,15 @@ SINGLE_BATTLE_TEST("Multi hit Moves hit the maximum amount with Skill Link")
}
}
SINGLE_BATTLE_TEST("Multi hit Moves hit twice 35% of the time")
SINGLE_BATTLE_TEST("Multi hit Moves hit twice 37.5/35% of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 3; trials = 8; }
PARAMETRIZE { genConfig = GEN_5; passes = 7; trials = 20; }
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -42,12 +45,15 @@ SINGLE_BATTLE_TEST("Multi hit Moves hit twice 35% of the time")
}
}
SINGLE_BATTLE_TEST("Multi hit Moves hit thrice 35% of the time")
SINGLE_BATTLE_TEST("Multi hit Moves hit thrice 37.5/35% of the time")
{
PASSES_RANDOMLY(35, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 3; trials = 8; }
PARAMETRIZE { genConfig = GEN_5; passes = 7; trials = 20; }
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -60,12 +66,15 @@ SINGLE_BATTLE_TEST("Multi hit Moves hit thrice 35% of the time")
}
}
SINGLE_BATTLE_TEST("Multi hit Moves hit four times 15% of the time")
SINGLE_BATTLE_TEST("Multi hit Moves hit four times 12.5/15% of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 1; trials = 8; }
PARAMETRIZE { genConfig = GEN_5; passes = 3; trials = 20; }
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -79,12 +88,15 @@ SINGLE_BATTLE_TEST("Multi hit Moves hit four times 15% of the time")
}
}
SINGLE_BATTLE_TEST("Multi hit Moves hit five times 15% of the time")
SINGLE_BATTLE_TEST("Multi hit Moves hit five times 12.5/15% of the time")
{
PASSES_RANDOMLY(15, 100, RNG_HITS);
u32 genConfig, passes, trials;
PARAMETRIZE { genConfig = GEN_4; passes = 1; trials = 8; }
PARAMETRIZE { genConfig = GEN_5; passes = 3; trials = 20; }
PASSES_RANDOMLY(passes, trials, RNG_HITS);
GIVEN {
ASSUME(B_MULTI_HIT_CHANCE >= GEN_5);
WITH_CONFIG(GEN_CONFIG_MULTI_HIT_CHANCE, genConfig);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {

View File

@ -44,11 +44,17 @@ SINGLE_BATTLE_TEST("Triple Arrows makes the foe flinch 30% of the time")
}
}
SINGLE_BATTLE_TEST("Triple Arrows lands a critical hit")
SINGLE_BATTLE_TEST("Triple Arrows has an increased critical hit ratio")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
u32 j, genConfig = 0, passes = 0, trials = 0;
PARAMETRIZE { genConfig = GEN_1; passes = 1; trials = 2; } // 50% with Wobbuffet's base speed
for (j = GEN_2; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = GEN_2; passes = 1; trials = 8; }
}
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_7);
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_TRIPLE_ARROWS].criticalHitStage == 1);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);

View File

@ -0,0 +1,24 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("criticalHitStage set to 1 increases critical hits occur at a 1/8 rate (Gen 2+) or x8 times more likely (Gen 1)")
{
u32 j, genConfig = 0, passes = 0, trials = 0;
PARAMETRIZE { genConfig = GEN_1; passes = 1; trials = 2; } // 50% with Wobbuffet's base speed
for (j = GEN_2; j <= GEN_9; j++) {
PARAMETRIZE { genConfig = GEN_2; passes = 1; trials = 8; }
}
PASSES_RANDOMLY(passes, trials, RNG_CRITICAL_HIT);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseSpeed == 33);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_SLASH); }
} SCENE {
MESSAGE("A critical hit!");
}
}

View File

@ -72,3 +72,23 @@ SINGLE_BATTLE_TEST("ignoresTargetAbility moves do ignore target's abilities", s1
EXPECT_EQ(results[4].damage, results[5].damage);
}
}
SINGLE_BATTLE_TEST("ignoresTargetAbility allows Pokémon with Battle Armor and Shell Armor to receive critical hits")
{
u32 species;
u32 ability;
PARAMETRIZE { species = SPECIES_KINGLER; ability = ABILITY_SHELL_ARMOR; }
PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; }
GIVEN {
ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility == TRUE);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(species) { Ability(ability); }
} WHEN {
TURN { MOVE(player, MOVE_SUNSTEEL_STRIKE, criticalHit: TRUE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNSTEEL_STRIKE, player);
MESSAGE("A critical hit!");
}
}

View File

@ -1,14 +1,16 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Paralysis reduces Speed by 50%")
SINGLE_BATTLE_TEST("Paralysis reduces Speed by 50% (Gen 7+) or 75% (Gen 1-6)")
{
u16 playerSpeed;
u32 playerSpeed, genConfig;
bool32 playerFirst;
PARAMETRIZE { playerSpeed = 98; playerFirst = FALSE; }
PARAMETRIZE { playerSpeed = 102; playerFirst = TRUE; }
PARAMETRIZE { playerSpeed = 196; playerFirst = FALSE; genConfig = GEN_6; }
PARAMETRIZE { playerSpeed = 204; playerFirst = TRUE; genConfig = GEN_6; }
PARAMETRIZE { playerSpeed = 98; playerFirst = FALSE; genConfig = GEN_7; }
PARAMETRIZE { playerSpeed = 102; playerFirst = TRUE; genConfig = GEN_7; }
GIVEN {
ASSUME(B_PARALYSIS_SPEED >= GEN_7);
WITH_CONFIG(GEN_CONFIG_PARALYSIS_SPEED, genConfig);
PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_PARALYSIS); Speed(playerSpeed); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); }
} WHEN {

View File

@ -4,11 +4,14 @@
SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power")
{
s16 damage[2];
u32 genConfig, pctChance;
ASSUME(gMovesInfo[MOVE_TACKLE].power == 40);
PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION);
PARAMETRIZE { genConfig = GEN_6; pctChance = 50; }
PARAMETRIZE { genConfig = GEN_7; pctChance = 33; }
PASSES_RANDOMLY(pctChance, 100, RNG_CONFUSION);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE, genConfig);
ASSUME(gMovesInfo[MOVE_TACKLE].power == 40);
PLAYER(SPECIES_WOBBUFFET) { Speed(1); };
OPPONENT(SPECIES_WOBBUFFET) { Speed(2); };
} WHEN {
@ -29,8 +32,13 @@ SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power")
SINGLE_BATTLE_TEST("Confusion self hit does not consume Gems")
{
PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION);
u32 genConfig, pctChance;
PARAMETRIZE { genConfig = GEN_6; pctChance = 50; }
PARAMETRIZE { genConfig = GEN_7; pctChance = 33; }
PASSES_RANDOMLY(pctChance, 100, RNG_CONFUSION);
GIVEN {
WITH_CONFIG(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE, genConfig);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {