Refactor Beat Up handling for Gen 3/4 defaults, fix crit check, and expand test coverage (#8307)
This commit is contained in:
parent
152ad88436
commit
fbc640d692
@ -1804,8 +1804,8 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifcriticalhit failInstr:req
|
||||
callnative BS_JumpIfCriticalHit
|
||||
.macro jumpifnotcriticalhit failInstr:req
|
||||
callnative BS_JumpIfNotCriticalHit
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
|
||||
@ -4290,37 +4290,18 @@ BattleScript_DoEffectTeleport::
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectBeatUp::
|
||||
jumpifgenconfiglowerthan GEN_CONFIG_BEAT_UP, GEN_5, BattleScript_EffectBeatUpGen3
|
||||
goto BattleScript_EffectHit
|
||||
|
||||
BattleScript_EffectBeatUpGen3:
|
||||
attackcanceler
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
attackstring
|
||||
pause B_WAIT_TIME_SHORT
|
||||
ppreduce
|
||||
setbyte gBattleCommunication, 0
|
||||
BattleScript_BeatUpLoop::
|
||||
movevaluescleanup
|
||||
trydobeatup BattleScript_BeatUpEnd, BattleScript_ButItFailed
|
||||
trydobeatup BattleScript_MoveEnd, BattleScript_ButItFailed
|
||||
printstring STRINGID_PKMNATTACK
|
||||
critcalc
|
||||
jumpifcriticalhit BattleScript_BeatUpAttack
|
||||
manipulatedamage DMG_DOUBLED
|
||||
BattleScript_BeatUpAttack::
|
||||
adjustdamage
|
||||
attackanimation
|
||||
waitanimation
|
||||
effectivenesssound
|
||||
hitanimation BS_TARGET
|
||||
waitstate
|
||||
healthbarupdate BS_TARGET
|
||||
datahpupdate BS_TARGET
|
||||
critmessage
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
resultmessage
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryfaintmon BS_TARGET
|
||||
moveendto MOVEEND_NEXT_TARGET
|
||||
goto BattleScript_BeatUpLoop
|
||||
BattleScript_BeatUpEnd::
|
||||
end
|
||||
goto BattleScript_HitFromCritCalc
|
||||
|
||||
BattleScript_EffectDefenseCurl::
|
||||
attackcanceler
|
||||
|
||||
@ -739,7 +739,7 @@ struct BattleStruct
|
||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
||||
u16 beatUpSpecies[PARTY_SIZE];
|
||||
u16 beatUpSpecies[PARTY_SIZE]; // Species for Gen5+ Beat Up, otherwise party indexes
|
||||
u8 attackerBeforeBounce:2;
|
||||
u8 beatUpSlot:3;
|
||||
u8 pledgeMove:1;
|
||||
|
||||
@ -96,10 +96,9 @@ enum CmdVarious
|
||||
|
||||
// Cmd_manipulatedamage
|
||||
#define DMG_CHANGE_SIGN 1
|
||||
#define DMG_DOUBLED 2
|
||||
#define DMG_1_8_TARGET_HP 3
|
||||
#define DMG_FULL_ATTACKER_HP 4
|
||||
#define DMG_BIG_ROOT 5
|
||||
#define DMG_1_8_TARGET_HP 2
|
||||
#define DMG_FULL_ATTACKER_HP 3
|
||||
#define DMG_BIG_ROOT 4
|
||||
|
||||
// Cmd_jumpifcantswitch
|
||||
#define SWITCH_IGNORE_ESCAPE_PREVENTION (1 << 7)
|
||||
|
||||
@ -48,6 +48,7 @@ enum GenConfigTag
|
||||
GEN_CONFIG_PARALYZE_ELECTRIC,
|
||||
GEN_CONFIG_BADGE_BOOST,
|
||||
GEN_CONFIG_LEAF_GUARD_PREVENTS_REST,
|
||||
GEN_CONFIG_BEAT_UP,
|
||||
GEN_CONFIG_WIDE_GUARD,
|
||||
GEN_CONFIG_QUICK_GUARD,
|
||||
GEN_CONFIG_DEFOG_EFFECT_CLEARING,
|
||||
|
||||
@ -51,6 +51,7 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
|
||||
[GEN_CONFIG_PARALYZE_ELECTRIC] = B_PARALYZE_ELECTRIC,
|
||||
[GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST,
|
||||
[GEN_CONFIG_LEAF_GUARD_PREVENTS_REST] = B_LEAF_GUARD_PREVENTS_REST,
|
||||
[GEN_CONFIG_BEAT_UP] = B_BEAT_UP,
|
||||
[GEN_CONFIG_WIDE_GUARD] = B_WIDE_GUARD,
|
||||
[GEN_CONFIG_QUICK_GUARD] = B_QUICK_GUARD,
|
||||
[GEN_CONFIG_DEFOG_EFFECT_CLEARING] = B_DEFOG_EFFECT_CLEARING,
|
||||
|
||||
@ -786,7 +786,7 @@ static inline void CalcDynamicMoveDamage(struct DamageContext *ctx, u16 *medianD
|
||||
median = maximum = minimum = max(0, gBattleMons[ctx->battlerDef].hp - gBattleMons[ctx->battlerAtk].hp);
|
||||
break;
|
||||
case EFFECT_BEAT_UP:
|
||||
if (B_BEAT_UP >= GEN_5)
|
||||
if (GetGenConfig(GEN_CONFIG_BEAT_UP) >= GEN_5)
|
||||
{
|
||||
u32 partyCount = CalculatePartyCount(GetBattlerParty(ctx->battlerAtk));
|
||||
u32 i;
|
||||
|
||||
@ -9870,9 +9870,6 @@ static void Cmd_manipulatedamage(void)
|
||||
case DMG_CHANGE_SIGN:
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
|
||||
break;
|
||||
case DMG_DOUBLED:
|
||||
gBattleStruct->moveDamage[gBattlerTarget] *= 2;
|
||||
break;
|
||||
case DMG_1_8_TARGET_HP:
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxMaxHP(gBattlerTarget) / 8;
|
||||
if (gBattleStruct->moveDamage[gBattlerTarget] == 0)
|
||||
@ -12592,48 +12589,20 @@ static void Cmd_trysetfutureattack(void)
|
||||
static void Cmd_trydobeatup(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *endInstr, const u8 *failInstr);
|
||||
struct Pokemon *party = GetBattlerParty(gBattlerAttacker);
|
||||
|
||||
if (!IsBattlerAlive(gBattlerTarget))
|
||||
{
|
||||
gMultiHitCounter = 0;
|
||||
gBattlescriptCurrInstr = cmd->endInstr;
|
||||
}
|
||||
else if (gBattleStruct->beatUpSlot == 0 && gMultiHitCounter == 0)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 beforeLoop = gBattleCommunication[0];
|
||||
for (;gBattleCommunication[0] < PARTY_SIZE; gBattleCommunication[0]++)
|
||||
{
|
||||
if (GetMonData(&party[gBattleCommunication[0]], MON_DATA_HP)
|
||||
&& GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
||||
&& GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
||||
&& !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS))
|
||||
break;
|
||||
}
|
||||
|
||||
if (gBattleCommunication[0] < PARTY_SIZE)
|
||||
{
|
||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattleCommunication[0])
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = GetSpeciesBaseAttack(GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES));
|
||||
gBattleStruct->moveDamage[gBattlerTarget] *= GetMovePower(gCurrentMove);
|
||||
gBattleStruct->moveDamage[gBattlerTarget] *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2);
|
||||
gBattleStruct->moveDamage[gBattlerTarget] /= GetSpeciesBaseDefense(gBattleMons[gBattlerTarget].species);
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = (gBattleStruct->moveDamage[gBattlerTarget] / 50) + 2;
|
||||
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
||||
gBattleStruct->moveDamage[gBattlerTarget] = gBattleStruct->moveDamage[gBattlerTarget] * 15 / 10;
|
||||
|
||||
gBattleCommunication[0]++;
|
||||
}
|
||||
else if (beforeLoop != 0)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->endInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot])
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16447,11 +16416,11 @@ void BS_JumpIfMoveResultFlags(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_JumpIfCriticalHit(void)
|
||||
void BS_JumpIfNotCriticalHit(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *jumpInstr);
|
||||
|
||||
if (gSpecialStatuses[gBattlerTarget].criticalHit)
|
||||
if (!gSpecialStatuses[gBattlerTarget].criticalHit)
|
||||
gBattlescriptCurrInstr = cmd->jumpInstr;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
@ -270,12 +270,34 @@ bool32 EndOrContinueWeather(void)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Gen5+
|
||||
static u32 CalcBeatUpPower(void)
|
||||
{
|
||||
u32 species = gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++];
|
||||
return (GetSpeciesBaseAttack(species) / 10) + 5;
|
||||
}
|
||||
|
||||
static s32 CalcBeatUpDamage(struct DamageContext *ctx)
|
||||
{
|
||||
u32 partyIndex = gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++];
|
||||
struct Pokemon *party = GetBattlerParty(ctx->battlerAtk);
|
||||
u32 species = GetMonData(&party[partyIndex], MON_DATA_SPECIES);
|
||||
u32 levelFactor = GetMonData(&party[partyIndex], MON_DATA_LEVEL) * 2 / 5 + 2;
|
||||
s32 dmg = GetSpeciesBaseAttack(species);
|
||||
|
||||
dmg *= GetMovePower(ctx->move);
|
||||
dmg *= levelFactor;
|
||||
dmg /= GetSpeciesBaseDefense(gBattleMons[ctx->battlerDef].species);
|
||||
dmg = (dmg / 50) + 2;
|
||||
|
||||
if (gProtectStructs[ctx->battlerAtk].helpingHand)
|
||||
dmg = dmg * 15 / 10;
|
||||
if (ctx->isCrit)
|
||||
dmg *= 2;
|
||||
|
||||
return dmg;
|
||||
}
|
||||
|
||||
static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 abilityDef)
|
||||
{
|
||||
if (!gSpecialStatuses[battlerDef].distortedTypeMatchups
|
||||
@ -2480,11 +2502,13 @@ static enum MoveCanceler CancelerMultihitMoves(void)
|
||||
|
||||
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0)
|
||||
}
|
||||
else if (B_BEAT_UP >= GEN_5 && GetMoveEffect(gCurrentMove) == EFFECT_BEAT_UP)
|
||||
else if (GetMoveEffect(gCurrentMove) == EFFECT_BEAT_UP)
|
||||
{
|
||||
struct Pokemon* party = GetBattlerParty(gBattlerAttacker);
|
||||
int i;
|
||||
gBattleStruct->beatUpSlot = 0;
|
||||
gMultiHitCounter = 0;
|
||||
memset(gBattleStruct->beatUpSpecies, 0xFF, sizeof(gBattleStruct->beatUpSpecies));
|
||||
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
@ -2494,12 +2518,14 @@ static enum MoveCanceler CancelerMultihitMoves(void)
|
||||
&& !GetMonData(&party[i], MON_DATA_IS_EGG)
|
||||
&& !GetMonData(&party[i], MON_DATA_STATUS))
|
||||
{
|
||||
gBattleStruct->beatUpSpecies[gBattleStruct->beatUpSlot++] = species;
|
||||
if (GetGenConfig(GEN_CONFIG_BEAT_UP) >= GEN_5)
|
||||
gBattleStruct->beatUpSpecies[gMultiHitCounter] = species;
|
||||
else
|
||||
gBattleStruct->beatUpSpecies[gMultiHitCounter] = i;
|
||||
gMultiHitCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
gBattleStruct->beatUpSlot = 0;
|
||||
PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0)
|
||||
}
|
||||
else
|
||||
@ -8267,7 +8293,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx)
|
||||
basePower *= 2;
|
||||
break;
|
||||
case EFFECT_BEAT_UP:
|
||||
if (B_BEAT_UP >= GEN_5)
|
||||
if (GetGenConfig(GEN_CONFIG_BEAT_UP) >= GEN_5)
|
||||
basePower = CalcBeatUpPower();
|
||||
break;
|
||||
case EFFECT_PSYBLADE:
|
||||
@ -9508,6 +9534,12 @@ s32 DoFixedDamageMoveCalc(struct DamageContext *ctx)
|
||||
case EFFECT_FINAL_GAMBIT:
|
||||
dmg = GetNonDynamaxHP(ctx->battlerAtk);
|
||||
break;
|
||||
case EFFECT_BEAT_UP:
|
||||
if (GetGenConfig(GEN_CONFIG_BEAT_UP) < GEN_5)
|
||||
dmg = CalcBeatUpDamage(ctx);
|
||||
else
|
||||
return INT32_MAX;
|
||||
break;
|
||||
default:
|
||||
return INT32_MAX;
|
||||
}
|
||||
|
||||
@ -791,7 +791,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_BEAT_UP] =
|
||||
{
|
||||
.battleScript = (B_BEAT_UP >= GEN_5) ? BattleScript_EffectHit : BattleScript_EffectBeatUp,
|
||||
.battleScript = BattleScript_EffectBeatUp,
|
||||
.battleTvScore = 2,
|
||||
},
|
||||
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
// General
|
||||
// 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(GEN_CONFIG_BEAT_UP, gen);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_PICHU)
|
||||
@ -21,37 +29,367 @@ SINGLE_BATTLE_TEST("Beat Up hits the target for each non-fainted, non-statused m
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player);
|
||||
MESSAGE("The Pokémon was hit 4 time(s)!");
|
||||
} THEN {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Beat Up doesn't consider Comatose as a status")
|
||||
TO_DO_BATTLE_TEST("Beat Up's strikes have each an independent chance of a critical hit");
|
||||
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)!");
|
||||
}
|
||||
}
|
||||
|
||||
// B_BEAT_UP Gen2-4
|
||||
TO_DO_BATTLE_TEST("Beat Up lists each party member's name");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is typeless");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage doesn't consider STAB");
|
||||
TO_DO_BATTLE_TEST("Beat Up's last strike-only can trigger King's Rock");
|
||||
TO_DO_BATTLE_TEST("Beat Up's base power is the same for each strike");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is determined by each striking Pokémon's base attack and level and the target's defense");
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores stat stage changes"); //eg. Swords Dance
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores Huge Power");
|
||||
TO_DO_BATTLE_TEST("Beat Up ignores Choice Band");
|
||||
SINGLE_BATTLE_TEST("Beat Up doesn't list party member's name (Gen5+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_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)!");
|
||||
}
|
||||
}
|
||||
|
||||
// B_BEAT_UP Gen5+
|
||||
TO_DO_BATTLE_TEST("Beat Up doesn't list party member's name");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is Dark-typed");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage receives STAB");
|
||||
TO_DO_BATTLE_TEST("Beat Up's can trigger King's Rock on all strikes");
|
||||
TO_DO_BATTLE_TEST("Beat Up's base power is determined by each striking Pokémon");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage is determined by the user's attack and the target's defense");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers stat stage changes"); //eg. Swords Dance
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers Huge Power");
|
||||
TO_DO_BATTLE_TEST("Beat Up's damage considers Choice Band");
|
||||
SINGLE_BATTLE_TEST("Beat Up's damage is Dark-typed (Gen5+)", s16 damage)
|
||||
{
|
||||
bool32 targetIsFairy;
|
||||
PARAMETRIZE { targetIsFairy = FALSE; }
|
||||
PARAMETRIZE { targetIsFairy = TRUE; }
|
||||
|
||||
// Unconfirmed by Bulbapedia
|
||||
// - Technician interacion
|
||||
ASSUME(GetMoveType(MOVE_BEAT_UP) == TYPE_DARK);
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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(GEN_CONFIG_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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user