Improve AI's setup logic (#7345)

This commit is contained in:
Pawkkie 2025-07-16 17:05:08 -04:00 committed by GitHub
parent 64f9d6a24e
commit 0406caa687
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 79 additions and 0 deletions

View File

@ -1443,6 +1443,26 @@ bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits)
return FALSE;
}
// Can battler KO the target ignoring any Endure effects (Sturdy, Focus Sash, etc.)
bool32 CanBattlerKOTargetIgnoringSturdy(u32 battlerAtk, u32 battlerDef)
{
struct AiLogicData *aiData = gAiLogicData;
s32 moveIndex, dmg;
u16 *moves = GetMovesArray(battlerAtk);
u32 moveLimitations = aiData->moveLimitations[battlerAtk];
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
{
if (IsMoveUnusable(moveIndex, moves[moveIndex], moveLimitations))
continue;
dmg = AI_GetDamage(battlerAtk, battlerDef, moveIndex, AI_ATTACKING, aiData);
if (gBattleMons[battlerDef].hp <= dmg && CanEndureHit(battlerAtk, battlerDef, moves[moveIndex]))
return TRUE;
}
return FALSE;
}
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits)
{
u32 indexSlot = GetMoveSlot(GetMovesArray(battlerDef), move);
@ -4220,6 +4240,35 @@ bool32 IsRecycleEncouragedItem(u32 item)
return FALSE;
}
bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint, u32 aiIsFaster)
{
s32 i;
u16 *moves = GetMovesArray(battlerId);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] == MOVE_NONE || moves[i] == MOVE_UNAVAILABLE)
continue;
if (noOfHitsToFaint <= 2)
{
if (GetMovePriority(moves[i]) > 0)
return TRUE;
switch (gMovesInfo[moves[i]].additionalEffects[i].moveEffect)
{
case MOVE_EFFECT_SPD_MINUS_1:
case MOVE_EFFECT_SPD_MINUS_2:
{
if(aiIsFaster)
return TRUE;
}
}
}
}
return FALSE;
}
static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, enum StatChange statId, bool32 considerContrary)
{
enum AIScore tempScore = NO_INCREASE;
@ -4268,6 +4317,14 @@ static enum AIScore IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef,
|| HasBattlerSideMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_HAZE)))
return NO_INCREASE;
// Don't increase stats if AI could KO target through Sturdy effect, as otherwise it always 2HKOs
if (CanBattlerKOTargetIgnoringSturdy(battlerAtk, battlerDef))
return NO_INCREASE;
// Don't increase stats if player has a move that can change the KO threshold
if (HasMoveThatChangesKOThreshold(battlerDef, noOfHitsToFaint, aiIsFaster))
return NO_INCREASE;
// Predicting switch
if (IsBattlerPredictedToSwitch(battlerDef))
{

View File

@ -923,3 +923,25 @@ AI_SINGLE_BATTLE_TEST("AI will prefer resisted move over failing move")
TURN { MOVE(player, MOVE_ABSORB); EXPECT_MOVE(opponent, MOVE_MEGA_DRAIN);}
}
}
AI_SINGLE_BATTLE_TEST("AI won't setup if it can KO through Sturdy effect")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_SKARMORY) { Ability(ABILITY_STURDY); Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_MOLTRES) { Moves(MOVE_FIRE_BLAST, MOVE_AGILITY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_FIRE_BLAST); }
}
}
AI_SINGLE_BATTLE_TEST("AI won't setup if otherwise good scenario is changed by the presence of priority")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_FLOATZEL) { Speed(2); Moves(MOVE_AQUA_JET, MOVE_SURF); }
OPPONENT(SPECIES_DONPHAN) { Speed(5); Moves(MOVE_BULK_UP, MOVE_EARTHQUAKE); }
} WHEN {
TURN { MOVE(player, MOVE_SURF); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); }
}
}