2026-02-06 11:57:33 +01:00

396 lines
13 KiB
C

#include "global.h"
#include "test/battle.h"
// TODO: Beat Up's strikes have each an independent chance of a critical hit
// Unconfirmed by Bulbapedia
// - Technician interacion
SINGLE_BATTLE_TEST("Beat Up hits the target for each non-fainted, non-statused member in the party")
{
u32 gen;
PARAMETRIZE { gen = GEN_3; }
PARAMETRIZE { gen = GEN_5; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, gen);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_PICHU)
PLAYER(SPECIES_PIKACHU) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_RAICHU)
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
MESSAGE("The Pokémon was hit 4 time(s)!");
} THEN {
if (gen == GEN_5) {
EXPECT_EQ(gBattleStruct->beatUpSpecies[0], SPECIES_WOBBUFFET);
EXPECT_EQ(gBattleStruct->beatUpSpecies[1], SPECIES_WYNAUT);
EXPECT_EQ(gBattleStruct->beatUpSpecies[2], SPECIES_PICHU);
EXPECT_EQ(gBattleStruct->beatUpSpecies[3], SPECIES_RAICHU);
}
else {
EXPECT_EQ(gBattleStruct->beatUpSpecies[0], 0);
EXPECT_EQ(gBattleStruct->beatUpSpecies[1], 1);
EXPECT_EQ(gBattleStruct->beatUpSpecies[2], 2);
EXPECT_EQ(gBattleStruct->beatUpSpecies[3], 4);
}
}
}
SINGLE_BATTLE_TEST("Beat Up doesn't consider Comatose as a status")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_WYNAUT) { Status1(STATUS1_SLEEP); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
SINGLE_BATTLE_TEST("Beat Up doesn't list party member's name (Gen5+)")
{
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
NONE_OF {
MESSAGE("Wobbuffet's attack!");
MESSAGE("Wynaut's attack!");
}
MESSAGE("The Pokémon was hit 2 time(s)!");
}
}
SINGLE_BATTLE_TEST("Beat Up's damage is Dark-typed (Gen5+)", s16 damage)
{
bool32 targetIsFairy;
PARAMETRIZE { targetIsFairy = FALSE; }
PARAMETRIZE { targetIsFairy = TRUE; }
ASSUME(GetMoveType(MOVE_BEAT_UP) == TYPE_DARK);
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_5);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(targetIsFairy ? SPECIES_SYLVEON : SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (targetIsFairy)
EXPECT_LT(results[i].damage, results[0].damage);
}
}
SINGLE_BATTLE_TEST("Beat Up's base power is determined by each striking Pokémon (Gen5+)")
{
s16 firstHit, secondHit;
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_5);
PLAYER(SPECIES_SHUCKLE);
PLAYER(SPECIES_DEOXYS_ATTACK);
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
OPPONENT(SPECIES_BLISSEY);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &firstHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &secondHit);
} THEN {
EXPECT_LT(firstHit, secondHit);
}
}
SINGLE_BATTLE_TEST("Beat Up's damage considers stat stage changes (Gen5+)", s16 damage)
{
bool32 boosted;
PARAMETRIZE { boosted = FALSE; }
PARAMETRIZE { boosted = TRUE; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_5);
PLAYER(SPECIES_UMBREON);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { if (boosted) { MOVE(player, MOVE_SWORDS_DANCE); } else { MOVE(player, MOVE_CELEBRATE); } }
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
if (boosted)
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (boosted)
EXPECT_GT(results[i].damage, results[0].damage);
}
}
SINGLE_BATTLE_TEST("Beat Up's damage considers Huge Power and Choice Band (Gen5+)", s16 damage)
{
u16 ability;
u16 item;
PARAMETRIZE { ability = ABILITY_THICK_FAT; item = ITEM_NONE; }
PARAMETRIZE { ability = ABILITY_HUGE_POWER; item = ITEM_NONE; }
PARAMETRIZE { ability = ABILITY_THICK_FAT; item = ITEM_CHOICE_BAND; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_5);
PLAYER(SPECIES_AZUMARILL) { Ability(ability); Item(item); Moves(MOVE_BEAT_UP); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (i == 1)
EXPECT_GT(results[i].damage, results[0].damage);
if (i == 2)
EXPECT_GT(results[i].damage, results[0].damage);
}
}
SINGLE_BATTLE_TEST("Beat Up lists each party member's name")
{
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_PIKACHU);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
MESSAGE("Wobbuffet's attack!");
MESSAGE("Wynaut's attack!");
NOT MESSAGE("Wynaut's attack!");
MESSAGE("Pikachu's attack!");
}
}
SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage)
{
u16 defender = SPECIES_WOBBUFFET;
u16 type1, type2;
PARAMETRIZE { defender = SPECIES_BLISSEY; } // Normal
PARAMETRIZE { defender = SPECIES_MACHAMP; } // Fighting
PARAMETRIZE { defender = SPECIES_TORNADUS; } // Flying
PARAMETRIZE { defender = SPECIES_GRIMER; } // Poison
PARAMETRIZE { defender = SPECIES_SANDSHREW; } // Ground
PARAMETRIZE { defender = SPECIES_NOSEPASS; } // Rock
PARAMETRIZE { defender = SPECIES_CATERPIE; } // Bug
PARAMETRIZE { defender = SPECIES_DUSKULL; } // Ghost
PARAMETRIZE { defender = SPECIES_REGISTEEL; } // Steel
PARAMETRIZE { defender = SPECIES_CHIMCHAR; } // Fire
PARAMETRIZE { defender = SPECIES_WARTORTLE; } // Water
PARAMETRIZE { defender = SPECIES_TANGELA; } // Grass
PARAMETRIZE { defender = SPECIES_PIKACHU; } // Electric
PARAMETRIZE { defender = SPECIES_ABRA; } // Psychic
PARAMETRIZE { defender = SPECIES_SNORUNT; } // Ice
PARAMETRIZE { defender = SPECIES_BAGON; } // Dragon
PARAMETRIZE { defender = SPECIES_UMBREON; } // Dark
PARAMETRIZE { defender = SPECIES_SYLVEON; } // Fairy
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
type1 = GetSpeciesType(defender, 0);
type2 = GetSpeciesType(defender, 1);
ASSUME(type2 == type1 || type2 == TYPE_MYSTERY); // Ensure monotype targets
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(defender);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
NONE_OF {
MESSAGE("It's super effective!");
MESSAGE("It's not very effective...");
MESSAGE("It doesn't affect");
}
} THEN {
EXPECT_GT(results[i].damage, 0);
}
}
SINGLE_BATTLE_TEST("Beat Up's damage doesn't consider STAB")
{
s16 damage;
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
damage = 0;
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT) { HP(0); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
HP_BAR(opponent, captureDamage: &damage);
} THEN {
// Raw damage: baseAtk 33 * basePower 1 * levelFactor ((100 * 2 / 5) + 2 = 42) = 1386
// Divide by baseDef 58 -> 23 (floor); 23/50 + 2 = 2;
u16 expected = 2;
EXPECT_EQ(damage, expected);
}
}
SINGLE_BATTLE_TEST("Beat Up's base power is the same for each strike")
{
s16 firstHit, secondHit;
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
firstHit = 0;
secondHit = 0;
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WYNAUT);
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &firstHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &secondHit);
} THEN {
EXPECT_EQ(firstHit, secondHit);
}
}
SINGLE_BATTLE_TEST("Beat Up's damage is determined by each striking Pokémon's base attack and level and the target's defense")
{
s16 shuckleHit, deoxysHit;
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
shuckleHit = 0;
deoxysHit = 0;
PLAYER(SPECIES_SHUCKLE);
PLAYER(SPECIES_DEOXYS_ATTACK);
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
PLAYER(SPECIES_WYNAUT) { HP(0); }
OPPONENT(SPECIES_BLISSEY);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &shuckleHit);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &deoxysHit);
} THEN {
// Shuckle: baseAtk 10 * basePower 1 * levelFactor 42 = 420; / baseDef 10 -> 42; 42/50 + 2 = 2
u16 shuckleDmg = 2;
// Deoxys-A: baseAtk 180 * basePower 1 * levelFactor 42 = 7560; / baseDef 10 -> 756; 756/50 + 2 = 17
u16 deoxysDmg = 17;
EXPECT_EQ(shuckleHit, shuckleDmg);
EXPECT_EQ(deoxysHit, deoxysDmg);
EXPECT_LT(shuckleHit, deoxysHit);
}
}
SINGLE_BATTLE_TEST("Beat Up ignores stat stage changes", s16 damage)
{
bool32 boosted;
PARAMETRIZE { boosted = FALSE; }
PARAMETRIZE { boosted = TRUE; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { if (boosted) { MOVE(player, MOVE_SWORDS_DANCE); } else { MOVE(player, MOVE_CELEBRATE); } }
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
if (boosted)
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWORDS_DANCE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (boosted)
EXPECT_EQ(results[i].damage, results[0].damage);
}
}
SINGLE_BATTLE_TEST("Beat Up ignores Huge Power", s16 damage)
{
u16 ability;
PARAMETRIZE { ability = ABILITY_THICK_FAT; }
PARAMETRIZE { ability = ABILITY_HUGE_POWER; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
PLAYER(SPECIES_AZUMARILL) { Ability(ability); Moves(MOVE_BEAT_UP); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (ability == ABILITY_HUGE_POWER)
EXPECT_EQ(results[i].damage, results[0].damage);
}
}
SINGLE_BATTLE_TEST("Beat Up ignores Choice Band", s16 damage)
{
u16 item;
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_CHOICE_BAND; }
GIVEN {
WITH_CONFIG(B_BEAT_UP, GEN_3);
PLAYER(SPECIES_URSARING) { Item(item); Moves(MOVE_BEAT_UP); }
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_BEAT_UP); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} THEN {
if (item == ITEM_CHOICE_BAND)
EXPECT_EQ(results[i].damage, results[0].damage);
}
}