From 0ad3f929abb96561eeb1de439cd5f4dd9adf97be Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 11 May 2025 11:34:16 +0200 Subject: [PATCH] Fixes Berserk Gene infinite loop (#6813) --- data/battle_scripts_1.s | 14 ++++-- include/battle_scripts.h | 1 + src/battle_util.c | 64 ++++++++++---------------- test/battle/hold_effect/berserk_gene.c | 16 +++++++ 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 7a47fff5b5..11797e72ed 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -10041,15 +10041,16 @@ BattleScript_CouldntFullyProtect:: return BattleScript_BerserkGeneRet:: + saveattacker savetarget copybyte gBattlerTarget, sBATTLER statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_BerserkGeneRet_TryConfuse setgraphicalstatchangevalues - playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 + playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM call BattleScript_StatUp BattleScript_BerserkGeneRet_TryConfuse: - jumpifability BS_SCRIPTING, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents + jumpifability BS_ATTACKER, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents jumpifsafeguard BattleScript_BerserkGeneRet_SafeguardProtected seteffectprimary MOVE_EFFECT_CONFUSION goto BattleScript_BerserkGeneRet_End @@ -10064,9 +10065,14 @@ BattleScript_BerserkGeneRet_OwnTempoPrevents: printstring STRINGID_PKMNPREVENTSCONFUSIONWITH waitmessage B_WAIT_TIME_LONG BattleScript_BerserkGeneRet_End: + restoreattacker restoretarget - removeitem BS_SCRIPTING - end3 + removeitem BS_ATTACKER + return + +BattleScript_BerserkGeneRetEnd2:: + call BattleScript_BerserkGeneRet + end2 BattleScript_BoosterEnergyEnd2:: call BattleScript_BoosterEnergyRet diff --git a/include/battle_scripts.h b/include/battle_scripts.h index d840ab5666..958cd71892 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -492,6 +492,7 @@ extern const u8 BattleScript_MoveEffectStockpileWoreOff[]; extern const u8 BattleScript_StealthRockActivates[]; extern const u8 BattleScript_SpikesActivates[]; extern const u8 BattleScript_BerserkGeneRet[]; +extern const u8 BattleScript_BerserkGeneRetEnd2[]; extern const u8 BattleScript_TargetFormChangeWithStringNoPopup[]; extern const u8 BattleScript_DefDown[]; extern const u8 BattleScript_UltraBurst[]; diff --git a/src/battle_util.c b/src/battle_util.c index ccd4d6fb2d..3b6818b8dd 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7163,6 +7163,28 @@ static enum ItemEffect TryEjectPack(u32 battler, enum ItemCaseId caseID) return ITEM_NO_EFFECT; } +static enum ItemEffect ConsumeBerserkGene(u32 battler, enum ItemCaseId caseID) +{ + if (CanBeInfinitelyConfused(battler)) + gStatuses4[battler] |= STATUS4_INFINITE_CONFUSION; + + BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE); + gBattlerAttacker = gEffectBattler = battler; + SET_STATCHANGER(STAT_ATK, 2, FALSE); + gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; + gBattleScripting.animArg2 = 0; + if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) + { + BattleScriptExecute(BattleScript_BerserkGeneRetEnd2); + } + else + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerserkGeneRet; + } + return ITEM_STATS_CHANGE; +} + static u32 ItemRestorePp(u32 battler, u32 itemId, enum ItemCaseId caseID) { struct Pokemon *party = GetBattlerParty(battler); @@ -7577,19 +7599,7 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect) } break; case HOLD_EFFECT_BERSERK_GENE: - BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE); - gEffectBattler = battler; - if (CanBeInfinitelyConfused(gEffectBattler)) - { - gStatuses4[gEffectBattler] |= STATUS4_INFINITE_CONFUSION; - } - SET_STATCHANGER(STAT_ATK, 2, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; - gBattleScripting.animArg2 = 0; - - BattleScriptPushCursorAndCallback(BattleScript_BerserkGeneRet); - effect = ITEM_STATS_CHANGE; + effect = ConsumeBerserkGene(battler, ITEMEFFECT_NONE); break; case HOLD_EFFECT_MIRROR_HERB: effect = TryConsumeMirrorHerb(battler, ITEMEFFECT_NONE); @@ -7860,19 +7870,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) effect = TryEjectPack(battler, caseID); break; case HOLD_EFFECT_BERSERK_GENE: - BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE); - gEffectBattler = battler; - if (CanBeInfinitelyConfused(gEffectBattler)) - { - gStatuses4[gEffectBattler] |= STATUS4_INFINITE_CONFUSION; - } - SET_STATCHANGER(STAT_ATK, 2, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; - gBattleScripting.animArg2 = 0; - - BattleScriptPushCursorAndCallback(BattleScript_BerserkGeneRet); - effect = ITEM_STATS_CHANGE; + effect = ConsumeBerserkGene(battler, caseID); break; case HOLD_EFFECT_MIRROR_HERB: effect = TryConsumeMirrorHerb(battler, caseID); @@ -8072,19 +8070,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) effect = TrySetMicleBerry(battler, gLastUsedItem, caseID); break; case HOLD_EFFECT_BERSERK_GENE: - BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE); - gEffectBattler = battler; - if (CanBeInfinitelyConfused(gEffectBattler)) - { - gStatuses4[gEffectBattler] |= STATUS4_INFINITE_CONFUSION; - } - SET_STATCHANGER(STAT_ATK, 2, FALSE); - - gBattleScripting.animArg1 = STAT_ANIM_PLUS1 + STAT_ATK; - gBattleScripting.animArg2 = 0; - - BattleScriptPushCursorAndCallback(BattleScript_BerserkGeneRet); - effect = ITEM_STATS_CHANGE; + effect = ConsumeBerserkGene(battler, caseID); break; case HOLD_EFFECT_MIRROR_HERB: effect = TryConsumeMirrorHerb(battler, caseID); diff --git a/test/battle/hold_effect/berserk_gene.c b/test/battle/hold_effect/berserk_gene.c index 164830ad52..640198c992 100644 --- a/test/battle/hold_effect/berserk_gene.c +++ b/test/battle/hold_effect/berserk_gene.c @@ -236,3 +236,19 @@ SINGLE_BATTLE_TEST("Berserk Gene causes confusion timer to not tick down", u32 s EXPECT_EQ(results[0].status2, results[1].status2); } } + +SINGLE_BATTLE_TEST("Berserk Gene does not cause an infinite loop") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_BESTOW) == EFFECT_BESTOW); + PLAYER(SPECIES_TOXEL) { Item(ITEM_BERSERK_GENE); Ability(ABILITY_KLUTZ); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BESTOW); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Using Berserk Gene, the Attack of the opposing Wobbuffet sharply rose!"); + } +}