Throw out unnecessary functions

This commit is contained in:
Pawkkie 2025-05-08 14:49:49 -04:00
parent 83b7732fae
commit b48d0c387d
5 changed files with 51 additions and 143 deletions

View File

@ -333,7 +333,7 @@ struct AiLogicData
u8 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack u8 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack
u8 predictingSwitch:1; // Determines whether AI will use switch predictions this turn or not u8 predictingSwitch:1; // Determines whether AI will use switch predictions this turn or not
u8 predictingMove:1; // Determines whether AI will use move predictions this turn or not u8 predictingMove:1; // Determines whether AI will use move predictions this turn or not
u8 aiSwitchPredictionInProgress:1; // Tracks whether the AI is in the middle of running prediction calculations u8 aiPredictionInProgress:1; // Tracks whether the AI is in the middle of running prediction calculations
u8 padding:2; u8 padding:2;
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
u8 aiCalcInProgress:1; u8 aiCalcInProgress:1;

View File

@ -240,5 +240,6 @@ bool32 IsBattlerItemEnabled(u32 battler);
bool32 IsBattlerPredictedToSwitch(u32 battler); bool32 IsBattlerPredictedToSwitch(u32 battler);
bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef); bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef);
bool32 HasBattlerSideAbility(u32 battlerDef, u32 ability, struct AiLogicData *aiData); bool32 HasBattlerSideAbility(u32 battlerDef, u32 ability, struct AiLogicData *aiData);
u32 GetThinkingBattler(u32 battler);
#endif //GUARD_BATTLE_AI_UTIL_H #endif //GUARD_BATTLE_AI_UTIL_H

View File

