From 3b6389ec217d34763ebc8bbaf0ae14bd2b353929 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Thu, 11 May 2023 22:13:43 -0700 Subject: [PATCH] updated tests --- data/battle_scripts_1.s | 44 ++--- include/battle_scripts.h | 3 +- include/config.h | 2 +- include/random.h | 4 + src/battle_dynamax.c | 32 ++-- src/battle_script_commands.c | 2 +- test/dynamax.c | 308 ++++++++++++++++++++--------------- 7 files changed, 222 insertions(+), 173 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 660da5d1bc..74ff203f1e 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -470,12 +470,6 @@ BattleScript_SpikesActivates:: waitmessage B_WAIT_TIME_LONG return -BattleScript_SteelsurgeActivates:: - setsteelsurge BattleScript_MoveEnd - printfromtable gDmgHazardsStringIds - waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd - BattleScript_EffectAttackUpUserAlly: jumpifnoally BS_ATTACKER, BattleScript_EffectAttackUp attackcanceler @@ -10507,8 +10501,8 @@ BattleScript_EffectMaxMove:: waitmessage B_WAIT_TIME_LONG resultmessage waitmessage B_WAIT_TIME_LONG - tryfaintmon BS_TARGET setmaxmoveeffect + tryfaintmon BS_TARGET moveendall end @@ -10529,7 +10523,7 @@ BattleScript_RaiseSideStatsIncrement: setallytonexttarget BattleScript_RaiseSideStatsLoop BattleScript_RaiseSideStatsEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_EffectLowerStatFoes:: savetarget @@ -10548,26 +10542,26 @@ BattleScript_LowerSideStatsIncrement: setallytonexttarget BattleScript_LowerSideStatsLoop BattleScript_LowerSideStatsEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_EffectSetWeather:: playanimation 0, B_ANIM_MAX_SET_WEATHER printfromtable gMoveWeatherChangeStringIds waitmessage B_WAIT_TIME_LONG call BattleScript_ActivateWeatherAbilities - return + goto BattleScript_MoveEnd BattleScript_EffectSetTerrain:: printfromtable gTerrainStringIds waitmessage B_WAIT_TIME_LONG playanimation BS_ATTACKER, B_ANIM_RESTORE_BG call BattleScript_ActivateTerrainEffects - return + goto BattleScript_MoveEnd BattleScript_DamageNonTypesStarts:: printfromtable gDamageNonTypesStartStringIds waitmessage B_WAIT_TIME_LONG - return + goto BattleScript_MoveEnd BattleScript_DamageNonTypesContinues:: setbyte gBattleCommunication, 0 @@ -10596,7 +10590,7 @@ BattleScript_EffectTryReducePP:: tryspiteppreduce BattleScript_MoveEnd printstring STRINGID_PKMNREDUCEDPP waitmessage B_WAIT_TIME_LONG - return + goto BattleScript_MoveEnd BattleScript_EffectStatus1Foes:: savetarget @@ -10615,7 +10609,7 @@ BattleScript_Status1FoesIncrement: setallytonexttarget BattleScript_Status1FoesLoop BattleScript_Status1FoesEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_EffectStatus2Foes:: savetarget @@ -10634,7 +10628,7 @@ BattleScript_Status2FoesIncrement: BattleScript_Status2FoesEnd: restoretarget jumpifbyte CMP_EQUAL, gBattleCommunication + 1, 1, BattleScript_PrintCoinsScattered @ Gold Rush - return + goto BattleScript_MoveEnd BattleScript_DoConfuseAnim: status2animation BS_EFFECT_BATTLER, STATUS2_CONFUSION @@ -10671,7 +10665,7 @@ BattleScript_RaiseCritAlliesIncrement: setallytonexttarget BattleScript_RaiseCritAlliesLoop BattleScript_RaiseCritAlliesEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_EffectHealOneSixthAllies:: jumpifteamhealthy BS_ATTACKER, BattleScript_MoveEnd @@ -10690,7 +10684,7 @@ BattleScript_HealOneSixthAlliesIncrement: setallytonexttarget BattleScript_HealOneSixthAlliesLoop BattleScript_HealOneSixthAlliesEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_EffectCureStatusAllies:: jumpifteamhealthy BS_ATTACKER, BattleScript_MoveEnd @@ -10704,7 +10698,7 @@ BattleScript_CureStatusAlliesIncrement: setallytonexttarget BattleScript_CureStatusAlliesLoop BattleScript_CureStatusAlliesEnd: restoretarget - return + goto BattleScript_MoveEnd BattleScript_CureStatusActivate: curestatus BS_TARGET @@ -10730,7 +10724,19 @@ BattleScript_RecycleBerriesAlliesIncrement: setallytonexttarget BattleScript_RecycleBerriesAlliesLoop BattleScript_RecycleBerriesAlliesEnd: restoretarget - return + goto BattleScript_MoveEnd + +BattleScript_EffectStonesurge:: + setstealthrock BattleScript_MoveEnd + printfromtable gDmgHazardsStringIds + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd + +BattleScript_EffectSteelsurge:: + setsteelsurge BattleScript_MoveEnd + printfromtable gDmgHazardsStringIds + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd @@@ END MAX MOVES @@@ diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 43f33dcb9c..69c1c17c05 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -485,7 +485,8 @@ extern const u8 BattleScript_EffectRaiseStatAllies[]; extern const u8 BattleScript_EffectLowerStatFoes[]; extern const u8 BattleScript_EffectSetWeather[]; extern const u8 BattleScript_EffectSetTerrain[]; -extern const u8 BattleScript_SteelsurgeActivates[]; +extern const u8 BattleScript_EffectStonesurge[]; +extern const u8 BattleScript_EffectSteelsurge[]; extern const u8 BattleScript_SteelsurgeFree[]; extern const u8 BattleScript_SteelsurgeDefog[]; extern const u8 BattleScript_DamageNonTypesStarts[]; diff --git a/include/config.h b/include/config.h index 9412c8f426..2ad84f29cd 100644 --- a/include/config.h +++ b/include/config.h @@ -6,7 +6,7 @@ // still has them in the ROM. This is because the developers forgot // to define NDEBUG before release, however this has been changed as // Ruby's actual debug build does not use the AGBPrint features. -// #define NDEBUG +#define NDEBUG // To enable printf debugging, comment out "#define NDEBUG". This allows // the various AGBPrint functions to be used. (See include/gba/isagbprint.h). diff --git a/include/random.h b/include/random.h index e7c2a3e284..44900a2563 100644 --- a/include/random.h +++ b/include/random.h @@ -67,6 +67,10 @@ enum RandomTag RNG_STATIC, RNG_STENCH, RNG_TRI_ATTACK, + RNG_G_MAX_STUN_SHOCK, + RNG_G_MAX_BEFUDDLE, + RNG_G_MAX_REPLENISH, + RNG_G_MAX_SNOOZE, }; #define RandomWeighted(tag, ...) \ diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index c2de1842a8..c2bf7949e3 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -525,19 +525,14 @@ u32 GetMaxMoveStatusEffect(u16 move) case MAX_EFFECT_POISON_FOES: return STATUS1_POISON; case MAX_EFFECT_POISON_PARALYZE_FOES: - if (Random() % 2) - return STATUS1_POISON; - else - return STATUS1_PARALYSIS; + { + static const u8 sStunShockEffects[] = {STATUS1_PARALYSIS, STATUS1_POISON}; + return RandomElement(RNG_G_MAX_STUN_SHOCK, sStunShockEffects); + } case MAX_EFFECT_EFFECT_SPORE_FOES: { - u8 effect = Random() % 3; - if (effect == 0) - return STATUS1_PARALYSIS; - else if (effect == 1) - return STATUS1_POISON; - else - return STATUS1_SLEEP; + static const u8 sBefuddleEffects[] = {STATUS1_PARALYSIS, STATUS1_POISON, STATUS1_SLEEP}; + return RandomElement(RNG_G_MAX_BEFUDDLE, sBefuddleEffects); } // Status 2 case MAX_EFFECT_CONFUSE_FOES: @@ -705,7 +700,7 @@ u16 SetMaxMoveEffect(u16 move) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_POINTEDSTONESFLOAT; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_StealthRockActivates; + gBattlescriptCurrInstr = BattleScript_EffectStonesurge; effect++; } break; @@ -714,7 +709,7 @@ u16 SetMaxMoveEffect(u16 move) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SHARPSTEELFLOATS; BattleScriptPush(gBattlescriptCurrInstr + 1); - gBattlescriptCurrInstr = BattleScript_SteelsurgeActivates; + gBattlescriptCurrInstr = BattleScript_EffectSteelsurge; effect++; } break; @@ -787,9 +782,11 @@ u16 SetMaxMoveEffect(u16 move) break; } case MAX_EFFECT_YAWN_FOE: + { + static const u8 sSnoozeEffects[] = {TRUE, FALSE}; if (!(gStatuses3[gBattlerTarget] & STATUS3_YAWN) && CanSleep(gBattlerTarget) - && Random() % 2) // 50% chance of success + && RandomElement(RNG_G_MAX_SNOOZE, sSnoozeEffects)) // 50% chance of success { gStatuses3[gBattlerTarget] |= STATUS3_YAWN_TURN(2); BattleScriptPush(gBattlescriptCurrInstr + 1); @@ -797,6 +794,7 @@ u16 SetMaxMoveEffect(u16 move) effect++; } break; + } case MAX_EFFECT_SPITE: if (gLastMoves[gBattlerTarget] != MOVE_NONE && gLastMoves[gBattlerTarget] != MOVE_UNAVAILABLE) @@ -850,14 +848,16 @@ u16 SetMaxMoveEffect(u16 move) effect++; break; case MAX_EFFECT_RECYCLE_BERRIES: - if (Random() % 2) // 50% chance of success + { + static const u8 sReplenishEffects[] = {TRUE, FALSE}; + if (RandomElement(RNG_G_MAX_REPLENISH, sReplenishEffects)) // 50% chance of success { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_EffectRecycleBerriesAllies; effect++; } break; - + } } return effect; } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9c6b788205..72961abaa0 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -13495,7 +13495,7 @@ static void Cmd_painsplitdmgcalc(void) if (!(DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))) { s32 hpDiff = (gBattleMons[gBattlerAttacker].hp + GetNonDynamaxHP(gBattlerTarget)) / 2; - s32 painSplitHp = gBattleMoveDamage = gBattleMons[gBattlerTarget].hp - hpDiff; + s32 painSplitHp = gBattleMoveDamage = GetNonDynamaxHP(gBattlerTarget) - hpDiff; u8 *storeLoc = (void *)(&gBattleScripting.painSplitHp); storeLoc[0] = (painSplitHp); diff --git a/test/dynamax.c b/test/dynamax.c index 8540387be0..9704c6a07e 100644 --- a/test/dynamax.c +++ b/test/dynamax.c @@ -13,12 +13,10 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x", u16 hp) } WHEN { TURN { MOVE(player, MOVE_TACKLE, dynamax: dynamax); MOVE(opponent, MOVE_CELEBRATE); } } SCENE { - if (dynamax) - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); - MESSAGE("Wobbuffet used Max Strike!"); + if (dynamax) { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); - MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("Wobbuffet used Max Strike!"); + } MESSAGE("Foe Wobbuffet used Celebrate!"); } THEN { results[i].hp = player->hp; @@ -520,91 +518,99 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot use Max Guard while holdi // Anything that is conditional based off max HP still uses gBattleMons[battler].maxHP. // Below are some tests, but very far from all encompassing: -SINGLE_BATTLE_TEST("(DYNAMAX) Endeavor uses a Pokemon's non-Dynamax HP") +SINGLE_BATTLE_TEST("(DYNAMAX) Endeavor uses a Pokemon's non-Dynamax HP", s16 damage) { - s16 damage; + bool32 dynamax; + PARAMETRIZE { dynamax = TRUE; } + PARAMETRIZE { dynamax = FALSE; } GIVEN { ASSUME(gBattleMoves[MOVE_ENDEAVOR].effect == EFFECT_ENDEAVOR); - PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); Speed(50); } - OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(100); Speed(100); } + PLAYER(SPECIES_WOBBUFFET) { Speed(50); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { - TURN { MOVE(opponent, MOVE_ENDEAVOR); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(opponent, MOVE_ENDEAVOR); MOVE(player, MOVE_TACKLE, dynamax: dynamax); } } SCENE { MESSAGE("Foe Wobbuffet used Endeavor!"); - HP_BAR(player, captureDamage: &damage); + HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_EQ(damage, 99); // difference between foe's HP and player's non-dynamax HP + EXPECT_EQ(results[0].damage, results[1].damage); } } -SINGLE_BATTLE_TEST("(DYNAMAX) Super Fang uses a Pokemon's non-Dynamax HP") +SINGLE_BATTLE_TEST("(DYNAMAX) Super Fang uses a Pokemon's non-Dynamax HP", s16 damage) { - s16 damage; + bool32 dynamax; + PARAMETRIZE { dynamax = TRUE; } + PARAMETRIZE { dynamax = FALSE; } GIVEN { ASSUME(gBattleMoves[MOVE_SUPER_FANG].effect == EFFECT_SUPER_FANG); - PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); Speed(50); } + PLAYER(SPECIES_WOBBUFFET) { Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } } WHEN { - TURN { MOVE(opponent, MOVE_SUPER_FANG); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(opponent, MOVE_SUPER_FANG); MOVE(player, MOVE_TACKLE, dynamax: dynamax); } } SCENE { MESSAGE("Foe Wobbuffet used Super Fang!"); - HP_BAR(player, captureDamage: &damage); + HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_EQ(damage, 25); + EXPECT_EQ(results[0].damage, results[1].damage); } } -SINGLE_BATTLE_TEST("(DYNAMAX) Pain Split uses a Pokemon's non-Dynamax HP") +SINGLE_BATTLE_TEST("(DYNAMAX) Pain Split uses a Pokemon's non-Dynamax HP", s16 damage) { - s16 damage; + bool32 dynamax; + PARAMETRIZE { dynamax = TRUE; } + PARAMETRIZE { dynamax = FALSE; } GIVEN { ASSUME(gBattleMoves[MOVE_PAIN_SPLIT].effect == EFFECT_PAIN_SPLIT); - PLAYER(SPECIES_WOBBUFFET) { HP(60); MaxHP(100); Speed(50); } - OPPONENT(SPECIES_WOBBUFFET) { HP(40); MaxHP(100); Speed(100); } + PLAYER(SPECIES_WOBBUFFET) { Speed(50); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { - TURN { MOVE(opponent, MOVE_PAIN_SPLIT); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(opponent, MOVE_PAIN_SPLIT); MOVE(player, MOVE_TACKLE, dynamax: dynamax); } } SCENE { MESSAGE("Foe Wobbuffet used Pain Split!"); - HP_BAR(player, captureDamage: &damage); + HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_EQ(damage, 10); + EXPECT_EQ(results[0].damage, results[1].damage); } } -SINGLE_BATTLE_TEST("(DYNAMAX) Sitrus Berries heal based on a Pokemon's non-Dynamax HP") +SINGLE_BATTLE_TEST("(DYNAMAX) Sitrus Berries heal based on a Pokemon's non-Dynamax HP", s16 damage) { - s16 damage; + bool32 dynamax; + PARAMETRIZE { dynamax = TRUE; } + PARAMETRIZE { dynamax = FALSE; } GIVEN { ASSUME(I_SITRUS_BERRY_HEAL >= GEN_4); ASSUME(gItems[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP); - PLAYER(SPECIES_WOBBUFFET) { HP(60); MaxHP(100); Speed(50); Item(ITEM_SITRUS_BERRY); } - OPPONENT(SPECIES_WOBBUFFET) { HP(40); MaxHP(100); Speed(100); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); } } WHEN { - TURN { MOVE(opponent, MOVE_PAIN_SPLIT); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(opponent, MOVE_FLING); MOVE(player, MOVE_TACKLE, dynamax: dynamax); } } SCENE { - MESSAGE("Foe Wobbuffet used Pain Split!"); - HP_BAR(player); MESSAGE("Wobbuffet's Sitrus Berry restored health!"); - HP_BAR(player, captureDamage: &damage); + HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_EQ(damage, 25); + EXPECT_EQ(results[0].damage, results[1].damage); } } -SINGLE_BATTLE_TEST("(DYNAMAX) Heal Pulse heals based on a Pokemon's non-Dynamax HP") +SINGLE_BATTLE_TEST("(DYNAMAX) Heal Pulse heals based on a Pokemon's non-Dynamax HP", s16 damage) { - s16 damage; + bool32 dynamax; + PARAMETRIZE { dynamax = TRUE; } + PARAMETRIZE { dynamax = FALSE; } GIVEN { ASSUME(gBattleMoves[MOVE_HEAL_PULSE].effect == EFFECT_HEAL_PULSE); - PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); Speed(50); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); Speed(100); } } WHEN { - TURN { MOVE(opponent, MOVE_HEAL_PULSE); MOVE(player, MOVE_TACKLE, dynamax: TRUE); } + TURN { MOVE(opponent, MOVE_HEAL_PULSE); MOVE(player, MOVE_TACKLE, dynamax: dynamax); } } SCENE { MESSAGE("Foe Wobbuffet used Heal Pulse!"); - HP_BAR(player, captureDamage: &damage); + HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { - EXPECT_EQ(damage, 50); + EXPECT_EQ(results[0].damage, results[1].damage); } } @@ -624,11 +630,11 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") MESSAGE("Foe Wobbuffet used Tackle!"); MESSAGE("Wobbuffet used Max Strike!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); // turn 2 MESSAGE("Wobbuffet used Max Strike!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); } } @@ -637,7 +643,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") DOUBLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers both opponents' speed") { GIVEN { - // Fails? ASSUME(GetMaxMove(B_POSITION_PLAYER_LEFT, MOVE_TACKLE) == MOVE_MAX_STRIKE); ASSUME(gBattleMoves[MOVE_MAX_STRIKE].argument == MAX_EFFECT_LOWER_SPEED); PLAYER(SPECIES_WOBBUFFET) { Speed(80); } PLAYER(SPECIES_WOBBUFFET) { Speed(79); } @@ -656,15 +661,15 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers both opponents' speed") MESSAGE("Foe Wobbuffet used Tackle!"); MESSAGE("Wobbuffet used Max Strike!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); // turn 2 MESSAGE("Wobbuffet used Max Strike!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); - MESSAGE("Foe Wobbuffet's speed fell!"); + MESSAGE("Foe Wobbuffet's Speed fell!"); MESSAGE("Foe Wobbuffet used Tackle!"); MESSAGE("Foe Wobbuffet used Tackle!"); } @@ -690,9 +695,9 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") MESSAGE("Wobbuffet used Max Knuckle!"); HP_BAR(opponentLeft, captureDamage: &damage[0]); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); - MESSAGE("Wobbuffet's attack rose!"); + MESSAGE("Wobbuffet's Attack rose!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); - MESSAGE("Wynaut's attack rose!"); + MESSAGE("Wynaut's Attack rose!"); MESSAGE("Wynaut used Tackle!"); HP_BAR(opponentRight, captureDamage: &damage[1]); MESSAGE("Foe Wobbuffet used Celebrate!"); @@ -701,12 +706,12 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") MESSAGE("Wobbuffet used Max Knuckle!"); HP_BAR(opponentLeft, captureDamage: &damage[2]); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); - MESSAGE("Wobbuffet's attack rose!"); + MESSAGE("Wobbuffet's Attack rose!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); - MESSAGE("Wynaut's attack rose!"); + MESSAGE("Wynaut's Attack rose!"); MESSAGE("Wynaut used Tackle!"); HP_BAR(opponentRight, captureDamage: &damage[3]); - } FINALLY { + } THEN { EXPECT_GT(damage[2], damage[0]); EXPECT_GT(damage[3], damage[1]); } @@ -863,13 +868,12 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") // The test below also tests that sharp steel does type-based damage and can be Defogged away. SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Steelsurge sets up sharp steel") { - s16 damage; GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); ASSUME(gBattleMoves[MOVE_G_MAX_STEELSURGE].argument == MAX_EFFECT_STEELSURGE); PLAYER(SPECIES_COPPERAJAH); OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_CLEFABLE) { MaxHP(100); } + OPPONENT(SPECIES_HATTERENE); } WHEN { TURN { MOVE(player, MOVE_IRON_HEAD, dynamax: TRUE); } TURN { SWITCH(opponent, 1); } @@ -880,13 +884,13 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Steelsurge sets up sharp steel") MESSAGE("Copperajah used G-Max Steelsurge!"); MESSAGE("Sharp-pointed steel floats around the opposing team!"); // turn 2 - HP_BAR(opponent, captureDamage: &damage); - MESSAGE("Sharp steel bit into Foe Clefable!"); + MESSAGE("2 sent out Hatterene!"); + MESSAGE("Sharp steel bit into Foe Hatterene!"); // turn 4 - MESSAGE("Foe Clefable used Defog!"); + MESSAGE("Foe Hatterene used Defog!"); MESSAGE("The sharp steel disappeared from the ground around the opposing team!"); - } FINALLY { - EXPECT_EQ(damage, 25); + } THEN { + EXPECT_MUL_EQ(opponent->maxHP, Q_4_12(0.75), opponent->hp); } } @@ -932,9 +936,15 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Volt Crash paralyzes both opponents") } } +// G-Max Stun Shock can apply different statuses to each opponent, but this isn't +// compatible with the test RNG set-up. DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponents") { - KNOWN_FAILING; // RNG issues + u8 statusAnim; + u16 species; + u32 rng; + PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = STATUS1_PARALYSIS; } + PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); ASSUME(gBattleMoves[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES); @@ -943,22 +953,36 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); } WHEN { - TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, dynamax: TRUE); } + TURN { MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft, dynamax: TRUE, \ + WITH_RNG(RNG_G_MAX_STUN_SHOCK, rng)); } } SCENE { MESSAGE("Toxtricity used G-Max Stun Shock!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentLeft); - STATUS_ICON(opponentLeft, poison: TRUE); - MESSAGE("Foe Wobbuffet was poisoned!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentRight); - STATUS_ICON(opponentRight, paralysis: TRUE); - MESSAGE("Foe Wynaut is paralyzed! It may be unable to move!"); + // opponent left + ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentLeft); + if (statusAnim == B_ANIM_STATUS_PSN) { + STATUS_ICON(opponentLeft, poison: TRUE); + MESSAGE("Foe Wobbuffet was poisoned!"); + } + else { + STATUS_ICON(opponentLeft, paralysis: TRUE); + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); + } + // opponent right + ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentRight); + if (statusAnim == B_ANIM_STATUS_PSN) { + STATUS_ICON(opponentRight, poison: TRUE); + MESSAGE("Foe Wynaut was poisoned!"); + } + else { + STATUS_ICON(opponentRight, paralysis: TRUE); + MESSAGE("Foe Wynaut is paralyzed! It may be unable to move!"); + } } } // This test extends to G-Max Befuddle, too. DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock chooses statuses before considering immunities") { - KNOWN_FAILING; // RNG issues GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); ASSUME(gBattleMoves[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES); @@ -967,53 +991,72 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock chooses statuses before consideri OPPONENT(SPECIES_GARBODOR); OPPONENT(SPECIES_TRUBBISH); } WHEN { - TURN { MOVE(playerLeft, MOVE_NUZZLE, target: opponentLeft, dynamax: TRUE); } + TURN { MOVE(playerLeft, MOVE_NUZZLE, target: opponentLeft, dynamax: TRUE, \ + WITH_RNG(RNG_G_MAX_STUN_SHOCK, STATUS1_POISON)); } } SCENE { MESSAGE("Toxtricity used G-Max Stun Shock!"); NONE_OF { - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentLeft); + // opponent left + STATUS_ICON(opponentLeft, poison: TRUE); + MESSAGE("Foe Garbodor was poisoned!"); + STATUS_ICON(opponentLeft, paralysis: TRUE); + MESSAGE("Foe Garbodor is paralyzed! It may be unable to move!"); + // opponent right + STATUS_ICON(opponentRight, poison: TRUE); + MESSAGE("Foe Trubbish was poisoned!"); + STATUS_ICON(opponentRight, paralysis: TRUE); + MESSAGE("Foe Trubbish is paralyzed! It may be unable to move!"); } - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentRight); - MESSAGE("Foe Trubbish is paralyzed! It may be unable to move!"); - STATUS_ICON(opponentRight, paralysis: TRUE); - } FINALLY { - EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].status1, STATUS1_NONE); } } DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both opponents") { - KNOWN_FAILING; // RNG issues + u8 statusAnim; + u16 species; + u32 rng; + PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = STATUS1_PARALYSIS; } + PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } + PARAMETRIZE { statusAnim = B_ANIM_STATUS_SLP; rng = STATUS1_SLEEP; } GIVEN { - RNGSeed(0x10000); ASSUME(gBattleMoves[MOVE_G_MAX_BEFUDDLE].argument == MAX_EFFECT_EFFECT_SPORE_FOES); PLAYER(SPECIES_BUTTERFREE); PLAYER(SPECIES_CATERPIE); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(playerLeft, MOVE_BUG_BITE, target: opponentLeft, dynamax: TRUE); } - TURN { SWITCH(opponentLeft, 2); SWITCH(opponentRight, 3); \ - MOVE(playerLeft, MOVE_BUG_BITE, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_BUG_BITE, target: opponentLeft, dynamax: TRUE, + WITH_RNG(RNG_G_MAX_BEFUDDLE, rng)); } } SCENE { - // turn 1 MESSAGE("Butterfree used G-Max Befuddle!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentLeft); - STATUS_ICON(opponentLeft, poison: TRUE); - MESSAGE("Foe Wobbuffet was poisoned!"); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponentRight); - STATUS_ICON(opponentRight, sleep: TRUE); - MESSAGE("Foe Wobbuffet fell asleep!"); - // turn 2 - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponentLeft); - MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); - STATUS_ICON(opponentLeft, paralysis: TRUE); - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponentRight); - MESSAGE("Foe Wobbuffet was poisoned!"); - STATUS_ICON(opponentRight, poison: TRUE); + // opponent left + ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentLeft); + if (statusAnim == B_ANIM_STATUS_PSN) { + STATUS_ICON(opponentLeft, poison: TRUE); + MESSAGE("Foe Wobbuffet was poisoned!"); + } + else if (statusAnim == B_ANIM_STATUS_PRZ) { + STATUS_ICON(opponentLeft, paralysis: TRUE); + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); + } + else { + STATUS_ICON(opponentLeft, sleep: TRUE); + MESSAGE("Foe Wobbuffet fell asleep!"); + } + // opponent right + ANIMATION(ANIM_TYPE_STATUS, statusAnim, opponentRight); + if (statusAnim == B_ANIM_STATUS_PSN) { + STATUS_ICON(opponentRight, poison: TRUE); + MESSAGE("Foe Wobbuffet was poisoned!"); + } + else if (statusAnim == B_ANIM_STATUS_PRZ) { + STATUS_ICON(opponentRight, paralysis: TRUE); + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); + } + else { + STATUS_ICON(opponentRight, sleep: TRUE); + MESSAGE("Foe Wobbuffet fell asleep!"); + } } } @@ -1073,7 +1116,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possibl MESSAGE("Foe Wobbuffet fell in love!"); NONE_OF { ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_INFATUATION, opponentRight); - MESSAGE("Foe Wobbuffet became confused!"); + MESSAGE("Foe Wobbuffet fell in love!"); } } } @@ -1092,8 +1135,8 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Terror traps both opponents") MESSAGE("Gengar used G-Max Terror!"); MESSAGE("Foe Wobbuffet can't escape now!"); MESSAGE("Foe Wobbuffet can't escape now!"); - } FINALLY { // Can't find good way to test trapping - EXPECT(gBattleMons[B_POSITION_OPPONENT_LEFT].status2 & STATUS2_ESCAPE_PREVENTION); + } THEN { // Can't find good way to test trapping + EXPECT(opponentLeft->status2 & STATUS2_ESCAPE_PREVENTION); } } @@ -1175,16 +1218,14 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Wildfire sets a field effect that damages no HP_BAR(opponentRight); MESSAGE("Foe Wynaut is burning up within G-Max Wildfire's flames!"); } - } FINALLY { + } THEN { EXPECT_EQ(damage, 100); } } -// This should probably be tested to only occur 50% of the time. -// I had some problems specific to Teatime with this where Snorlax stored -// the used berry in usedHeldItem, while Munchlax stored it in changedItem. -DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries") +DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries 50\% of the time") { + PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH); GIVEN { ASSUME(gBattleMoves[MOVE_G_MAX_REPLENISH].argument == MAX_EFFECT_RECYCLE_BERRIES); PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); } @@ -1199,10 +1240,10 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries") TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft, dynamax: TRUE); } } SCENE { // turn 1 - MESSAGE("Using Apicot Berry, the sp. defense of Snorlax rose!"); - MESSAGE("Using Apicot Berry, the sp. defense of Munchlax rose!"); - MESSAGE("Using Apicot Berry, the sp. defense of Foe Wobbuffet rose!"); - MESSAGE("Using Apicot Berry, the sp. defense of Foe Wobbuffet rose!"); + MESSAGE("Using Apicot Berry, the Sp. Def of Snorlax rose!"); + MESSAGE("Using Apicot Berry, the Sp. Def of Munchlax rose!"); + MESSAGE("Using Apicot Berry, the Sp. Def of Foe Wobbuffet rose!"); + MESSAGE("Using Apicot Berry, the Sp. Def of Foe Wobbuffet rose!"); // turn 2 MESSAGE("Snorlax used G-Max Replenish!"); MESSAGE("Snorlax found one Apicot Berry!"); @@ -1212,7 +1253,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Snooze makes only the target drowsy") { - KNOWN_FAILING; // RNG issues + PASSES_RANDOMLY(1, 2, RNG_G_MAX_SNOOZE); GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); ASSUME(gBattleMoves[MOVE_G_MAX_SNOOZE].argument == MAX_EFFECT_YAWN_FOE); @@ -1227,15 +1268,10 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Snooze makes only the target drowsy") // turn 1 MESSAGE("Grimmsnarl used G-Max Snooze!"); MESSAGE("Grimmsnarl made Foe Blissey drowsy!"); - NONE_OF { MESSAGE("Grimmsnarl made Foe Chansey drowsy!"); } // turn 2 ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponentLeft); MESSAGE("Foe Blissey fell asleep!"); STATUS_ICON(opponentLeft, sleep: TRUE); - NONE_OF { - ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponentRight); - STATUS_ICON(opponentRight, sleep: TRUE); - } } } @@ -1245,20 +1281,19 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health") GIVEN { ASSUME(P_GEN_8_POKEMON == TRUE); ASSUME(gBattleMoves[MOVE_G_MAX_FINALE].argument == MAX_EFFECT_HEAL_TEAM); - PLAYER(SPECIES_ALCREMIE) { HP(200); MaxHP(300); } - PLAYER(SPECIES_MILCERY) { HP(200); MaxHP(300); } + PLAYER(SPECIES_ALCREMIE) { HP(1); } + PLAYER(SPECIES_MILCERY) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(playerLeft, MOVE_MOONBLAST, target: opponentLeft, dynamax: TRUE); } } SCENE { - // turn 1 MESSAGE("Alcremie used G-Max Finale!"); HP_BAR(playerLeft, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); - } FINALLY { - EXPECT_EQ(damage1, -75); // heals based on Dynamax HP - EXPECT_EQ(damage2, -50); + } THEN { + EXPECT_MUL_EQ(playerLeft->hp - 1, Q_4_12(6), playerLeft->maxHP); // heals based on Dynamax HP + EXPECT_MUL_EQ(playerRight->hp - 1, Q_4_12(6), playerRight->maxHP); } } @@ -1283,7 +1318,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions") } } -// This test should apply to G-Max Sandblast, too. +// This test applies to G-Max Sandblast, too. DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin") { s16 damage1, damage2; @@ -1316,7 +1351,8 @@ 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") { s16 damage1, damage2; - KNOWN_FAILING; + u32 j; + KNOWN_FAILING; // Debug printing confirms Machop is at +5 crit stages. Not sure what's broken. GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_6); ASSUME(gBattleMoves[MOVE_G_MAX_CHI_STRIKE].argument == MAX_EFFECT_CRIT_PLUS); @@ -1325,20 +1361,22 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(playerLeft, MOVE_FORCE_PALM, target: opponentLeft, dynamax: TRUE); \ + TURN { MOVE(playerLeft, MOVE_FORCE_PALM, target: opponentLeft, dynamax: TRUE); } + TURN { MOVE(playerLeft, MOVE_FORCE_PALM, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_FORCE_PALM, target: opponentLeft); \ MOVE(playerRight, MOVE_FOCUS_ENERGY); } TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } } SCENE { - // turn 1 - MESSAGE("Machamp used G-Max Chi Strike!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); - MESSAGE("Machamp is getting pumped!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); - MESSAGE("Machop is getting pumped!"); - MESSAGE("Machop used Focus Energy!"); - MESSAGE("Machop is getting pumped!"); - // turn 2 - MESSAGE("Machop used Tackle!"); // Machop is at +3 crit stages, 100% crit chance + // turn 1 - 3 + for (j = 0; j < 3; ++j) { + MESSAGE("Machamp used G-Max Chi Strike!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Machamp is getting pumped!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Machop is getting pumped!"); + } + // turn 4 + MESSAGE("Machop used Tackle!"); // Machop is at +5 crit stages MESSAGE("A critical hit!"); } } @@ -1362,7 +1400,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Depletion takes away 2 PP from the target's } } -// This test should apply to G-Max Rapid Flow, too. +// This test applies to G-Max Rapid Flow, too. DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max One Blow bypasses Max Guard for full damage", s16 damage) { bool32 protect;