From 55f9f6adead0e74eccf3291f7140ac099ceaa908 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Wed, 30 Apr 2025 17:54:42 +0200 Subject: [PATCH] Refactor battler flee and watch options + clean up (#6724) --- include/battle.h | 5 +- include/battle_ai_main.h | 8 +- src/battle_ai_main.c | 144 ++++++++++++++++--------- src/battle_ai_switch_items.c | 4 +- src/battle_ai_util.c | 6 +- src/battle_controller_opponent.c | 87 ++++++++------- src/battle_controller_player_partner.c | 12 +-- src/battle_gfx_sfx_util.c | 26 ++--- src/battle_main.c | 43 +------- 9 files changed, 169 insertions(+), 166 deletions(-) diff --git a/include/battle.h b/include/battle.h index 65fad63651..0d3cc543f0 100644 --- a/include/battle.h +++ b/include/battle.h @@ -816,8 +816,11 @@ struct BattleStruct struct AiBattleData { s32 finalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier - u8 moveOrAction[MAX_BATTLERS_COUNT]; + u8 chosenMoveIndex[MAX_BATTLERS_COUNT]; u8 chosenTarget[MAX_BATTLERS_COUNT]; + u8 actionFlee:1; + u8 choiceWatch:1; + u8 padding:6; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index ada512dba8..a385d7ce21 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -6,11 +6,6 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32); #define UNKNOWN_NO_OF_HITS UINT32_MAX -// return vals for BattleAI_ChooseMoveOrAction -// 0 - 3 are move idx -#define AI_CHOICE_FLEE 4 -#define AI_CHOICE_WATCH 5 - // for AI_WhoStrikesFirst #define AI_IS_FASTER 1 #define AI_IS_SLOWER -1 @@ -114,7 +109,8 @@ enum AIScore void BattleAI_SetupItems(void); void BattleAI_SetupFlags(void); void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler); -u32 BattleAI_ChooseMoveOrAction(u32 battler); +void ComputeBattlerDecisions(u32 battler); +u32 BattleAI_ChooseMoveIndex(u32 battler); void Ai_InitPartyStruct(void); void Ai_UpdateSwitchInData(u32 battler); void Ai_UpdateFaintData(u32 battler); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 6dd43982be..8acfe60858 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -265,14 +265,78 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) gAiBattleData->chosenTarget[battler] = gBattlerTarget; } -u32 BattleAI_ChooseMoveOrAction(u32 battler) +bool32 BattlerChoseNonMoveAction(void) { - u32 ret; + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + { + gAiBattleData->actionFlee = TRUE; + return TRUE; + } + + if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) + { + gAiBattleData->choiceWatch = TRUE; + return TRUE; + } + + return FALSE; +} + +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)) + { + AI_DATA->aiSwitchPredictionInProgress = TRUE; + AI_DATA->battlerDoingPrediction = battler; + AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType); + if (ShouldSwitch(opposingBattler)) + AI_DATA->shouldSwitch |= (1u << opposingBattler); + AI_DATA->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); + } + + // AI's data + AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType); + if (ShouldSwitch(battler)) + AI_DATA->shouldSwitch |= (1u << battler); + gBattleStruct->prevTurnSpecies[battler] = gBattleMons[battler].species; +} + +void ComputeBattlerDecisions(u32 battler) +{ + if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) + && (BattlerHasAi(battler) + && !(gBattleTypeFlags & BATTLE_TYPE_PALACE))) + { + // If ai is about to flee or chosen to watch player, no need to calc anything + if (BattlerChoseNonMoveAction()) + 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; + + AI_DATA->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; + } +} + +u32 BattleAI_ChooseMoveIndex(u32 battler) +{ + u32 chosenMoveIndex; if (!IsDoubleBattle()) - ret = ChooseMoveOrAction_Singles(battler); + chosenMoveIndex = ChooseMoveOrAction_Singles(battler); else - ret = ChooseMoveOrAction_Doubles(battler); + chosenMoveIndex = ChooseMoveOrAction_Doubles(battler); // Clear protect structures, some flags may be set during AI calcs // e.g. pranksterElevated from GetBattleMovePriority @@ -280,7 +344,8 @@ u32 BattleAI_ChooseMoveOrAction(u32 battler) #if TESTING TestRunner_Battle_CheckAiMoveScores(battler); #endif // TESTING - return ret; + + return chosenMoveIndex; } static void CopyBattlerDataToAIParty(u32 bPosition, u32 side) @@ -516,12 +581,6 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi) gAiBattleData->finalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i]; } - // Check special AI actions. - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) - return AI_CHOICE_FLEE; - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) - return AI_CHOICE_WATCH; - numOfBestMoves = 1; currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; consideredMoveArray[0] = 0; @@ -594,48 +653,37 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) AI_THINKING_STRUCT->aiLogicId++; } - if (AI_THINKING_STRUCT->aiAction & AI_ACTION_FLEE) + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; + mostViableMovesIndices[0] = 0; + mostViableMovesNo = 1; + for (j = 1; j < MAX_MON_MOVES; j++) { - actionOrMoveIndex[i] = AI_CHOICE_FLEE; - } - else if (AI_THINKING_STRUCT->aiAction & AI_ACTION_WATCH) - { - actionOrMoveIndex[i] = AI_CHOICE_WATCH; - } - else - { - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[0]; - mostViableMovesIndices[0] = 0; - mostViableMovesNo = 1; - for (j = 1; j < MAX_MON_MOVES; j++) + if (gBattleMons[battlerAi].moves[j] != 0) { - if (gBattleMons[battlerAi].moves[j] != 0) - { - if (!CanTargetBattler(battlerAi, i, gBattleMons[battlerAi].moves[j])) - continue; + if (!CanTargetBattler(battlerAi, i, gBattleMons[battlerAi].moves[j])) + continue; - if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) - { - mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; - mostViableMovesIndices[mostViableMovesNo] = j; - mostViableMovesNo++; - } - if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) - { - mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; - mostViableMovesIndices[0] = j; - mostViableMovesNo = 1; - } + if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[mostViableMovesNo] = j; + mostViableMovesNo++; + } + if (mostViableMovesScores[0] < AI_THINKING_STRUCT->score[j]) + { + mostViableMovesScores[0] = AI_THINKING_STRUCT->score[j]; + mostViableMovesIndices[0] = j; + mostViableMovesNo = 1; } } - actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo]; - bestMovePointsForTarget[i] = mostViableMovesScores[0]; + } + actionOrMoveIndex[i] = mostViableMovesIndices[Random() % mostViableMovesNo]; + bestMovePointsForTarget[i] = mostViableMovesScores[0]; - // Don't use a move against ally if it has less than 100 points. - if (i == BATTLE_PARTNER(battlerAi) && bestMovePointsForTarget[i] < AI_SCORE_DEFAULT) - { - bestMovePointsForTarget[i] = -1; - } + // Don't use a move against ally if it has less than 100 points. + if (i == BATTLE_PARTNER(battlerAi) && bestMovePointsForTarget[i] < AI_SCORE_DEFAULT) + { + bestMovePointsForTarget[i] = -1; } for (j = 0; j < MAX_MON_MOVES; j++) @@ -862,7 +910,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) RETURN_SCORE_MINUS(20); // Don't setup into expected Focus Punch. Revisit alongside predictedMove with move prediction - if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS && moveEffect != EFFECT_SLEEP + if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS && moveEffect != EFFECT_SLEEP && GetMoveEffect(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)) == EFFECT_FOCUS_PUNCH && RandomPercentage(RNG_AI_STATUS_FOCUS_PUNCH, STATUS_MOVE_FOCUS_PUNCH_CHANCE)) { RETURN_SCORE_MINUS(20); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index f10cbdfd45..3a936a18f5 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -2232,11 +2232,11 @@ static bool32 AiExpectsToFaintPlayer(u32 battler) { u8 target = gAiBattleData->chosenTarget[battler]; - if (gAiBattleData->moveOrAction[battler] > 3) + if (gAiBattleData->actionFlee || gAiBattleData->choiceWatch) return FALSE; // AI not planning to use move if (GetBattlerSide(target) != GetBattlerSide(battler) - && CanIndexMoveFaintTarget(battler, target, gAiBattleData->moveOrAction[battler], AI_ATTACKING) + && CanIndexMoveFaintTarget(battler, target, gAiBattleData->chosenMoveIndex[battler], AI_ATTACKING) && AI_IsFaster(battler, target, GetAIChosenMove(battler))) { // We expect to faint the target and move first -> dont use an item diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 98ce0840e7..23b1a66e46 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -87,7 +87,7 @@ bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move) u32 GetAIChosenMove(u32 battlerId) { - return (gBattleMons[battlerId].moves[gAiBattleData->moveOrAction[battlerId]]); + return (gBattleMons[battlerId].moves[gAiBattleData->chosenMoveIndex[battlerId]]); } bool32 AI_RandLessThan(u32 val) @@ -3184,8 +3184,8 @@ bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef, u32 abilityDef) else { // Battler can be frostbitten and has move/ability that synergizes with being frostbitten - if (CanBeFrozen(battlerAtk, battlerDef, abilityDef) && - DoesBattlerBenefitFromAllVolatileStatus(battlerDef, abilityDef)) + if (CanBeFrozen(battlerAtk, battlerDef, abilityDef) + && DoesBattlerBenefitFromAllVolatileStatus(battlerDef, abilityDef)) { if (battlerAtk == battlerDef) // Targeting self return TRUE; diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 0a52d88064..654311c417 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -532,7 +532,7 @@ static void OpponentHandleChooseAction(u32 battler) static void OpponentHandleChooseMove(u32 battler) { - u8 chosenMoveId; + u32 chosenMoveIndex; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER) @@ -542,61 +542,58 @@ static void OpponentHandleChooseMove(u32 battler) { BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, ChooseMoveAndTargetInBattlePalace(battler)); } + else if (gAiBattleData->actionFlee) + { + gAiBattleData->actionFlee = FALSE; + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_RUN, 0); + } + else if (gAiBattleData->choiceWatch) + { + gAiBattleData->choiceWatch = FALSE; + BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SAFARI_WATCH_CAREFULLY, 0); + } else { - chosenMoveId = gAiBattleData->moveOrAction[battler]; + chosenMoveIndex = gAiBattleData->chosenMoveIndex[battler]; gBattlerTarget = gAiBattleData->chosenTarget[battler]; - switch (chosenMoveId) + + u32 chosenMove = moveInfo->moves[chosenMoveIndex]; + if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_USER) + gBattlerTarget = battler; + if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_BOTH) { - case AI_CHOICE_WATCH: - BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SAFARI_WATCH_CAREFULLY, 0); - break; - case AI_CHOICE_FLEE: - BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_RUN, 0); - break; - case 6: - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 15, gBattlerTarget); - break; - default: - { - u16 chosenMove = moveInfo->moves[chosenMoveId]; - if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_USER) - gBattlerTarget = battler; - if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_BOTH) - { - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); - if (gAbsentBattlerFlags & (1u << gBattlerTarget)) - gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); - } - // If opponent can and should use a gimmick (considering trainer data), do it - if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE - && !(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE - && !ShouldUseZMove(battler, gBattlerTarget, moveInfo->moves[chosenMoveId]))) - { - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_GIMMICK) | (gBattlerTarget << 8)); - } - else - { - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8)); - } - } - break; + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + if (gAbsentBattlerFlags & (1u << gBattlerTarget)) + gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + // If opponent can and should use a gimmick (considering trainer data), do it + if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE + && !(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE + && !ShouldUseZMove(battler, gBattlerTarget, moveInfo->moves[chosenMoveIndex]))) + { + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (RET_GIMMICK) | (gBattlerTarget << 8)); + } + else + { + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (gBattlerTarget << 8)); } } OpponentBufferExecCompleted(battler); } else // Wild pokemon - use random move { - u16 move; - u8 target; + u32 move; + u32 target; do { - chosenMoveId = Random() & 3; - move = moveInfo->moves[chosenMoveId]; + chosenMoveIndex = Random() & (MAX_MON_MOVES - 1); + move = moveInfo->moves[chosenMoveIndex]; } while (move == MOVE_NONE); if (GetBattlerMoveTargetType(battler, move) & MOVE_TARGET_USER) - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (battler << 8)); + { + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (battler << 8)); + } else if (IsDoubleBattle()) { do { @@ -629,17 +626,17 @@ static void OpponentHandleChooseMove(u32 battler) } } if (isPartnerEnemy && CanTargetBattler(battler, target, move)) - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(BATTLE_PARTNER(battler)) << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (GetBattlerAtPosition(BATTLE_PARTNER(battler)) << 8)); else - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (target << 8)); } else { - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (target << 8)); } } else - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8)); OpponentBufferExecCompleted(battler); } diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index b7c8560996..feb860a286 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -346,12 +346,12 @@ static void PlayerPartnerHandleChooseAction(u32 battler) static void PlayerPartnerHandleChooseMove(u32 battler) { - u8 chosenMoveId; + u32 chosenMoveIndex; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); - chosenMoveId = gAiBattleData->moveOrAction[battler]; + chosenMoveIndex = gAiBattleData->chosenMoveIndex[battler]; gBattlerTarget = gAiBattleData->chosenTarget[battler]; - u32 moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]); + u32 moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveIndex]); if (moveTarget & MOVE_TARGET_USER) gBattlerTarget = battler; @@ -364,13 +364,13 @@ static void PlayerPartnerHandleChooseMove(u32 battler) // If partner can and should use a gimmick (considering trainer data), do it if (gBattleStruct->gimmick.usableGimmick[battler] != GIMMICK_NONE && !(gBattleStruct->gimmick.usableGimmick[battler] == GIMMICK_Z_MOVE - && !ShouldUseZMove(battler, gBattlerTarget, moveInfo->moves[chosenMoveId]))) + && !ShouldUseZMove(battler, gBattlerTarget, moveInfo->moves[chosenMoveIndex]))) { - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_GIMMICK) | (gBattlerTarget << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (RET_GIMMICK) | (gBattlerTarget << 8)); } else { - BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8)); + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveIndex) | (gBattlerTarget << 8)); } PlayerPartnerBufferExecCompleted(battler); diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index d003399a9b..7e3d783b1b 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -146,7 +146,7 @@ void FreeBattleSpritesData(void) u16 ChooseMoveAndTargetInBattlePalace(u32 battler) { s32 i, var1, var2; - s32 chosenMoveId = -1; + s32 chosenMoveIndex = -1; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); u8 unusableMovesBits = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL); s32 percent = Random() % 100; @@ -199,15 +199,15 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler) gBattleStruct->palaceFlags &= (1 << MAX_BATTLERS_COUNT) - 1; gBattleStruct->palaceFlags |= (selectedMoves << MAX_BATTLERS_COUNT); BattleAI_SetupAIData(selectedMoves, battler); - chosenMoveId = BattleAI_ChooseMoveOrAction(battler); + chosenMoveIndex = BattleAI_ChooseMoveIndex(battler); } // If no moves matched the selected group, pick a new move from groups the Pokémon has // In this case the AI is not checked again, so the choice may be worse // If a move is chosen this way, there's a 50% chance that it will be unable to use it anyway - if (chosenMoveId == -1 || chosenMoveId >= MAX_MON_MOVES) + if (chosenMoveIndex == -1 || chosenMoveIndex >= MAX_MON_MOVES) { - chosenMoveId = -1; + chosenMoveIndex = -1; if (unusableMovesBits != ALL_MOVES_MASK) { numMovesPerGroup = 0, numMultipleMoveGroups = 0; @@ -254,8 +254,8 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler) { i = Random() % MAX_MON_MOVES; if (!((1u << i) & unusableMovesBits)) - chosenMoveId = i; - } while (chosenMoveId == -1); + chosenMoveIndex = i; + } while (chosenMoveIndex == -1); } else { @@ -280,8 +280,8 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler) { i = Random() % MAX_MON_MOVES; if (!((1u << i) & unusableMovesBits) && randSelectGroup == GetBattlePalaceMoveGroup(battler, moveInfo->moves[i])) - chosenMoveId = i; - } while (chosenMoveId == -1); + chosenMoveIndex = i; + } while (chosenMoveIndex == -1); } // Because the selected move was not from the Nature-chosen move group there's a 50% chance @@ -300,16 +300,16 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler) } } - moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]); + moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveIndex]); if (moveTarget & MOVE_TARGET_USER) - chosenMoveId |= (battler << 8); + chosenMoveIndex |= (battler << 8); else if (moveTarget == MOVE_TARGET_SELECTED) - chosenMoveId |= GetBattlePalaceTarget(battler); + chosenMoveIndex |= GetBattlePalaceTarget(battler); else - chosenMoveId |= (GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(battler))) << 8); + chosenMoveIndex |= (GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerSide(battler))) << 8); - return chosenMoveId; + return chosenMoveIndex; } #undef maxGroupNum diff --git a/src/battle_main.c b/src/battle_main.c index c69a408084..d049dbb370 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4126,32 +4126,6 @@ enum STATE_SELECTION_SCRIPT_MAY_RUN }; -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)) - { - AI_DATA->aiSwitchPredictionInProgress = TRUE; - AI_DATA->battlerDoingPrediction = battler; - AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType); - if (ShouldSwitch(opposingBattler)) - AI_DATA->shouldSwitch |= (1u << opposingBattler); - AI_DATA->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); - } - - // AI's data - AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, switchType); - if (ShouldSwitch(battler)) - AI_DATA->shouldSwitch |= (1u << battler); - gBattleStruct->prevTurnSpecies[battler] = gBattleMons[battler].species; -} - static void HandleTurnActionSelectionState(void) { s32 i, battler; @@ -4165,22 +4139,7 @@ static void HandleTurnActionSelectionState(void) case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn. RecordedBattle_CopyBattlerMoves(battler); gBattleCommunication[battler] = STATE_BEFORE_ACTION_CHOSEN; - enum SwitchType switchType = (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_RISKY) ? SWITCH_AFTER_KO : SWITCH_MID_BATTLE; // Risky AI switches aggressively even mid battle - - // Do AI score computations here so we can use them in AI_TrySwitchOrUseItem - if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) - && (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE))) - { - AI_DATA->aiCalcInProgress = TRUE; - - // Setup battler data - BattleAI_SetupAIData(0xF, battler); - SetupAISwitchingData(battler, switchType); - - // Do scoring - gAiBattleData->moveOrAction[battler] = BattleAI_ChooseMoveOrAction(battler); - AI_DATA->aiCalcInProgress = FALSE; - } + ComputeBattlerDecisions(battler); // Do AI score computations here so we can use them in AI_TrySwitchOrUseItem // fallthrough case STATE_BEFORE_ACTION_CHOSEN: // Choose an action. gBattleStruct->monToSwitchIntoId[battler] = PARTY_SIZE;