diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 85f090e1f6..6c98d530df 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1755,14 +1755,14 @@ various \battler, VARIOUS_JUMP_IF_ABSENT .4byte \ptr .endm - - .macro activateitemeffects battler:req - various \battler, VARIOUS_MOVEEND_ITEM_EFFECTS - .endm - - .macro pickpocketsteal - various 0, VARIOUS_PICKPOCKET - .endm + + .macro activateitemeffects battler:req + various \battler, VARIOUS_MOVEEND_ITEM_EFFECTS + .endm + + .macro pickpocketsteal + various 0, VARIOUS_PICKPOCKET + .endm @ helpful macros .macro setstatchanger stat:req, stages:req, down:req diff --git a/include/battle.h b/include/battle.h index 15c4a466b9..ffa500ace5 100644 --- a/include/battle.h +++ b/include/battle.h @@ -541,6 +541,7 @@ struct BattleStruct u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used. u16 moveEffect2; // For Knock Off u16 changedSpecies[PARTY_SIZE]; // For Zygarde or future forms when multiple mons can change into the same pokemon. + u16 itemStolen[PARTY_SIZE]; //player's team that had items stolen (bit per party member) }; #define GET_MOVE_TYPE(move, typeArg) \ diff --git a/include/battle_util.h b/include/battle_util.h index 36364bdb79..4623cff263 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -132,6 +132,6 @@ bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId); u8 GetBattleMoveSplit(u32 moveId); void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast); bool32 TestSheerForceFlag(u8 battler, u16 move); -bool32 ItemCanBeStolen(u16 item, u8 battlerId); +void TryRestoreStolenItems(void); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 4659e15958..6412129a09 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -132,6 +132,7 @@ #define B_SLEEP_TURNS GEN_6 // In Gen5+, sleep lasts for 1-3 turns instead of 2-5 turns. #define B_PARALYZE_ELECTRIC GEN_6 // In Gen6+, Electric type Pokémon can't be paralyzed. #define B_POWDER_GRASS GEN_6 // In Gen6+, Grass type Pokémon are immune to powder and spore moves. +#define B_TRAINERS_STEAL_ITEMS TRUE // If TRUE, trainer with thief/pickpocket will temporarily steal your items // Animation Settings #define B_NEW_SWORD_PARTICLE TRUE // If set to TRUE, it updates Swords Dance's particle. diff --git a/src/battle_main.c b/src/battle_main.c index 781f9e20b3..34280b32cc 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4819,6 +4819,10 @@ static void HandleEndTurn_FinishBattle(void) sub_8186444(); BeginFastPaletteFade(3); FadeOutMapMusic(5); + #if B_TRAINERS_STEAL_ITEMS + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + TryRestoreStolenItems(); + #endif for (i = 0; i < PARTY_SIZE; i++) { UndoMegaEvolution(i); @@ -4837,7 +4841,7 @@ static void HandleEndTurn_FinishBattle(void) static void FreeResetData_ReturnToOvOrDoEvolutions(void) { if (!gPaletteFade.active) - { + { ResetSpriteData(); if (gLeveledUpInBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index d5b57af483..676fe31e7d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2369,6 +2369,35 @@ static void CheckSetUnburden(u8 battlerId) } } +//slight difference in thief/pickpocket requires this +static void StealTargetItem(void) +{ + gLastUsedItem = gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerTarget].item; + gBattleMons[gBattlerTarget].item = 0; + + RecordItemEffectBattle(gBattlerTarget, 0); + RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem)); + //item assignment doesn't happen yet for thief + + CheckSetUnburden(gBattlerTarget); + gBattleResources->flags->flags[gBattlerAttacker] &= ~(RESOURCE_FLAG_UNBURDEN); + + gActiveBattler = gBattlerAttacker; + BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); + MarkBattlerForControllerExec(gBattlerAttacker); + + gActiveBattler = gBattlerTarget; + BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item); + MarkBattlerForControllerExec(gBattlerTarget); + + gBattleStruct->choicedMove[gBattlerTarget] = 0; + + #if B_TRAINERS_STEAL_ITEMS + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) + gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerTarget]] = gLastUsedItem; + #endif +} + #define INCREMENT_RESET_RETURN \ { \ gBattlescriptCurrInstr++; \ @@ -2922,7 +2951,7 @@ void SetMoveEffect(bool32 primary, u32 certain) break; case MOVE_EFFECT_STEAL_ITEM: { - if (!ItemCanBeStolen(gBattleMons[gBattlerTarget].item, gBattlerAttacker)) + if (!CanBattlerGetOrLoseItem(gBattlerAttacker, gBattleMons[gBattlerTarget].item)) { gBattlescriptCurrInstr++; break; @@ -2944,28 +2973,9 @@ void SetMoveEffect(bool32 primary, u32 certain) } else { - gLastUsedItem = gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerTarget].item; - gBattleMons[gBattlerTarget].item = 0; - - RecordItemEffectBattle(gBattlerTarget, 0); - RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem)); - //item assignment doesn't happen yet - - CheckSetUnburden(gBattlerTarget); - gBattleResources->flags->flags[gBattlerAttacker] &= ~(RESOURCE_FLAG_UNBURDEN); - - gActiveBattler = gBattlerAttacker; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); - MarkBattlerForControllerExec(gBattlerAttacker); - - gActiveBattler = gBattlerTarget; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item); - MarkBattlerForControllerExec(gBattlerTarget); - + StealTargetItem(); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_ItemSteal; - - gBattleStruct->choicedMove[gBattlerTarget] = 0; } } @@ -5022,7 +5032,7 @@ static void Cmd_moveend(void) && !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler) //subsitute unaffected && IsBattlerAlive(battler) //battler must be alive to be pickpocketed && gBattleMons[battler].item == ITEM_NONE //pickpocketer can't have an item already - && ItemCanBeStolen(gBattleMons[gBattlerAttacker].item, battler)) //cannot steal plates, mega stones, etc + && CanBattlerGetOrLoseItem(battler, gBattleMons[gBattlerAttacker].item)) //cannot steal plates, mega stones, etc { gBattlerTarget = gBattlerAbility = battler; BattleScriptPushCursor(); @@ -8316,28 +8326,9 @@ static void Cmd_various(void) break; case VARIOUS_PICKPOCKET: { - // different from MOVE_EFFECT_STEAL_ITEM in that it immediately assigns the stolen item to the 'attacker' - gEffectBattler = gBattlerTarget; gBattleScripting.battler = gBattlerAttacker; - gLastUsedItem = gBattleMons[gEffectBattler].item; - gBattleMons[gEffectBattler].item = 0; + StealTargetItem(); gBattleMons[gBattlerAttacker].item = gLastUsedItem; - - RecordItemEffectBattle(gBattlerTarget, 0); - RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem)); - - CheckSetUnburden(gEffectBattler); //Give target Unburden boost - gBattleResources->flags->flags[gBattlerTarget] &= ~(RESOURCE_FLAG_UNBURDEN); //remove attacker boost - - gActiveBattler = gBattlerAttacker; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); - MarkBattlerForControllerExec(gActiveBattler); - - gActiveBattler = gEffectBattler; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gActiveBattler].item); - MarkBattlerForControllerExec(gActiveBattler); - - gBattleStruct->choicedMove[gEffectBattler] = 0; } break; } @@ -11066,7 +11057,11 @@ static void Cmd_tryswapitems(void) // trick | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_SECRET_BASE - | BATTLE_TYPE_x2000000)))) + | BATTLE_TYPE_x2000000 + #if B_TRAINERS_STEAL_ITEMS + | BATTLE_TYPE_TRAINER + #endif + )))) { gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); } @@ -11130,6 +11125,16 @@ static void Cmd_tryswapitems(void) // trick PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) + + #if B_TRAINERS_STEAL_ITEMS + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerAttacker]] = oldItemAtk; + if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) + gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerTarget]] = *newItemAtk; + } + #endif if (oldItemAtk != 0 && *newItemAtk != 0) gBattleCommunication[MULTISTRING_CHOOSER] = 2; // attacker's item -> <- target's item diff --git a/src/battle_util.c b/src/battle_util.c index 91d10af230..480e1d57d7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -7793,61 +7793,16 @@ bool32 TestSheerForceFlag(u8 battler, u16 move) return FALSE; } -bool32 ItemCanBeStolen(u16 item, u8 battlerId) +void TryRestoreStolenItems(void) { - u8 effect = ItemId_GetHoldEffect(item); + u32 i; + u16 stolenItem = ITEM_NONE; - if (item == ITEM_ENIGMA_BERRY) - return FALSE; - - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL) - return FALSE; - - if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT - && !(gBattleTypeFlags & - (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_SECRET_BASE))) + for (i = 0; i < PARTY_SIZE; i++) { - return FALSE; + stolenItem = gBattleStruct->itemStolen[i]; + if (stolenItem != ITEM_NONE && ItemId_GetPocket(stolenItem) != POCKET_BERRIES) + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &stolenItem); //restore stolen non-berry items } - else if (!(gBattleTypeFlags & - (BATTLE_TYPE_EREADER_TRAINER - | BATTLE_TYPE_FRONTIER - | BATTLE_TYPE_LINK - | BATTLE_TYPE_x2000000 - | BATTLE_TYPE_SECRET_BASE)) - && (gWishFutureKnock.knockedOffMons[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]])) - { - return FALSE; - } - - if (IS_ITEM_MAIL(item)) - return FALSE; - - switch (effect) - { - case HOLD_EFFECT_MEGA_STONE: - #ifdef HOLD_EFFECT_MEMORY - case HOLD_EFFECT_MEMORY: - #endif - #ifdef HOLD_EFFECT_Z_CRYSTAL - case HOLD_EFFECT_Z_CRYSTAL: - #endif - #ifdef HOLD_EFFECT_DRIVE - case HOLD_EFFECT_DRIVE: - #endif - #ifdef HOLD_EFFECT_GEMS - case HOLD_EFFECT_GEMS: - #endif - #ifdef HOLD_EFFECT_GRISEOUS_ORB - case HOLD_EFFECT_GRISEOUS_ORB: - #endif - return FALSE; - } - - return TRUE; }