Fix AI_FLAG_PREDICT_MOVES scoring bug (#6867)

This commit is contained in:
Pawkkie 2025-05-15 13:53:51 -04:00 committed by GitHub
parent 39022f3e6a
commit 0ea1ebe8de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 23 additions and 10 deletions

View File

@ -358,7 +358,6 @@ void SetupAIPredictionData(u32 battler, enum SwitchType switchType)
if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_MOVE)
{
gAiLogicData->predictedMove[opposingBattler] = gBattleMons[opposingBattler].moves[BattleAI_ChooseMoveIndex(opposingBattler)];
DebugPrintf("Predicted move: %d", gAiLogicData->predictedMove[opposingBattler]);
ModifySwitchAfterMoveScoring(opposingBattler);
// Determine whether AI will use predictions this turn
@ -678,16 +677,17 @@ static u32 ChooseMoveOrAction_Singles(u32 battler)
u32 numOfBestMoves;
s32 i;
u64 flags = gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)];
u32 opposingBattler = GetOppositeBattler(battler);
gAiLogicData->partnerMove = 0; // no ally
while (flags != 0)
{
if (flags & 1)
{
if (IsBattlerPredictedToSwitch(gBattlerTarget) && (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battler, gBattlerTarget);
if (IsBattlerPredictedToSwitch(opposingBattler) && (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_PREDICT_INCOMING_MON))
BattleAI_DoAIProcessing_PredictedSwitchin(gAiThinkingStruct, gAiLogicData, battler, opposingBattler);
else
BattleAI_DoAIProcessing(gAiThinkingStruct, battler, gBattlerTarget);
BattleAI_DoAIProcessing(gAiThinkingStruct, battler, opposingBattler);
}
flags >>= (u64)1;
gAiThinkingStruct->aiLogicId++;
@ -695,7 +695,7 @@ static u32 ChooseMoveOrAction_Singles(u32 battler)
for (i = 0; i < MAX_MON_MOVES; i++)
{
gAiBattleData->finalScore[battler][gBattlerTarget][i] = gAiThinkingStruct->score[i];
gAiBattleData->finalScore[battler][opposingBattler][i] = gAiThinkingStruct->score[i];
}
numOfBestMoves = 1;
@ -1003,7 +1003,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
u32 i;
u32 weather;
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData);
u32 abilityAtk = aiData->abilities[battlerAtk];
u32 abilityDef = aiData->abilities[battlerDef];
s32 atkPriority = GetBattleMovePriority(battlerAtk, abilityAtk, move);
@ -2932,7 +2932,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
bool32 partnerProtecting = (partnerEffect == EFFECT_PROTECT);
bool32 attackerHasBadAbility = (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating < 0);
bool32 partnerHasBadAbility = (gAbilitiesInfo[atkPartnerAbility].aiRating < 0);
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData);
SetTypeBeforeUsingMove(move, battlerAtk);
moveType = GetBattleMoveType(move);
@ -3503,7 +3503,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
s32 score = 0;
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? gAiLogicData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData);
u32 predictedType = GetMoveType(predictedMove);
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
@ -5611,7 +5611,7 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
struct AiLogicData *aiData = gAiLogicData;
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex];
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_PREDICT_MOVE) && aiData->predictingMove) ? aiData->predictedMove[battlerDef] : aiData->lastUsedMove[battlerDef];
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData);
// Switch benefit
switch (moveEffect)

View File

@ -1142,7 +1142,7 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered)
u32 abilityAI = gAiLogicData->abilities[battlerAI];
u32 abilityPlayer = gAiLogicData->abilities[battler];
u32 predictedMove = ((gAiThinkingStruct->aiFlags[battlerAI] & AI_FLAG_PREDICT_MOVE) && gAiLogicData->predictingMove) ? gAiLogicData->predictedMove[battler] : gAiLogicData->lastUsedMove[battler];
u32 predictedMove = GetIncomingMove(battlerAI, battler, gAiLogicData);
s8 aiPriority = GetBattleMovePriority(battlerAI, abilityAI, moveConsidered);
s8 playerPriority = GetBattleMovePriority(battler, abilityPlayer, predictedMove);

View File

@ -14,3 +14,16 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_MOVE: AI will predict player's move")
TURN { MOVE(player, MOVE_SURF); EXPECT_SWITCH(opponent, 1); }
}
}
AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_MOVE: AI will still attack you when it should")
{
PASSES_RANDOMLY(PREDICT_MOVE_CHANCE, 100, RNG_AI_PREDICT_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) { Ability(ABILITY_WATER_ABSORB); Moves(MOVE_SURF, MOVE_TACKLE); }
OPPONENT(SPECIES_SCEPTILE) { Moves(MOVE_LEAF_BLADE); }
OPPONENT(SPECIES_RHYDON) { Ability(ABILITY_ROCK_HEAD); Moves(MOVE_EARTHQUAKE); }
} WHEN {
TURN { MOVE(player, MOVE_SURF); EXPECT_MOVE(opponent, MOVE_LEAF_BLADE); }
}
}