From 10e55bd18ddb2b67972bd170fdd7ea1bfa9d8087 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 1 Jul 2025 17:49:31 +0200 Subject: [PATCH] Fixes Life Dew playing anim when it is not supposed to + tests (#7239) --- data/battle_scripts_1.s | 34 +++++++++- include/battle_scripts.h | 1 + include/constants/battle_move_effects.h | 1 + src/battle_script_commands.c | 8 +-- src/data/battle_move_effects.h | 6 ++ src/data/moves_info.h | 6 +- test/battle/move.c | 2 +- test/battle/move_effect/life_dew.c | 86 +++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 test/battle/move_effect/life_dew.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index f7e3c382d5..b2c4374857 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1038,7 +1038,6 @@ JungleHealing_RestoreTargetHealth: printstring STRINGID_PKMNREGAINEDHEALTH waitmessage B_WAIT_TIME_LONG BattleScript_JungleHealing_TryCureStatus: - jumpifmove MOVE_LIFE_DEW, BattleScript_JungleHealingTryRestoreAlly @ life dew only heals jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_JungleHealingCureStatus goto BattleScript_JungleHealingTryRestoreAlly BattleScript_JungleHealingCureStatus: @@ -1053,6 +1052,39 @@ BattleScript_JungleHealingTryRestoreAlly: setallytonexttarget JungleHealing_RestoreTargetHealth goto BattleScript_MoveEnd +BattleScript_EffectLifeDew:: + attackcanceler + attackstring + ppreduce + jumpiffullhp BS_ATTACKER, BattleScript_EffectLifeDewCheckPartner + copybyte gBattlerTarget, gBattlerAttacker + attackanimation + waitanimation + call BattleScript_EffectLifeDewHealing + jumpifabsent BS_ATTACKER_PARTNER, BattleScript_EffectLifeDewEnd + jumpiffullhp BS_ATTACKER_PARTNER, BattleScript_EffectLifeDewEnd + setallytonexttarget BattleScript_EffectLifeDewNextTarget +BattleScript_EffectLifeDewNextTarget: + call BattleScript_EffectLifeDewHealing +BattleScript_EffectLifeDewEnd: + goto BattleScript_MoveEnd + +BattleScript_EffectLifeDewCheckPartner: + jumpifabsent BS_ATTACKER_PARTNER, BattleScript_ButItFailed + jumpiffullhp BS_ATTACKER_PARTNER, BattleScript_ButItFailed + attackanimation + waitanimation + setallytonexttarget BattleScript_EffectLifeDewNextTarget + +BattleScript_EffectLifeDewHealing: + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE + tryhealquarterhealth BS_TARGET, BattleScript_EffectLifeDewEnd + healthbarupdate BS_TARGET + datahpupdate BS_TARGET + printstring STRINGID_PKMNREGAINEDHEALTH + waitmessage B_WAIT_TIME_LONG + return + BattleScript_EffectAllySwitch:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 379e45cd39..4531121cbd 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -343,6 +343,7 @@ extern const u8 BattleScript_GrassySurgeActivates[]; extern const u8 BattleScript_MistySurgeActivates[]; extern const u8 BattleScript_ElectricSurgeActivates[]; extern const u8 BattleScript_EffectSpectralThief[]; +extern const u8 BattleScript_EffectLifeDew[]; extern const u8 BattleScript_AbilityRaisesDefenderStat[]; extern const u8 BattleScript_PowderMoveNoEffect[]; extern const u8 BattleScript_GrassyTerrainHeals[]; diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index f77a0d9799..aeda6b8cf7 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -348,6 +348,7 @@ enum BattleMoveEffects EFFECT_SPECTRAL_THIEF, EFFECT_RECOIL, EFFECT_SMACK_DOWN, + EFFECT_LIFE_DEW, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 19f787dc9d..61cdfc65e6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -14329,7 +14329,7 @@ static void Cmd_recoverbasedonsunlight(void) { u32 healingModifier = 1; u32 time = GetTimeOfDay(); - + switch (GetMoveEffect(gCurrentMove)) { case EFFECT_MOONLIGHT: @@ -14349,14 +14349,14 @@ static void Cmd_recoverbasedonsunlight(void) healingModifier = 1; break; } - + if (!(gBattleWeather & B_WEATHER_ANY) || !HasWeatherEffect() || GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA) gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; else if (gBattleWeather & B_WEATHER_SUN) gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else // not sunny weather gBattleStruct->moveDamage[gBattlerAttacker] = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; - + } if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) @@ -16446,7 +16446,7 @@ static void Cmd_setnonvolatilestatus(void) { CMD_ARGS(u8 trigger); gBattlescriptCurrInstr = cmd->nextInstr - 1; - + switch (cmd->trigger) { case TRIGGER_ON_ABILITY: diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index ca7e866e9c..54ad1c5cf7 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2212,4 +2212,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_LIFE_DEW] = + { + .battleScript = BattleScript_EffectLifeDew, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 08daab5a6b..7436eaf3f6 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -6056,7 +6056,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = "User spins and removes some\n" #if B_SPEED_BUFFING_RAPID_SPIN >= GEN_8 "effects, while upping speed."), - #else + #else "effects."), #endif .effect = EFFECT_RAPID_SPIN, @@ -18277,12 +18277,12 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .description = COMPOUND_STRING( "Scatters water to restore\n" "the HP of itself and allies."), - .effect = EFFECT_JUNGLE_HEALING, + .effect = EFFECT_LIFE_DEW, .power = 0, .type = TYPE_WATER, .accuracy = 0, .pp = 10, - .target = MOVE_TARGET_ALL_BATTLERS, + .target = MOVE_TARGET_USER, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .snatchAffected = TRUE, diff --git a/test/battle/move.c b/test/battle/move.c index 5a95c21d89..64500bb211 100644 --- a/test/battle/move.c +++ b/test/battle/move.c @@ -87,7 +87,7 @@ DOUBLE_BATTLE_TEST("Turn order is determined randomly if priority and Speed tie GIVEN { ASSUME(GetMoveEffect(MOVE_ENDEAVOR) == EFFECT_ENDEAVOR); - ASSUME(GetMoveEffect(MOVE_LIFE_DEW) == EFFECT_JUNGLE_HEALING); + ASSUME(GetMoveEffect(MOVE_LIFE_DEW) == EFFECT_LIFE_DEW); ASSUME(GetMoveEffect(MOVE_CRUSH_GRIP) == EFFECT_POWER_BASED_ON_TARGET_HP); ASSUME(GetMoveEffect(MOVE_SUPER_FANG) == EFFECT_FIXED_PERCENT_DAMAGE); PLAYER(SPECIES_WOBBUFFET) { MaxHP(480); HP(360); Defense(100); Speed(1); } diff --git a/test/battle/move_effect/life_dew.c b/test/battle/move_effect/life_dew.c new file mode 100644 index 0000000000..493c4c73e7 --- /dev/null +++ b/test/battle/move_effect/life_dew.c @@ -0,0 +1,86 @@ +#include "global.h" +#include "test/battle.h" + +DOUBLE_BATTLE_TEST("Life Dew fails if user and partner are both at full hp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_LIFE_DEW); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_LIFE_DEW, playerLeft); + MESSAGE("But it failed!"); + } +} + +DOUBLE_BATTLE_TEST("Life Dew recovers 25% of hp for both user and partner") +{ + s16 healing[2]; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WYNAUT) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_LIFE_DEW); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LIFE_DEW, playerLeft); + HP_BAR(playerLeft, captureDamage: &healing[0]); + MESSAGE("Wobbuffet's HP was restored."); + HP_BAR(playerRight, captureDamage: &healing[1]); + MESSAGE("Wynaut's HP was restored."); + } THEN { + EXPECT_EQ(playerLeft->maxHP / 4, -healing[0]); + EXPECT_EQ(playerRight->maxHP / 4, -healing[1]); + } +} + +SINGLE_BATTLE_TEST("Life Dew works in singles on user") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_LIFE_DEW); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LIFE_DEW, player); + HP_BAR(player); + NOT HP_BAR(opponent); + } +} + +DOUBLE_BATTLE_TEST("Life Dew only works on user if partner is at full hp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_LIFE_DEW); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LIFE_DEW, playerLeft); + HP_BAR(playerLeft); + NOT HP_BAR(playerRight); + } +} + +DOUBLE_BATTLE_TEST("Life Dew only works on partner if user is at full hp") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_LIFE_DEW); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LIFE_DEW, playerLeft); + NOT HP_BAR(playerLeft); + HP_BAR(playerRight); + } +}