From 6233627a5732f2702ef8947a7e913591c3ec0d94 Mon Sep 17 00:00:00 2001 From: AgustinGDLV Date: Wed, 22 Mar 2023 17:04:05 -0700 Subject: [PATCH] more tests + fixed hp reversion issues --- data/battle_scripts_1.s | 9 +- include/battle_scripts.h | 1 + include/constants/battle_string_ids.h | 21 ++-- src/battle_dynamax.c | 13 ++- src/battle_main.c | 6 ++ src/battle_message.c | 2 + src/battle_script_commands.c | 2 +- test/dynamax.c | 143 +++++++++++++++++++++++++- 8 files changed, 181 insertions(+), 16 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 4978a770b6..8c41290fef 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7483,6 +7483,11 @@ BattleScript_StealthRockFree:: waitmessage B_WAIT_TIME_LONG return +BattleScript_SteelsurgeFree:: + printstring STRINGID_PKMNBLEWAWAYSHARPSTEEL + waitmessage B_WAIT_TIME_LONG + return + BattleScript_SpikesDefog:: printstring STRINGID_SPIKESDISAPPEAREDFROMTEAM waitmessage B_WAIT_TIME_LONG @@ -7503,8 +7508,8 @@ BattleScript_StealthRockDefog:: waitmessage B_WAIT_TIME_LONG return -BattleScript_SteelsurgeFree:: - printstring STRINGID_PKMNBLEWAWAYSHARPSTEEL +BattleScript_SteelsurgeDefog:: + printstring STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM waitmessage B_WAIT_TIME_LONG return diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 70acc0824a..eca739fb2f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -477,6 +477,7 @@ extern const u8 BattleScript_EffectSetWeather[]; extern const u8 BattleScript_EffectSetTerrain[]; extern const u8 BattleScript_SteelsurgeActivates[]; extern const u8 BattleScript_SteelsurgeFree[]; +extern const u8 BattleScript_SteelsurgeDefog[]; extern const u8 BattleScript_DamageNonTypesStarts[]; extern const u8 BattleScript_DamageNonTypesContinues[]; extern const u8 BattleScript_DefogTryHazards[]; diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index c40dd14362..5b6fa1d6a3 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -650,17 +650,18 @@ #define STRINGID_SHARPSTEELFLOATS 648 #define STRINGID_SHARPSTEELDMG 649 #define STRINGID_PKMNBLEWAWAYSHARPSTEEL 650 -#define STRINGID_TEAMTRAPPEDWITHVINES 651 -#define STRINGID_PKMNHURTBYVINES 652 -#define STRINGID_TEAMCAUGHTINVORTEX 653 -#define STRINGID_PKMNHURTBYVORTEX 654 -#define STRINGID_TEAMSURROUNDEDBYFIRE 655 -#define STRINGID_PKMNBURNINGUP 656 -#define STRINGID_TEAMSURROUNDEDBYROCKS 657 -#define STRINGID_PKMNHURTBYROCKSTHROWN 658 -#define STRINGID_MOVEBLOCKEDBYDYNAMAX 659 +#define STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM 651 +#define STRINGID_TEAMTRAPPEDWITHVINES 652 +#define STRINGID_PKMNHURTBYVINES 653 +#define STRINGID_TEAMCAUGHTINVORTEX 654 +#define STRINGID_PKMNHURTBYVORTEX 655 +#define STRINGID_TEAMSURROUNDEDBYFIRE 656 +#define STRINGID_PKMNBURNINGUP 657 +#define STRINGID_TEAMSURROUNDEDBYROCKS 658 +#define STRINGID_PKMNHURTBYROCKSTHROWN 659 +#define STRINGID_MOVEBLOCKEDBYDYNAMAX 660 -#define BATTLESTRINGS_COUNT 660 +#define BATTLESTRINGS_COUNT 661 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index fa2909b58d..cc7a76f52c 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -179,12 +179,21 @@ void PrepareBattlerForDynamax(u16 battlerId) TryBattleFormChange(battlerId, FORM_CHANGE_BATTLE_GIGANTAMAX); } -// Sets flags needed for undoing Dynamax and undoes Gigantamax forms. +// Unsets the flags used for Dynamaxing and reverts max HP if needed. void UndoDynamax(u16 battlerId) { u8 side = GetBattlerSide(battlerId); + // Revert HP if battler is Dynamaxed. + if (IsDynamaxed(battlerId)) + { + struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; + u16 mult = UQ_4_12(1.0/1.5); // placeholder + u16 hp = UQ_4_12_TO_INT((gBattleMons[battlerId].hp * mult + 1) + UQ_4_12_ROUND); // round up + SetMonData(&party[gBattlerPartyIndexes[battlerId]], MON_DATA_HP, &hp); + } + // Makes sure there are no Dynamax flags set, including on switch / faint. gBattleStruct->dynamax.dynamaxed[battlerId] = FALSE; - gBattleStruct->dynamax.dynamaxTurns[battlerId] = 0; // safety check for switch-in / faint + gBattleStruct->dynamax.dynamaxTurns[battlerId] = 0; } // Weight-based moves (and some other moves in Raids) are blocked by Dynamax. diff --git a/src/battle_main.c b/src/battle_main.c index 56fe1e5fac..055823f6c1 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5247,6 +5247,12 @@ static void HandleEndTurn_FinishBattle(void) if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) TryRestoreStolenItems(); #endif + + // Undo Dynamax HP multiplier before recalculating stats. + for (i = 0; i < gBattlersCount; ++i) + if (IsDynamaxed(i)) + UndoDynamax(i); + for (i = 0; i < PARTY_SIZE; i++) { bool8 changedForm = FALSE; diff --git a/src/battle_message.c b/src/battle_message.c index 084fb6241e..771ce162c7 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -783,6 +783,7 @@ static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell static const u8 sText_SharpSteelFloats[] = _("Sharp-pointed steel floats\naround {B_DEF_TEAM2} team!"); static const u8 sText_SharpSteelDmg[] = _("Sharp steel bit into {B_DEF_NAME_WITH_PREFIX}!"); static const u8 sText_PkmnBlewAwaySharpSteel[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nsharp steel!"); +static const u8 sText_SharpSteelDisappearedFromTeam[] = _("The sharp steel disappeared from\nthe ground around {B_ATK_TEAM2} team!"); static const u8 sText_TeamTrappedWithVines[] = _("{B_DEF_TEAM1} team got trapped\nwith vines!"); static const u8 sText_PkmnHurtByVines[] = _("{B_ATK_NAME_WITH_PREFIX} is hurt by\nG-Max Vine Lash's ferocious beating!"); static const u8 sText_TeamCaughtInVortex[] = _("{B_DEF_TEAM1} team got caught\nin a vortex of water!"); @@ -1401,6 +1402,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_TOXICSPIKESDISAPPEAREDFROMTEAM - BATTLESTRINGS_TABLE_START] = sText_ToxicSpikesDisappearedFromTeam, [STRINGID_STEALTHROCKDISAPPEAREDFROMTEAM - BATTLESTRINGS_TABLE_START] = sText_StealthRockDisappearedFromTeam, [STRINGID_STICKYWEBDISAPPEAREDFROMTEAM - BATTLESTRINGS_TABLE_START] = sText_StickyWebDisappearedFromTeam, + [STRINGID_SHARPSTEELDISAPPEAREDFROMTEAM - BATTLESTRINGS_TABLE_START] = sText_SharpSteelDisappearedFromTeam, [STRINGID_IONDELUGEON - BATTLESTRINGS_TABLE_START] = sText_IonDelugeOn, [STRINGID_TOPSYTURVYSWITCHEDSTATS - BATTLESTRINGS_TABLE_START] = sText_TopsyTurvySwitchedStats, [STRINGID_TERRAINBECOMESMISTY - BATTLESTRINGS_TABLE_START] = sText_TerrainBecomesMisty, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 78bd161f4d..5f35e4ac7e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8493,7 +8493,7 @@ static bool32 TryDefogClear(u8 battlerAtk, bool32 clear) DEFOG_CLEAR(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, BattleScript_StealthRockDefog, 0); DEFOG_CLEAR(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, BattleScript_ToxicSpikesDefog, 0); DEFOG_CLEAR(SIDE_STATUS_STICKY_WEB, stickyWebAmount, BattleScript_StickyWebDefog, 0); - DEFOG_CLEAR(SIDE_STATUS_STEELSURGE, steelsurgeAmount, BattleScript_SteelsurgeFree, 0); + DEFOG_CLEAR(SIDE_STATUS_STEELSURGE, steelsurgeAmount, BattleScript_SteelsurgeDefog, 0); #if B_DEFOG_CLEARS_TERRAIN >= GEN_8 if (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) { diff --git a/test/dynamax.c b/test/dynamax.c index 980e65f722..3c3c174228 100644 --- a/test/dynamax.c +++ b/test/dynamax.c @@ -5,7 +5,6 @@ // TEST: Max Guard protects against Transform, Block (not Mean Look), Flower Shield, Gear Up, and so on (see Bulba). // TEST: Imprison doesn't stop Max Moves. (how?) // TEST: Max Moves change type as you'd expect with Normalize, Weather Ball, etc. -// TEST: Reverting HP after Dynamax rounds up, so does Endeavor? // TEST: You use Struggle while Dynamaxed if out of PP. // Refactor code to remove dynamax.usingMaxMove? Might keep for Raids // Ditto cannot turn into a Gigantamax form. @@ -677,6 +676,47 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers both opponents' speed") } } +DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") +{ + s16 damage[4]; + GIVEN { + ASSUME(gBattleMoves[MOVE_MAX_KNUCKLE].argument == MAX_EFFECT_RAISE_TEAM_ATTACK); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_CLOSE_COMBAT, target: opponentLeft, dynamax: TRUE); \ + MOVE(playerRight, MOVE_TACKLE, target: opponentRight); } + TURN { MOVE(playerLeft, MOVE_CLOSE_COMBAT, target: opponentLeft); \ + MOVE(playerRight, MOVE_TACKLE, target: opponentRight); } + } SCENE { + // turn 1 + 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!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Wynaut's attack rose!"); + MESSAGE("Wynaut used Tackle!"); + HP_BAR(opponentRight, captureDamage: &damage[1]); + MESSAGE("Foe Wobbuffet used Celebrate!"); + MESSAGE("Foe Wynaut used Celebrate!"); + // turn 2 + 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!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Wynaut's attack rose!"); + MESSAGE("Wynaut used Tackle!"); + HP_BAR(opponentRight, captureDamage: &damage[3]); + } FINALLY { + EXPECT_GT(damage[2], damage[0]); + EXPECT_GT(damage[3], damage[1]); + } +} + SINGLE_BATTLE_TEST("(DYNAMAX) Max Flare sets up sunlight") { GIVEN { @@ -775,3 +815,104 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") MESSAGE("Wobbuffet used Max Mindstorm!"); } } + +SINGLE_BATTLE_TEST("(DYNAMAX) Max Lightning sets up Electric Terrain") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MAX_LIGHTNING].argument == MAX_EFFECT_ELECTRIC_TERRAIN); + OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_THUNDERBOLT, dynamax: TRUE); MOVE(opponent, MOVE_SPORE); } + } SCENE { + MESSAGE("Wobbuffet used Max Lightning!"); + MESSAGE("Foe Wobbuffet used Spore!"); + MESSAGE("Wobbuffet surrounds itself with electrified terrain!"); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Max Starfall sets up Misty Terrain") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_MAX_STARFALL].argument == MAX_EFFECT_MISTY_TERRAIN); + OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MOONBLAST, dynamax: TRUE); MOVE(opponent, MOVE_TOXIC); } + } SCENE { + MESSAGE("Wobbuffet used Max Starfall!"); + MESSAGE("Foe Wobbuffet used Toxic!"); + MESSAGE("Wobbuffet surrounds itself with a protective mist!"); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") +{ + GIVEN { + ASSUME(P_GEN_8_POKEMON == TRUE); + ASSUME(gBattleMoves[MOVE_G_MAX_STONESURGE].argument == MAX_EFFECT_STEALTH_ROCK); + PLAYER(SPECIES_DREDNAW); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_LIQUIDATION, dynamax: TRUE); } + TURN { SWITCH(opponent, 1); } + } SCENE { + // turn 1 + MESSAGE("Drednaw used G-Max Stonesurge!"); + MESSAGE("Pointed stones float in the air around the opposing team!"); + // turn 2 + MESSAGE("Pointed stones dug into Foe Wobbuffet!"); + } +} + +// 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); } + } WHEN { + TURN { MOVE(player, MOVE_IRON_HEAD, dynamax: TRUE); } + TURN { SWITCH(opponent, 1); } + TURN { } // wait out Dynamax + TURN { MOVE(opponent, MOVE_DEFOG); } + } SCENE { + // turn 1 + 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!"); + // turn 4 + MESSAGE("Foe Clefable used Defog!"); + MESSAGE("The sharp steel disappeared from the ground around the opposing team!"); + } FINALLY { + EXPECT_EQ(damage, 25); + } +} + +// The test below should apply to G-Max Fireball and G-Max Drum Solo, too. +SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abilities", s16 damage) +{ + u16 move; + PARAMETRIZE { move = MOVE_WATER_GUN; } + PARAMETRIZE { move = MOVE_HYDRO_CANNON; } + GIVEN { + ASSUME(P_GEN_8_POKEMON == TRUE); + ASSUME(gBattleMoves[MOVE_G_MAX_HYDROSNIPE].argument == MAX_EFFECT_FIXED_POWER); + PLAYER(SPECIES_INTELEON); + OPPONENT(SPECIES_ARCTOVISH) { Ability(ABILITY_WATER_ABSORB); } + } WHEN { + TURN { MOVE(player, move, dynamax: TRUE); } + } SCENE { + MESSAGE("Inteleon used G-Max Hydrosnipe!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +}