From 6e5f40d506405af3e9a0621dcc91c13c12e7db47 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sat, 11 Jan 2025 11:12:22 +0100 Subject: [PATCH] Introduces BattlerState struct for the Battle Engine (#5954) --- include/battle.h | 54 +++++++++++++++---------- include/battle_util.h | 3 ++ src/battle_ai_main.c | 2 +- src/battle_ai_switch_items.c | 4 +- src/battle_ai_util.c | 4 +- src/battle_arena.c | 5 +-- src/battle_interface.c | 22 +++++++--- src/battle_main.c | 59 ++++++++++----------------- src/battle_script_commands.c | 78 ++++++++++++++++++------------------ src/battle_util.c | 68 +++++++++++++++++++++---------- 10 files changed, 166 insertions(+), 133 deletions(-) diff --git a/include/battle.h b/include/battle.h index 05c3b3a822..673da55299 100644 --- a/include/battle.h +++ b/include/battle.h @@ -137,6 +137,7 @@ struct DisableStruct u8 terrainAbilityDone:1; u8 usedProteanLibero:1; u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching) + u8 boosterEnergyActivates:1; }; struct ProtectStruct @@ -235,6 +236,8 @@ struct SpecialStatus u8 teraShellAbilityDone:1; u8 criticalHit:1; // End of byte + u8 enduredDamage:1; + u8 padding:7; }; struct SideTimer @@ -621,8 +624,32 @@ enum BattleIntroStates BATTLE_INTRO_STATE_SET_DEX_AND_BATTLE_VARS }; +struct BattlerState +{ + u8 targetsDone[MAX_BATTLERS_COUNT]; + + u32 commandingDondozo:1; + u32 absentBattlerFlags:1; + u32 focusPunchBattlers:1; + u32 multipleSwitchInBattlers:1; + u32 alreadyStatusedMoveAttempt:1; // For example when using Thunder Wave on an already paralyzed Pokémon. + u32 activeAbilityPopUps:1; + u32 lastMoveFailed:1; // For Stomping Tantrum + u32 forcedSwitch:1; + u32 storedHealingWish:1; + u32 storedLunarDance:1; + u32 usedEjectItem:1; + u32 sleepClauseEffectExempt:1; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore) + u32 usedMicleBerry:1; + u32 pursuitTarget:1; + u32 padding:17; + // End of Word +}; + +// Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise. struct BattleStruct { + struct BattlerState battlerState[MAX_BATTLERS_COUNT]; u8 turnEffectsTracker; u8 turnEffectsBattlerId; u8 turnCountersTracker; @@ -640,7 +667,6 @@ struct BattleStruct u8 wildVictorySong; u8 dynamicMoveType; u8 wrappedBy[MAX_BATTLERS_COUNT]; - u8 focusPunchBattlers; // as bits u8 battlerPreventingSwitchout; u8 moneyMultiplier:6; u8 moneyMultiplierItem:1; @@ -681,9 +707,9 @@ struct BattleStruct u8 hpScale; u16 synchronizeMoveEffect; u8 anyMonHasTransformed:1; // Only used in battle_tv.c - u8 multipleSwitchInBattlers:4; // One bit per battler u8 multipleSwitchInState:2; u8 multipleSwitchInCursor:3; + u8 padding1:2; u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT]; void (*savedCallback)(void); u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle @@ -720,7 +746,6 @@ struct BattleStruct u16 arenaStartHp[2]; u8 arenaLostPlayerMons; // Bits for party member, lost as in referee's decision, not by fainting. u8 arenaLostOpponentMons; - u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon. u8 debugBattler; u8 magnitudeBasePower; u8 presentBasePower; @@ -730,7 +755,6 @@ struct BattleStruct u8 savedTargetCount:4; u8 savedAttackerCount:4; bool8 ateBoost[MAX_BATTLERS_COUNT]; - u8 activeAbilityPopUps; // as bits for each battler u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler struct ZMoveData zmove; struct DynamaxData dynamax; @@ -739,7 +763,6 @@ struct BattleStruct enum BattleIntroStates introState:8; u8 ateBerry[2]; // array id determined by side, each party pokemon as bit u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages - u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct u16 tracedAbility[MAX_BATTLERS_COUNT]; u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell. @@ -754,8 +777,6 @@ struct BattleStruct u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. u8 quickClawBattlerId; struct LostItem itemLost[NUM_BATTLE_SIDES][PARTY_SIZE]; // Pokemon that had items consumed or stolen (two bytes per party member per side) - u8 forcedSwitch:4; // For each battler - u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects u8 blunderPolicy:1; // should blunder policy activate u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky u8 bouncedMoveIsUsed:1; @@ -773,10 +794,7 @@ struct BattleStruct u8 hitSwitchTargetFailed:1; u8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects. u8 spriteIgnore0Hp:1; - u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit. u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party. - u8 storedHealingWish:4; // Each battler as a bit. - u8 storedLunarDance:4; // Each battler as a bit. u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; @@ -795,7 +813,6 @@ struct BattleStruct u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 enduredDamage; u8 transformZeroToHero[NUM_BATTLE_SIDES]; u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; @@ -806,18 +823,13 @@ struct BattleStruct u8 quickDrawRandom[MAX_BATTLERS_COUNT]; u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; u8 speedTieBreaks; // MAX_BATTLERS_COUNT! values. - u8 boosterEnergyActivates; u8 categoryOverride; // for Z-Moves and Max Moves - u8 commandingDondozo; u16 commanderActive[MAX_BATTLERS_COUNT]; u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side - u8 redCardActivates:1; - u8 padding1:7; - u8 usedEjectItem; u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party - u8 sleepClauseEffectExempt:4; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore) - u8 usedMicleBerry:4; - u8 pursuitTarget:4; // Each battler as a bit. + u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects + u8 redCardActivates:1; + u8 padding2:2; // padding in the middle so pursuit fields are together u8 pursuitSwitchByMove:1; u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; @@ -833,7 +845,7 @@ struct BattleStruct u8 calculatedSpreadMoveAccuracy:1; u8 printedStrongWindsWeakenedAttack:1; u8 numSpreadTargets:2; - u8 padding2:2; + u8 padding3:2; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, @@ -1190,7 +1202,7 @@ static inline bool32 IsBattlerTurnDamaged(u32 battler) { return gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0 - || gBattleStruct->enduredDamage & (1u << battler); + || gSpecialStatuses[battler].enduredDamage; } static inline bool32 IsBattlerAtMaxHp(u32 battler) diff --git a/include/battle_util.h b/include/battle_util.h index 5ab72967dc..57beae337e 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -339,5 +339,8 @@ void ClearDamageCalcResults(void); u32 DoesDestinyBondFail(u32 battler); bool32 IsMoveEffectBlockedByTarget(u32 ability); u32 NumAffectedSpreadMoveTargets(void); +bool32 IsPursuitTargetSet(void); +void ClearPursuitValuesIfSet(u32 battler); +void ClearPursuitValues(void); #endif // GUARD_BATTLE_UTIL_H diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index d856fae81f..b4b1909237 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -734,7 +734,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) RETURN_SCORE_MINUS(10); - if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].commandingDondozo) RETURN_SCORE_MINUS(20); // check if negates type diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 8a8fe367ac..7522c7ec05 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -40,11 +40,11 @@ static void InitializeSwitchinCandidate(struct Pokemon *mon) static bool32 IsAceMon(u32 battler, u32 monPartyId) { if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON - && !(gBattleStruct->forcedSwitch & (1u << battler)) + && !gBattleStruct->battlerState[battler].forcedSwitch && monPartyId == CalculateEnemyPartyCountInSide(battler)-1) return TRUE; if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON - && !(gBattleStruct->forcedSwitch & (1u << battler)) + && !gBattleStruct->battlerState[battler].forcedSwitch && (monPartyId == CalculateEnemyPartyCount()-1 || monPartyId == CalculateEnemyPartyCount()-2)) return TRUE; return FALSE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 7306237de4..c9a3ae07b2 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -430,7 +430,7 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy if (battlerDef == BATTLE_PARTNER(battlerAtk)) battlerDefAbility = aiData->abilities[battlerDef]; - if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].commandingDondozo) return TRUE; if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef])) @@ -1511,7 +1511,7 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u32 move) { if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) return TRUE; - else if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + else if (gBattleStruct->battlerState[battlerDef].commandingDondozo) return TRUE; else if (!MoveDamagesAirborne(move) && gStatuses3[battlerDef] & STATUS3_ON_AIR) return TRUE; diff --git a/src/battle_arena.c b/src/battle_arena.c index ff406a37df..dd0f0c1bbd 100644 --- a/src/battle_arena.c +++ b/src/battle_arena.c @@ -386,10 +386,9 @@ void BattleArena_AddSkillPoints(u8 battler) if (gHitMarker & HITMARKER_OBEYS) { - u8 *failedMoveBits = &gBattleStruct->alreadyStatusedMoveAttempt; - if (*failedMoveBits & (1u << battler)) + if (gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt) { - *failedMoveBits &= ~((1u << battler)); + gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt = FALSE; skillPoints[battler] -= 2; } else if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) diff --git a/src/battle_interface.c b/src/battle_interface.c index 5c514a0d80..196f338495 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -2695,6 +2695,17 @@ static void RestoreOverwrittenPixels(u8 *tiles) Free(buffer); } +static inline bool32 IsAnyAbilityPopUpActive(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleStruct->battlerState[battler].activeAbilityPopUps) + return TRUE; + } + + return FALSE; +} + void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) { const s16 (*coords)[2]; @@ -2713,12 +2724,13 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) return; } - if (!gBattleStruct->activeAbilityPopUps) + if (!IsAnyAbilityPopUpActive()) { LoadSpriteSheet(&sSpriteSheet_AbilityPopUp); LoadSpritePalette(&sSpritePalette_AbilityPopUp); } - gBattleStruct->activeAbilityPopUps |= 1u << battlerId; + + gBattleStruct->battlerState[battlerId].activeAbilityPopUps = TRUE; battlerPosition = GetBattlerPosition(battlerId); if (isDoubleBattle) @@ -2809,7 +2821,7 @@ static void SpriteCb_AbilityPopUp(struct Sprite *sprite) ||(sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE) ) { - gBattleStruct->activeAbilityPopUps &= ~(1u << sprite->tBattlerId); + gBattleStruct->battlerState[sprite->tBattlerId].activeAbilityPopUps = FALSE; DestroySprite(sprite); } } @@ -2823,7 +2835,7 @@ static void SpriteCb_AbilityPopUp(struct Sprite *sprite) void DestroyAbilityPopUp(u8 battlerId) { - if (gBattleStruct->activeAbilityPopUps & (1u << battlerId)) + if (gBattleStruct->battlerState[battlerId].activeAbilityPopUps) { gSprites[gBattleStruct->abilityPopUpSpriteIds[battlerId][0]].tFrames = 0; gSprites[gBattleStruct->abilityPopUpSpriteIds[battlerId][1]].tFrames = 0; @@ -2835,7 +2847,7 @@ static void Task_FreeAbilityPopUpGfx(u8 taskId) { if (!gSprites[gTasks[taskId].tSpriteId1].inUse && !gSprites[gTasks[taskId].tSpriteId2].inUse - && !gBattleStruct->activeAbilityPopUps) + && !IsAnyAbilityPopUpActive()) { FreeSpriteTilesByTag(ABILITY_POP_UP_TAG); FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); diff --git a/src/battle_main.c b/src/battle_main.c index ebc391983a..e0072829e0 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3133,10 +3133,8 @@ static void BattleStartClearSetData(void) gBattleStruct->swapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky gBattleStruct->categoryOverride = FALSE; // used for Z-Moves and Max Moves - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; + ClearPursuitValues(); gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing gCategoryIconSpriteId = 0xFF; @@ -3243,17 +3241,11 @@ void SwitchInClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - gBattleStruct->lastMoveFailed &= ~(1u << battler); + gBattleStruct->battlerState[battler].lastMoveFailed = FALSE; gBattleStruct->palaceFlags &= ~(1u << battler); - gBattleStruct->boosterEnergyActivates &= ~(1u << battler); gBattleStruct->canPickupItem &= ~(1u << battler); - if (gBattleStruct->pursuitTarget & (1u << battler)) - { - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; - } + ClearPursuitValuesIfSet(battler); for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) { @@ -3278,7 +3270,7 @@ void SwitchInClearSetData(u32 battler) // 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; - gBattleStruct->enduredDamage &= ~(1u << battler); + gSpecialStatuses[battler].enduredDamage = FALSE; // Reset Eject Button / Eject Pack switch detection AI_DATA->ejectButtonSwitch = FALSE; @@ -3383,16 +3375,9 @@ const u8* FaintClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - - if (gBattleStruct->pursuitTarget & (1u << battler)) - { - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; - } - gBattleStruct->palaceFlags &= ~(1u << battler); - gBattleStruct->boosterEnergyActivates &= ~(1u << battler); + + ClearPursuitValuesIfSet(battler); if (gBattleStruct->commanderActive[battler] != SPECIES_NONE) { @@ -3953,10 +3938,10 @@ static void TryDoEventsBeforeFirstTurn(void) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; gChosenActionByBattler[i] = B_ACTION_NONE; gChosenMoveByBattler[i] = MOVE_NONE; + gBattleStruct->battlerState[i].absentBattlerFlags = gAbsentBattlerFlags & (1u << i); } TurnValuesCleanUp(FALSE); SpecialStatusesClear(); - *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); gBattleMainFunc = HandleTurnActionSelectionState; @@ -4070,12 +4055,12 @@ void BattleTurnPassed(void) { gChosenActionByBattler[i] = B_ACTION_NONE; gChosenMoveByBattler[i] = MOVE_NONE; + gBattleStruct->battlerState[i].absentBattlerFlags = gAbsentBattlerFlags & (1u << i); } for (i = 0; i < MAX_BATTLERS_COUNT; i++) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; - *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); SetShellSideArmCategory(); @@ -4259,10 +4244,10 @@ static void HandleTurnActionSelectionState(void) *(gBattleStruct->monToSwitchIntoId + battler) = PARTY_SIZE; if (gBattleTypeFlags & BATTLE_TYPE_MULTI || (position & BIT_FLANK) == B_FLANK_LEFT - || gBattleStruct->absentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position))) + || gBattleStruct->battlerState[GetBattlerAtPosition(BATTLE_PARTNER(position))].absentBattlerFlags || gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED) { - if ((gBattleStruct->absentBattlerFlags & (1u << battler)) || (gBattleStruct->commandingDondozo & (1u << battler))) + if (gBattleStruct->battlerState[battler].absentBattlerFlags || gBattleStruct->battlerState[battler].commandingDondozo) { gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED; if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) @@ -4637,7 +4622,7 @@ static void HandleTurnActionSelectionState(void) if (((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !IsDoubleBattle()) || (position & BIT_FLANK) != B_FLANK_LEFT - || (*(&gBattleStruct->absentBattlerFlags) & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position))))) + || gBattleStruct->battlerState[GetBattlerAtPosition(BATTLE_PARTNER(position))].absentBattlerFlags) { BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_STOP_BOUNCE, i); } @@ -4803,9 +4788,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) speed *= 2; else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) speed /= 2; - else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gDisableStructs[battler].boosterEnergyActivates)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; - else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivates)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; // stat stages @@ -5186,9 +5171,10 @@ static void TurnValuesCleanUp(bool8 var0) gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; if (!(gStatuses3[i] & STATUS3_COMMANDER)) - gBattleStruct->commandingDondozo &= ~(1u << i); + gBattleStruct->battlerState[i].commandingDondozo = FALSE; gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; + gBattleStruct->battlerState[i].usedEjectItem = FALSE; } gSideStatuses[B_SIDE_PLAYER] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); @@ -5196,11 +5182,8 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; - gBattleStruct->usedEjectItem = 0; - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller + ClearPursuitValues(); ClearDamageCalcResults(); } @@ -5264,12 +5247,12 @@ static bool32 TryDoMoveEffectsBeforeMoves(void) SortBattlersBySpeed(battlers, FALSE); for (i = 0; i < gBattlersCount; i++) { - if (!(gBattleStruct->focusPunchBattlers & (1u << battlers[i])) + if (!gBattleStruct->battlerState[battlers[i]].focusPunchBattlers && !(gBattleMons[battlers[i]].status1 & STATUS1_SLEEP) && !(gDisableStructs[battlers[i]].truantCounter) && !(gProtectStructs[battlers[i]].noValidMoves)) { - gBattleStruct->focusPunchBattlers |= 1u << battlers[i]; + gBattleStruct->battlerState[battlers[i]].focusPunchBattlers = TRUE; gBattlerAttacker = battlers[i]; switch (GetMoveEffect(gChosenMoveByBattler[gBattlerAttacker])) { @@ -5390,9 +5373,9 @@ static void CheckChangingTurnOrderEffects(void) gCurrentActionFuncId = gActionsByTurnOrder[0]; gBattleStruct->dynamicMoveType = 0; gBattleStruct->effectsBeforeUsingMoveDone = FALSE; - gBattleStruct->focusPunchBattlers = 0; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { + gBattleStruct->battlerState[i].focusPunchBattlers = FALSE; gBattleStruct->ateBoost[i] = FALSE; gSpecialStatuses[i].gemBoost = FALSE; } @@ -5412,7 +5395,7 @@ static void RunTurnActionsFunctions(void) // Mega Evolve / Focus Punch-like moves after switching, items, running, but before using a move. if (gCurrentActionFuncId == B_ACTION_USE_MOVE && !gBattleStruct->effectsBeforeUsingMoveDone) { - if (!gBattleStruct->pursuitTarget) + if (!IsPursuitTargetSet()) { if (TryDoGimmicksBeforeMoves()) return; @@ -5690,7 +5673,7 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) IncrementDexNavChain(); else gSaveBlock3Ptr->dexNavChain = 0; - + gDexNavBattle = FALSE; ResetSpriteData(); if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2c50f26d9d..29b075e855 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1166,9 +1166,9 @@ static void Cmd_attackcanceler(void) s32 i; - if (gBattleStruct->usedEjectItem & (1u << gBattlerAttacker)) + if (gBattleStruct->battlerState[gBattlerAttacker].usedEjectItem) { - gBattleStruct->usedEjectItem = 0; + gBattleStruct->battlerState[gBattlerAttacker].usedEjectItem = FALSE; gCurrentActionFuncId = B_ACTION_TRY_FINISH; return; } @@ -1432,7 +1432,7 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) { effect = TRUE; } - else if (gBattleStruct->pursuitTarget & (1u << battler)) + else if (gBattleStruct->battlerState[battler].pursuitTarget) { effect = TRUE; } @@ -1581,7 +1581,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u break; } - if (gBattleStruct->usedMicleBerry & 1u << battlerAtk) + if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry) { if (atkAbility == ABILITY_RIPEN) calc = (calc * 140) / 100; // ripen gives 40% acc boost @@ -2128,7 +2128,7 @@ static void Cmd_adjustdamage(void) if (DoesDisguiseBlockMove(battlerDef, gCurrentMove)) { - gBattleStruct->enduredDamage |= 1u << battlerDef; + gSpecialStatuses[battlerDef].enduredDamage = TRUE; continue; } if (GetBattlerAbility(battlerDef) == ABILITY_ICE_FACE && IsBattleMovePhysical(gCurrentMove) && gBattleMons[battlerDef].species == SPECIES_EISCUE) @@ -2182,7 +2182,7 @@ static void Cmd_adjustdamage(void) // Handle reducing the dmg to 1 hp. gBattleStruct->moveDamage[battlerDef] = gBattleMons[battlerDef].hp - 1; - gBattleStruct->enduredDamage |= 1u << battlerDef; + gSpecialStatuses[battlerDef].enduredDamage = TRUE; if (gProtectStructs[battlerDef].endured) { @@ -3209,7 +3209,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) if (i != gBattlersCount) break; - if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), BLOCKED_BY_SLEEP_CLAUSE) && !(gBattleStruct->sleepClauseEffectExempt & (1u << gEffectBattler))) + if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), BLOCKED_BY_SLEEP_CLAUSE) && !gBattleStruct->battlerState[gEffectBattler].sleepClauseEffectExempt) break; cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler); @@ -5895,7 +5895,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent) if (battler != gBattlerAttacker && !(excludeCurrent && battler == gBattlerTarget) && IsBattlerAlive(battler) - && !(gBattleStruct->targetsDone[gBattlerAttacker] & (1u << battler)) + && !gBattleStruct->battlerState[gBattlerAttacker].targetsDone[battler] && (GetBattlerSide(battler) != GetBattlerSide(gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) break; } @@ -6396,9 +6396,9 @@ static void Cmd_moveend(void) if ((gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE)) || (gBattleMons[gBattlerAttacker].status2 & (STATUS2_FLINCHED)) || gProtectStructs[gBattlerAttacker].prlzImmobility) - gBattleStruct->lastMoveFailed |= 1u << gBattlerAttacker; + gBattleStruct->battlerState[gBattlerAttacker].lastMoveFailed = TRUE; else - gBattleStruct->lastMoveFailed &= ~(1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].lastMoveFailed = FALSE; // Set ShellTrap to activate after the attacker's turn if target was hit by a physical move. if (GetMoveEffect(gChosenMoveByBattler[gBattlerTarget]) == EFFECT_SHELL_TRAP @@ -6436,7 +6436,7 @@ static void Cmd_moveend(void) } u32 originalEffect = GetMoveEffect(originallyUsedMove); if (!(gAbsentBattlerFlags & (1u << gBattlerAttacker)) - && !(gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker)) + && !gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags && originalEffect != EFFECT_BATON_PASS && originalEffect != EFFECT_HEALING_WISH) { if (gHitMarker & HITMARKER_OBEYS) @@ -6480,7 +6480,7 @@ static void Cmd_moveend(void) break; case MOVEEND_MIRROR_MOVE: // mirror move if (!(gAbsentBattlerFlags & (1u << gBattlerAttacker)) - && !(gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker)) + && !gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags && !IsMoveMirrorMoveBanned(originallyUsedMove) && gHitMarker & HITMARKER_OBEYS && gBattlerAttacker != gBattlerTarget @@ -6500,7 +6500,7 @@ static void Cmd_moveend(void) && MoveResultHasEffect(gBattlerTarget)) gProtectStructs[gBattlerAttacker].targetAffected = TRUE; - gBattleStruct->targetsDone[gBattlerAttacker] |= 1u << gBattlerTarget; + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[gBattlerTarget] = TRUE; if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && IsDoubleBattle() && !gProtectStructs[gBattlerAttacker].chargingTurn @@ -6531,9 +6531,9 @@ static void Cmd_moveend(void) u8 originalBounceTarget = gBattlerAttacker; gBattleStruct->bouncedMoveIsUsed = FALSE; gBattlerAttacker = gBattleStruct->attackerBeforeBounce; - gBattleStruct->targetsDone[gBattlerAttacker] |= 1u << originalBounceTarget; - gBattleStruct->targetsDone[originalBounceTarget] = 0; - + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[originalBounceTarget] = TRUE; + for (i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[originalBounceTarget].targetsDone[i] = FALSE; nextTarget = GetNextTarget(moveTarget, FALSE); if (nextTarget != MAX_BATTLERS_COUNT) { @@ -6703,7 +6703,7 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection effect = TRUE; BattleScriptPushCursor(); - gBattleStruct->usedEjectItem |= 1u << battler; + gBattleStruct->battlerState[battler].usedEjectItem = TRUE; if (ejectButtonBattlers & (1u << battler)) { gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; @@ -6972,7 +6972,6 @@ static void Cmd_moveend(void) DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); // #endif } - gBattleStruct->targetsDone[gBattlerAttacker] = 0; gProtectStructs[gBattlerAttacker].targetAffected = FALSE; gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gBattleStruct->ateBoost[gBattlerAttacker] = FALSE; @@ -6988,12 +6987,11 @@ static void Cmd_moveend(void) gBattleStruct->categoryOverride = FALSE; gBattleStruct->bouncedMoveIsUsed = FALSE; gBattleStruct->snatchedMoveIsUsed = FALSE; - gBattleStruct->enduredDamage = 0; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; gBattleStruct->fickleBeamBoosted = FALSE; gBattleStruct->redCardActivates = FALSE; - gBattleStruct->usedMicleBerry &= ~(1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].usedMicleBerry = FALSE; if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) gBattleStruct->pledgeMove = FALSE; if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) @@ -7005,6 +7003,8 @@ static void Cmd_moveend(void) for (i = 0; i < gBattlersCount; i++) { + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[i] = FALSE; + if (gBattleStruct->commanderActive[i] != SPECIES_NONE && !IsBattlerAlive(i)) { u32 partner = BATTLE_PARTNER(i); @@ -7017,7 +7017,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_PURSUIT_NEXT_ACTION: - if (gBattleStruct->pursuitTarget & (1u << gBattlerTarget)) + if (gBattleStruct->battlerState[gBattlerTarget].pursuitTarget) { u32 storedTarget = gBattlerTarget; if (SetTargetToNextPursuiter(gBattlerTarget)) @@ -7034,9 +7034,7 @@ static void Cmd_moveend(void) else gBattlescriptCurrInstr = BattleScript_DoSwitchOut; *(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = gBattleStruct->pursuitStoredSwitch; - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; + ClearPursuitValues(); effect = TRUE; } } @@ -7719,20 +7717,20 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) } // Healing Wish activates before hazards. // Starting from Gen8 - it heals only pokemon which can be healed. In gens 5,6,7 the effect activates anyways. - else if (((gBattleStruct->storedHealingWish & (1u << battler)) || (gBattleStruct->storedLunarDance & (1u << battler))) + else if ((gBattleStruct->battlerState[battler].storedHealingWish || gBattleStruct->battlerState[battler].storedLunarDance) && (gBattleMons[battler].hp != gBattleMons[battler].maxHP || gBattleMons[battler].status1 != 0 || B_HEALING_WISH_SWITCH < GEN_8)) { - if (gBattleStruct->storedHealingWish & (1u << battler)) + if (gBattleStruct->battlerState[battler].storedHealingWish) { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HealingWishActivates; - gBattleStruct->storedHealingWish &= ~(1u << battler); + gBattleStruct->battlerState[battler].storedHealingWish = FALSE; } else // Lunar Dance { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_LunarDanceActivates; - gBattleStruct->storedLunarDance &= ~(1u << battler); + gBattleStruct->battlerState[battler].storedLunarDance = FALSE; } } else if (!(gDisableStructs[battler].spikesDone) @@ -7881,7 +7879,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp; } - gBattleStruct->forcedSwitch &= ~(1u << battler); + gBattleStruct->battlerState[battler].forcedSwitch = FALSE; return FALSE; } @@ -7897,7 +7895,7 @@ static void Cmd_switchineffects(void) { // Multiple mons fainted and are being switched-in. Their abilities/hazards will play according to speed ties. case BS_FAINTED_MULTIPLE_1: // Saves the battlers. - gBattleStruct->multipleSwitchInBattlers |= 1 << battler; + gBattleStruct->battlerState[battler].multipleSwitchInBattlers = TRUE; UpdateSentMonFlags(battler); // Increment fainted battler. @@ -7926,14 +7924,16 @@ static void Cmd_switchineffects(void) for (; gBattleStruct->multipleSwitchInCursor < gBattlersCount; gBattleStruct->multipleSwitchInCursor++) { gBattlerFainted = gBattleStruct->multipleSwitchInSortedBattlers[gBattleStruct->multipleSwitchInCursor]; - if (gBattleStruct->multipleSwitchInBattlers & (1 << (gBattlerFainted))) + if (gBattleStruct->battlerState[gBattlerFainted].multipleSwitchInBattlers) { if (DoSwitchInEffectsForBattler(gBattlerFainted)) return; } } // All battlers done, end - gBattleStruct->multipleSwitchInBattlers = 0; + for (i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[i].multipleSwitchInBattlers = FALSE; + gBattleStruct->multipleSwitchInState = 0; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -10048,7 +10048,7 @@ static void Cmd_various(void) case VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT: { VARIOUS_ARGS(); - gBattleStruct->alreadyStatusedMoveAttempt |= 1u << battler; + gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt = TRUE; break; } case VARIOUS_PALACE_TRY_ESCAPE_STATUS: @@ -12486,7 +12486,7 @@ static void Cmd_forcerandomswitch(void) { *(gBattleStruct->battlerPartyIndexes + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget]; gBattlescriptCurrInstr = BattleScript_RoarSuccessSwitch; - gBattleStruct->forcedSwitch |= 1u << gBattlerTarget; + gBattleStruct->battlerState[gBattlerTarget].forcedSwitch = TRUE; *(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = validMons[RandomUniform(RNG_FORCE_RANDOM_SWITCH, 0, validMonsCount - 1)]; if (!IsMultiBattle()) @@ -14021,7 +14021,7 @@ static void Cmd_jumpifnopursuitswitchdmg(void) if (SetTargetToNextPursuiter(gBattlerAttacker)) { ChangeOrderTargetAfterAttacker(); - gBattleStruct->pursuitTarget = 1u << gBattlerAttacker; + gBattleStruct->battlerState[gBattlerAttacker].pursuitTarget = TRUE; gBattleStruct->pursuitSwitchByMove = gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE; gBattleStruct->pursuitStoredSwitch = gBattleStruct->monToSwitchIntoId[gBattlerAttacker]; *(gBattleStruct->moveTarget + gBattlerTarget) = gBattlerAttacker; @@ -17619,11 +17619,11 @@ void BS_JumpIfSleepClause(void) // Can freely sleep own partner if (IsDoubleBattle() && IsSleepClauseEnabled() && GetBattlerSide(gBattlerAttacker) == GetBattlerSide(gBattlerTarget)) { - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerTarget); + gBattleStruct->battlerState[gBattlerTarget].sleepClauseEffectExempt = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; return; } - gBattleStruct->sleepClauseEffectExempt &= ~(1u << gBattlerTarget); + gBattleStruct->battlerState[gBattlerTarget].sleepClauseEffectExempt = FALSE; // Can't sleep if clause is active otherwise if (IsSleepClauseActiveForSide(GetBattlerSide(gBattlerTarget))) gBattlescriptCurrInstr = cmd->jumpInstr; @@ -17795,9 +17795,9 @@ void BS_StoreHealingWish(void) u32 battler = GetBattlerForBattleScript(cmd->battler); if (gCurrentMove == MOVE_LUNAR_DANCE) - gBattleStruct->storedLunarDance |= 1u << battler; + gBattleStruct->battlerState[battler].storedLunarDance = TRUE; else - gBattleStruct->storedHealingWish |= 1u << battler; + gBattleStruct->battlerState[battler].storedHealingWish = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/src/battle_util.c b/src/battle_util.c index fef04096a4..88918320da 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -223,7 +223,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) return FALSE; - if (effect == EFFECT_PURSUIT && gBattleStruct->pursuitTarget) + if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) return FALSE; if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) @@ -239,8 +239,8 @@ void HandleAction_UseMove(void) u16 moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - if (gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker) - || gBattleStruct->commandingDondozo & (1u << gBattlerAttacker) + if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags + || gBattleStruct->battlerState[gBattlerAttacker].commandingDondozo || !IsBattlerAlive(gBattlerAttacker)) { gCurrentActionFuncId = B_ACTION_FINISHED; @@ -334,7 +334,7 @@ void HandleAction_UseMove(void) } else if (IsDoubleBattle() && gSideTimers[side].followmeTimer == 0 - && !(gBattleStruct->pursuitTarget & (1u << *(gBattleStruct->moveTarget + gBattlerAttacker))) + && !gBattleStruct->battlerState[*(gBattleStruct->moveTarget + gBattlerAttacker)].pursuitTarget && (!IsBattleMoveStatus(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) @@ -815,7 +815,7 @@ void HandleAction_ActionFinished(void) gBattleScripting.multihitMoveEffect = 0; gBattleResources->battleScriptsStack->size = 0; - if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !gBattleStruct->pursuitTarget) + if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !IsPursuitTargetSet()) { // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action @@ -3280,7 +3280,7 @@ static void CancellerObedience(u32 *effect) break; case DISOBEYS_FALL_ASLEEP: if (IsSleepClauseEnabled()) - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; break; @@ -5244,7 +5244,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 SaveBattlerAttacker(gBattlerAttacker); gSpecialStatuses[battler].switchInAbilityDone = TRUE; gBattlerAttacker = partner; - gBattleStruct->commandingDondozo |= 1u << battler; + gBattleStruct->battlerState[battler].commandingDondozo = TRUE; gBattleStruct->commanderActive[partner] = gBattleMons[battler].species; gStatuses3[battler] |= STATUS3_COMMANDER; if (gBattleMons[battler].status2 & STATUS2_CONFUSION @@ -5930,7 +5930,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsMoveMakingContact(move, gBattlerAttacker)) { if (IsSleepClauseEnabled()) - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_SLEEP; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptPushCursor(); @@ -6556,7 +6556,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gDisableStructs[battler].weatherAbilityDone && (gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) - && !(gBattleStruct->boosterEnergyActivates & (1u << battler))) + && !gDisableStructs[battler].boosterEnergyActivates) { gDisableStructs[battler].weatherAbilityDone = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); @@ -6585,7 +6585,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gDisableStructs[battler].terrainAbilityDone && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) - && !(gBattleStruct->boosterEnergyActivates & (1u << battler))) + && !gDisableStructs[battler].boosterEnergyActivates) { gDisableStructs[battler].terrainAbilityDone = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); @@ -7046,7 +7046,7 @@ static u32 TrySetMicleBerry(u32 battler, u32 itemId, enum ItemEffect caseID) { if (HasEnoughHpToEatBerry(battler, 4, itemId)) { - gBattleStruct->usedMicleBerry |= 1u << battler; + gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) { BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); @@ -7305,7 +7305,7 @@ static u32 TryConsumeMirrorHerb(u32 battler, enum ItemEffect caseID) static inline u32 TryBoosterEnergy(u32 battler, enum ItemEffect caseID) { - if (gBattleStruct->boosterEnergyActivates & (1u << battler) || gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gDisableStructs[battler].boosterEnergyActivates || gBattleMons[battler].status2 & STATUS2_TRANSFORMED) return ITEM_NO_EFFECT; if (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT)) @@ -7313,7 +7313,7 @@ static inline u32 TryBoosterEnergy(u32 battler, enum ItemEffect caseID) { PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); gBattlerAbility = gBattleScripting.battler = battler; - gBattleStruct->boosterEnergyActivates |= 1u << battler; + gDisableStructs[battler].boosterEnergyActivates = TRUE; if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) { BattleScriptExecute(BattleScript_BoosterEnergyEnd2); @@ -9133,7 +9133,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData basePower *= 2; break; case EFFECT_PURSUIT: - if (gBattleStruct->pursuitTarget & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].pursuitTarget) basePower *= 2; break; case EFFECT_NATURAL_GIFT: @@ -9362,7 +9362,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(0.5)); break; case EFFECT_STOMPING_TANTRUM: - if (gBattleStruct->lastMoveFailed & (1u << battlerAtk)) + if (gBattleStruct->battlerState[battlerAtk].lastMoveFailed) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); break; case EFFECT_MAGNITUDE: @@ -9550,7 +9550,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * case ABILITY_PROTOSYNTHESIS: { u8 defHighestStat = GetHighestStatId(battlerDef); - if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerDef)) + if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gDisableStructs[battlerDef].boosterEnergyActivates) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); @@ -9559,7 +9559,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * case ABILITY_QUARK_DRIVE: { u8 defHighestStat = GetHighestStatId(battlerDef); - if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef)) + if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerDef].boosterEnergyActivates) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); @@ -9829,7 +9829,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); - if (((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk)) + if (((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT) || gDisableStructs[battlerAtk].boosterEnergyActivates) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); @@ -9840,7 +9840,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk)) + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivates) { if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); @@ -12147,9 +12147,9 @@ u32 GetBattleMoveType(u32 move) void TryActivateSleepClause(u32 battler, u32 indexInParty) { - if (gBattleStruct->sleepClauseEffectExempt & (1u << battler)) + if (gBattleStruct->battlerState[battler].sleepClauseEffectExempt) { - gBattleStruct->sleepClauseEffectExempt &= ~(1u << battler); + gBattleStruct->battlerState[battler].sleepClauseEffectExempt = FALSE; return; } @@ -12205,7 +12205,7 @@ bool32 DoesDestinyBondFail(u32 battler) { if (B_DESTINY_BOND_FAIL >= GEN_7 && GetMoveEffect(gLastResultingMoves[battler]) == EFFECT_DESTINY_BOND - && !(gBattleStruct->lastMoveFailed & (1u << battler))) + && !gBattleStruct->battlerState[battler].lastMoveFailed) return TRUE; return FALSE; } @@ -12243,3 +12243,27 @@ u32 NumAffectedSpreadMoveTargets(void) return targetCount; } + +bool32 IsPursuitTargetSet(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleStruct->battlerState[battler].pursuitTarget) + return TRUE; + } + return FALSE; +} + +void ClearPursuitValues(void) +{ + for (u32 i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[i].pursuitTarget = FALSE; + gBattleStruct->pursuitSwitchByMove = FALSE; + gBattleStruct->pursuitStoredSwitch = 0; +} + +void ClearPursuitValuesIfSet(u32 battler) +{ + if (gBattleStruct->battlerState[battler].pursuitTarget) + ClearPursuitValues(); +}