Optimization / Clean up of AI move usability (#6332)
This commit is contained in:
parent
6031bb2a78
commit
98a5fab898
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user