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:
parent
d510a3957d
commit
99cb40d896
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
49
test/battle/ability/battle_armor.c
Normal file
49
test/battle/ability/battle_armor.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
@ -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); };
|
||||
|
||||
16
test/battle/ability/merciless.c
Normal file
16
test/battle/ability/merciless.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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); }
|
||||
|
||||
4
test/battle/ability/shell_armor.c
Normal file
4
test/battle/ability/shell_armor.c
Normal 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
|
||||
25
test/battle/ability/super_luck.c
Normal file
25
test/battle/ability/super_luck.c
Normal 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+)");
|
||||
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
36
test/battle/hold_effect/leek.c
Normal file
36
test/battle/hold_effect/leek.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
25
test/battle/hold_effect/luck_punch.c
Normal file
25
test/battle/hold_effect/luck_punch.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
23
test/battle/hold_effect/scope_lens.c
Normal file
23
test/battle/hold_effect/scope_lens.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
26
test/battle/item_effect/dire_hit.c
Normal file
26
test/battle/item_effect/dire_hit.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
41
test/battle/move_effect/focus_energy.c
Normal file
41
test/battle/move_effect/focus_energy.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
23
test/battle/move_effect/laser_focus.c
Normal file
23
test/battle/move_effect/laser_focus.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
16
test/battle/move_effect/lucky_chant.c
Normal file
16
test/battle/move_effect/lucky_chant.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
24
test/battle/move_flags/critical_hit_stage.c
Normal file
24
test/battle/move_flags/critical_hit_stage.c
Normal 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!");
|
||||
}
|
||||
}
|
||||
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user