fix (scoring): AI_IsMoveEffectInPlus - AI should not see secondary effect of Sheer Force boosted moves as beneficial (#8579)

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
ghostyboyy97 2025-12-19 12:40:46 -05:00 committed by GitHub
parent 9451af1c64
commit a901d227cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 25 additions and 12 deletions

View File

@ -343,7 +343,7 @@ bool32 IsPartnerMonFromSameTrainer(u32 battler);
enum DamageCategory GetCategoryBasedOnStats(u32 battler); enum DamageCategory GetCategoryBasedOnStats(u32 battler);
void SetShellSideArmCategory(void); void SetShellSideArmCategory(void);
bool32 MoveIsAffectedBySheerForce(u32 move); bool32 MoveIsAffectedBySheerForce(u32 move);
bool32 TestIfSheerForceAffected(u32 battler, u16 move); bool32 IsSheerForceAffected(u16 move, enum Ability ability);
void TryRestoreHeldItems(void); void TryRestoreHeldItems(void);
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item); bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item);
void TrySaveExchangedItem(u32 battler, u16 stolenItem); void TrySaveExchangedItem(u32 battler, u16 stolenItem);

View File

@ -5697,17 +5697,14 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move
u32 i; u32 i;
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move); u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
if (IsSheerForceAffected(move, aiData->abilities[battlerAtk]))
return score;
// check move additional effects that are likely to happen // check move additional effects that are likely to happen
for (i = 0; i < additionalEffectCount; i++) for (i = 0; i < additionalEffectCount; i++)
{ {
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
if (aiData->abilities[battlerAtk] == ABILITY_SHEER_FORCE)
{
if ((additionalEffect->chance > 0) != additionalEffect->sheerForceOverride)
continue;
}
// Only consider effects with a guaranteed chance to happen // Only consider effects with a guaranteed chance to happen
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect)) if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect))
continue; continue;

View File

@ -1030,6 +1030,9 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
enum Ability abilityDef = gAiLogicData->abilities[battlerDef]; enum Ability abilityDef = gAiLogicData->abilities[battlerDef];
enum Ability abilityAtk = gAiLogicData->abilities[battlerAtk]; enum Ability abilityAtk = gAiLogicData->abilities[battlerAtk];
if (IsSheerForceAffected(move, abilityAtk))
return FALSE;
switch (GetMoveEffect(move)) switch (GetMoveEffect(move))
{ {
case EFFECT_HIT_ESCAPE: case EFFECT_HIT_ESCAPE:

View File

@ -3049,7 +3049,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, enum MoveEffect moveEffect, c
if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility)) if (!primary && !affectsUser && IsMoveEffectBlockedByTarget(battlerAbility))
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
else if (!primary else if (!primary
&& TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) && IsSheerForceAffected(gCurrentMove, GetBattlerAbility(battler))
&& !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE)) && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->battlerState[gBattlerAttacker].commanderSpecies != SPECIES_NONE))
moveEffect = MOVE_EFFECT_NONE; moveEffect = MOVE_EFFECT_NONE;
else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint) else if (!IsBattlerAlive(gEffectBattler) && !activateAfterFaint)
@ -6400,7 +6400,7 @@ static void Cmd_moveend(void)
&& gBattlerTarget != gBattlerAttacker && gBattlerTarget != gBattlerAttacker
&& !IsBattlerAlly(gBattlerTarget, gBattlerAttacker) && !IsBattlerAlly(gBattlerTarget, gBattlerAttacker)
&& gProtectStructs[gBattlerTarget].physicalBattlerId == gBattlerAttacker && gProtectStructs[gBattlerTarget].physicalBattlerId == gBattlerAttacker
&& !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && !IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker)))
{ {
gProtectStructs[gBattlerTarget].shellTrap = TRUE; gProtectStructs[gBattlerTarget].shellTrap = TRUE;
// Change move order in double battles, so the hit mon with shell trap moves immediately after being hit. // Change move order in double battles, so the hit mon with shell trap moves immediately after being hit.
@ -6660,7 +6660,7 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_SHEER_FORCE: case MOVEEND_SHEER_FORCE:
if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) if (IsSheerForceAffected(gCurrentMove, GetBattlerAbility(gBattlerAttacker)))
gBattleScripting.moveendState = MOVEEND_EJECT_PACK; gBattleScripting.moveendState = MOVEEND_EJECT_PACK;
else else
gBattleScripting.moveendState++; gBattleScripting.moveendState++;

View File

@ -9892,9 +9892,9 @@ bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes)
return ret; return ret;
} }
bool32 TestIfSheerForceAffected(u32 battler, u16 move) bool32 IsSheerForceAffected(u16 move, enum Ability ability)
{ {
return GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move); return ability == ABILITY_SHEER_FORCE && MoveIsAffectedBySheerForce(move);
} }
// This function is the body of "jumpifstat", but can be used dynamically in a function // This function is the body of "jumpifstat", but can be used dynamically in a function

View File

@ -133,3 +133,16 @@ AI_SINGLE_BATTLE_TEST("HasMoveThatChangesKOThreshold - AI should not see self-ta
TURN { MOVE(player, MOVE_HAMMER_ARM); EXPECT_MOVE(opponent, move == MOVE_EARTHQUAKE ? MOVE_NASTY_PLOT : MOVE_AURA_SPHERE); } TURN { MOVE(player, MOVE_HAMMER_ARM); EXPECT_MOVE(opponent, move == MOVE_EARTHQUAKE ? MOVE_NASTY_PLOT : MOVE_AURA_SPHERE); }
} }
} }
AI_SINGLE_BATTLE_TEST("AI_IsMoveEffectInPlus - AI should not see secondary effect of Sheer Force boosted moves as beneficial")
{
GIVEN {
ASSUME(GetMovePower(MOVE_PSYCHIC) == 90);
ASSUME(MoveHasAdditionalEffect(MOVE_PSYCHIC, MOVE_EFFECT_SP_DEF_MINUS_1) == TRUE);
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);
PLAYER(SPECIES_STEELIX) { Level(100); Nature(NATURE_SASSY); Item(ITEM_STEELIXITE); Ability(ABILITY_STURDY); Speed(58); Moves(MOVE_GYRO_BALL); }
OPPONENT(SPECIES_BRAVIARY_HISUI) { Level(100); Nature(NATURE_TIMID); Ability(ABILITY_SHEER_FORCE); Speed(251); Moves(MOVE_PSYCHIC, MOVE_NIGHT_SHADE); }
} WHEN {
TURN { MOVE(player, MOVE_GYRO_BALL); SCORE_EQ_VAL(opponent, MOVE_PSYCHIC, 101); SCORE_EQ_VAL(opponent, MOVE_NIGHT_SHADE, 101); }
}
}