Remove global sBattler_AI (#6128)

This commit is contained in:
Alex 2025-01-29 19:58:16 +01:00 committed by GitHub
parent 94c98e6233
commit 32eb5dfba5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 104 additions and 96 deletions

View File

@ -57,21 +57,30 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32);
#define SET_SCORE(battler, movesetIndex, val) \
do \
{ \
TestRunner_Battle_AISetScore(__FILE__, __LINE__, battler, movesetIndex, val); \
if (TESTING) \
{ \
TestRunner_Battle_AISetScore(__FILE__, __LINE__, battler, movesetIndex, val); \
} \
AI_THINKING_STRUCT->score[movesetIndex] = val; \
} while (0) \
#define ADJUST_SCORE(val) \
do \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, sBattler_AI, AI_THINKING_STRUCT->movesetIndex, val); \
if (TESTING) \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
} \
score += val; \
} while (0) \
#define ADJUST_AND_RETURN_SCORE(val) \
do \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, sBattler_AI, AI_THINKING_STRUCT->movesetIndex, val); \
if (TESTING) \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
} \
score += val; \
return score; \
} while (0) \
@ -79,7 +88,10 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32);
#define ADJUST_SCORE_PTR(val) \
do \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, sBattler_AI, AI_THINKING_STRUCT->movesetIndex, val); \
if (TESTING) \
{ \
TestRunner_Battle_AIAdjustScore(__FILE__, __LINE__, battlerAtk, AI_THINKING_STRUCT->movesetIndex, val); \
} \
(*score) += val; \
} while (0) \
@ -98,13 +110,11 @@ typedef s32 (*AiScoreFunc)(u32, u32, u32, s32);
void BattleAI_SetupItems(void);
void BattleAI_SetupFlags(void);
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler);
u32 BattleAI_ChooseMoveOrAction(void);
u32 BattleAI_ChooseMoveOrAction(u32 battler);
void Ai_InitPartyStruct(void);
void Ai_UpdateSwitchInData(u32 battler);
void Ai_UpdateFaintData(u32 battler);
void SetAiLogicDataForTurn(struct AiLogicData *aiData);
void ResetDynamicAiFunc(void);
extern u8 sBattler_AI;
#endif // GUARD_BATTLE_AI_MAIN_H

View File

@ -56,8 +56,8 @@ bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits)
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
s32 AI_DecideKnownAbilityForTurn(u32 battlerId);
u32 AI_DecideHoldEffectForTurn(u32 battlerId);
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
u32 AI_GetWeather(struct AiLogicData *aiData);
bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move);
u32 AI_GetWeather(void);
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits);
bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits);
bool32 HasDamagingMove(u32 battlerId);
@ -84,7 +84,7 @@ u32 AI_GetBattlerAbility(u32 battler);
// stat stage checks
bool32 AnyStatIsRaised(u32 battlerId);
bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat);
bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 battlerAbility, u32 stat);
bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat);
bool32 AreBattlersStatsMaxed(u32 battler);
u32 CountPositiveStatStages(u32 battlerId);
@ -125,7 +125,7 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool
bool32 HasAnyKnownMove(u32 battlerId);
bool32 IsAromaVeilProtectedEffect(u32 moveEffect);
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility);
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMoveEffect(u32 moveEffect);
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move);

View File

