From 04da838d88b53b8182ef2d7c5dd325f2703a88b2 Mon Sep 17 00:00:00 2001 From: wiz1989 <80073265+wiz1989@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:00:09 +0100 Subject: [PATCH 1/2] Innards Out and Future Sight interaction --- include/battle.h | 1 + include/battle_ai_util.h | 1 + src/battle_ai_util.c | 8 ++++ src/battle_script_commands.c | 6 +++ src/battle_util.c | 24 +++++++++-- test/battle/ability/innards_out.c | 63 ++++++++++++++++++++++++++++ test/battle/hold_effect/shell_bell.c | 35 ++++++++++++++++ 7 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 test/battle/hold_effect/shell_bell.c diff --git a/include/battle.h b/include/battle.h index f0571d747e..27f7be5173 100644 --- a/include/battle.h +++ b/include/battle.h @@ -310,6 +310,7 @@ struct WishFutureKnock u8 wishPartyId[MAX_BATTLERS_COUNT]; u8 weatherDuration; u8 knockedOffMons[NUM_BATTLE_SIDES]; // Each battler is represented by a bit. + u8 futureSightDmg[MAX_BATTLERS_COUNT]; }; struct AI_SavedBattleMon diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index c74cad2e78..b26b608e99 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -137,6 +137,7 @@ bool32 ShouldSetRain(u32 battlerAtk, u32 ability, u32 holdEffect); bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect); bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef); bool32 IsHealingMove(u32 move); +bool32 IsForeSeenMove(u32 moveId); bool32 HasHealingEffect(u32 battler); bool32 IsTrappingMove(u32 move); bool32 HasTrappingMoveEffect(u32 battler); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index b68112374d..3e841a3d69 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2188,6 +2188,14 @@ bool32 HasHealingEffect(u32 battlerId) return FALSE; } +bool32 IsForeSeenMove(u32 moveId) +{ + if (moveId == MOVE_FUTURE_SIGHT || moveId == MOVE_DOOM_DESIRE) + return TRUE; + else + return FALSE; +} + bool32 IsTrappingMove(u32 move) { switch (gMovesInfo[move].effect) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2f31b230ae..6f3b85daa5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2459,6 +2459,11 @@ static void Cmd_datahpupdate(void) if (gSpecialStatuses[battler].shellBellDmg == 0 && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE)) gSpecialStatuses[battler].shellBellDmg = gHpDealt; + // Record damage for foreseen moves + if (gWishFutureKnock.futureSightDmg[battler] == 0 + && IsForeSeenMove(gWishFutureKnock.futureSightMove[battler])) + gWishFutureKnock.futureSightDmg[battler] = gHpDealt; + // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are // used in combination as general damage trackers for other purposes. specialDmg is additionally used // to help determine if a fire move should defrost the target. @@ -13955,6 +13960,7 @@ static void Cmd_trysetfutureattack(void) gWishFutureKnock.futureSightBattlerIndex[gBattlerTarget] = gBattlerAttacker; gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] = gBattlerPartyIndexes[gBattlerAttacker]; gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3; + gWishFutureKnock.futureSightDmg[gBattlerTarget] = 0; if (gCurrentMove == MOVE_DOOM_DESIRE) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOOM_DESIRE; diff --git a/src/battle_util.c b/src/battle_util.c index 9245ef21fc..b3fc4042c8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5803,10 +5803,26 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !IsBattlerAlive(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleMoveDamage = gSpecialStatuses[gBattlerTarget].shellBellDmg; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AftermathDmg; - effect++; + //special Future Sight handling + if (IsForeSeenMove(gWishFutureKnock.futureSightMove[gBattlerTarget])) + { + //no Innards Out effect if Future Sight user is currently not on field + if (gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] == gBattlerPartyIndexes[gBattlerAttacker] + || gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] == BATTLE_PARTNER(gBattlerPartyIndexes[gBattlerAttacker])) + { + gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gBattlerTarget]; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AftermathDmg; + effect++; + } + } + else + { + gBattleMoveDamage = gSpecialStatuses[gBattlerTarget].shellBellDmg; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AftermathDmg; + effect++; + } } break; case ABILITY_EFFECT_SPORE: diff --git a/test/battle/ability/innards_out.c b/test/battle/ability/innards_out.c index 5837b98d1f..e14356b07b 100644 --- a/test/battle/ability/innards_out.c +++ b/test/battle/ability/innards_out.c @@ -65,3 +65,66 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon") NOT HP_BAR(opponent); } } + +// IO damage for Future Sight must equal the actually lost HP of the Future Sight target +SINGLE_BATTLE_TEST("Innards Out uses correct damage amount for Future Sight") +{ + GIVEN { + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent, damage: 1); + } +} + +// IO shouldn't trigger if future sight user is no longer on field +SINGLE_BATTLE_TEST("Innards Out doesn't trigger if Future Sight user is not on field") +{ + GIVEN { + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { SWITCH(opponent, 1); } + TURN { SEND_OUT(player, 1); } //SEND_OUT(opponent, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + NONE_OF { + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent); + } + } +} + +//IO should trigger if future sight user returns on the field +SINGLE_BATTLE_TEST("Innards Out triggers if Future Sight user is back on the field") +{ + GIVEN { + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent); + } +} diff --git a/test/battle/hold_effect/shell_bell.c b/test/battle/hold_effect/shell_bell.c new file mode 100644 index 0000000000..dbcb593fa5 --- /dev/null +++ b/test/battle/hold_effect/shell_bell.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Shell Bell restores 1/8 HP of damage dealt") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); } + OPPONENT(SPECIES_WOBBUFFET) { Level(16); }; + } WHEN { + TURN { MOVE(player, MOVE_SEISMIC_TOSS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player); + HP_BAR(opponent); + HP_BAR(player, damage: -2); + } +} + +SINGLE_BATTLE_TEST("Shell Bell doesn't restore HP for damage dealt by a foreseen move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); } + OPPONENT(SPECIES_WOBBUFFET) { Level(16); }; + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("The opposing Wobbuffet took the Future Sight attack!"); + HP_BAR(opponent); + NONE_OF { + HP_BAR(player); + } + } +} From 5bfc25a4fff708af2440cd654daf355f43fffd50 Mon Sep 17 00:00:00 2001 From: wiz1989 <80073265+wiz1989@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:33:22 +0100 Subject: [PATCH 2/2] changed data according to suggestions from the PR --- include/battle_ai_util.h | 1 - src/battle_ai_util.c | 8 -------- src/battle_script_commands.c | 2 +- src/battle_util.c | 2 +- test/battle/ability/innards_out.c | 6 +++--- test/battle/hold_effect/shell_bell.c | 1 + 6 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index b26b608e99..c74cad2e78 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -137,7 +137,6 @@ bool32 ShouldSetRain(u32 battlerAtk, u32 ability, u32 holdEffect); bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect); bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef); bool32 IsHealingMove(u32 move); -bool32 IsForeSeenMove(u32 moveId); bool32 HasHealingEffect(u32 battler); bool32 IsTrappingMove(u32 move); bool32 HasTrappingMoveEffect(u32 battler); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 3e841a3d69..b68112374d 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2188,14 +2188,6 @@ bool32 HasHealingEffect(u32 battlerId) return FALSE; } -bool32 IsForeSeenMove(u32 moveId) -{ - if (moveId == MOVE_FUTURE_SIGHT || moveId == MOVE_DOOM_DESIRE) - return TRUE; - else - return FALSE; -} - bool32 IsTrappingMove(u32 move) { switch (gMovesInfo[move].effect) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6f3b85daa5..31ae0f2646 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2461,7 +2461,7 @@ static void Cmd_datahpupdate(void) // Record damage for foreseen moves if (gWishFutureKnock.futureSightDmg[battler] == 0 - && IsForeSeenMove(gWishFutureKnock.futureSightMove[battler])) + && gMovesInfo[gWishFutureKnock.futureSightMove[battler]].effect == EFFECT_FUTURE_SIGHT) gWishFutureKnock.futureSightDmg[battler] = gHpDealt; // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are diff --git a/src/battle_util.c b/src/battle_util.c index b3fc4042c8..54d6862c48 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5804,7 +5804,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerAlive(gBattlerAttacker)) { //special Future Sight handling - if (IsForeSeenMove(gWishFutureKnock.futureSightMove[gBattlerTarget])) + if (gMovesInfo[gWishFutureKnock.futureSightMove[battler]].effect == EFFECT_FUTURE_SIGHT) { //no Innards Out effect if Future Sight user is currently not on field if (gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] == gBattlerPartyIndexes[gBattlerAttacker] diff --git a/test/battle/ability/innards_out.c b/test/battle/ability/innards_out.c index e14356b07b..e4f8e58ef6 100644 --- a/test/battle/ability/innards_out.c +++ b/test/battle/ability/innards_out.c @@ -66,10 +66,10 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon") } } -// IO damage for Future Sight must equal the actually lost HP of the Future Sight target SINGLE_BATTLE_TEST("Innards Out uses correct damage amount for Future Sight") { GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); @@ -86,10 +86,10 @@ SINGLE_BATTLE_TEST("Innards Out uses correct damage amount for Future Sight") } } -// IO shouldn't trigger if future sight user is no longer on field SINGLE_BATTLE_TEST("Innards Out doesn't trigger if Future Sight user is not on field") { GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -109,10 +109,10 @@ SINGLE_BATTLE_TEST("Innards Out doesn't trigger if Future Sight user is not on f } } -//IO should trigger if future sight user returns on the field SINGLE_BATTLE_TEST("Innards Out triggers if Future Sight user is back on the field") { GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/hold_effect/shell_bell.c b/test/battle/hold_effect/shell_bell.c index dbcb593fa5..9cac6831d9 100644 --- a/test/battle/hold_effect/shell_bell.c +++ b/test/battle/hold_effect/shell_bell.c @@ -18,6 +18,7 @@ SINGLE_BATTLE_TEST("Shell Bell restores 1/8 HP of damage dealt") SINGLE_BATTLE_TEST("Shell Bell doesn't restore HP for damage dealt by a foreseen move") { GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); } OPPONENT(SPECIES_WOBBUFFET) { Level(16); }; } WHEN {