From 38dcb3c66cd1a3998bb21af166adc0736357ad7a Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Wed, 13 Sep 2023 17:28:26 +0200 Subject: [PATCH] ai weather optimization --- data/scripts/debug.inc | 1 + include/battle.h | 2 + include/battle_ai_main.h | 2 +- include/battle_ai_util.h | 256 ++++++++++++------------- include/battle_util.h | 2 +- src/battle_ai_main.c | 40 ++-- src/battle_ai_util.c | 395 ++++++++++++++++++++------------------- src/battle_main.c | 6 +- src/battle_util.c | 23 +-- 9 files changed, 369 insertions(+), 358 deletions(-) diff --git a/data/scripts/debug.inc b/data/scripts/debug.inc index 64b7e1dd01..8e09deb5e6 100644 --- a/data/scripts/debug.inc +++ b/data/scripts/debug.inc @@ -70,6 +70,7 @@ Debug_BoxFilledMessage_Text: .string "Storage boxes filled!$" Debug_Script_1:: + multi_fixed_2_vs_2 TRAINER_WALLACE, NULL, TRAINER_JUAN_5, NULL, TRAINER_STEVEN, TRAINER_BACK_PIC_STEVEN end Debug_Script_2:: diff --git a/include/battle.h b/include/battle.h index ef88d3dc79..a906d75cd7 100644 --- a/include/battle.h +++ b/include/battle.h @@ -277,6 +277,7 @@ struct AIPartyData // Opposing battlers - party mons. u8 count[NUM_BATTLE_SIDES]; }; +// Ai Data used when deciding which move to use, computed only once before each turn's start. struct AiLogicData { u16 abilities[MAX_BATTLERS_COUNT]; @@ -293,6 +294,7 @@ struct AiLogicData u8 moveLimitations[MAX_BATTLERS_COUNT]; bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler. u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch. + bool8 weatherHasEffect; // WEATHER_HAS_EFFECT, so it doesn't have to be used all the time }; struct AI_ThinkingStruct diff --git a/include/battle_ai_main.h b/include/battle_ai_main.h index f8eb2b77ba..1bf670cdd4 100644 --- a/include/battle_ai_main.h +++ b/include/battle_ai_main.h @@ -27,7 +27,7 @@ u8 BattleAI_ChooseMoveOrAction(void); void Ai_InitPartyStruct(void); void Ai_UpdateSwitchInData(u32 battler); void Ai_UpdateFaintData(u32 battler); -void SetAiLogicDataForTurn(void); +void SetAiLogicDataForTurn(struct AiLogicData *aiData); extern u8 sBattler_AI; diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 854146ecd0..e3bd6cd518 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -9,184 +9,184 @@ #define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER)) -bool32 AI_RandLessThan(u8 val); +bool32 AI_RandLessThan(u32 val); bool32 IsAiVsAiBattle(void); bool32 BattlerHasAi(u32 battlerId); bool32 IsAiBattlerAware(u32 battlerId); -void ClearBattlerMoveHistory(u8 battlerId); +void ClearBattlerMoveHistory(u32 battlerId); void RecordLastUsedMoveBy(u32 battlerId, u32 move); -void RecordKnownMove(u8 battlerId, u32 move); -void RecordAbilityBattle(u8 battlerId, u16 abilityId); -void ClearBattlerAbilityHistory(u8 battlerId); -void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); -void ClearBattlerItemEffectHistory(u8 battlerId); +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); -u16 GetAIChosenMove(u8 battlerId); +u16 GetAIChosenMove(u32 battlerId); u32 GetTotalBaseStat(u32 species); bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler); -bool32 AtMaxHp(u8 battler); -u32 GetHealthPercentage(u8 battler); -bool32 IsBattlerTrapped(u8 battler, bool8 switching); +bool32 AtMaxHp(u32 battler); +u32 GetHealthPercentage(u32 battler); +bool32 IsBattlerTrapped(u32 battler, bool32 switching); u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered); bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk); -bool32 CanMoveFaintBattler(u16 move, u32 battlerDef, u32 battlerAtk, u8 nHits); +bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits); bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); u16 AI_GetHoldEffect(u32 battlerId); -u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u16 move); -bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); -bool32 AI_WeatherHasEffect(void); -bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u8 numHits); -bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u8 index, u8 numHits); -bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags); -bool32 AI_IsBattlerGrounded(u8 battlerId); -bool32 HasDamagingMove(u8 battlerId); -bool32 HasDamagingMoveOfType(u8 battlerId, u8 type); -u32 GetBattlerSecondaryDamage(u8 battlerId); -bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); -bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability); -bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move); -bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u8 moveIndex); +u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u32 move); +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); u32 GetBattlerSideSpeedAverage(u32 battler); -bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u16 move, s32 damage); -bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u16 move, u8 healPercent); -bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u16 moveEffect); -bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 moveIndex); +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); bool32 IsRecycleEncouragedItem(u16 item); bool32 ShouldRestoreHpBerry(u32 battlerAtk, u16 item); bool32 IsStatBoostingBerry(u16 item); -bool32 CanKnockOffItem(u8 battler, u16 item); -bool32 IsAbilityOfRating(u16 ability, s8 rating); -s8 GetAbilityRating(u16 ability); +bool32 CanKnockOffItem(u32 battler, u16 item); +bool32 IsAbilityOfRating(u32 ability, s8 rating); +s8 GetAbilityRating(u32 ability); bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability); -bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move); -u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move); +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move); +u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move); bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u16 chosenMove); // stat stage checks -bool32 AnyStatIsRaised(u8 battlerId); -bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat); -bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat); -bool32 AreBattlersStatsMaxed(u8 battler); -bool32 BattlerHasAnyStatRaised(u8 battlerId); -u32 CountPositiveStatStages(u8 battlerId); -u32 CountNegativeStatStages(u8 battlerId); -bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u16 defAbility); +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); // move checks -bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); +bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower); -s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower); +s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather); u32 GetNoOfHitsToKO(u32 dmg, s32 hp); void SetMoveDamageResult(u32 battlerAtk, u16 *moves); u32 GetMoveDamageResult(u32 battlerAtk, u32 battlerDef, u32 moveIndex); u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef); -uq4_12_t AI_GetTypeEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef); -u32 AI_GetMoveEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef); +uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef); +u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef); u16 *GetMovesArray(u32 battler); -bool32 IsConfusionMoveEffect(u16 moveEffect); +bool32 IsConfusionMoveEffect(u32 moveEffect); bool32 HasMove(u32 battlerId, u32 move); bool32 HasOnlyMovesWithSplit(u32 battlerId, u32 split, bool32 onlyOffensive); bool32 HasMoveWithSplit(u32 battler, u32 split); -bool32 HasMoveWithType(u32 battler, u8 type); -bool32 HasMoveWithTypeAndSplit(u32 battler, u8 type, u8 split); -bool32 HasMoveEffect(u32 battlerId, u16 moveEffect); -bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect); -bool32 IsAromaVeilProtectedMove(u16 move); -bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect); -bool32 IsStatLoweringMoveEffect(u16 moveEffect); -bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility); -bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u16 move); -bool32 IsHazardMoveEffect(u16 moveEffect); -bool32 MoveCallsOtherMove(u16 move); -bool32 MoveRequiresRecharging(u16 move); -bool32 IsEncoreEncouragedEffect(u16 moveEffect); -void ProtectChecks(u32 battlerAtk, u32 battlerDef, u16 move, u16 predictedMove, s32 *score); -bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect); -bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect); -bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect); -bool32 ShouldSetRain(u32 battlerAtk, u16 ability, u16 holdEffect); -bool32 ShouldSetSun(u32 battlerAtk, u16 atkAbility, u16 holdEffect); +bool32 HasMoveWithType(u32 battler, u32 type); +bool32 HasMoveWithTypeAndSplit(u32 battler, u32 type, u32 split); +bool32 HasMoveEffect(u32 battlerId, u32 moveEffect); +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 MoveCallsOtherMove(u32 move); +bool32 MoveRequiresRecharging(u32 move); +bool32 IsEncoreEncouragedEffect(u32 moveEffect); +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 IsHealingMoveEffect(u16 effect); +bool32 IsHealingMoveEffect(u32 effect); bool32 HasHealingEffect(u32 battler); -bool32 IsTrappingMoveEffect(u16 effect); -bool32 HasTrappingMoveEffect(u8 battler); -bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u16 move); -bool32 HasThawingMove(u8 battler); -bool32 IsStatRaisingEffect(u16 effect); -bool32 IsStatLoweringEffect(u16 effect); -bool32 IsStatRaisingEffect(u16 effect); -bool32 IsAttackBoostMoveEffect(u16 effect); -bool32 IsUngroundingEffect(u16 effect); -bool32 IsSemiInvulnerable(u32 battlerDef, u16 move); -bool32 HasSoundMove(u8 battler); -bool32 HasHighCritRatioMove(u8 battler); -bool32 HasMagicCoatAffectedMove(u8 battler); -bool32 HasSnatchAffectedMove(u8 battler); +bool32 IsTrappingMoveEffect(u32 effect); +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 IsStatRaisingEffect(u32 effect); +bool32 IsAttackBoostMoveEffect(u32 effect); +bool32 IsUngroundingEffect(u32 effect); +bool32 IsSemiInvulnerable(u32 battlerDef, u32 move); +bool32 HasSoundMove(u32 battler); +bool32 HasHighCritRatioMove(u32 battler); +bool32 HasMagicCoatAffectedMove(u32 battler); +bool32 HasSnatchAffectedMove(u32 battler); // status checks -bool32 AI_CanBeBurned(u8 battler, u16 ability); -bool32 AI_CanGetFrostbite(u8 battler, u16 ability); -bool32 AI_CanBeConfused(u8 battler, u16 ability); -bool32 AI_CanSleep(u8 battler, u16 ability); -bool32 IsBattlerIncapacitated(u8 battler, u16 ability); -bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 ShouldPoisonSelf(u8 battler, u16 ability); -bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 ShouldBurnSelf(u8 battler, u16 ability); -bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u16 defAbility); -bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof); -u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move); -bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u16 move); -bool32 IsWakeupTurn(u8 battler); -bool32 AI_IsBattlerAsleepOrComatose(u8 battlerId); +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); // partner logic #define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK)) -u16 GetAllyChosenMove(u8 battlerId); +u32 GetAllyChosenMove(u32 battlerId); bool32 IsValidDoubleBattle(u32 battlerAtk); bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef); -bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove); -bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u16 partnerMove); -bool32 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u16 partnerMove); -bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u16 partnerMove); -bool32 PartnerMoveIs(u32 battlerAtkPartner, u16 partnerMove, u16 moveCheck); -bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove); -bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u16 move); +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 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u32 partnerMove); +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); // party logic struct BattlePokemon *AllocSaveBattleMons(void); void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons); s32 AI_CalcPartyMonBestMoveDamage(u32 battlerAtk, u32 battlerDef, struct Pokemon *attackerMon, struct Pokemon *targetMon); -s32 CountUsablePartyMons(u8 battlerId); -bool32 IsPartyFullyHealedExceptBattler(u8 battler); -bool32 PartyHasMoveSplit(u8 battlerId, u8 split); -bool32 SideHasMoveSplit(u8 battlerId, u8 split); +s32 CountUsablePartyMons(u32 battlerId); +bool32 IsPartyFullyHealedExceptBattler(u32 battler); +bool32 PartyHasMoveSplit(u32 battlerId, u32 split); +bool32 SideHasMoveSplit(u32 battlerId, u32 split); // score increases -void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s32 *score); -void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); -void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); -void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); -void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); -void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); -void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score); +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); #endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_util.h b/include/battle_util.h index 16b33ad0ec..6b155665da 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -172,7 +172,7 @@ u32 GetBattlerWeight(u32 battler); u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer); u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); -s32 CalculateMoveDamageWithEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, bool32 isCrit); +s32 CalculateMoveDamageWithEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, bool32 isCrit, u32 weather); uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities); uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef); uq4_12_t GetTypeModifier(u32 atkType, u32 defType); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 86db71e9ab..96e2928bff 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -350,14 +350,15 @@ static void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); } -static void SetBattlerAiMovesData(u32 battlerAtk, u32 battlersCount) +static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u32 battlersCount) { - u32 battlerDef, i; + u32 battlerDef, i, weather; u16 *moves; // Simulate dmg for both ai controlled mons and for player controlled mons. SaveBattlerData(battlerAtk); moves = GetMovesArray(battlerAtk); + weather = AI_GetWeather(aiData); for (battlerDef = 0; battlerDef < battlersCount; battlerDef++) { if (battlerAtk == battlerDef) @@ -373,28 +374,29 @@ static void SetBattlerAiMovesData(u32 battlerAtk, u32 battlersCount) if (move != 0 && move != 0xFFFF //&& gBattleMoves[move].power != 0 /* we want to get effectiveness of status moves */ - && !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) { - dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE); + && !(aiData->moveLimitations[battlerAtk] & gBitTable[i])) { + dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather); } - AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg; - AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness; + aiData->simulatedDmg[battlerAtk][battlerDef][i] = dmg; + aiData->effectiveness[battlerAtk][battlerDef][i] = effectiveness; } } SetMoveDamageResult(battlerAtk, moves); } -void SetAiLogicDataForTurn(void) +void SetAiLogicDataForTurn(struct AiLogicData *aiData) { u32 battlerAtk, battlersCount; - memset(AI_DATA, 0, sizeof(struct AiLogicData)); - + memset(aiData, 0, sizeof(struct AiLogicData)); if (!(gBattleTypeFlags & BATTLE_TYPE_HAS_AI) && !IsWildMonSmart()) return; + // Set delay timer to count how long it takes for AI to choose action/move gBattleStruct->aiDelayTimer = gMain.vblankCounter1; + aiData->weatherHasEffect = WEATHER_HAS_EFFECT; // get/assume all battler data and simulate AI damage battlersCount = gBattlersCount; for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++) @@ -402,8 +404,8 @@ void SetAiLogicDataForTurn(void) if (!IsBattlerAlive(battlerAtk)) continue; - SetBattlerAiData(battlerAtk, AI_DATA); - SetBattlerAiMovesData(battlerAtk, battlersCount); + SetBattlerAiData(battlerAtk, aiData); + SetBattlerAiMovesData(aiData, battlerAtk, battlersCount); } } @@ -891,7 +893,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score) RETURN_SCORE_MINUS(10); break; case ABILITY_LEAF_GUARD: - if (AI_WeatherHasEffect() && (gBattleWeather & B_WEATHER_SUN) + if ((AI_GetWeather(AI_DATA) & B_WEATHER_SUN) && AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_UTILITY_UMBRELLA && IsNonVolatileStatusMoveEffect(moveEffect)) RETURN_SCORE_MINUS(10); @@ -971,7 +973,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score) if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(battlerAtk, move)) return 0; // Can't even select heal blocked move // primal weather check - if (WEATHER_HAS_EFFECT) + if (gBattleWeather && WEATHER_HAS_EFFECT) { if (gBattleWeather & B_WEATHER_PRIMAL_ANY) { @@ -1848,7 +1850,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score) case EFFECT_MORNING_SUN: case EFFECT_SYNTHESIS: case EFFECT_MOONLIGHT: - if (AI_WeatherHasEffect() && (gBattleWeather & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL))) + if ((AI_GetWeather(AI_DATA) & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL))) score -= 3; else if (AtMaxHp(battlerAtk)) score -= 10; @@ -2124,7 +2126,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score) break; case EFFECT_SOLAR_BEAM: if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB - || (AI_WeatherHasEffect() && gBattleWeather & B_WEATHER_SUN && AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA)) + || ((AI_GetWeather(AI_DATA) & B_WEATHER_SUN) && AI_DATA->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA)) break; if (CanTargetFaintAi(battlerDef, battlerAtk)) //Attacker can be knocked out score -= 4; @@ -4354,17 +4356,17 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score score += 3; break; case HOLD_EFFECT_UTILITY_UMBRELLA: - if (AI_DATA->abilities[battlerAtk] != ABILITY_SOLAR_POWER && AI_DATA->abilities[battlerAtk] != ABILITY_DRY_SKIN && AI_WeatherHasEffect()) + if (AI_DATA->abilities[battlerAtk] != ABILITY_SOLAR_POWER && AI_DATA->abilities[battlerAtk] != ABILITY_DRY_SKIN) { switch (AI_DATA->abilities[battlerDef]) { case ABILITY_SWIFT_SWIM: - if (gBattleWeather & B_WEATHER_RAIN) + if (AI_GetWeather(AI_DATA) & B_WEATHER_RAIN) score += 3; // Slow 'em down break; case ABILITY_CHLOROPHYLL: case ABILITY_FLOWER_GIFT: - if (gBattleWeather & B_WEATHER_SUN) + if (AI_GetWeather(AI_DATA) & B_WEATHER_SUN) score += 3; // Slow 'em down break; } @@ -4901,7 +4903,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score } break; case EFFECT_SHORE_UP: - if (AI_WeatherHasEffect() && (gBattleWeather & B_WEATHER_SANDSTORM) + if ((AI_GetWeather(AI_DATA) & B_WEATHER_SANDSTORM) && ShouldRecover(battlerAtk, battlerDef, move, 67)) score += 3; else if (ShouldRecover(battlerAtk, battlerDef, move, 50)) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index e8bf3bab4c..5b9a42d9a9 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -419,12 +419,12 @@ static const u16 sOtherMoveCallingMoves[] = }; // Functions -u16 GetAIChosenMove(u8 battlerId) +u16 GetAIChosenMove(u32 battlerId) { return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]); } -bool32 AI_RandLessThan(u8 val) +bool32 AI_RandLessThan(u32 val) { if ((Random() % 0xFF) < val) return TRUE; @@ -465,7 +465,7 @@ bool32 IsAiBattlerAware(u32 battlerId) return BattlerHasAi(battlerId); } -void ClearBattlerMoveHistory(u8 battlerId) +void ClearBattlerMoveHistory(u32 battlerId) { memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId])); memset(BATTLE_HISTORY->moveHistory[battlerId], 0, sizeof(BATTLE_HISTORY->moveHistory[battlerId])); @@ -481,7 +481,7 @@ void RecordLastUsedMoveBy(u32 battlerId, u32 move) BATTLE_HISTORY->moveHistory[battlerId][*index] = move; } -void RecordKnownMove(u8 battlerId, u32 move) +void RecordKnownMove(u32 battlerId, u32 move) { s32 i; for (i = 0; i < MAX_MON_MOVES; i++) @@ -497,24 +497,24 @@ void RecordKnownMove(u8 battlerId, u32 move) } } -void RecordAbilityBattle(u8 battlerId, u16 abilityId) +void RecordAbilityBattle(u32 battlerId, u32 abilityId) { BATTLE_HISTORY->abilities[battlerId] = abilityId; AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].ability = abilityId; } -void ClearBattlerAbilityHistory(u8 battlerId) +void ClearBattlerAbilityHistory(u32 battlerId) { BATTLE_HISTORY->abilities[battlerId] = ABILITY_NONE; } -void RecordItemEffectBattle(u8 battlerId, u8 itemEffect) +void RecordItemEffectBattle(u32 battlerId, u32 itemEffect) { BATTLE_HISTORY->itemEffects[battlerId] = itemEffect; AI_PARTY->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect = itemEffect; } -void ClearBattlerItemEffectHistory(u8 battlerId) +void ClearBattlerItemEffectHistory(u32 battlerId) { BATTLE_HISTORY->itemEffects[battlerId] = 0; } @@ -536,7 +536,7 @@ void SaveBattlerData(u32 battlerId) AI_THINKING_STRUCT->saved[battlerId].types[1] = gBattleMons[battlerId].type2; } -static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId) +static bool32 ShouldFailForIllusion(u32 illusionSpecies, u32 battlerId) { u32 i, j; @@ -546,7 +546,7 @@ static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId) // Don't fall for Illusion if the mon used a move it cannot know. for (i = 0; i < MAX_MON_MOVES; i++) { - u16 move = BATTLE_HISTORY->usedMoves[battlerId][i]; + u32 move = BATTLE_HISTORY->usedMoves[battlerId][i]; if (move == MOVE_NONE) continue; @@ -630,21 +630,21 @@ void RestoreBattlerData(u32 battlerId) gBattleMons[battlerId].type2 = AI_THINKING_STRUCT->saved[battlerId].types[1]; } -u32 GetHealthPercentage(u8 battlerId) +u32 GetHealthPercentage(u32 battlerId) { return (u32)((100 * gBattleMons[battlerId].hp) / gBattleMons[battlerId].maxHP); } -bool32 AtMaxHp(u8 battlerId) +bool32 AtMaxHp(u32 battlerId) { if (AI_DATA->hpPercents[battlerId] == 100) return TRUE; return FALSE; } -bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch) +bool32 IsBattlerTrapped(u32 battler, bool32 checkSwitch) { - u8 holdEffect = AI_DATA->holdEffects[battler]; + u32 holdEffect = AI_DATA->holdEffects[battler]; #if B_GHOSTS_ESCAPE >= GEN_6 if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) @@ -694,7 +694,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) } // move checks -bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect) +bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect) { if (ability == ABILITY_OVERCOAT #if B_POWDER_GRASS >= GEN_6 @@ -771,10 +771,10 @@ s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *type { SaveBattlerData(battlerAtk); SaveBattlerData(battlerDef); - AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower); + AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower, AI_GetWeather(AI_DATA)); } -s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) +s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather) { s32 dmg, moveType, critDmg, normalDmg, fixedBasePower, n; s8 critChance; @@ -817,8 +817,8 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes fixedBasePower = 0; break; } - normalDmg = CalculateMoveDamageWithEffectiveness(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, FALSE); - critDmg = CalculateMoveDamageWithEffectiveness(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, TRUE); + normalDmg = CalculateMoveDamageWithEffectiveness(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, FALSE, weather); + critDmg = CalculateMoveDamageWithEffectiveness(move, battlerAtk, battlerDef, moveType, fixedBasePower, effectivenessMultiplier, TRUE, weather); if (critChance == -1) dmg = normalDmg; @@ -944,11 +944,11 @@ void SetMoveDamageResult(u32 battlerAtk, u16 *moves) { s32 i, j, battlerDef, bestId, currId, hp, result; s32 moveDmgs[MAX_MON_MOVES]; - bool8 isNotConsidered[MAX_MON_MOVES]; + bool32 isNotConsidered[MAX_MON_MOVES]; for (i = 0; i < MAX_MON_MOVES; i++) { - u16 move = moves[i]; + u32 move = moves[i]; for (j = 0; sIgnoredPowerfulMoveEffects[j] != IGNORED_MOVES_END; j++) { if (gBattleMoves[move].effect == sIgnoredPowerfulMoveEffects[j]) @@ -1034,10 +1034,10 @@ u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef) return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; } -uq4_12_t AI_GetTypeEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef) +uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) { uq4_12_t typeEffectiveness; - u16 moveType; + u32 moveType; SaveBattlerData(battlerAtk); SaveBattlerData(battlerDef); @@ -1056,7 +1056,7 @@ uq4_12_t AI_GetTypeEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef) return typeEffectiveness; } -u32 AI_GetMoveEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef) +u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef) { gMoveResultFlags = 0; return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef)); @@ -1159,7 +1159,7 @@ bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk) // Check if AI mon has the means to faint the target with any of its moves. // If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects) -bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u8 numHits) +bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits) { s32 i, dmg; u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; @@ -1183,7 +1183,7 @@ bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u8 numHits) return FALSE; } -bool32 CanMoveFaintBattler(u16 move, u32 battlerDef, u32 battlerAtk, u8 nHits) +bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits) { s32 i, dmg; u8 effectiveness; @@ -1262,7 +1262,7 @@ s32 AI_GetAbility(u32 battlerId) // Else, guess the ability if (gSpeciesInfo[gBattleMons[battlerId].species].abilities[0] != ABILITY_NONE) { - u16 abilityGuess = ABILITY_NONE; + u32 abilityGuess = ABILITY_NONE; while (abilityGuess == ABILITY_NONE) { abilityGuess = gSpeciesInfo[gBattleMons[battlerId].species].abilities[Random() % NUM_ABILITY_SLOTS]; @@ -1296,7 +1296,7 @@ u16 AI_GetHoldEffect(u32 battlerId) return holdEffect; } -bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags) +bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags) { if (gStatuses3[battlerId] & STATUS3_SEMI_INVULNERABLE) return FALSE; @@ -1306,7 +1306,7 @@ bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags) } // different from IsBattlerGrounded in that we don't always know battler's hold effect or ability -bool32 AI_IsBattlerGrounded(u8 battlerId) +bool32 AI_IsBattlerGrounded(u32 battlerId) { u32 holdEffect = AI_DATA->holdEffects[battlerId]; @@ -1332,7 +1332,7 @@ bool32 AI_IsBattlerGrounded(u8 battlerId) return TRUE; } -bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) +bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move) { u32 i; @@ -1353,16 +1353,24 @@ bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move) return FALSE; } -bool32 AI_WeatherHasEffect(void) +static inline bool32 AI_WeatherHasEffect(struct AiLogicData *aiData) { - u32 i; if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return TRUE; // AI doesn't understand weather supression (handicap) - return WEATHER_HAS_EFFECT; // weather damping abilities are announced + return aiData->weatherHasEffect; // weather damping abilities are announced } -u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move) +u32 AI_GetWeather(struct AiLogicData *aiData) +{ + if (gBattleWeather == B_WEATHER_NONE) + return B_WEATHER_NONE; + if (!AI_WeatherHasEffect(aiData)) + return B_WEATHER_NONE; + return gBattleWeather; +} + +u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move) { u32 target; @@ -1372,7 +1380,7 @@ u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move) return gBattleMoves[move].target; } -bool32 IsAromaVeilProtectedMove(u16 move) +bool32 IsAromaVeilProtectedMove(u32 move) { u32 i; @@ -1390,7 +1398,7 @@ bool32 IsAromaVeilProtectedMove(u16 move) } } -bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect) +bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect) { switch (moveEffect) { @@ -1406,7 +1414,7 @@ bool32 IsNonVolatileStatusMoveEffect(u16 moveEffect) } } -bool32 IsConfusionMoveEffect(u16 moveEffect) +bool32 IsConfusionMoveEffect(u32 moveEffect) { switch (moveEffect) { @@ -1420,7 +1428,7 @@ bool32 IsConfusionMoveEffect(u16 moveEffect) } } -bool32 IsStatLoweringMoveEffect(u16 moveEffect) +bool32 IsStatLoweringMoveEffect(u32 moveEffect) { switch (moveEffect) { @@ -1444,7 +1452,7 @@ bool32 IsStatLoweringMoveEffect(u16 moveEffect) } } -bool32 IsHazardMoveEffect(u16 moveEffect) +bool32 IsHazardMoveEffect(u32 moveEffect) { switch (moveEffect) { @@ -1458,7 +1466,7 @@ bool32 IsHazardMoveEffect(u16 moveEffect) } } -bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) +bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility) { if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE) return FALSE; @@ -1471,13 +1479,13 @@ bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) return FALSE; } -u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u16 move) +u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u32 move) { return GetTotalAccuracy(battlerAtk, battlerDef, move, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]); } -bool32 IsSemiInvulnerable(u32 battlerDef, u16 move) +bool32 IsSemiInvulnerable(u32 battlerDef, u32 move) { if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) return TRUE; @@ -1491,8 +1499,9 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u16 move) return FALSE; } -bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u16 move) +bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move) { + u32 weather; if (IsSemiInvulnerable(battlerDef, move)) return FALSE; @@ -1511,14 +1520,14 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u16 move) #endif // discouraged from hitting - if (AI_WeatherHasEffect() && (gBattleWeather & B_WEATHER_SUN) + weather = AI_GetWeather(AI_DATA); + if ((weather & B_WEATHER_SUN) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) return FALSE; // increased accuracy but don't always hit - if ((AI_WeatherHasEffect() && - (((gBattleWeather & B_WEATHER_RAIN) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) - || (((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && move == MOVE_BLIZZARD)))) + if ((((weather & B_WEATHER_RAIN) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) + || (((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && move == MOVE_BLIZZARD))) || (gBattleMoves[move].effect == EFFECT_VITAL_THROW) #if B_MINIMIZE_DMG_ACC >= GEN_6 || ((gStatuses3[battlerDef] & STATUS3_MINIMIZED) && gBattleMoves[move].minimizeDoubleDamage) @@ -1531,7 +1540,7 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u16 move) return FALSE; } -bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move) +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) { u32 holdEffect = AI_DATA->holdEffects[battlerDef]; u32 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, move); @@ -1565,11 +1574,10 @@ bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbil return FALSE; } -bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect) +bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect) { - if (!AI_WeatherHasEffect()) - return FALSE; - else if (gBattleWeather & B_WEATHER_SANDSTORM) + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_SANDSTORM) return FALSE; if (ability == ABILITY_SAND_VEIL @@ -1589,11 +1597,10 @@ bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect) return FALSE; } -bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) +bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect) { - if (!AI_WeatherHasEffect()) - return FALSE; - else if (gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) + u32 weather = AI_GetWeather(AI_DATA); + if (weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) return FALSE; if (ability == ABILITY_SNOW_CLOAK @@ -1613,11 +1620,10 @@ bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) return FALSE; } -bool32 ShouldSetRain(u32 battlerAtk, u16 atkAbility, u16 holdEffect) +bool32 ShouldSetRain(u32 battlerAtk, u32 atkAbility, u32 holdEffect) { - if (!AI_WeatherHasEffect()) - return FALSE; - else if (gBattleWeather & B_WEATHER_RAIN) + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_RAIN) return FALSE; if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA @@ -1636,11 +1642,10 @@ bool32 ShouldSetRain(u32 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; } -bool32 ShouldSetSun(u32 battlerAtk, u16 atkAbility, u16 holdEffect) +bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect) { - if (!AI_WeatherHasEffect()) - return FALSE; - else if (gBattleWeather & B_WEATHER_SUN) + u32 weather = AI_GetWeather(AI_DATA); + if (weather & B_WEATHER_SUN) return FALSE; if (holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA @@ -1663,11 +1668,10 @@ bool32 ShouldSetSun(u32 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; } -bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect) +bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect) { - if (!AI_WeatherHasEffect()) - return FALSE; - else if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_HAIL)) + u32 weather = AI_GetWeather(AI_DATA); + if (weather & (B_WEATHER_SNOW | B_WEATHER_HAIL)) return FALSE; if (ability == ABILITY_SNOW_CLOAK @@ -1684,11 +1688,11 @@ bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect) return FALSE; } -void ProtectChecks(u32 battlerAtk, u32 battlerDef, u16 move, u16 predictedMove, s32 *score) +void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score) { // TODO more sophisticated logic - u16 predictedEffect = gBattleMoves[predictedMove].effect; - u8 defAbility = AI_DATA->abilities[battlerDef]; + u32 predictedEffect = gBattleMoves[predictedMove].effect; + u32 defAbility = AI_DATA->abilities[battlerDef]; u32 uses = gDisableStructs[battlerAtk].protectUses; /*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED)) @@ -1726,7 +1730,7 @@ void ProtectChecks(u32 battlerAtk, u32 battlerDef, u16 move, u16 predictedMove, } // stat stages -bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat) +bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat) { if ((gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE)) @@ -1743,7 +1747,7 @@ bool32 ShouldLowerStat(u8 battler, u16 battlerAbility, u8 stat) return FALSE; } -bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat) +bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat) { if ((gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) || (battlerAbility == ABILITY_CONTRARY && gBattleMons[battler].statStages[stat] > MIN_STAT_STAGE)) @@ -1751,7 +1755,7 @@ bool32 BattlerStatCanRise(u8 battler, u16 battlerAbility, u8 stat) return FALSE; } -bool32 AreBattlersStatsMaxed(u8 battlerId) +bool32 AreBattlersStatsMaxed(u32 battlerId) { u32 i; for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++) @@ -1762,7 +1766,7 @@ bool32 AreBattlersStatsMaxed(u8 battlerId) return TRUE; } -bool32 AnyStatIsRaised(u8 battlerId) +bool32 AnyStatIsRaised(u32 battlerId) { u32 i; @@ -1774,7 +1778,7 @@ bool32 AnyStatIsRaised(u8 battlerId) return FALSE; } -u32 CountPositiveStatStages(u8 battlerId) +u32 CountPositiveStatStages(u32 battlerId) { u32 count = 0; u32 i; @@ -1786,7 +1790,7 @@ u32 CountPositiveStatStages(u8 battlerId) return count; } -u32 CountNegativeStatStages(u8 battlerId) +u32 CountNegativeStatStages(u32 battlerId) { u32 count = 0; u32 i; @@ -1798,7 +1802,7 @@ u32 CountNegativeStatStages(u8 battlerId) return count; } -bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1815,7 +1819,7 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1832,7 +1836,7 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1847,7 +1851,7 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1863,7 +1867,7 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1879,7 +1883,7 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1894,7 +1898,7 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1909,7 +1913,7 @@ bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u16 defAbility) return FALSE; } -bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u8 index, u8 numHits) +bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits) { s32 dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][index]; @@ -1959,7 +1963,7 @@ bool32 HasMoveWithSplit(u32 battler, u32 split) return FALSE; } -bool32 HasMoveWithType(u32 battler, u8 type) +bool32 HasMoveWithType(u32 battler, u32 type) { s32 i; u16 *moves = GetMovesArray(battler); @@ -1973,7 +1977,7 @@ bool32 HasMoveWithType(u32 battler, u8 type) return FALSE; } -bool32 HasMoveEffect(u32 battlerId, u16 moveEffect) +bool32 HasMoveEffect(u32 battlerId, u32 moveEffect) { s32 i; u16 *moves = GetMovesArray(battlerId); @@ -2001,11 +2005,11 @@ bool32 HasMove(u32 battlerId, u32 move) return FALSE; } -bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect) +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect) { s32 i; u16 *moves = GetMovesArray(battlerAtk); - u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2030,7 +2034,7 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u8 accCheck, bool3 bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) { - u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; + u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u32 i; u16 *moves = GetMovesArray(battlerAtk); @@ -2048,7 +2052,7 @@ bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) return FALSE; } -bool32 IsHealingMoveEffect(u16 effect) +bool32 IsHealingMoveEffect(u32 effect) { switch (effect) { @@ -2084,7 +2088,7 @@ bool32 HasHealingEffect(u32 battlerId) return FALSE; } -bool32 IsTrappingMoveEffect(u16 effect) +bool32 IsTrappingMoveEffect(u32 effect) { switch (effect) { @@ -2099,7 +2103,7 @@ bool32 IsTrappingMoveEffect(u16 effect) } } -bool32 HasTrappingMoveEffect(u8 battler) +bool32 HasTrappingMoveEffect(u32 battler) { s32 i; u16 *moves = GetMovesArray(battler); @@ -2113,12 +2117,12 @@ bool32 HasTrappingMoveEffect(u8 battler) return FALSE; } -bool32 HasThawingMove(u8 battler) +bool32 HasThawingMove(u32 battler) { CHECK_MOVE_FLAG(thawsUser); } -bool32 IsUngroundingEffect(u16 effect) +bool32 IsUngroundingEffect(u32 effect) { switch (effect) { @@ -2130,7 +2134,7 @@ bool32 IsUngroundingEffect(u16 effect) } // for anger point -bool32 IsAttackBoostMoveEffect(u16 effect) +bool32 IsAttackBoostMoveEffect(u32 effect) { switch (effect) { @@ -2149,7 +2153,7 @@ bool32 IsAttackBoostMoveEffect(u16 effect) } } -bool32 IsStatRaisingEffect(u16 effect) +bool32 IsStatRaisingEffect(u32 effect) { switch (effect) { @@ -2195,7 +2199,7 @@ bool32 IsStatRaisingEffect(u16 effect) } } -bool32 IsStatLoweringEffect(u16 effect) +bool32 IsStatLoweringEffect(u32 effect) { // ignore other potentially-beneficial effects like defog, gravity switch (effect) @@ -2223,7 +2227,7 @@ bool32 IsStatLoweringEffect(u16 effect) } } -bool32 HasDamagingMove(u8 battlerId) +bool32 HasDamagingMove(u32 battlerId) { u32 i; u16 *moves = GetMovesArray(battlerId); @@ -2237,7 +2241,7 @@ bool32 HasDamagingMove(u8 battlerId) return FALSE; } -bool32 HasDamagingMoveOfType(u8 battlerId, u8 type) +bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) { s32 i; u16 *moves = GetMovesArray(battlerId); @@ -2252,27 +2256,27 @@ bool32 HasDamagingMoveOfType(u8 battlerId, u8 type) return FALSE; } -bool32 HasSoundMove(u8 battler) +bool32 HasSoundMove(u32 battler) { CHECK_MOVE_FLAG(soundMove); } -bool32 HasHighCritRatioMove(u8 battler) +bool32 HasHighCritRatioMove(u32 battler) { CHECK_MOVE_FLAG(highCritRatio); } -bool32 HasMagicCoatAffectedMove(u8 battler) +bool32 HasMagicCoatAffectedMove(u32 battler) { CHECK_MOVE_FLAG(magicCoatAffected); } -bool32 HasSnatchAffectedMove(u8 battler) +bool32 HasSnatchAffectedMove(u32 battler) { CHECK_MOVE_FLAG(snatchAffected); } -bool32 IsEncoreEncouragedEffect(u16 moveEffect) +bool32 IsEncoreEncouragedEffect(u32 moveEffect) { u32 i; @@ -2284,7 +2288,7 @@ bool32 IsEncoreEncouragedEffect(u16 moveEffect) return FALSE; } -bool32 MoveRequiresRecharging(u16 move) +bool32 MoveRequiresRecharging(u32 move) { u32 i; for (i = 0; i < ARRAY_COUNT(sRechargeMoves); i++) @@ -2295,7 +2299,7 @@ bool32 MoveRequiresRecharging(u16 move) return FALSE; } -bool32 MoveCallsOtherMove(u16 move) +bool32 MoveCallsOtherMove(u32 move) { u32 i; for (i = 0; i < ARRAY_COUNT(sOtherMoveCallingMoves); i++) @@ -2306,7 +2310,7 @@ bool32 MoveCallsOtherMove(u16 move) return FALSE; } -static u32 GetLeechSeedDamage(u8 battlerId) +static u32 GetLeechSeedDamage(u32 battlerId) { u32 damage = 0; if ((gStatuses3[battlerId] & STATUS3_LEECHSEED) @@ -2319,7 +2323,7 @@ static u32 GetLeechSeedDamage(u8 battlerId) return damage; } -static u32 GetNightmareDamage(u8 battlerId) +static u32 GetNightmareDamage(u32 battlerId) { u32 damage = 0; if ((gBattleMons[battlerId].status2 & STATUS2_NIGHTMARE) && gBattleMons[battlerId].status1 & STATUS1_SLEEP) @@ -2331,7 +2335,7 @@ static u32 GetNightmareDamage(u8 battlerId) return damage; } -static u32 GetCurseDamage(u8 battlerId) +static u32 GetCurseDamage(u32 battlerId) { u32 damage = 0; if (gBattleMons[battlerId].status2 & STATUS2_CURSED) @@ -2343,7 +2347,7 @@ static u32 GetCurseDamage(u8 battlerId) return damage; } -static u32 GetTrapDamage(u8 battlerId) +static u32 GetTrapDamage(u32 battlerId) { // ai has no knowledge about turns remaining u32 damage = 0; @@ -2366,7 +2370,7 @@ static u32 GetTrapDamage(u8 battlerId) return damage; } -static u32 GetPoisonDamage(u8 battlerId) +static u32 GetPoisonDamage(u32 battlerId) { u32 damage = 0; @@ -2391,7 +2395,7 @@ static u32 GetPoisonDamage(u8 battlerId) return damage; } -static bool32 BattlerAffectedBySandstorm(u8 battlerId, u16 ability) +static bool32 BattlerAffectedBySandstorm(u32 battlerId, u32 ability) { if (!IS_BATTLER_OF_TYPE(battlerId, TYPE_ROCK) && !IS_BATTLER_OF_TYPE(battlerId, TYPE_GROUND) @@ -2404,7 +2408,7 @@ static bool32 BattlerAffectedBySandstorm(u8 battlerId, u16 ability) return FALSE; } -static bool32 BattlerAffectedByHail(u8 battlerId, u16 ability) +static bool32 BattlerAffectedByHail(u32 battlerId, u32 ability) { if (!IS_BATTLER_OF_TYPE(battlerId, TYPE_ICE) && ability != ABILITY_SNOW_CLOAK @@ -2414,15 +2418,16 @@ static bool32 BattlerAffectedByHail(u8 battlerId, u16 ability) return FALSE; } -static u32 GetWeatherDamage(u8 battlerId) +static u32 GetWeatherDamage(u32 battlerId) { u32 ability = AI_DATA->abilities[battlerId]; u32 holdEffect = AI_DATA->holdEffects[battlerId]; u32 damage = 0; - if (!AI_WeatherHasEffect()) + u32 weather = AI_GetWeather(AI_DATA); + if (!weather) return 0; - if (gBattleWeather & B_WEATHER_SANDSTORM) + if (weather & B_WEATHER_SANDSTORM) { if (BattlerAffectedBySandstorm(battlerId, ability) && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) @@ -2433,7 +2438,7 @@ static u32 GetWeatherDamage(u8 battlerId) damage = 1; } } - if ((gBattleWeather & B_WEATHER_HAIL) && ability != ABILITY_ICE_BODY) + if ((weather & B_WEATHER_HAIL) && ability != ABILITY_ICE_BODY) { if (BattlerAffectedByHail(battlerId, ability) && !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER)) @@ -2447,7 +2452,7 @@ static u32 GetWeatherDamage(u8 battlerId) return damage; } -u32 GetBattlerSecondaryDamage(u8 battlerId) +u32 GetBattlerSecondaryDamage(u32 battlerId) { u32 secondaryDamage; @@ -2464,7 +2469,7 @@ u32 GetBattlerSecondaryDamage(u8 battlerId) return secondaryDamage; } -bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) +bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability) { if ((BattlerAffectedBySandstorm(battler, ability) || BattlerAffectedByHail(battler, ability)) && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) @@ -2473,7 +2478,7 @@ bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability) return FALSE; } -bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability) +bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability) { if (GetBattlerSecondaryDamage(battler) != 0 && gBattleMons[battler].hp <= gBattleMons[battler].maxHP / 16) @@ -2481,9 +2486,9 @@ bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability) return FALSE; } -static bool32 AnyUsefulStatIsRaised(u8 battler) +static bool32 AnyUsefulStatIsRaised(u32 battler) { - u8 statId; + u32 statId; for (statId = STAT_ATK; statId < NUM_BATTLE_STATS; statId++) { @@ -2508,7 +2513,7 @@ static bool32 AnyUsefulStatIsRaised(u8 battler) return FALSE; } -struct Pokemon *GetPartyBattlerPartyData(u8 battlerId, u8 switchBattler) +struct Pokemon *GetPartyBattlerPartyData(u32 battlerId, u32 switchBattler) { struct Pokemon *mon; if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) @@ -2518,16 +2523,16 @@ struct Pokemon *GetPartyBattlerPartyData(u8 battlerId, u8 switchBattler) return mon; } -static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler) +static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) { struct Pokemon *mon = GetPartyBattlerPartyData(currBattler, switchBattler); - u16 ability = GetMonAbility(mon); // we know our own party data - u16 holdEffect; + u32 ability = GetMonAbility(mon); // we know our own party data + u32 holdEffect; u16 species = GetMonData(mon, MON_DATA_SPECIES); u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); s32 hazardDamage = 0; - u8 type1 = gSpeciesInfo[species].types[0]; - u8 type2 = gSpeciesInfo[species].types[1]; + u32 type1 = gSpeciesInfo[species].types[0]; + u32 type2 = gSpeciesInfo[species].types[1]; u32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); if (flags == 0) @@ -2549,7 +2554,7 @@ static bool32 PartyBattlerShouldAvoidHazards(u8 currBattler, u8 switchBattler) && ability != ABILITY_LEVITATE && holdEffect != HOLD_EFFECT_AIR_BALLOON) || holdEffect == HOLD_EFFECT_IRON_BALL || gFieldStatuses & STATUS_FIELD_GRAVITY)) { - u8 spikesDmg = maxHp / ((5 - gSideTimers[GetBattlerSide(currBattler)].spikesAmount) * 2); + s32 spikesDmg = maxHp / ((5 - gSideTimers[GetBattlerSide(currBattler)].spikesAmount) * 2); if (spikesDmg == 0) spikesDmg = 1; hazardDamage += spikesDmg; @@ -2565,11 +2570,11 @@ enum { CAN_TRY_PIVOT, PIVOT, }; -bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 moveIndex) +bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex) { - bool8 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class + bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class bool32 shouldSwitch; - u8 battlerToSwitch; + u32 battlerToSwitch; shouldSwitch = ShouldSwitch(battlerAtk); battlerToSwitch = *(gBattleStruct->AI_monToSwitchIntoId + battlerAtk); @@ -2627,8 +2632,8 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) { - bool8 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); - bool8 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); + bool32 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool32 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); //Pivot if attacking stats are bad if (physMoveInMoveset && !specMoveInMoveset) @@ -2710,8 +2715,8 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 /*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE) { - bool8 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); - bool8 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); + bool32 physMoveInMoveset = PhysicalMoveInMoveset(battlerAtk); + bool32 specMoveInMoveset = SpecialMoveInMoveset(battlerAtk); //Pivot if attacking stats are bad if (physMoveInMoveset && !specMoveInMoveset) @@ -2741,7 +2746,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 return DONT_PIVOT; } -bool32 CanKnockOffItem(u8 battler, u16 item) +bool32 CanKnockOffItem(u32 battler, u16 item) { if (item == ITEM_NONE) return FALSE; @@ -2767,7 +2772,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item) } // status checks -bool32 IsBattlerIncapacitated(u8 battler, u16 ability) +bool32 IsBattlerIncapacitated(u32 battler, u32 ability) { if ((gBattleMons[battler].status1 & STATUS1_FREEZE) && !HasThawingMove(battler)) return TRUE; // if battler has thawing move we assume they will definitely use it, and thus being frozen should be neglected @@ -2781,7 +2786,7 @@ bool32 IsBattlerIncapacitated(u8 battler, u16 ability) return FALSE; } -bool32 AI_CanSleep(u8 battler, u16 ability) +bool32 AI_CanSleep(u32 battler, u32 ability) { if (ability == ABILITY_INSOMNIA || ability == ABILITY_VITAL_SPIRIT @@ -2794,7 +2799,7 @@ bool32 AI_CanSleep(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) { if (!AI_CanSleep(battlerDef, defAbility) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) @@ -2803,7 +2808,7 @@ bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move return TRUE; } -static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget) +static bool32 AI_CanPoisonType(u32 battlerAttacker, u32 battlerTarget) { return ((AI_DATA->abilities[battlerAttacker] == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS) || !(IS_BATTLER_OF_TYPE(battlerTarget, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL))); @@ -2811,7 +2816,7 @@ static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget) static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef) { - u16 ability = AI_DATA->abilities[battlerDef]; + u32 ability = AI_DATA->abilities[battlerDef]; if (!(AI_CanPoisonType(battlerAtk, battlerDef)) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD @@ -2826,7 +2831,7 @@ static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef) return TRUE; } -bool32 ShouldPoisonSelf(u8 battler, u16 ability) +bool32 ShouldPoisonSelf(u32 battler, u32 ability) { if (AI_CanBePoisoned(battler, battler) && ( ability == ABILITY_MARVEL_SCALE @@ -2841,7 +2846,7 @@ bool32 ShouldPoisonSelf(u8 battler, u16 ability) return FALSE; } -bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) { if (!AI_CanBePoisoned(battlerAtk, battlerDef) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2856,7 +2861,7 @@ bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u1 return TRUE; } -static bool32 AI_CanBeParalyzed(u8 battler, u16 ability) +static bool32 AI_CanBeParalyzed(u32 battler, u32 ability) { if (ability == ABILITY_LIMBER || ability == ABILITY_COMATOSE @@ -2867,7 +2872,7 @@ static bool32 AI_CanBeParalyzed(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove) { if (!AI_CanBeParalyzed(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2878,7 +2883,7 @@ bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, return TRUE; } -bool32 AI_CanBeConfused(u8 battler, u16 ability) +bool32 AI_CanBeConfused(u32 battler, u32 ability) { if ((gBattleMons[battler].status2 & STATUS2_CONFUSION) || (ability == ABILITY_OWN_TEMPO) @@ -2887,7 +2892,7 @@ bool32 AI_CanBeConfused(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!AI_CanBeConfused(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2901,7 +2906,7 @@ bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battler return TRUE; } -bool32 AI_CanBeBurned(u8 battler, u16 ability) +bool32 AI_CanBeBurned(u32 battler, u32 ability) { if (ability == ABILITY_WATER_VEIL || ability == ABILITY_WATER_BUBBLE @@ -2914,7 +2919,7 @@ bool32 AI_CanBeBurned(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanGetFrostbite(u8 battler, u16 ability) +bool32 AI_CanGetFrostbite(u32 battler, u32 ability) { if (ability == ABILITY_MAGMA_ARMOR || ability == ABILITY_COMATOSE @@ -2926,7 +2931,7 @@ bool32 AI_CanGetFrostbite(u8 battler, u16 ability) return TRUE; } -bool32 ShouldBurnSelf(u8 battler, u16 ability) +bool32 ShouldBurnSelf(u32 battler, u32 ability) { if (AI_CanBeBurned(battler, ability) && ( ability == ABILITY_QUICK_FEET @@ -2940,7 +2945,7 @@ bool32 ShouldBurnSelf(u8 battler, u16 ability) return FALSE; } -bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!AI_CanBeBurned(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2952,7 +2957,7 @@ bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtk return TRUE; } -bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!AI_CanGetFrostbite(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2964,7 +2969,7 @@ bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 b return TRUE; } -bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u16 defAbility) +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) { if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) || AI_GetMoveEffectiveness(AI_THINKING_STRUCT->moveConsidered, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2975,7 +2980,7 @@ bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u16 defAbility) return TRUE; } -u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move) +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move) { if (((AI_DATA->abilities[battlerAtk] != ABILITY_MOLD_BREAKER && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) || AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_COVERT_CLOAK @@ -2996,7 +3001,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbi return 0; // don't try to flinch } -bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u16 move) +bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move) { if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef])) return TRUE; // battler is taking secondary damage with low HP @@ -3010,7 +3015,7 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u16 move) return FALSE; } -bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u16 move) +bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move) { if (!gDisableStructs[battlerAtk].isFirstTurn || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS @@ -3035,7 +3040,7 @@ static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) return BATTLE_HISTORY->moveHistory[battlerId][index]; } -bool32 IsWakeupTurn(u8 battler) +bool32 IsWakeupTurn(u32 battler) { // Check if rest was used 2 turns ago if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && FindMoveUsedXTurnsAgo(battler, 2) == MOVE_REST) @@ -3044,7 +3049,7 @@ bool32 IsWakeupTurn(u8 battler) return FALSE; } -bool32 AnyPartyMemberStatused(u8 battlerId, bool32 checkSoundproof) +bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof) { struct Pokemon *party; u32 i; @@ -3087,7 +3092,7 @@ u32 GetBattlerSideSpeedAverage(u32 battler) return (speed1 + speed2) / numBattlersAlive; } -bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u8 moveIndex) +bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex) { if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left @@ -3101,12 +3106,12 @@ bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u8 mov return TRUE; } -bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u16 move, s32 damage) +bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage) { if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { // using item or user goes first - u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; + u32 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument; s32 healDmg = (healPercent * damage) / 100; if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) @@ -3128,7 +3133,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u16 move, s32 damage) return FALSE; } -bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u16 move, u8 healPercent) +bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent) { if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { @@ -3147,14 +3152,14 @@ bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u16 move, u8 healPercent) return FALSE; } -bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u16 moveEffect) +bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect) { - u8 atkSide = GetBattlerSide(battlerAtk); + u32 atkSide = GetBattlerSide(battlerAtk); switch (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 ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) + if ((AI_GetWeather(AI_DATA) & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && !(gSideStatuses[atkSide] & (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL))) return TRUE; break; @@ -3184,9 +3189,9 @@ bool32 IsValidDoubleBattle(u32 battlerAtk) return FALSE; } -u16 GetAllyChosenMove(u8 battlerId) +u32 GetAllyChosenMove(u32 battlerId) { - u8 partnerBattler = BATTLE_PARTNER(battlerId); + u32 partnerBattler = BATTLE_PARTNER(battlerId); if (!IsBattlerAlive(partnerBattler) || !IsAiBattlerAware(partnerBattler)) return MOVE_NONE; @@ -3197,7 +3202,7 @@ u16 GetAllyChosenMove(u8 battlerId) } //PARTNER_MOVE_EFFECT_IS_SAME -bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove) +bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3212,7 +3217,7 @@ bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u16 } //PARTNER_MOVE_EFFECT_IS_SAME_NO_TARGET -bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3224,7 +3229,7 @@ bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u16 move, u1 } //PARTNER_MOVE_EFFECT_IS_STATUS_SAME_TARGET -bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u16 partnerMove) +bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3242,7 +3247,7 @@ bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef } //PARTNER_MOVE_EFFECT_IS_WEATHER -bool32 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u16 partnerMove) +bool32 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3259,7 +3264,7 @@ bool32 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u16 partnerMove) } //PARTNER_MOVE_EFFECT_IS_TERRAIN -bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u16 partnerMove) +bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3275,7 +3280,7 @@ bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u16 partnerMove) } //PARTNER_MOVE_IS_TAILWIND_TRICKROOM -bool32 PartnerMoveIs(u32 battlerAtkPartner, u16 partnerMove, u16 moveCheck) +bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck) { if (!IsDoubleBattle()) return FALSE; @@ -3286,7 +3291,7 @@ bool32 PartnerMoveIs(u32 battlerAtkPartner, u16 partnerMove, u16 moveCheck) } //PARTNER_MOVE_IS_SAME -bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove) +bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3297,7 +3302,7 @@ bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u16 mo } //PARTNER_MOVE_IS_SAME_NO_TARGET -bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3306,7 +3311,7 @@ bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u16 move, u16 partnerMov return FALSE; } -bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u16 move) +bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move) { u32 i; u32 firstId, lastId; @@ -3420,7 +3425,7 @@ s32 AI_CalcPartyMonBestMoveDamage(u32 battlerAtk, u32 battlerDef, struct Pokemon return dmg; } -s32 CountUsablePartyMons(u8 battlerId) +s32 CountUsablePartyMons(u32 battlerId) { s32 battlerOnField1, battlerOnField2, i, ret; struct Pokemon *party; @@ -3456,7 +3461,7 @@ s32 CountUsablePartyMons(u8 battlerId) return ret; } -bool32 IsPartyFullyHealedExceptBattler(u8 battlerId) +bool32 IsPartyFullyHealedExceptBattler(u32 battlerId) { struct Pokemon *party; u32 i; @@ -3478,9 +3483,9 @@ bool32 IsPartyFullyHealedExceptBattler(u8 battlerId) return TRUE; } -bool32 PartyHasMoveSplit(u8 battlerId, u8 split) +bool32 PartyHasMoveSplit(u32 battlerId, u32 split) { - u8 firstId, lastId; + u32 firstId, lastId; struct Pokemon *party = GetBattlerParty(battlerId); u32 i, j; @@ -3491,7 +3496,7 @@ bool32 PartyHasMoveSplit(u8 battlerId, u8 split) for (j = 0; j < MAX_MON_MOVES; j++) { - u16 move = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); + u32 move = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL); u16 pp = GetMonData(&party[i], MON_DATA_PP1 + j, NULL); if (pp > 0 && move != MOVE_NONE) @@ -3506,7 +3511,7 @@ bool32 PartyHasMoveSplit(u8 battlerId, u8 split) return FALSE; } -bool32 SideHasMoveSplit(u8 battlerId, u8 split) +bool32 SideHasMoveSplit(u32 battlerId, u32 split) { if (IsDoubleBattle()) { @@ -3521,14 +3526,14 @@ bool32 SideHasMoveSplit(u8 battlerId, u8 split) return FALSE; } -bool32 IsAbilityOfRating(u16 ability, s8 rating) +bool32 IsAbilityOfRating(u32 ability, s8 rating) { if (sAiAbilityRatings[ability] >= rating) return TRUE; return FALSE; } -s8 GetAbilityRating(u16 ability) +s8 GetAbilityRating(u32 ability) { return sAiAbilityRatings[ability]; } @@ -3599,7 +3604,7 @@ bool32 IsRecycleEncouragedItem(u16 item) // score increases #define STAT_UP_2_STAGE 8 #define STAT_UP_STAGE 10 -void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s32 *score) +void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score) { if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) return; @@ -3679,7 +3684,7 @@ void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s32 *score) } } -void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PSN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) @@ -3703,7 +3708,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) } } -void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_BRN || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) @@ -3723,7 +3728,7 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) } } -void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_PAR || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) @@ -3745,7 +3750,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) } } -void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) @@ -3764,7 +3769,7 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) (*score)++; } -void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if (((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_CONFUSION || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) @@ -3783,7 +3788,7 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score } } -void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score) +void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; @@ -3802,7 +3807,7 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u16 move, s32 *score } } -bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move) +bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move) { if (gBattleMoves[move].makesContact && ability != ABILITY_LONG_REACH @@ -3843,7 +3848,7 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u16 chosenMove) return FALSE; } -bool32 AI_IsBattlerAsleepOrComatose(u8 battlerId) +bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId) { return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerId] == ABILITY_COMATOSE; } diff --git a/src/battle_main.c b/src/battle_main.c index 979c4a18bb..c4e3fa6b0e 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3724,7 +3724,7 @@ static void DoBattleIntro(void) gBattleStruct->switchInAbilitiesCounter = 0; gBattleStruct->switchInItemsCounter = 0; gBattleStruct->overworldWeatherDone = FALSE; - SetAiLogicDataForTurn(); // get assumed abilities, hold effects, etc of all battlers + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield. gBattleMainFunc = TryDoEventsBeforeFirstTurn; } @@ -3857,7 +3857,7 @@ static void TryDoEventsBeforeFirstTurn(void) gRandomTurnNumber = Random(); - SetAiLogicDataForTurn(); // get assumed abilities, hold effects, etc of all battlers + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers if (gBattleTypeFlags & BATTLE_TYPE_ARENA) { @@ -3949,7 +3949,7 @@ void BattleTurnPassed(void) *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); - SetAiLogicDataForTurn(); // get assumed abilities, hold effects, etc of all battlers + SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; gRandomTurnNumber = Random(); diff --git a/src/battle_util.c b/src/battle_util.c index 544b29e0c3..380aec8012 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9759,10 +9759,9 @@ static inline uq4_12_t GetOtherModifiers(u32 move, u32 moveType, u32 battlerAtk, } while (0) static inline s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, - bool32 isCrit, bool32 randomFactor, bool32 updateFlags, uq4_12_t typeEffectivenessModifier) + bool32 isCrit, bool32 randomFactor, bool32 updateFlags, uq4_12_t typeEffectivenessModifier, u32 weather) { s32 dmg; - u32 weather; u32 userFinalAttack; u32 targetFinalDefense; u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); @@ -9773,12 +9772,6 @@ static inline s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 if (typeEffectivenessModifier == UQ_4_12(0.0)) return 0; - // Store weather in a local variable, so there's no need to call WEATHER_HAS_EFFECT every time weather is checked. - if (gBattleWeather == B_WEATHER_NONE || !WEATHER_HAS_EFFECT) - weather = B_WEATHER_NONE; - else - weather = gBattleWeather; - if (fixedBasePower) gBattleMovePower = fixedBasePower; else @@ -9812,16 +9805,24 @@ static inline s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 #undef DAMAGE_APPLY_MODIFIER +static u32 GetWeather(void) +{ + if (gBattleWeather == B_WEATHER_NONE || !WEATHER_HAS_EFFECT) + return B_WEATHER_NONE; + else + return gBattleWeather; +} + s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags) { return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, randomFactor, - updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags)); + updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags), GetWeather()); } // for AI so that typeEffectivenessModifier is calculated only once -s32 CalculateMoveDamageWithEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, bool32 isCrit) +s32 CalculateMoveDamageWithEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier, bool32 isCrit, u32 weather) { - return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, FALSE, FALSE, typeEffectivenessModifier); + return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, FALSE, FALSE, typeEffectivenessModifier, weather); } static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 moveType, u32 battlerDef, u32 defType, u32 battlerAtk, bool32 recordAbilities)