1708c80200
Replaced ALWAYS_CRIT with an alwaysCriticalHit flag to account for the fact that in earlier generations, there is no crit stage at which crits are guaranteed. Renamed critBoost to criticalHitStage (at Edu's prompting). Reorder .criticalHitStage defines in battle_moves.h to be aligned with struct order.
172 lines
5.4 KiB
C
172 lines
5.4 KiB
C
#include "global.h"
|
|
#include "test/battle.h"
|
|
|
|
SINGLE_BATTLE_TEST("Accuracy controls the proportion of misses")
|
|
{
|
|
u32 move;
|
|
PARAMETRIZE { move = MOVE_DYNAMIC_PUNCH; }
|
|
PARAMETRIZE { move = MOVE_THUNDER; }
|
|
PARAMETRIZE { move = MOVE_HYDRO_PUMP; }
|
|
PARAMETRIZE { move = MOVE_RAZOR_LEAF; }
|
|
PARAMETRIZE { move = MOVE_SCRATCH; }
|
|
ASSUME(0 < gBattleMoves[move].accuracy && gBattleMoves[move].accuracy <= 100);
|
|
PASSES_RANDOMLY(gBattleMoves[move].accuracy, 100, RNG_ACCURACY);
|
|
GIVEN {
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(player, move); }
|
|
} SCENE {
|
|
ANIMATION(ANIM_TYPE_MOVE, move, player);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Secondary Effect Chance controls the proportion of secondary effects")
|
|
{
|
|
u32 move;
|
|
PARAMETRIZE { move = MOVE_THUNDER_SHOCK; }
|
|
PARAMETRIZE { move = MOVE_DISCHARGE; }
|
|
PARAMETRIZE { move = MOVE_NUZZLE; }
|
|
ASSUME(gBattleMoves[move].effect == EFFECT_PARALYZE_HIT);
|
|
ASSUME(0 < gBattleMoves[move].secondaryEffectChance && gBattleMoves[move].secondaryEffectChance <= 100);
|
|
PASSES_RANDOMLY(gBattleMoves[move].secondaryEffectChance, 100, RNG_SECONDARY_EFFECT);
|
|
GIVEN {
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(player, move); }
|
|
} SCENE {
|
|
STATUS_ICON(opponent, paralysis: TRUE);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Turn order is determined by priority")
|
|
{
|
|
GIVEN {
|
|
ASSUME(gBattleMoves[MOVE_QUICK_ATTACK].priority > gBattleMoves[MOVE_TACKLE].priority);
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_TACKLE); }
|
|
} SCENE {
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player);
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Turn order is determined by Speed if priority ties")
|
|
{
|
|
GIVEN {
|
|
PLAYER(SPECIES_WOBBUFFET) { Speed(2); }
|
|
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
|
|
} WHEN {
|
|
TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); }
|
|
} SCENE {
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player);
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Turn order is determined randomly if priority and Speed tie")
|
|
{
|
|
KNOWN_FAILING; // The algorithm is significantly biased.
|
|
PASSES_RANDOMLY(1, 2);
|
|
GIVEN {
|
|
PLAYER(SPECIES_WOBBUFFET) { Speed(1); }
|
|
OPPONENT(SPECIES_WOBBUFFET) { Speed(1); }
|
|
} WHEN {
|
|
TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); }
|
|
} SCENE {
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player);
|
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Critical hits occur at a 1/24 rate")
|
|
{
|
|
ASSUME(B_CRIT_CHANCE >= GEN_7);
|
|
PASSES_RANDOMLY(1, 24, RNG_CRITICAL_HIT);
|
|
GIVEN {
|
|
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")
|
|
{
|
|
ASSUME(B_CRIT_CHANCE >= GEN_7);
|
|
ASSUME(gBattleMoves[MOVE_SLASH].criticalHitStage == 1);
|
|
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
|
|
GIVEN {
|
|
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)
|
|
{
|
|
bool32 criticalHit;
|
|
PARAMETRIZE { criticalHit = FALSE; }
|
|
PARAMETRIZE { criticalHit = TRUE; }
|
|
GIVEN {
|
|
ASSUME(B_CRIT_MULTIPLIER >= GEN_6);
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(player, MOVE_SCRATCH, criticalHit: criticalHit); }
|
|
} SCENE {
|
|
HP_BAR(opponent, captureDamage: &results[i].damage);
|
|
} FINALLY {
|
|
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Critical hits do not ignore positive stat stages", s16 damage)
|
|
{
|
|
u32 move;
|
|
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
|
PARAMETRIZE { move = MOVE_HOWL; }
|
|
PARAMETRIZE { move = MOVE_TAIL_WHIP; }
|
|
GIVEN {
|
|
ASSUME(gBattleMoves[MOVE_SCRATCH].category == BATTLE_CATEGORY_PHYSICAL);
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(player, move); }
|
|
TURN { MOVE(player, MOVE_SCRATCH, criticalHit: TRUE); }
|
|
} SCENE {
|
|
HP_BAR(opponent, captureDamage: &results[i].damage);
|
|
} THEN {
|
|
if (i > 0)
|
|
EXPECT_LT(results[0].damage, results[i].damage);
|
|
}
|
|
}
|
|
|
|
SINGLE_BATTLE_TEST("Critical hits ignore negative stat stages", s16 damage)
|
|
{
|
|
u32 move;
|
|
PARAMETRIZE { move = MOVE_CELEBRATE; }
|
|
PARAMETRIZE { move = MOVE_HARDEN; }
|
|
PARAMETRIZE { move = MOVE_GROWL; }
|
|
GIVEN {
|
|
ASSUME(gBattleMoves[MOVE_SCRATCH].category == BATTLE_CATEGORY_PHYSICAL);
|
|
PLAYER(SPECIES_WOBBUFFET);
|
|
OPPONENT(SPECIES_WOBBUFFET);
|
|
} WHEN {
|
|
TURN { MOVE(opponent, move); }
|
|
TURN { MOVE(player, MOVE_SCRATCH, criticalHit: TRUE); }
|
|
} SCENE {
|
|
HP_BAR(opponent, captureDamage: &results[i].damage);
|
|
} THEN {
|
|
if (i > 0)
|
|
EXPECT_EQ(results[0].damage, results[i].damage);
|
|
}
|
|
}
|