Introduces BattlerState struct for the Battle Engine (#5954)

This commit is contained in:
Alex 2025-01-11 11:12:22 +01:00 committed by GitHub
parent 21bc5cfd30
commit 6e5f40d506
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 166 additions and 133 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}