From afbda761c3b834ab41aab8425a4307dfd1977202 Mon Sep 17 00:00:00 2001 From: cawtds Date: Tue, 30 Apr 2024 21:20:14 +0200 Subject: [PATCH] updated Cmd_dofaintanimation and Cmd_cleareffectsonfaint --- include/battle.h | 74 ++++- include/battle_main.h | 5 +- src/battle_ai_script_commands.c | 2 +- src/battle_main.c | 508 +++++++++++++++++++------------- src/battle_script_commands.c | 38 ++- 5 files changed, 400 insertions(+), 227 deletions(-) diff --git a/include/battle.h b/include/battle.h index 8b6251f8e..c53b39039 100644 --- a/include/battle.h +++ b/include/battle.h @@ -354,10 +354,23 @@ struct SideTimer // pokeemerald u8 retaliateTimer; u8 stealthRockAmount; + u8 stickyWebBattlerId; }; extern struct SideTimer gSideTimers[]; +struct FieldTimer +{ + u8 mudSportTimer; + u8 waterSportTimer; + u8 wonderRoomTimer; + u8 magicRoomTimer; + u8 trickRoomTimer; + u8 terrainTimer; + u8 gravityTimer; + u8 fairyLockTimer; +}; + struct WishFutureKnock { u8 futureSightCounter[MAX_BATTLERS_COUNT]; @@ -478,6 +491,24 @@ struct LinkBattlerHeader struct BattleEnigmaBerry battleEnigmaBerry; }; +struct MegaEvolutionData +{ + u8 toEvolve; // As flags using gBitTable. + bool8 alreadyEvolved[4]; // Array id is used for mon position. + u8 battlerId; + bool8 playerSelect; + u8 triggerSpriteId; +}; + +struct UltraBurstData +{ + u8 toBurst; // As flags using gBitTable. + bool8 alreadyBursted[4]; // Array id is used for mon position. + u8 battlerId; + bool8 playerSelect; + u8 triggerSpriteId; +}; + struct Illusion { u8 on; @@ -487,6 +518,25 @@ struct Illusion struct Pokemon *mon; }; +struct ZMoveData +{ + u8 viable:1; // current move can become a z move + u8 viewing:1; // if player is viewing the z move name instead of regular moves + u8 active:1; // is z move being used this turn + u8 zStatusActive:1; + u8 healReplacement:1; + u8 activeCategory:2; // active z move category + u8 zUnused:1; + u8 triggerSpriteId; + u8 possibleZMoves[MAX_BATTLERS_COUNT]; + u16 chosenZMove; // z move of move cursor is on + u8 effect; + u8 used[MAX_BATTLERS_COUNT]; //one per bank for multi-battles + u16 toBeUsed[MAX_BATTLERS_COUNT]; // z moves per battler to be used + u16 baseMoves[MAX_BATTLERS_COUNT]; + u8 categories[MAX_BATTLERS_COUNT]; +}; + struct LostItem { u16 originalItem:15; @@ -525,8 +575,8 @@ struct BattleStruct u8 runTries; u8 caughtMonNick[POKEMON_NAME_LENGTH + 1]; u8 field_78; // unused - u8 safariRockThrowCounter; - u8 safariBaitThrowCounter; + u8 safariRockThrowCounter; // safariGoNearCounter in pokeemerald + u8 safariBaitThrowCounter; // safariPkblThrowCounter in pokeemerald u8 safariEscapeFactor; u8 safariCatchFactor; u8 linkBattleVsSpriteId_V; @@ -556,7 +606,7 @@ struct BattleStruct u8 multiplayerId; u8 overworldWeatherDone; u8 atkCancellerTracker; - u16 usedHeldItems[MAX_BATTLERS_COUNT]; + u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle u8 chosenItem[MAX_BATTLERS_COUNT]; // why is this an u8? u8 AI_itemType[2]; u8 AI_itemFlags[2]; @@ -568,7 +618,7 @@ struct BattleStruct u8 turnSideTracker; u8 fillerDC[0xDF-0xDC]; u8 givenExpMons; - u8 lastTakenMoveFrom[MAX_BATTLERS_COUNT * MAX_BATTLERS_COUNT * 2]; + u8 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; u16 castformPalette[MAX_BATTLERS_COUNT][16]; u8 wishPerishSongState; u8 wishPerishSongBattlerId; @@ -612,6 +662,12 @@ struct BattleStruct struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member) u8 savedBattlerTarget; u8 ateBerry[2]; // array id determined by side, each party pokemon as bit + u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching) + struct MegaEvolutionData mega; + struct UltraBurstData burst; + struct ZMoveData zmove; + u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change + bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face. }; // size == 0x200 bytes extern struct BattleStruct *gBattleStruct; @@ -848,6 +904,12 @@ struct PokedudeBattlerState u8 saved_bg0y; }; +struct QueuedStatBoost +{ + u8 stats; // bitfield for each battle stat that is set if the stat changes + s8 statChanges[NUM_BATTLE_STATS - 1]; // highest bit being set decreases the stat +}; /* size = 8 */ + extern u16 gBattle_BG0_X; extern u16 gBattle_BG0_Y; extern u16 gBattle_BG1_X; @@ -952,6 +1014,10 @@ extern s32 gBideDmg[MAX_BATTLERS_COUNT]; extern u8 gBideTarget[MAX_BATTLERS_COUNT]; extern u16 gLastUsedMove; extern u8 gIsCriticalHit; +extern struct FieldTimer gFieldTimers; +extern bool8 gHasFetchedBall; +extern u8 gLastUsedBall; +extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT]; static inline u32 GetBattlerPosition(u32 battler) { diff --git a/include/battle_main.h b/include/battle_main.h index a1893d872..d094ad55b 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -79,8 +79,8 @@ void SpriteCB_PlayerThrowInit(struct Sprite *sprite); void UpdatePlayerPosInThrowAnim(struct Sprite *sprite); void BeginBattleIntroDummy(void); void BeginBattleIntro(void); -void SwitchInClearSetData(void); -void FaintClearSetData(void); +void SwitchInClearSetData(u32 battler); +const u8* FaintClearSetData(u32 battler); void BattleTurnPassed(void); u8 IsRunningFromBattleImpossible(void); void UpdatePartyOwnerOnSwitch_NonMulti(u8 battler); @@ -93,5 +93,6 @@ s8 GetMovePriority(u32 battlerId, u16 move); s8 GetChosenMovePriority(u32 battlerId); u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect); u32 GetBattlerTotalSpeedStat(u32 battler); +void SpecialStatusesClear(void); #endif // GUARD_BATTLE_MAIN_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index af53e9209..82362eb0c 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -1877,7 +1877,7 @@ static void Cmd_get_used_held_item(void) else battlerId = gBattlerTarget; - AI_THINKING_STRUCT->funcResult = ((u8 *)gBattleStruct->usedHeldItems)[battlerId * 2]; + AI_THINKING_STRUCT->funcResult = gBattleStruct->usedHeldItems[battlerId][GetBattlerSide(battlerId)]; sAIScriptPtr += 2; } diff --git a/src/battle_main.c b/src/battle_main.c index 9d6bf7d10..77ce4003a 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -86,7 +86,6 @@ static void SpriteCB_PlayerThrowUpdate(struct Sprite *sprite); static void BattleStartClearSetData(void); static void BattleIntroGetMonsData(void); static void TurnValuesCleanUp(bool8 var0); -static void SpecialStatusesClear(void); static void BattleIntroPrepareBackgroundSlide(void); static void BattleIntroDrawTrainersOrMonsSprites(void); static void BattleIntroDrawPartySummaryScreens(void); @@ -227,6 +226,10 @@ EWRAM_DATA s32 gBideDmg[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u8 gBideTarget[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u16 gLastUsedMove = 0; EWRAM_DATA u8 gIsCriticalHit = FALSE; +EWRAM_DATA struct FieldTimer gFieldTimers = {0}; +EWRAM_DATA bool8 gHasFetchedBall = FALSE; +EWRAM_DATA u8 gLastUsedBall = 0; +EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0}; void (*gPreBattleCallback1)(void); void (*gBattleMainFunc)(void); @@ -2223,26 +2226,37 @@ static void BattleMainCB1(void) gBattlerControllerFuncs[gActiveBattler](); } +static void ClearSetBScriptingStruct(void) +{ + // windowsType is set up earlier in BattleInitBgsAndWindows, so we need to save the value + u32 temp = gBattleScripting.windowsType; + memset(&gBattleScripting, 0, sizeof(gBattleScripting)); + + gBattleScripting.windowsType = temp; + gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; + gBattleScripting.expOnCatch = (B_EXP_CATCH >= GEN_6); +} + static void BattleStartClearSetData(void) { s32 i; - u32 j; - u8 *dataPtr; TurnValuesCleanUp(FALSE); SpecialStatusesClear(); + memset(&gDisableStructs, 0, sizeof(gDisableStructs)); + memset(&gFieldTimers, 0, sizeof(gFieldTimers)); + memset(&gSideStatuses, 0, sizeof(gSideStatuses)); + memset(&gSideTimers, 0, sizeof(gSideTimers)); + memset(&gWishFutureKnock, 0, sizeof(gWishFutureKnock)); + memset(&gBattleResults, 0, sizeof(gBattleResults)); + ClearSetBScriptingStruct(); + for (i = 0; i < MAX_BATTLERS_COUNT; i++) { gStatuses3[i] = 0; gStatuses4[i] = 0; - - dataPtr = (u8 *)&gDisableStructs[i]; - for (j = 0; j < sizeof(struct DisableStruct); j++) - dataPtr[j] = 0; - gDisableStructs[i].isFirstTurn = 2; - sUnusedBattlersArray[i] = 0; gLastMoves[i] = MOVE_NONE; gLastLandedMoves[i] = MOVE_NONE; gLastHitByType[i] = 0; @@ -2251,32 +2265,34 @@ static void BattleStartClearSetData(void) gLockedMoves[i] = MOVE_NONE; gLastPrintedMoves[i] = MOVE_NONE; gBattleResources->flags->flags[i] = 0; + gBattleStruct->lastTakenMove[i] = MOVE_NONE; + gBattleStruct->choicedMove[i] = MOVE_NONE; + gBattleStruct->changedItems[i] = 0; + gBattleStruct->lastTakenMoveFrom[i][0] = MOVE_NONE; + gBattleStruct->lastTakenMoveFrom[i][1] = MOVE_NONE; + gBattleStruct->lastTakenMoveFrom[i][2] = MOVE_NONE; + gBattleStruct->lastTakenMoveFrom[i][3] = MOVE_NONE; + gBattleStruct->AI_monToSwitchIntoId[i] = PARTY_SIZE; + gBattleStruct->skyDropTargets[i] = 0xFF; + gBattleStruct->overwrittenAbilities[i] = ABILITY_NONE; } - for (i = 0; i < 2; i++) - { - gSideStatuses[i] = 0; + gLastUsedMove = 0; + gFieldStatuses = 0; - dataPtr = (u8 *)&gSideTimers[i]; - for (j = 0; j < sizeof(struct SideTimer); j++) - dataPtr[j] = 0; - } + gHasFetchedBall = FALSE; + gLastUsedBall = 0; gBattlerAttacker = 0; gBattlerTarget = 0; + gEffectBattler = 0; + gBattlerAbility = 0; gBattleWeather = 0; - - dataPtr = (u8 *)&gWishFutureKnock; - for (i = 0; i < sizeof(struct WishFutureKnock); i++) - dataPtr[i] = 0; - gHitMarker = 0; if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_POKEDUDE)) && gSaveBlock2Ptr->optionsBattleSceneOff) gHitMarker |= HITMARKER_NO_ANIMATIONS; - gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; - gMultiHitCounter = 0; gBattleOutcome = 0; gBattleControllerExecFlags = 0; @@ -2290,63 +2306,45 @@ static void BattleStartClearSetData(void) gPauseCounterBattle = 0; gBattleMoveDamage = 0; gIntroSlideFlags = 0; - gBattleScripting.animTurn = 0; - gBattleScripting.animTargetsHit = 0; gLeveledUpInBattle = 0; gAbsentBattlerFlags = 0; gBattleStruct->runTries = 0; gBattleStruct->safariRockThrowCounter = 0; gBattleStruct->safariBaitThrowCounter = 0; - *(&gBattleStruct->safariCatchFactor) = gSpeciesInfo[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275; - *(&gBattleStruct->safariEscapeFactor) = gSpeciesInfo[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].safariZoneFleeRate * 100 / 1275; - if (gBattleStruct->safariEscapeFactor <= 1) - gBattleStruct->safariEscapeFactor = 2; + gBattleStruct->safariCatchFactor = gSpeciesInfo[GetMonData(&gEnemyParty[0], MON_DATA_SPECIES)].catchRate * 100 / 1275; + gBattleStruct->safariEscapeFactor = 3; gBattleStruct->wildVictorySong = 0; gBattleStruct->moneyMultiplier = 1; - for (i = 0; i < 8; i++) + gBattleStruct->givenExpMons = 0; + + gBattleResults.shinyWildMon = IsMonShiny(&gEnemyParty[0]); + + gBattleStruct->mega.triggerSpriteId = 0xFF; + gBattleStruct->burst.triggerSpriteId = 0xFF; + + for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) { - *((u8 *)gBattleStruct->lastTakenMove + i) = MOVE_NONE; - *((u8 *)gBattleStruct->usedHeldItems + i) = ITEM_NONE; - *((u8 *)gBattleStruct->choicedMove + i) = MOVE_NONE; - *((u8 *)gBattleStruct->changedItems + i) = ITEM_NONE; - *(i + 0 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(i + 1 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(i + 2 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(i + 3 * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; + gSideTimers[i].stickyWebBattlerId = 0xFF; } - *(gBattleStruct->AI_monToSwitchIntoId + 0) = PARTY_SIZE; - *(gBattleStruct->AI_monToSwitchIntoId + 1) = PARTY_SIZE; - *(&gBattleStruct->givenExpMons) = 0; - for (i = 0; i < 11; i++) - gBattleResults.catchAttempts[i] = 0; - gBattleResults.battleTurnCounter = 0; - gBattleResults.playerFaintCounter = 0; - gBattleResults.opponentFaintCounter = 0; - gBattleResults.playerSwitchesCounter = 0; - gBattleResults.numHealingItemsUsed = 0; - gBattleResults.numRevivesUsed = 0; - gBattleResults.playerMonWasDamaged = FALSE; - gBattleResults.usedMasterBall = FALSE; - gBattleResults.lastOpponentSpecies = SPECIES_NONE; - gBattleResults.lastUsedMovePlayer = MOVE_NONE; - gBattleResults.lastUsedMoveOpponent = MOVE_NONE; - gBattleResults.playerMon1Species = SPECIES_NONE; - gBattleResults.playerMon2Species = SPECIES_NONE; - gBattleResults.caughtMonSpecies = SPECIES_NONE; - for (i = 0; i < POKEMON_NAME_LENGTH; ++i) + gBattleStruct->appearedInBattle = 0; + gBattleStruct->beatUpSlot = 0; + + for (i = 0; i < PARTY_SIZE; i++) { - gBattleResults.playerMon1Name[i] = 0; - gBattleResults.playerMon2Name[i] = 0; - gBattleResults.caughtMonNick[i] = 0; + gBattleStruct->usedHeldItems[i][B_SIDE_PLAYER] = 0; + gBattleStruct->usedHeldItems[i][B_SIDE_OPPONENT] = 0; + gBattleStruct->itemLost[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + gPartyCriticalHits[i] = 0; + gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_PLAYER] = FALSE; + gBattleStruct->allowedToChangeFormInWeather[i][B_SIDE_OPPONENT] = FALSE; } - for (i = 0; i < PARTY_SIZE; i++) { - gPartyCriticalHits[i] = 0; - } + gBattleStruct->swapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky + gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing } -void SwitchInClearSetData(void) +void SwitchInClearSetData(u32 battler) { struct DisableStruct disableStructCopy = gDisableStructs[gActiveBattler]; s32 i; @@ -2355,12 +2353,12 @@ void SwitchInClearSetData(void) if (gMovesInfo[gCurrentMove].effect != EFFECT_BATON_PASS) { for (i = 0; i < NUM_BATTLE_STATS; i++) - gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE; + gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; for (i = 0; i < gBattlersCount; i++) { - if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler) + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler) gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; - if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == gActiveBattler) + if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == battler) { gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; gDisableStructs[i].battlerWithSureHit = 0; @@ -2369,173 +2367,268 @@ void SwitchInClearSetData(void) } if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) { - gBattleMons[gActiveBattler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); - gStatuses3[gActiveBattler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED); - gStatuses4[gActiveBattler] &= (STATUS4_MUD_SPORT | STATUS4_WATER_SPORT); + gBattleMons[battler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY_ANY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); + gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED + | STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK + | STATUS3_AQUA_RING | STATUS3_POWER_TRICK); + gStatuses4[battler] &= (STATUS4_MUD_SPORT | STATUS4_WATER_SPORT | STATUS4_INFINITE_CONFUSION); for (i = 0; i < gBattlersCount; i++) { - if (GetBattlerSide(gActiveBattler) != GetBattlerSide(i) + if (GetBattlerSide(battler) != GetBattlerSide(i) && (gStatuses3[i] & STATUS3_ALWAYS_HITS) != 0 - && (gDisableStructs[i].battlerWithSureHit == gActiveBattler)) + && (gDisableStructs[i].battlerWithSureHit == battler)) { gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; gStatuses3[i] |= STATUS3_ALWAYS_HITS_TURN(2); } } + if (gStatuses3[battler] & STATUS3_POWER_TRICK) + SWAP(gBattleMons[battler].attack, gBattleMons[battler].defense, i); } else { - gBattleMons[gActiveBattler].status2 = 0; - gStatuses3[gActiveBattler] = 0; - gStatuses4[gActiveBattler] = 0; + gBattleMons[battler].status2 = 0; + gStatuses3[battler] = 0; + gStatuses4[battler] = 0; } for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler)) - gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(gActiveBattler); - if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler) + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler)) + gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == battler) gBattleMons[i].status2 &= ~STATUS2_WRAPPED; + if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && *(gBattleStruct->stickySyrupdBy + i) == battler) + gStatuses4[i] &= ~STATUS4_SYRUP_BOMB; } - gActionSelectionCursor[gActiveBattler] = 0; - gMoveSelectionCursor[gActiveBattler] = 0; + gActionSelectionCursor[battler] = 0; + gMoveSelectionCursor[battler] = 0; - ptr = (u8 *)&gDisableStructs[gActiveBattler]; - for (i = 0; i < sizeof(struct DisableStruct); i++) - ptr[i] = 0; + memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct)); if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) { - gDisableStructs[gActiveBattler].substituteHP = disableStructCopy.substituteHP; - gDisableStructs[gActiveBattler].battlerWithSureHit = disableStructCopy.battlerWithSureHit; - gDisableStructs[gActiveBattler].perishSongTimer = disableStructCopy.perishSongTimer; - // gDisableStructs[gActiveBattler].perishSongTimerStartValue = disableStructCopy.perishSongTimerStartValue; - gDisableStructs[gActiveBattler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape; + gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP; + gDisableStructs[battler].battlerWithSureHit = disableStructCopy.battlerWithSureHit; + gDisableStructs[battler].perishSongTimer = disableStructCopy.perishSongTimer; + gDisableStructs[battler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape; + gDisableStructs[battler].embargoTimer = disableStructCopy.embargoTimer; + } + else if (gMovesInfo[gCurrentMove].effect == EFFECT_SHED_TAIL) + { + gBattleMons[battler].status2 |= STATUS2_SUBSTITUTE; + gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP; } gMoveResultFlags = 0; - gDisableStructs[gActiveBattler].isFirstTurn = 2; - gLastMoves[gActiveBattler] = MOVE_NONE; - gLastLandedMoves[gActiveBattler] = MOVE_NONE; - gLastHitByType[gActiveBattler] = 0; - gLastResultingMoves[gActiveBattler] = MOVE_NONE; - gLastPrintedMoves[gActiveBattler] = MOVE_NONE; - gLastHitBy[gActiveBattler] = 0xFF; + gDisableStructs[battler].isFirstTurn = 2; + gDisableStructs[battler].truantSwitchInHack = disableStructCopy.truantSwitchInHack; + gLastMoves[battler] = MOVE_NONE; + gLastLandedMoves[battler] = MOVE_NONE; + gLastHitByType[battler] = 0; + gLastResultingMoves[battler] = MOVE_NONE; + gLastPrintedMoves[battler] = MOVE_NONE; + gLastHitBy[battler] = 0xFF; - *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE; - *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE; - *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + gBattleStruct->lastTakenMove[battler] = 0; + gBattleStruct->sameMoveTurns[battler] = 0; + gBattleStruct->lastTakenMoveFrom[battler][0] = 0; + gBattleStruct->lastTakenMoveFrom[battler][1] = 0; + gBattleStruct->lastTakenMoveFrom[battler][2] = 0; + gBattleStruct->lastTakenMoveFrom[battler][3] = 0; + gBattleStruct->lastMoveFailed &= ~(gBitTable[battler]); + + for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) + { + // Switched into sticky web user slot, so reset stored battler ID + if (gSideTimers[i].stickyWebBattlerId == battler) + gSideTimers[i].stickyWebBattlerId = 0xFF; + } for (i = 0; i < gBattlersCount; i++) { - if (i != gActiveBattler) - { - *(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE; - *(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE; - } - *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + if (i != battler && GetBattlerSide(i) != GetBattlerSide(battler)) + gBattleStruct->lastTakenMove[i] = MOVE_NONE; + + gBattleStruct->lastTakenMoveFrom[i][battler] = 0; } - *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE; - *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE; - - gBattleResources->flags->flags[gActiveBattler] = 0; + gBattleStruct->choicedMove[battler] = MOVE_NONE; + gBattleResources->flags->flags[battler] = 0; gCurrentMove = MOVE_NONE; + + // Reset damage to prevent things like red card activating if the switched-in mon is holding it + gSpecialStatuses[battler].physicalDmg = 0; + gSpecialStatuses[battler].specialDmg = 0; + + // Reset G-Max Chi Strike boosts. + gBattleStruct->bonusCritStages[battler] = 0; + + // TODO: Dynamax + // Reset Dynamax flags. + // UndoDynamax(battler); + + gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; + + // Clear selected party ID so Revival Blessing doesn't get confused. + gSelectedMonPartyId = PARTY_SIZE; + + // TODO: AI + // Ai_UpdateSwitchInData(battler); } -void FaintClearSetData(void) +const u8* FaintClearSetData(u32 battler) { s32 i; - u8 *ptr; + const u8 *result = NULL; + u8 battlerSide = GetBattlerSide(battler); for (i = 0; i < NUM_BATTLE_STATS; i++) - gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE; + gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; - gBattleMons[gActiveBattler].status2 = 0; - gStatuses3[gActiveBattler] = 0; - gStatuses4[gActiveBattler] = 0; + gBattleMons[battler].status2 = 0; + gStatuses3[battler] &= STATUS3_GASTRO_ACID; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out. + gStatuses4[battler] = 0; for (i = 0; i < gBattlersCount; i++) { - if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == gActiveBattler) + if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler) gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; - if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(gActiveBattler)) - gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(gActiveBattler); - if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == gActiveBattler) + if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler)) + gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler); + if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && *(gBattleStruct->wrappedBy + i) == battler) gBattleMons[i].status2 &= ~STATUS2_WRAPPED; + if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && *(gBattleStruct->stickySyrupdBy + i) == battler) + gStatuses4[i] &= ~STATUS4_SYRUP_BOMB; } - gActionSelectionCursor[gActiveBattler] = 0; - gMoveSelectionCursor[gActiveBattler] = 0; + gActionSelectionCursor[battler] = 0; + gMoveSelectionCursor[battler] = 0; - ptr = (u8 *)&gDisableStructs[gActiveBattler]; - for (i = 0; i < sizeof(struct DisableStruct); i++) - ptr[i] = 0; + memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct)); - gProtectStructs[gActiveBattler].protected = FALSE; - gProtectStructs[gActiveBattler].endured = FALSE; - gProtectStructs[gActiveBattler].noValidMoves = FALSE; - gProtectStructs[gActiveBattler].helpingHand = FALSE; - gProtectStructs[gActiveBattler].bounceMove = FALSE; - gProtectStructs[gActiveBattler].stealMove = FALSE; - gProtectStructs[gActiveBattler].prlzImmobility = FALSE; - gProtectStructs[gActiveBattler].confusionSelfDmg = FALSE; - gProtectStructs[gActiveBattler].targetNotAffected = FALSE; - gProtectStructs[gActiveBattler].chargingTurn = FALSE; - gProtectStructs[gActiveBattler].fleeType = 0; - gProtectStructs[gActiveBattler].usedImprisonedMove = FALSE; - gProtectStructs[gActiveBattler].loveImmobility = FALSE; - gProtectStructs[gActiveBattler].usedDisabledMove = FALSE; - gProtectStructs[gActiveBattler].usedTauntedMove = FALSE; - gProtectStructs[gActiveBattler].flag2Unknown = FALSE; - gProtectStructs[gActiveBattler].flinchImmobility = FALSE; - gProtectStructs[gActiveBattler].notFirstStrike = FALSE; + gProtectStructs[battler].protected = FALSE; + gProtectStructs[battler].spikyShielded = FALSE; + gProtectStructs[battler].kingsShielded = FALSE; + gProtectStructs[battler].banefulBunkered = FALSE; + gProtectStructs[battler].quash = FALSE; + gProtectStructs[battler].obstructed = FALSE; + gProtectStructs[battler].silkTrapped = FALSE; + gProtectStructs[battler].burningBulwarked = FALSE; + gProtectStructs[battler].endured = FALSE; + gProtectStructs[battler].noValidMoves = FALSE; + gProtectStructs[battler].helpingHand = FALSE; + gProtectStructs[battler].bounceMove = FALSE; + gProtectStructs[battler].stealMove = FALSE; + gProtectStructs[battler].prlzImmobility = FALSE; + gProtectStructs[battler].confusionSelfDmg = FALSE; + gProtectStructs[battler].targetAffected = FALSE; + gProtectStructs[battler].chargingTurn = FALSE; + gProtectStructs[battler].fleeType = 0; + gProtectStructs[battler].usedImprisonedMove = FALSE; + gProtectStructs[battler].loveImmobility = FALSE; + gProtectStructs[battler].usedDisabledMove = FALSE; + gProtectStructs[battler].usedTauntedMove = FALSE; + gProtectStructs[battler].flag2Unknown = FALSE; + gProtectStructs[battler].flinchImmobility = FALSE; + gProtectStructs[battler].notFirstStrike = FALSE; + gProtectStructs[battler].usedHealBlockedMove = FALSE; + gProtectStructs[battler].usesBouncedMove = FALSE; + gProtectStructs[battler].usedGravityPreventedMove = FALSE; + gProtectStructs[battler].usedThroatChopPreventedMove = FALSE; + gProtectStructs[battler].statRaised = FALSE; + gProtectStructs[battler].statFell = FALSE; + gProtectStructs[battler].pranksterElevated = FALSE; - gDisableStructs[gActiveBattler].isFirstTurn = 2; + gDisableStructs[battler].isFirstTurn = 2; - gLastMoves[gActiveBattler] = MOVE_NONE; - gLastLandedMoves[gActiveBattler] = MOVE_NONE; - gLastHitByType[gActiveBattler] = 0; - gLastResultingMoves[gActiveBattler] = MOVE_NONE; - gLastPrintedMoves[gActiveBattler] = MOVE_NONE; - gLastHitBy[gActiveBattler] = 0xFF; + gLastMoves[battler] = MOVE_NONE; + gLastLandedMoves[battler] = MOVE_NONE; + gLastHitByType[battler] = 0; + gLastResultingMoves[battler] = MOVE_NONE; + gLastPrintedMoves[battler] = MOVE_NONE; + gLastHitBy[battler] = 0xFF; - *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 0) = MOVE_NONE; - *((u8 *)(&gBattleStruct->choicedMove[gActiveBattler]) + 1) = MOVE_NONE; + gBattleStruct->choicedMove[battler] = MOVE_NONE; + gBattleStruct->sameMoveTurns[battler] = 0; + gBattleStruct->lastTakenMove[battler] = MOVE_NONE; + gBattleStruct->lastTakenMoveFrom[battler][0] = 0; + gBattleStruct->lastTakenMoveFrom[battler][1] = 0; + gBattleStruct->lastTakenMoveFrom[battler][2] = 0; + gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 0) = MOVE_NONE; - *(gBattleStruct->lastTakenMove + gActiveBattler * 2 + 1) = MOVE_NONE; - *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(0 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(1 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(2 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; - *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(3 * 2 + gActiveBattler * 8 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) + { + // User of sticky web fainted, so reset the stored battler ID + if (gSideTimers[i].stickyWebBattlerId == battler) + gSideTimers[i].stickyWebBattlerId = 0xFF; + } for (i = 0; i < gBattlersCount; i++) { - if (i != gActiveBattler) - { - *(gBattleStruct->lastTakenMove + i * 2 + 0) = MOVE_NONE; - *(gBattleStruct->lastTakenMove + i * 2 + 1) = MOVE_NONE; - } - *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 0) = 0; - *(i * 8 + gActiveBattler * 2 + (u8 *)(gBattleStruct->lastTakenMoveFrom) + 1) = 0; + if (i != battler && GetBattlerSide(i) != battlerSide) + gBattleStruct->lastTakenMove[i] = MOVE_NONE; + + gBattleStruct->lastTakenMoveFrom[i][battler] = 0; } - gBattleResources->flags->flags[gActiveBattler] = 0; - gBattleMons[gActiveBattler].type1 = gSpeciesInfo[gBattleMons[gActiveBattler].species].types[0]; - gBattleMons[gActiveBattler].type2 = gSpeciesInfo[gBattleMons[gActiveBattler].species].types[1]; + + gBattleResources->flags->flags[battler] = 0; + + gBattleMons[battler].type1 = gSpeciesInfo[gBattleMons[battler].species].types[0]; + gBattleMons[battler].type2 = gSpeciesInfo[gBattleMons[battler].species].types[1]; + gBattleMons[battler].type3 = TYPE_MYSTERY; + + // TODO: AI + // Ai_UpdateFaintData(battler); + TryBattleFormChange(battler, FORM_CHANGE_FAINT); + + gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; + + // If the fainted mon was involved in a Sky Drop + if (gBattleStruct->skyDropTargets[battler] != 0xFF) + { + // Get battler id of the other Pokemon involved in this Sky Drop + u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler]; + + // Clear Sky Drop data + gBattleStruct->skyDropTargets[battler] = 0xFF; + gBattleStruct->skyDropTargets[otherSkyDropper] = 0xFF; + + // If the other Pokemon involved in this Sky Drop was the target, not the attacker + if (gStatuses3[otherSkyDropper] & STATUS3_SKY_DROPPED) + { + // Release the target and take them out of the semi-invulnerable state + gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR); + + // Make the target's sprite visible + gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE; + + // If the target was sky dropped in the middle of using Outrage/Petal Dance/Thrash, + // confuse them upon release and print "confused via fatigue" message and animation. + if (gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE) + { + gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE); + + // If the released mon can be confused, do so. + // Don't use CanBeConfused here, since it can cause issues in edge cases. + if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO + || gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION + || IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN))) + { + gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); + gBattlerAttacker = otherSkyDropper; + result = BattleScript_ThrashConfuses; + } + } + } + } + + // Clear Z-Move data + gBattleStruct->zmove.active = FALSE; + gBattleStruct->zmove.toBeUsed[battler] = MOVE_NONE; + gBattleStruct->zmove.effect = EFFECT_HIT; + return result; } static void BattleIntroGetMonsData(void) @@ -3646,47 +3739,52 @@ static void SetActionsAndBattlersTurnOrder(void) static void TurnValuesCleanUp(bool8 var0) { s32 i; - u8 *dataPtr; - for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) + for (i = 0; i < gBattlersCount; i++) { if (var0) { - gProtectStructs[gActiveBattler].protected = FALSE; - gProtectStructs[gActiveBattler].endured = FALSE; + gProtectStructs[i].protected = FALSE; + gProtectStructs[i].spikyShielded = FALSE; + gProtectStructs[i].kingsShielded = FALSE; + gProtectStructs[i].banefulBunkered = FALSE; + gProtectStructs[i].quash = FALSE; + gProtectStructs[i].usedCustapBerry = FALSE; + gProtectStructs[i].quickDraw = FALSE; + memset(&gQueuedStatBoosts[i], 0, sizeof(struct QueuedStatBoost)); } else { - dataPtr = (u8 *)(&gProtectStructs[gActiveBattler]); - for (i = 0; i < sizeof(struct ProtectStruct); i++) - dataPtr[i] = 0; - if (gDisableStructs[gActiveBattler].isFirstTurn) - --gDisableStructs[gActiveBattler].isFirstTurn; - if (gDisableStructs[gActiveBattler].rechargeTimer) + memset(&gProtectStructs[i], 0, sizeof(struct ProtectStruct)); + + if (gDisableStructs[i].isFirstTurn) + gDisableStructs[i].isFirstTurn--; + + if (gDisableStructs[i].rechargeTimer) { - --gDisableStructs[gActiveBattler].rechargeTimer; - if (gDisableStructs[gActiveBattler].rechargeTimer == 0) - gBattleMons[gActiveBattler].status2 &= ~(STATUS2_RECHARGE); + gDisableStructs[i].rechargeTimer--; + if (gDisableStructs[i].rechargeTimer == 0) + gBattleMons[i].status2 &= ~STATUS2_RECHARGE; } } - if (gDisableStructs[gActiveBattler].substituteHP == 0) - gBattleMons[gActiveBattler].status2 &= ~(STATUS2_SUBSTITUTE); + if (gDisableStructs[i].substituteHP == 0) + gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + + gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; } - gSideTimers[0].followmeTimer = 0; - gSideTimers[1].followmeTimer = 0; + + gSideStatuses[B_SIDE_PLAYER] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); + gSideStatuses[B_SIDE_OPPONENT] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); + gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; + gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; + + gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller } -static void SpecialStatusesClear(void) +void SpecialStatusesClear(void) { - for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++) - { - s32 i; - u8 *dataPtr = (u8 *)(&gSpecialStatuses[gActiveBattler]); - - for (i = 0; i < sizeof(struct SpecialStatus); i++) - dataPtr[i] = 0; - } + memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses)); } static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 05a2b84ea..660378421 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -394,8 +394,8 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_seteffectsecondary, //0x17 // done Cmd_clearstatusfromeffect, //0x18 // done Cmd_tryfaintmon, //0x19 // done - Cmd_dofaintanimation, //0x1A - Cmd_cleareffectsonfaint, //0x1B + Cmd_dofaintanimation, //0x1A // done + Cmd_cleareffectsonfaint, //0x1B // done Cmd_jumpifstatus, //0x1C Cmd_jumpifstatus2, //0x1D Cmd_jumpifability, //0x1E @@ -4092,27 +4092,35 @@ static void Cmd_tryfaintmon(void) static void Cmd_dofaintanimation(void) { + CMD_ARGS(u8 battler); + if (gBattleControllerExecFlags == 0) { - gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); + u32 battler = gActiveBattler = GetBattlerForBattleScript(cmd->battler); BtlController_EmitFaintAnimation(BUFFER_A); - MarkBattlerForControllerExec(gActiveBattler); - gBattlescriptCurrInstr += 2; + MarkBattlerForControllerExec(battler); + gBattlescriptCurrInstr = cmd->nextInstr; } } static void Cmd_cleareffectsonfaint(void) { + CMD_ARGS(u8 battler); + if (gBattleControllerExecFlags == 0) { - gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); + u32 battler = gActiveBattler = GetBattlerForBattleScript(cmd->battler); + const u8 *clearDataResult = NULL; - gBattleMons[gActiveBattler].status1 = 0; - BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gActiveBattler].status1), &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); + gBattleMons[battler].status1 = 0; + BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1); + MarkBattlerForControllerExec(battler); - FaintClearSetData(); // Effects like attractions, trapping, etc. - gBattlescriptCurrInstr += 2; + clearDataResult = FaintClearSetData(battler); // Effects like attractions, trapping, etc. + if (clearDataResult) + gBattlescriptCurrInstr = clearDataResult; + else + gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -5706,7 +5714,7 @@ static void Cmd_switchindataupdate(void) gBattleMons[gActiveBattler].status2 = oldData.status2; } - SwitchInClearSetData(); + SwitchInClearSetData(gActiveBattler); gBattleScripting.battler = gActiveBattler; @@ -6851,7 +6859,7 @@ static void Cmd_removeitem(void) gActiveBattler = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); - usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler]; + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler][GetBattlerSide(gActiveBattler)]; *usedHeldItem = gBattleMons[gActiveBattler].item; gBattleMons[gActiveBattler].item = ITEM_NONE; @@ -7719,7 +7727,7 @@ static void Cmd_trymirrormove(void) { if (i != gBattlerAttacker) { - move = T1_READ_16(i * 2 + gBattlerAttacker * 8 + gBattleStruct->lastTakenMoveFrom); + move = gBattleStruct->lastTakenMoveFrom[gBattlerAttacker][i]; if (move != MOVE_NONE && move != MOVE_UNAVAILABLE) { @@ -10740,7 +10748,7 @@ static void Cmd_tryrecycleitem(void) u16 *usedHeldItem; gActiveBattler = gBattlerAttacker; - usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler]; + usedHeldItem = &gBattleStruct->usedHeldItems[gActiveBattler][GetBattlerSide(gActiveBattler)]; if (*usedHeldItem != ITEM_NONE && gBattleMons[gActiveBattler].item == ITEM_NONE) { gLastUsedItem = *usedHeldItem;