From 68a974af8616794b3499db9bb119300ac80155ee Mon Sep 17 00:00:00 2001 From: FosterProgramming Date: Mon, 24 Nov 2025 18:34:00 +0100 Subject: [PATCH] Fix cure status item effect not working properly in doubles (#8339) --- asm/macros/battle_script.inc | 3 +- data/battle_scripts_2.s | 9 +- src/battle_script_commands.c | 32 ++++-- test/battle/item_effect/cure_status.c | 97 +++++++++++++++++++ .../battle/item_effect/heal_and_cure_status.c | 4 +- 5 files changed, 130 insertions(+), 15 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 517ab09e45..0825fe013b 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1421,9 +1421,10 @@ .4byte \restoreBattlerInstr .endm - .macro itemcurestatus jumpInstr:req + .macro itemcurestatus jumpInstr:req, restoreBattlerInstr:req callnative BS_ItemCureStatus .4byte \jumpInstr + .4byte \restoreBattlerInstr .endm .macro itemincreasestat diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index b086582250..2c7a56078f 100755 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -87,13 +87,18 @@ BattleScript_ItemRestoreHP_SendOutRevivedBattler: BattleScript_ItemCureStatus:: call BattleScript_UseItemMessage BattleScript_ItemCureStatusAfterItemMsg: - itemcurestatus BattleScript_ItemCureStatusEnd - updatestatusicon BS_SCRIPTING + itemcurestatus BattleScript_ItemCureStatusEnd, BattleScript_CureStatus_Battler printstring STRINGID_ITEMCUREDSPECIESSTATUS waitmessage B_WAIT_TIME_LONG BattleScript_ItemCureStatusEnd: end +BattleScript_CureStatus_Battler:: + updatestatusicon BS_SCRIPTING + printstring STRINGID_ITEMCUREDSPECIESSTATUS + waitmessage B_WAIT_TIME_LONG + end + BattleScript_ItemHealAndCureStatus:: call BattleScript_UseItemMessage itemrestorehp BattleScript_ItemCureStatusAfterItemMsg, BattleScript_ItemHealAndCureStatus_Battler diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e5d9d0a588..efe91ac3ee 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -15202,37 +15202,49 @@ void BS_ItemRestoreHP(void) void BS_ItemCureStatus(void) { - NATIVE_ARGS(const u8 *noStatusInstr); - u32 battler = gBattlerAttacker; + NATIVE_ARGS(const u8 *noStatusInstr, const u8 *restoreBattlerInstr); + u32 targetBattler = MAX_BATTLERS_COUNT; bool32 statusChanged = FALSE; struct Pokemon *party = GetBattlerParty(gBattlerAttacker); // Heal volatile conditions if battler is active. if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker]) - statusChanged = ItemHealMonVolatile(battler, gLastUsedItem); + { + statusChanged = ItemHealMonVolatile(gBattlerAttacker, gLastUsedItem); + targetBattler = gBattlerAttacker; + } else if (IsDoubleBattle() && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) + { statusChanged = ItemHealMonVolatile(BATTLE_PARTNER(gBattlerAttacker), gLastUsedItem); + targetBattler = BATTLE_PARTNER(gBattlerAttacker); + } // Heal Status1 conditions. - if (!HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], GetItemStatus1Mask(gLastUsedItem), battler)) + if (!HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], GetItemStatus1Mask(gLastUsedItem), targetBattler)) { statusChanged = TRUE; if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP) - gBattleMons[battler].volatiles.nightmare = FALSE; + gBattleMons[targetBattler].volatiles.nightmare = FALSE; if (ItemHasVolatileFlag(gLastUsedItem, VOLATILE_CONFUSION)) - gBattleMons[battler].volatiles.infiniteConfusion = FALSE; + gBattleMons[targetBattler].volatiles.infiniteConfusion = FALSE; } - if (statusChanged) + if (!statusChanged) + { + gBattlescriptCurrInstr = cmd->noStatusInstr; + return; + } + + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES)); + if (targetBattler == MAX_BATTLERS_COUNT) { - gBattleScripting.battler = battler; - PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES)); gBattlescriptCurrInstr = cmd->nextInstr; } else { - gBattlescriptCurrInstr = cmd->noStatusInstr; + gBattleScripting.battler = targetBattler; + gBattlescriptCurrInstr = cmd->restoreBattlerInstr; } } diff --git a/test/battle/item_effect/cure_status.c b/test/battle/item_effect/cure_status.c index 919b4539af..79490b48dc 100644 --- a/test/battle/item_effect/cure_status.c +++ b/test/battle/item_effect/cure_status.c @@ -31,6 +31,29 @@ SINGLE_BATTLE_TEST("Antidote heals a battler from being poisoned") } } +DOUBLE_BATTLE_TEST("Antidote heals a battler from being poisoned (doubles)") +{ + u32 index; + struct BattlePokemon *user = NULL; + struct BattlePokemon *target = NULL; + PARAMETRIZE { index = 0; user = playerRight; target = playerLeft;} + PARAMETRIZE { index = 1; user = playerLeft; target = playerRight;} + PARAMETRIZE { index = 0; user = playerLeft; target = playerLeft;} + PARAMETRIZE { index = 1; user = playerRight; target = playerRight; } + + GIVEN { + ASSUME(gItemsInfo[ITEM_ANTIDOTE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + PLAYER(SPECIES_WYNAUT) { } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(user, ITEM_ANTIDOTE, partyIndex: index); } + } THEN { + EXPECT_EQ(target->status1, STATUS1_NONE); + } +} + SINGLE_BATTLE_TEST("Antidote heals a battler from being badly poisoned") { GIVEN { @@ -135,6 +158,43 @@ SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status") } } +DOUBLE_BATTLE_TEST("Full Heal heals a battler from any primary status (doubles)") +{ + u32 statusParameters[7] = + { + STATUS1_SLEEP, + STATUS1_POISON, + STATUS1_BURN, + STATUS1_FREEZE, + STATUS1_PARALYSIS, + STATUS1_TOXIC_POISON, + STATUS1_FROSTBITE + }; + + u16 status = 0; + u32 index = 0; + struct BattlePokemon *user = NULL; + struct BattlePokemon *target = NULL; + for (u32 j = 0; j < 7; j++) + { + PARAMETRIZE {status = statusParameters[j]; user = playerRight; target = playerLeft; index = 0;} + PARAMETRIZE {status = statusParameters[j]; user = playerLeft; target = playerRight; index = 1;} + PARAMETRIZE {status = statusParameters[j]; user = playerLeft; target = playerLeft; index = 0;} + PARAMETRIZE {status = statusParameters[j]; user = playerRight; target = playerRight; index = 1;} + } + GIVEN { + ASSUME(gItemsInfo[ITEM_FULL_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(user, ITEM_FULL_HEAL, partyIndex: index); } + } THEN { + EXPECT_EQ(target->status1, STATUS1_NONE); + } +} + SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status") { u16 status; @@ -158,6 +218,43 @@ SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status") } } +DOUBLE_BATTLE_TEST("Heal Powder heals a battler from any primary status (doubles)") +{ + u32 statusParameters[7] = + { + STATUS1_SLEEP, + STATUS1_POISON, + STATUS1_BURN, + STATUS1_FREEZE, + STATUS1_PARALYSIS, + STATUS1_TOXIC_POISON, + STATUS1_FROSTBITE + }; + + u16 status = 0; + u32 index = 0; + struct BattlePokemon *user = NULL; + struct BattlePokemon *target = NULL; + for (u32 j = 0; j < 7; j++) + { + PARAMETRIZE {status = statusParameters[j]; user = playerRight; target = playerLeft; index = 0;} + PARAMETRIZE {status = statusParameters[j]; user = playerLeft; target = playerRight; index = 1;} + PARAMETRIZE {status = statusParameters[j]; user = playerLeft; target = playerLeft; index = 0;} + PARAMETRIZE {status = statusParameters[j]; user = playerRight; target = playerRight; index = 1;} + } + GIVEN { + ASSUME(gItemsInfo[ITEM_HEAL_POWDER].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(user, ITEM_HEAL_POWDER, partyIndex: index); } + } THEN { + EXPECT_EQ(target->status1, STATUS1_NONE); + } +} + SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status") { u16 status; diff --git a/test/battle/item_effect/heal_and_cure_status.c b/test/battle/item_effect/heal_and_cure_status.c index 99507df3cd..d85f11b33d 100644 --- a/test/battle/item_effect/heal_and_cure_status.c +++ b/test/battle/item_effect/heal_and_cure_status.c @@ -43,8 +43,8 @@ SINGLE_BATTLE_TEST("Full Restore restores a party members HP and cures any prima PARAMETRIZE { status = STATUS1_SLEEP; } PARAMETRIZE { status = STATUS1_NONE; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); } - PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(300); Status1(status); } + PLAYER(SPECIES_WOBBUFFET) { HP(100); MaxHP(300); Status1(status); } + PLAYER(SPECIES_WYNAUT) { HP(100); MaxHP(300); Status1(status); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 1); }