diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 24a5467ef5d6..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 @@ -1359,15 +1359,15 @@ .macro restoretarget callnative BS_RestoreTarget .endm - + .macro saveattacker callnative BS_SaveAttacker .endm - + .macro restoreattacker callnative BS_RestoreAttacker .endm - + .macro metalburstdamagecalculator failInstr:req callnative BS_CalcMetalBurstDmg .4byte \failInstr @@ -1560,10 +1560,6 @@ .4byte \failInstr .endm - .macro damagenontypes - callnative BS_DamageNonTypes - .endm - .macro trysetstatus1, ptr:req callnative BS_TrySetStatus1 .4byte \ptr @@ -1659,7 +1655,7 @@ .macro removeweather callnative BS_RemoveWeather .endm - + .macro applyterastallization callnative BS_ApplyTerastallization .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 3c67f15c7cc5..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:: @@ -9834,27 +9823,11 @@ BattleScript_DamageNonTypesStarts:: goto BattleScript_MoveEnd BattleScript_DamageNonTypesContinues:: - setbyte gBattleCommunication, 0 -BattleScript_DamageNonTypesLoop:: - copyarraywithindex gBattlerAttacker, gBattlerByTurnOrder, gBattleCommunication, 1 - damagenontypes - jumpifword CMP_EQUAL, gBattleMoveDamage, 0, BattleScript_DamageNonTypesLoopIncrement printfromtable gDamageNonTypesDmgStringIds waitmessage B_WAIT_TIME_LONG effectivenesssound - hitanimation BS_ATTACKER - orword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - tryfaintmon BS_ATTACKER - checkteamslost BattleScript_DamageNonTypesLoopIncrement -BattleScript_DamageNonTypesLoopIncrement:: - jumpifbyte CMP_NOT_EQUAL, gBattleOutcome, 0, BattleScript_DamageNonTypesContinuesEnd - addbyte gBattleCommunication, 1 - jumpifbytenotequal gBattleCommunication, gBattlersCount, BattleScript_DamageNonTypesLoop -BattleScript_DamageNonTypesContinuesEnd:: - bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE | HITMARKER_GRUDGE - end2 + hitanimation BS_SCRIPTING + goto BattleScript_DoTurnDmg BattleScript_EffectTryReducePP:: tryspiteppreduce BattleScript_MoveEnd diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index b5223f271b4b..20cd4d5e79ee 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -76,7 +76,6 @@ void BS_SetMaxMoveEffect(void); void BS_SetSteelsurge(void); void BS_TrySetStatus1(void); void BS_TrySetStatus2(void); -void BS_DamageNonTypes(void); void BS_HealOneSixth(void); void BS_TryRecycleBerry(void); void BS_JumpIfDynamaxed(void); 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/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_dynamax.c b/src/battle_dynamax.c index 9e00486bc44e..06a26718a978 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -971,24 +971,6 @@ void BS_TrySetStatus2(void) } } -// Applies the endturn damage effect associated with the "Damage Non-" G-Max moves. -void BS_DamageNonTypes(void) -{ - NATIVE_ARGS(); - u8 side = GetBattlerSide(gBattlerAttacker); - gBattleMoveDamage = 0; - if (gSideTimers[side].damageNonTypesTimer - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, gSideTimers[side].damageNonTypesType) - && IsBattlerAlive(gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) - { - gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 6; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - } - gBattlescriptCurrInstr = cmd->nextInstr; -} - // Heals one-sixth of the target's HP, including for Dynamaxed targets. void BS_HealOneSixth(void) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index cb38834a200c..9907edbe866c 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 aa83fba0ff21..cba5c49711e2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1715,7 +1715,7 @@ u8 DoFieldEndTurnEffects(void) do { s32 i; - u8 side; + u32 side; switch (gBattleStruct->turnCountersTracker) { @@ -2068,19 +2068,11 @@ u8 DoFieldEndTurnEffects(void) while (gBattleStruct->turnSideTracker < 2) { side = gBattleStruct->turnSideTracker; - if (gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES) + if (gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES && --gSideTimers[side].damageNonTypesTimer == 0) { - if (--gSideTimers[side].damageNonTypesTimer == 0) - { - // There is no in-game message when this side status ends. - gSideStatuses[side] &= ~SIDE_STATUS_DAMAGE_NON_TYPES; - effect++; - } - else - { - ChooseDamageNonTypesString(gSideTimers[side].damageNonTypesType); - BattleScriptExecute(BattleScript_DamageNonTypesContinues); - } + // There is no in-game message when this side status ends. + gSideStatuses[side] &= ~SIDE_STATUS_DAMAGE_NON_TYPES; + effect++; } gBattleStruct->turnSideTracker++; if (effect != 0) @@ -2346,7 +2338,9 @@ enum ENDTURN_SALT_CURE, ENDTURN_SYRUP_BOMB, ENDTURN_DYNAMAX, + ENDTURN_GMAX_MOVE_RESIDUAL_DAMAGE, ENDTURN_SEA_OF_FIRE_DAMAGE, + ENDTURN_WEATHER_DAMAGE, ENDTURN_BATTLER_COUNT }; @@ -2933,10 +2927,27 @@ 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) + { + gBattleScripting.battler = battler; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 6; + 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) { - gBattleMoveDamage = gBattleMons[battler].maxHP / 8; + gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 8; BtlController_EmitStatusAnimation(battler, BUFFER_A, FALSE, STATUS1_BURN); MarkBattlerForControllerExec(battler); BattleScriptExecute(BattleScript_HurtByTheSeaOfFire); @@ -2944,6 +2955,55 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_WEATHER_DAMAGE: + ability = GetBattlerAbility(battler); + if (!IsBattlerAlive(battler) || !WEATHER_HAS_EFFECT || ability == ABILITY_MAGIC_GUARD) + { + 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/ability/ice_body.c b/test/battle/ability/ice_body.c index aca84532a447..1aa7c80a4d98 100644 --- a/test/battle/ability/ice_body.c +++ b/test/battle/ability/ice_body.c @@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("Ice Body recovers 1/16th of Max HP in hail.") TURN { MOVE(opponent, MOVE_HAIL); } } SCENE { ABILITY_POPUP(player, ABILITY_ICE_BODY); - MESSAGE("Glalie's Ice Body healed it a little bit!"); HP_BAR(player, damage: -(100 / 16)); + MESSAGE("Glalie's Ice Body healed it a little bit!"); } } diff --git a/test/battle/weather/hail.c b/test/battle/weather/hail.c index 567037ccaa28..5caeb8489151 100644 --- a/test/battle/weather/hail.c +++ b/test/battle/weather/hail.c @@ -53,3 +53,20 @@ SINGLE_BATTLE_TEST("Hail fails if Desolate Land or Primordial Sea are active") } } } + +DOUBLE_BATTLE_TEST("Hail deals damage 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); + } +} diff --git a/test/battle/weather/sandstorm.c b/test/battle/weather/sandstorm.c index 2f3f4e7ca266..63b24afd7e41 100644 --- a/test/battle/weather/sandstorm.c +++ b/test/battle/weather/sandstorm.c @@ -65,3 +65,20 @@ SINGLE_BATTLE_TEST("Sandstorm damage does not hurt Ground, Rock, and Steel-type } } } + +DOUBLE_BATTLE_TEST("Sandstorm deals damage based on turn order") +{ + GIVEN { + PLAYER(SPECIES_PHANPY); + PLAYER(SPECIES_WYNAUT) { Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } + OPPONENT(SPECIES_WYNAUT) { Speed(3); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SANDSTORM); } + } SCENE { + NOT HP_BAR(playerLeft); + HP_BAR(opponentRight); + HP_BAR(opponentLeft); + HP_BAR(playerRight); + } +}