Initial attempt, doesn't see move effectiveness / damage
This commit is contained in:
parent
d7a6e0bea8
commit
11d26af7a8
@ -352,6 +352,7 @@ struct AiLogicData
|
||||
u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out
|
||||
u8 aiCalcInProgress:1;
|
||||
u8 battlerDoingPrediction; // Stores which battler is currently running its prediction calcs
|
||||
u16 predictedMove[MAX_BATTLERS_COUNT];
|
||||
};
|
||||
|
||||
struct AI_ThinkingStruct
|
||||
|
||||
@ -122,5 +122,6 @@ void Ai_UpdateSwitchInData(u32 battler);
|
||||
void Ai_UpdateFaintData(u32 battler);
|
||||
void SetAiLogicDataForTurn(struct AiLogicData *aiData);
|
||||
void ResetDynamicAiFunc(void);
|
||||
u32 BattleAI_PredictMove(u32 battler, u32 opposingBattler);
|
||||
|
||||
#endif // GUARD_BATTLE_AI_MAIN_H
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
// still has them in the ROM. This is because the developers forgot
|
||||
// to define NDEBUG before release, however this has been changed as
|
||||
// Ruby's actual debug build does not use the AGBPrint features.
|
||||
#define NDEBUG
|
||||
// #define NDEBUG
|
||||
|
||||
// To enable printf debugging, comment out "#define NDEBUG". This allows
|
||||
// the various AGBPrint functions to be used. (See include/gba/isagbprint.h).
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
static u32 ChooseMoveOrAction_Singles(u32 battlerAi);
|
||||
static u32 ChooseMoveOrAction_Doubles(u32 battlerAi);
|
||||
static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u32 battlerAi, 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 battlerAi, u32 battlerDef);
|
||||
static bool32 IsPinchBerryItemEffect(u32 holdEffect);
|
||||
|
||||
@ -239,6 +240,7 @@ void BattleAI_SetupFlags(void)
|
||||
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
{
|
||||
u32 moveLimitations, moveLimitationsTarget;
|
||||
u8 defaultScoreMovesTarget = defaultScoreMoves;
|
||||
u32 flags[MAX_BATTLERS_COUNT];
|
||||
u32 moveIndex;
|
||||
|
||||
@ -268,16 +270,19 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
|
||||
// Initialize move prediction scores
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES)
|
||||
{
|
||||
moveLimitationsTarget = AI_DATA->moveLimitations[gBattlerTarget];
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
moveLimitationsTarget = AI_DATA->moveLimitations[opposingBattler];
|
||||
|
||||
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
|
||||
{
|
||||
if (moveLimitations & (1u << moveIndex))
|
||||
SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, 0);
|
||||
if (defaultScoreMoves & 1)
|
||||
SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, AI_SCORE_DEFAULT);
|
||||
if (moveLimitationsTarget & (1u << moveIndex))
|
||||
SET_PREDICTED_SCORE(opposingBattler, moveIndex, 0);
|
||||
if (defaultScoreMovesTarget & 1)
|
||||
SET_PREDICTED_SCORE(opposingBattler, moveIndex, AI_SCORE_DEFAULT);
|
||||
else
|
||||
SET_PREDICTED_SCORE(gBattlerTarget, moveIndex, 0);
|
||||
SET_PREDICTED_SCORE(opposingBattler, moveIndex, 0);
|
||||
|
||||
defaultScoreMovesTarget >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -501,6 +506,56 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
|
||||
AI_DATA->aiCalcInProgress = FALSE;
|
||||
}
|
||||
|
||||
u32 BattleAI_PredictMove(u32 battler, u32 opposingBattler)
|
||||
{
|
||||
u8 currentMoveArray[MAX_MON_MOVES];
|
||||
u8 consideredMoveArray[MAX_MON_MOVES];
|
||||
u32 numOfBestMoves;
|
||||
s32 i;
|
||||
u32 flags = AI_THINKING_STRUCT->aiFlags[battler];
|
||||
|
||||
AI_DATA->partnerMove = 0; // no ally
|
||||
while (flags != 0)
|
||||
{
|
||||
if (flags & 1)
|
||||
{
|
||||
BattleAI_DoAIProcessing_PredictMove(AI_THINKING_STRUCT, battler, opposingBattler);
|
||||
}
|
||||
flags >>= 1;
|
||||
AI_THINKING_STRUCT->aiLogicId++;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
gAiBattleData->finalScore[opposingBattler][battler][i] = AI_THINKING_STRUCT->predictedScore[i][opposingBattler];
|
||||
DebugPrintf("Final score: %d", gAiBattleData->finalScore[opposingBattler][battler][i]);
|
||||
}
|
||||
|
||||
numOfBestMoves = 1;
|
||||
currentMoveArray[0] = AI_THINKING_STRUCT->predictedScore[0][opposingBattler];
|
||||
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->predictedScore[i][opposingBattler])
|
||||
{
|
||||
currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->predictedScore[i][opposingBattler];
|
||||
consideredMoveArray[numOfBestMoves++] = i;
|
||||
}
|
||||
if (currentMoveArray[0] < AI_THINKING_STRUCT->predictedScore[i][opposingBattler])
|
||||
{
|
||||
numOfBestMoves = 1;
|
||||
currentMoveArray[0] = AI_THINKING_STRUCT->predictedScore[i][opposingBattler];
|
||||
consideredMoveArray[0] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return consideredMoveArray[Random() % numOfBestMoves];
|
||||
}
|
||||
|
||||
static u32 ChooseMoveOrAction_Singles(u32 battlerAi)
|
||||
{
|
||||
u8 currentMoveArray[MAX_MON_MOVES];
|
||||
@ -692,6 +747,44 @@ static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void BattleAI_DoAIProcessing_PredictMove(struct AI_ThinkingStruct *aiThink, u32 battler, u32 opposingBattler)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (gBattleMons[opposingBattler].pp[aiThink->movesetIndex] == 0)
|
||||
aiThink->moveConsidered = MOVE_NONE;
|
||||
else
|
||||
aiThink->moveConsidered = gBattleMons[opposingBattler].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.
|
||||
if (aiThink->moveConsidered != MOVE_NONE
|
||||
&& aiThink->score[aiThink->movesetIndex] > 0
|
||||
&& ShouldConsiderMoveForBattler(opposingBattler, battler, aiThink->moveConsidered))
|
||||
{
|
||||
if (aiThink->aiLogicId < ARRAY_COUNT(sBattleAiFuncTable)
|
||||
&& sBattleAiFuncTable[aiThink->aiLogicId] != NULL)
|
||||
{
|
||||
// Call AI function
|
||||
aiThink->predictedScore[aiThink->movesetIndex][opposingBattler] =
|
||||
sBattleAiFuncTable[aiThink->aiLogicId](opposingBattler,
|
||||
battler,
|
||||
aiThink->moveConsidered,
|
||||
aiThink->predictedScore[aiThink->movesetIndex][opposingBattler]);
|
||||
DebugPrintf("Current score: %d", aiThink->predictedScore[aiThink->movesetIndex][opposingBattler]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aiThink->predictedScore[aiThink->movesetIndex][opposingBattler] = 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
|
||||
|
||||
@ -448,7 +448,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
struct Pokemon *party;
|
||||
u16 monAbility, aiMove;
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler];
|
||||
u32 incomingMove = (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES) ? AI_DATA->predictedMove[opposingBattler] : AI_DATA->lastUsedMove[opposingBattler];
|
||||
u32 incomingType = GetMoveType(incomingMove);
|
||||
u32 predictedMove = incomingMove; // Update for move prediction
|
||||
u32 predictedType = GetMoveType(predictedMove);
|
||||
|
||||
@ -4142,10 +4142,8 @@ enum
|
||||
STATE_SELECTION_SCRIPT_MAY_RUN
|
||||
};
|
||||
|
||||
void SetupAISwitchingData(u32 battler, enum SwitchType switchType)
|
||||
void SetupAISwitchingData(u32 battler, u32 opposingBattler, enum SwitchType switchType)
|
||||
{
|
||||
s32 opposingBattler = GetOppositeBattler(battler);
|
||||
|
||||
// AI's predicting data
|
||||
if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH))
|
||||
{
|
||||
@ -4188,10 +4186,17 @@ static void HandleTurnActionSelectionState(void)
|
||||
&& (BattlerHasAi(battler) && !(gBattleTypeFlags & BATTLE_TYPE_PALACE)))
|
||||
{
|
||||
AI_DATA->aiCalcInProgress = TRUE;
|
||||
u32 opposingBattler = GetOppositeBattler(battler);
|
||||
|
||||
// Setup battler data
|
||||
BattleAI_SetupAIData(0xF, battler);
|
||||
SetupAISwitchingData(battler, switchType);
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_MOVES)
|
||||
{
|
||||
AI_DATA->predictedMove[opposingBattler] = BattleAI_PredictMove(battler, opposingBattler);
|
||||
DebugPrintf("Predicted move: %d", AI_DATA->predictedMove[opposingBattler]);
|
||||
}
|
||||
|
||||
SetupAISwitchingData(battler, opposingBattler, switchType);
|
||||
|
||||
// Do scoring
|
||||
gAiBattleData->moveOrAction[battler] = BattleAI_ChooseMoveOrAction(battler);
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_MOVE: AI will predict player's move")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_MOVE);
|
||||
PLAYER(SPECIES_VAPOREON) { Moves(MOVE_SURF, MOVE_TACKLE); }
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_MOVES);
|
||||
PLAYER(SPECIES_VAPOREON) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_SURF, MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_NUMEL) { Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_VAPOREON) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_TACKLE); }
|
||||
} WHEN {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user