@ -32,11 +32,10 @@
#define AI_ACTION_WATCH (1 << 2) #define AI_ACTION_WATCH (1 << 2)
#define AI_ACTION_DO_NOT_ATTACK (1 << 3) #define AI_ACTION_DO_NOT_ATTACK (1 << 3)
static u32 ChooseMoveOrAction_Singles(u32 battlerAi); static u32 ChooseMoveOrAction_Singles(u32 battler);
static u32 ChooseMoveOrAction_Doubles(u32 battlerAi); static u32 ChooseMoveOrAction_Doubles(u32 battler);
static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef); static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battler, u32 battlerDef);
static inline void BattleAI_DoAIProcessing_PredictMove(struct AI_ThinkingStruct *aiThink, u32 battler, u32 opposingBattler); static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef);
static inline void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink, struct AiLogicData *aiData, u32 battlerAi, u32 battlerDef);
static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect); static bool32 IsPinchBerryItemEffect(enum ItemHoldEffect holdEffect);
// ewram // ewram
@ -308,16 +307,15 @@ bool32 BattlerChoseNonMoveAction(void)
void SetupAIPredictionData(u32 battler, enum SwitchType switchType) void SetupAIPredictionData(u32 battler, enum SwitchType switchType)
{ {
s32 opposingBattler = GetOppositeBattler(battler); s32 opposingBattler = GetOppositeBattler(battler);
AI_DATA->aiPredictionInProgress = TRUE;
AI_DATA->battlerDoingPrediction = battler;
// Switch prediction // Switch prediction
if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH)) 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); AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, switchType);
if (ShouldSwitch(opposingBattler)) if (ShouldSwitch(opposingBattler))
AI_DATA->shouldSwitch |= (1u << opposingBattler); AI_DATA->shouldSwitch |= (1u << opposingBattler);
AI_DATA->aiSwitchPredictionInProgress = FALSE;
gBattleStruct->prevTurnSpecies[opposingBattler] = gBattleMons[opposingBattler].species; gBattleStruct->prevTurnSpecies[opposingBattler] = gBattleMons[opposingBattler].species;
// Determine whether AI will use predictions this turn // Determine whether AI will use predictions this turn
@ -327,13 +325,14 @@ void SetupAIPredictionData(u32 battler, enum SwitchType switchType)
// Move prediction // Move prediction
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES) if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES)
{ {
AI_DATA->predictedMove[opposingBattler] = gBattleMons[opposingBattler].moves[BattleAI_PredictMove(battler, opposingBattler)]; AI_DATA->predictedMove[opposingBattler] = gBattleMons[opposingBattler].moves[BattleAI_ChooseMoveIndex(opposingBattler)];
DebugPrintf("Predicted move: %d", AI_DATA->predictedMove[opposingBattler]); DebugPrintf("Predicted move: %d", AI_DATA->predictedMove[opposingBattler]);
ModifySwitchAfterMoveScoring(opposingBattler); ModifySwitchAfterMoveScoring(opposingBattler);
// Determine whether AI will use predictions this turn // Determine whether AI will use predictions this turn
AI_DATA->predictingMove = RandomPercentage(RNG_AI_PREDICT_MOVE, PREDICT_MOVE_CHANCE); AI_DATA->predictingMove = RandomPercentage(RNG_AI_PREDICT_MOVE, PREDICT_MOVE_CHANCE);
} }
AI_DATA->aiPredictionInProgress = FALSE;
} }
void ComputeBattlerDecisions(u32 battler) void ComputeBattlerDecisions(u32 battler)
@ -640,77 +639,23 @@ static u32 PpStallReduction(u32 move, u32 battlerAtk)
return returnValue; return returnValue;
} }
u32 BattleAI_PredictMove(u32 battler, u32 opposingBattler) static u32 ChooseMoveOrAction_Singles(u32 battler)
{ {
u8 currentMoveArray[MAX_MON_MOVES]; u8 currentMoveArray[MAX_MON_MOVES];
u8 consideredMoveArray[MAX_MON_MOVES]; u8 consideredMoveArray[MAX_MON_MOVES];
u32 numOfBestMoves; u32 numOfBestMoves;
s32 i; s32 i;
u32 flags = AI_THINKING_STRUCT->aiFlags[battler]; u64 flags = AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)];
AI_DATA->partnerMove = 0; // no ally AI_DATA->partnerMove = 0; // no ally
while (flags != 0) while (flags != 0)
{ {
if (flags & 1) if (flags & 1)
{ {
BattleAI_DoAIProcessing_PredictMove(AI_THINKING_STRUCT, battler, opposingBattler); if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
} BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battler, gBattlerTarget);
flags >>= 1;
AI_THINKING_STRUCT->aiLogicId++;
}
for (i = 0; i < MAX_MON_MOVES; i++)
{
gAiBattleData->finalScore[opposingBattler][battler][i] = AI_THINKING_STRUCT->score[i];
DebugPrintf("Final score: %d", gAiBattleData->finalScore[opposingBattler][battler][i]);
}
numOfBestMoves = 1;
currentMoveArray[0] = AI_THINKING_STRUCT->score[0];
consideredMoveArray[0] = 0;
for (i = 1; i < MAX_MON_MOVES; i++)
{
if (gBattleMons[opposingBattler].moves[i] != MOVE_NONE)
{
// In ruby, the order of these if statements is reversed.
if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i])
{
currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i];
consideredMoveArray[numOfBestMoves++] = i;
}
if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i])
{
numOfBestMoves = 1;
currentMoveArray[0] = AI_THINKING_STRUCT->score[i];
consideredMoveArray[0] = i;
}
}
}
DebugPrintf("Number of best moves: %d", numOfBestMoves);
DebugPrintf("Random best move: %d", consideredMoveArray[Random() % numOfBestMoves]);
DebugPrintf("Random best move: %d", consideredMoveArray[Random() % numOfBestMoves]);
DebugPrintf("Random best move: %d", consideredMoveArray[Random() % numOfBestMoves]);
return consideredMoveArray[Random() % numOfBestMoves];
}
static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
{
u8 currentMoveArray[MAX_MON_MOVES];
u8 consideredMoveArray[MAX_MON_MOVES];
u32 numOfBestMoves;
s32 i;
u64 flags = AI_THINKING_STRUCT->aiFlags[battlerAi];
AI_DATA->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);
else else
BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battler, gBattlerTarget);
} }
flags >>= (u64)1; flags >>= (u64)1;
AI_THINKING_STRUCT->aiLogicId++; AI_THINKING_STRUCT->aiLogicId++;
@ -718,7 +663,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
for (i = 0; i < MAX_MON_MOVES; i++) for (i = 0; i < MAX_MON_MOVES; i++)
{ {
gAiBattleData->finalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i]; gAiBattleData->finalScore[battler][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i];
} }
numOfBestMoves = 1; numOfBestMoves = 1;
@ -727,7 +672,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
for (i = 1; i < MAX_MON_MOVES; i++) for (i = 1; i < MAX_MON_MOVES; i++)
{ {
if (gBattleMons[battlerAi].moves[i] != MOVE_NONE) if (gBattleMons[battler].moves[i] != MOVE_NONE)
{ {
// In ruby, the order of these if statements is reversed. // In ruby, the order of these if statements is reversed.
if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i])
@ -746,7 +691,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
return consideredMoveArray[Random() % numOfBestMoves]; return consideredMoveArray[Random() % numOfBestMoves];
} }
static u32 ChooseMoveOrAction_Doubles(u32 battlerAi) static u32 ChooseMoveOrAction_Doubles(u32 battler)
{ {
s32 i, j; s32 i, j;
u64 flags; u64 flags;
@ -761,7 +706,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
for (i = 0; i < MAX_BATTLERS_COUNT; i++) for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{ {
if (i == battlerAi || gBattleMons[i].hp == 0) if (i == battler || gBattleMons[i].hp == 0)
{ {
actionOrMoveIndex[i] = 0xFF; actionOrMoveIndex[i] = 0xFF;
bestMovePointsForTarget[i] = -1; bestMovePointsForTarget[i] = -1;
@ -769,25 +714,25 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
else else
{ {
if (gBattleTypeFlags & BATTLE_TYPE_PALACE) if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
BattleAI_SetupAIData(gBattleStruct->palaceFlags >> 4, battlerAi); BattleAI_SetupAIData(gBattleStruct->palaceFlags >> 4, battler);
else else
BattleAI_SetupAIData(0xF, battlerAi); BattleAI_SetupAIData(0xF, battler);
gBattlerTarget = i; gBattlerTarget = i;
AI_DATA->partnerMove = GetAllyChosenMove(battlerAi); AI_DATA->partnerMove = GetAllyChosenMove(battler);
AI_THINKING_STRUCT->aiLogicId = 0; AI_THINKING_STRUCT->aiLogicId = 0;
AI_THINKING_STRUCT->movesetIndex = 0; AI_THINKING_STRUCT->movesetIndex = 0;
flags = AI_THINKING_STRUCT->aiFlags[battlerAi]; flags = AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)];
while (flags != 0) while (flags != 0)
{ {
if (flags & 1) if (flags & 1)
{ {
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battlerAi] & AI_FLAG_PREDICT_INCOMING_MON)) if (IsBattlerPredictedToSwitch(gBattlerTarget) && (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battlerAi, gBattlerTarget); BattleAI_DoAIProcessing_PredictedSwitchin(AI_THINKING_STRUCT, AI_DATA, battler, gBattlerTarget);
else else
BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battlerAi, gBattlerTarget); BattleAI_DoAIProcessing(AI_THINKING_STRUCT, battler, gBattlerTarget);
} }
flags >>= (u64)1; flags >>= (u64)1;
AI_THINKING_STRUCT->aiLogicId++; AI_THINKING_STRUCT->aiLogicId++;
@ -798,9 +743,9 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
mostViableMovesNo = 1; mostViableMovesNo = 1;
for (j = 1; j < MAX_MON_MOVES; j++) for (j = 1; j < MAX_MON_MOVES; j++)
{ {
if (gBattleMons[battlerAi].moves[j] != 0) if (gBattleMons[battler].moves[j] != 0)
{ {
if (!CanTargetBattler(battlerAi, i, gBattleMons[battlerAi].moves[j])) if (!CanTargetBattler(battler, i, gBattleMons[battler].moves[j]))
continue; continue;
if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j]) if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j])
@ -821,14 +766,14 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
bestMovePointsForTarget[i] = mostViableMovesScores[0]; bestMovePointsForTarget[i] = mostViableMovesScores[0];
// Don't use a move against ally if it has less than 100 points. // Don't use a move against ally if it has less than 100 points.
if (i == BATTLE_PARTNER(battlerAi) && bestMovePointsForTarget[i] < AI_SCORE_DEFAULT) if (i == BATTLE_PARTNER(battler) && bestMovePointsForTarget[i] < AI_SCORE_DEFAULT)
{ {
bestMovePointsForTarget[i] = -1; bestMovePointsForTarget[i] = -1;
} }
for (j = 0; j < MAX_MON_MOVES; j++) for (j = 0; j < MAX_MON_MOVES; j++)
{ {
gAiBattleData->finalScore[battlerAi][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j]; gAiBattleData->finalScore[battler][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j];
} }
} }
} }
@ -853,7 +798,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
} }
gBattlerTarget = mostViableTargetsArray[Random() % mostViableTargetsNo]; gBattlerTarget = mostViableTargetsArray[Random() % mostViableTargetsNo];
gAiBattleData->chosenTarget[battlerAi] = gBattlerTarget; gAiBattleData->chosenTarget[battler] = gBattlerTarget;
return actionOrMoveIndex[gBattlerTarget]; return actionOrMoveIndex[gBattlerTarget];
} }
@ -868,64 +813,26 @@ static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef,
return TRUE; return TRUE;
} }
static inline void BattleAI_DoAIProcessing_PredictMove(struct AI_ThinkingStruct *aiThink, u32 battler, u32 opposingBattler) static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battler, u32 battlerDef)
{ {
do do
{ {
if (gBattleMons[opposingBattler].pp[aiThink->movesetIndex] == 0) if (gBattleMons[battler].pp[aiThink->movesetIndex] == 0)
aiThink->moveConsidered = MOVE_NONE; aiThink->moveConsidered = MOVE_NONE;
else else
aiThink->moveConsidered = gBattleMons[opposingBattler].moves[aiThink->movesetIndex]; aiThink->moveConsidered = gBattleMons[battler].moves[aiThink->movesetIndex];
DebugPrintf("Move considered: %d", aiThink->moveConsidered);
// There is no point in calculating scores for all 3 battlers(2 opponents + 1 ally) with certain moves. // There is no point in calculating scores for all 3 battlers(2 opponents + 1 ally) with certain moves.
if (aiThink->moveConsidered != MOVE_NONE if (aiThink->moveConsidered != MOVE_NONE
&& aiThink->score[aiThink->movesetIndex] > 0 && aiThink->score[aiThink->movesetIndex] > 0
&& ShouldConsiderMoveForBattler(opposingBattler, battler, aiThink->moveConsidered)) && ShouldConsiderMoveForBattler(battler, battlerDef, aiThink->moveConsidered))
{ {
if (aiThink->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable) if (aiThink->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable)
&& sBattleAiFuncTable[aiThink->aiLogicId] != NULL) && sBattleAiFuncTable[aiThink->aiLogicId] != NULL)
{ {
// Call AI function // Call AI function
aiThink->score[aiThink->movesetIndex] = aiThink->score[aiThink->movesetIndex] =
sBattleAiFuncTable[aiThink->aiLogicId](opposingBattler, sBattleAiFuncTable[aiThink->aiLogicId](battler,
battler,
aiThink->moveConsidered,
aiThink->score[aiThink->movesetIndex]);
DebugPrintf("Current score: %d", aiThink->score[aiThink->movesetIndex]);
}
}
else
{
aiThink->score[aiThink->movesetIndex] = 0;
}
aiThink->movesetIndex++;
} while (aiThink->movesetIndex < MAX_MON_MOVES);
aiThink->movesetIndex = 0;
}
static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, u32 battlerDef)
{
do
{
if (gBattleMons[battlerAi].pp[aiThink->movesetIndex] == 0)
aiThink->moveConsidered = MOVE_NONE;
else
aiThink->moveConsidered = gBattleMons[battlerAi].moves[aiThink->movesetIndex];
// There is no point in calculating scores for all 3 battlers(2 opponents + 1 ally) with certain moves.
if (aiThink->moveConsidered != MOVE_NONE
&& aiThink->score[aiThink->movesetIndex] > 0
&& ShouldConsiderMoveForBattler(battlerAi, battlerDef, aiThink->moveConsidered))
{
if (aiThink->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable)
&& sBattleAiFuncTable[aiThink->aiLogicId] != NULL)
{
// Call AI function
aiThink->score[aiThink->movesetIndex] =
sBattleAiFuncTable[aiThink->aiLogicId](battlerAi,
battlerDef, battlerDef,
aiThink->moveConsidered, aiThink->moveConsidered,
aiThink->score[aiThink->movesetIndex]); aiThink->score[aiThink->movesetIndex]);

View File

@ -108,13 +108,6 @@ u32 GetSwitchChance(enum ShouldSwitchScenario shouldSwitchScenario)
} }
} }
u32 GetThinkingBattler(u32 battler)
{
if (AI_DATA->aiSwitchPredictionInProgress)
return AI_DATA->battlerDoingPrediction;
return battler;
}
static bool32 IsAceMon(u32 battler, u32 monPartyId) static bool32 IsAceMon(u32 battler, u32 monPartyId)
{ {
if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON
@ -295,7 +288,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4))) && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4)))
{ {
// 50% chance to stay in regardless // 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))) && !AI_DATA->aiPredictionInProgress)
return FALSE; return FALSE;
// Switch mon out // Switch mon out
@ -315,7 +308,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
return FALSE; return FALSE;
// 50% chance to stay in regardless // 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))) && !AI_DATA->aiPredictionInProgress)
return FALSE; return FALSE;
// Switch mon out // Switch mon out
@ -465,7 +458,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
return FALSE; return FALSE;
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species && !(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES)) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species && !(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES)) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE
return FALSE; 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) || AI_DATA->aiPredictionInProgress))
return FALSE; return FALSE;
if (AreStatsRaised(battler)) if (AreStatsRaised(battler))
return FALSE; return FALSE;
@ -898,7 +891,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc
if (move == 0) if (move == 0)
continue; 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) || AI_DATA->aiPredictionInProgress))
return SetSwitchinAndSwitch(battler, i); return SetSwitchinAndSwitch(battler, i);
} }
} }
@ -990,7 +983,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
return FALSE; return FALSE;
// Switch out 50% of the time otherwise // 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)) || AI_DATA->aiPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
return SetSwitchinAndSwitch(battler, PARTY_SIZE); return SetSwitchinAndSwitch(battler, PARTY_SIZE);
return FALSE; return FALSE;
@ -1036,7 +1029,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
// 50% chance if attack at -2 and have a good candidate mon // 50% chance if attack at -2 and have a good candidate mon
else if (attackingStage == DEFAULT_STAT_STAGE - 2) 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 (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiPredictionInProgress))
return SetSwitchinAndSwitch(battler, PARTY_SIZE); return SetSwitchinAndSwitch(battler, PARTY_SIZE);
} }
// If at -3 or worse, switch out regardless // If at -3 or worse, switch out regardless
@ -1053,7 +1046,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler)
// 50% chance if attack at -2 and have a good candidate mon // 50% chance if attack at -2 and have a good candidate mon
else if (spAttackingStage == DEFAULT_STAT_STAGE - 2) 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 (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, GetSwitchChance(SHOULD_SWITCH_ATTACKING_STAT_MINUS_TWO)) || AI_DATA->aiPredictionInProgress))
return SetSwitchinAndSwitch(battler, PARTY_SIZE); return SetSwitchinAndSwitch(battler, PARTY_SIZE);
} }
// If at -3 or worse, switch out regardless // If at -3 or worse, switch out regardless

View File

@ -4517,3 +4517,10 @@ bool32 HasBattlerSideAbility(u32 battler, u32 ability, struct AiLogicData *aiDat
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
u32 GetThinkingBattler(u32 battler)
{
if (AI_DATA->aiPredictionInProgress)
return AI_DATA->battlerDoingPrediction;
return battler;
}