From 182d42642d14ee30a0004435164772ebd3f51757 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Thu, 1 May 2025 11:22:57 +0200 Subject: [PATCH 1/6] Move out ai struct out of BattleResources --- docs/changelogs/1.6.x/1.6.0.md | 2 +- docs/changelogs/1.9.x/1.9.0.md | 2 +- include/battle.h | 24 +- include/battle_ai_main.h | 8 +- include/config/debug.h | 2 +- src/battle_ai_main.c | 286 +++++++++--------- src/battle_ai_switch_items.c | 228 +++++++-------- src/battle_ai_util.c | 480 +++++++++++++++---------------- src/battle_controller_opponent.c | 4 +- src/battle_debug.c | 24 +- src/battle_main.c | 15 +- src/battle_script_commands.c | 10 +- src/battle_util.c | 6 +- src/battle_util2.c | 16 +- src/recorded_battle.c | 2 +- test/battle/ai/ai.c | 4 +- 16 files changed, 558 insertions(+), 555 deletions(-) diff --git a/docs/changelogs/1.6.x/1.6.0.md b/docs/changelogs/1.6.x/1.6.0.md index f215ffb673..f391940205 100644 --- a/docs/changelogs/1.6.x/1.6.0.md +++ b/docs/changelogs/1.6.x/1.6.0.md @@ -143,7 +143,7 @@ * Prevent certain status moves when item is known + Fake Out changes by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3219 * Improve AI switching with bad moves by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3213 * Fixed `CanTargetFaintAi` index issue by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3306 -* Transform updates `AI_PARTY` data by @ghoulslash in https://github.com/rh-hideout/pokeemerald-expansion/pull/3295 +* Transform updates `gAiPartyData` data by @ghoulslash in https://github.com/rh-hideout/pokeemerald-expansion/pull/3295 * Greatly reduce AI lag by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3308 ### Cleanup diff --git a/docs/changelogs/1.9.x/1.9.0.md b/docs/changelogs/1.9.x/1.9.0.md index b0815c6e2a..44d5a8aec7 100644 --- a/docs/changelogs/1.9.x/1.9.0.md +++ b/docs/changelogs/1.9.x/1.9.0.md @@ -510,7 +510,7 @@ * `AI_STRIKES_FIRST` is also replaced by `AI_IsFaster`. * Switch AI uses trapping abilities aggressively by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4669 * Use 9th roll instead of average in AI calcs by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4679 -* Use `AI_DATA->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 +* Use `gAiLogicData->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 * Minor switch AI cleanup by @Pawkkie, @DizzyEggg, @AlexOn1ine and @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4849 * Removed `SetBattlerData` from `AI_CalcDamage` by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4881 * Removed unused `AI_FLAG_HELP_PARTNER` by @pkmnsnfrn and @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4918 diff --git a/include/battle.h b/include/battle.h index 0d3cc543f0..eb26509b9d 100644 --- a/include/battle.h +++ b/include/battle.h @@ -289,16 +289,17 @@ struct AiPartyMon u16 item; u16 heldEffect; u16 ability; - u16 gender; u16 level; u16 moves[MAX_MON_MOVES]; u32 status; - bool8 isFainted; - bool8 wasSentInBattle; u8 switchInCount; // Counts how many times this Pokemon has been sent out or switched into in a battle. + u8 gender:2; + u8 isFainted:1; + u8 wasSentInBattle:1; + u8 padding:4; }; -struct AIPartyData // Opposing battlers - party mons. +struct AiPartyData // Opposing battlers - party mons. { struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party. u8 count[NUM_BATTLE_SIDES]; @@ -346,7 +347,7 @@ struct AiLogicData u8 battlerDoingPrediction; // Stores which battler is currently running its prediction calcs }; -struct AI_ThinkingStruct +struct AiThinkingStruct { u8 aiState; u8 movesetIndex; @@ -397,20 +398,11 @@ struct BattleResources struct BattleScriptsStack* battleScriptsStack; struct BattleCallbacksStack* battleCallbackStack; struct StatsArray* beforeLvlUp; - struct AI_ThinkingStruct *ai; - struct AiLogicData *aiData; - struct AIPartyData *aiParty; - struct BattleHistory *battleHistory; u8 bufferA[MAX_BATTLERS_COUNT][0x200]; u8 bufferB[MAX_BATTLERS_COUNT][0x200]; u8 transferBuffer[0x100]; }; -#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData)) -#define AI_PARTY ((struct AIPartyData *)(gBattleResources->aiParty)) -#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) - struct BattleResults { u8 playerFaintCounter; // 0x0 @@ -1127,6 +1119,10 @@ extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT]; extern struct BattleScripting gBattleScripting; extern struct BattleStruct *gBattleStruct; extern struct AiBattleData *gAiBattleData; +extern struct AiThinkingStruct *gAiThinkingStruct; +extern struct AiLogicData *gAiLogicData; +extern struct AiPartyData *gAiPartyData; +extern struct BattleHistory *gBattleHistory; extern u8 *gLinkBattleSendBuffer; extern u8 *gLinkBattleRecvBuffer; extern struct BattleResources *gBattleResources; diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index a385d7ce21..31d6437b97 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -60,7 +60,7 @@ enum AIScore { \ TestRunner_Battle_AISetScore(__FILE__, __LINE__, battler, movesetIndex, val); \ } \ - AI_THINKING_STRUCT->score[movesetIndex] = val; \ + gAiThinkingStruct->score[movesetIndex] = val; \ } while (0) \ #define ADJUST_SCORE(val) \ @@ -68,7 +68,7 @@ enum AIScore { \ if (TESTING) \ { \ - TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \ + TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \ } \ score += val; \ } while (0) \ @@ -78,7 +78,7 @@ enum AIScore { \ if (TESTING) \ { \ - TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \ + TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \ } \ score += val; \ return score; \ @@ -89,7 +89,7 @@ enum AIScore { \ if (TESTING) \ { \ - TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \ + TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, gAiThinkingStruct->movesetIndex, val); \ } \ (*score) += val; \ } while (0) \ diff --git a/include/config/debug.h b/include/config/debug.h index 2446b9360c..1542015e50 100644 --- a/include/config/debug.h +++ b/include/config/debug.h @@ -9,7 +9,7 @@ // Battle Debug Menu #define DEBUG_BATTLE_MENU TRUE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. -#define DEBUG_AI_DELAY_TIMER FALSE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. +#define DEBUG_AI_DELAY_TIMER TRUE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. // Pokémon Debug #define DEBUG_POKEMON_SPRITE_VISUALIZER TRUE // Enables a debug menu for Pokémon sprites and icons, accessed by pressing Select in the summary screen. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 8acfe60858..93f5ddc933 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -34,8 +34,8 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi); static u32 ChooseMoveOrAction_Doubles(u32 battlerAi); -static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef); -static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAi, u32 battlerDef); +static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef); +static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAi, u32 battlerDef); static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect); // ewram @@ -99,7 +99,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = void BattleAI_SetupItems(void) { s32 i; - u8 *data = (u8 *)BATTLE_HISTORY; + u8 *data = (u8 *)gBattleHistory; const u16 *items = GetTrainerItemsFromId(TRAINER_BATTLE_PARAM.opponentA); for (i = 0; i < sizeof(struct BattleHistory); i++) @@ -117,8 +117,8 @@ void BattleAI_SetupItems(void) { if (items[i] != ITEM_NONE) { - BATTLE_HISTORY->trainerItems[BATTLE_HISTORY->itemsNo] = items[i]; - BATTLE_HISTORY->itemsNo++; + gBattleHistory->trainerItems[gBattleHistory->itemsNo] = items[i]; + gBattleHistory->itemsNo++; } } } @@ -196,43 +196,43 @@ static u32 GetAiFlags(u16 trainerId) void BattleAI_SetupFlags(void) { if (IsAiVsAiBattle()) - AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); else - AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI if (DEBUG_OVERWORLD_MENU && gIsDebugBattle) { - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; return; } if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) { // smart wild AI - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); } else { - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); if (TRAINER_BATTLE_PARAM.opponentB != 0) - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); else - AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT]; + gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; } if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { - AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); } else if (IsDoubleBattle() && IsAiVsAiBattle()) { - AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_LEFT]; + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT]; } else { - AI_THINKING_STRUCT->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player + gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player } } @@ -242,11 +242,11 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) u32 flags[MAX_BATTLERS_COUNT]; // Clear AI data but preserve the flags. - memcpy(&flags[0], &AI_THINKING_STRUCT->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT); - memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct)); - memcpy(&AI_THINKING_STRUCT->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + memcpy(&flags[0], &gAiThinkingStruct->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + memset(gAiThinkingStruct, 0, sizeof(struct AiThinkingStruct)); + memcpy(&gAiThinkingStruct->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); - moveLimitations = AI_DATA->moveLimitations[battler]; + moveLimitations = gAiLogicData->moveLimitations[battler]; // Conditional score reset, unlike Ruby. for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) @@ -267,13 +267,13 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) bool32 BattlerChoseNonMoveAction(void) { - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + if (gAiThinkingStruct->aiAction & AI_ACTION_FLEE) { gAiBattleData->actionFlee = TRUE; return TRUE; } - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + if (gAiThinkingStruct->aiAction & AI_ACTION_WATCH) { gAiBattleData->choiceWatch = TRUE; return TRUE; @@ -287,24 +287,24 @@ void SetupAISwitchingData(u32 battler, enum SwitchType switchType) s32 opposingBattler = GetOppositeBattler(battler); // AI's predicting data - if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH)) + if ((gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH)) { - AI_DATA->aiSwitchPredictionInProgress = TRUE; - AI_DATA->battlerDoingPrediction = battler; - AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType); + gAiLogicData->aiSwitchPredictionInProgress = TRUE; + gAiLogicData->battlerDoingPrediction = battler; + gAiLogicData->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType); if (ShouldSwitch(opposingBattler)) - AI_DATA->shouldSwitch |= (1u << opposingBattler); - AI_DATA->aiSwitchPredictionInProgress = FALSE; + gAiLogicData->shouldSwitch |= (1u << opposingBattler); + gAiLogicData->aiSwitchPredictionInProgress = FALSE; gBattleStruct->prevTurnSpecies[opposingBattler] = gBattleMons[opposingBattler].species; // Determine whether AI will use predictions this turn - AI_DATA->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, PREDICT_SWITCH_CHANCE); + gAiLogicData->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, PREDICT_SWITCH_CHANCE); } // AI's data - AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType); + gAiLogicData->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType); if (ShouldSwitch(battler)) - AI_DATA->shouldSwitch |= (1u << battler); + gAiLogicData->shouldSwitch |= (1u << battler); gBattleStruct->prevTurnSpecies[battler] = gBattleMons[battler].species; } @@ -319,13 +319,13 @@ void ComputeBattlerDecisions(u32 battler) return; // Risky AI switches aggressively even mid battle - enum SwitchType switchType = (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; + enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; - AI_DATA->aiCalcInProgress = TRUE; + gAiLogicData->aiCalcInProgress = TRUE; BattleAI_SetupAIData(0xF, battler); SetupAISwitchingData(battler, switchType); gAiBattleData->chosenMoveIndex[battler] = BattleAI_ChooseMoveIndex(battler); // Calculate score and chose move index - AI_DATA->aiCalcInProgress = FALSE; + gAiLogicData->aiCalcInProgress = FALSE; } } @@ -351,7 +351,7 @@ u32 BattleAI_ChooseMoveIndex(u32 battler) static void CopyBattlerDataToAIParty(u32 bPosition, u32 side) { u32 battler = GetBattlerAtPosition(bPosition); - struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]]; + struct AiPartyMon *aiMon = &gAiPartyData->mons[side][gBattlerPartyIndexes[battler]]; struct BattlePokemon *bMon = &gBattleMons[battler]; aiMon->species = bMon->species; @@ -366,11 +366,11 @@ static void CopyBattlerDataToAIParty(u32 bPosition, u32 side) void Ai_InitPartyStruct(void) { u32 i; - bool32 isOmniscient = (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); + bool32 isOmniscient = (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); struct Pokemon *mon; - AI_PARTY->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount(); - AI_PARTY->count[B_SIDE_OPPONENT] = CalculateEnemyPartyCount(); + gAiPartyData->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount(); + gAiPartyData->count[B_SIDE_OPPONENT] = CalculateEnemyPartyCount(); // Save first 2 or 4(in doubles) mons CopyBattlerDataToAIParty(B_POSITION_PLAYER_LEFT, B_SIDE_PLAYER); @@ -385,20 +385,20 @@ void Ai_InitPartyStruct(void) } // Find fainted mons - for (i = 0; i < AI_PARTY->count[B_SIDE_PLAYER]; i++) + for (i = 0; i < gAiPartyData->count[B_SIDE_PLAYER]; i++) { if (GetMonData(&gPlayerParty[i], MON_DATA_HP) == 0) - AI_PARTY->mons[B_SIDE_PLAYER][i].isFainted = TRUE; + gAiPartyData->mons[B_SIDE_PLAYER][i].isFainted = TRUE; if (isOmniscient) { u32 j; mon = &gPlayerParty[i]; - AI_PARTY->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM); - AI_PARTY->mons[B_SIDE_PLAYER][i].heldEffect = ItemId_GetHoldEffect(AI_PARTY->mons[B_SIDE_PLAYER][i].item); - AI_PARTY->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon); + gAiPartyData->mons[B_SIDE_PLAYER][i].item = GetMonData(mon, MON_DATA_HELD_ITEM); + gAiPartyData->mons[B_SIDE_PLAYER][i].heldEffect = ItemId_GetHoldEffect(gAiPartyData->mons[B_SIDE_PLAYER][i].item); + gAiPartyData->mons[B_SIDE_PLAYER][i].ability = GetMonAbility(mon); for (j = 0; j < MAX_MON_MOVES; j++) - AI_PARTY->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j); + gAiPartyData->mons[B_SIDE_PLAYER][i].moves[j] = GetMonData(mon, MON_DATA_MOVE1 + j); } } } @@ -407,19 +407,19 @@ void Ai_UpdateSwitchInData(u32 battler) { u32 i; u32 side = GetBattlerSide(battler); - struct AiPartyMon *aiMon = &AI_PARTY->mons[side][gBattlerPartyIndexes[battler]]; + struct AiPartyMon *aiMon = &gAiPartyData->mons[side][gBattlerPartyIndexes[battler]]; // See if the switched-in mon has been already in battle if (aiMon->wasSentInBattle) { if (aiMon->ability) - BATTLE_HISTORY->abilities[battler] = aiMon->ability; + gBattleHistory->abilities[battler] = aiMon->ability; if (aiMon->heldEffect) - BATTLE_HISTORY->itemEffects[battler] = aiMon->heldEffect; + gBattleHistory->itemEffects[battler] = aiMon->heldEffect; for (i = 0; i < MAX_MON_MOVES; i++) { if (aiMon->moves[i]) - BATTLE_HISTORY->usedMoves[battler][i] = aiMon->moves[i]; + gBattleHistory->usedMoves[battler][i] = aiMon->moves[i]; } aiMon->switchInCount++; aiMon->status = gBattleMons[battler].status1; // Copy status, because it could've been changed in battle. @@ -435,7 +435,7 @@ void Ai_UpdateSwitchInData(u32 battler) void Ai_UpdateFaintData(u32 battler) { - struct AiPartyMon *aiMon = &AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]]; + struct AiPartyMon *aiMon = &gAiPartyData->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]]; ClearBattlerMoveHistory(battler); ClearBattlerAbilityHistory(battler); ClearBattlerItemEffectHistory(battler); @@ -530,7 +530,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData) // get/assume all battler data and simulate AI damage battlersCount = gBattlersCount; - AI_DATA->aiCalcInProgress = TRUE; + gAiLogicData->aiCalcInProgress = TRUE; if (DEBUG_AI_DELAY_TIMER) CycleCountStart(); for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++) @@ -551,7 +551,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData) if (DEBUG_AI_DELAY_TIMER) // We add to existing to compound multiple calls gBattleStruct->aiDelayCycles += CycleCountEnd(); - AI_DATA->aiCalcInProgress = FALSE; + gAiLogicData->aiCalcInProgress = FALSE; } static u32 ChooseMoveOrAction_Singles(u32 battlerAi) @@ -560,29 +560,29 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi) u8 consideredMoveArray[MAX_MON_MOVES]; u32 numOfBestMoves; s32 i; - u32 flags = AI_THINKING_STRUCT->aiFlags[battlerAi]; + u32 flags = gAiThinkingStruct->aiFlags[battlerAi]; - AI_DATA->partnerMove = 0; // no ally + gAiLogicData->partnerMove = 0; // no ally while (flags != 0) { if (flags & 1) { - if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) - BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battlerAi, gBattlerTarget); + if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) + BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battlerAi, gBattlerTarget); else - BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); + BattleAI_DoAIProcessing(gAiThinkingStruct, battlerAi, gBattlerTarget); } flags >>= 1; - AI_THINKING_STRUCT->aiLogicId++; + gAiThinkingStruct->aiLogicId++; } for (i = 0; i < MAX_MON_MOVES; i++) { - gAiBattleData->finalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i]; + gAiBattleData->finalScore[battlerAi][gBattlerTarget][i] = gAiThinkingStruct->score[i]; } numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; + currentMoveArray[0] = gAiThinkingStruct->score[0]; consideredMoveArray[0] = 0; for (i = 1; i < MAX_MON_MOVES; i++) @@ -590,15 +590,15 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi) if (gBattleMons[battlerAi].moves[i] != MOVE_NONE) { // In ruby, the order of these if statements is reversed. - if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) + if (currentMoveArray[0] == gAiThinkingStruct->score[i]) { - currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; + currentMoveArray[numOfBestMoves] = gAiThinkingStruct->score[i]; consideredMoveArray[numOfBestMoves++] = i; } - if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) + if (currentMoveArray[0] < gAiThinkingStruct->score[i]) { numOfBestMoves = 1; - currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; + currentMoveArray[0] = gAiThinkingStruct->score[i]; consideredMoveArray[0] = i; } } @@ -635,25 +635,25 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) gBattlerTarget = i; - AI_DATA->partnerMove = GetAllyChosenMove(battlerAi); - AI_THINKING_STRUCT->aiLogicId = 0; - AI_THINKING_STRUCT->movesetIndex = 0; - flags = AI_THINKING_STRUCT->aiFlags[battlerAi]; + gAiLogicData->partnerMove = GetAllyChosenMove(battlerAi); + gAiThinkingStruct->aiLogicId = 0; + gAiThinkingStruct->movesetIndex = 0; + flags = gAiThinkingStruct->aiFlags[battlerAi]; while (flags != 0) { if (flags & 1) { - if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) - BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battlerAi, gBattlerTarget); + if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) + BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battlerAi, gBattlerTarget); else - BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); + BattleAI_DoAIProcessing(gAiThinkingStruct, battlerAi, gBattlerTarget); } flags >>= 1; - AI_THINKING_STRUCT->aiLogicId++; + gAiThinkingStruct->aiLogicId++; } - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; + mostViableMovesScores[0] = gAiThinkingStruct->score[0]; mostViableMovesIndices[0] = 0; mostViableMovesNo = 1; for (j = 1; j < MAX_MON_MOVES; j++) @@ -663,15 +663,15 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) if (!CanTargetBattler(battlerAi, i, gBattleMons[battlerAi].moves[j])) continue; - if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) + if (mostViableMovesScores[0] == gAiThinkingStruct->score[j]) { - mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; + mostViableMovesScores[mostViableMovesNo] = gAiThinkingStruct->score[j]; mostViableMovesIndices[mostViableMovesNo] = j; mostViableMovesNo++; } - if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) + if (mostViableMovesScores[0] < gAiThinkingStruct->score[j]) { - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; + mostViableMovesScores[0] = gAiThinkingStruct->score[j]; mostViableMovesIndices[0] = j; mostViableMovesNo = 1; } @@ -688,7 +688,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) for (j = 0; j < MAX_MON_MOVES; j++) { - gAiBattleData->finalScore[battlerAi][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j]; + gAiBattleData->finalScore[battlerAi][gBattlerTarget][j] = gAiThinkingStruct->score[j]; } } } @@ -728,7 +728,7 @@ static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef, return TRUE; } -static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef) +static inline void BattleAI_DoAIProcessing(struct AiThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef) { do { @@ -763,7 +763,7 @@ static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u3 aiThink->movesetIndex = 0; } -void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef) +void BattleAI_DoAIProcessing_PredictedSwitchin(struct AiThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef) { struct BattlePokemon switchoutCandidate = gBattleMons[battlerDef]; struct SimulatedDamage simulatedDamageSwitchout[MAX_MON_MOVES]; @@ -881,8 +881,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) enum BattleMoveEffects moveEffect = GetMoveEffect(move); s32 moveType; u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); - struct AiLogicData *aiData = AI_DATA; - uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + struct AiLogicData *aiData = gAiLogicData; + uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk); u32 i; u32 weather; @@ -1151,7 +1151,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-20); break; case EFFECT_EXPLOSION: - if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)) + if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)) ADJUST_SCORE(-2); if (effectiveness == UQ_4_12(0.0)) @@ -1501,7 +1501,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-1); if ((predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS || DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove)) - && !(predictedMove == MOVE_NONE && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats + && !(predictedMove == MOVE_NONE && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats ADJUST_SCORE(-10); break; @@ -2006,8 +2006,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-8); //No point in healing, but should at least do it if nothing better break; case EFFECT_RECOIL_IF_MISS: - if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] < 75 - && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] < 75 + && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) ADJUST_SCORE(-6); break; case EFFECT_TRANSFORM: @@ -2122,7 +2122,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } } - /*if (AI_THINKING_STRUCT->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI + /*if (gAiThinkingStruct->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI && IsDoubleBattle()) //Make the regular AI know how to use Protect minimally in Doubles { u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move); @@ -2436,7 +2436,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { ADJUST_SCORE(-10); } - else if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + else if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) { if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up { @@ -2759,7 +2759,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // Don't use a status move if the mon is the last one in the party, has no good switchin, or is trapped else if (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_STATUS && (CountUsablePartyMons(battlerAtk) < 1 - || AI_DATA->mostSuitableMonId[battlerAtk] == PARTY_SIZE + || gAiLogicData->mostSuitableMonId[battlerAtk] == PARTY_SIZE || (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk)))) ADJUST_SCORE(-30); } @@ -2772,7 +2772,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { - u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex; + u32 movesetIndex = gAiThinkingStruct->movesetIndex; if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; @@ -2791,7 +2791,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } else if (CanTargetFaintAi(battlerDef, battlerAtk) && GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER - && GetBattleMovePriority(battlerAtk, AI_DATA->abilities[battlerAtk], move) > 0) + && GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) > 0) { ADJUST_SCORE(LAST_CHANCE); } @@ -2808,7 +2808,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); // ally data u32 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; u32 atkPartnerAbility = aiData->abilities[BATTLE_PARTNER(battlerAtk)]; u32 atkPartnerHoldEffect = aiData->holdEffects[BATTLE_PARTNER(battlerAtk)]; enum BattleMoveEffects partnerEffect = GetMoveEffect(aiData->partnerMove); @@ -2949,13 +2949,13 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (MoveAlwaysCrits(move) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) && AI_IsFaster(battlerAtk, battlerAtkPartner, move) - && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING)) { RETURN_SCORE_PLUS(GOOD_EFFECT); } break; case ABILITY_VOLT_ABSORB: - if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) { RETURN_SCORE_MINUS(10); } @@ -2978,7 +2978,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case ABILITY_WATER_ABSORB: case ABILITY_DRY_SKIN: case ABILITY_EARTH_EATER: - if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) { RETURN_SCORE_MINUS(10); } @@ -2993,7 +2993,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case ABILITY_WATER_COMPACTION: - if (moveType == TYPE_WATER && GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) >= 4) + if (moveType == TYPE_WATER && GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) >= 4) { RETURN_SCORE_PLUS(WEAK_EFFECT); // only mon with this ability is weak to water so only make it okay if we do very little damage } @@ -3020,7 +3020,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) && !IsBattleMoveStatus(move) && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING)) { RETURN_SCORE_PLUS(WEAK_EFFECT); } @@ -3029,7 +3029,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (!IsBattleMoveStatus(move) && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) - && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING)) { RETURN_SCORE_PLUS(WEAK_EFFECT); } @@ -3086,7 +3086,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) && !IsBattleMoveStatus(move) && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) - && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING)) + && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, gAiThinkingStruct->movesetIndex, AI_ATTACKING)) { RETURN_SCORE_PLUS(WEAK_EFFECT); } @@ -3225,8 +3225,8 @@ static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect) static s32 CompareMoveAccuracies(u32 battlerAtk, u32 battlerDef, u32 moveSlot1, u32 moveSlot2) { - u32 acc1 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot1]; - u32 acc2 = AI_DATA->moveAccuracy[battlerAtk][battlerDef][moveSlot2]; + u32 acc1 = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][moveSlot1]; + u32 acc2 = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][moveSlot2]; if (acc1 > acc2) return 1; @@ -3349,7 +3349,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId) static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; enum ItemHoldEffect holdEffect = aiData->holdEffects[battlerAtk]; s32 score = 0; @@ -3358,7 +3358,7 @@ static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) { case HOLD_EFFECT_BLUNDER_POLICY: { - u32 moveAcc = aiData->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + u32 moveAcc = aiData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; if (moveAcc <= LOW_ACCURACY_THRESHOLD) { @@ -3381,8 +3381,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) { // move data enum BattleMoveEffects moveEffect = GetMoveEffect(move); - struct AiLogicData *aiData = AI_DATA; - u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex; + struct AiLogicData *aiData = gAiLogicData; + u32 movesetIndex = gAiThinkingStruct->movesetIndex; uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex]; s32 score = 0; @@ -3397,7 +3397,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) moveEffect = EFFECT_PROTECT; // check status move preference - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) ADJUST_SCORE(10); // check thawing moves @@ -3405,7 +3405,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(10); // check burn / frostbite - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_DATA->abilities[battlerAtk] == ABILITY_NATURAL_CURE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE) { if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE)) || (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE))) @@ -3431,14 +3431,14 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_EXPLOSION: case EFFECT_MEMENTO: - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) { if (aiData->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128)) ADJUST_SCORE(DECENT_EFFECT); } break; case EFFECT_FINAL_GAMBIT: - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_MIRROR_MOVE: @@ -3767,7 +3767,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_BATON_PASS: - if ((AI_DATA->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) || AnyStatIsRaised(battlerAtk))) ADJUST_SCORE(BEST_EFFECT); @@ -4451,7 +4451,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(GOOD_EFFECT); // Partner might use pledge move break; case EFFECT_TRICK_ROOM: - if (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) { if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) ADJUST_SCORE(GOOD_EFFECT); @@ -4620,9 +4620,9 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (GetFirstFaintedPartyIndex(battlerAtk) != PARTY_SIZE) { ADJUST_SCORE(DECENT_EFFECT); - if (AI_DATA->shouldSwitch & (1u << battlerAtk)) // Bad matchup + if (gAiLogicData->shouldSwitch & (1u << battlerAtk)) // Bad matchup ADJUST_SCORE(WEAK_EFFECT); - if (AI_DATA->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after + if (gAiLogicData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after ADJUST_SCORE(WEAK_EFFECT); } break; @@ -4909,15 +4909,15 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score if (GetMovePower(move) != 0) { - if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 0) + if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 0) ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); // No point in checking the move further so return early else { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE) && GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING) == move) ADJUST_SCORE(BEST_DAMAGE_MOVE); else - ADJUST_SCORE(AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)); + ADJUST_SCORE(AI_CompareDamagingMoves(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex)); } } @@ -4935,10 +4935,10 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 || gBattleResults.battleTurnCounter != 0) return score; - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_IsSlower(battlerAtk, battlerDef, move) && CanTargetFaintAi(battlerDef, battlerAtk) - && GetBattleMovePriority(battlerAtk, AI_DATA->abilities[battlerAtk], move) == 0) + && GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) == 0) { RETURN_SCORE_MINUS(20); // No point in setting up if you will faint. Should just switch if possible.. } @@ -5062,7 +5062,7 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { u8 i; - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; @@ -5138,9 +5138,9 @@ static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; - if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 1) + if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 1) ADJUST_SCORE(BEST_EFFECT); - else if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING) == 2) + else if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING) == 2) ADJUST_SCORE(DECENT_EFFECT); return score; @@ -5162,7 +5162,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor { if (gBattleResults.battleTurnCounter == 0) ADJUST_SCORE(GOOD_EFFECT); - else if (AI_DATA->hpPercents[battlerAtk] < 60) + else if (gAiLogicData->hpPercents[battlerAtk] < 60) ADJUST_SCORE(-10); else ADJUST_SCORE(WEAK_EFFECT); @@ -5210,9 +5210,9 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) { if ((effect == EFFECT_HEAL_PULSE || effect == EFFECT_HIT_ENEMY_HEAL_ALLY) - || (moveType == TYPE_ELECTRIC && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB) - || (moveType == TYPE_GROUND && AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_EARTH_EATER) - || (moveType == TYPE_WATER && (AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB))) + || (moveType == TYPE_ELECTRIC && gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_VOLT_ABSORB) + || (moveType == TYPE_GROUND && gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_EARTH_EATER) + || (moveType == TYPE_WATER && (gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_DRY_SKIN || gAiLogicData->abilities[BATTLE_PARTNER(battlerAtk)] == ABILITY_WATER_ABSORB))) { if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK) return 0; @@ -5221,14 +5221,14 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) || (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), BATTLE_PARTNER(battlerAtk)))) ADJUST_SCORE(-1); - if (AI_DATA->hpPercents[battlerDef] <= 50) + if (gAiLogicData->hpPercents[battlerDef] <= 50) ADJUST_SCORE(WEAK_EFFECT); } } else { // Consider AI HP - if (AI_DATA->hpPercents[battlerAtk] > 70) + if (gAiLogicData->hpPercents[battlerAtk] > 70) { // high hp switch (effect) @@ -5253,7 +5253,7 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; } } - else if (AI_DATA->hpPercents[battlerAtk] > 30) + else if (gAiLogicData->hpPercents[battlerAtk] > 30) { // med hp if (IsStatRaisingEffect(effect) || IsStatLoweringEffect(effect)) @@ -5316,18 +5316,18 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } // consider target HP - if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING)) + if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING)) { ADJUST_SCORE(DECENT_EFFECT); } else { - if (AI_DATA->hpPercents[battlerDef] > 70) + if (gAiLogicData->hpPercents[battlerDef] > 70) { // high HP ; // nothing yet } - else if (AI_DATA->hpPercents[battlerDef] > 30) + else if (gAiLogicData->hpPercents[battlerDef] > 30) { // med HP - check discouraged effects switch (effect) @@ -5395,7 +5395,7 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score { enum BattleMoveEffects moveEffect = GetMoveEffect(move); - if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS || GetMoveEffect(AI_DATA->partnerMove) == moveEffect) + if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS || GetMoveEffect(gAiLogicData->partnerMove) == moveEffect) return score; switch (moveEffect) @@ -5438,7 +5438,7 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case EFFECT_STEALTH_ROCK: case EFFECT_STICKY_WEB: case EFFECT_TOXIC_SPIKES: - if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, AI_DATA)) + if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, gAiLogicData)) ADJUST_SCORE(POWERFUL_STATUS_MOVE); break; case EFFECT_GRASSY_TERRAIN: @@ -5492,15 +5492,15 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) u32 opposingHazardFlags = gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_TOXIC_SPIKES); u32 aiHazardFlags = gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_HAZARDS_ANY); enum BattleMoveEffects moveEffect = GetMoveEffect(move); - struct AiLogicData *aiData = AI_DATA; - uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + struct AiLogicData *aiData = gAiLogicData; + uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; // Switch benefit switch (moveEffect) { case EFFECT_PURSUIT: { - u32 hitsToKO = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, AI_ATTACKING); + u32 hitsToKO = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, AI_ATTACKING); if (hitsToKO == 2) ADJUST_SCORE(GOOD_EFFECT); else if (hitsToKO == 1) @@ -5512,7 +5512,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_FOCUS_PUNCH: ADJUST_SCORE(DECENT_EFFECT); - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE) { if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < UQ_4_12(2.0)) ADJUST_SCORE(10); @@ -5573,7 +5573,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_RESTORE_HP: - if (AI_DATA->hpPercents[battlerAtk] < 60) + if (gAiLogicData->hpPercents[battlerAtk] < 60) ADJUST_SCORE(GOOD_EFFECT); break; @@ -5639,12 +5639,12 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) static void AI_Flee(void) { - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); + gAiThinkingStruct->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); } static void AI_Watch(void) { - AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); + gAiThinkingStruct->aiAction |= (AI_ACTION_DONE | AI_ACTION_WATCH | AI_ACTION_DO_NOT_ATTACK); } // Roaming pokemon logic @@ -5654,9 +5654,9 @@ static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (AI_CanBattlerEscape(battlerAtk)) roamerCanFlee = TRUE; - else if (AI_DATA->abilities[battlerAtk] == ABILITY_RUN_AWAY) + else if (gAiLogicData->abilities[battlerAtk] == ABILITY_RUN_AWAY) roamerCanFlee = TRUE; - else if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CAN_ALWAYS_RUN) + else if (gAiLogicData->holdEffects[battlerAtk] == HOLD_EFFECT_CAN_ALWAYS_RUN) roamerCanFlee = TRUE; if (!roamerCanFlee && IsBattlerTrapped(battlerDef, battlerAtk)) @@ -5682,7 +5682,7 @@ static s32 AI_Safari(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // First battle logic static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { - if (AI_DATA->hpPercents[battlerDef] <= 20) + if (gAiLogicData->hpPercents[battlerDef] <= 20) AI_Flee(); return score; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index c1ff6d9c4a..4937719b44 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -34,8 +34,8 @@ static u32 GetHPHealAmount(u8 itemEffectParam, struct Pokemon *mon); static void InitializeSwitchinCandidate(struct Pokemon *mon) { - PokemonToBattleMon(mon, &AI_DATA->switchinCandidate.battleMon); - AI_DATA->switchinCandidate.hypotheticalStatus = FALSE; + PokemonToBattleMon(mon, &gAiLogicData->switchinCandidate.battleMon); + gAiLogicData->switchinCandidate.hypotheticalStatus = FALSE; } u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario) @@ -108,18 +108,18 @@ u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario) u32 GetThinkingBattler(u32 battler) { - if (AI_DATA->aiSwitchPredictionInProgress) - return AI_DATA->battlerDoingPrediction; + if (gAiLogicData->aiSwitchPredictionInProgress) + return gAiLogicData->battlerDoingPrediction; return battler; } static bool32 IsAceMon(u32 battler, u32 monPartyId) { - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON && !gBattleStruct->battlerState[battler].forcedSwitch && monPartyId == CalculateEnemyPartyCountInSide(battler)-1) return TRUE; - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON && !gBattleStruct->battlerState[battler].forcedSwitch && (monPartyId == CalculateEnemyPartyCount()-1 || monPartyId == CalculateEnemyPartyCount()-2)) return TRUE; @@ -168,7 +168,7 @@ static inline bool32 SetSwitchinAndSwitch(u32 battler, u32 switchinId) static bool32 AI_DoesChoiceItemBlockMove(u32 battler, u32 move) { // Choice locked into something else - if (AI_DATA->lastUsedMove[battler] != MOVE_NONE && AI_DATA->lastUsedMove[battler] != move && HOLD_EFFECT_CHOICE(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler)) + if (gAiLogicData->lastUsedMove[battler] != MOVE_NONE && gAiLogicData->lastUsedMove[battler] != move && HOLD_EFFECT_CHOICE(GetBattlerHoldEffect(battler, FALSE)) && IsBattlerItemEnabled(battler)) return TRUE; return FALSE; } @@ -181,13 +181,13 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) //Variable initialization u8 opposingPosition, atkType1, atkType2, defType1, defType2; s32 i, damageDealt = 0, maxDamageDealt = 0, damageTaken = 0, maxDamageTaken = 0; - u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = AI_DATA->abilities[battler], opposingBattler; + u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = gAiLogicData->abilities[battler], opposingBattler; bool32 getsOneShot = FALSE, hasStatusMove = FALSE, hasSuperEffectiveMove = FALSE; u16 typeEffectiveness = UQ_4_12(1.0); //baseline typing damage enum BattleMoveEffects aiMoveEffect; // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic @@ -228,7 +228,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) hasSuperEffectiveMove = TRUE; // Get maximum damage mon can deal - damageDealt = AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, AI_DATA); + damageDealt = AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, gAiLogicData); if(damageDealt > maxDamageDealt && !AI_DoesChoiceItemBlockMove(battler, aiMove)) { maxDamageDealt = damageDealt; @@ -255,7 +255,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) playerMove = gBattleMons[opposingBattler].moves[i]; if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove) && GetMoveEffect(playerMove) != EFFECT_FOCUS_PUNCH) { - damageTaken = AI_GetDamage(opposingBattler, battler, i, AI_DEFENDING, AI_DATA); + damageTaken = AI_GetDamage(opposingBattler, battler, i, AI_DEFENDING, gAiLogicData); if (playerMove == gBattleStruct->choicedMove[opposingBattler]) // If player is choiced, only care about the choice locked move { return maxDamageTaken = damageTaken; @@ -281,7 +281,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) } // If we don't have any other viable options, don't switch out - if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) + if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) return FALSE; // Start assessing whether or not mon has bad odds @@ -293,7 +293,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4))) { // 50% chance to stay in regardless - if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiSwitchPredictionInProgress) + if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !gAiLogicData->aiSwitchPredictionInProgress) return FALSE; // Switch mon out @@ -313,7 +313,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) return FALSE; // 50% chance to stay in regardless - if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !AI_DATA->aiSwitchPredictionInProgress) + if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, (100 - GetSwitchChance(SHOULD_SWITCH_HASBADODDS))) && !gAiLogicData->aiSwitchPredictionInProgress) return FALSE; // Switch mon out @@ -326,11 +326,11 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) static bool32 ShouldSwitchIfTruant(u32 battler) { // Switch if mon with truant is bodied by Protect or invulnerability spam - if (AI_DATA->abilities[battler] == ABILITY_TRUANT + if (gAiLogicData->abilities[battler] == ABILITY_TRUANT && IsTruantMonVulnerable(battler, gBattlerTarget) && gDisableStructs[battler].truantCounter && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2 - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE) { if (RandomPercentage(RNG_AI_SWITCH_TRUANT, GetSwitchChance(SHOULD_SWITCH_TRUANT))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -402,7 +402,7 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler) if (RandomPercentage(RNG_AI_SWITCH_ALL_MOVES_BAD, GetSwitchChance(SHOULD_SWITCH_ALL_MOVES_BAD))) { - if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage + if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage return FindMonWithMoveOfEffectiveness(battler, opposingBattler, UQ_4_12(1.0)); else // Good candidate mon, send that in return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -419,7 +419,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler) if (IsDoubleBattle()) return FALSE; - if (AI_DATA->abilities[opposingBattler] != ABILITY_WONDER_GUARD) + if (gAiLogicData->abilities[opposingBattler] != ABILITY_WONDER_GUARD) return FALSE; // Check if Pokémon has a super effective move. @@ -435,7 +435,7 @@ static bool32 ShouldSwitchIfWonderGuard(u32 battler) if (RandomPercentage(RNG_AI_SWITCH_WONDER_GUARD, GetSwitchChance(SHOULD_SWITCH_WONDER_GUARD))) { - if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage + if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) // No good candidate mons, find any one that can deal damage return FindMonWithMoveOfEffectiveness(battler, opposingBattler, UQ_4_12(2.0)); else // Good candidate mon, send that in return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -454,18 +454,18 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) struct Pokemon *party; u16 monAbility, aiMove; u32 opposingBattler = GetOppositeBattler(battler); - u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler]; + u32 incomingMove = gAiLogicData->lastUsedMove[opposingBattler]; u32 incomingType = GetMoveType(incomingMove); u32 predictedMove = incomingMove; // Update for move prediction u32 predictedType = GetMoveType(predictedMove); bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); s32 i, j; - if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE return FALSE; - if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || AI_DATA->aiSwitchPredictionInProgress)) + if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || gAiLogicData->aiSwitchPredictionInProgress)) return FALSE; if (AreStatsRaised(battler)) return FALSE; @@ -479,7 +479,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) // Only check damage if it's a damaging move if (!IsBattleMoveStatus(aiMove)) { - if (AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, AI_DATA) > gBattleMons[opposingBattler].hp) + if (AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, gAiLogicData) > gBattleMons[opposingBattler].hp) return FALSE; } } @@ -581,13 +581,13 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler) { u32 opposingBattler = GetOppositeBattler(battler); - u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler]; + u32 incomingMove = gAiLogicData->lastUsedMove[opposingBattler]; bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); - if (IsDoubleBattle() || !(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; - if (isOpposingBattlerChargingOrInvulnerable && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) + if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); return FALSE; @@ -603,7 +603,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) s32 opposingBattler = GetOppositeBattler(battler); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Check if current mon has an ability that traps opponent @@ -624,7 +624,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && monAbility == ABILITY_TRACE)) { // If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1 - if (i == AI_DATA->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) + if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } } @@ -634,8 +634,8 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) static bool32 ShouldSwitchIfBadlyStatused(u32 battler) { bool32 switchMon = FALSE; - u16 monAbility = AI_DATA->abilities[battler]; - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[battler]; + u16 monAbility = gAiLogicData->abilities[battler]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; u8 opposingPosition = BATTLE_OPPOSITE(GetBattlerPosition(battler)); u8 opposingBattler = GetBattlerAtPosition(opposingPosition); bool32 hasStatRaised = AnyStatIsRaised(battler); @@ -647,7 +647,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) && RandomPercentage(RNG_AI_SWITCH_PERISH_SONG, GetSwitchChance(SHOULD_SWITCH_PERISH_SONG))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) { //Yawn if (gStatuses3[battler] & STATUS3_YAWN @@ -658,7 +658,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) switchMon = TRUE; // If we don't have a good switchin, not worth switching - if (AI_DATA->mostSuitableMonId[battler] == PARTY_SIZE) + if (gAiLogicData->mostSuitableMonId[battler] == PARTY_SIZE) switchMon = FALSE; // Check if Active Pokemon can KO opponent instead of switching @@ -680,10 +680,10 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) // Check if Active Pokemon evasion boosted and might be able to dodge until awake if (gBattleMons[battler].statStages[STAT_EVASION] > (DEFAULT_STAT_STAGE + 3) - && AI_DATA->abilities[opposingBattler] != ABILITY_UNAWARE - && AI_DATA->abilities[opposingBattler] != ABILITY_KEEN_EYE - && AI_DATA->abilities[opposingBattler] != ABILITY_MINDS_EYE - && (B_ILLUMINATE_EFFECT >= GEN_9 && AI_DATA->abilities[opposingBattler] != ABILITY_ILLUMINATE) + && gAiLogicData->abilities[opposingBattler] != ABILITY_UNAWARE + && gAiLogicData->abilities[opposingBattler] != ABILITY_KEEN_EYE + && gAiLogicData->abilities[opposingBattler] != ABILITY_MINDS_EYE + && (B_ILLUMINATE_EFFECT >= GEN_9 && gAiLogicData->abilities[opposingBattler] != ABILITY_ILLUMINATE) && !(gBattleMons[battler].status2 & STATUS2_FORESIGHT) && !(gStatuses3[battler] & STATUS3_MIRACLE_EYED)) switchMon = FALSE; @@ -695,12 +695,12 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) // Secondary Damage if (monAbility != ABILITY_MAGIC_GUARD && !AiExpectsToFaintPlayer(battler) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE) { //Toxic if (((gBattleMons[battler].status1 & STATUS1_TOXIC_COUNTER) >= STATUS1_TOXIC_TURN(2)) && gBattleMons[battler].hp >= (gBattleMons[battler].maxHP / 3) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_BADLY_POISONED, GetSwitchChance(SHOULD_SWITCH_BADLY_POISONED)))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -723,7 +723,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) // Infatuation if (gBattleMons[battler].status2 & STATUS2_INFATUATION && !AiExpectsToFaintPlayer(battler) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_INFATUATION, GetSwitchChance(SHOULD_SWITCH_INFATUATION))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } @@ -740,18 +740,18 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler) || IsNeutralizingGasOnField()) return FALSE; - switch(AI_DATA->abilities[battler]) + switch(gAiLogicData->abilities[battler]) { case ABILITY_NATURAL_CURE: //Attempt to cure bad ailment if (gBattleMons[battler].status1 & (STATUS1_SLEEP | STATUS1_FREEZE | STATUS1_TOXIC_POISON) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_STRONG)))) break; //Attempt to cure lesser ailment if ((gBattleMons[battler].status1 & STATUS1_ANY) && (gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NATURAL_CURE, GetSwitchChance(SHOULD_SWITCH_NATURAL_CURE_WEAK)))) break; @@ -762,7 +762,7 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler) if (gBattleMons[battler].status1 & STATUS1_ANY) return FALSE; if ((gBattleMons[battler].hp <= ((gBattleMons[battler].maxHP * 2) / 3)) - && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE + && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_REGENERATOR, GetSwitchChance(SHOULD_SWITCH_REGENERATOR)))) break; @@ -836,7 +836,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc u16 move; // Similar functionality handled more thoroughly by ShouldSwitchIfHasBadOdds - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (gLastLandedMoves[battler] == MOVE_NONE) @@ -898,7 +898,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc if (move == 0) continue; - if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || AI_DATA->aiSwitchPredictionInProgress)) + if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= UQ_4_12(2.0) && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || gAiLogicData->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, i); } } @@ -911,7 +911,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler) { u32 battlerIn1, battlerIn2; u32 hazardDamage = 0, battlerHp = gBattleMons[battler].hp; - u32 ability = AI_DATA->abilities[battler], aiMove; + u32 ability = gAiLogicData->abilities[battler], aiMove; s32 firstId, lastId, i, j; struct Pokemon *party; @@ -974,7 +974,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) u32 opposingBattler = GetOppositeBattler(battler); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // If not Encore'd don't switch @@ -990,7 +990,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) return FALSE; // Switch out 50% of the time otherwise - else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_DAMAGE)) || AI_DATA->aiSwitchPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) + else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, GetSwitchChance(SHOULD_SWITCH_ENCORE_DAMAGE)) || gAiLogicData->aiSwitchPredictionInProgress) && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE) return SetSwitchinAndSwitch(battler, PARTY_SIZE); return FALSE; @@ -999,13 +999,13 @@ static bool32 ShouldSwitchIfEncored(u32 battler) static bool32 ShouldSwitchIfBadChoiceLock(u32 battler) { enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); - u32 lastUsedMove = AI_DATA->lastUsedMove[battler]; + u32 lastUsedMove = gAiLogicData->lastUsedMove[battler]; u32 opposingBattler = GetOppositeBattler(battler); bool32 moveAffectsTarget = TRUE; if (lastUsedMove != MOVE_NONE && (AI_GetMoveEffectiveness(lastUsedMove, battler, opposingBattler) == UQ_4_12(0.0) - || CanAbilityAbsorbMove(battler, opposingBattler, AI_DATA->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), ABILITY_CHECK_TRIGGER) - || CanAbilityBlockMove(battler, opposingBattler, AI_DATA->abilities[battler], AI_DATA->abilities[opposingBattler], lastUsedMove, ABILITY_CHECK_TRIGGER))) + || CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], lastUsedMove, GetMoveType(lastUsedMove), ABILITY_CHECK_TRIGGER) + || CanAbilityBlockMove(battler, opposingBattler, gAiLogicData->abilities[battler], gAiLogicData->abilities[opposingBattler], lastUsedMove, ABILITY_CHECK_TRIGGER))) moveAffectsTarget = FALSE; if (HOLD_EFFECT_CHOICE(holdEffect) && IsBattlerItemEnabled(battler)) @@ -1024,7 +1024,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK]; // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Physical attacker @@ -1036,7 +1036,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) // 50% chance if attack at -2 and have a good candidate mon else if (attackingStage == DEFAULT_STAT_STAGE - 2) { - if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiSwitchPredictionInProgress)) + if (gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || gAiLogicData->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } // If at -3 or worse, switch out regardless @@ -1053,7 +1053,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) // 50% chance if attack at -2 and have a good candidate mon else if (spAttackingStage == DEFAULT_STAT_STAGE - 2) { - if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiSwitchPredictionInProgress)) + if (gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || gAiLogicData->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } // If at -3 or worse, switch out regardless @@ -1100,7 +1100,7 @@ bool32 ShouldSwitch(u32 battler) return FALSE; // Sequence Switching AI never switches mid-battle - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) return FALSE; availableToSwitch = 0; @@ -1152,7 +1152,7 @@ bool32 ShouldSwitch(u32 battler) if (ShouldSwitchIfWonderGuard(battler)) return TRUE; - if ((AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) + if ((gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) return FALSE; if (HasGoodSubstituteMove(battler)) return FALSE; @@ -1182,7 +1182,7 @@ bool32 ShouldSwitch(u32 battler) // Removing switch capabilites under specific conditions // These Functions prevent the "FindMonWithFlagsAndSuperEffective" from getting out of hand. // We don't use FindMonWithFlagsAndSuperEffective with AI_FLAG_SMART_SWITCHING, so we can bail early. - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE)) return FALSE; @@ -1206,14 +1206,14 @@ bool32 IsSwitchinValid(u32 battler) u32 partner = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerAtPosition(battler))); if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) // Generic switch { - if ((AI_DATA->shouldSwitch & (1u << partner)) && AI_DATA->monToSwitchInId[partner] == AI_DATA->mostSuitableMonId[battler]) + if ((gAiLogicData->shouldSwitch & (1u << partner)) && gAiLogicData->monToSwitchInId[partner] == gAiLogicData->mostSuitableMonId[battler]) { return FALSE; } } else // Override switch { - if ((AI_DATA->shouldSwitch & (1u << partner)) && AI_DATA->monToSwitchInId[partner] == gBattleStruct->AI_monToSwitchIntoId[battler]) + if ((gAiLogicData->shouldSwitch & (1u << partner)) && gAiLogicData->monToSwitchInId[partner] == gBattleStruct->AI_monToSwitchIntoId[battler]) { return FALSE; } @@ -1233,12 +1233,12 @@ void AI_TrySwitchOrUseItem(u32 battler) if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { - if (AI_DATA->shouldSwitch & (1u << battler) && IsSwitchinValid(battler)) + if (gAiLogicData->shouldSwitch & (1u << battler) && IsSwitchinValid(battler)) { BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SWITCH, 0); if (gBattleStruct->AI_monToSwitchIntoId[battler] == PARTY_SIZE) { - s32 monToSwitchId = AI_DATA->mostSuitableMonId[battler]; + s32 monToSwitchId = gAiLogicData->mostSuitableMonId[battler]; if (monToSwitchId == PARTY_SIZE) { if (!IsDoubleBattle()) @@ -1277,7 +1277,7 @@ void AI_TrySwitchOrUseItem(u32 battler) } gBattleStruct->monToSwitchIntoId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler]; - AI_DATA->monToSwitchInId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler]; + gAiLogicData->monToSwitchInId[battler] = gBattleStruct->AI_monToSwitchIntoId[battler]; return; } else if (ShouldUseItem(battler)) @@ -1400,11 +1400,11 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva InitializeSwitchinCandidate(&party[i]); for (j = 0; j < MAX_MON_MOVES; j++) { - aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; + aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j]; if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove)) { aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j); - dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING); + dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING); if (bestDmg < dmg) { bestDmg = dmg; @@ -1494,8 +1494,8 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon // Gets damage / healing from weather static s32 GetSwitchinWeatherImpact(void) { - s32 weatherImpact = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item); + s32 weatherImpact = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); if (HasWeatherEffect()) { @@ -1503,7 +1503,7 @@ static s32 GetSwitchinWeatherImpact(void) if (holdEffect != HOLD_EFFECT_SAFETY_GOGGLES && ability != ABILITY_MAGIC_GUARD && ability != ABILITY_OVERCOAT) { if ((gBattleWeather & B_WEATHER_HAIL) - && (AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_ICE || AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_ICE) + && (gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_ICE || gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_ICE) && ability != ABILITY_SNOW_CLOAK && ability != ABILITY_ICE_BODY) { weatherImpact = maxHP / 16; @@ -1511,9 +1511,9 @@ static s32 GetSwitchinWeatherImpact(void) weatherImpact = 1; } else if ((gBattleWeather & B_WEATHER_SANDSTORM) - && (AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_GROUND && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_GROUND - && AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_ROCK && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_ROCK - && AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_STEEL && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_STEEL + && (gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_GROUND && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_GROUND + && gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_ROCK && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_ROCK + && gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_STEEL && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_STEEL && ability != ABILITY_SAND_VEIL && ability != ABILITY_SAND_RUSH && ability != ABILITY_SAND_FORCE)) { weatherImpact = maxHP / 16; @@ -1558,13 +1558,13 @@ static s32 GetSwitchinWeatherImpact(void) // Gets one turn of recurring healing static u32 GetSwitchinRecurringHealing(void) { - u32 recurringHealing = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item); + u32 recurringHealing = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_KLUTZ) { - if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && (AI_DATA->switchinCandidate.battleMon.types[0] == TYPE_POISON || AI_DATA->switchinCandidate.battleMon.types[1] == TYPE_POISON)) + if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && (gAiLogicData->switchinCandidate.battleMon.types[0] == TYPE_POISON || gAiLogicData->switchinCandidate.battleMon.types[1] == TYPE_POISON)) { recurringHealing = maxHP / 16; if (recurringHealing == 0) @@ -1579,7 +1579,7 @@ static u32 GetSwitchinRecurringHealing(void) } // Intentionally omitting Shell Bell for its inconsistency // Abilities - if (ability == ABILITY_POISON_HEAL && (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_POISON)) + if (ability == ABILITY_POISON_HEAL && (gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_POISON)) { u32 healing = maxHP / 8; if (healing == 0) @@ -1592,13 +1592,13 @@ static u32 GetSwitchinRecurringHealing(void) // Gets one turn of recurring damage static u32 GetSwitchinRecurringDamage(void) { - u32 passiveDamage = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability; - enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item); + u32 passiveDamage = 0, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, ability = gAiLogicData->switchinCandidate.battleMon.ability; + enum ItemHoldEffect holdEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); // Items if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ) { - if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && AI_DATA->switchinCandidate.battleMon.types[0] != TYPE_POISON && AI_DATA->switchinCandidate.battleMon.types[1] != TYPE_POISON) + if (holdEffect == HOLD_EFFECT_BLACK_SLUDGE && gAiLogicData->switchinCandidate.battleMon.types[0] != TYPE_POISON && gAiLogicData->switchinCandidate.battleMon.types[1] != TYPE_POISON) { passiveDamage = maxHP / 8; if (passiveDamage == 0) @@ -1623,14 +1623,14 @@ static u32 GetSwitchinRecurringDamage(void) // Gets one turn of status damage static u32 GetSwitchinStatusDamage(u32 battler) { - u8 defType1 = AI_DATA->switchinCandidate.battleMon.types[0], defType2 = AI_DATA->switchinCandidate.battleMon.types[1]; + u8 defType1 = gAiLogicData->switchinCandidate.battleMon.types[0], defType2 = gAiLogicData->switchinCandidate.battleMon.types[1]; u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount; - u16 heldItemEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item); - u32 status = AI_DATA->switchinCandidate.battleMon.status1, ability = AI_DATA->switchinCandidate.battleMon.ability, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP; + u16 heldItemEffect = ItemId_GetHoldEffect(gAiLogicData->switchinCandidate.battleMon.item); + u32 status = gAiLogicData->switchinCandidate.battleMon.status1, ability = gAiLogicData->switchinCandidate.battleMon.ability, maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP; u32 statusDamage = 0; // Status condition damage - if ((status != 0) && AI_DATA->switchinCandidate.battleMon.ability != ABILITY_MAGIC_GUARD) + if ((status != 0) && gAiLogicData->switchinCandidate.battleMon.ability != ABILITY_MAGIC_GUARD) { if (status & STATUS1_BURN) { @@ -1661,11 +1661,11 @@ static u32 GetSwitchinStatusDamage(u32 battler) else if ((status & STATUS1_TOXIC_POISON) && ability != ABILITY_POISON_HEAL) { if ((status & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_TURN(15)) // not 16 turns - AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); + gAiLogicData->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); statusDamage = maxHP / 16; if (statusDamage == 0) statusDamage = 1; - statusDamage *= AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8; + statusDamage *= gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_COUNTER >> 8; } } @@ -1681,14 +1681,14 @@ static u32 GetSwitchinStatusDamage(u32 battler) { if (tSpikesLayers == 1) { - AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes - AI_DATA->switchinCandidate.hypotheticalStatus = TRUE; + gAiLogicData->switchinCandidate.battleMon.status1 = STATUS1_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes + gAiLogicData->switchinCandidate.hypotheticalStatus = TRUE; } if (tSpikesLayers == 2) { - AI_DATA->switchinCandidate.battleMon.status1 = STATUS1_TOXIC_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes - AI_DATA->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); - AI_DATA->switchinCandidate.hypotheticalStatus = TRUE; + gAiLogicData->switchinCandidate.battleMon.status1 = STATUS1_TOXIC_POISON; // Assign "hypothetical" status to the switchin candidate so we can get the damage it would take from TSpikes + gAiLogicData->switchinCandidate.battleMon.status1 += STATUS1_TOXIC_TURN(1); + gAiLogicData->switchinCandidate.hypotheticalStatus = TRUE; } } return statusDamage; @@ -1697,16 +1697,16 @@ static u32 GetSwitchinStatusDamage(u32 battler) // Gets number of hits to KO factoring in hazards, healing held items, status, and weather static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) { - u32 startingHP = AI_DATA->switchinCandidate.battleMon.hp - GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon); + u32 startingHP = gAiLogicData->switchinCandidate.battleMon.hp - GetSwitchinHazardsDamage(battler, &gAiLogicData->switchinCandidate.battleMon); s32 weatherImpact = GetSwitchinWeatherImpact(); // Signed to handle both damage and healing in the same value u32 recurringDamage = GetSwitchinRecurringDamage(); u32 recurringHealing = GetSwitchinRecurringHealing(); u32 statusDamage = GetSwitchinStatusDamage(battler); u32 hitsToKO = 0, singleUseItemHeal = 0; - u16 maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, item = AI_DATA->switchinCandidate.battleMon.item, heldItemEffect = ItemId_GetHoldEffect(item); + u16 maxHP = gAiLogicData->switchinCandidate.battleMon.maxHP, item = gAiLogicData->switchinCandidate.battleMon.item, heldItemEffect = ItemId_GetHoldEffect(item); u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = ItemId_GetHoldEffectParam(item); u32 opposingBattler = GetOppositeBattler(battler); - u32 opposingAbility = gBattleMons[opposingBattler].ability, ability = AI_DATA->switchinCandidate.battleMon.ability; + u32 opposingAbility = gBattleMons[opposingBattler].ability, ability = gAiLogicData->switchinCandidate.battleMon.ability; bool32 usedSingleUseHealingItem = FALSE, opponentCanBreakMold = IsMoldBreakerTypeAbility(opposingBattler, opposingAbility); s32 currentHP = startingHP; @@ -1737,7 +1737,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) currentHP = currentHP - weatherImpact; // Check if we're at a single use healing item threshold - if (AI_DATA->switchinCandidate.battleMon.ability != ABILITY_KLUTZ && usedSingleUseHealingItem == FALSE + if (gAiLogicData->switchinCandidate.battleMon.ability != ABILITY_KLUTZ && usedSingleUseHealingItem == FALSE && !(opposingAbility == ABILITY_UNNERVE && GetPocketByItemId(item) == POCKET_BERRIES)) { switch (heldItemEffect) @@ -1784,7 +1784,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) currentHP = currentHP + recurringHealing - recurringDamage - statusDamage; // Recalculate toxic damage if needed - if (AI_DATA->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_POISON) + if (gAiLogicData->switchinCandidate.battleMon.status1 & STATUS1_TOXIC_POISON) statusDamage = GetSwitchinStatusDamage(battler); // Reduce weather duration @@ -1795,14 +1795,14 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) } // Disguise will always add an extra hit to KO - if (opponentCanBreakMold && AI_DATA->switchinCandidate.battleMon.species == SPECIES_MIMIKYU_DISGUISED) + if (opponentCanBreakMold && gAiLogicData->switchinCandidate.battleMon.species == SPECIES_MIMIKYU_DISGUISED) hitsToKO++; // If mon had a hypothetical status from TSpikes, clear it - if (AI_DATA->switchinCandidate.hypotheticalStatus == TRUE) + if (gAiLogicData->switchinCandidate.hypotheticalStatus == TRUE) { - AI_DATA->switchinCandidate.battleMon.status1 = 0; - AI_DATA->switchinCandidate.hypotheticalStatus = FALSE; + gAiLogicData->switchinCandidate.battleMon.status1 = 0; + gAiLogicData->switchinCandidate.hypotheticalStatus = FALSE; } return hitsToKO; } @@ -1875,7 +1875,7 @@ static bool32 CanAbilityTrapOpponent(u16 ability, u32 opponent) return FALSE; else if (ability == ABILITY_SHADOW_TAG) { - if (B_SHADOW_TAG_ESCAPE >= GEN_4 && AI_DATA->abilities[opponent] == ABILITY_SHADOW_TAG) // Check if ability exists in species + if (B_SHADOW_TAG_ESCAPE >= GEN_4 && gAiLogicData->abilities[opponent] == ABILITY_SHADOW_TAG) // Check if ability exists in species return FALSE; else return TRUE; @@ -1897,9 +1897,9 @@ static inline bool32 IsFreeSwitch(enum SwitchType switchType, u32 battlerSwitchi { if (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) && movedSecond) return TRUE; - if (AI_DATA->ejectButtonSwitch) + if (gAiLogicData->ejectButtonSwitch) return TRUE; - if (AI_DATA->ejectPackSwitch) + if (gAiLogicData->ejectPackSwitch) { u32 opposingAbility = AI_GetBattlerAbility(opposingBattler); // If faster, not a free switch; likely lowered own stats @@ -1969,12 +1969,12 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, InitializeSwitchinCandidate(&party[i]); // While not really invalid per se, not really wise to switch into this mon - if (AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler)) + if (gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler)) continue; // Get max number of hits for player to KO AI mon and type matchup for defensive switching - hitsToKOAI = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon), battler); - typeMatchup = GetSwitchinTypeMatchup(opposingBattler, AI_DATA->switchinCandidate.battleMon); + hitsToKOAI = GetSwitchinHitsToKO(GetMaxDamagePlayerCouldDealToSwitchin(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon), battler); + typeMatchup = GetSwitchinTypeMatchup(opposingBattler, gAiLogicData->switchinCandidate.battleMon); // Track max hits to KO and set defensive mon if(hitsToKOAI > maxHitsToKO) @@ -1987,13 +1987,13 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, // Check through current mon's moves for (j = 0; j < MAX_MON_MOVES; j++) { - aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; + aiMove = gAiLogicData->switchinCandidate.battleMon.moves[j]; if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove)) - damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, AI_ATTACKING); + damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, AI_ATTACKING); // Offensive switchin decisions are based on which whether switchin moves first and whether it can win a 1v1 - isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, aiMove); + isSwitchinFirst = AI_WhoStrikesFirstPartyMon(battler, opposingBattler, gAiLogicData->switchinCandidate.battleMon, aiMove); canSwitchinWin1v1 = CanSwitchinWin1v1(hitsToKOAI, GetNoOfHitsToKOBattlerDmg(damageDealt, opposingBattler), isSwitchinFirst, isFreeSwitch); // Check for Baton Pass; hitsToKO requirements mean mon can boost and BP without dying whether it's slower or not @@ -2068,8 +2068,8 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, } // If mon can trap - if ((CanAbilityTrapOpponent(AI_DATA->switchinCandidate.battleMon.ability, opposingBattler) - || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRACE)) + if ((CanAbilityTrapOpponent(gAiLogicData->switchinCandidate.battleMon.ability, opposingBattler) + || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRACE)) && CountUsablePartyMons(opposingBattler) > 0 && canSwitchinWin1v1) trapperId = i; @@ -2104,7 +2104,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, } // If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon. if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount - && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || AI_DATA->ejectButtonSwitch || AI_DATA->ejectPackSwitch)) + && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch)) return aceMonId; return PARTY_SIZE; @@ -2166,14 +2166,14 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) GetAIPartyIndexes(battler, &firstId, &lastId); party = GetBattlerParty(battler); - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) { bestMonId = GetNextMonInParty(party, firstId, lastId, battlerIn1, battlerIn2); return bestMonId; } // Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer. - if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic + if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic { bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchType); return bestMonId; @@ -2221,7 +2221,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) // If ace mon is the last available Pokemon and U-Turn/Volt Switch or Eject Pack/Button was used - switch to the mon. if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount - && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || AI_DATA->ejectButtonSwitch || AI_DATA->ejectPackSwitch)) + && (IsSwitchOutEffect(GetMoveEffect(gCurrentMove)) || gAiLogicData->ejectButtonSwitch || gAiLogicData->ejectPackSwitch)) return aceMonId; return PARTY_SIZE; @@ -2284,7 +2284,7 @@ static bool32 ShouldUseItem(u32 battler) const u8 *itemEffects; u8 battlerSide; - item = gBattleResources->battleHistory->trainerItems[i]; + item = gBattleHistory->trainerItems[i]; if (item == ITEM_NONE) continue; itemEffects = ItemId_GetEffect(item); @@ -2354,7 +2354,7 @@ static bool32 ShouldUseItem(u32 battler) gBattleStruct->itemPartyIndex[battler] = gBattlerPartyIndexes[battler]; BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_USE_ITEM, 0); gBattleStruct->chosenItem[battler] = item; - gBattleResources->battleHistory->trainerItems[i] = 0; + gBattleHistory->trainerItems[i] = 0; return shouldUse; } } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 74f0646ed3..e0d040c294 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -55,17 +55,17 @@ u32 AI_GetDamage(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcC if (calcContext == AI_ATTACKING && BattlerHasAi(battlerAtk)) { - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it deals max damage + if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it deals max damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it deals min damage + if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it deals min damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].median; // Default assumes it deals median damage } else if (calcContext == AI_DEFENDING && BattlerHasAi(battlerDef)) { - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it takes min damage + if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it takes min damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it takes max damage + if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it takes max damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].median; // Default assumes it takes median damage } @@ -125,8 +125,8 @@ bool32 BattlerHasAi(u32 battlerId) bool32 IsAiBattlerAware(u32 battlerId) { - if (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT - || AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT) + if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT + || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT) return TRUE; return BattlerHasAi(battlerId); @@ -134,8 +134,8 @@ bool32 IsAiBattlerAware(u32 battlerId) bool32 IsAiBattlerPredictingAbility(u32 battlerId) { - if (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_WEIGH_ABILITY_PREDICTION - || AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_WEIGH_ABILITY_PREDICTION) + if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_WEIGH_ABILITY_PREDICTION + || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_WEIGH_ABILITY_PREDICTION) return TRUE; return BattlerHasAi(battlerId); @@ -144,10 +144,10 @@ bool32 IsAiBattlerPredictingAbility(u32 battlerId) bool32 IsBattlerPredictedToSwitch(u32 battler) { // Check for prediction flag on AI, whether they're using those predictions this turn, and whether the AI thinks the player should switch - if (AI_THINKING_STRUCT->aiFlags[AI_DATA->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH - || AI_THINKING_STRUCT->aiFlags[AI_DATA->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH) + if (gAiThinkingStruct->aiFlags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH + || gAiThinkingStruct->aiFlags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH) { - if (AI_DATA->predictingSwitch && AI_DATA->shouldSwitch & (1u << battler)) + if (gAiLogicData->predictingSwitch && gAiLogicData->shouldSwitch & (1u << battler)) return TRUE; } return FALSE; @@ -155,18 +155,18 @@ bool32 IsBattlerPredictedToSwitch(u32 battler) void ClearBattlerMoveHistory(u32 battlerId) { - memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId])); - memset(BATTLE_HISTORY->moveHistory[battlerId], 0, sizeof(BATTLE_HISTORY->moveHistory[battlerId])); - BATTLE_HISTORY->moveHistoryIndex[battlerId] = 0; + memset(gBattleHistory->usedMoves[battlerId], 0, sizeof(gBattleHistory->usedMoves[battlerId])); + memset(gBattleHistory->moveHistory[battlerId], 0, sizeof(gBattleHistory->moveHistory[battlerId])); + gBattleHistory->moveHistoryIndex[battlerId] = 0; } void RecordLastUsedMoveBy(u32 battlerId, u32 move) { - u8 *index = &BATTLE_HISTORY->moveHistoryIndex[battlerId]; + u8 *index = &gBattleHistory->moveHistoryIndex[battlerId]; if (++(*index) >= AI_MOVE_HISTORY_COUNT) *index = 0; - BATTLE_HISTORY->moveHistory[battlerId][*index] = move; + gBattleHistory->moveHistory[battlerId][*index] = move; } void RecordKnownMove(u32 battlerId, u32 move) @@ -175,12 +175,12 @@ void RecordKnownMove(u32 battlerId, u32 move) for (i = 0; i < MAX_MON_MOVES; i++) { - if (BATTLE_HISTORY->usedMoves[battlerId][i] == move) + if (gBattleHistory->usedMoves[battlerId][i] == move) break; - if (BATTLE_HISTORY->usedMoves[battlerId][i] == MOVE_NONE) + if (gBattleHistory->usedMoves[battlerId][i] == MOVE_NONE) { - BATTLE_HISTORY->usedMoves[battlerId][i] = move; - AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; + gBattleHistory->usedMoves[battlerId][i] = move; + gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].moves[i] = move; break; } } @@ -188,47 +188,47 @@ void RecordKnownMove(u32 battlerId, u32 move) void RecordAllMoves(u32 battler) { - memcpy(AI_PARTY->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); + memcpy(gAiPartyData->mons[GetBattlerSide(battler)][gBattlerPartyIndexes[battler]].moves, gBattleMons[battler].moves, MAX_MON_MOVES * sizeof(u16)); } void RecordAbilityBattle(u32 battlerId, u32 abilityId) { - BATTLE_HISTORY->abilities[battlerId] = abilityId; - AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; + gBattleHistory->abilities[battlerId] = abilityId; + gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; } void ClearBattlerAbilityHistory(u32 battlerId) { - BATTLE_HISTORY->abilities[battlerId] = ABILITY_NONE; + gBattleHistory->abilities[battlerId] = ABILITY_NONE; } void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) { - BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; - AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; + gBattleHistory->itemEffects[battlerId] = itemEffect; + gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; } void ClearBattlerItemEffectHistory(u32 battlerId) { - BATTLE_HISTORY->itemEffects[battlerId] = 0; + gBattleHistory->itemEffects[battlerId] = 0; } void SaveBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId) && !AI_THINKING_STRUCT->saved[battlerId].saved) + if (!BattlerHasAi(battlerId) && !gAiThinkingStruct->saved[battlerId].saved) { u32 i; - AI_THINKING_STRUCT->saved[battlerId].saved = TRUE; - AI_THINKING_STRUCT->saved[battlerId].ability = gBattleMons[battlerId].ability; - AI_THINKING_STRUCT->saved[battlerId].heldItem = gBattleMons[battlerId].item; - AI_THINKING_STRUCT->saved[battlerId].species = gBattleMons[battlerId].species; + gAiThinkingStruct->saved[battlerId].saved = TRUE; + gAiThinkingStruct->saved[battlerId].ability = gBattleMons[battlerId].ability; + gAiThinkingStruct->saved[battlerId].heldItem = gBattleMons[battlerId].item; + gAiThinkingStruct->saved[battlerId].species = gBattleMons[battlerId].species; for (i = 0; i < 4; i++) - AI_THINKING_STRUCT->saved[battlerId].moves[i] = gBattleMons[battlerId].moves[i]; + gAiThinkingStruct->saved[battlerId].moves[i] = gBattleMons[battlerId].moves[i]; } // Save and restore types even for AI controlled battlers in case it gets changed during move evaluation process. - AI_THINKING_STRUCT->saved[battlerId].types[0] = gBattleMons[battlerId].types[0]; - AI_THINKING_STRUCT->saved[battlerId].types[1] = gBattleMons[battlerId].types[1]; + gAiThinkingStruct->saved[battlerId].types[0] = gBattleMons[battlerId].types[0]; + gAiThinkingStruct->saved[battlerId].types[1] = gBattleMons[battlerId].types[1]; } static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) @@ -236,13 +236,13 @@ static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) u32 i, j; const struct LevelUpMove *learnset; - if (BATTLE_HISTORY->abilities[battlerId] == ABILITY_ILLUSION) + if (gBattleHistory->abilities[battlerId] == ABILITY_ILLUSION) return FALSE; // Don't fall for Illusion if the mon used a move it cannot know. for (i = 0; i < MAX_MON_MOVES; i++) { - u32 move = BATTLE_HISTORY->usedMoves[battlerId][i]; + u32 move = gBattleHistory->usedMoves[battlerId][i]; if (move == MOVE_NONE) continue; @@ -269,7 +269,7 @@ static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) void SetBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId) && AI_THINKING_STRUCT->saved[battlerId].saved) + if (!BattlerHasAi(battlerId) && gAiThinkingStruct->saved[battlerId].saved) { u32 i, species, illusionSpecies, side; side = GetBattlerSide(battlerId); @@ -290,8 +290,8 @@ void SetBattlerData(u32 battlerId) } // Use the known battler's ability. - if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) - gBattleMons[battlerId].ability = AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].ability; + if (gAiPartyData->mons[side][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) + gBattleMons[battlerId].ability = gAiPartyData->mons[side][gBattlerPartyIndexes[battlerId]].ability; // Check if mon can only have one ability. else if (gSpeciesInfo[species].abilities[1] == ABILITY_NONE || gSpeciesInfo[species].abilities[1] == gSpeciesInfo[species].abilities[0]) @@ -300,12 +300,12 @@ void SetBattlerData(u32 battlerId) else gBattleMons[battlerId].ability = ABILITY_NONE; - if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].heldEffect == 0) + if (gAiPartyData->mons[side][gBattlerPartyIndexes[battlerId]].heldEffect == 0) gBattleMons[battlerId].item = 0; for (i = 0; i < MAX_MON_MOVES; i++) { - if (AI_PARTY->mons[side][gBattlerPartyIndexes[battlerId]].moves[i] == 0) + if (gAiPartyData->mons[side][gBattlerPartyIndexes[battlerId]].moves[i] == 0) gBattleMons[battlerId].moves[i] = 0; } } @@ -313,19 +313,19 @@ void SetBattlerData(u32 battlerId) void RestoreBattlerData(u32 battlerId) { - if (!BattlerHasAi(battlerId) && AI_THINKING_STRUCT->saved[battlerId].saved) + if (!BattlerHasAi(battlerId) && gAiThinkingStruct->saved[battlerId].saved) { u32 i; - AI_THINKING_STRUCT->saved[battlerId].saved = FALSE; - gBattleMons[battlerId].ability = AI_THINKING_STRUCT->saved[battlerId].ability; - gBattleMons[battlerId].item = AI_THINKING_STRUCT->saved[battlerId].heldItem; - gBattleMons[battlerId].species = AI_THINKING_STRUCT->saved[battlerId].species; + gAiThinkingStruct->saved[battlerId].saved = FALSE; + gBattleMons[battlerId].ability = gAiThinkingStruct->saved[battlerId].ability; + gBattleMons[battlerId].item = gAiThinkingStruct->saved[battlerId].heldItem; + gBattleMons[battlerId].species = gAiThinkingStruct->saved[battlerId].species; for (i = 0; i < 4; i++) - gBattleMons[battlerId].moves[i] = AI_THINKING_STRUCT->saved[battlerId].moves[i]; + gBattleMons[battlerId].moves[i] = gAiThinkingStruct->saved[battlerId].moves[i]; } - gBattleMons[battlerId].types[0] = AI_THINKING_STRUCT->saved[battlerId].types[0]; - gBattleMons[battlerId].types[1] = AI_THINKING_STRUCT->saved[battlerId].types[1]; + gBattleMons[battlerId].types[0] = gAiThinkingStruct->saved[battlerId].types[0]; + gBattleMons[battlerId].types[1] = gAiThinkingStruct->saved[battlerId].types[1]; } u32 GetHealthPercentage(u32 battlerId) @@ -335,7 +335,7 @@ u32 GetHealthPercentage(u32 battlerId) bool32 AI_BattlerAtMaxHp(u32 battlerId) { - if (AI_DATA->hpPercents[battlerId] == 100) + if (gAiLogicData->hpPercents[battlerId] == 100) return TRUE; return FALSE; } @@ -343,7 +343,7 @@ bool32 AI_BattlerAtMaxHp(u32 battlerId) bool32 AI_CanBattlerEscape(u32 battler) { - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[battler]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battler]; if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; @@ -362,7 +362,7 @@ bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef) if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK) return TRUE; if (AI_IsAbilityOnSide(battlerAtk, ABILITY_SHADOW_TAG) - && (B_SHADOW_TAG_ESCAPE >= GEN_4 && AI_DATA->abilities[battlerDef] != ABILITY_SHADOW_TAG)) + && (B_SHADOW_TAG_ESCAPE >= GEN_4 && gAiLogicData->abilities[battlerDef] != ABILITY_SHADOW_TAG)) return TRUE; if (AI_IsAbilityOnSide(battlerAtk, ABILITY_ARENA_TRAP) && IsBattlerGrounded(battlerAtk)) @@ -390,7 +390,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) for (i = 0; i < MAX_MON_MOVES; i++) { - u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; + u32 move = gBattleHistory->usedMoves[opposingBattler][i]; enum BattleMoveEffects effect = GetMoveEffect(move); if (effect == EFFECT_PROTECT && move != MOVE_ENDURE) return TRUE; @@ -417,7 +417,7 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) s32 i, moveType; u32 usable = 0; u16 *moves = GetMovesArray(attacker); - u32 moveLimitations = AI_DATA->moveLimitations[attacker]; + u32 moveLimitations = gAiLogicData->moveLimitations[attacker]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -428,7 +428,7 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) { SetTypeBeforeUsingMove(moves[i], attacker); moveType = GetBattleMoveType(moves[i]); - if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0) + if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, gAiLogicData->abilities[target], FALSE) != 0) usable |= 1u << i; } } @@ -474,7 +474,7 @@ static inline s32 DmgRoll(s32 dmg) bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveType) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; if (gBattleStruct->battlerState[battlerDef].commandingDondozo) return TRUE; @@ -513,7 +513,7 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy return TRUE; break; case EFFECT_POLTERGEIST: - if (AI_DATA->items[battlerDef] == ITEM_NONE || !IsBattlerItemEnabled(battlerDef)) + if (gAiLogicData->items[battlerDef] == ITEM_NONE || !IsBattlerItemEnabled(battlerDef)) return TRUE; break; case EFFECT_FIRST_TURN_ONLY: @@ -677,11 +677,11 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo if (critChanceIndex == CRITICAL_HIT_ALWAYS) return TRUE; if (critChanceIndex >= RISKY_AI_CRIT_STAGE_THRESHOLD // Not guaranteed but above Risky threshold - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && GetGenConfig(GEN_CONFIG_CRIT_CHANCE) != GEN_1) return TRUE; if (critChanceIndex >= RISKY_AI_CRIT_THRESHOLD_GEN_1 // Not guaranteed but above Risky threshold - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1) return TRUE; return FALSE; @@ -695,8 +695,8 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u uq4_12_t effectivenessMultiplier; bool32 isDamageMoveUnusable = FALSE; bool32 toggledGimmick = FALSE; - struct AiLogicData *aiData = AI_DATA; - AI_DATA->aiCalcInProgress = TRUE; + struct AiLogicData *aiData = gAiLogicData; + gAiLogicData->aiCalcInProgress = TRUE; if (moveEffect == EFFECT_NATURE_POWER) move = GetNaturePowerMove(battlerAtk); @@ -817,13 +817,13 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE; if (toggledGimmick) SetActiveGimmick(battlerAtk, GIMMICK_NONE); - AI_DATA->aiCalcInProgress = FALSE; + gAiLogicData->aiCalcInProgress = FALSE; return simDamage; } bool32 AI_IsDamagedByRecoil(u32 battler) { - u32 ability = AI_DATA->abilities[battler]; + u32 ability = gAiLogicData->abilities[battler]; if (ability == ABILITY_MAGIC_GUARD || ability == ABILITY_ROCK_HEAD) return FALSE; return TRUE; @@ -833,13 +833,13 @@ bool32 AI_IsDamagedByRecoil(u32 battler) static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) { u32 i; - u32 abilityDef = AI_DATA->abilities[battlerDef]; - u32 abilityAtk = AI_DATA->abilities[battlerAtk]; + u32 abilityDef = gAiLogicData->abilities[battlerDef]; + u32 abilityAtk = gAiLogicData->abilities[battlerAtk]; switch (GetMoveEffect(move)) { case EFFECT_HIT_ESCAPE: - if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityDef, move, AI_THINKING_STRUCT->movesetIndex)) + if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityDef, move, gAiThinkingStruct->movesetIndex)) return TRUE; break; case EFFECT_FELL_STINGER: @@ -961,8 +961,8 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s32 noOfHitsToKo) { - u32 abilityAtk = AI_DATA->abilities[battlerAtk]; - u32 abilityDef = AI_DATA->abilities[battlerDef]; + u32 abilityAtk = gAiLogicData->abilities[battlerAtk]; + u32 abilityDef = gAiLogicData->abilities[battlerDef]; u8 i; switch (GetMoveEffect(move)) @@ -1041,12 +1041,12 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo) { bool32 effect1, effect2; - u32 defAbility = AI_DATA->abilities[battlerDef]; - u32 atkAbility = AI_DATA->abilities[battlerAtk]; + u32 defAbility = gAiLogicData->abilities[battlerDef]; + u32 atkAbility = gAiLogicData->abilities[battlerAtk]; // Check if physical moves hurt. - if (AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_PROTECTIVE_PADS && atkAbility != ABILITY_LONG_REACH - && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET + if (gAiLogicData->holdEffects[battlerAtk] != HOLD_EFFECT_PROTECTIVE_PADS && atkAbility != ABILITY_LONG_REACH + && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET || defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN)) { bool32 moveContact1 = MoveMakesContact(move1); @@ -1089,12 +1089,12 @@ u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef) u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext) { - return GetNoOfHitsToKOBattlerDmg(AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, AI_DATA), battlerDef); + return GetNoOfHitsToKOBattlerDmg(AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, gAiLogicData), battlerDef); } u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext) { - int bestDmg = AI_GetDamage(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, calcContext, AI_DATA); + int bestDmg = AI_GetDamage(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, calcContext, gAiLogicData); return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; } @@ -1113,7 +1113,7 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) gBattleStruct->dynamicMoveType = 0; SetTypeBeforeUsingMove(move, battlerAtk); moveType = GetBattleMoveType(move); - typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], FALSE); + typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], FALSE); RestoreBattlerData(battlerAtk); RestoreBattlerData(battlerDef); @@ -1130,12 +1130,12 @@ uq4_12_t AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered) { u32 speedBattlerAI, speedBattler; - enum ItemHoldEffect holdEffectAI = AI_DATA->holdEffects[battlerAI]; - enum ItemHoldEffect holdEffectPlayer = AI_DATA->holdEffects[battler]; - u32 abilityAI = AI_DATA->abilities[battlerAI]; - u32 abilityPlayer = AI_DATA->abilities[battler]; + enum ItemHoldEffect holdEffectAI = gAiLogicData->holdEffects[battlerAI]; + enum ItemHoldEffect holdEffectPlayer = gAiLogicData->holdEffects[battler]; + u32 abilityAI = gAiLogicData->abilities[battlerAI]; + u32 abilityPlayer = gAiLogicData->abilities[battler]; - u32 predictedMove = AI_DATA->lastUsedMove[battler]; // TODO update for move prediction + u32 predictedMove = gAiLogicData->lastUsedMove[battler]; // TODO update for move prediction s8 aiPriority = GetBattleMovePriority(battlerAI, abilityAI, moveConsidered); s8 playerPriority = GetBattleMovePriority(battler, abilityPlayer, predictedMove); @@ -1187,12 +1187,12 @@ static bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) return FALSE; if (GetMoveStrikeCount(move) > 1 && !(effect == EFFECT_DRAGON_DARTS && IsValidDoubleBattle(battlerTarget))) return FALSE; - if (AI_DATA->holdEffects[battlerTarget] == HOLD_EFFECT_FOCUS_SASH) + if (gAiLogicData->holdEffects[battlerTarget] == HOLD_EFFECT_FOCUS_SASH) return TRUE; - if (!DoesBattlerIgnoreAbilityChecks(battler, AI_DATA->abilities[battler], move)) + if (!DoesBattlerIgnoreAbilityChecks(battler, gAiLogicData->abilities[battler], move)) { - if (B_STURDY >= GEN_5 && AI_DATA->abilities[battlerTarget] == ABILITY_STURDY) + if (B_STURDY >= GEN_5 && gAiLogicData->abilities[battlerTarget] == ABILITY_STURDY) return TRUE; if (gBattleMons[battlerTarget].species == SPECIES_MIMIKYU_DISGUISED) return TRUE; @@ -1204,7 +1204,7 @@ static bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) // Check if target has means to faint ai mon. bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; s32 moveIndex; u16 *moves = GetMovesArray(battlerDef); u32 moveLimitations = aiData->moveLimitations[battlerDef]; @@ -1242,7 +1242,7 @@ u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk) u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; u32 moveIndex; u32 move = 0; u32 bestDmg = 0; @@ -1265,7 +1265,7 @@ u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcCon u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext calcContext) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; u32 moveIndex; u32 bestDmg = 0; u16 *moves = GetMovesArray(battler); @@ -1288,7 +1288,7 @@ u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext // If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects) bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; s32 moveIndex, dmg; u16 *moves = gBattleMons[battlerAtk].moves; u32 moveLimitations = aiData->moveLimitations[battlerAtk]; @@ -1321,7 +1321,7 @@ bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) u32 indexSlot = GetMoveSlot(GetMovesArray(battlerDef), move); if (indexSlot < MAX_MON_MOVES) { - if (GetNoOfHitsToKO(AI_GetDamage(battlerDef, battlerAtk, indexSlot, AI_DEFENDING, AI_DATA), gBattleMons[battlerAtk].hp) <= nHits) + if (GetNoOfHitsToKO(AI_GetDamage(battlerDef, battlerAtk, indexSlot, AI_DEFENDING, gAiLogicData), gBattleMons[battlerAtk].hp) <= nHits) return TRUE; } return FALSE; @@ -1330,7 +1330,7 @@ bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) // Check if target has means to faint ai mon after modding hp/dmg bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod) { - struct AiLogicData *aiData = AI_DATA; + struct AiLogicData *aiData = gAiLogicData; u32 moveIndex; s32 dmg; u16 *moves = GetMovesArray(battlerDef); @@ -1359,9 +1359,9 @@ bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dm bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) { - if (IsBattlerAlive(battlerId) && AI_DATA->abilities[battlerId] == ability) + if (IsBattlerAlive(battlerId) && gAiLogicData->abilities[battlerId] == ability) return TRUE; - else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_DATA->abilities[BATTLE_PARTNER(battlerId)] == ability) + else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && gAiLogicData->abilities[BATTLE_PARTNER(battlerId)] == ability) return TRUE; else return FALSE; @@ -1392,7 +1392,7 @@ s32 AI_DecideKnownAbilityForTurn(u32 battlerId) u32 indexAbility; u32 abilityAiRatings[NUM_ABILITY_SLOTS] = {0}; - // We've had ability overwritten by e.g. Worry Seed. It is not part of AI_PARTY in case of switching + // We've had ability overwritten by e.g. Worry Seed. It is not part of gAiPartyData in case of switching if (gDisableStructs[battlerId].overwrittenAbility) return gDisableStructs[battlerId].overwrittenAbility; @@ -1404,8 +1404,8 @@ s32 AI_DecideKnownAbilityForTurn(u32 battlerId) if (knownAbility == ABILITY_NONE) return knownAbility; - if (AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) - return AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability; + if (gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability != ABILITY_NONE) + return gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability; // Abilities that prevent fleeing - treat as always known if (knownAbility == ABILITY_SHADOW_TAG || knownAbility == ABILITY_MAGNET_PULL || knownAbility == ABILITY_ARENA_TRAP) @@ -1435,18 +1435,18 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) enum ItemHoldEffect holdEffect; if (!IsAiBattlerAware(battlerId)) - holdEffect = AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; + holdEffect = gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect; else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - if (AI_THINKING_STRUCT->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE) return holdEffect; if (gStatuses3[battlerId] & STATUS3_EMBARGO) return HOLD_EFFECT_NONE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return HOLD_EFFECT_NONE; - if (AI_DATA->abilities[battlerId] == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + if (gAiLogicData->abilities[battlerId] == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) return HOLD_EFFECT_NONE; return holdEffect; @@ -1454,7 +1454,7 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI handicap flag: doesn't understand ability suppression concept if (IsMoldBreakerTypeAbility(battlerAtk, atkAbility) || MoveIgnoresTargetAbility(move)) @@ -1465,11 +1465,11 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move) static inline bool32 AI_WeatherHasEffect(void) { - if (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_NEGATE_UNAWARE - || AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_NEGATE_UNAWARE + || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_NEGATE_UNAWARE) return TRUE; // AI doesn't understand weather supression (handicap) - return AI_DATA->weatherHasEffect; // weather damping abilities are announced + return gAiLogicData->weatherHasEffect; // weather damping abilities are announced } u32 AI_GetWeather(void) @@ -1583,7 +1583,7 @@ bool32 IsHazardClearingMove(u32 move) bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; enum BattleMoveEffects effect = GetMoveEffect(move); @@ -1623,7 +1623,7 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move) if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk) return TRUE; - if (AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD) + if (gAiLogicData->abilities[battlerDef] == ABILITY_NO_GUARD || gAiLogicData->abilities[battlerAtk] == ABILITY_NO_GUARD) return TRUE; enum BattleMoveEffects effect = GetMoveEffect(move); @@ -1650,11 +1650,11 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move) bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) { - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[battlerDef]; - u32 accuracy = AI_DATA->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef]; + u32 accuracy = gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex]; gPotentialItemEffectBattler = battlerDef; - if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < AI_DATA->holdEffectParams[battlerDef]) + if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < gAiLogicData->holdEffectParams[battlerDef]) return FALSE; //probabilistically speaking, focus band should activate so dont OHKO else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AI_BattlerAtMaxHp(battlerDef)) return FALSE; @@ -1836,7 +1836,7 @@ bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) if (gBattleMons[battlerDef].statStages[stat] == MIN_STAT_STAGE) return FALSE; - if (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) + if (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) return FALSE; switch (abilityDef) @@ -1872,7 +1872,7 @@ bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) if (stat == STAT_SPEED) { // If AI is faster and doesn't have any mons left, lowering speed doesn't give any - return !(AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) + return !(AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) && CountUsablePartyMons(battlerAtk) == 0 && !HasMoveEffect(battlerAtk, EFFECT_ELECTRO_BALL)); } @@ -1937,8 +1937,8 @@ u32 CountNegativeStatStages(u32 battlerId) bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1949,15 +1949,15 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_HYPER_CUTTER - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1968,7 +1968,7 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_BIG_PECKS - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -1979,16 +1979,16 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) || defAbility == ABILITY_CLEAR_BODY || defAbility == ABILITY_FULL_METAL_BODY || defAbility == ABILITY_WHITE_SMOKE - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) return FALSE; - return (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)); + return (AI_IsSlower(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered)); } bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1998,15 +1998,15 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2016,15 +2016,15 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2035,15 +2035,15 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_KEEN_EYE && defAbility != ABILITY_MINDS_EYE && (B_ILLUMINATE_EFFECT >= GEN_9 && defAbility != ABILITY_ILLUMINATE) - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) - && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) + && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2052,7 +2052,7 @@ bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) && defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_WHITE_SMOKE - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) return TRUE; return FALSE; } @@ -2063,9 +2063,9 @@ bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 moveIndex, en u16 *moves = gBattleMons[battlerAtk].moves; if (IsDoubleBattle() && battlerDef == BATTLE_PARTNER(battlerAtk)) - dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; // Attacking partner, be careful + dmg = gAiLogicData->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; // Attacking partner, be careful else - dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, AI_DATA); + dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, gAiLogicData); if (gBattleMons[battlerDef].hp <= dmg && !CanEndureHit(battlerAtk, battlerDef, moves[moveIndex])) return TRUE; @@ -2077,7 +2077,7 @@ bool32 CanIndexMoveGuaranteeFaintTarget(u32 battlerAtk, u32 battlerDef, u32 move s32 dmg; u16 *moves = gBattleMons[battlerAtk].moves; - dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; // Explictly care about guaranteed KOs universally + dmg = gAiLogicData->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; // Explictly care about guaranteed KOs universally if (gBattleMons[battlerDef].hp <= dmg && !CanEndureHit(battlerAtk, battlerDef, moves[moveIndex])) return TRUE; @@ -2089,7 +2089,7 @@ u16 *GetMovesArray(u32 battler) if (IsAiBattlerAware(battler) || IsAiBattlerAware(BATTLE_PARTNER(battler))) return gBattleMons[battler].moves; else - return gBattleResources->battleHistory->usedMoves[battler]; + return gBattleHistory->usedMoves[battler]; } bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensive) @@ -2266,7 +2266,7 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool { s32 i; u16 *moves = GetMovesArray(battlerAtk); - u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u32 moveLimitations = gAiLogicData->moveLimitations[battlerAtk]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2279,7 +2279,7 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool || GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) continue; - if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= accCheck) + if (gAiLogicData->moveAccuracy[battlerAtk][battlerDef][i] <= accCheck) return TRUE; } @@ -2290,14 +2290,14 @@ bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) { u32 i; u16 *moves = GetMovesArray(battlerAtk); - u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u32 moveLimitations = gAiLogicData->moveLimitations[battlerAtk]; for (i = 0; i < MAX_MON_MOVES; i++) { if (IsMoveUnusable(i, moves[i], moveLimitations)) continue; - if (GetMoveEffect(moves[i]) == EFFECT_SLEEP && AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85) + if (GetMoveEffect(moves[i]) == EFFECT_SLEEP && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][i] < 85) return TRUE; } return FALSE; @@ -2652,7 +2652,7 @@ bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move) { case EFFECT_SOLAR_BEAM: case EFFECT_TWO_TURNS_ATTACK: - return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB + return !(gAiLogicData->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB || (AI_GetWeather() & GetMoveTwoTurnAttackWeather(move))); default: return FALSE; @@ -2700,7 +2700,7 @@ static u32 GetTrapDamage(u32 battlerId) { // ai has no knowledge about turns remaining u32 damage = 0; - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[gBattleStruct->wrappedBy[battlerId]]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[gBattleStruct->wrappedBy[battlerId]]; if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED) { if (holdEffect == HOLD_EFFECT_BINDING_BAND) @@ -2718,7 +2718,7 @@ static u32 GetPoisonDamage(u32 battlerId) { u32 damage = 0; - if (AI_DATA->abilities[battlerId] == ABILITY_POISON_HEAL) + if (gAiLogicData->abilities[battlerId] == ABILITY_POISON_HEAL) return damage; if (gBattleMons[battlerId].status1 & STATUS1_POISON) @@ -2763,8 +2763,8 @@ static bool32 BattlerAffectedByHail(u32 battlerId, u32 ability) static u32 GetWeatherDamage(u32 battlerId) { - u32 ability = AI_DATA->abilities[battlerId]; - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[battlerId]; + u32 ability = gAiLogicData->abilities[battlerId]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerId]; u32 damage = 0; u32 weather = AI_GetWeather(); if (!weather) @@ -2799,7 +2799,7 @@ u32 GetBattlerSecondaryDamage(u32 battlerId) { u32 secondaryDamage; - if (AI_DATA->abilities[battlerId] == ABILITY_MAGIC_GUARD) + if (gAiLogicData->abilities[battlerId] == ABILITY_MAGIC_GUARD) return FALSE; secondaryDamage = GetLeechSeedDamage(battlerId) @@ -2928,8 +2928,8 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov if (CanTargetFaintAi(battlerDef, battlerAtk)) return SHOULD_PIVOT; // Won't get the two turns, pivot - if (!IsBattleMoveStatus(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk)) - || (AI_BattlerAtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH + if (!IsBattleMoveStatus(move) && ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) + || (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD)))) @@ -2937,20 +2937,20 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov } else if (!hasStatBoost) { - if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH + if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH || (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY) || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD))) return SHOULD_PIVOT; // pivot to break sash/sturdy/multiscale - if (AI_DATA->shouldSwitch & (1u << battlerAtk)) + if (gAiLogicData->shouldSwitch & (1u << battlerAtk)) return SHOULD_PIVOT; /* TODO - check if switchable mon unafffected by/will remove hazards if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS) return SHOULD_PIVOT;*/ - /*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) + /*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, gAiLogicData->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE) return SHOULD_PIVOT;*/ /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) @@ -2993,7 +2993,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov { if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { - if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk])) + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, gAiLogicData->abilities[battlerAtk])) return CAN_TRY_PIVOT; // Use this move to KO if you must } else // Can't KO the foe @@ -3005,7 +3005,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov { if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) { - if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) // This is the only move that can KO + if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, gAiLogicData->abilities[battlerAtk]) // This is the only move that can KO && !hasStatBoost) //You're not wasting a valuable stat boost { return CAN_TRY_PIVOT; @@ -3014,9 +3014,9 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov else if (CanAIFaintTarget(battlerAtk, battlerDef, 2)) { // can knock out foe in 2 hits - if (IsBattleMoveStatus(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk)) //Damaging move + if (IsBattleMoveStatus(move) && ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) //Damaging move //&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards - || (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AI_BattlerAtMaxHp(battlerDef)))) + || (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AI_BattlerAtMaxHp(battlerDef)))) return DONT_PIVOT; // Pivot to break the sash else return CAN_TRY_PIVOT; @@ -3083,7 +3083,7 @@ bool32 CanKnockOffItem(u32 battler, u32 item) )) && GetBattlerSide(battler) == B_SIDE_PLAYER) return FALSE; - if (AI_DATA->abilities[battler] == ABILITY_STICKY_HOLD) + if (gAiLogicData->abilities[battler] == ABILITY_STICKY_HOLD) return FALSE; if (!CanBattlerGetOrLoseItem(battler, item)) @@ -3130,9 +3130,9 @@ static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, u32 ab bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef) { - u32 abilityDef = AI_DATA->abilities[battlerDef]; + u32 abilityDef = gAiLogicData->abilities[battlerDef]; // Battler can be poisoned and has move/ability that synergizes with being poisoned - if (CanBePoisoned(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], abilityDef) && ( + if (CanBePoisoned(battlerAtk, battlerDef, gAiLogicData->abilities[battlerAtk], abilityDef) && ( DoesBattlerBenefitFromAllVolatileStatus(battlerDef, abilityDef) || abilityDef == ABILITY_POISON_HEAL || (abilityDef == ABILITY_TOXIC_BOOST && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)))) @@ -3219,8 +3219,8 @@ bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef, u32 abilityDef) bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) { - if (!CanBePoisoned(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], defAbility) - || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == UQ_4_12(0.0) + if (!CanBePoisoned(battlerAtk, battlerDef, gAiLogicData->abilities[battlerAtk], defAbility) + || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) return FALSE; @@ -3231,7 +3231,7 @@ bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u3 bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) { if (!CanBeParalyzed(battlerAtk, battlerDef, defAbility) - || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == UQ_4_12(0.0) + || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(BATTLE_PARTNER(battlerAtk), battlerDef, partnerMove)) return FALSE; @@ -3241,7 +3241,7 @@ bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability) { if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) - || (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, AI_DATA->abilities[battlerAtk], move)) + || (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, gAiLogicData->abilities[battlerAtk], move)) || IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD || DoesSubstituteBlockMove(battlerAtk, battlerDef, move)) @@ -3253,7 +3253,7 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battler { if (GetBattlerMoveTargetType(battlerAtk, move) == MOVE_TARGET_FOES_AND_ALLY && AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility) - && !AI_CanBeConfused(battlerAtk, BATTLE_PARTNER(battlerDef), move, AI_DATA->abilities[BATTLE_PARTNER(battlerDef)])) + && !AI_CanBeConfused(battlerAtk, BATTLE_PARTNER(battlerDef), move, gAiLogicData->abilities[BATTLE_PARTNER(battlerDef)])) return FALSE; if (!AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility) @@ -3266,7 +3266,7 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battler bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!CanBeBurned(battlerAtk, battlerDef, defAbility) - || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == UQ_4_12(0.0) + || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) { @@ -3278,7 +3278,7 @@ bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtk bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!CanBeFrozen(battlerAtk, battlerDef, defAbility) - || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == UQ_4_12(0.0) + || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || PartnerMoveEffectIsStatusSameTarget(battlerAtkPartner, battlerDef, partnerMove)) { @@ -3290,7 +3290,7 @@ bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 b bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) - || AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex] == UQ_4_12(0.0) + || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || defAbility == ABILITY_OBLIVIOUS || !AreBattlersOfOppositeGender(battlerAtk, battlerDef) || AI_IsAbilityOnSide(battlerDef, ABILITY_AROMA_VEIL)) @@ -3300,8 +3300,8 @@ bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) { - if (((!IsMoldBreakerTypeAbility(battlerAtk, AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK + if (((!IsMoldBreakerTypeAbility(battlerAtk, gAiLogicData->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || AI_IsSlower(battlerAtk, battlerDef, move))) // Opponent goes first { @@ -3327,10 +3327,10 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move) if (IsBattlerTrapped(battlerAtk, battlerDef)) return FALSE; - if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef])) + if (BattlerWillFaintFromSecondaryDamage(battlerDef, gAiLogicData->abilities[battlerDef])) return TRUE; // battler is taking secondary damage with low HP - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) { if (!CanTargetFaintAi(battlerDef, battlerAtk)) return TRUE; // attacker goes first and opponent can't kill us @@ -3342,12 +3342,12 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move) bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move) { if ((!gDisableStructs[battlerAtk].isFirstTurn && MoveHasAdditionalEffectWithChance(move, MOVE_EFFECT_FLINCH, 100)) - || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS - || AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK + || gAiLogicData->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS + || gAiLogicData->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) - || (!IsMoldBreakerTypeAbility(battlerAtk, AI_DATA->abilities[battlerAtk]) - && (AI_DATA->abilities[battlerDef] == ABILITY_SHIELD_DUST || AI_DATA->abilities[battlerDef] == ABILITY_INNER_FOCUS))) + || (!IsMoldBreakerTypeAbility(battlerAtk, gAiLogicData->abilities[battlerAtk]) + && (gAiLogicData->abilities[battlerDef] == ABILITY_SHIELD_DUST || gAiLogicData->abilities[battlerDef] == ABILITY_INNER_FOCUS))) return FALSE; return TRUE; @@ -3355,13 +3355,13 @@ bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move) static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) { - s32 i, index = BATTLE_HISTORY->moveHistoryIndex[battlerId]; + s32 i, index = gBattleHistory->moveHistoryIndex[battlerId]; for (i = 0; i < x; i++) { if (--index < 0) index = AI_MOVE_HISTORY_COUNT - 1; } - return BATTLE_HISTORY->moveHistory[battlerId][index]; + return gBattleHistory->moveHistory[battlerId][index]; } bool32 IsWakeupTurn(u32 battler) @@ -3386,7 +3386,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) battlerOnField2 = gBattlerPartyIndexes[GetPartnerBattler(battlerId)]; // Check partner's status if ((GetGenConfig(GEN_CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5 - || AI_DATA->abilities[BATTLE_PARTNER(battlerId)] != ABILITY_SOUNDPROOF + || gAiLogicData->abilities[BATTLE_PARTNER(battlerId)] != ABILITY_SOUNDPROOF || !checkSoundproof) && GetMonData(&party[battlerOnField2], MON_DATA_STATUS) != STATUS1_NONE) return TRUE; @@ -3400,7 +3400,7 @@ bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) // Check attacker's status if ((GetGenConfig(GEN_CONFIG_HEAL_BELL_SOUNDPROOF) == GEN_5 || GetGenConfig(GEN_CONFIG_HEAL_BELL_SOUNDPROOF) >= GEN_8 - || AI_DATA->abilities[battlerId] != ABILITY_SOUNDPROOF || !checkSoundproof) + || gAiLogicData->abilities[battlerId] != ABILITY_SOUNDPROOF || !checkSoundproof) && GetMonData(&party[battlerOnField1], MON_DATA_STATUS) != STATUS1_NONE) return TRUE; @@ -3428,13 +3428,13 @@ u32 GetBattlerSideSpeedAverage(u32 battler) if (IsBattlerAlive(battler)) { - speed1 = AI_DATA->speedStats[battler]; + speed1 = gAiLogicData->speedStats[battler]; numBattlersAlive++; } if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(battler))) { - speed2 = AI_DATA->speedStats[BATTLE_PARTNER(battler)]; + speed2 = gAiLogicData->speedStats[BATTLE_PARTNER(battler)]; numBattlersAlive++; } @@ -3468,7 +3468,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage) if (CanTargetFaintAi(battlerDef, battlerAtk) && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0)) return TRUE; // target can faint attacker unless they heal - else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && gAiLogicData->hpPercents[battlerAtk] < 60 && (Random() % 3)) return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing } else @@ -3486,7 +3486,7 @@ bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent, if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move)) { // using item or user going first - s32 damage = AI_GetDamage(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, calcContext, AI_DATA); + s32 damage = AI_GetDamage(battlerAtk, battlerDef, gAiThinkingStruct->movesetIndex, calcContext, gAiLogicData); s32 healAmount = (healPercent * damage) / 100; if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) healAmount = 0; @@ -3494,7 +3494,7 @@ bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent, if (CanTargetFaintAi(battlerDef, battlerAtk) && !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healAmount, 0)) return TRUE; // target can faint attacker unless they heal - else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3)) + else if (!CanTargetFaintAi(battlerDef, battlerAtk) && gAiLogicData->hpPercents[battlerAtk] < 60 && (Random() % 3)) return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing } return FALSE; @@ -3697,7 +3697,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move) party = GetBattlerParty(battlerAtk); if (CountUsablePartyMons(battlerAtk) == 0 - && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]))) + && (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, gAiLogicData->abilities[battlerAtk]))) return FALSE; // Don't heal if last mon and will faint for (i = 0; i < PARTY_SIZE; i++) @@ -3774,16 +3774,16 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl if (calcContext == AI_ATTACKING) { gBattleMons[battlerAtk] = switchinCandidate; - AI_THINKING_STRUCT->saved[battlerDef].saved = TRUE; - SetBattlerAiData(battlerAtk, AI_DATA); // set known opposing battler data - AI_THINKING_STRUCT->saved[battlerDef].saved = FALSE; + gAiThinkingStruct->saved[battlerDef].saved = TRUE; + SetBattlerAiData(battlerAtk, gAiLogicData); // set known opposing battler data + gAiThinkingStruct->saved[battlerDef].saved = FALSE; } else if (calcContext == AI_DEFENDING) { gBattleMons[battlerDef] = switchinCandidate; - AI_THINKING_STRUCT->saved[battlerAtk].saved = TRUE; - SetBattlerAiData(battlerDef, AI_DATA); // set known opposing battler data - AI_THINKING_STRUCT->saved[battlerAtk].saved = FALSE; + gAiThinkingStruct->saved[battlerAtk].saved = TRUE; + SetBattlerAiData(battlerDef, gAiLogicData); // set known opposing battler data + gAiThinkingStruct->saved[battlerAtk].saved = FALSE; } dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather()); @@ -3793,10 +3793,10 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl if (calcContext == AI_ATTACKING) { - SetBattlerAiData(battlerAtk, AI_DATA); - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + SetBattlerAiData(battlerAtk, gAiLogicData); + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) return dmg.maximum; - else if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + else if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) return dmg.minimum; else return dmg.median; @@ -3804,10 +3804,10 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl else if (calcContext == AI_DEFENDING) { - SetBattlerAiData(battlerDef, AI_DATA); - if (AI_THINKING_STRUCT->aiFlags[battlerDef] & AI_FLAG_RISKY && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + SetBattlerAiData(battlerDef, gAiLogicData); + if (gAiThinkingStruct->aiFlags[battlerDef] & AI_FLAG_RISKY && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) return dmg.minimum; - else if (AI_THINKING_STRUCT->aiFlags[battlerDef] & AI_FLAG_CONSERVATIVE && !(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + else if (gAiThinkingStruct->aiFlags[battlerDef] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) return dmg.maximum; else return dmg.median; @@ -3821,10 +3821,10 @@ u32 AI_WhoStrikesFirstPartyMon(u32 battlerAtk, u32 battlerDef, struct BattlePoke struct BattlePokemon *savedBattleMons = AllocSaveBattleMons(); gBattleMons[battlerAtk] = switchinCandidate; - SetBattlerAiData(battlerAtk, AI_DATA); + SetBattlerAiData(battlerAtk, gAiLogicData); u32 aiMonFaster = AI_IsFaster(battlerAtk, battlerDef, moveConsidered); FreeRestoreBattleMons(savedBattleMons); - SetBattlerAiData(battlerAtk, AI_DATA); + SetBattlerAiData(battlerAtk, gAiLogicData); return aiMonFaster; } @@ -4013,11 +4013,11 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); u32 i; - if (considerContrary && AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) + if (considerContrary && gAiLogicData->abilities[battlerAtk] == ABILITY_CONTRARY) return NO_INCREASE; // Don't increase stats if opposing battler has Unaware - if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, AI_DATA)) + if (HasBattlerSideAbility(battlerDef, ABILITY_UNAWARE, gAiLogicData)) return NO_INCREASE; // Don't increase stat if AI is at +4 @@ -4025,7 +4025,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, return NO_INCREASE; // Don't increase stat if AI has less then 70% HP and number of hits isn't known - if (AI_DATA->hpPercents[battlerAtk] < 70 && noOfHitsToFaint == UNKNOWN_NO_OF_HITS) + if (gAiLogicData->hpPercents[battlerAtk] < 70 && noOfHitsToFaint == UNKNOWN_NO_OF_HITS) return NO_INCREASE; // Don't set up if AI is dead to residual damage from weather @@ -4033,7 +4033,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, return NO_INCREASE; // Don't increase stats if opposing battler has Opportunist - if (AI_DATA->abilities[battlerDef] == ABILITY_OPPORTUNIST) + if (gAiLogicData->abilities[battlerDef] == ABILITY_OPPORTUNIST) return NO_INCREASE; // Don't increase stats if opposing battler has Encore @@ -4050,10 +4050,10 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, // If expected switchin outspeeds and has Encore, don't increase for (i = 0; i < MAX_MON_MOVES; i++) { - if (GetMoveEffect(GetMonData(&playerParty[AI_DATA->mostSuitableMonId[battlerDef]], MON_DATA_MOVE1 + i, NULL)) == EFFECT_ENCORE - && GetMonData(&playerParty[AI_DATA->mostSuitableMonId[battlerDef]], MON_DATA_PP1 + i, NULL) > 0); + if (GetMoveEffect(GetMonData(&playerParty[gAiLogicData->mostSuitableMonId[battlerDef]], MON_DATA_MOVE1 + i, NULL)) == EFFECT_ENCORE + && GetMonData(&playerParty[gAiLogicData->mostSuitableMonId[battlerDef]], MON_DATA_PP1 + i, NULL) > 0); { - if (GetMonData(&playerParty[AI_DATA->mostSuitableMonId[battlerDef]], MON_DATA_SPEED, NULL) > gBattleMons[battlerAtk].speed) + if (GetMonData(&playerParty[gAiLogicData->mostSuitableMonId[battlerDef]], MON_DATA_SPEED, NULL) > gBattleMons[battlerAtk].speed) return NO_INCREASE; } } @@ -4070,7 +4070,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_DEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) tempScore += DECENT_EFFECT; else tempScore += WEAK_EFFECT; @@ -4087,7 +4087,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_SPDEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) tempScore += DECENT_EFFECT; else tempScore += WEAK_EFFECT; @@ -4100,7 +4100,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_DEF_2: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) tempScore += GOOD_EFFECT; else tempScore += DECENT_EFFECT; @@ -4117,7 +4117,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_SPDEF_2: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) { - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) tempScore += GOOD_EFFECT; else tempScore += DECENT_EFFECT; @@ -4150,21 +4150,21 @@ u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; - if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20) + if (AI_CanPoison(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], move, gAiLogicData->partnerMove) && gAiLogicData->hpPercents[battlerDef] > 20) { if (!HasDamagingMove(battlerDef)) ADJUST_SCORE_PTR(DECENT_EFFECT); - if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) + if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) ADJUST_SCORE_PTR(WEAK_EFFECT); // stall tactic if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) - || AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS) + || gAiLogicData->abilities[battlerAtk] == ABILITY_MERCILESS) ADJUST_SCORE_PTR(DECENT_EFFECT); else ADJUST_SCORE_PTR(WEAK_EFFECT); @@ -4173,14 +4173,14 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; - if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + if (AI_CanBurn(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, gAiLogicData->partnerMove)) { if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) - || (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects physical attacker + || (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects physical attacker && gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack + 10)) { if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)) == DAMAGE_CATEGORY_PHYSICAL) @@ -4197,14 +4197,14 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; - if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) + if (AI_CanParalyze(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], move, gAiLogicData->partnerMove)) { - u32 atkSpeed = AI_DATA->speedStats[battlerAtk]; - u32 defSpeed = AI_DATA->speedStats[battlerDef]; + u32 atkSpeed = gAiLogicData->speedStats[battlerAtk]; + u32 defSpeed = gAiLogicData->speedStats[battlerDef]; if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe || IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) @@ -4219,11 +4219,11 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0) && GetMoveEffect(GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING)) != EFFECT_FOCUS_PUNCH) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0) && GetMoveEffect(GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING)) != EFFECT_FOCUS_PUNCH) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; - if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove)) + if (AI_CanPutToSleep(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], move, gAiLogicData->partnerMove)) ADJUST_SCORE_PTR(DECENT_EFFECT); else return; @@ -4239,17 +4239,17 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) - || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) + if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; - if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove) - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_CONFUSION - && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS) + if (AI_CanConfuse(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, gAiLogicData->partnerMove) + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CURE_CONFUSION + && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS) { if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION - || (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY))) + || (gAiLogicData->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY))) ADJUST_SCORE_PTR(GOOD_EFFECT); else ADJUST_SCORE_PTR(DECENT_EFFECT); @@ -4258,13 +4258,13 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; - if (AI_CanGiveFrostbite(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)) + if (AI_CanGiveFrostbite(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, gAiLogicData->partnerMove)) { if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) - || (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects special attacker + || (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects special attacker && gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack + 10)) { if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)) == DAMAGE_CATEGORY_SPECIAL) @@ -4330,7 +4330,7 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove) bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId) { - return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerId] == ABILITY_COMATOSE; + return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || gAiLogicData->abilities[battlerId] == ABILITY_COMATOSE; } s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle) @@ -4362,7 +4362,7 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) return TRUE; case STAT_DEF: case STAT_SPDEF: - return (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL); + return (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL); } } } @@ -4455,7 +4455,7 @@ u32 IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) } else if (effect == EFFECT_SHED_TAIL) // Shed Tail specific { - if ((ShouldPivot(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_THINKING_STRUCT->movesetIndex)) + if ((ShouldPivot(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], move, gAiThinkingStruct->movesetIndex)) && (HasAnyKnownMove(battlerDef) && (GetBestDmgFromBattler(battlerDef, battlerAtk, AI_DEFENDING) < gBattleMons[battlerAtk].maxHP / 2))) scoreIncrease += BEST_EFFECT; } @@ -4480,7 +4480,7 @@ u32 IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) || HasMoveEffect(battlerDef, EFFECT_LEECH_SEED)) scoreIncrease += GOOD_EFFECT; - if (AI_DATA->hpPercents[battlerAtk] > 70) + if (gAiLogicData->hpPercents[battlerAtk] > 70) scoreIncrease += WEAK_EFFECT; return scoreIncrease; } @@ -4490,7 +4490,7 @@ bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef) int i; for (i = 0; i < MAX_MON_MOVES; i++) { - if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= LOW_ACCURACY_THRESHOLD) + if (gAiLogicData->moveAccuracy[battlerAtk][battlerDef][i] <= LOW_ACCURACY_THRESHOLD) return TRUE; } return FALSE; @@ -4498,7 +4498,7 @@ bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef) bool32 IsBattlerItemEnabled(u32 battler) { - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_NEGATE_UNAWARE) return TRUE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return FALSE; @@ -4513,7 +4513,7 @@ bool32 HasBattlerSideAbility(u32 battler, u32 ability, struct AiLogicData *aiDat { if (aiData->abilities[battler] == ability) return TRUE; - if (IsDoubleBattle() && AI_DATA->abilities[BATTLE_PARTNER(battler)] == ability) + if (IsDoubleBattle() && gAiLogicData->abilities[BATTLE_PARTNER(battler)] == ability) return TRUE; return FALSE; } diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 654311c417..ce95927c8e 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -650,14 +650,14 @@ static void OpponentHandleChooseItem(u32 battler) static inline bool32 IsAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) { - return AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON + return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_ACE_POKEMON && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle; } static inline bool32 IsDoubleAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) { - return AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON + return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 2) && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle diff --git a/src/battle_debug.c b/src/battle_debug.c index efdebf6377..e863e78181 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -972,7 +972,7 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 83 + count * 54, i * 15, 0, NULL); ConvertIntToDecimalStringN(text, - AI_GetDamage(data->aiBattlerId, battlerDef, i, AI_ATTACKING, AI_DATA), + AI_GetDamage(data->aiBattlerId, battlerDef, i, AI_ATTACKING, gAiLogicData), STR_CONV_MODE_RIGHT_ALIGN, 3); AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 110 + count * 54, i * 15, 0, NULL); @@ -980,9 +980,9 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) } } - if (AI_DATA->shouldSwitch & (1u << data->aiBattlerId)) + if (gAiLogicData->shouldSwitch & (1u << data->aiBattlerId)) { - u32 switchMon = GetMonData(&gEnemyParty[AI_DATA->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES); + u32 switchMon = GetMonData(&gEnemyParty[gAiLogicData->mostSuitableMonId[data->aiBattlerId]], MON_DATA_SPECIES); AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, sText_IsSwitching, 74, 64, 0, NULL); AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, gSpeciesInfo[switchMon].speciesName, 74 + 68, 64, 0, NULL); @@ -1129,9 +1129,9 @@ static void PutAiInfoText(struct BattleDebugMenu *data) { if (GetBattlerSide(i) == B_SIDE_PLAYER && IsBattlerAlive(i)) { - u16 ability = AI_DATA->abilities[i]; - enum ItemHoldEffect holdEffect = AI_DATA->holdEffects[i]; - u16 item = AI_DATA->items[i]; + u16 ability = gAiLogicData->abilities[i]; + enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[i]; + u16 item = gAiLogicData->items[i]; u8 x = (i == B_POSITION_PLAYER_LEFT) ? 83 + (i) * 75 : 83 + (i-1) * 75; AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, gAbilitiesInfo[ability].name, x, 0, 0, NULL); AddTextPrinterParameterized(data->aiMovesWindowId, FONT_SMALL, ItemId_GetName(item), x, 15, 0, NULL); @@ -1147,10 +1147,10 @@ static void PutAiPartyText(struct BattleDebugMenu *data) { u32 i, j, count; u8 *text = Alloc(0x50), *txtPtr; - struct AiPartyMon *aiMons = AI_PARTY->mons[GetBattlerSide(data->aiBattlerId)]; + struct AiPartyMon *aiMons = gAiPartyData->mons[GetBattlerSide(data->aiBattlerId)]; FillWindowPixelBuffer(data->aiMovesWindowId, 0x11); - count = AI_PARTY->count[GetBattlerSide(data->aiBattlerId)]; + count = gAiPartyData->count[GetBattlerSide(data->aiBattlerId)]; for (i = 0; i < count; i++) { if (aiMons[i].wasSentInBattle) @@ -1276,8 +1276,8 @@ static void Task_ShowAiParty(u8 taskId) LoadMonIconPalettes(); LoadPartyMenuAilmentGfx(); data->aiBattlerId = data->battlerId; - aiMons = AI_PARTY->mons[GetBattlerSide(data->aiBattlerId)]; - for (i = 0; i < AI_PARTY->count[GetBattlerSide(data->aiBattlerId)]; i++) + aiMons = gAiPartyData->mons[GetBattlerSide(data->aiBattlerId)]; + for (i = 0; i < gAiPartyData->count[GetBattlerSide(data->aiBattlerId)]; i++) { u16 species = SPECIES_NONE; // Question mark if (aiMons[i].wasSentInBattle && aiMons[i].species) @@ -2199,8 +2199,8 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) data->modifyArrows.typeOfVal = VAL_BITFIELD_32; goto CASE_ITEM_STATUS; case LIST_ITEM_AI: - data->modifyArrows.modifiedValPtr = &gBattleResources->ai->aiFlags[data->battlerId]; - data->modifyArrows.currValue = GetBitfieldValue(gBattleResources->ai->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount); + data->modifyArrows.modifiedValPtr = &gAiThinkingStruct->aiFlags[data->battlerId]; + data->modifyArrows.currValue = GetBitfieldValue(gAiThinkingStruct->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount); data->modifyArrows.typeOfVal = VAL_BITFIELD_32; goto CASE_ITEM_STATUS; CASE_ITEM_STATUS: diff --git a/src/battle_main.c b/src/battle_main.c index d049dbb370..02c111cb4f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -209,7 +209,14 @@ EWRAM_DATA u8 gSentPokesToOpponent[2] = {0}; EWRAM_DATA struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA struct BattleScripting gBattleScripting = {0}; EWRAM_DATA struct BattleStruct *gBattleStruct = NULL; + +EWRAM_DATA struct AiThinkingStruct *gAiThinkingStruct = NULL; +EWRAM_DATA struct AiLogicData *gAiLogicData = NULL; +EWRAM_DATA struct AiPartyData *gAiPartyData = NULL; +EWRAM_DATA struct BattleHistory *gBattleHistory = NULL; + EWRAM_DATA struct AiBattleData *gAiBattleData = NULL; + EWRAM_DATA u8 *gLinkBattleSendBuffer = NULL; EWRAM_DATA u8 *gLinkBattleRecvBuffer = NULL; EWRAM_DATA struct BattleResources *gBattleResources = NULL; @@ -3230,8 +3237,8 @@ void SwitchInClearSetData(u32 battler) gSpecialStatuses[battler].enduredDamage = FALSE; // Reset Eject Button / Eject Pack switch detection - AI_DATA->ejectButtonSwitch = FALSE; - AI_DATA->ejectPackSwitch = FALSE; + gAiLogicData->ejectButtonSwitch = FALSE; + gAiLogicData->ejectPackSwitch = FALSE; // Reset G-Max Chi Strike boosts. gBattleStruct->bonusCritStages[battler] = 0; @@ -3887,7 +3894,7 @@ static void TryDoEventsBeforeFirstTurn(void) memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); SetShellSideArmCategory(); - SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers + SetAiLogicDataForTurn(gAiLogicData); // get assumed abilities, hold effects, etc of all battlers if (gBattleTypeFlags & BATTLE_TYPE_ARENA) { @@ -3987,7 +3994,7 @@ void BattleTurnPassed(void) BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); SetShellSideArmCategory(); - SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers + SetAiLogicDataForTurn(gAiLogicData); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 914ffe7fc1..63720331c9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -7109,7 +7109,7 @@ static void Cmd_moveend(void) gBattleStruct->battlerState[battler].usedEjectItem = TRUE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; - AI_DATA->ejectButtonSwitch = TRUE; + gAiLogicData->ejectButtonSwitch = TRUE; break; // Only the fastest Eject Button activates } } @@ -7159,7 +7159,7 @@ static void Cmd_moveend(void) gBattleStruct->battlerState[battler].usedEjectItem = TRUE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EjectPackActivates; - AI_DATA->ejectPackSwitch = TRUE; + gAiLogicData->ejectPackSwitch = TRUE; break; // Only the fastest Eject item activates } } @@ -11643,13 +11643,13 @@ static void Cmd_various(void) case VARIOUS_SAVE_BATTLER_ITEM: { VARIOUS_ARGS(); - gBattleResources->battleHistory->heldItems[battler] = gBattleMons[battler].item; + gBattleHistory->heldItems[battler] = gBattleMons[battler].item; break; } case VARIOUS_RESTORE_BATTLER_ITEM: { VARIOUS_ARGS(); - gBattleMons[battler].item = gBattleResources->battleHistory->heldItems[battler]; + gBattleMons[battler].item = gBattleHistory->heldItems[battler]; break; } case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM: @@ -18704,7 +18704,7 @@ void BS_TryIntimidatEjectpack(void) { gProtectStructs[battler].statFell = FALSE; gProtectStructs[partnerBattler].statFell = FALSE; - AI_DATA->ejectPackSwitch = TRUE; + gAiLogicData->ejectPackSwitch = TRUE; gBattleScripting.battler = affectedBattler; gLastUsedItem = gBattleMons[affectedBattler].item; RecordItemEffectBattle(affectedBattler, HOLD_EFFECT_EJECT_PACK); diff --git a/src/battle_util.c b/src/battle_util.c index 43d507707c..32194c4b3c 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2984,7 +2984,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a && !IsBattlerAlly(battlerAtk, partnerDef)) { if (option == ABILITY_CHECK_TRIGGER_AI) - abilityDef = AI_DATA->abilities[partnerDef]; + abilityDef = gAiLogicData->abilities[partnerDef]; else abilityDef = GetBattlerAbility(partnerDef); @@ -6080,7 +6080,7 @@ static enum ItemEffect TryEjectPack(u32 battler, enum ItemCaseId caseID) { gProtectStructs[battler].statFell = FALSE; gBattleScripting.battler = battler; - AI_DATA->ejectPackSwitch = TRUE; + gAiLogicData->ejectPackSwitch = TRUE; if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN) { BattleScriptExecute(BattleScript_EjectPackActivate_End2); @@ -7822,7 +7822,7 @@ static bool32 IsBattlerGroundedInverseCheck(u32 battler, bool32 considerInverse) return FALSE; if (holdEffect == HOLD_EFFECT_AIR_BALLOON) return FALSE; - if ((AI_DATA->aiCalcInProgress ? AI_DATA->abilities[battler] : GetBattlerAbility(battler)) == ABILITY_LEVITATE) + if ((gAiLogicData->aiCalcInProgress ? gAiLogicData->abilities[battler] : GetBattlerAbility(battler)) == ABILITY_LEVITATE) return FALSE; if (IS_BATTLER_OF_TYPE(battler, TYPE_FLYING) && (!considerInverse || !FlagGet(B_FLAG_INVERSE_BATTLE))) return FALSE; diff --git a/src/battle_util2.c b/src/battle_util2.c index 3fd6549a19..a77af79d78 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -19,6 +19,10 @@ void AllocateBattleResources(void) gBattleStruct = AllocZeroed(sizeof(*gBattleStruct)); gAiBattleData = AllocZeroed(sizeof(*gAiBattleData)); + gAiThinkingStruct = AllocZeroed(sizeof(*gAiThinkingStruct)); + gAiLogicData = AllocZeroed(sizeof(*gAiLogicData)); + gAiPartyData = AllocZeroed(sizeof(*gAiPartyData)); + gBattleHistory = AllocZeroed(sizeof(*gBattleHistory)); #if B_FLAG_SKY_BATTLE gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE); @@ -29,10 +33,6 @@ void AllocateBattleResources(void) gBattleResources->battleScriptsStack = AllocZeroed(sizeof(*gBattleResources->battleScriptsStack)); gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack)); gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp)); - gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai)); - gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData)); - gBattleResources->aiParty = AllocZeroed(sizeof(*gBattleResources->aiParty)); - gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory)); gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE); gLinkBattleRecvBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE); @@ -57,15 +57,15 @@ void FreeBattleResources(void) { FREE_AND_SET_NULL(gBattleStruct); FREE_AND_SET_NULL(gAiBattleData); + FREE_AND_SET_NULL(gAiThinkingStruct); + FREE_AND_SET_NULL(gAiLogicData); + FREE_AND_SET_NULL(gAiPartyData); + FREE_AND_SET_NULL(gBattleHistory); FREE_AND_SET_NULL(gBattleResources->secretBase); FREE_AND_SET_NULL(gBattleResources->battleScriptsStack); FREE_AND_SET_NULL(gBattleResources->battleCallbackStack); FREE_AND_SET_NULL(gBattleResources->beforeLvlUp); - FREE_AND_SET_NULL(gBattleResources->ai); - FREE_AND_SET_NULL(gBattleResources->aiData); - FREE_AND_SET_NULL(gBattleResources->aiParty); - FREE_AND_SET_NULL(gBattleResources->battleHistory); FREE_AND_SET_NULL(gBattleResources); FREE_AND_SET_NULL(gLinkBattleSendBuffer); diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 0b385c017c..0349b08ff0 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -87,7 +87,7 @@ void RecordedBattle_Init(u8 mode) for (j = 0; j < BATTLER_RECORD_SIZE; j++) sBattleRecords[i][j] = 0xFF; sBattleFlags = gBattleTypeFlags; - sAI_Scripts = gBattleResources->ai->aiFlags[B_POSITION_OPPONENT_LEFT]; + sAI_Scripts = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; } } } diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index c67095b5e9..e4edecd3df 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -45,7 +45,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers Water Gun over Bubble if it knows that foe has } SCENE { MESSAGE("Shuckle's Defense fell!"); // Contrary activates } THEN { - EXPECT(gBattleResources->aiData->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY); + EXPECT(gAiThinkingStruct->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY); } } @@ -749,7 +749,7 @@ AI_DOUBLE_BATTLE_TEST("AI recognizes Volt Absorb received from Trace") } WHEN { TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDERSHOCK); NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDER_WAVE); NOT_EXPECT_MOVE(opponentRight, MOVE_THUNDER_WAVE); } } THEN { - EXPECT(gBattleResources->aiData->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB); + EXPECT(gAiThinkingStruct->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB); } } From 057c0f548088c4cdda615bee66db58c6a93e7781 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Thu, 1 May 2025 17:25:27 +0200 Subject: [PATCH 2/6] fix test compiling --- test/battle/ai/ai.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index e4edecd3df..a499a3b841 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -45,7 +45,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers Water Gun over Bubble if it knows that foe has } SCENE { MESSAGE("Shuckle's Defense fell!"); // Contrary activates } THEN { - EXPECT(gAiThinkingStruct->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY); + EXPECT(gAiLogicData->abilities[B_POSITION_PLAYER_LEFT] == ABILITY_CONTRARY); } } @@ -749,7 +749,7 @@ AI_DOUBLE_BATTLE_TEST("AI recognizes Volt Absorb received from Trace") } WHEN { TURN { NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDERSHOCK); NOT_EXPECT_MOVE(opponentLeft, MOVE_THUNDER_WAVE); NOT_EXPECT_MOVE(opponentRight, MOVE_THUNDER_WAVE); } } THEN { - EXPECT(gAiThinkingStruct->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB); + EXPECT(gAiLogicData->abilities[B_POSITION_PLAYER_RIGHT] == ABILITY_VOLT_ABSORB); } } From 9a14bb2dd3956a5ad36c36ee77632d8a9ede6a0e Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Thu, 1 May 2025 20:22:11 +0200 Subject: [PATCH 3/6] removed aiFlags prefix --- include/battle.h | 2 +- src/battle_ai_main.c | 72 +++++++++++++------------- src/battle_ai_switch_items.c | 30 +++++------ src/battle_ai_util.c | 86 ++++++++++++++++---------------- src/battle_controller_opponent.c | 4 +- src/battle_debug.c | 4 +- src/debug.c | 6 +-- src/recorded_battle.c | 2 +- 8 files changed, 103 insertions(+), 103 deletions(-) diff --git a/include/battle.h b/include/battle.h index eb26509b9d..dff832f725 100644 --- a/include/battle.h +++ b/include/battle.h @@ -354,7 +354,7 @@ struct AiThinkingStruct u16 moveConsidered; s32 score[MAX_MON_MOVES]; u32 funcResult; - u32 aiFlags[MAX_BATTLERS_COUNT]; + u32 flags[MAX_BATTLERS_COUNT]; u8 aiAction; u8 aiLogicId; struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT]; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 93f5ddc933..c6d1559020 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -196,43 +196,43 @@ static u32 GetAiFlags(u16 trainerId) void BattleAI_SetupFlags(void) { if (IsAiVsAiBattle()) - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); + gAiThinkingStruct->flags[B_POSITION_PLAYER_LEFT] = GetAiFlags(gPartnerTrainerId); else - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI + gAiThinkingStruct->flags[B_POSITION_PLAYER_LEFT] = 0; // player has no AI if (DEBUG_OVERWORLD_MENU && gIsDebugBattle) { - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; + gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] = gDebugAIFlags; + gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] = gDebugAIFlags; return; } if (IsWildMonSmart() && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))) { // smart wild AI - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(0xFFFF); + gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(0xFFFF); } else { - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); + gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentA); if (TRAINER_BATTLE_PARAM.opponentB != 0) - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); + gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] = GetAiFlags(TRAINER_BATTLE_PARAM.opponentB); else - gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; + gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] = gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT]; } if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); + gAiThinkingStruct->flags[B_POSITION_PLAYER_RIGHT] = GetAiFlags(gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)); } else if (IsDoubleBattle() && IsAiVsAiBattle()) { - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_LEFT]; + gAiThinkingStruct->flags[B_POSITION_PLAYER_RIGHT] = gAiThinkingStruct->flags[B_POSITION_PLAYER_LEFT]; } else { - gAiThinkingStruct->aiFlags[B_POSITION_PLAYER_RIGHT] = 0; // player + gAiThinkingStruct->flags[B_POSITION_PLAYER_RIGHT] = 0; // player } } @@ -242,9 +242,9 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) u32 flags[MAX_BATTLERS_COUNT]; // Clear AI data but preserve the flags. - memcpy(&flags[0], &gAiThinkingStruct->aiFlags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + memcpy(&flags[0], &gAiThinkingStruct->flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); memset(gAiThinkingStruct, 0, sizeof(struct AiThinkingStruct)); - memcpy(&gAiThinkingStruct->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); + memcpy(&gAiThinkingStruct->flags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); moveLimitations = gAiLogicData->moveLimitations[battler]; @@ -287,7 +287,7 @@ void SetupAISwitchingData(u32 battler, enum SwitchType switchType) s32 opposingBattler = GetOppositeBattler(battler); // AI's predicting data - if ((gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH)) + if ((gAiThinkingStruct->flags[battler] & AI_FLAG_PREDICT_SWITCH)) { gAiLogicData->aiSwitchPredictionInProgress = TRUE; gAiLogicData->battlerDoingPrediction = battler; @@ -319,7 +319,7 @@ void ComputeBattlerDecisions(u32 battler) return; // Risky AI switches aggressively even mid battle - enum SwitchType switchType = (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; + enum SwitchType switchType = (gAiThinkingStruct->flags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; gAiLogicData->aiCalcInProgress = TRUE; BattleAI_SetupAIData(0xF, battler); @@ -366,7 +366,7 @@ static void CopyBattlerDataToAIParty(u32 bPosition, u32 side) void Ai_InitPartyStruct(void) { u32 i; - bool32 isOmniscient = (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); + bool32 isOmniscient = (gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT) || (gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT); struct Pokemon *mon; gAiPartyData->count[B_SIDE_PLAYER] = CalculatePlayerPartyCount(); @@ -560,14 +560,14 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi) u8 consideredMoveArray[MAX_MON_MOVES]; u32 numOfBestMoves; s32 i; - u32 flags = gAiThinkingStruct->aiFlags[battlerAi]; + u32 flags = gAiThinkingStruct->flags[battlerAi]; gAiLogicData->partnerMove = 0; // no ally while (flags != 0) { if (flags & 1) { - if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) + if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->flags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battlerAi, gBattlerTarget); else BattleAI_DoAIProcessing(gAiThinkingStruct, battlerAi, gBattlerTarget); @@ -638,13 +638,13 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) gAiLogicData->partnerMove = GetAllyChosenMove(battlerAi); gAiThinkingStruct->aiLogicId = 0; gAiThinkingStruct->movesetIndex = 0; - flags = gAiThinkingStruct->aiFlags[battlerAi]; + flags = gAiThinkingStruct->flags[battlerAi]; while (flags != 0) { if (flags & 1) { - if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) + if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->flags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battlerAi, gBattlerTarget); else BattleAI_DoAIProcessing(gAiThinkingStruct, battlerAi, gBattlerTarget); @@ -1151,7 +1151,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-20); break; case EFFECT_EXPLOSION: - if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE)) + if (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_WILL_SUICIDE)) ADJUST_SCORE(-2); if (effectiveness == UQ_4_12(0.0)) @@ -1501,7 +1501,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-1); if ((predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS || DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove)) - && !(predictedMove == MOVE_NONE && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats + && !(predictedMove == MOVE_NONE && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY))) // Let Risky AI predict blindly based on stats ADJUST_SCORE(-10); break; @@ -2007,7 +2007,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_RECOIL_IF_MISS: if (aiData->abilities[battlerAtk] != ABILITY_MAGIC_GUARD && gAiLogicData->moveAccuracy[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] < 75 - && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY)) ADJUST_SCORE(-6); break; case EFFECT_TRANSFORM: @@ -2122,7 +2122,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } } - /*if (gAiThinkingStruct->aiFlags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI + /*if (gAiThinkingStruct->flags[battlerAtk] == AI_SCRIPT_CHECK_BAD_MOVE //Only basic AI && IsDoubleBattle()) //Make the regular AI know how to use Protect minimally in Doubles { u8 shouldProtect = ShouldProtect(battlerAtk, battlerDef, move); @@ -2436,7 +2436,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { ADJUST_SCORE(-10); } - else if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + else if (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) { if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room Up { @@ -2955,7 +2955,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case ABILITY_VOLT_ABSORB: - if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + if (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_HP_AWARE)) { RETURN_SCORE_MINUS(10); } @@ -2978,7 +2978,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case ABILITY_WATER_ABSORB: case ABILITY_DRY_SKIN: case ABILITY_EARTH_EATER: - if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_HP_AWARE)) + if (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_HP_AWARE)) { RETURN_SCORE_MINUS(10); } @@ -3397,7 +3397,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) moveEffect = EFFECT_PROTECT; // check status move preference - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != UQ_4_12(0.0)) ADJUST_SCORE(10); // check thawing moves @@ -3405,7 +3405,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(10); // check burn / frostbite - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE) { if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE)) || (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE))) @@ -3431,14 +3431,14 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_EXPLOSION: case EFFECT_MEMENTO: - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_WILL_SUICIDE && gBattleMons[battlerDef].statStages[STAT_EVASION] < 7) { if (aiData->hpPercents[battlerAtk] < 50 && AI_RandLessThan(128)) ADJUST_SCORE(DECENT_EFFECT); } break; case EFFECT_FINAL_GAMBIT: - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_WILL_SUICIDE) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_WILL_SUICIDE) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_MIRROR_MOVE: @@ -4451,7 +4451,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(GOOD_EFFECT); // Partner might use pledge move break; case EFFECT_TRICK_ROOM: - if (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) + if (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_POWERFUL_STATUS)) { if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && GetBattlerSideSpeedAverage(battlerAtk) < GetBattlerSideSpeedAverage(battlerDef)) ADJUST_SCORE(GOOD_EFFECT); @@ -4913,7 +4913,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); // No point in checking the move further so return early else { - if (gAiThinkingStruct->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE) + if (gAiThinkingStruct->flags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE) && GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING) == move) ADJUST_SCORE(BEST_DAMAGE_MOVE); else @@ -4935,7 +4935,7 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 || gBattleResults.battleTurnCounter != 0) return score; - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_SMART_SWITCHING && AI_IsSlower(battlerAtk, battlerDef, move) && CanTargetFaintAi(battlerDef, battlerAtk) && GetBattleMovePriority(battlerAtk, gAiLogicData->abilities[battlerAtk], move) == 0) @@ -5512,7 +5512,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_FOCUS_PUNCH: ADJUST_SCORE(DECENT_EFFECT); - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE) { if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < UQ_4_12(2.0)) ADJUST_SCORE(10); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 4937719b44..d28c95834b 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -115,11 +115,11 @@ u32 GetThinkingBattler(u32 battler) static bool32 IsAceMon(u32 battler, u32 monPartyId) { - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON && !gBattleStruct->battlerState[battler].forcedSwitch && monPartyId == CalculateEnemyPartyCountInSide(battler)-1) return TRUE; - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON && !gBattleStruct->battlerState[battler].forcedSwitch && (monPartyId == CalculateEnemyPartyCount()-1 || monPartyId == CalculateEnemyPartyCount()-2)) return TRUE; @@ -187,7 +187,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) enum BattleMoveEffects aiMoveEffect; // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic @@ -461,7 +461,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler) bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); s32 i, j; - if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE return FALSE; @@ -584,7 +584,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler) u32 incomingMove = gAiLogicData->lastUsedMove[opposingBattler]; bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); - if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (IsDoubleBattle() || !(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; if (isOpposingBattlerChargingOrInvulnerable && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) @@ -603,7 +603,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) s32 opposingBattler = GetOppositeBattler(battler); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Check if current mon has an ability that traps opponent @@ -647,7 +647,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) && RandomPercentage(RNG_AI_SWITCH_PERISH_SONG, GetSwitchChance(SHOULD_SWITCH_PERISH_SONG))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) { //Yawn if (gStatuses3[battler] & STATUS3_YAWN @@ -836,7 +836,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc u16 move; // Similar functionality handled more thoroughly by ShouldSwitchIfHasBadOdds - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (gLastLandedMoves[battler] == MOVE_NONE) @@ -974,7 +974,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) u32 opposingBattler = GetOppositeBattler(battler); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // If not Encore'd don't switch @@ -1024,7 +1024,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK]; // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) + if (!(gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Physical attacker @@ -1100,7 +1100,7 @@ bool32 ShouldSwitch(u32 battler) return FALSE; // Sequence Switching AI never switches mid-battle - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) return FALSE; availableToSwitch = 0; @@ -1152,7 +1152,7 @@ bool32 ShouldSwitch(u32 battler) if (ShouldSwitchIfWonderGuard(battler)) return TRUE; - if ((gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) + if ((gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) return FALSE; if (HasGoodSubstituteMove(battler)) return FALSE; @@ -1182,7 +1182,7 @@ bool32 ShouldSwitch(u32 battler) // Removing switch capabilites under specific conditions // These Functions prevent the "FindMonWithFlagsAndSuperEffective" from getting out of hand. // We don't use FindMonWithFlagsAndSuperEffective with AI_FLAG_SMART_SWITCHING, so we can bail early. - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE)) return FALSE; @@ -2166,14 +2166,14 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) GetAIPartyIndexes(battler, &firstId, &lastId); party = GetBattlerParty(battler); - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) { bestMonId = GetNextMonInParty(party, firstId, lastId, battlerIn1, battlerIn2); return bestMonId; } // Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer. - if (gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic + if (gAiThinkingStruct->flags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic { bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchType); return bestMonId; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index e0d040c294..08c3623a17 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -55,17 +55,17 @@ u32 AI_GetDamage(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcC if (calcContext == AI_ATTACKING && BattlerHasAi(battlerAtk)) { - if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it deals max damage + if ((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it deals max damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; - if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it deals min damage + if ((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it deals min damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].median; // Default assumes it deals median damage } else if (calcContext == AI_DEFENDING && BattlerHasAi(battlerDef)) { - if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it takes min damage + if ((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY) && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE)) // Risky assumes it takes min damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].minimum; - if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it takes max damage + if ((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE) && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY)) // Conservative assumes it takes max damage return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].maximum; return aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex].median; // Default assumes it takes median damage } @@ -125,8 +125,8 @@ bool32 BattlerHasAi(u32 battlerId) bool32 IsAiBattlerAware(u32 battlerId) { - if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT - || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT) + if (gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_OMNISCIENT + || gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_OMNISCIENT) return TRUE; return BattlerHasAi(battlerId); @@ -134,8 +134,8 @@ bool32 IsAiBattlerAware(u32 battlerId) bool32 IsAiBattlerPredictingAbility(u32 battlerId) { - if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_WEIGH_ABILITY_PREDICTION - || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_WEIGH_ABILITY_PREDICTION) + if (gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_WEIGH_ABILITY_PREDICTION + || gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_WEIGH_ABILITY_PREDICTION) return TRUE; return BattlerHasAi(battlerId); @@ -144,8 +144,8 @@ bool32 IsAiBattlerPredictingAbility(u32 battlerId) bool32 IsBattlerPredictedToSwitch(u32 battler) { // Check for prediction flag on AI, whether they're using those predictions this turn, and whether the AI thinks the player should switch - if (gAiThinkingStruct->aiFlags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH - || gAiThinkingStruct->aiFlags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH) + if (gAiThinkingStruct->flags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH + || gAiThinkingStruct->flags[gAiLogicData->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH) { if (gAiLogicData->predictingSwitch && gAiLogicData->shouldSwitch & (1u << battler)) return TRUE; @@ -677,11 +677,11 @@ static inline bool32 ShouldCalcCritDamage(u32 battlerAtk, u32 battlerDef, u32 mo if (critChanceIndex == CRITICAL_HIT_ALWAYS) return TRUE; if (critChanceIndex >= RISKY_AI_CRIT_STAGE_THRESHOLD // Not guaranteed but above Risky threshold - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY) && GetGenConfig(GEN_CONFIG_CRIT_CHANCE) != GEN_1) return TRUE; if (critChanceIndex >= RISKY_AI_CRIT_THRESHOLD_GEN_1 // Not guaranteed but above Risky threshold - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY) && GetGenConfig(GEN_CONFIG_CRIT_CHANCE) == GEN_1) return TRUE; return FALSE; @@ -1439,7 +1439,7 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) else holdEffect = GetBattlerHoldEffect(battlerId, FALSE); - if (gAiThinkingStruct->aiFlags[battlerId] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->flags[battlerId] & AI_FLAG_NEGATE_UNAWARE) return holdEffect; if (gStatuses3[battlerId] & STATUS3_EMBARGO) @@ -1454,7 +1454,7 @@ enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId) bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; // AI handicap flag: doesn't understand ability suppression concept if (IsMoldBreakerTypeAbility(battlerAtk, atkAbility) || MoveIgnoresTargetAbility(move)) @@ -1465,8 +1465,8 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move) static inline bool32 AI_WeatherHasEffect(void) { - if (gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_NEGATE_UNAWARE - || gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_NEGATE_UNAWARE + || gAiThinkingStruct->flags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_NEGATE_UNAWARE) return TRUE; // AI doesn't understand weather supression (handicap) return gAiLogicData->weatherHasEffect; // weather damping abilities are announced @@ -1583,7 +1583,7 @@ bool32 IsHazardClearingMove(u32 move) bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE) return FALSE; enum BattleMoveEffects effect = GetMoveEffect(move); @@ -1938,7 +1938,7 @@ u32 CountNegativeStatStages(u32 battlerId) bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1957,7 +1957,7 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1988,7 +1988,7 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2006,7 +2006,7 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2024,7 +2024,7 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -2043,7 +2043,7 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) + && (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -3330,7 +3330,7 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move) if (BattlerWillFaintFromSecondaryDamage(battlerDef, gAiLogicData->abilities[battlerDef])) return TRUE; // battler is taking secondary damage with low HP - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL) { if (!CanTargetFaintAi(battlerDef, battlerAtk)) return TRUE; // attacker goes first and opponent can't kill us @@ -3794,9 +3794,9 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl if (calcContext == AI_ATTACKING) { SetBattlerAiData(battlerAtk, gAiLogicData); - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE)) return dmg.maximum; - else if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + else if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY)) return dmg.minimum; else return dmg.median; @@ -3805,9 +3805,9 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl else if (calcContext == AI_DEFENDING) { SetBattlerAiData(battlerDef, gAiLogicData); - if (gAiThinkingStruct->aiFlags[battlerDef] & AI_FLAG_RISKY && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_CONSERVATIVE)) + if (gAiThinkingStruct->flags[battlerDef] & AI_FLAG_RISKY && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_CONSERVATIVE)) return dmg.minimum; - else if (gAiThinkingStruct->aiFlags[battlerDef] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_RISKY)) + else if (gAiThinkingStruct->flags[battlerDef] & AI_FLAG_CONSERVATIVE && !(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_RISKY)) return dmg.maximum; else return dmg.median; @@ -4070,7 +4070,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_DEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL) tempScore += DECENT_EFFECT; else tempScore += WEAK_EFFECT; @@ -4087,7 +4087,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_SPDEF: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL) tempScore += DECENT_EFFECT; else tempScore += WEAK_EFFECT; @@ -4100,7 +4100,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_DEF_2: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL) tempScore += GOOD_EFFECT; else tempScore += DECENT_EFFECT; @@ -4117,7 +4117,7 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, case STAT_CHANGE_SPDEF_2: if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) || !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) { - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL) tempScore += GOOD_EFFECT; else tempScore += DECENT_EFFECT; @@ -4150,7 +4150,7 @@ u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; @@ -4159,7 +4159,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) if (!HasDamagingMove(battlerDef)) ADJUST_SCORE_PTR(DECENT_EFFECT); - if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) + if (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) ADJUST_SCORE_PTR(WEAK_EFFECT); // stall tactic if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) @@ -4173,14 +4173,14 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; if (AI_CanBurn(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, gAiLogicData->partnerMove)) { if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) - || (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects physical attacker + || (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects physical attacker && gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack + 10)) { if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)) == DAMAGE_CATEGORY_PHYSICAL) @@ -4197,7 +4197,7 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; @@ -4219,7 +4219,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0) && GetMoveEffect(GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING)) != EFFECT_FOCUS_PUNCH) + if (((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0) && GetMoveEffect(GetBestDmgMoveFromBattler(battlerAtk, battlerDef, AI_ATTACKING)) != EFFECT_FOCUS_PUNCH) || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; @@ -4239,7 +4239,7 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; @@ -4258,13 +4258,13 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if ((gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; if (AI_CanGiveFrostbite(battlerAtk, battlerDef, gAiLogicData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, gAiLogicData->partnerMove)) { if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) - || (!(gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects special attacker + || (!(gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects special attacker && gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack + 10)) { if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)) == DAMAGE_CATEGORY_SPECIAL) @@ -4362,7 +4362,7 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef) return TRUE; case STAT_DEF: case STAT_SPDEF: - return (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_STALL); + return (gAiThinkingStruct->flags[battlerAtk] & AI_FLAG_STALL); } } } @@ -4498,7 +4498,7 @@ bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef) bool32 IsBattlerItemEnabled(u32 battler) { - if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_NEGATE_UNAWARE) + if (gAiThinkingStruct->flags[battler] & AI_FLAG_NEGATE_UNAWARE) return TRUE; if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) return FALSE; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index ce95927c8e..c809fe641f 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -650,14 +650,14 @@ static void OpponentHandleChooseItem(u32 battler) static inline bool32 IsAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) { - return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_ACE_POKEMON + return gAiThinkingStruct->flags[battler] & AI_FLAG_ACE_POKEMON && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle; } static inline bool32 IsDoubleAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) { - return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON + return gAiThinkingStruct->flags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 2) && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle diff --git a/src/battle_debug.c b/src/battle_debug.c index e863e78181..e8307b3879 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -2199,8 +2199,8 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) data->modifyArrows.typeOfVal = VAL_BITFIELD_32; goto CASE_ITEM_STATUS; case LIST_ITEM_AI: - data->modifyArrows.modifiedValPtr = &gAiThinkingStruct->aiFlags[data->battlerId]; - data->modifyArrows.currValue = GetBitfieldValue(gAiThinkingStruct->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount); + data->modifyArrows.modifiedValPtr = &gAiThinkingStruct->flags[data->battlerId]; + data->modifyArrows.currValue = GetBitfieldValue(gAiThinkingStruct->flags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount); data->modifyArrows.typeOfVal = VAL_BITFIELD_32; goto CASE_ITEM_STATUS; CASE_ITEM_STATUS: diff --git a/src/debug.c b/src/debug.c index ad0cf449d4..cfdf8794b1 100644 --- a/src/debug.c +++ b/src/debug.c @@ -120,7 +120,7 @@ enum TimeMenuTimeOfDay DEBUG_TIME_MENU_ITEM_MORNING, DEBUG_TIME_MENU_ITEM_DAY, DEBUG_TIME_MENU_ITEM_EVENING, - DEBUG_TIME_MENU_ITEM_NIGHT, + DEBUG_TIME_MENU_ITEM_NIGHT, }; enum TimeMenuWeekdays @@ -3776,7 +3776,7 @@ static void DebugAction_Give_DayCareEgg(u8 taskId) static void DebugAction_TimeMenu_ChangeTimeOfDay(u8 taskId) { u32 input = ListMenu_ProcessInput(gTasks[taskId].tMenuTaskId); - + DebugAction_DestroyExtraWindow(taskId); switch (input) { @@ -3808,7 +3808,7 @@ static void DebugAction_TimeMenu_ChangeWeekdays(u8 taskId) { case DEBUG_TIME_MENU_ITEM_SUNDAY: daysToAdd = ((WEEKDAY_SUN - rtc->dayOfWeek) + WEEKDAY_COUNT) % WEEKDAY_COUNT; - FakeRtc_AdvanceTimeBy(daysToAdd, 0, 0, 0); + FakeRtc_AdvanceTimeBy(daysToAdd, 0, 0, 0); break; case DEBUG_TIME_MENU_ITEM_MONDAY: daysToAdd = ((WEEKDAY_MON - rtc->dayOfWeek) + WEEKDAY_COUNT) % WEEKDAY_COUNT; diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 0349b08ff0..8b8f97ce43 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -87,7 +87,7 @@ void RecordedBattle_Init(u8 mode) for (j = 0; j < BATTLER_RECORD_SIZE; j++) sBattleRecords[i][j] = 0xFF; sBattleFlags = gBattleTypeFlags; - sAI_Scripts = gAiThinkingStruct->aiFlags[B_POSITION_OPPONENT_LEFT]; + sAI_Scripts = gAiThinkingStruct->flags[B_POSITION_OPPONENT_LEFT]; } } } From d60aba377399dc204a79318fc9337bb734558543 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Fri, 9 May 2025 21:50:17 +0200 Subject: [PATCH 4/6] revert changelog changes --- docs/changelogs/1.6.x/1.6.0.md | 2 +- docs/changelogs/1.9.x/1.9.0.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelogs/1.6.x/1.6.0.md b/docs/changelogs/1.6.x/1.6.0.md index f391940205..f215ffb673 100644 --- a/docs/changelogs/1.6.x/1.6.0.md +++ b/docs/changelogs/1.6.x/1.6.0.md @@ -143,7 +143,7 @@ * Prevent certain status moves when item is known + Fake Out changes by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3219 * Improve AI switching with bad moves by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3213 * Fixed `CanTargetFaintAi` index issue by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/3306 -* Transform updates `gAiPartyData` data by @ghoulslash in https://github.com/rh-hideout/pokeemerald-expansion/pull/3295 +* Transform updates `AI_PARTY` data by @ghoulslash in https://github.com/rh-hideout/pokeemerald-expansion/pull/3295 * Greatly reduce AI lag by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3308 ### Cleanup diff --git a/docs/changelogs/1.9.x/1.9.0.md b/docs/changelogs/1.9.x/1.9.0.md index 44d5a8aec7..b0815c6e2a 100644 --- a/docs/changelogs/1.9.x/1.9.0.md +++ b/docs/changelogs/1.9.x/1.9.0.md @@ -510,7 +510,7 @@ * `AI_STRIKES_FIRST` is also replaced by `AI_IsFaster`. * Switch AI uses trapping abilities aggressively by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4669 * Use 9th roll instead of average in AI calcs by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4679 -* Use `gAiLogicData->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 +* Use `AI_DATA->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 * Minor switch AI cleanup by @Pawkkie, @DizzyEggg, @AlexOn1ine and @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4849 * Removed `SetBattlerData` from `AI_CalcDamage` by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4881 * Removed unused `AI_FLAG_HELP_PARTNER` by @pkmnsnfrn and @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4918 From 19e2bb82b5f6b6b10a1d6fd19e5c857e31a7b2fd Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Wed, 14 May 2025 23:34:43 +0200 Subject: [PATCH 5/6] clean up --- docs/changelogs/1.9.x/1.9.0.md | 2 +- include/config/debug.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelogs/1.9.x/1.9.0.md b/docs/changelogs/1.9.x/1.9.0.md index 44d5a8aec7..b0815c6e2a 100644 --- a/docs/changelogs/1.9.x/1.9.0.md +++ b/docs/changelogs/1.9.x/1.9.0.md @@ -510,7 +510,7 @@ * `AI_STRIKES_FIRST` is also replaced by `AI_IsFaster`. * Switch AI uses trapping abilities aggressively by @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4669 * Use 9th roll instead of average in AI calcs by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4679 -* Use `gAiLogicData->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 +* Use `AI_DATA->abilities` in more places by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4729 * Minor switch AI cleanup by @Pawkkie, @DizzyEggg, @AlexOn1ine and @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4849 * Removed `SetBattlerData` from `AI_CalcDamage` by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4881 * Removed unused `AI_FLAG_HELP_PARTNER` by @pkmnsnfrn and @Pawkkie in https://github.com/rh-hideout/pokeemerald-expansion/pull/4918 diff --git a/include/config/debug.h b/include/config/debug.h index 1542015e50..2446b9360c 100644 --- a/include/config/debug.h +++ b/include/config/debug.h @@ -9,7 +9,7 @@ // Battle Debug Menu #define DEBUG_BATTLE_MENU TRUE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. -#define DEBUG_AI_DELAY_TIMER TRUE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. +#define DEBUG_AI_DELAY_TIMER FALSE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. // Pokémon Debug #define DEBUG_POKEMON_SPRITE_VISUALIZER TRUE // Enables a debug menu for Pokémon sprites and icons, accessed by pressing Select in the summary screen. From 56c9549bbe0b968d244b43274e5a0d4c9b30c0a9 Mon Sep 17 00:00:00 2001 From: AlexOn1ine Date: Wed, 14 May 2025 23:45:31 +0200 Subject: [PATCH 6/6] fix test --- test/battle/ai/ai.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 738b08aa9b..3f799d09ab 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -942,15 +942,15 @@ SINGLE_BATTLE_TEST("AI correctly records used moves") TURN { MOVE(player, MOVE_TORCH_SONG); MOVE(opponent, MOVE_PSYCHIC); } TURN { MOVE(player, MOVE_GROWL); MOVE(opponent, MOVE_RAGE_FIST); } } THEN { - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][0], MOVE_TACKLE); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][1], MOVE_GROWL); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][2], MOVE_FLOWER_TRICK); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_PLAYER_LEFT][3], MOVE_TORCH_SONG); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][0], MOVE_TACKLE); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][1], MOVE_GROWL); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][2], MOVE_FLOWER_TRICK); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_PLAYER_LEFT][3], MOVE_TORCH_SONG); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][0], MOVE_RAGE_FIST); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][1], MOVE_PSYCHIC); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][2], MOVE_SCRATCH); - EXPECT_EQ(BATTLE_HISTORY->usedMoves[B_POSITION_OPPONENT_LEFT][3], MOVE_EARTHQUAKE); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][0], MOVE_RAGE_FIST); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][1], MOVE_PSYCHIC); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][2], MOVE_SCRATCH); + EXPECT_EQ(gBattleHistory->usedMoves[B_POSITION_OPPONENT_LEFT][3], MOVE_EARTHQUAKE); } }