Removes duplicate AI ability func (#7045)

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
Alex 2025-06-09 11:30:16 +02:00 committed by GitHub
parent f4ff5e6d26
commit fd856e5068
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 29 additions and 39 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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); }