Fix Full Restore / Antidote not reseting Toxic Counter (#4135)

* Fix Full Restore / Antidote not reseting Toxic Counter

* Update battle_scripts_2.s

---------

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
DizzyEggg 2024-02-09 13:58:16 +01:00 committed by GitHub
parent 452432533a
commit 31ac151e29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 168 additions and 80 deletions

View File

@ -1332,12 +1332,14 @@
.4byte \jumpInstr
.endm
.macro itemrestorehp
.macro itemrestorehp jumpInstr:req
callnative BS_ItemRestoreHP
.4byte \jumpInstr
.endm
.macro itemcurestatus
.macro itemcurestatus jumpInstr:req
callnative BS_ItemCureStatus
.4byte \jumpInstr
.endm
.macro itemincreasestat

View File

@ -45,16 +45,21 @@ BattleScript_UseItemMessage:
printfromtable gTrainerUsedItemStringIds
waitmessage B_WAIT_TIME_LONG
return
BattleScript_ItemRestoreHP::
call BattleScript_UseItemMessage
itemrestorehp
BattleScript_ItemRestoreHPRet:
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
printstring STRINGID_ITEMRESTOREDSPECIESHEALTH
waitmessage B_WAIT_TIME_LONG
return
BattleScript_ItemRestoreHP::
call BattleScript_UseItemMessage
itemrestorehp BattleScript_ItemRestoreHPEnd
call BattleScript_ItemRestoreHPRet
BattleScript_ItemRestoreHPEnd:
end
BattleScript_ItemRestoreHP_Party::
@ -72,26 +77,19 @@ BattleScript_ItemRestoreHP_SendOutRevivedBattler:
BattleScript_ItemCureStatus::
call BattleScript_UseItemMessage
itemcurestatus
BattleScript_ItemCureStatusAfterItemMsg:
itemcurestatus BattleScript_ItemCureStatusEnd
updatestatusicon BS_SCRIPTING
printstring STRINGID_ITEMCUREDSPECIESSTATUS
waitmessage B_WAIT_TIME_LONG
BattleScript_ItemCureStatusEnd:
end
BattleScript_ItemHealAndCureStatus::
call BattleScript_UseItemMessage
itemrestorehp
itemcurestatus
printstring STRINGID_ITEMRESTOREDSPECIESHEALTH
waitmessage B_WAIT_TIME_LONG
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_SCRIPTING
datahpupdate BS_SCRIPTING
updatestatusicon BS_SCRIPTING
printstring STRINGID_ITEMRESTOREDSPECIESHEALTH
waitmessage B_WAIT_TIME_LONG
end
itemrestorehp BattleScript_ItemCureStatusAfterItemMsg
call BattleScript_ItemRestoreHPRet
goto BattleScript_ItemCureStatusAfterItemMsg
BattleScript_ItemIncreaseStat::
call BattleScript_UseItemMessage
@ -118,7 +116,7 @@ BattleScript_ItemSetFocusEnergy::
setfocusenergy
playmoveanimation BS_ATTACKER, MOVE_FOCUS_ENERGY
waitanimation
copybyte sBATTLER, gBattlerAttacker
copybyte sBATTLER, gBattlerAttacker
printstring STRINGID_PKMNUSEDXTOGETPUMPED
waitmessage B_WAIT_TIME_LONG
end

View File

@ -15793,7 +15793,7 @@ void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBat
void BS_ItemRestoreHP(void)
{
NATIVE_ARGS();
NATIVE_ARGS(const u8 *alreadyMaxHpInstr);
u16 healAmount;
u32 battler = MAX_BATTLERS_COUNT;
u32 healParam = GetItemEffect(gLastUsedItem)[6];
@ -15803,90 +15803,113 @@ void BS_ItemRestoreHP(void)
u16 maxHP = GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_MAX_HP);
gBattleCommunication[MULTIUSE_STATE] = 0;
// Track the number of Revives used in a battle.
if (hp == 0 && side == B_SIDE_PLAYER && gBattleResults.numRevivesUsed < 255)
gBattleResults.numRevivesUsed++;
// Check if the recipient is an active battler.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
battler = gBattlerAttacker;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
battler = BATTLE_PARTNER(gBattlerAttacker);
// Get amount to heal.
switch (healParam)
if (hp == maxHP)
{
case ITEM6_HEAL_HP_FULL:
healAmount = maxHP;
break;
case ITEM6_HEAL_HP_HALF:
healAmount = maxHP / 2;
break;
case ITEM6_HEAL_HP_QUARTER:
healAmount = maxHP / 4;
break;
default:
healAmount = healParam;
break;
}
if (hp + healAmount > maxHP)
healAmount = maxHP - hp;
gBattleScripting.battler = battler;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
// Heal is applied as move damage if battler is active.
if (battler != MAX_BATTLERS_COUNT && hp != 0)
{
gBattleMoveDamage = -healAmount;
gBattlescriptCurrInstr = cmd->nextInstr;
gBattlescriptCurrInstr = cmd->alreadyMaxHpInstr;
}
else
{
hp += healAmount;
SetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP, &hp);
// Track the number of Revives used in a battle.
if (hp == 0 && side == B_SIDE_PLAYER && gBattleResults.numRevivesUsed < 255)
gBattleResults.numRevivesUsed++;
// Revived battlers on the field need to be brought back.
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && battler != MAX_BATTLERS_COUNT)
// Check if the recipient is an active battler.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
battler = gBattlerAttacker;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
battler = BATTLE_PARTNER(gBattlerAttacker);
// Get amount to heal.
switch (healParam)
{
gAbsentBattlerFlags &= ~gBitTable[battler];
gBattleCommunication[MULTIUSE_STATE] = TRUE;
case ITEM6_HEAL_HP_FULL:
healAmount = maxHP;
break;
case ITEM6_HEAL_HP_HALF:
healAmount = maxHP / 2;
break;
case ITEM6_HEAL_HP_QUARTER:
healAmount = maxHP / 4;
break;
default:
healAmount = healParam;
break;
}
if (hp + healAmount > maxHP)
healAmount = maxHP - hp;
gBattleScripting.battler = battler;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
// Heal is applied as move damage if battler is active.
if (battler != MAX_BATTLERS_COUNT && hp != 0)
{
gBattleMoveDamage = -healAmount;
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
{
hp += healAmount;
SetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_HP, &hp);
// Revived battlers on the field need to be brought back.
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && battler != MAX_BATTLERS_COUNT)
{
gAbsentBattlerFlags &= ~gBitTable[battler];
gBattleCommunication[MULTIUSE_STATE] = TRUE;
}
gBattlescriptCurrInstr = BattleScript_ItemRestoreHP_Party;
}
gBattlescriptCurrInstr = BattleScript_ItemRestoreHP_Party;
}
}
void BS_ItemCureStatus(void)
{
NATIVE_ARGS();
NATIVE_ARGS(const u8 *noStatusInstr);
u32 battler = gBattlerAttacker;
u32 side = GetBattlerSide(gBattlerAttacker);
u32 previousStatus2 = 0;
bool32 statusChanged = FALSE;
struct Pokemon *party = GetSideParty(side);
// Heal Status2 conditions if battler is active.
if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker])
{
previousStatus2 = gBattleMons[battler].status2;
gBattleMons[gBattlerAttacker].status2 &= ~GetItemStatus2Mask(gLastUsedItem);
}
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)])
{
gBattleMons[gBattlerAttacker].status2 &= ~GetItemStatus2Mask(gLastUsedItem);
battler = BATTLE_PARTNER(gBattlerAttacker);
previousStatus2 = gBattleMons[battler].status2;
gBattleMons[battler].status2 &= ~GetItemStatus2Mask(gLastUsedItem);
}
if (previousStatus2 != gBattleMons[battler].status2)
statusChanged = TRUE;
// Heal Status1 conditions.
HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], GetItemStatus1Mask(gLastUsedItem), battler);
if (!HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], GetItemStatus1Mask(gLastUsedItem), battler))
{
statusChanged = TRUE;
if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
if (GetItemStatus2Mask(gLastUsedItem) & STATUS2_CONFUSION)
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
}
if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP)
gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE;
if (GetItemStatus2Mask(gLastUsedItem) & STATUS2_CONFUSION)
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
gBattleScripting.battler = battler;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
gBattlescriptCurrInstr = cmd->nextInstr;
if (statusChanged)
{
gBattleScripting.battler = battler;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, GetMonData(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], MON_DATA_SPECIES));
gBattlescriptCurrInstr = cmd->nextInstr;
}
else
{
gBattlescriptCurrInstr = cmd->noStatusInstr;
}
}
void BS_ItemIncreaseStat(void)

