From ecf134d34d6067689c49a8a53b30b85743514557 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 12 Jul 2024 12:30:26 +0200 Subject: [PATCH] Refactor weather damage script --- asm/macros/battle_script.inc | 2 +- data/battle_anim_scripts.s | 7 +++ data/battle_scripts_1.s | 35 ++++++--------- include/battle_scripts.h | 2 + include/config/general.h | 2 +- include/constants/battle_anim.h | 1 + src/battle_script_commands.c | 74 ++---------------------------- src/battle_util.c | 80 +++++++++++++++++++++++++++------ test/battle/weather/hail.c | 32 +++++++++++++ 9 files changed, 127 insertions(+), 108 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index ad1338f426ed..bda2a578d7bb 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -838,7 +838,7 @@ .byte 0x95 .endm - .macro weatherdamage + .macro unused_96 .byte 0x96 .endm diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index e98274d2f6c1..259d18142c63 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -85,6 +85,7 @@ gBattleAnims_General:: .4byte General_Fog @ B_ANIM_FOG_CONTINUES .4byte General_TeraCharge @ B_ANIM_TERA_CHARGE .4byte General_TeraActivate @ B_ANIM_TERA_ACTIVATE + .4byte General_SimpleHeal @ B_ANIM_SIMPLE_HEAL .align 2 gBattleAnims_Special:: @@ -27347,6 +27348,12 @@ General_WishHeal: createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_BG, 3, 10, 0, RGB_BLACK end +General_SimpleHeal: + loadspritegfx ANIM_TAG_BLUE_STAR + call HealingEffect + waitforvisualfinish + end + General_IllusionOff: monbg ANIM_TARGET createvisualtask AnimTask_TransformMon, 2, 1, 0 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index bc504629be36..0b8abac19c86 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -5921,33 +5921,22 @@ BattleScript_DamagingWeatherContinues:: waitmessage B_WAIT_TIME_LONG playanimation_var BS_ATTACKER, sB_ANIM_ARG1 setbyte gBattleCommunication, 0 -BattleScript_DamagingWeatherLoop:: - copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattleCommunication, 1 - weatherdamage - jumpifword CMP_EQUAL, gBattleMoveDamage, 0, BattleScript_DamagingWeatherLoopIncrement - jumpifword CMP_COMMON_BITS gBattleMoveDamage, 1 << 31, BattleScript_DamagingWeatherHeal + end2 + +BattleScript_DamagingWeather:: printfromtable gSandStormHailDmgStringIds waitmessage B_WAIT_TIME_LONG effectivenesssound - hitanimation BS_ATTACKER - goto BattleScript_DamagingWeatherHpChange -BattleScript_DamagingWeatherHeal: - call BattleScript_AbilityPopUp + hitanimation BS_SCRIPTING + goto BattleScript_DoTurnDmg + +BattleScript_IceBodyHeal:: + call BattleScript_AbilityPopUpScripting + playanimation BS_SCRIPTING, B_ANIM_SIMPLE_HEAL + healthbarupdate BS_SCRIPTING + datahpupdate BS_SCRIPTING printstring STRINGID_ICEBODYHPGAIN waitmessage B_WAIT_TIME_LONG -BattleScript_DamagingWeatherHpChange: - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - tryfaintmon BS_ATTACKER - checkteamslost BattleScript_DamagingWeatherLoopIncrement -BattleScript_DamagingWeatherLoopIncrement:: - jumpifbyte CMP_NOT_EQUAL, gBattleOutcome, 0, BattleScript_DamagingWeatherContinuesEnd - addbyte gBattleCommunication, 1 - jumpifbytenotequal gBattleCommunication, gBattlersCount, BattleScript_DamagingWeatherLoop -BattleScript_DamagingWeatherContinuesEnd:: - bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE - call BattleScript_ActivateWeatherAbilities end2 BattleScript_SandStormHailSnowEnds:: @@ -9836,6 +9825,8 @@ BattleScript_DamageNonTypesStarts:: BattleScript_DamageNonTypesContinues:: printfromtable gDamageNonTypesDmgStringIds waitmessage B_WAIT_TIME_LONG + effectivenesssound + hitanimation BS_SCRIPTING goto BattleScript_DoTurnDmg BattleScript_EffectTryReducePP:: diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 8643f62ad9bc..0c9f72c276a0 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -51,6 +51,8 @@ extern const u8 BattleScript_LevelUp[]; extern const u8 BattleScript_RainContinuesOrEnds[]; extern const u8 BattleScript_SnowContinuesOrEnds[]; extern const u8 BattleScript_DamagingWeatherContinues[]; +extern const u8 BattleScript_DamagingWeather[]; +extern const u8 BattleScript_IceBodyHeal[]; extern const u8 BattleScript_SandStormHailSnowEnds[]; extern const u8 BattleScript_SunlightContinues[]; extern const u8 BattleScript_SunlightFaded[]; diff --git a/include/config/general.h b/include/config/general.h index a374ee97a17e..fb537b56ae76 100644 --- a/include/config/general.h +++ b/include/config/general.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/constants/battle_anim.h b/include/constants/battle_anim.h index 613f39098f2f..8d095215309c 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -573,6 +573,7 @@ #define B_ANIM_FOG_CONTINUES 49 #define B_ANIM_TERA_CHARGE 50 #define B_ANIM_TERA_ACTIVATE 51 +#define B_ANIM_SIMPLE_HEAL 52 // special animations table (gBattleAnims_Special) #define B_ANIM_LVL_UP 0 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cb38834a200c..7f94ba63d3a2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -490,7 +490,7 @@ static void Cmd_setlightscreen(void); static void Cmd_tryKO(void); static void Cmd_damagetohalftargethp(void); static void Cmd_unused_95(void); -static void Cmd_weatherdamage(void); +static void Cmd_unused_96(void); static void Cmd_tryinfatuating(void); static void Cmd_updatestatusicon(void); static void Cmd_setmist(void); @@ -749,7 +749,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_tryKO, //0x93 Cmd_damagetohalftargethp, //0x94 Cmd_unused_95, //0x95 - Cmd_weatherdamage, //0x96 + Cmd_unused_96, //0x96 Cmd_tryinfatuating, //0x97 Cmd_updatestatusicon, //0x98 Cmd_setmist, //0x99 @@ -12411,74 +12411,8 @@ static void Cmd_unused_95(void) { } -static void Cmd_weatherdamage(void) +static void Cmd_unused_96(void) { - CMD_ARGS(); - - u32 ability = GetBattlerAbility(gBattlerAttacker); - - gBattleMoveDamage = 0; - if (IsBattlerAlive(gBattlerAttacker) && WEATHER_HAS_EFFECT && ability != ABILITY_MAGIC_GUARD) - { - if (gBattleWeather & B_WEATHER_SANDSTORM) - { - if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ROCK) - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GROUND) - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_STEEL) - && ability != ABILITY_SAND_VEIL - && ability != ABILITY_SAND_FORCE - && ability != ABILITY_SAND_RUSH - && ability != ABILITY_OVERCOAT - && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) - { - gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } - } - if (gBattleWeather & B_WEATHER_HAIL) - { - if (ability == ABILITY_ICE_BODY - && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) - && !BATTLER_MAX_HP(gBattlerAttacker) - && !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK)) - { - gBattlerAbility = gBattlerAttacker; - gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - } - else if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE) - && ability != ABILITY_SNOW_CLOAK - && ability != ABILITY_OVERCOAT - && ability != ABILITY_ICE_BODY - && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) - { - gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } - } - if (gBattleWeather & B_WEATHER_SNOW) - { - if (ability == ABILITY_ICE_BODY - && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) - && !BATTLER_MAX_HP(gBattlerAttacker) - && !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK)) - { - gBattlerAbility = gBattlerAttacker; - gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 16; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - gBattleMoveDamage *= -1; - } - } - } - - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_tryinfatuating(void) @@ -14044,7 +13978,7 @@ u32 GetNaturePowerMove(u32 battler) move = MOVE_PSYCHIC; else if (sNaturePowerMoves[gBattleTerrain] == MOVE_NONE) move = MOVE_TRI_ATTACK; - + if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE) { gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; diff --git a/src/battle_util.c b/src/battle_util.c index 61996c7726cf..e048670552d5 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2338,8 +2338,9 @@ enum ENDTURN_SALT_CURE, ENDTURN_SYRUP_BOMB, ENDTURN_DYNAMAX, - ENDTURN_SEA_OF_FIRE_DAMAGE, ENDTURN_GMAX_MOVE_RESIDUAL_DAMAGE, + ENDTURN_SEA_OF_FIRE_DAMAGE, + ENDTURN_WEATHER_DAMAGE, ENDTURN_BATTLER_COUNT }; @@ -2926,9 +2927,28 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_GMAX_MOVE_RESIDUAL_DAMAGE: + { + u32 side = GetBattlerSide(gBattlerAttacker); + if (gSideTimers[side].damageNonTypesTimer + && !IS_BATTLER_OF_TYPE(gBattlerAttacker, gSideTimers[side].damageNonTypesType) + && IsBattlerAlive(gBattlerAttacker) + && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 6; + BtlController_EmitHitAnimation(battler, BUFFER_A); + MarkBattlerForControllerExec(battler); + ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); + BattleScriptExecute(BattleScript_DamageNonTypesContinues); + effect++; + } + gBattleStruct->turnEffectsTracker++; + break; + } case ENDTURN_SEA_OF_FIRE_DAMAGE: if (IsBattlerAlive(battler) && gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_SEA_OF_FIRE) { + gBattleScripting.battler = battler; gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; BtlController_EmitStatusAnimation(battler, BUFFER_A, FALSE, STATUS1_BURN); MarkBattlerForControllerExec(battler); @@ -2937,23 +2957,55 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; - case ENDTURN_GMAX_MOVE_RESIDUAL_DAMAGE: + case ENDTURN_WEATHER_DAMAGE: + ability = GetBattlerAbility(battler); + if (!IsBattlerAlive(battler) || !WEATHER_HAS_EFFECT || ability == ABILITY_MAGIC_GUARD) { - u32 side = GetBattlerSide(gBattlerAttacker); - if (gSideTimers[side].damageNonTypesTimer - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, gSideTimers[side].damageNonTypesType) - && IsBattlerAlive(gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 6; - MarkBattlerForControllerExec(battler); - ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); - BattleScriptExecute(BattleScript_DamageNonTypesContinues); - effect++; - } gBattleStruct->turnEffectsTracker++; break; } + else if (gBattleWeather & B_WEATHER_SANDSTORM + && ability != ABILITY_SAND_VEIL + && ability != ABILITY_SAND_FORCE + && ability != ABILITY_SAND_RUSH + && ability != ABILITY_OVERCOAT + && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ROCK) + && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GROUND) + && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_STEEL) + && !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) + { + gBattleScripting.battler = battler; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 16; + BattleScriptExecute(BattleScript_DamagingWeather); + effect++; + } + else if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW) + && ability == ABILITY_ICE_BODY + && !(gStatuses3[battler] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && !BATTLER_MAX_HP(battler) + && !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) + { + gBattleScripting.battler = battler; + gBattleMoveDamage = -1 * (GetNonDynamaxMaxHP(battler) / 16); + BattleScriptExecute(BattleScript_IceBodyHeal); + effect++; + } + else if (gBattleWeather & B_WEATHER_HAIL + && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE) + && ability != ABILITY_SNOW_CLOAK + && ability != ABILITY_OVERCOAT + && ability != ABILITY_ICE_BODY + && !(gStatuses3[battler] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) + && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) + { + gBattleScripting.battler = battler; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 16; + BattleScriptExecute(BattleScript_DamagingWeather); + effect++; + } + gBattleStruct->turnEffectsTracker++; + break; case ENDTURN_BATTLER_COUNT: // done gBattleStruct->turnEffectsTracker = 0; gBattleStruct->turnEffectsBattlerId++; diff --git a/test/battle/weather/hail.c b/test/battle/weather/hail.c index 567037ccaa28..f5b0e432825f 100644 --- a/test/battle/weather/hail.c +++ b/test/battle/weather/hail.c @@ -17,6 +17,21 @@ SINGLE_BATTLE_TEST("Hail deals 1/16 damage per turn") } THEN { EXPECT_EQ(hailDamage, opponent->maxHP / 16); } } +SINGLE_BATTLE_TEST("Hail heals 1/16 damage per turn on Icy Body") +{ + s16 hailDamage; + + GIVEN { + PLAYER(SPECIES_GLALIE); + OPPONENT(SPECIES_SEEL) { HP(1); Ability(ABILITY_ICE_BODY); } + } WHEN { + TURN {MOVE(player, MOVE_HAIL);} + } SCENE { + ABILITY_POPUP(opponent, ABILITY_ICE_BODY); + HP_BAR(opponent, captureDamage: &hailDamage); + } THEN { EXPECT_EQ(hailDamage, -(opponent->maxHP / 16)); } +} + SINGLE_BATTLE_TEST("Hail damage does not affect Ice-type Pokémon") { GIVEN { @@ -53,3 +68,20 @@ SINGLE_BATTLE_TEST("Hail fails if Desolate Land or Primordial Sea are active") } } } + +DOUBLE_BATTLE_TEST("Hail deals based on turn order") +{ + GIVEN { + PLAYER(SPECIES_GLALIE); + PLAYER(SPECIES_WYNAUT) { Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } + OPPONENT(SPECIES_WYNAUT) { Speed(3); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_HAIL); } + } SCENE { + NOT HP_BAR(playerLeft); + HP_BAR(opponentRight); + HP_BAR(opponentLeft); + HP_BAR(playerRight); + } +} \ No newline at end of file