diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index 3617be910ff..f30759fd247 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -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 diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 44aa9a9ce6b..6ea96601687 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -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); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index cadf627e203..95e0e3ef5f7 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -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); } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index e90423a7960..c341fb5175d 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -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; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dbb5aa84146..3f0b86fcd1e 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -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]; diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 945fa660ca2..a71ee9c94f6 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -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 diff --git a/src/battle_main.c b/src/battle_main.c index 59f36ab1e13..3360bd35157 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -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