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] 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); + } + } +}