View File

@ -974,11 +974,11 @@ u32 GetItemStatus1Mask(u16 itemId)
case ITEM3_BURN:
return STATUS1_BURN;
case ITEM3_POISON:
return STATUS1_POISON | STATUS1_TOXIC_POISON;
return STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER;
case ITEM3_SLEEP:
return STATUS1_SLEEP;
case ITEM3_STATUS_ALL:
return STATUS1_ANY;
return STATUS1_ANY | STATUS1_TOXIC_COUNTER;
}
return 0;
}

View File

@ -46,6 +46,24 @@ SINGLE_BATTLE_TEST("Antidote heals a battler from being badly poisoned")
}
}
SINGLE_BATTLE_TEST("Antidote resets Toxic Counter")
{
GIVEN {
ASSUME(gItems[ITEM_ANTIDOTE].battleUsage == EFFECT_ITEM_CURE_STATUS);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TOXIC); }
TURN { ; }
TURN { USE_ITEM(player, ITEM_ANTIDOTE, partyIndex: 0); }
} SCENE {
MESSAGE("Foe Wobbuffet used Toxic!");
MESSAGE("Wobbuffet had its status healed!");
} THEN {
EXPECT_EQ(player->status1, STATUS1_NONE);
}
}
SINGLE_BATTLE_TEST("Awakening heals a battler from being asleep")
{
GIVEN {

View File

@ -1,6 +1,11 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gItems[ITEM_FULL_RESTORE].battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS);
}
SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary status")
{
u16 status;
@ -10,24 +15,48 @@ SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary s
PARAMETRIZE{ status = STATUS1_POISON; }
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
PARAMETRIZE{ status = STATUS1_SLEEP; }
PARAMETRIZE{ status = STATUS1_NONE; }
GIVEN {
ASSUME(gItems[ITEM_FULL_RESTORE].battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS);
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN{ USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 0); }
} SCENE {
MESSAGE("Wobbuffet had its HP restored!");
if (status != STATUS1_NONE) {
MESSAGE("Wobbuffet had its status healed!"); // The message is not printed if status wasn't healed.
}
} THEN {
EXPECT_EQ(player->hp, player->maxHP);
EXPECT_EQ(player->status1, STATUS1_NONE);
}
}
SINGLE_BATTLE_TEST("Full Restore heals a battler from any primary status")
{
u16 status;
PARAMETRIZE{ status = STATUS1_BURN; }
PARAMETRIZE{ status = STATUS1_FREEZE; }
PARAMETRIZE{ status = STATUS1_PARALYSIS; }
PARAMETRIZE{ status = STATUS1_POISON; }
PARAMETRIZE{ status = STATUS1_TOXIC_POISON; }
PARAMETRIZE{ status = STATUS1_SLEEP; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Status1(status); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 0); }
} SCENE {
NOT MESSAGE("Wobbuffet had its HP restored!"); // The message is not printed if mon has max HP.
MESSAGE("Wobbuffet had its status healed!");
} THEN {
EXPECT_EQ(player->status1, STATUS1_NONE);
}
}
SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures confusion")
{
GIVEN {
ASSUME(gItems[ITEM_FULL_RESTORE].battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS);
PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -41,3 +70,21 @@ SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures confusion")
EXPECT_EQ(player->hp, player->maxHP);
}
}
SINGLE_BATTLE_TEST("Full Restore resets Toxic Counter")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TOXIC); }
TURN { ; }
TURN { USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 0); }
} SCENE {
MESSAGE("Foe Wobbuffet used Toxic!");
MESSAGE("Wobbuffet had its HP restored!");
MESSAGE("Wobbuffet had its status healed!");
} THEN {
EXPECT_EQ(player->status1, STATUS1_NONE);
}
}