Moved some AI stuff out of the battlestruct (#6405)

Co-authored-by: Hedara <hedara90@gmail.com>
This commit is contained in:
hedara90 2025-03-11 21:23:02 +01:00 committed by GitHub
parent 4a1d08d760
commit 4e01ce6993
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 33 additions and 25 deletions

View File

@ -765,9 +765,6 @@ struct BattleStruct
u16 tracedAbility[MAX_BATTLERS_COUNT];
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell.
struct Illusion illusion[MAX_BATTLERS_COUNT];
s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
u8 aiMoveOrAction[MAX_BATTLERS_COUNT];
u8 aiChosenTarget[MAX_BATTLERS_COUNT];
u8 soulheartBattlerId;
u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles.
u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used.
@ -840,6 +837,13 @@ struct BattleStruct
u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card
};
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 chosenTarget[MAX_BATTLERS_COUNT];
};
// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
// and 1 flag per battler to indicate whether the battler is awake and at <= 50% HP (which affects move choice).
// The assert below is to ensure palaceFlags is large enough to store these flags without overlap.
@ -1155,6 +1159,7 @@ extern u8 gSentPokesToOpponent[2];
extern struct BattleEnigmaBerry gEnigmaBerries[MAX_BATTLERS_COUNT];
extern struct BattleScripting gBattleScripting;
extern struct BattleStruct *gBattleStruct;
extern struct AiBattleData *gAiBattleData;
extern u8 *gLinkBattleSendBuffer;
extern u8 *gLinkBattleRecvBuffer;
extern struct BattleResources *gBattleResources;

View File

@ -268,7 +268,7 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
}
gBattlerTarget = SetRandomTarget(battler);
gBattleStruct->aiChosenTarget[battler] = gBattlerTarget;
gAiBattleData->chosenTarget[battler] = gBattlerTarget;
}
u32 BattleAI_ChooseMoveOrAction(u32 battler)
@ -514,7 +514,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
for (i = 0; i < MAX_MON_MOVES; i++)
{
gBattleStruct->aiFinalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i];
gAiBattleData->finalScore[battlerAi][gBattlerTarget][i] = AI_THINKING_STRUCT->score[i];
}
// Check special AI actions.
@ -641,7 +641,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
for (j = 0; j < MAX_MON_MOVES; j++)
{
gBattleStruct->aiFinalScore[battlerAi][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j];
gAiBattleData->finalScore[battlerAi][gBattlerTarget][j] = AI_THINKING_STRUCT->score[j];
}
}
}
@ -666,7 +666,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
}
gBattlerTarget = mostViableTargetsArray[Random() % mostViableTargetsNo];
gBattleStruct->aiChosenTarget[battlerAi] = gBattlerTarget;
gAiBattleData->chosenTarget[battlerAi] = gBattlerTarget;
return actionOrMoveIndex[gBattlerTarget];
}

View File

@ -2201,13 +2201,13 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType)
static bool32 AiExpectsToFaintPlayer(u32 battler)
{
u8 target = gBattleStruct->aiChosenTarget[battler];
u8 target = gAiBattleData->chosenTarget[battler];
if (gBattleStruct->aiMoveOrAction[battler] > 3)
if (gAiBattleData->moveOrAction[battler] > 3)
return FALSE; // AI not planning to use move
if (GetBattlerSide(target) != GetBattlerSide(battler)
&& CanIndexMoveFaintTarget(battler, target, gBattleStruct->aiMoveOrAction[battler], AI_ATTACKING)
&& CanIndexMoveFaintTarget(battler, target, gAiBattleData->moveOrAction[battler], AI_ATTACKING)
&& AI_IsFaster(battler, target, GetAIChosenMove(battler)))
{
// We expect to faint the target and move first -> dont use an item

View File

@ -61,7 +61,7 @@ bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move)
u32 GetAIChosenMove(u32 battlerId)
{
return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]);
return (gBattleMons[battlerId].moves[gAiBattleData->moveOrAction[battlerId]]);
}
bool32 AI_RandLessThan(u32 val)

View File

@ -544,8 +544,8 @@ static void OpponentHandleChooseMove(u32 battler)
}
else
{
chosenMoveId = gBattleStruct->aiMoveOrAction[battler];
gBattlerTarget = gBattleStruct->aiChosenTarget[battler];
chosenMoveId = gAiBattleData->moveOrAction[battler];
gBattlerTarget = gAiBattleData->chosenTarget[battler];
switch (chosenMoveId)
{
case AI_CHOICE_WATCH:

View File

@ -2042,13 +2042,13 @@ static void PlayerHandleChooseAction(u32 battler)
u32 moveTarget = GetBattlerMoveTargetType(B_POSITION_PLAYER_RIGHT, move);
if (moveTarget == MOVE_TARGET_SELECTED)
{
if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_OPPONENT_LEFT)
if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_OPPONENT_LEFT)
StringAppend(gStringVar1, COMPOUND_STRING(" -{UP_ARROW}"));
else if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_OPPONENT_RIGHT)
else if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_OPPONENT_RIGHT)
StringAppend(gStringVar1, COMPOUND_STRING(" {UP_ARROW}-"));
else if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_LEFT)
else if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_LEFT)
StringAppend(gStringVar1, COMPOUND_STRING(" {DOWN_ARROW}-"));
else if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_RIGHT)
else if (gAiBattleData->chosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_RIGHT)
StringAppend(gStringVar1, COMPOUND_STRING(" {DOWN_ARROW}-"));
}
else if (moveTarget == MOVE_TARGET_BOTH)

