diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 678688dbc3..2cf314c00d 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -28,6 +28,13 @@ enum AIPivot SHOULD_PIVOT, }; +static inline bool32 IsMoveUnusable(u32 moveIndex, u32 move, u32 moveLimitations) +{ + return move == MOVE_NONE + || move == MOVE_UNAVAILABLE + || moveLimitations & 1u << moveIndex; +} + bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move); bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move); bool32 AI_RandLessThan(u32 val); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index a764cf14c2..c7bf1b1bb7 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -238,8 +238,7 @@ void BattleAI_SetupFlags(void) void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) { - s32 i; - u8 moveLimitations; + u32 moveLimitations; u32 flags[MAX_BATTLERS_COUNT]; // Clear AI data but preserve the flags. @@ -247,24 +246,19 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler) memset(AI_THINKING_STRUCT, 0, sizeof(struct AI_ThinkingStruct)); memcpy(&AI_THINKING_STRUCT->aiFlags[0], &flags[0], sizeof(u32) * MAX_BATTLERS_COUNT); - // Conditional score reset, unlike Ruby. - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (defaultScoreMoves & 1) - SET_SCORE(battler, i, AI_SCORE_DEFAULT); - else - SET_SCORE(battler, i, 0); - - defaultScoreMoves >>= 1; - } - moveLimitations = AI_DATA->moveLimitations[battler]; - // Ignore moves that aren't possible to use. - for (i = 0; i < MAX_MON_MOVES; i++) + // Conditional score reset, unlike Ruby. + for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if ((1u << i) & moveLimitations) - SET_SCORE(battler, i, 0); + if (moveLimitations & (1u << moveIndex)) + SET_SCORE(battler, moveIndex, 0); + if (defaultScoreMoves & 1) + SET_SCORE(battler, moveIndex, AI_SCORE_DEFAULT); + else + SET_SCORE(battler, moveIndex, 0); + + defaultScoreMoves >>= 1; } gBattlerTarget = SetRandomTarget(battler); @@ -414,6 +408,7 @@ static void CalcBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u { u32 moveIndex, move; u16 *moves = GetMovesArray(battlerAtk); + u32 moveLimitations = aiData->moveLimitations[battlerAtk]; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { @@ -421,14 +416,13 @@ static void CalcBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u uq4_12_t effectiveness = Q_4_12(0.0); move = moves[moveIndex]; - if (move != MOVE_NONE - && move != MOVE_UNAVAILABLE - //&& !IsBattleMoveStatus(move) /* we want to get effectiveness and accuracy of status moves */ - && !(aiData->moveLimitations[battlerAtk] & (1u << moveIndex))) - { - dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather); - aiData->moveAccuracy[battlerAtk][battlerDef][moveIndex] = Ai_SetMoveAccuracy(aiData, battlerAtk, battlerDef, move); - } + if (IsMoveUnusable(moveIndex, move, moveLimitations)) + continue; + + // Also get effectiveness of status moves + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather); + aiData->moveAccuracy[battlerAtk][battlerDef][moveIndex] = Ai_SetMoveAccuracy(aiData, battlerAtk, battlerDef, move); + aiData->simulatedDmg[battlerAtk][battlerDef][moveIndex] = dmg; aiData->effectiveness[battlerAtk][battlerDef][moveIndex] = effectiveness; } diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 1c2d0789cd..22da0d931b 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -415,15 +415,15 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category) { s32 i, moveType; u32 usable = 0; - u32 unusable = AI_DATA->moveLimitations[attacker]; u16 *moves = GetMovesArray(attacker); + u32 moveLimitations = AI_DATA->moveLimitations[attacker]; for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE - && moves[i] != MOVE_UNAVAILABLE - && GetBattleMoveCategory(moves[i]) == category - && !(unusable & (1u << i))) + if (IsMoveUnusable(i, moves[i], moveLimitations)) + continue; + + if (GetBattleMoveCategory(moves[i]) == category) { SetTypeBeforeUsingMove(moves[i], attacker); moveType = GetBattleMoveType(moves[i]); @@ -1231,18 +1231,19 @@ 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; s32 moveIndex; - u32 unusable = AI_DATA->moveLimitations[battlerDef]; u16 *moves = GetMovesArray(battlerDef); + u32 moveLimitations = aiData->moveLimitations[battlerDef]; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (moves[moveIndex] != MOVE_NONE && moves[moveIndex] != MOVE_UNAVAILABLE && !(unusable & (1u << moveIndex)) - && AI_GetDamage(battlerDef, battlerAtk, moveIndex, AI_DEFENDING, AI_DATA) >= gBattleMons[battlerAtk].hp + if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) + continue; + + if (AI_GetDamage(battlerDef, battlerAtk, moveIndex, AI_DEFENDING, aiData) >= gBattleMons[battlerAtk].hp && !CanEndureHit(battlerDef, battlerAtk, moves[moveIndex])) - { return TRUE; - } } return FALSE; @@ -1268,18 +1269,21 @@ u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk) u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcContext calcContext) { + struct AiLogicData *aiData = AI_DATA; u32 moveIndex; u32 move = 0; u32 bestDmg = 0; - u32 unusable = AI_DATA->moveLimitations[battlerAtk]; u16 *moves = GetMovesArray(battlerAtk); + u32 moveLimitations = aiData->moveLimitations[battlerAtk]; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (moves[moveIndex] != MOVE_NONE && moves[moveIndex] != MOVE_UNAVAILABLE && !(unusable & (1u << moveIndex)) - && bestDmg < AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, AI_DATA)) + if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) + continue; + + if (bestDmg < AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, aiData)) { - bestDmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, AI_DATA); + bestDmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, calcContext, aiData); move = moves[moveIndex]; } } @@ -1288,20 +1292,20 @@ u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef, enum DamageCalcCon u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget, enum DamageCalcContext calcContext) { + struct AiLogicData *aiData = AI_DATA; u32 moveIndex; u32 bestDmg = 0; - u32 unusable = AI_DATA->moveLimitations[battler]; u16 *moves = GetMovesArray(battler); + u32 moveLimitations = aiData->moveLimitations[battler]; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (moves[moveIndex] != MOVE_NONE - && moves[moveIndex] != MOVE_UNAVAILABLE - && !(unusable & (1u << moveIndex)) - && bestDmg < AI_GetDamage(battler, battlerTarget, moveIndex, calcContext, AI_DATA)) - { - bestDmg = AI_GetDamage(battler, battlerTarget, moveIndex, calcContext, AI_DATA); - } + if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) + continue; + + u32 damage = AI_GetDamage(battler, battlerTarget, moveIndex, calcContext, aiData); + if (bestDmg < damage) + bestDmg = damage; } return bestDmg; @@ -1311,28 +1315,28 @@ 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; s32 moveIndex, dmg; - u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u16 *moves = gBattleMons[battlerAtk].moves; + u32 moveLimitations = aiData->moveLimitations[battlerAtk]; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - if (moves[moveIndex] != MOVE_NONE && moves[moveIndex] != MOVE_UNAVAILABLE && !(moveLimitations & (1u << moveIndex))) + if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) + continue; + + dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_ATTACKING, aiData); + + if (numHits) + dmg *= numHits; + + if (gBattleMons[battlerDef].hp <= dmg) { - // Use the pre-calculated value in simulatedDmg instead of re-calculating it - dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_ATTACKING, AI_DATA); + if (numHits > 1) + return TRUE; - if (numHits) - dmg *= numHits; - - if (gBattleMons[battlerDef].hp <= dmg) - { - if (numHits > 1) - return TRUE; - - if (!CanEndureHit(battlerAtk, battlerDef, moves[moveIndex])) - return TRUE; - } + if (!CanEndureHit(battlerAtk, battlerDef, moves[moveIndex])) + return TRUE; } } @@ -1353,25 +1357,28 @@ 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; u32 moveIndex; - u32 unusable = AI_DATA->moveLimitations[battlerDef]; s32 dmg; - u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; + u16 *moves = GetMovesArray(battlerDef); u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod; + u32 moveLimitations = aiData->moveLimitations[battlerAtk]; if (hpCheck > gBattleMons[battlerAtk].maxHP) hpCheck = gBattleMons[battlerAtk].maxHP; for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++) { - dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_DEFENDING, AI_DATA); + if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations)) + continue; + + dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_DEFENDING, aiData); + if (dmgMod) dmg *= dmgMod; - if (moves[moveIndex] != MOVE_NONE && moves[moveIndex] != MOVE_UNAVAILABLE && !(unusable & (1u << moveIndex)) && dmg >= hpCheck) - { + if (dmg >= hpCheck) return TRUE; - } } return FALSE; @@ -2271,20 +2278,17 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] == MOVE_NONE || moves[i] == MOVE_UNAVAILABLE) + if (IsMoveUnusable(i, moves[i], moveLimitations)) continue; - if (!((1u << i) & moveLimitations)) - { - if (ignoreStatus && IsBattleMoveStatus(moves[i])) - continue; - else if ((!IsBattleMoveStatus(moves[i]) && GetMoveAccuracy(moves[i]) == 0) - || GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) - continue; + if (ignoreStatus && IsBattleMoveStatus(moves[i])) + continue; + else if ((!IsBattleMoveStatus(moves[i]) && GetMoveAccuracy(moves[i]) == 0) + || GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD)) + continue; - if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= accCheck) - return TRUE; - } + if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= accCheck) + return TRUE; } return FALSE; @@ -2292,20 +2296,17 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) { - u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u32 i; u16 *moves = GetMovesArray(battlerAtk); + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] == MOVE_NONE) - break; - if (!((1u << i) & moveLimitations)) - { - if (GetMoveEffect(moves[i]) == EFFECT_SLEEP - && AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85) - return TRUE; - } + if (IsMoveUnusable(i, moves[i], moveLimitations)) + continue; + + if (GetMoveEffect(moves[i]) == EFFECT_SLEEP && AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85) + return TRUE; } return FALSE; }