Moving additional effects out of AI_CalcMoveEffectScore and into AI_CalcMoveAdditionalEffectScore (#7727)

This commit is contained in:
surskitty 2025-09-13 04:58:16 -04:00 committed by GitHub
parent fab4dc1163
commit abc0e10558
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 13 deletions

View File

@ -3990,9 +3990,8 @@ static void AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef)
}
}
static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
static s32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData)
{
struct AiLogicData *aiData = gAiLogicData;
enum ItemHoldEffect holdEffect = aiData->holdEffects[battlerAtk];
s32 score = 0;
@ -4020,17 +4019,16 @@ static u32 AI_CalcHoldEffectMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
return score;
}
static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData)
{
// move data
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
struct AiLogicData *aiData = gAiLogicData;
u32 movesetIndex = gAiThinkingStruct->movesetIndex;
uq4_12_t effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
s32 score = 0;
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, gAiLogicData);
u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, gAiLogicData);
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, aiData);
u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, aiData);
u32 predictedType = GetMoveType(predictedMove);
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
bool32 isBattle1v1 = IsBattle1v1();
@ -4052,7 +4050,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(10);
// check burn / frostbite
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && gAiLogicData->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
if (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING && aiData->abilities[battlerAtk] == ABILITY_NATURAL_CURE)
{
if ((gBattleMons[battlerAtk].status1 & STATUS1_BURN && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL, TRUE))
|| (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE && HasOnlyMovesWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL, TRUE)))
@ -4478,7 +4476,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
}
break;
case EFFECT_BATON_PASS:
if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].volatiles.substitute
if ((aiData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].volatiles.substitute
|| gBattleMons[battlerAtk].volatiles.powerTrick
|| gBattleMons[battlerAtk].volatiles.magnetRise
|| gBattleMons[battlerAtk].volatiles.aquaRing
@ -5482,9 +5480,9 @@ case EFFECT_GUARD_SPLIT:
if (GetFirstFaintedPartyIndex(battlerAtk) != PARTY_SIZE)
{
ADJUST_SCORE(DECENT_EFFECT);
if (gAiLogicData->shouldSwitch & (1u << battlerAtk)) // Bad matchup
if (aiData->shouldSwitch & (1u << battlerAtk)) // Bad matchup
ADJUST_SCORE(WEAK_EFFECT);
if (gAiLogicData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after
if (aiData->mostSuitableMonId[battlerAtk] != PARTY_SIZE) // Good mon to send in after
ADJUST_SCORE(WEAK_EFFECT);
}
break;
@ -5590,11 +5588,30 @@ case EFFECT_GUARD_SPLIT:
break;
} // move effect checks
return score;
}
static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, struct AiLogicData *aiData)
{
// move data
s32 score = 0;
u32 predictedMove = GetIncomingMove(battlerAtk, battlerDef, aiData);
bool32 hasPartner = HasPartner(battlerAtk);
u32 i;
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
// check move additional effects that are likely to happen
for (i = 0; i < additionalEffectCount; 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
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect))
continue;
@ -5753,8 +5770,12 @@ case EFFECT_GUARD_SPLIT:
IncreasePoisonScore(battlerAtk, battlerDef, move, &score);
break;
case MOVE_EFFECT_CLEAR_SMOG:
{
bool32 moveTargetsBothOpponents = HasTwoOpponents(battlerAtk) && (gMovesInfo[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_ALL_BATTLERS));
score += AI_TryToClearStats(battlerAtk, battlerDef, moveTargetsBothOpponents);
break;
}
case MOVE_EFFECT_BUG_BITE: // And pluck
if (gBattleMons[battlerDef].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD)
break;
@ -5783,6 +5804,8 @@ case EFFECT_GUARD_SPLIT:
case MOVE_EFFECT_THROAT_CHOP:
if (IsSoundMove(GetBestDmgMoveFromBattler(battlerDef, battlerAtk, AI_DEFENDING)))
{
u32 predictedMoveSpeedCheck = GetIncomingMoveSpeedCheck(battlerAtk, battlerDef, aiData);
if (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY))
ADJUST_SCORE(GOOD_EFFECT);
else
@ -5874,13 +5897,14 @@ case EFFECT_GUARD_SPLIT:
}
}
}
return score;
}
// AI_FLAG_CHECK_VIABILITY - Chooses best possible move to hit player
static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
struct AiLogicData *aiData = gAiLogicData;
// Targeting partner, check benefits of doing that instead
if (IsTargetingPartner(battlerAtk, battlerDef))
return score;
@ -5897,8 +5921,9 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
}
}
ADJUST_SCORE(AI_CalcMoveEffectScore(battlerAtk, battlerDef, move));
ADJUST_SCORE(AI_CalcHoldEffectMoveScore(battlerAtk, battlerDef, move));
ADJUST_SCORE(AI_CalcMoveEffectScore(battlerAtk, battlerDef, move, aiData));
ADJUST_SCORE(AI_CalcAdditionalEffectScore(battlerAtk, battlerDef, move, aiData));
ADJUST_SCORE(AI_CalcHoldEffectMoveScore(battlerAtk, battlerDef, move, aiData));
return score;
}

View File

@ -1358,3 +1358,19 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to
EXPECT_EQ(damage2, damage1);
}
}
AI_SINGLE_BATTLE_TEST("AI sees Sheer Force skips additional effects")
{
u16 ability, expectedMove;
PARAMETRIZE { ability = ABILITY_NONE; expectedMove = MOVE_POWER_UP_PUNCH; }
PARAMETRIZE { ability = ABILITY_SHEER_FORCE; expectedMove = MOVE_KARATE_CHOP; }
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Ability(ability); Moves(MOVE_POWER_UP_PUNCH, MOVE_KARATE_CHOP); }
} WHEN {
TURN { EXPECT_MOVE(opponent, expectedMove); }
}
}