fix (AI scoring): shield dust considerations, IsMoveEffectInMinus self effect edge case, hitsToKO zero-case consideration (#8126)

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
ghostyboyy97 2025-11-04 03:35:43 -05:00 committed by GitHub
parent 6bcf9823c5
commit 3c72ca1158
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 51 additions and 5 deletions

View File

@ -155,6 +155,7 @@ bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffe
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category);
enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef);
bool32 IsAdditionalEffectBlocked(u32 battlerAtk, u32 abilityAtk, u32 battlerDef, u32 abilityDef);
struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef, u32 weather);
bool32 AI_IsDamagedByRecoil(u32 battler);
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);

View File

@ -5069,7 +5069,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
if (gBattleMons[battlerDef].speed > gBattleMons[battlerAtk].speed)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_GUARD_SPLIT:
case EFFECT_GUARD_SPLIT:
{
u32 atkDefense = gBattleMons[battlerAtk].defense;
u32 defDefense = gBattleMons[battlerDef].defense;
@ -5590,6 +5590,9 @@ case EFFECT_GUARD_SPLIT:
}
else // consider move effects that hinder the target
{
if (IsAdditionalEffectBlocked(battlerAtk, aiData->abilities[battlerAtk], battlerDef, aiData->abilities[battlerDef]))
continue;
switch (additionalEffect->moveEffect)
{
case MOVE_EFFECT_FLINCH:

View File

@ -701,6 +701,17 @@ bool32 IsDamageMoveUnusable(struct DamageContext *ctx)
return FALSE;
}
bool32 IsAdditionalEffectBlocked(u32 battlerAtk, u32 abilityAtk, u32 battlerDef, u32 abilityDef)
{
if (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK)
return TRUE;
if (abilityDef == ABILITY_SHIELD_DUST && !IsMoldBreakerTypeAbility(battlerAtk, abilityAtk))
return TRUE;
return FALSE;
}
static inline s32 GetDamageByRollType(s32 dmg, enum DamageRollType rollType)
{
if (rollType == DMG_ROLL_LOWEST)
@ -1073,6 +1084,9 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
}
else // consider move effects that hinder the target
{
if (IsAdditionalEffectBlocked(battlerAtk, abilityAtk, battlerDef, abilityDef))
continue;
switch (additionalEffect->moveEffect)
{
case MOVE_EFFECT_POISON:
@ -1107,7 +1121,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_1:
case MOVE_EFFECT_ACC_MINUS_1:
case MOVE_EFFECT_EVS_MINUS_1:
if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo > 1)
return TRUE;
break;
case MOVE_EFFECT_ATK_MINUS_2:
@ -1117,7 +1131,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
case MOVE_EFFECT_SP_DEF_MINUS_2:
case MOVE_EFFECT_ACC_MINUS_2:
case MOVE_EFFECT_EVS_MINUS_2:
if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo > 1)
return TRUE;
break;
default:
@ -1174,7 +1188,7 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
case MOVE_EFFECT_ATK_DEF_DOWN:
case MOVE_EFFECT_DEF_SPDEF_DOWN:
if ((additionalEffect->self && abilityAtk != ABILITY_CONTRARY)
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)))
|| (noOfHitsToKo > 1 && !additionalEffect->self && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)))
return TRUE;
break;
case MOVE_EFFECT_RECHARGE:
@ -1195,7 +1209,7 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
case MOVE_EFFECT_ACC_PLUS_2:
case MOVE_EFFECT_ALL_STATS_UP:
if ((additionalEffect->self && abilityAtk == ABILITY_CONTRARY)
|| (noOfHitsToKo != 1 && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move))))
|| (noOfHitsToKo > 1 && !additionalEffect->self && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move))))
return TRUE;
break;
default:

View File

@ -188,3 +188,31 @@ SINGLE_BATTLE_TEST("Shield Dust does not prevent ability stat changes")
MESSAGE("Vivillon's Speed fell!");
}
}
AI_SINGLE_BATTLE_TEST("AI will score secondary effects against shield dust correctly")
{
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT);
GIVEN {
PLAYER(SPECIES_DUSTOX){ Ability(ABILITY_SHIELD_DUST); Moves(MOVE_GUST); }
OPPONENT(SPECIES_SUNFLORA){ Ability(ABILITY_EARLY_BIRD); Moves(MOVE_MYSTICAL_FIRE, MOVE_FIERY_DANCE); }
} WHEN {
TURN {
MOVE(player, MOVE_GUST);
EXPECT_MOVE(opponent, MOVE_FIERY_DANCE);
}
}
}
AI_SINGLE_BATTLE_TEST("AI will score secondary effects against shield dust correctly when it has Mold Breaker")
{
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT);
GIVEN {
PLAYER(SPECIES_DUSTOX){ Ability(ABILITY_SHIELD_DUST); Moves(MOVE_GUST); }
OPPONENT(SPECIES_SUNFLORA){ Ability(ABILITY_MOLD_BREAKER); Moves(MOVE_MYSTICAL_FIRE, MOVE_FIERY_DANCE); }
} WHEN {
TURN {
MOVE(player, MOVE_GUST);
EXPECT_MOVE(opponent, MOVE_MYSTICAL_FIRE);
}
}
}