From fd856e50683364fdbbff3f9dbf84b8e1e54a8036 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:30:16 +0200 Subject: [PATCH] Removes duplicate AI ability func (#7045) Co-authored-by: Bassoonian --- include/battle.h | 13 +++++-------- include/battle_ai_util.h | 5 ++--- include/battle_util.h | 2 ++ src/battle_ai_switch_items.c | 6 +++--- src/battle_ai_util.c | 18 +----------------- src/battle_util.c | 22 +++++++++++++++------- test/battle/ai/ai_switching.c | 2 +- 7 files changed, 29 insertions(+), 39 deletions(-) diff --git a/include/battle.h b/include/battle.h index 77da1c4f0a..086c9b25be 100644 --- a/include/battle.h +++ b/include/battle.h @@ -760,10 +760,9 @@ struct BattleStruct u16 commanderActive[MAX_BATTLERS_COUNT]; u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party - u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects - s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg - u8 cheekPouchActivated:1; - u8 padding2:3; + u16 opponentMonCanTera:6; + u16 opponentMonCanDynamax:6; + u16 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn @@ -777,13 +776,11 @@ struct BattleStruct u8 calculatedSpreadMoveAccuracy:1; u8 printedStrongWindsWeakenedAttack:1; u8 numSpreadTargets:2; - u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY u8 noTargetPresent:1; + u8 cheekPouchActivated:1; + s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; - u16 opponentMonCanTera:6; - u16 opponentMonCanDynamax:6; - u16 padding:4; }; struct AiBattleData diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 75a08f5b4a..0a70acce1f 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -38,7 +38,7 @@ enum WeatherState WEATHER_INACTIVE_AND_BLOCKED, }; -enum AIConsiderGimmick +enum AIConsiderGimmick { NO_GIMMICK, USE_GIMMICK, @@ -115,9 +115,8 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); bool32 AI_MoveMakesContact(u32 ability, enum ItemHoldEffect holdEffect, u32 move); bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove); void SetAIUsingGimmick(u32 battler, enum AIConsiderGimmick use); -bool32 IsAIUsingGimmick(u32 battler); +bool32 IsAIUsingGimmick(u32 battler); void DecideTerastal(u32 battler); -u32 AI_GetBattlerAbility(u32 battler); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); diff --git a/include/battle_util.h b/include/battle_util.h index 4870330361..53de080665 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -243,6 +243,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 bool32 TryPrimalReversion(u32 battler); bool32 IsNeutralizingGasOnField(void); bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability); +u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler); +u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker); u32 GetBattlerAbility(u32 battler); u32 IsAbilityOnSide(u32 battler, u32 ability); u32 IsAbilityOnOpposingSide(u32 battler, u32 ability); diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index fdfefd7238..6aa5bf16b6 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -628,7 +628,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) monAbility = GetMonAbility(&party[i]); - if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && monAbility == ABILITY_TRACE)) + if (CanAbilityTrapOpponent(monAbility, opposingBattler) || (CanAbilityTrapOpponent(gAiLogicData->abilities[opposingBattler], opposingBattler) && monAbility == ABILITY_TRACE)) { // If mon in slot i is the most suitable switchin candidate, then it's a trapper than wins 1v1 if (i == gAiLogicData->mostSuitableMonId[battler] && RandomPercentage(RNG_AI_SWITCH_FREE_TURN, GetSwitchChance(SHOULD_SWITCH_FREE_TURN))) @@ -1990,7 +1990,7 @@ static inline bool32 IsFreeSwitch(enum SwitchType switchType, u32 battlerSwitchi return TRUE; if (gAiLogicData->ejectPackSwitch) { - u32 opposingAbility = AI_GetBattlerAbility(opposingBattler); + u32 opposingAbility = GetBattlerAbilityIgnoreMoldBreaker(opposingBattler); // If faster, not a free switch; likely lowered own stats if (!movedSecond && opposingAbility != ABILITY_INTIMIDATE && opposingAbility != ABILITY_SUPERSWEET_SYRUP) // Intimidate triggers switches before turn starts return FALSE; @@ -2160,7 +2160,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, // If mon can trap if ((CanAbilityTrapOpponent(gAiLogicData->switchinCandidate.battleMon.ability, opposingBattler) - || (CanAbilityTrapOpponent(AI_GetBattlerAbility(opposingBattler), opposingBattler) && gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRACE)) + || (CanAbilityTrapOpponent(gAiLogicData->abilities[opposingBattler], opposingBattler) && gAiLogicData->switchinCandidate.battleMon.ability == ABILITY_TRACE)) && CountUsablePartyMons(opposingBattler) > 0 && canSwitchinWin1v1) trapperId = i; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index c9363e344a..dbbd30c68a 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1419,28 +1419,12 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability) return FALSE; } -u32 AI_GetBattlerAbility(u32 battler) -{ - if (gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed) - return gBattleMons[battler].ability; - - if (gStatuses3[battler] & STATUS3_GASTRO_ACID) - return ABILITY_NONE; - - if (IsNeutralizingGasOnField() - && gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS - && GetBattlerHoldEffectIgnoreAbility(battler, TRUE) != HOLD_EFFECT_ABILITY_SHIELD) - return ABILITY_NONE; - - return gBattleMons[battler].ability; -} - // does NOT include ability suppression checks s32 AI_DecideKnownAbilityForTurn(u32 battlerId) { u32 validAbilities[NUM_ABILITY_SLOTS]; u8 i, numValidAbilities = 0; - u32 knownAbility = AI_GetBattlerAbility(battlerId); + u32 knownAbility = GetBattlerAbilityIgnoreMoldBreaker(battlerId); // during ai checking for mold breaker could lead to inaccuracies u32 indexAbility; u32 abilityAiRatings[NUM_ABILITY_SLOTS] = {0}; diff --git a/src/battle_util.c b/src/battle_util.c index d6034a1478..7efebde7c2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5000,10 +5000,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITYEFFECT_IMMUNITY: - gBattleStruct->bypassMoldBreakerChecks = TRUE; for (battler = 0; battler < gBattlersCount; battler++) { - switch (GetBattlerAbility(battler)) + switch (GetBattlerAbilityIgnoreMoldBreaker(battler)) { case ABILITY_IMMUNITY: case ABILITY_PASTEL_VEIL: @@ -5089,7 +5088,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 return effect; } } - gBattleStruct->bypassMoldBreakerChecks = FALSE; break; case ABILITYEFFECT_SYNCHRONIZE: if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONIZE_EFFECT)) @@ -5330,9 +5328,9 @@ bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) || (ability == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gCurrentMove))); } -static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 ability, u32 hasAbilityShield) +static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 ability, u32 hasAbilityShield, u32 ignoreMoldBreaker) { - if (hasAbilityShield || gBattleStruct->bypassMoldBreakerChecks) + if (hasAbilityShield || ignoreMoldBreaker) return FALSE; return ((IsMoldBreakerTypeAbility(battlerAtk, ability) || MoveIgnoresTargetAbility(gCurrentMove)) @@ -5343,7 +5341,17 @@ static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 && gCurrentTurnActionNumber < gBattlersCount); } +u32 GetBattlerAbilityIgnoreMoldBreaker(u32 battler) +{ + return GetBattlerAbilityInternal(battler, TRUE); +} + u32 GetBattlerAbility(u32 battler) +{ + return GetBattlerAbilityInternal(battler, FALSE); +} + +u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker) { bool32 hasAbilityShield = GetBattlerHoldEffectIgnoreAbility(battler, TRUE) == HOLD_EFFECT_ABILITY_SHIELD; bool32 abilityCantBeSuppressed = gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed; @@ -5356,7 +5364,7 @@ u32 GetBattlerAbility(u32 battler) && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; - if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield)) + if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield, ignoreMoldBreaker)) return ABILITY_NONE; return gBattleMons[battler].ability; @@ -5370,7 +5378,7 @@ u32 GetBattlerAbility(u32 battler) && gBattleMons[battler].ability != ABILITY_NEUTRALIZING_GAS) return ABILITY_NONE; - if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield)) + if (CanBreakThroughAbility(gBattlerAttacker, battler, gBattleMons[gBattlerAttacker].ability, hasAbilityShield, ignoreMoldBreaker)) return ABILITY_NONE; return gBattleMons[battler].ability; diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index d1378812f1..7a7fd64864 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -388,7 +388,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize GIVEN { ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); ASSUME(MoveHasAdditionalEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_MINUS_2) == TRUE); - AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_OMNISCIENT); PLAYER(SPECIES_STARAPTOR) { Level(30); Ability(ABILITY_INTIMIDATE); Moves(MOVE_WING_ATTACK, MOVE_BOOMBURST); Speed(5); SpAttack(50); } OPPONENT(SPECIES_PONYTA) { Level(1); Item(ITEM_EJECT_PACK); Moves(MOVE_OVERHEAT); Speed(6); } // Forces switchout OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_IRON_HEAD); Speed(4); SpDefense(50); }