View File

@ -349,8 +349,8 @@ static void PlayerPartnerHandleChooseMove(u32 battler)
u8 chosenMoveId;
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]);
chosenMoveId = gBattleStruct->aiMoveOrAction[battler];
gBattlerTarget = gBattleStruct->aiChosenTarget[battler];
chosenMoveId = gAiBattleData->moveOrAction[battler];
gBattlerTarget = gAiBattleData->chosenTarget[battler];
u32 moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]);
if (moveTarget & MOVE_TARGET_USER)

View File

@ -941,7 +941,7 @@ static void PutMovesPointsText(struct BattleDebugMenu *data)
continue;
battlerDef = gSprites[data->spriteIds.aiIconSpriteIds[j]].data[0];
ConvertIntToDecimalStringN(text,
gBattleStruct->aiFinalScore[data->aiBattlerId][battlerDef][i],
gAiBattleData->finalScore[data->aiBattlerId][battlerDef][i],
STR_CONV_MODE_RIGHT_ALIGN, 3);
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, text, 83 + count * 54, i * 15, 0, NULL);

View File

@ -207,6 +207,7 @@ 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 AiBattleData *gAiBattleData = NULL;
EWRAM_DATA u8 *gLinkBattleSendBuffer = NULL;
EWRAM_DATA u8 *gLinkBattleRecvBuffer = NULL;
EWRAM_DATA struct BattleResources *gBattleResources = NULL;
@ -4200,7 +4201,7 @@ static void HandleTurnActionSelectionState(void)
SetupAISwitchingData(battler, switchType);
// Do scoring
gBattleStruct->aiMoveOrAction[battler] = BattleAI_ChooseMoveOrAction(battler);
gAiBattleData->moveOrAction[battler] = BattleAI_ChooseMoveOrAction(battler);
AI_DATA->aiCalcInProgress = FALSE;
}
// fallthrough

View File

@ -18,6 +18,7 @@ void AllocateBattleResources(void)
InitTrainerHillBattleStruct();
gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));
gAiBattleData = AllocZeroed(sizeof(*gAiBattleData));
#if B_FLAG_SKY_BATTLE
gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE);
@ -55,6 +56,7 @@ void FreeBattleResources(void)
if (gBattleResources != NULL)
{
FREE_AND_SET_NULL(gBattleStruct);
FREE_AND_SET_NULL(gAiBattleData);
FREE_AND_SET_NULL(gBattleResources->secretBase);
FREE_AND_SET_NULL(gBattleResources->battleScriptsStack);

View File

@ -771,7 +771,7 @@ static u32 CountAiExpectMoves(struct ExpectedAIAction *expectedAction, u32 battl
if ((1u << i) & expectedAction->moveSlots)
{
if (printLog)
PrintAiMoveLog(battlerId, i, gBattleMons[battlerId].moves[i], gBattleStruct->aiFinalScore[battlerId][expectedAction->target][i]);
PrintAiMoveLog(battlerId, i, gBattleMons[battlerId].moves[i], gAiBattleData->finalScore[battlerId][expectedAction->target][i]);
countExpected++;
}
}
@ -830,7 +830,7 @@ void TestRunner_Battle_CheckChosenMove(u32 battlerId, u32 moveId, u32 target)
if (!expectedAction->notMove && !movePasses)
{
u32 moveSlot = GetMoveSlot(gBattleMons[battlerId].moves, moveId);
PrintAiMoveLog(battlerId, moveSlot, moveId, gBattleStruct->aiFinalScore[battlerId][expectedAction->target][moveSlot]);
PrintAiMoveLog(battlerId, moveSlot, moveId, gAiBattleData->finalScore[battlerId][expectedAction->target][moveSlot]);
if (countExpected > 1)
Test_ExitWithResult(TEST_RESULT_FAIL, SourceLine(0), ":L%s:%d: Unmatched EXPECT_MOVES %S, got %S", filename, expectedAction->sourceLine, GetMoveName(expectedMoveId), GetMoveName(moveId));
else
@ -904,7 +904,7 @@ static const char *const sCmpToStringTable[] =
static void CheckIfMaxScoreEqualExpectMove(u32 battlerId, s32 target, struct ExpectedAIAction *aiAction, const char *filename)
{
u32 i;
s32 *scores = gBattleStruct->aiFinalScore[battlerId][target];
s32 *scores = gAiBattleData->finalScore[battlerId][target];
s32 bestScore = 0, bestScoreId = 0;
u16 *moves = gBattleMons[battlerId].moves;
for (i = 0; i < MAX_MON_MOVES; i++)
@ -1006,7 +1006,7 @@ void TestRunner_Battle_CheckAiMoveScores(u32 battlerId)
{
u32 moveId1 = gBattleMons[battlerId].moves[scoreCtx->moveSlot1];
s32 target = scoreCtx->target;
s32 *scores = gBattleStruct->aiFinalScore[battlerId][target];
s32 *scores = gAiBattleData->finalScore[battlerId][target];
if (scoreCtx->toValue)
{