diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index f51871d1f..0f512dc88 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7700,10 +7700,25 @@ BattleScript_AnnounceAirLockCloudNine:: BattleScript_Pickpocket:: call BattleScript_AbilityPopUp - setmoveeffect MOVE_EFFECT_STEAL_ITEM + jumpifability BS_ATTACKER, ABILITY_STICKY_HOLD, BattleScript_PickpocketPrevented swapattackerwithtarget - pickpocketsteal call BattleScript_ItemSteal swapattackerwithtarget activateitemeffects BS_TARGET return + +BattleScript_PickpocketPrevented: + pause 0x20 + copybyte gBattlerAbility, gBattlerAttacker + call BattleScript_AbilityPopUp + printstring STRINGID_ITEMCANNOTBEREMOVED + waitmessage 0x40 + return + +BattleScript_StickyBarbTransfer:: + playanimation BS_TARGET, B_ANIM_ITEM_STEAL, NULL + printstring STRINGID_STICKYBARBTRANSFER + waitmessage 0x40 + removeitem BS_TARGET + return + \ No newline at end of file diff --git a/include/battle.h b/include/battle.h index 5c62d0711..fe71c52e6 100644 --- a/include/battle.h +++ b/include/battle.h @@ -427,6 +427,12 @@ struct Illusion struct Pokemon *mon; }; +struct StolenItem +{ + u16 originalItem:15; + u16 stolen:1; +}; + struct BattleStruct { u8 turnEffectsTracker; @@ -541,7 +547,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) + struct StolenItem 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_script_commands.h b/include/battle_script_commands.h index 454b6ab34..60f108520 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -26,6 +26,7 @@ u32 IsFlowerVeilProtected(u32 battler); u32 IsLeafGuardProtected(u32 battler); bool32 IsShieldsDownProtected(u32 battler); u32 IsAbilityStatusProtected(u32 battler); +void StealTargetItem(u8 battlerStealer, u8 battlerItem); extern void (* const gBattleScriptingCommandsTable[])(void); extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 37447ded9..0084a3eab 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -351,5 +351,6 @@ extern const u8 BattleScript_EmergencyExitWildNoPopUp[]; extern const u8 BattleScript_CheekPouchActivates[]; extern const u8 BattleScript_AnnounceAirLockCloudNine[]; extern const u8 BattleScript_Pickpocket[]; +extern const u8 BattleScript_StickyBarbTransfer[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index 39d8de6a8..3a6746450 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -133,6 +133,8 @@ u8 GetBattleMoveSplit(u32 moveId); void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast); bool32 TestSheerForceFlag(u8 battler, u16 move); void TryRestoreStolenItems(void); -bool8 CanStealItem(u8 battlerId, u16 item); +bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item); +void TrySaveExchangedItem(u8 battlerId, u16 stolenItem); +bool32 IsPartnerMonFromSameTrainer(u8 battlerId); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 816a4b991..95c7a57be 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -166,7 +166,6 @@ #define VARIOUS_PARALYZE_TYPE_IMMUNITY 100 #define VARIOUS_JUMP_IF_ABSENT 101 #define VARIOUS_MOVEEND_ITEM_EFFECTS 102 -#define VARIOUS_PICKPOCKET 103 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 9348d67d5..8ddea0f21 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -558,8 +558,10 @@ #define STRINGID_AURABREAKENTERS 554 #define STRINGID_COMATOSEENTERS 555 #define STRINGID_SCREENCLEANERENTERS 556 +#define STRINGID_ITEMCANNOTBEREMOVED 557 +#define STRINGID_STICKYBARBTRANSFER 558 -#define BATTLESTRINGS_COUNT 557 +#define BATTLESTRINGS_COUNT 559 //// multichoice message IDs // switch in ability message diff --git a/src/battle_main.c b/src/battle_main.c index a916e3e27..3d589084f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -2941,6 +2941,9 @@ static void BattleStartClearSetData(void) gBattleStruct->arenaLostOpponentMons = 0; gBattleStruct->mega.triggerSpriteId = 0xFF; + + for (i = 0; i < PARTY_SIZE; i++) + gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); } void SwitchInClearSetData(void) diff --git a/src/battle_message.c b/src/battle_message.c index 35ccc6e26..6dba30a31 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -685,9 +685,13 @@ static const u8 sText_FairyAuraActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} static const u8 sText_AuraBreakActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} reversed all\nother POKéMON's auras!"); static const u8 sText_ComatoseActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is drowsing!"); static const u8 sText_ScreenCleanerActivates[] = _("All screens on the field were\ncleansed!"); +static const u8 sText_ItemCannotBeRemoved[] = _("{B_ATK_NAME_WITH_PREFIX}'s item cannot be removed!"); +static const u8 sText_StickyBarbTransfer[] = _("The {B_LAST_ITEM} attached itself to\n{B_ATK_NAME_WITH_PREFIX}!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_STICKYBARBTRANSFER - 12] = sText_StickyBarbTransfer, + [STRINGID_ITEMCANNOTBEREMOVED - 12] = sText_ItemCannotBeRemoved, [STRINGID_STATWASNOTLOWERED - 12] = sText_StatWasNotLowered, [STRINGID_CLOAKEDINAFREEZINGLIGHT - 12] = sText_CloakedInAFreezingLight, [STRINGID_DESTINYKNOTACTIVATES - 12] = sText_DestinyKnotActivates, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 34d2271c9..1d236a3a9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2369,33 +2369,30 @@ 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; +// battlerStealer steals the item of battlerItem +void StealTargetItem(u8 battlerStealer, u8 battlerItem) +{ + gLastUsedItem = gBattleMons[battlerItem].item; + gBattleMons[battlerItem].item = 0; - RecordItemEffectBattle(gBattlerTarget, 0); - RecordItemEffectBattle(gBattlerAttacker, ItemId_GetHoldEffect(gLastUsedItem)); - //item assignment doesn't happen yet for thief + RecordItemEffectBattle(battlerItem, 0); + RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); + gBattleMons[battlerStealer].item = gLastUsedItem; - CheckSetUnburden(gBattlerTarget); - gBattleResources->flags->flags[gBattlerAttacker] &= ~(RESOURCE_FLAG_UNBURDEN); + CheckSetUnburden(battlerItem); + gBattleResources->flags->flags[battlerStealer] &= ~(RESOURCE_FLAG_UNBURDEN); - gActiveBattler = gBattlerAttacker; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); - MarkBattlerForControllerExec(gBattlerAttacker); + gActiveBattler = battlerStealer; + BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem); // set attacker item + MarkBattlerForControllerExec(battlerStealer); - gActiveBattler = gBattlerTarget; - BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[gBattlerTarget].item); - MarkBattlerForControllerExec(gBattlerTarget); + gActiveBattler = battlerItem; + BtlController_EmitSetMonData(0, REQUEST_HELDITEM_BATTLE, 0, 2, &gBattleMons[battlerItem].item); // remove target item + MarkBattlerForControllerExec(battlerItem); - gBattleStruct->choicedMove[gBattlerTarget] = 0; + gBattleStruct->choicedMove[battlerItem] = 0; - #if B_TRAINERS_KNOCK_OFF_ITEMS == TRUE - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) - gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerTarget]] = gLastUsedItem; - #endif + TrySaveExchangedItem(battlerItem, gLastUsedItem); } #define INCREMENT_RESET_RETURN \ @@ -2951,7 +2948,7 @@ void SetMoveEffect(bool32 primary, u32 certain) break; case MOVE_EFFECT_STEAL_ITEM: { - if (!CanStealItem(gBattlerAttacker, gBattleMons[gBattlerTarget].item)) + if (!CanStealItem(gBattlerAttacker, gBattlerTarget, gBattleMons[gBattlerTarget].item)) { gBattlescriptCurrInstr++; break; @@ -2966,14 +2963,15 @@ void SetMoveEffect(bool32 primary, u32 certain) } else if (gBattleMons[gBattlerAttacker].item != 0 || gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY - || IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item) || gBattleMons[gBattlerTarget].item == 0) { gBattlescriptCurrInstr++; } else { - StealTargetItem(); + StealTargetItem(gBattlerAttacker, gBattlerTarget); //attacker steals target item + gBattleMons[gBattlerAttacker].item = 0; //item assigned later on with thief (see MOVEEND_CHANGED_ITEMS) + gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // stolen item to be assigned later BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_ItemSteal; } @@ -5014,29 +5012,33 @@ static void Cmd_moveend(void) break; case MOVEEND_PICKPOCKET: if (IsBattlerAlive(gBattlerAttacker) - && GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD - && gBattleMons[gBattlerAttacker].item != ITEM_NONE //attacker must be holding an item - && !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) //pickpocket doesn't activate for sheer force - && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) //pickpocket requires contact - && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) //obviously attack needs to have worked + && gBattleMons[gBattlerAttacker].item != ITEM_NONE // attacker must be holding an item + && !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)) // pickpocket doesn't activate for sheer force + && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) // pickpocket requires contact + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) // obviously attack needs to have worked { u8 battlers[4] = {0, 1, 2, 3}; - SortBattlersBySpeed(battlers, FALSE); //pickpocket activates for fastest mon without item + SortBattlersBySpeed(battlers, FALSE); // pickpocket activates for fastest mon without item for (i = 0; i < gBattlersCount; i++) { u8 battler = battlers[i]; - //attacker is mon who made contact, battler is mon with pickpocket - if (battler != gBattlerAttacker //cannot pickpocket yourself - && GetBattlerAbility(battler) == ABILITY_PICKPOCKET //'target' must have pickpocket ability - && BATTLER_DAMAGED(battler) //obviously battler needs to have been damaged as well - && !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler) //subsitute unaffected - && IsBattlerAlive(battler) //battler must be alive to pickpocket - && gBattleMons[battler].item == ITEM_NONE //pickpocketer can't have an item already - && CanStealItem(battler, gBattleMons[gBattlerAttacker].item)) //cannot steal plates, mega stones, etc + // attacker is mon who made contact, battler is mon with pickpocket + if (battler != gBattlerAttacker // cannot pickpocket yourself + && GetBattlerAbility(battler) == ABILITY_PICKPOCKET // 'target' must have pickpocket ability + && BATTLER_DAMAGED(battler) // target needs to have been damaged + && !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler) // subsitute unaffected + && IsBattlerAlive(battler) // battler must be alive to pickpocket + && gBattleMons[battler].item == ITEM_NONE // pickpocketer can't have an item already + && CanStealItem(battler, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) // cannot steal plates, mega stones, etc { gBattlerTarget = gBattlerAbility = battler; + // battle scripting is super brittle so we shall do the item exchange now (if possible) + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD) + StealTargetItem(gBattlerTarget, gBattlerAttacker); // target takes attacker's item + + gEffectBattler = gBattlerAttacker; BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_Pickpocket; + gBattlescriptCurrInstr = BattleScript_Pickpocket; // includes sticky hold check to print separate string effect = TRUE; break; // pickpocket activates on fastest mon, so exit loop. } @@ -8322,14 +8324,8 @@ static void Cmd_various(void) } return; case VARIOUS_MOVEEND_ITEM_EFFECTS: - ItemBattleEffects(1, gActiveBattler, FALSE); - break; - case VARIOUS_PICKPOCKET: - { - gBattleScripting.battler = gBattlerAttacker; - StealTargetItem(); - gBattleMons[gBattlerAttacker].item = gLastUsedItem; - } + if (ItemBattleEffects(1, gActiveBattler, FALSE)) + return; break; } @@ -11126,15 +11122,14 @@ static void Cmd_tryswapitems(void) // trick PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) - #if B_TRAINERS_KNOCK_OFF_ITEMS - if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) + if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker))) { + // if targeting your own side and you aren't in a multi battle, don't save items as stolen if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) - gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerAttacker]] = oldItemAtk; + TrySaveExchangedItem(gBattlerAttacker, oldItemAtk); if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) - gBattleStruct->itemStolen[gBattlerPartyIndexes[gBattlerTarget]] = *newItemAtk; + TrySaveExchangedItem(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 83af12f9d..a503dfc48 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5388,18 +5388,6 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) case HOLD_EFFECT_BLACK_SLUDGE: if (IS_BATTLER_OF_TYPE(battlerId, TYPE_POISON)) goto LEFTOVERS; - case HOLD_EFFECT_STICKY_BARB: - if (!moveTurn) - { - gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8; - if (gBattleMoveDamage == 0) - gBattleMoveDamage = 1; - BattleScriptExecute(BattleScript_ItemHurtEnd2); - effect = ITEM_HP_CHANGE; - RecordItemEffectBattle(battlerId, battlerHoldEffect); - PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); - } - break; case HOLD_EFFECT_LEFTOVERS: LEFTOVERS: if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn) @@ -5862,6 +5850,22 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) gBattleScripting.statChanger = SET_STATCHANGER(STAT_SPATK, 1, FALSE); } break; + case HOLD_EFFECT_STICKY_BARB: + if (TARGET_TURN_DAMAGED + && (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) + && IsMoveMakingContact(gCurrentMove, gBattlerAttacker) + && !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battlerId) + && IsBattlerAlive(gBattlerAttacker) + && gBattleMons[gBattlerAttacker].item == ITEM_NONE) + { + //no sticky hold checks. item is already known so no CanStealItem checks + gEffectBattler = battlerId; //effect battler = target + StealTargetItem(gBattlerAttacker, gBattlerTarget); //attacker takes target's barb + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StickyBarbTransfer; + effect = ITEM_EFFECT_OTHER; + } + break; } } break; @@ -5890,6 +5894,18 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) RecordItemEffectBattle(battlerId, battlerHoldEffect); } break; + case HOLD_EFFECT_STICKY_BARB: //not an orb per-say, but similar effect, and needs to NOT activate with pickpocket + if (GetBattlerAbility(battlerId) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = gBattleMons[battlerId].maxHP / 8; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + BattleScriptExecute(BattleScript_ItemHurtEnd2); + effect = ITEM_HP_CHANGE; + RecordItemEffectBattle(battlerId, battlerHoldEffect); + PREPARE_ITEM_BUFFER(gBattleTextBuff1, gLastUsedItem); + } + break; } if (effect == ITEM_STATUS_CHANGE) @@ -7553,7 +7569,7 @@ s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId) return dmg; } -static bool32 IsPartnerMonFromSameTrainer(u8 battlerId) +bool32 IsPartnerMonFromSameTrainer(u8 battlerId) { if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) return FALSE; @@ -7721,25 +7737,37 @@ bool32 DoBattlersShareType(u32 battler1, u32 battler2) bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId) { u16 species = gBattleMons[battlerId].species; - - if (IS_ITEM_MAIL(itemId)) - return FALSE; - else if (itemId == ITEM_ENIGMA_BERRY) + u16 holdEffect = ItemId_GetHoldEffect(itemId); + + // Mail can be stolen now + if (itemId == ITEM_ENIGMA_BERRY) return FALSE; else if (species == SPECIES_KYOGRE && itemId == ITEM_BLUE_ORB) return FALSE; else if (species == SPECIES_GROUDON && itemId == ITEM_RED_ORB) return FALSE; // Mega stone cannot be lost if pokemon can mega evolve with it or is already mega evolved. - else if (ItemId_GetHoldEffect(itemId) == HOLD_EFFECT_MEGA_STONE - && ((GetMegaEvolutionSpecies(species, itemId) != SPECIES_NONE) || gBattleStruct->mega.evolvedPartyIds[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]])) + else if (holdEffect == HOLD_EFFECT_MEGA_STONE + && ((GetMegaEvolutionSpecies(species, itemId) != SPECIES_NONE) + || gBattleStruct->mega.evolvedPartyIds[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]])) return FALSE; +#ifdef HOLD_EFFECT_PRIMAL_ORB + // Primal orbs cannot be lost if the species can undergo primal reversion (no need to check if it has since it always does) + else if (holdEffect == HOLD_EFFECT_PRIMAL_ORB + && ((GetPrimalMegaEvolutionSpecies(species, itemId) != SPECIES_NONE)) +#endif else if (species == SPECIES_GIRATINA && itemId == ITEM_GRISEOUS_ORB) return FALSE; else if (species == SPECIES_GENESECT && GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_DRIVE) return FALSE; else if (species == SPECIES_SILVALLY && GetBattlerHoldEffect(battlerId, FALSE) == HOLD_EFFECT_MEMORY) return FALSE; + else if (species == SPECIES_ARCEUS && holdEffect == HOLD_EFFECT_PLATE) + return FALSE; +#ifdef HOLD_EFFECT_Z_CRYSTAL + else if (holdEffect == HOLD_EFFECT_Z_CRYSTAL) + return FALSE; +#endif else return TRUE; } @@ -7835,40 +7863,40 @@ u8 GetBattleMoveSplit(u32 moveId) // useful for effects like pickpocket, eject button, red card, dancer void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast) { - int i, j, key, keyBank; - u16 speeds[4] = {0}; + int i, j, currSpeed, currBattler; + u16 speeds[4] = {0}; - for (i = 0; i < gBattlersCount; i++) - speeds[i] = GetBattlerTotalSpeedStat(battlers[i]); + for (i = 0; i < gBattlersCount; i++) + speeds[i] = GetBattlerTotalSpeedStat(battlers[i]); - for (i = 1; i < gBattlersCount; i++) - { - keyBank = battlers[i]; - key = speeds[i]; - j = i - 1; + for (i = 1; i < gBattlersCount; i++) + { + currBattler = battlers[i]; + currSpeed = speeds[i]; + j = i - 1; - if (slowToFast) - { - while (j >= 0 && speeds[j] > key) - { - battlers[j + 1] = battlers[j]; - speeds[j + 1] = speeds[j]; - j = j - 1; - } - } - else - { - while (j >= 0 && speeds[j] < key) - { - battlers[j + 1] = battlers[j]; - speeds[j + 1] = speeds[j]; - j = j - 1; - } - } + if (slowToFast) + { + while (j >= 0 && speeds[j] > currSpeed) + { + battlers[j + 1] = battlers[j]; + speeds[j + 1] = speeds[j]; + j = j - 1; + } + } + else + { + while (j >= 0 && speeds[j] < currSpeed) + { + battlers[j + 1] = battlers[j]; + speeds[j + 1] = speeds[j]; + j = j - 1; + } + } - battlers[j + 1] = keyBank; - speeds[j + 1] = key; - } + battlers[j + 1] = currBattler; + speeds[j + 1] = currSpeed; + } } bool32 TestSheerForceFlag(u8 battler, u16 move) @@ -7886,18 +7914,24 @@ void TryRestoreStolenItems(void) for (i = 0; i < PARTY_SIZE; i++) { - 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 + if (gBattleStruct->itemStolen[i].stolen) + { + stolenItem = gBattleStruct->itemStolen[i].originalItem; + if (stolenItem != ITEM_NONE && ItemId_GetPocket(stolenItem) != POCKET_BERRIES) + SetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM, &stolenItem); //restore stolen non-berry items + } } } -bool8 CanStealItem(u8 battlerId, u16 item) +bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item) { + u8 stealerSide = GetBattlerSide(battlerStealing); + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_HILL) return FALSE; - - if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT + + // check if the battler trying to steal should be able to + if (stealerSide == B_SIDE_OPPONENT && !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_FRONTIER @@ -7917,11 +7951,25 @@ bool8 CanStealItem(u8 battlerId, u16 item) | BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000 | BATTLE_TYPE_SECRET_BASE)) - && (gWishFutureKnock.knockedOffMons[GetBattlerSide(battlerId)] & gBitTable[gBattlerPartyIndexes[battlerId]])) + && (gWishFutureKnock.knockedOffMons[stealerSide] & gBitTable[gBattlerPartyIndexes[battlerStealing]])) { return FALSE; } - return CanBattlerGetOrLoseItem(battlerId, item); + // check if battler with the item can lose it + return CanBattlerGetOrLoseItem(battlerItem, item); } +void TrySaveExchangedItem(u8 battlerId, u16 stolenItem) +{ + // because BtlController_EmitSetMonData does SetMonData, we need to save the stolen item only if it matches the battler's original + // so, if the player steals an item during battle and has it stolen from it, it will not end the battle with it (naturally) + #if B_TRAINERS_KNOCK_OFF_ITEMS == TRUE + // If regular trainer battle and mon's original item matches what is being stolen, save it to be restored at end of battle + if (gBattleTypeFlags & BATTLE_TYPE_TRAINER + && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) + && GetBattlerSide(battlerId) == B_SIDE_PLAYER + && stolenItem == gBattleStruct->itemStolen[gBattlerPartyIndexes[battlerId]].originalItem) + gBattleStruct->itemStolen[gBattlerPartyIndexes[battlerId]].stolen = TRUE; + #endif +}