sovereignx/include/battle_ai_util.h

195 lines
11 KiB
C
Raw Normal View History

#ifndef GUARD_BATTLE_AI_UTIL_H
#define GUARD_BATTLE_AI_UTIL_H
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
2020-12-13 22:02:21 +00:00
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
2023-09-13 16:28:26 +01:00
bool32 AI_RandLessThan(u32 val);
2023-08-09 14:57:22 +01:00
bool32 IsAiVsAiBattle(void);
2023-03-28 15:38:48 +01:00
bool32 BattlerHasAi(u32 battlerId);
2023-04-10 16:36:17 +01:00
bool32 IsAiBattlerAware(u32 battlerId);
2023-09-13 16:28:26 +01:00
void ClearBattlerMoveHistory(u32 battlerId);
2020-12-11 15:05:00 +00:00
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
void RecordAllMoves(u32 battler);
2023-09-13 16:28:26 +01:00
void RecordKnownMove(u32 battlerId, u32 move);
void RecordAbilityBattle(u32 battlerId, u32 abilityId);
void ClearBattlerAbilityHistory(u32 battlerId);
void RecordItemEffectBattle(u32 battlerId, u32 itemEffect);
void ClearBattlerItemEffectHistory(u32 battlerId);
void SaveBattlerData(u32 battlerId);
void SetBattlerData(u32 battlerId);
void RestoreBattlerData(u32 battlerId);
2023-09-24 10:06:45 +01:00
u32 GetAIChosenMove(u32 battlerId);
2020-12-20 21:47:20 +00:00
u32 GetTotalBaseStat(u32 species);
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
2023-09-13 16:28:26 +01:00
bool32 AtMaxHp(u32 battler);
u32 GetHealthPercentage(u32 battler);
bool32 IsBattlerTrapped(u32 battler, bool32 switching);
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);
u32 GetBestDmgMoveFromTarget(u32 battlerAtk, u32 battlerDef);
2023-09-14 10:05:00 +01:00
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);
2023-09-13 16:28:26 +01:00
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
u32 AI_GetWeather(struct AiLogicData *aiData);
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits);
bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits);
bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags);
bool32 AI_IsBattlerGrounded(u32 battlerId);
bool32 HasDamagingMove(u32 battlerId);
bool32 HasDamagingMoveOfType(u32 battlerId, u32 type);
u32 GetBattlerSecondaryDamage(u32 battlerId);
bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability);
bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability);
bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex);
2023-09-13 13:04:25 +01:00
u32 GetBattlerSideSpeedAverage(u32 battler);
2023-09-13 16:28:26 +01:00
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage);
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent);
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect);
bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
2023-09-24 10:06:45 +01:00
bool32 IsRecycleEncouragedItem(u32 item);
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
bool32 IsStatBoostingBerry(u32 item);
bool32 CanKnockOffItem(u32 battler, u32 item);
2023-09-13 16:28:26 +01:00
bool32 IsAbilityOfRating(u32 ability, s8 rating);
2021-11-04 14:43:33 +00:00
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
2023-09-13 16:28:26 +01:00
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move);
u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move);
2023-09-24 10:06:45 +01:00
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove);
2020-12-13 22:02:21 +00:00
// stat stage checks
2023-09-13 16:28:26 +01:00
bool32 AnyStatIsRaised(u32 battlerId);
bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat);
bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat);
bool32 AreBattlersStatsMaxed(u32 battler);
bool32 BattlerHasAnyStatRaised(u32 battlerId);
u32 CountPositiveStatStages(u32 battlerId);
u32 CountNegativeStatStages(u32 battlerId);
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility);
2020-12-13 22:02:21 +00:00
// move checks
2023-09-13 16:28:26 +01:00
bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect);
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category);
s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower);
2023-09-13 16:28:26 +01:00
s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather);
bool32 AI_IsDamagedByRecoil(u32 battler);
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef);
u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex);
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef);
2023-09-13 16:28:26 +01:00
uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
2020-12-13 22:02:21 +00:00
u16 *GetMovesArray(u32 battler);
2023-09-13 16:28:26 +01:00
bool32 IsConfusionMoveEffect(u32 moveEffect);
2020-12-20 04:58:23 +00:00
bool32 HasMove(u32 battlerId, u32 move);
bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensive);
bool32 HasMoveWithCategory(u32 battler, u32 category);
2023-09-13 16:28:26 +01:00
bool32 HasMoveWithType(u32 battler, u32 type);
bool32 HasMoveEffect(u32 battlerId, u32 moveEffect);
bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument);
2023-12-30 08:42:53 +00:00
bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect);
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception);
2023-09-13 16:28:26 +01:00
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
bool32 IsAromaVeilProtectedMove(u32 move);
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
bool32 IsStatLoweringMoveEffect(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMoveEffect(u32 moveEffect);
bool32 IsChargingMove(u32 battlerAtk, u32 effect);
2023-09-13 16:28:26 +01:00
void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score);
bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect);
bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect);
bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect);
bool32 ShouldSetRain(u32 battlerAtk, u32 ability, u32 holdEffect);
bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect);
bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef);
bool32 IsHealingMove(u32 move);
2020-12-20 04:58:23 +00:00
bool32 HasHealingEffect(u32 battler);
bool32 IsTrappingMove(u32 move);
2023-09-13 16:28:26 +01:00
bool32 HasTrappingMoveEffect(u32 battler);
bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 HasThawingMove(u32 battler);
bool32 IsStatRaisingEffect(u32 effect);
bool32 IsStatLoweringEffect(u32 effect);
bool32 IsAttackBoostMoveEffect(u32 effect);
bool32 IsUngroundingEffect(u32 effect);
bool32 IsSemiInvulnerable(u32 battlerDef, u32 move);
bool32 HasSubstituteIgnoringMove(u32 battler);
2023-09-13 16:28:26 +01:00
bool32 HasHighCritRatioMove(u32 battler);
bool32 HasMagicCoatAffectedMove(u32 battler);
bool32 HasSnatchAffectedMove(u32 battler);
2020-12-13 22:02:21 +00:00
// status checks
2023-09-13 16:28:26 +01:00
bool32 AI_CanBeBurned(u32 battler, u32 ability);
bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
bool32 AI_CanBeConfused(u32 battler, u32 ability);
bool32 AI_CanSleep(u32 battler, u32 ability);
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 ShouldPoisonSelf(u32 battler, u32 ability);
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 ShouldBurnSelf(u32 battler, u32 ability);
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility);
bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof);
u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsWakeupTurn(u32 battler);
bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId);
2020-12-13 22:02:21 +00:00
// partner logic
2023-09-13 13:04:25 +01:00
#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK))
2023-09-13 16:28:26 +01:00
u32 GetAllyChosenMove(u32 battlerId);
bool32 IsValidDoubleBattle(u32 battlerAtk);
bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef);
2023-09-13 16:28:26 +01:00
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove);
bool32 IsMoveEffectWeather(u32 move);
2023-09-13 16:28:26 +01:00
bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove);
bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck);
bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move);
2020-12-16 04:57:33 +00:00
// party logic
2023-07-18 11:01:25 +01:00
struct BattlePokemon *AllocSaveBattleMons(void);
void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons);
2023-09-13 16:28:26 +01:00
s32 CountUsablePartyMons(u32 battlerId);
bool32 IsPartyFullyHealedExceptBattler(u32 battler);
bool32 PartyHasMoveCategory(u32 battlerId, u32 category);
bool32 SideHasMoveCategory(u32 battlerId, u32 category);
2020-12-20 04:58:23 +00:00
// score increases
2023-09-13 16:28:26 +01:00
void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score);
void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
2020-12-16 04:57:33 +00:00
Smarter SwitchAI Mon Choices | HasBadOdds Switch Check (#3253) * SwitchAI makes much smarter mon choices * Add HasHadOdds check to ShouldSwitch decision * Remove early return * Rework Baton Pass check as per discussion with Alex * Forgot to adjust a comment * Don't program before breakfast lol (if / else if fix) * Switch AI_CalcDamage for AI_DATA->simulatedDmg in HasBadOdds Thanks Alex! :D * Typo in a hitToKO comparison * Remove and replace AI_CalcPartyMonBestMoveDamage and IsAiPartyMonOHKOBy from https://github.com/rh-hideout/pokeemerald-expansion/pull/3146 See https://discord.com/channels/419213663107416084/1144447521960251472 for details * Major refactor, new struct, switchin considers damage / healing from hazards / status / held item / weather * Forgot Snow exists and heals Ice Body, haven't played Switch games lol * (https://github.com/rh-hideout/pokeemerald-expansion/commit/766a1a27a7298e50dd89c5fecc1989b3dd8b8ce3) Compatibility, use new struct field instead of function call * Fixing oversight from previous upstream merge * Improve TSpikes handling to make GetSwitchinHazardDamage more applicable Small fixes: - EFFECT_EXPLOSION typo (!= to ==) - Order of if statements near bestResistEffective - Spacing of terms in big HasBadOdds if statements * Forgot to uncomment blocks disabled for debugging what turned out to be vanilla behaviour lol * Remove another holdover from debugging, sorry :/ * Lastly, undoing my debug trainer * Type matchup based on species type rather than current type Suggested by BLourenco on Discord, the idea is that a mon that's had its type affected by a move like Soak will still have moves as though it was its regular typing, and so prioritizing the temporary typing wouldn't be ideal. https://discord.com/channels/419213663107416084/1144447521960251472/1146644578141736970 * gActiveBattler upcoming merge fixes * Egg changes part 1 * Egg changes part 2, just need to address EWRAM still * Move SwitchinCandidate struct to AiLogicData * Consider Steel type when checking TSpikes * Comment about CanBePoisoned compatibility * Changes for Egg's 2nd review * Put period back in comment, whoops lol * Latest upcoming merge fixes * Missed a few u32 updates * Combine GetBestMonIntegrate functions / flags, some modularization * Fix merge error * Make modern fixes * Two tests done, two to go * Accidentally pushed reference test, removing it * Type matchup switching tests * Tests for defensive vs offense switches --------- Co-authored-by: DizzyEggg <jajkodizzy@wp.pl>
2023-11-11 13:37:35 +00:00
s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool8 isPartyMonAttacker);
2024-01-11 19:01:33 +00:00
s32 AI_CheckMoveEffects(u32 battlerAtk, u32 battlerDef, u32 move, s32 score, struct AiLogicData *aiData, u32 predictedMove, bool32 isDoubleBattle);
s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle);
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
s32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
Smarter SwitchAI Mon Choices | HasBadOdds Switch Check (#3253) * SwitchAI makes much smarter mon choices * Add HasHadOdds check to ShouldSwitch decision * Remove early return * Rework Baton Pass check as per discussion with Alex * Forgot to adjust a comment * Don't program before breakfast lol (if / else if fix) * Switch AI_CalcDamage for AI_DATA->simulatedDmg in HasBadOdds Thanks Alex! :D * Typo in a hitToKO comparison * Remove and replace AI_CalcPartyMonBestMoveDamage and IsAiPartyMonOHKOBy from https://github.com/rh-hideout/pokeemerald-expansion/pull/3146 See https://discord.com/channels/419213663107416084/1144447521960251472 for details * Major refactor, new struct, switchin considers damage / healing from hazards / status / held item / weather * Forgot Snow exists and heals Ice Body, haven't played Switch games lol * (https://github.com/rh-hideout/pokeemerald-expansion/commit/766a1a27a7298e50dd89c5fecc1989b3dd8b8ce3) Compatibility, use new struct field instead of function call * Fixing oversight from previous upstream merge * Improve TSpikes handling to make GetSwitchinHazardDamage more applicable Small fixes: - EFFECT_EXPLOSION typo (!= to ==) - Order of if statements near bestResistEffective - Spacing of terms in big HasBadOdds if statements * Forgot to uncomment blocks disabled for debugging what turned out to be vanilla behaviour lol * Remove another holdover from debugging, sorry :/ * Lastly, undoing my debug trainer * Type matchup based on species type rather than current type Suggested by BLourenco on Discord, the idea is that a mon that's had its type affected by a move like Soak will still have moves as though it was its regular typing, and so prioritizing the temporary typing wouldn't be ideal. https://discord.com/channels/419213663107416084/1144447521960251472/1146644578141736970 * gActiveBattler upcoming merge fixes * Egg changes part 1 * Egg changes part 2, just need to address EWRAM still * Move SwitchinCandidate struct to AiLogicData * Consider Steel type when checking TSpikes * Comment about CanBePoisoned compatibility * Changes for Egg's 2nd review * Put period back in comment, whoops lol * Latest upcoming merge fixes * Missed a few u32 updates * Combine GetBestMonIntegrate functions / flags, some modularization * Fix merge error * Make modern fixes * Two tests done, two to go * Accidentally pushed reference test, removing it * Type matchup switching tests * Tests for defensive vs offense switches --------- Co-authored-by: DizzyEggg <jajkodizzy@wp.pl>
2023-11-11 13:37:35 +00:00
#endif //GUARD_BATTLE_AI_UTIL_H