@ -40,7 +40,6 @@ static bool32 IsPinchBerryItemEffect(u32 holdEffect);
// ewram
EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests
EWRAM_DATA u8 sBattler_AI = 0;
EWRAM_DATA AiScoreFunc sDynamicAiFunc = NULL;
// const rom data
@ -268,25 +267,24 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler)
SET_SCORE(battler, i, 0);
}
//sBattler_AI = battler;
gBattlerTarget = SetRandomTarget(sBattler_AI);
gBattleStruct->aiChosenTarget[sBattler_AI] = gBattlerTarget;
gBattlerTarget = SetRandomTarget(battler);
gBattleStruct->aiChosenTarget[battler] = gBattlerTarget;
}
u32 BattleAI_ChooseMoveOrAction(void)
u32 BattleAI_ChooseMoveOrAction(u32 battler)
{
u32 ret;
if (!IsDoubleBattle())
ret = ChooseMoveOrAction_Singles(sBattler_AI);
ret = ChooseMoveOrAction_Singles(battler);
else
ret = ChooseMoveOrAction_Doubles(sBattler_AI);
ret = ChooseMoveOrAction_Doubles(battler);
// Clear protect structures, some flags may be set during AI calcs
// e.g. pranksterElevated from GetBattleMovePriority
memset(&gProtectStructs, 0, MAX_BATTLERS_COUNT * sizeof(struct ProtectStruct));
#if TESTING
TestRunner_Battle_CheckAiMoveScores(sBattler_AI);
TestRunner_Battle_CheckAiMoveScores(battler);
#endif // TESTING
return ret;
}
@ -469,7 +467,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData)
gBattleStruct->aiDelayTimer = gMain.vblankCounter1;
aiData->weatherHasEffect = HasWeatherEffect();
weather = AI_GetWeather(aiData);
weather = AI_GetWeather();
// get/assume all battler data and simulate AI damage
battlersCount = gBattlersCount;
@ -583,7 +581,7 @@ static u32 ChooseMoveOrAction_Doubles(u32 battlerAi)
AI_DATA->partnerMove = GetAllyChosenMove(battlerAi);
AI_THINKING_STRUCT->aiLogicId = 0;
AI_THINKING_STRUCT->movesetIndex = 0;
flags = AI_THINKING_STRUCT->aiFlags[sBattler_AI];
flags = AI_THINKING_STRUCT->aiFlags[battlerAi];
while (flags != 0)
{
@ -747,7 +745,7 @@ void BattleAI_DoAIProcessing_PredictedSwitchin(struct AI_ThinkingStruct *aiThink
PokemonToBattleMon(&party[aiData->mostSuitableMonId[battlerDef]], &switchinCandidate);
gBattleMons[battlerDef] = switchinCandidate;
SetBattlerAiData(battlerDef, aiData);
CalcBattlerAiMovesData(aiData, battlerAtk, battlerDef, AI_GetWeather(aiData));
CalcBattlerAiMovesData(aiData, battlerAtk, battlerDef, AI_GetWeather());
// Regular processing with new battler
do
@ -893,7 +891,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (!(moveTarget & MOVE_TARGET_USER))
{
// target ability checks
if (!DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
{
if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef]))
RETURN_SCORE_MINUS(20);
@ -989,7 +987,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
RETURN_SCORE_MINUS(10);
break;
case ABILITY_LEAF_GUARD:
if ((AI_GetWeather(aiData) & B_WEATHER_SUN)
if ((AI_GetWeather() & B_WEATHER_SUN)
&& aiData->holdEffects[battlerDef] != HOLD_EFFECT_UTILITY_UMBRELLA
&& IsNonVolatileStatusMoveEffect(moveEffect))
RETURN_SCORE_MINUS(10);
@ -1005,11 +1003,11 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
switch (aiData->abilities[BATTLE_PARTNER(battlerDef)])
{
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(move, aiData->abilities[battlerAtk]))
if (moveType == TYPE_ELECTRIC && !IsMoveRedirectionPrevented(battlerAtk, move, aiData->abilities[battlerAtk]))
RETURN_SCORE_MINUS(20);
break;
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(move, aiData->abilities[battlerAtk]))
if (moveType == TYPE_WATER && !IsMoveRedirectionPrevented(battlerAtk, move, aiData->abilities[battlerAtk]))
RETURN_SCORE_MINUS(20);
break;
case ABILITY_MAGIC_BOUNCE:
@ -1067,7 +1065,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
return 0; // Can't even select heal blocked move
// primal weather check
weather = AI_GetWeather(aiData);
weather = AI_GetWeather();
if (weather & B_WEATHER_PRIMAL_ANY)
{
switch (moveEffect)
@ -1118,7 +1116,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
ADJUST_SCORE(-10);
}
else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
else if (IsAbilityOnField(ABILITY_DAMP) && !DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
{
ADJUST_SCORE(-10);
}
@ -1357,36 +1355,36 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// stat lowering effects
case EFFECT_ATTACK_DOWN:
case EFFECT_ATTACK_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL))
ADJUST_SCORE(-10);
else if (aiData->abilities[battlerDef] == ABILITY_HYPER_CUTTER)
ADJUST_SCORE(-10);
break;
case EFFECT_DEFENSE_DOWN:
case EFFECT_DEFENSE_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_DEF))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_DEF))
ADJUST_SCORE(-10);
break;
case EFFECT_SPEED_DOWN:
case EFFECT_SPEED_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
ADJUST_SCORE(-10);
else if (aiData->abilities[battlerDef] == ABILITY_SPEED_BOOST)
ADJUST_SCORE(-10);
break;
case EFFECT_SPECIAL_ATTACK_DOWN:
case EFFECT_SPECIAL_ATTACK_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL))
ADJUST_SCORE(-10);
break;
case EFFECT_SPECIAL_DEFENSE_DOWN:
case EFFECT_SPECIAL_DEFENSE_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPDEF))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPDEF))
ADJUST_SCORE(-10);
break;
case EFFECT_ACCURACY_DOWN:
case EFFECT_ACCURACY_DOWN_2:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ACC))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ACC))
ADJUST_SCORE(-10);
else if (aiData->abilities[battlerDef] == ABILITY_KEEN_EYE || aiData->abilities[battlerDef] == ABILITY_MINDS_EYE
|| (B_ILLUMINATE_EFFECT >= GEN_9 && aiData->abilities[battlerDef] == ABILITY_ILLUMINATE))
@ -1395,9 +1393,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_EVASION_DOWN:
case EFFECT_EVASION_DOWN_2:
case EFFECT_TICKLE:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK))
ADJUST_SCORE(-10);
else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_DEF))
else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_DEF))
ADJUST_SCORE(-8);
break;
case EFFECT_VENOM_DRENCH:
@ -1407,18 +1405,18 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
else
{
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
ADJUST_SCORE(-10);
else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK))
else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPATK))
ADJUST_SCORE(-8);
else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK))
ADJUST_SCORE(-6);
}
break;
case EFFECT_NOBLE_ROAR:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPATK))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPATK))
ADJUST_SCORE(-10);
else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK))
ADJUST_SCORE(-8);
break;
case EFFECT_CAPTIVATE:
@ -1479,7 +1477,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_TOXIC_THREAD:
if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_SPEED))
ADJUST_SCORE(-1); // may still want to just poison
//fallthrough
case EFFECT_POISON:
@ -1894,7 +1892,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_STRENGTH_SAP:
if (aiData->abilities[battlerDef] == ABILITY_CONTRARY)
ADJUST_SCORE(-10);
else if (!ShouldLowerStat(battlerDef, aiData->abilities[battlerDef], STAT_ATK))
else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK))
ADJUST_SCORE(-10);
break;
case EFFECT_COPYCAT:
@ -1943,7 +1941,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_MORNING_SUN:
case EFFECT_SYNTHESIS:
case EFFECT_MOONLIGHT:
if ((AI_GetWeather(aiData) & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL | B_WEATHER_SNOW | B_WEATHER_FOG)))
if ((AI_GetWeather() & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL | B_WEATHER_SNOW | B_WEATHER_FOG)))
ADJUST_SCORE(-3);
else if (AI_BattlerAtMaxHp(battlerAtk))
ADJUST_SCORE(-10);
@ -2716,7 +2714,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// Don't use user-target moves ie. Swords Dance, with exceptions
if ((moveTarget & MOVE_TARGET_USER)
&& moveEffect != EFFECT_DESTINY_BOND && moveEffect != EFFECT_WISH && moveEffect != EFFECT_HEALING_WISH
&& !(moveEffect == EFFECT_AURORA_VEIL && (AI_GetWeather(aiData) & (B_WEATHER_SNOW | B_WEATHER_HAIL))))
&& !(moveEffect == EFFECT_AURORA_VEIL && (AI_GetWeather() & (B_WEATHER_SNOW | B_WEATHER_HAIL))))
ADJUST_SCORE(-30);
// Don't use a status move if the mon is the last one in the party, has no good switchin, or is trapped
else if (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_STATUS
@ -2895,7 +2893,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
{
// partner ability checks
if (!partnerProtecting && moveTarget != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
if (!partnerProtecting && moveTarget != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
{
switch (atkPartnerAbility)
{
@ -3597,7 +3595,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|| HasMoveEffect(EFFECT_SNORE, battlerAtk)
|| aiData->abilities[battlerAtk] == ABILITY_SHED_SKIN
|| aiData->abilities[battlerAtk] == ABILITY_EARLY_BIRD
|| (AI_GetWeather(aiData) & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && aiData->abilities[battlerAtk] == ABILITY_HYDRATION && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA))
|| (AI_GetWeather() & B_WEATHER_RAIN && gWishFutureKnock.weatherDuration != 1 && aiData->abilities[battlerAtk] == ABILITY_HYDRATION && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA))
ADJUST_SCORE(GOOD_EFFECT);
}
break;
@ -4070,12 +4068,12 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
switch (aiData->abilities[battlerDef])
{
case ABILITY_SWIFT_SWIM:
if (AI_GetWeather(aiData) & B_WEATHER_RAIN)
if (AI_GetWeather() & B_WEATHER_RAIN)
ADJUST_SCORE(DECENT_EFFECT); // Slow 'em down
break;
case ABILITY_CHLOROPHYLL:
case ABILITY_FLOWER_GIFT:
if (AI_GetWeather(aiData) & B_WEATHER_SUN)
if (AI_GetWeather() & B_WEATHER_SUN)
ADJUST_SCORE(DECENT_EFFECT); // Slow 'em down
break;
}
@ -4523,7 +4521,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(GOOD_EFFECT);
break;
case EFFECT_SHORE_UP:
if ((AI_GetWeather(aiData) & B_WEATHER_SANDSTORM) && ShouldRecover(battlerAtk, battlerDef, move, 67))
if ((AI_GetWeather() & B_WEATHER_SANDSTORM) && ShouldRecover(battlerAtk, battlerDef, move, 67))
ADJUST_SCORE(DECENT_EFFECT);
else if (ShouldRecover(battlerAtk, battlerDef, move, 50))
ADJUST_SCORE(DECENT_EFFECT);
@ -5373,23 +5371,23 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SANDSTORM:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY)))
if (!(AI_GetWeather() & (B_WEATHER_SANDSTORM | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SUNNY_DAY:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY)))
if (!(AI_GetWeather() & (B_WEATHER_SUN | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_RAIN_DANCE:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY)))
if (!(AI_GetWeather() & (B_WEATHER_RAIN | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_HAIL:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY)))
if (!(AI_GetWeather() & (B_WEATHER_HAIL | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
break;
case EFFECT_SNOWSCAPE:
if (!(AI_GetWeather(AI_DATA) & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY)))
if (!(AI_GetWeather() & (B_WEATHER_SNOW | B_WEATHER_PRIMAL_ANY)))
ADJUST_SCORE(POWERFUL_STATUS_MOVE);
}

View File

@ -90,7 +90,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
//Variable initialization
u8 opposingPosition, atkType1, atkType2, defType1, defType2;
s32 i, damageDealt = 0, maxDamageDealt = 0, damageTaken = 0, maxDamageTaken = 0;
u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = AI_DATA->abilities[battler], opposingBattler, weather = AI_GetWeather(AI_DATA);
u32 aiMove, playerMove, aiBestMove = MOVE_NONE, aiAbility = AI_DATA->abilities[battler], opposingBattler, weather = AI_GetWeather();
bool32 getsOneShot = FALSE, hasStatusMove = FALSE, hasSuperEffectiveMove = FALSE;
u16 typeEffectiveness = UQ_4_12(1.0), aiMoveEffect; //baseline typing damage
uq4_12_t effectiveness;

View File

@ -393,7 +393,7 @@ struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 b
SaveBattlerData(battlerDef);
SetBattlerData(battlerAtk);
SetBattlerData(battlerDef);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(AI_DATA), rollType);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(), rollType);
RestoreBattlerData(battlerAtk);
RestoreBattlerData(battlerDef);
return dmg;
@ -426,7 +426,7 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy
u32 battlerDefAbility;
u32 partnerBattlerDefAbility;
if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
if (DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
{
battlerDefAbility = ABILITY_NONE;
partnerBattlerDefAbility = ABILITY_NONE;
@ -877,7 +877,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 (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
if (ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
return TRUE;
break;
case MOVE_EFFECT_ATK_MINUS_2:
@ -887,7 +887,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 (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
if (ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
return TRUE;
break;
}
@ -944,7 +944,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(abilityAtk, move)))
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)))
return TRUE;
break;
case MOVE_EFFECT_RECHARGE:
@ -965,7 +965,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(abilityAtk, move))))
|| (noOfHitsToKo != 1 && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move))))
return TRUE;
break;
}
@ -1122,7 +1122,7 @@ static bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move)
if (AI_DATA->holdEffects[battlerTarget] == HOLD_EFFECT_FOCUS_SASH)
return TRUE;
if (!DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battler], move))
if (!DoesBattlerIgnoreAbilityChecks(battler, AI_DATA->abilities[battler], move))
{
if (B_STURDY >= GEN_5 && AI_DATA->abilities[battlerTarget] == ABILITY_STURDY)
return TRUE;
@ -1377,30 +1377,31 @@ u32 AI_DecideHoldEffectForTurn(u32 battlerId)
return holdEffect;
}
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move)
bool32 DoesBattlerIgnoreAbilityChecks(u32 battlerAtk, u32 atkAbility, u32 move)
{
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE)
return FALSE; // AI handicap flag: doesn't understand ability suppression concept
if (IsMoldBreakerTypeAbility(sBattler_AI, atkAbility) || MoveIgnoresTargetAbility(move))
if (IsMoldBreakerTypeAbility(battlerAtk, atkAbility) || MoveIgnoresTargetAbility(move))
return TRUE;
return FALSE;
}
static inline bool32 AI_WeatherHasEffect(struct AiLogicData *aiData)
static inline bool32 AI_WeatherHasEffect(void)
{
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
if (AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_LEFT] & AI_FLAG_NEGATE_UNAWARE
|| AI_THINKING_STRUCT->aiFlags[B_POSITION_OPPONENT_RIGHT] & AI_FLAG_NEGATE_UNAWARE)
return TRUE; // AI doesn't understand weather supression (handicap)
return aiData->weatherHasEffect; // weather damping abilities are announced
return AI_DATA->weatherHasEffect; // weather damping abilities are announced
}
u32 AI_GetWeather(struct AiLogicData *aiData)
u32 AI_GetWeather(void)
{
if (gBattleWeather == B_WEATHER_NONE)
return B_WEATHER_NONE;
if (!AI_WeatherHasEffect(aiData))
if (!AI_WeatherHasEffect())
return B_WEATHER_NONE;
return gBattleWeather;
}
@ -1464,9 +1465,9 @@ bool32 IsHazardMoveEffect(u32 moveEffect)
}
}
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility)
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility)
{
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_NEGATE_UNAWARE)
return FALSE;
u32 effect = GetMoveEffect(move);
@ -1514,7 +1515,7 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move)
return TRUE;
// discouraged from hitting
weather = AI_GetWeather(AI_DATA);
weather = AI_GetWeather();
if ((weather & B_WEATHER_SUN) && effect == EFFECT_THUNDER)
return FALSE;
@ -1542,7 +1543,7 @@ bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbil
else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AI_BattlerAtMaxHp(battlerDef))
return FALSE;
if (!DoesBattlerIgnoreAbilityChecks(atkAbility, move) && defAbility == ABILITY_STURDY)
if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, atkAbility, move) && defAbility == ABILITY_STURDY)
return FALSE;
if ((((gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS)
@ -1565,7 +1566,7 @@ bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbil
bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect)
{
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (weather & B_WEATHER_SANDSTORM)
return FALSE;
@ -1586,7 +1587,7 @@ bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect)
bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect)
{
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (weather & (B_WEATHER_HAIL | B_WEATHER_SNOW))
return FALSE;
@ -1609,7 +1610,7 @@ bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect)
bool32 ShouldSetRain(u32 battlerAtk, u32 atkAbility, u32 holdEffect)
{
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (weather & B_WEATHER_RAIN)
return FALSE;
@ -1630,7 +1631,7 @@ bool32 ShouldSetRain(u32 battlerAtk, u32 atkAbility, u32 holdEffect)
bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect)
{
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (weather & B_WEATHER_SUN)
return FALSE;
@ -1656,7 +1657,7 @@ bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect)
bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect)
{
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (weather & (B_WEATHER_SNOW | B_WEATHER_HAIL))
return FALSE;
@ -1714,11 +1715,11 @@ void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove,
}
// stat stages
bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat)
bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 battlerAbility, u32 stat)
{
if (gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY)
if (gBattleMons[battlerDef].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY)
{
if (AI_DATA->holdEffects[battler] == HOLD_EFFECT_CLEAR_AMULET
if (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET
|| battlerAbility == ABILITY_CLEAR_BODY
|| battlerAbility == ABILITY_WHITE_SMOKE
|| battlerAbility == ABILITY_FULL_METAL_BODY)
@ -1732,9 +1733,9 @@ bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat)
return !(battlerAbility == ABILITY_BIG_PECKS);
case STAT_SPEED:
// If AI is faster and doesn't have any mons left, lowering speed doesn't give any
return !(AI_IsFaster(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered)
&& CountUsablePartyMons(sBattler_AI) == 0
&& !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL));
return !(AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& CountUsablePartyMons(battlerAtk) == 0
&& !HasMoveEffect(battlerAtk, EFFECT_ELECTRO_BALL));
case STAT_ACC:
return !(battlerAbility == ABILITY_KEEN_EYE || (B_ILLUMINATE_EFFECT >= GEN_9 && battlerAbility == ABILITY_ILLUMINATE));
}
@ -2491,7 +2492,7 @@ bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move)
case EFFECT_SOLAR_BEAM:
case EFFECT_TWO_TURNS_ATTACK:
return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB
|| (AI_GetWeather(AI_DATA) & GetMoveTwoTurnAttackWeather(move)));
|| (AI_GetWeather() & GetMoveTwoTurnAttackWeather(move)));
default:
return FALSE;
}
@ -2603,7 +2604,7 @@ static u32 GetWeatherDamage(u32 battlerId)
u32 ability = AI_DATA->abilities[battlerId];
u32 holdEffect = AI_DATA->holdEffects[battlerId];
u32 damage = 0;
u32 weather = AI_GetWeather(AI_DATA);
u32 weather = AI_GetWeather();
if (!weather)
return 0;
@ -3007,7 +3008,7 @@ bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move,
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability)
{
if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|| (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move))
|| (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, AI_DATA->abilities[battlerAtk], move))
|| IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN)
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
@ -3297,7 +3298,7 @@ bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect)
{
case EFFECT_AURORA_VEIL:
// Use only in Hail and only if AI doesn't already have Reflect, Light Screen or Aurora Veil itself active.
if ((AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_SNOW))
if ((AI_GetWeather() & (B_WEATHER_HAIL | B_WEATHER_SNOW))
&& !(gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL)))
return TRUE;
break;
@ -3562,7 +3563,7 @@ s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct Battl
AI_THINKING_STRUCT->saved[battlerAtk].saved = FALSE;
}
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather(AI_DATA), rollType);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE, AI_GetWeather(), rollType);
// restores original gBattleMon struct
FreeRestoreBattleMons(savedBattleMons);
@ -4123,7 +4124,7 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st
u32 partnerAbility;
u32 partnerHoldEffect = aiData->holdEffects[battlerAtkPartner];
if (DoesBattlerIgnoreAbilityChecks(aiData->abilities[battlerAtk], move))
if (DoesBattlerIgnoreAbilityChecks(battlerAtk, aiData->abilities[battlerAtk], move))
partnerAbility = ABILITY_NONE;
else
partnerAbility = aiData->abilities[battlerAtkPartner];

View File

@ -199,7 +199,7 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler)
gBattleStruct->palaceFlags &= (1 << MAX_BATTLERS_COUNT) - 1;
gBattleStruct->palaceFlags |= (selectedMoves << MAX_BATTLERS_COUNT);
BattleAI_SetupAIData(selectedMoves, battler);
chosenMoveId = BattleAI_ChooseMoveOrAction();
chosenMoveId = BattleAI_ChooseMoveOrAction(battler);
}
// If no moves matched the selected group, pick a new move from groups the Pokémon has

View File

@ -4191,12 +4191,11 @@ static void HandleTurnActionSelectionState(void)
AI_DATA->aiCalcInProgress = TRUE;
// Setup battler data
sBattler_AI = battler;
BattleAI_SetupAIData(0xF, sBattler_AI);
BattleAI_SetupAIData(0xF, battler);
SetupAISwitchingData(battler, isAiRisky);
// Do scoring
gBattleStruct->aiMoveOrAction[battler] = BattleAI_ChooseMoveOrAction();
gBattleStruct->aiMoveOrAction[battler] = BattleAI_ChooseMoveOrAction(battler);
AI_DATA->aiCalcInProgress = FALSE;
}
// fallthrough