Fix AI hazard move handling, minor AI tweaks (#6311)

This commit is contained in:
Pawkkie 2025-02-21 03:58:14 -05:00 committed by GitHub
parent fe7ed22f5b
commit bf263efa4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 83 additions and 17 deletions

View File

@ -127,7 +127,7 @@ bool32 IsAromaVeilProtectedEffect(u32 moveEffect);
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMoveEffect(u32 moveEffect);
bool32 IsHazardMove(u32 move);
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move);
void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score);
bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect);
@ -154,6 +154,7 @@ bool32 HasSubstituteIgnoringMove(u32 battler);
bool32 HasHighCritRatioMove(u32 battler);
bool32 HasMagicCoatAffectedMove(u32 battler);
bool32 HasSnatchAffectedMove(u32 battler);
bool32 IsHazardClearingMove(u32 move);
// status checks
bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
@ -217,5 +218,6 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData);
void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
bool32 IsBattlerPredictedToSwitch(u32 battler);
bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef);
#endif //GUARD_BATTLE_AI_UTIL_H

View File

@ -44,7 +44,7 @@
#define SHOULD_SWITCH_REGENERATOR_STATS_RAISED_PERCENTAGE 20
// AI held item-based move scoring
#define BLUNDER_POLICY_ACCURACY_THRESHOLD 75 // Moves with accuracy equal below this value are prioritized when holding Blunder Policy
#define LOW_ACCURACY_THRESHOLD 75 // Moves with accuracy equal OR below this value are considered low accuracy
// AI prediction chances
#define PREDICT_SWITCH_CHANCE 50

View File

@ -2112,7 +2112,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (isDoubleBattle)
{
if (IsHazardMoveEffect(GetMoveEffect(aiData->partnerMove)) // partner is going to set up hazards
if (IsHazardMove(aiData->partnerMove) // partner is going to set up hazards
&& AI_IsFaster(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove)) // partner is going to set up before the potential Defog
{
ADJUST_SCORE(-10);
@ -3308,7 +3308,7 @@ static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
{
u32 moveAcc = aiData->moveAccuracy[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
if (moveAcc <= BLUNDER_POLICY_ACCURACY_THRESHOLD)
if (moveAcc <= LOW_ACCURACY_THRESHOLD)
{
ADJUST_SCORE(GOOD_EFFECT);
}
@ -4015,7 +4015,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
{
if (isDoubleBattle)
{
if (IsHazardMoveEffect(GetMoveEffect(aiData->partnerMove)) // Partner is going to set up hazards
if (IsHazardMove(aiData->partnerMove) // Partner is going to set up hazards
&& AI_IsSlower(battlerAtk, BATTLE_PARTNER(battlerAtk), move)) // Partner going first
break; // Don't use Defog if partner is going to set up hazards
}

View File

@ -908,14 +908,8 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
for (j = 0; j < MAX_MON_MOVES; j++)
{
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL);
u32 aiEffect = GetMoveEffect(aiMove);
if (aiEffect == EFFECT_RAPID_SPIN
|| (B_DEFOG_EFFECT_CLEARING >= GEN_6 && aiEffect == EFFECT_DEFOG)
|| aiEffect == EFFECT_TIDY_UP)
{
// Have a mon that can clear the hazards, so switching out is okay
if (IsHazardClearingMove(aiMove)) // Have a mon that can clear the hazards, so switching out is okay
return TRUE;
}
}
}
// Faints to hazards and party can't clear them, don't switch out

View File

@ -1471,8 +1471,10 @@ bool32 IsConfusionMoveEffect(u32 moveEffect)
}
}
bool32 IsHazardMoveEffect(u32 moveEffect)
bool32 IsHazardMove(u32 move)
{
// Hazard setting moves like Stealth Rock, Spikes, etc.
u32 i, moveEffect = gMovesInfo[move].effect;
switch (moveEffect)
{
case EFFECT_SPIKES:
@ -1480,9 +1482,48 @@ bool32 IsHazardMoveEffect(u32 moveEffect)
case EFFECT_STICKY_WEB:
case EFFECT_STEALTH_ROCK:
return TRUE;
default:
return FALSE;
}
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
for (i = 0; i < additionalEffectCount; i++)
{
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
switch (additionalEffect->moveEffect)
{
case MOVE_EFFECT_STEELSURGE:
return TRUE;
}
}
return FALSE;
}
bool32 IsHazardClearingMove(u32 move)
{
// Hazard clearing effects like Rapid Spin, Tidy Up, etc.
u32 i, moveEffect = gMovesInfo[move].effect;
switch (moveEffect)
{
case EFFECT_RAPID_SPIN:
case EFFECT_TIDY_UP:
return TRUE;
case EFFECT_DEFOG:
if (B_DEFOG_EFFECT_CLEARING >= GEN_6)
return TRUE;
break;
}
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
for (i = 0; i < additionalEffectCount; i++)
{
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
switch (additionalEffect->moveEffect)
{
case MOVE_EFFECT_DEFOG:
return TRUE;
}
}
return FALSE;
}
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility)
@ -2957,7 +2998,7 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability)
if ((gBattleMons[battler].status1 & STATUS1_FREEZE) && !HasThawingMove(battler))
return TRUE; // if battler has thawing move we assume they will definitely use it, and thus being frozen should be neglected
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
if (gBattleMons[battler].status1 & STATUS1_SLEEP && !HasMoveEffect(battler, EFFECT_SLEEP_TALK))
return TRUE;
if (gBattleMons[battler].status2 & STATUS2_RECHARGE || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0))
@ -3713,6 +3754,20 @@ static const u16 sRecycleEncouragedItems[] =
ITEM_CUSTAP_BERRY,
ITEM_MENTAL_HERB,
ITEM_FOCUS_SASH,
ITEM_SALAC_BERRY,
ITEM_LIECHI_BERRY,
ITEM_AGUAV_BERRY,
ITEM_FIGY_BERRY,
ITEM_IAPAPA_BERRY,
ITEM_MAGO_BERRY,
ITEM_WIKI_BERRY,
ITEM_MENTAL_HERB,
ITEM_POWER_HERB,
ITEM_BERRY_JUICE,
ITEM_WEAKNESS_POLICY,
ITEM_BLUNDER_POLICY,
ITEM_KEE_BERRY,
ITEM_MARANGA_BERRY,
// TODO expand this
};
@ -4091,6 +4146,7 @@ bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef)
case STAT_SPATK:
return (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL));
case STAT_ACC:
return (HasLowAccuracyMove(battlerAtk, battlerDef));
case STAT_EVASION:
case STAT_SPEED:
return TRUE;
@ -4110,7 +4166,10 @@ bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData
if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE
|| CountUsablePartyMons(battlerDef) == 0
|| HasMoveEffect(battlerDef, EFFECT_RAPID_SPIN)
|| HasMoveEffect(battlerDef, EFFECT_DEFOG))
|| HasMoveEffect(battlerDef, EFFECT_TIDY_UP)
|| HasMoveEffect(battlerDef, EFFECT_DEFOG)
|| HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_DEFOG)
|| HasMoveEffect(battlerDef, EFFECT_MAGIC_COAT))
return FALSE;
return TRUE;
@ -4211,3 +4270,14 @@ void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *
if (AI_DATA->hpPercents[battlerAtk] > 70)
ADJUST_SCORE_PTR(WEAK_EFFECT);
}
bool32 HasLowAccuracyMove(u32 battlerAtk, u32 battlerDef)
{
int i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] <= LOW_ACCURACY_THRESHOLD)
return TRUE;
}
return FALSE;
}