From 44bd830d2a88a3b298ea44f1a2ee5589fcf85ec1 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 12 Sep 2023 23:20:09 +0200 Subject: [PATCH] optimize dmg calc and ai dmg calc to reduce lag --- include/battle_ai_util.h | 128 ++++++++++++------------- include/battle_main.h | 2 +- include/battle_script_commands.h | 8 +- include/battle_util.h | 16 ++-- include/config/debug.h | 2 +- src/battle_ai_main.c | 92 ++++++++---------- src/battle_ai_util.c | 158 +++++++++++++++---------------- src/battle_main.c | 2 +- src/battle_script_commands.c | 11 ++- src/battle_util.c | 114 +++++++++++----------- 10 files changed, 259 insertions(+), 274 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 5f077fe0c..ecd3c43cc 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -8,7 +8,6 @@ #define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) bool32 AI_RandLessThan(u8 val); -void RecordLastUsedMoveByTarget(void); bool32 IsAiVsAiBattle(void); bool32 BattlerHasAi(u32 battlerId); bool32 IsAiBattlerAware(u32 battlerId); @@ -19,9 +18,9 @@ void RecordAbilityBattle(u8 battlerId, u16 abilityId); void ClearBattlerAbilityHistory(u8 battlerId); void RecordItemEffectBattle(u8 battlerId, u8 itemEffect); void ClearBattlerItemEffectHistory(u8 battlerId); -void SaveBattlerData(u8 battlerId); -void SetBattlerData(u8 battlerId); -void RestoreBattlerData(u8 battlerId); +void SaveBattlerData(u32 battlerId); +void SetBattlerData(u32 battlerId); +void RestoreBattlerData(u32 battlerId); u16 GetAIChosenMove(u8 battlerId); bool32 WillAIStrikeFirst(void); @@ -31,16 +30,16 @@ bool32 AtMaxHp(u8 battler); u32 GetHealthPercentage(u8 battler); bool32 IsBattlerTrapped(u8 battler, bool8 switching); u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 consideredMove); -bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk); -bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits); -bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod); +bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk); +bool32 CanMoveFaintBattler(u16 move, u32 battlerDef, u32 battlerAtk, u8 nHits); +bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod); s32 AI_GetAbility(u32 battlerId); u16 AI_GetHoldEffect(u32 battlerId); -u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move); +u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 AI_WeatherHasEffect(void); -bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits); -bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); +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); @@ -48,15 +47,15 @@ bool32 HasDamagingMoveOfType(u8 battlerId, u8 type); u32 GetBattlerSecondaryDamage(u8 battlerId); bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability); bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability); -bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move); -bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex); +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move); +bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u8 moveIndex); u16 GetBattlerSideSpeedAverage(u8 battler); -bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage); -bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent); -bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect); -bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex); +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 IsRecycleEncouragedItem(u16 item); -bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item); +bool32 ShouldRestoreHpBerry(u32 battlerAtk, u16 item); bool32 IsStatBoostingBerry(u16 item); bool32 CanKnockOffItem(u8 battler, u16 item); bool32 IsAbilityOfRating(u16 ability, s8 rating); @@ -64,7 +63,7 @@ s8 GetAbilityRating(u16 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 ShouldUseZMove(u8 activeId, u8 targetId, u16 chosenMove); +bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u16 chosenMove); // stat stage checks bool32 AnyStatIsRaised(u8 battlerId); @@ -74,23 +73,24 @@ bool32 AreBattlersStatsMaxed(u8 battler); bool32 BattlerHasAnyStatRaised(u8 battlerId); u32 CountPositiveStatStages(u8 battlerId); u32 CountNegativeStatStages(u8 battlerId); -bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility); -bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility); +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); // move checks bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect); bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split); -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *effectiveness, bool32 considerZPower); +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); u32 GetNoOfHitsToKO(u32 dmg, s32 hp); u8 GetMoveDamageResult(u16 move); -u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef); -uq4_12_t AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); -u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef); +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); u16 *GetMovesArray(u32 battler); bool32 IsConfusionMoveEffect(u16 moveEffect); bool32 HasMove(u32 battlerId, u32 move); @@ -99,35 +99,35 @@ 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(u8, u8, u8, bool32, u16, u16, u16, u16); +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(u8 battlerAtk, u8 battlerDef, u16 move); +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(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score); +void ProtectChecks(u32 battlerAtk, u32 battlerDef, u16 move, u16 predictedMove, s16 *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(u8 battlerAtk, u16 ability, u16 holdEffect); -bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect); -bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef); +bool32 ShouldSetRain(u32 battlerAtk, u16 ability, u16 holdEffect); +bool32 ShouldSetSun(u32 battlerAtk, u16 atkAbility, u16 holdEffect); +bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef); bool32 IsHealingMoveEffect(u16 effect); bool32 HasHealingEffect(u32 battler); bool32 IsTrappingMoveEffect(u16 effect); bool32 HasTrappingMoveEffect(u8 battler); -bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move); +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(u8 battlerDef, u16 move); +bool32 IsSemiInvulnerable(u32 battlerDef, u16 move); bool32 HasSoundMove(u8 battler); bool32 HasHighCritRatioMove(u8 battler); bool32 HasMagicCoatAffectedMove(u8 battler); @@ -139,34 +139,34 @@ 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(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove); bool32 ShouldPoisonSelf(u8 battler, u16 ability); -bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove); -bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); +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(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 AI_CanGiveFrostbite(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility); +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(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move); -bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move); +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); // partner logic u16 GetAllyChosenMove(u8 battlerId); -bool32 IsValidDoubleBattle(u8 battlerAtk); -bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef); -bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); -bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, u16 partnerMove); -bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove); -bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove); -bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck); -bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove); -bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove); -bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move); +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); // party logic struct BattlePokemon *AllocSaveBattleMons(void); @@ -178,12 +178,12 @@ bool32 PartyHasMoveSplit(u8 battlerId, u8 split); bool32 SideHasMoveSplit(u8 battlerId, u8 split); // score increases -void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score); -void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); -void IncreaseFrostbiteScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score); +void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s16 *score); +void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); +void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); +void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); +void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); +void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); +void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score); #endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_main.h b/include/battle_main.h index 0ae62cd35..5cf7e7219 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -67,7 +67,7 @@ void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); bool8 TryRunFromBattle(u8 battlerId); void SpecialStatusesClear(void); -void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk); +void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk); bool32 IsWildMonSmart(void); u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags); void ModifyPersonalityForNature(u32 *personality, u32 newNature); diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index dcf601e80..9d24b457d 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -16,8 +16,8 @@ struct StatFractions u8 divisor; }; -s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility); -s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move); +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility); +s8 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move); u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); u8 GetBattlerTurnOrderNum(u8 battlerId); bool32 NoAliveMonsForEitherParty(void); @@ -28,8 +28,8 @@ void BattleCreateYesNoCursorAt(u8 cursorPosition); void BufferMoveToLearnIntoBattleTextBuff2(void); void HandleBattleWindow(u8 xStart, u8 yStart, u8 xEnd, u8 yEnd, u8 flags); bool8 UproarWakeUpCheck(u8 battlerId); -bool32 DoesSubstituteBlockMove(u8 battlerAtk, u8 battlerDef, u32 move); -bool32 DoesDisguiseBlockMove(u8 battlerAtk, u8 battlerDef, u32 move); +bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move); +bool32 DoesDisguiseBlockMove(u32 battlerAtk, u32 battlerDef, u32 move); bool32 CanPoisonType(u8 battlerAttacker, u8 battlerTarget); bool32 CanParalyzeType(u8 battlerAttacker, u8 battlerTarget); bool32 CanUseLastResort(u8 battlerId); diff --git a/include/battle_util.h b/include/battle_util.h index 62394d85d..e3ae799b4 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -161,20 +161,20 @@ void HandleAction_RunBattleScript(void); u32 SetRandomTarget(u32 battler); u32 GetMoveTarget(u16 move, u8 setTarget); u8 IsMonDisobedient(void); -u32 GetBattlerHoldEffect(u8 battler, bool32 checkNegating); +u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating); u32 GetBattlerHoldEffectParam(u8 battler); -bool32 IsMoveMakingContact(u16 move, u8 battlerAtk); +bool32 IsMoveMakingContact(u16 move, u32 battlerAtk); bool32 IsBattlerGrounded(u8 battler); bool32 IsBattlerAlive(u8 battler); u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move); u32 GetBattlerWeight(u8 battler); u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer); u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter); -s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); -s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, uq4_12_t *typeEffectivenessModifier); -uq4_12_t CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities); +s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags); +s32 CalculateMoveDamageAndEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t *typeEffectivenessModifier); +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(u8 atkType, u8 defType); +uq4_12_t GetTypeModifier(u32 atkType, u32 defType); s32 GetStealthHazardDamage(u8 hazardType, u8 battler); s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp); bool32 CanMegaEvolve(u8 battler); @@ -209,11 +209,11 @@ void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast); bool32 CompareStat(u8 battler, u8 statId, u8 cmpTo, u8 cmpKind); bool32 TryRoomService(u8 battler); void BufferStatChange(u8 battler, u8 statId, u8 stringId); -bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget); +bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u32 battlerDef, bool32 checkTarget); u16 GetUsedHeldItem(u8 battler); bool32 IsBattlerWeatherAffected(u8 battler, u32 weatherFlags); u32 GetBattlerMoveTargetType(u8 battler, u16 move); -bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move); +bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move); bool8 IsMoveAffectedByParentalBond(u16 move, u8 battler); void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon); void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon); diff --git a/include/config/debug.h b/include/config/debug.h index eea676b30..ff54f6ac1 100644 --- a/include/config/debug.h +++ b/include/config/debug.h @@ -9,7 +9,7 @@ // Battle Debug Menu #define DEBUG_BATTLE_MENU TRUE // If set to TRUE, enables a debug menu to use in battles by pressing the Select button. -#define DEBUG_AI_DELAY_TIMER FALSE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. +#define DEBUG_AI_DELAY_TIMER TRUE // If set to TRUE, displays the number of frames it takes for the AI to choose a move. Replaces the "What will PKMN do" text. Useful for devs or anyone who modifies the AI code and wants to see if it doesn't take too long to run. // Pokémon Debug #define DEBUG_POKEMON_MENU TRUE // Enables a debug menu for pokemon sprites and icons, accessed by pressing SELECT in the summary screen. diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index a8946bcec..810e2ffff 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -47,20 +47,20 @@ EWRAM_DATA const u8 *gAIScriptPtr = NULL; // Still used in contests EWRAM_DATA u8 sBattler_AI = 0; // const rom data -static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); -static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score); +static s16 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_Risky(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_HPAware(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_Roaming(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_Safari(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); +static s16 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s16 score); -static s16 (*const sBattleAiFuncTable[])(u8, u8, u16, s16) = +static s16 (*const sBattleAiFuncTable[])(u32, u32, u16, s16) = { [0] = AI_CheckBadMove, // AI_FLAG_CHECK_BAD_MOVE [1] = AI_TryToFaint, // AI_FLAG_TRY_TO_FAINT @@ -349,9 +349,7 @@ static void SetBattlerAiData(u32 battler) void SetAiLogicDataForTurn(void) { - u32 battlerAtk, battlerDef, i, move; - u8 effectiveness; - s32 dmg; + u32 battlerAtk, battlerDef, i, battlersCount; memset(AI_DATA, 0, sizeof(struct AiLogicData)); @@ -360,33 +358,29 @@ void SetAiLogicDataForTurn(void) gBattleStruct->aiDelayTimer = gMain.vblankCounter1; - // get/assume all battler data - for (i = 0; i < gBattlersCount; i++) + // get/assume all battler data and simulate AI damage + battlersCount = gBattlersCount; + for (battlerAtk = 0; battlerAtk < battlersCount; battlerAtk++) { - if (IsBattlerAlive(i)) { - SetBattlerAiData(i); - } - } - - // simulate AI damage - for (battlerAtk = 0; battlerAtk < gBattlersCount; battlerAtk++) - { - if (!IsBattlerAlive(battlerAtk) - || !IsAiBattlerAware(battlerAtk)) { + if (!IsBattlerAlive(battlerAtk)) continue; - } - for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + SetBattlerAiData(battlerAtk); + if (!IsAiBattlerAware(battlerAtk)) + continue; + + SaveBattlerData(battlerAtk); + for (battlerDef = 0; battlerDef < battlersCount; battlerDef++) { if (battlerAtk == battlerDef) continue; - RecordKnownMove(battlerDef, gLastMoves[battlerDef]); + SaveBattlerData(battlerDef); for (i = 0; i < MAX_MON_MOVES; i++) { - dmg = 0; - effectiveness = AI_EFFECTIVENESS_x0; - move = gBattleMons[battlerAtk].moves[i]; + s32 dmg = 0; + u8 effectiveness = AI_EFFECTIVENESS_x0; + u32 move = gBattleMons[battlerAtk].moves[i]; if (move != 0 && move != 0xFFFF @@ -562,8 +556,6 @@ static u8 ChooseMoveOrAction_Doubles(void) BattleAI_SetupAIData(0xF, sBattler_AI); gBattlerTarget = i; - if ((i & BIT_SIDE) != (sBattler_AI & BIT_SIDE)) - RecordLastUsedMoveByTarget(); AI_DATA->partnerMove = GetAllyChosenMove(i); AI_THINKING_STRUCT->aiLogicId = 0; @@ -710,7 +702,7 @@ static void BattleAI_DoAIProcessing(void) // AI Score Functions // AI_FLAG_CHECK_BAD_MOVE - decreases move scores -static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { // move data u8 atkPriority = GetMovePriority(battlerAtk, move); @@ -2694,7 +2686,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (IsTargetingPartner(battlerAtk, battlerDef)) return score; @@ -2749,14 +2741,14 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // double battle logic -static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { // move data u8 moveType = gBattleMoves[move].type; u16 effect = gBattleMoves[move].effect; u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move); // ally data - u8 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); + u32 battlerAtkPartner = BATTLE_PARTNER(battlerAtk); u16 atkPartnerAbility = AI_DATA->abilities[BATTLE_PARTNER(battlerAtk)]; u16 atkPartnerHoldEffect = AI_DATA->holdEffects[BATTLE_PARTNER(battlerAtk)]; bool32 partnerProtecting = (gBattleMoves[AI_DATA->partnerMove].effect == EFFECT_PROTECT); @@ -3148,7 +3140,7 @@ static bool32 IsPinchBerryItemEffect(u16 holdEffect) return FALSE; } -static u32 GetAIMostDamagingMoveId(u8 battlerAtk, u8 battlerDef) +static u32 GetAIMostDamagingMoveId(u32 battlerAtk, u32 battlerDef) { u32 i, id = 0; u32 mostDmg = 0; @@ -3162,7 +3154,7 @@ static u32 GetAIMostDamagingMoveId(u8 battlerAtk, u8 battlerDef) } // AI_FLAG_CHECK_VIABILITY - a weird mix of increasing and decreasing scores -static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { // move data u16 moveEffect = gBattleMoves[move].effect; @@ -4964,7 +4956,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // Effects that are encouraged on the first turn of battle -static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (IsTargetingPartner(battlerAtk, battlerDef) || gBattleResults.battleTurnCounter != 0) @@ -5075,7 +5067,7 @@ static s16 AI_SetupFirstTurn(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // Adds score bonus to 'riskier' move effects and high crit moves -static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Risky(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (IsTargetingPartner(battlerAtk, battlerDef)) return score; @@ -5114,7 +5106,7 @@ static s16 AI_Risky(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // Adds score bonus to best powered move -static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (IsTargetingPartner(battlerAtk, battlerDef)) return score; @@ -5126,7 +5118,7 @@ static s16 AI_PreferStrongestMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 sc } // Prefers moves that are good for baton pass -static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { u32 i; @@ -5181,7 +5173,7 @@ static s16 AI_PreferBatonPass(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) return score; } -static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_HPAware(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { u16 effect = gBattleMoves[move].effect; u8 moveType = gBattleMoves[move].type; @@ -5384,7 +5376,7 @@ static void AI_Watch(void) } // Roaming pokemon logic -static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Roaming(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (IsBattlerTrapped(battlerAtk, FALSE)) return score; @@ -5394,7 +5386,7 @@ static s16 AI_Roaming(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // Safari pokemon logic -static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_Safari(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { u8 safariFleeRate = gBattleStruct->safariEscapeFactor * 5; // Safari flee rate, from 0-20. @@ -5407,7 +5399,7 @@ static s16 AI_Safari(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) } // First battle logic -static s16 AI_FirstBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score) +static s16 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u16 move, s16 score) { if (AI_DATA->hpPercents[battlerDef] <= 20) AI_Flee(); diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 5072645bd..19eba9051 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -436,11 +436,6 @@ bool32 AI_RandLessThan(u8 val) return FALSE; } -void RecordLastUsedMoveByTarget(void) -{ - RecordKnownMove(gBattlerTarget, gLastMoves[gBattlerTarget]); -} - bool32 IsAiVsAiBattle(void) { return (B_FLAG_AI_VS_AI_BATTLE && FlagGet(B_FLAG_AI_VS_AI_BATTLE)); @@ -529,7 +524,7 @@ void ClearBattlerItemEffectHistory(u8 battlerId) BATTLE_HISTORY->itemEffects[battlerId] = 0; } -void SaveBattlerData(u8 battlerId) +void SaveBattlerData(u32 battlerId) { if (!BattlerHasAi(battlerId)) { @@ -580,7 +575,7 @@ static bool32 ShouldFailForIllusion(u16 illusionSpecies, u32 battlerId) return TRUE; } -void SetBattlerData(u8 battlerId) +void SetBattlerData(u32 battlerId) { if (!BattlerHasAi(battlerId)) { @@ -624,7 +619,7 @@ void SetBattlerData(u8 battlerId) } } -void RestoreBattlerData(u8 battlerId) +void RestoreBattlerData(u32 battlerId) { if (!BattlerHasAi(battlerId)) { @@ -741,7 +736,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split) return (usable == 0); } -static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) +static bool32 AI_GetIfCrit(u32 move, u32 battlerAtk, u32 battlerDef) { bool32 isCrit; @@ -776,12 +771,23 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef) return isCrit; } -s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) +// To save computation time this function has 2 variants. One saves, sets and restores battlers, while the other doesn't. +s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) +{ + SaveBattlerData(battlerAtk); + SaveBattlerData(battlerDef); + AI_CalcDamage(move, battlerAtk, battlerDef, typeEffectiveness, considerZPower); +} + +s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower) { s32 dmg, moveType, critDmg, normalDmg, fixedBasePower, n; s8 critChance; uq4_12_t effectivenessMultiplier; + SetBattlerData(battlerAtk); + SetBattlerData(battlerDef); + if (considerZPower && IsViableZMove(battlerAtk, move)) { //temporarily enable z moves for damage calcs @@ -789,12 +795,6 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness, gBattleStruct->zmove.active = TRUE; } - SaveBattlerData(battlerAtk); - SaveBattlerData(battlerDef); - - SetBattlerData(battlerAtk); - SetBattlerData(battlerDef); - gBattleStruct->dynamicMoveType = 0; if (move == MOVE_NATURE_POWER) @@ -1026,14 +1026,14 @@ u8 GetMoveDamageResult(u16 move) return AI_THINKING_STRUCT->funcResult; } -u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef) +u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef) { int bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; return (bestDmg * 100) / gBattleMons[battlerDef].maxHP; } -uq4_12_t AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) +uq4_12_t AI_GetTypeEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef) { uq4_12_t typeEffectiveness; u16 moveType; @@ -1055,7 +1055,7 @@ uq4_12_t AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) return typeEffectiveness; } -u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef) +u32 AI_GetMoveEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef) { gMoveResultFlags = 0; return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef)); @@ -1134,7 +1134,7 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 moveConsidered) } // Check if target has means to faint ai mon. -bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) +bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk) { s32 i, dmg; u32 unusable = AI_DATA->moveLimitations[battlerDef]; @@ -1154,7 +1154,7 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 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(u8 battlerAtk, u8 battlerDef, u8 numHits) +bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u8 numHits) { s32 i, dmg; u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; @@ -1178,7 +1178,7 @@ bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits) return FALSE; } -bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) +bool32 CanMoveFaintBattler(u16 move, u32 battlerDef, u32 battlerAtk, u8 nHits) { s32 i, dmg; u8 effectiveness; @@ -1187,14 +1187,14 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) - && AI_CalcDamage(move, battlerDef, battlerAtk, &effectiveness, FALSE) >= gBattleMons[battlerAtk].hp) + && AI_CalcDamageSaveBattlers(move, battlerDef, battlerAtk, &effectiveness, FALSE) >= gBattleMons[battlerAtk].hp) return TRUE; return FALSE; } // Check if target has means to faint ai mon after modding hp/dmg -bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) +bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod) { u32 i; u32 unusable = AI_DATA->moveLimitations[battlerDef]; @@ -1466,13 +1466,13 @@ bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility) return FALSE; } -u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move) +u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u16 move) { return GetTotalAccuracy(battlerAtk, battlerDef, move, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]); } -bool32 IsSemiInvulnerable(u8 battlerDef, u16 move) +bool32 IsSemiInvulnerable(u32 battlerDef, u16 move) { if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) return TRUE; @@ -1486,7 +1486,7 @@ bool32 IsSemiInvulnerable(u8 battlerDef, u16 move) return FALSE; } -bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) +bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u16 move) { if (IsSemiInvulnerable(battlerDef, move)) return FALSE; @@ -1526,7 +1526,7 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move) return FALSE; } -bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move) +bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move) { u32 holdEffect = AI_DATA->holdEffects[battlerDef]; u32 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, move); @@ -1608,7 +1608,7 @@ bool32 ShouldSetHail(u8 battler, u16 ability, u16 holdEffect) return FALSE; } -bool32 ShouldSetRain(u8 battlerAtk, u16 atkAbility, u16 holdEffect) +bool32 ShouldSetRain(u32 battlerAtk, u16 atkAbility, u16 holdEffect) { if (!AI_WeatherHasEffect()) return FALSE; @@ -1631,7 +1631,7 @@ bool32 ShouldSetRain(u8 battlerAtk, u16 atkAbility, u16 holdEffect) return FALSE; } -bool32 ShouldSetSun(u8 battlerAtk, u16 atkAbility, u16 holdEffect) +bool32 ShouldSetSun(u32 battlerAtk, u16 atkAbility, u16 holdEffect) { if (!AI_WeatherHasEffect()) return FALSE; @@ -1679,7 +1679,7 @@ bool32 ShouldSetSnow(u8 battler, u16 ability, u16 holdEffect) return FALSE; } -void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s16 *score) +void ProtectChecks(u32 battlerAtk, u32 battlerDef, u16 move, u16 predictedMove, s16 *score) { // TODO more sophisticated logic u16 predictedEffect = gBattleMoves[predictedMove].effect; @@ -1793,7 +1793,7 @@ u32 CountNegativeStatStages(u8 battlerId) return count; } -bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1810,7 +1810,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1827,7 +1827,7 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1842,7 +1842,7 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1858,7 +1858,7 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1874,7 +1874,7 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1889,7 +1889,7 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return FALSE; // Don't bother lowering stats if can kill enemy. @@ -1904,7 +1904,7 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) return FALSE; } -bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) +bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u8 index, u8 numHits) { s32 dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][index]; @@ -1996,7 +1996,7 @@ bool32 HasMove(u32 battlerId, u32 move) return FALSE; } -bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect) +bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u8 accCheck, bool32 ignoreStatus, u16 atkAbility, u16 defAbility, u16 atkHoldEffect, u16 defHoldEffect) { s32 i; u16 *moves = GetMovesArray(battlerAtk); @@ -2023,7 +2023,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32 return FALSE; } -bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef) +bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef) { u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk]; u32 i; @@ -2560,7 +2560,7 @@ enum { CAN_TRY_PIVOT, PIVOT, }; -bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 moveIndex) +bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u8 moveIndex) { bool8 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class bool32 shouldSwitch; @@ -2789,7 +2789,7 @@ bool32 AI_CanSleep(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (!AI_CanSleep(battlerDef, defAbility) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move) @@ -2804,7 +2804,7 @@ static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget) || !(IS_BATTLER_OF_TYPE(battlerTarget, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL))); } -static bool32 AI_CanBePoisoned(u8 battlerAtk, u8 battlerDef) +static bool32 AI_CanBePoisoned(u32 battlerAtk, u32 battlerDef) { u16 ability = AI_DATA->abilities[battlerDef]; @@ -2836,7 +2836,7 @@ bool32 ShouldPoisonSelf(u8 battler, u16 ability) return FALSE; } -bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (!AI_CanBePoisoned(battlerAtk, battlerDef) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2862,7 +2862,7 @@ static bool32 AI_CanBeParalyzed(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanParalyze(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16 partnerMove) +bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u16 defAbility, u16 move, u16 partnerMove) { if (!AI_CanBeParalyzed(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2882,7 +2882,7 @@ bool32 AI_CanBeConfused(u8 battler, u16 ability) return TRUE; } -bool32 AI_CanConfuse(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) { if (!AI_CanBeConfused(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2935,7 +2935,7 @@ bool32 ShouldBurnSelf(u8 battler, u16 ability) return FALSE; } -bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) { if (!AI_CanBeBurned(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2947,7 +2947,7 @@ bool32 AI_CanBurn(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPar return TRUE; } -bool32 AI_CanGiveFrostbite(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u16 defAbility, u32 battlerAtkPartner, u16 move, u16 partnerMove) { if (!AI_CanGetFrostbite(battlerDef, defAbility) || AI_GetMoveEffectiveness(move, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2959,7 +2959,7 @@ bool32 AI_CanGiveFrostbite(u8 battlerAtk, u8 battlerDef, u16 defAbility, u8 batt return TRUE; } -bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility) +bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u16 defAbility) { if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) || AI_GetMoveEffectiveness(AI_THINKING_STRUCT->moveConsidered, battlerAtk, battlerDef) == AI_EFFECTIVENESS_x0 @@ -2970,7 +2970,7 @@ bool32 AI_CanBeInfatuated(u8 battlerAtk, u8 battlerDef, u16 defAbility) return TRUE; } -u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move) +u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u16 atkAbility, u16 defAbility, u16 move) { if (((AI_DATA->abilities[battlerAtk] != ABILITY_MOLD_BREAKER && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) || AI_GetHoldEffect(battlerDef) == HOLD_EFFECT_COVERT_CLOAK @@ -2991,7 +2991,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili return 0; // don't try to flinch } -bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) +bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u16 move) { if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef])) return TRUE; // battler is taking secondary damage with low HP @@ -3005,7 +3005,7 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move) return FALSE; } -bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move) +bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u16 move) { if (!gDisableStructs[battlerAtk].isFirstTurn || AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS @@ -3082,7 +3082,7 @@ u16 GetBattlerSideSpeedAverage(u8 battler) return (speed1 + speed2) / numBattlersAlive; } -bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex) +bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u8 moveIndex) { if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left @@ -3096,7 +3096,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI return TRUE; } -bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) +bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u16 move, s32 damage) { if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { @@ -3123,7 +3123,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage) return FALSE; } -bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) +bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u16 move, u8 healPercent) { if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) { @@ -3142,7 +3142,7 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent) return FALSE; } -bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect) +bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u16 moveEffect) { u8 atkSide = GetBattlerSide(battlerAtk); switch (moveEffect) @@ -3171,7 +3171,7 @@ bool32 ShouldSetScreen(u8 battlerAtk, u8 battlerDef, u16 moveEffect) } // Partner Logic -bool32 IsValidDoubleBattle(u8 battlerAtk) +bool32 IsValidDoubleBattle(u32 battlerAtk) { if (IsDoubleBattle() && ((IsBattlerAlive(BATTLE_OPPOSITE(battlerAtk)) && IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battlerAtk)))) || IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))) @@ -3191,7 +3191,7 @@ u16 GetAllyChosenMove(u8 battlerId) return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]]; } -bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) +bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef) { if ((battlerAtk & BIT_SIDE) == (battlerDef & BIT_SIDE)) return TRUE; @@ -3200,7 +3200,7 @@ bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef) } //PARTNER_MOVE_EFFECT_IS_SAME -bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove) +bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3215,7 +3215,7 @@ bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 mo } //PARTNER_MOVE_EFFECT_IS_SAME_NO_TARGET -bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3227,7 +3227,7 @@ bool32 PartnerHasSameMoveEffectWithoutTarget(u8 battlerAtkPartner, u16 move, u16 } //PARTNER_MOVE_EFFECT_IS_STATUS_SAME_TARGET -bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, u16 partnerMove) +bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3245,7 +3245,7 @@ bool32 PartnerMoveEffectIsStatusSameTarget(u8 battlerAtkPartner, u8 battlerDef, } //PARTNER_MOVE_EFFECT_IS_WEATHER -bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove) +bool32 PartnerMoveEffectIsWeather(u32 battlerAtkPartner, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3262,7 +3262,7 @@ bool32 PartnerMoveEffectIsWeather(u8 battlerAtkPartner, u16 partnerMove) } //PARTNER_MOVE_EFFECT_IS_TERRAIN -bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove) +bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3278,7 +3278,7 @@ bool32 PartnerMoveEffectIsTerrain(u8 battlerAtkPartner, u16 partnerMove) } //PARTNER_MOVE_IS_TAILWIND_TRICKROOM -bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck) +bool32 PartnerMoveIs(u32 battlerAtkPartner, u16 partnerMove, u16 moveCheck) { if (!IsDoubleBattle()) return FALSE; @@ -3289,7 +3289,7 @@ bool32 PartnerMoveIs(u8 battlerAtkPartner, u16 partnerMove, u16 moveCheck) } //PARTNER_MOVE_IS_SAME -bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove) +bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u16 move, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3300,7 +3300,7 @@ bool32 PartnerMoveIsSameAsAttacker(u8 battlerAtkPartner, u8 battlerDef, u16 move } //PARTNER_MOVE_IS_SAME_NO_TARGET -bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove) +bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u16 move, u16 partnerMove) { if (!IsDoubleBattle()) return FALSE; @@ -3309,7 +3309,7 @@ bool32 PartnerMoveIsSameNoTarget(u8 battlerAtkPartner, u16 move, u16 partnerMove return FALSE; } -bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move) +bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u16 move) { u32 i; u32 firstId, lastId; @@ -3413,7 +3413,7 @@ s32 AI_CalcPartyMonBestMoveDamage(u32 battlerAtk, u32 battlerDef, struct Pokemon if (move != MOVE_NONE && gBattleMoves[move].power != 0) { - dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE); + dmg = AI_CalcDamageSaveBattlers(move, battlerAtk, battlerDef, &effectiveness, FALSE); if (dmg > bestDmg) bestDmg = dmg; } @@ -3568,7 +3568,7 @@ bool32 IsStatBoostingBerry(u16 item) } } -bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item) +bool32 ShouldRestoreHpBerry(u32 battlerAtk, u16 item) { switch (item) { @@ -3602,7 +3602,7 @@ bool32 IsRecycleEncouragedItem(u16 item) // score increases #define STAT_UP_2_STAGE 8 #define STAT_UP_STAGE 10 -void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) +void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s16 *score) { if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) return; @@ -3682,7 +3682,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score) } } -void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *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) @@ -3706,7 +3706,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) } } -void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *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) @@ -3726,7 +3726,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) } } -void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *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) @@ -3748,7 +3748,7 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) } } -void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *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) @@ -3767,7 +3767,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) (*score)++; } -void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *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) @@ -3786,7 +3786,7 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) } } -void IncreaseFrostbiteScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score) +void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u16 move, s16 *score) { if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) return; @@ -3815,7 +3815,7 @@ bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move) } //TODO - this could use some more sophisticated logic -bool32 ShouldUseZMove(u8 battlerAtk, u8 battlerDef, u16 chosenMove) +bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u16 chosenMove) { // simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && battlerDef == BATTLE_PARTNER(battlerAtk)) @@ -3837,7 +3837,7 @@ bool32 ShouldUseZMove(u8 battlerAtk, u8 battlerDef, u16 chosenMove) else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove)) return FALSE; - if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamage(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE) >= gBattleMons[battlerDef].hp) + if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE) >= gBattleMons[battlerDef].hp) return FALSE; // don't waste damaging z move if can otherwise faint target return TRUE; diff --git a/src/battle_main.c b/src/battle_main.c index 7f985f16e..6fbbec8a1 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5575,7 +5575,7 @@ void RunBattleScriptCommands(void) gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); } -void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk) +void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk) { u32 moveType, ateType, attackerAbility; u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b75520ff9..b93586d84 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1907,7 +1907,7 @@ static void Cmd_ppreduce(void) #endif // B_CRIT_CHANCE #define BENEFITS_FROM_LEEK(battler, holdEffect)((holdEffect == HOLD_EFFECT_LEEK) && (GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_FARFETCHD || gBattleMons[battler].species == SPECIES_SIRFETCHD)) -s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility) +s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility) { s32 critChance = 0; u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); @@ -1952,7 +1952,7 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi } #undef BENEFITS_FROM_LEEK -s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move) +s8 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move) { s32 critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE); if(critChanceIndex < 0) @@ -5657,6 +5657,7 @@ static void Cmd_moveend(void) if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) { gLastMoves[gBattlerAttacker] = gChosenMove; + RecordKnownMove(gBattlerAttacker, gChosenMove); gLastResultingMoves[gBattlerAttacker] = gCurrentMove; } } @@ -8242,7 +8243,7 @@ static void RemoveAllTerrains(void) } \ } -static bool32 TryDefogClear(u8 battlerAtk, bool32 clear) +static bool32 TryDefogClear(u32 battlerAtk, bool32 clear) { s32 i; for (i = 0; i < 2; i++) @@ -14760,7 +14761,7 @@ static void Cmd_settypebasedhalvers(void) gBattlescriptCurrInstr = cmd->failInstr; } -bool32 DoesSubstituteBlockMove(u8 battlerAtk, u8 battlerDef, u32 move) +bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) { if (!(gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE)) return FALSE; @@ -14776,7 +14777,7 @@ bool32 DoesSubstituteBlockMove(u8 battlerAtk, u8 battlerDef, u32 move) return TRUE; } -bool32 DoesDisguiseBlockMove(u8 battlerAtk, u8 battlerDef, u32 move) +bool32 DoesDisguiseBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) { if (gBattleMons[battlerDef].species != SPECIES_MIMIKYU || gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED diff --git a/src/battle_util.c b/src/battle_util.c index d4e873b7e..0bacf29ae 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4244,7 +4244,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move gBattleWeather = B_WEATHER_SNOW; gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; effect++; - #else + #else gBattleWeather = B_WEATHER_HAIL; gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; effect++; @@ -8100,7 +8100,7 @@ u8 IsMonDisobedient(void) } } -u32 GetBattlerHoldEffect(u8 battler, bool32 checkNegating) +u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating) { if (checkNegating) { @@ -8136,7 +8136,7 @@ u32 GetBattlerHoldEffectParam(u8 battler) return ItemId_GetHoldEffectParam(gBattleMons[battler].item); } -bool32 IsMoveMakingContact(u16 move, u8 battlerAtk) +bool32 IsMoveMakingContact(u16 move, u32 battlerAtk) { u16 atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE); @@ -8321,7 +8321,7 @@ u32 CountBattlerStatIncreases(u8 battler, bool32 countEvasionAcc) return count; } -u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef) +u32 GetMoveTargetCount(u16 move, u32 battlerAtk, u32 battlerDef) { switch (GetBattlerMoveTargetType(gBattlerAttacker, move)) { @@ -8460,7 +8460,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter) return basePower; } -static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) +static inline u16 CalcMoveBasePower(u16 move, u32 battlerAtk, u32 battlerDef, u32 abilityDef) { u32 i; u16 basePower = gBattleMoves[move].power; @@ -8535,7 +8535,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) basePower = gNaturalGiftTable[ITEM_TO_BERRY(gBattleMons[battlerAtk].item)].power; break; case EFFECT_WAKE_UP_SLAP: - if (gBattleMons[battlerDef].status1 & STATUS1_SLEEP || GetBattlerAbility(battlerDef) == ABILITY_COMATOSE) + if (gBattleMons[battlerDef].status1 & STATUS1_SLEEP || abilityDef == ABILITY_COMATOSE) basePower *= 2; break; case EFFECT_SMELLINGSALT: @@ -8547,7 +8547,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) break; case EFFECT_HEX: case EFFECT_INFERNAL_PARADE: - if (gBattleMons[battlerDef].status1 & STATUS1_ANY || GetBattlerAbility(battlerDef) == ABILITY_COMATOSE) + if (gBattleMons[battlerDef].status1 & STATUS1_ANY || abilityDef == ABILITY_COMATOSE) basePower *= 2; break; case EFFECT_ASSURANCE: @@ -8716,16 +8716,14 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef) return basePower; } -static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, bool32 updateFlags) +static inline u32 CalcMoveBasePowerAfterModifiers(u16 move, u32 battlerAtk, u32 battlerDef, u8 moveType, bool32 updateFlags, u32 atkAbility, u32 defAbility, u32 holdEffectAtk) { u32 i; - u32 holdEffectAtk, holdEffectParamAtk; - u16 basePower = CalcMoveBasePower(move, battlerAtk, battlerDef); + u32 holdEffectParamAtk; + u16 basePower = CalcMoveBasePower(move, battlerAtk, battlerDef, defAbility); uq4_12_t holdEffectModifier; uq4_12_t modifier = UQ_4_12(1.0); u32 atkSide = GET_BATTLER_SIDE(battlerAtk); - u16 atkAbility = GetBattlerAbility(battlerAtk); - u16 defAbility = GetBattlerAbility(battlerDef); // move effect switch (gBattleMoves[move].effect) @@ -9020,7 +9018,6 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe break; } - holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); holdEffectParamAtk = GetBattlerHoldEffectParam(battlerAtk); if (holdEffectParamAtk > 100) holdEffectParamAtk = 100; @@ -9099,7 +9096,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe } #undef TERRAIN_TYPE_BOOST -static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, bool32 isCrit, bool32 updateFlags) +static inline u32 CalcAttackStat(u16 move, u32 battlerAtk, u32 battlerDef, u8 moveType, bool32 isCrit, bool32 updateFlags, u32 atkAbility, u32 defAbility, u32 holdEffectAtk) { u8 atkStage; u32 atkStat; @@ -9144,7 +9141,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b if (isCrit && atkStage < DEFAULT_STAT_STAGE) atkStage = DEFAULT_STAT_STAGE; // pokemon with unaware ignore attack stat changes while taking damage - if (GetBattlerAbility(battlerDef) == ABILITY_UNAWARE) + if (defAbility == ABILITY_UNAWARE) atkStage = DEFAULT_STAT_STAGE; atkStat *= gStatStageRatios[atkStage][0]; @@ -9154,7 +9151,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b modifier = UQ_4_12(1.0); // attacker's abilities - switch (GetBattlerAbility(battlerAtk)) + switch (atkAbility) { case ABILITY_HUGE_POWER: case ABILITY_PURE_POWER: @@ -9232,7 +9229,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b } // target's abilities - switch (GetBattlerAbility(battlerDef)) + switch (defAbility) { case ABILITY_THICK_FAT: if (moveType == TYPE_FIRE || moveType == TYPE_ICE) @@ -9257,7 +9254,7 @@ static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, b } // attacker's hold effect - switch (GetBattlerHoldEffect(battlerAtk, TRUE)) + switch (holdEffectAtk) { case HOLD_EFFECT_THICK_CLUB: if ((atkBaseSpeciesId == SPECIES_CUBONE || atkBaseSpeciesId == SPECIES_MAROWAK) && IS_MOVE_PHYSICAL(move)) @@ -9303,7 +9300,7 @@ static bool32 CanEvolve(u32 species) return FALSE; } -static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, bool32 isCrit, bool32 updateFlags) +static inline u32 CalcDefenseStat(u16 move, u32 battlerAtk, u32 battlerDef, u8 moveType, bool32 isCrit, bool32 updateFlags, u32 atkAbility, u32 defAbility, u32 holdEffectDef) { bool32 usesDefStat; u8 defStage; @@ -9344,7 +9341,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, if (isCrit && defStage > DEFAULT_STAT_STAGE) defStage = DEFAULT_STAT_STAGE; // pokemon with unaware ignore defense stat changes while dealing damage - if (GetBattlerAbility(battlerAtk) == ABILITY_UNAWARE) + if (atkAbility == ABILITY_UNAWARE) defStage = DEFAULT_STAT_STAGE; // certain moves also ignore stat changes if (gBattleMoves[move].ignoresTargetDefenseEvasionStages) @@ -9357,7 +9354,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, modifier = UQ_4_12(1.0); // target's abilities - switch (GetBattlerAbility(battlerDef)) + switch (defAbility) { case ABILITY_MARVEL_SCALE: if (gBattleMons[battlerDef].status1 & STATUS1_ANY && usesDefStat) @@ -9406,7 +9403,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, } // target's hold effects - switch (GetBattlerHoldEffect(battlerDef, TRUE)) + switch (holdEffectDef) { case HOLD_EFFECT_DEEP_SEA_SCALE: if (gBattleMons[battlerDef].species == SPECIES_CLAMPERL && !usesDefStat) @@ -9582,13 +9579,12 @@ static inline uq4_12_t GetAirborneModifier(u32 move, u32 battlerDef) return UQ_4_12(1.0); } -static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerDef, bool32 isCrit) +static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerDef, bool32 isCrit, u32 abilityAtk) { u32 sideStatus = gSideStatuses[GET_BATTLER_SIDE(battlerDef)]; bool32 lightScreen = (sideStatus & SIDE_STATUS_LIGHTSCREEN) && IS_MOVE_SPECIAL(move); bool32 reflect = (sideStatus & SIDE_STATUS_REFLECT) && IS_MOVE_PHYSICAL(move); bool32 auroraVeil = sideStatus & SIDE_STATUS_AURORA_VEIL; - u32 abilityAtk = GetBattlerAbility(battlerAtk); if (isCrit || abilityAtk == ABILITY_INFILTRATOR || gProtectStructs[battlerAtk].confusionSelfDmg) return UQ_4_12(1.0); @@ -9604,9 +9600,8 @@ static inline uq4_12_t GetCollisionCourseElectroDriftModifier(u32 move, uq4_12_t return UQ_4_12(1.0); } -static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, bool32 isCrit) +static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, bool32 isCrit, u32 abilityAtk) { - u32 abilityAtk = GetBattlerAbility(battlerAtk); switch (abilityAtk) { case ABILITY_NEUROFORCE: @@ -9625,9 +9620,8 @@ static inline uq4_12_t GetAttackerAbilitiesModifier(u32 battlerAtk, uq4_12_t typ return UQ_4_12(1.0); } -static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t typeEffectivenessModifier) +static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t typeEffectivenessModifier, u32 abilityDef) { - u32 abilityDef = GetBattlerAbility(battlerDef); switch (abilityDef) { case ABILITY_MULTISCALE: @@ -9673,9 +9667,8 @@ static inline uq4_12_t GetDefenderPartnerAbilitiesModifier(u32 battlerPartnerDef return UQ_4_12(1.0); } -static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier) +static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEffectivenessModifier, u32 holdEffectAtk) { - u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); u32 percentBoost; switch (holdEffectAtk) { @@ -9694,12 +9687,10 @@ static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEff return UQ_4_12(1.0); } -static inline uq4_12_t GetDefenderItemsModifier(u32 moveType, u32 battlerDef, uq4_12_t typeEffectivenessModifier, bool32 updateFlags) +static inline uq4_12_t GetDefenderItemsModifier(u32 moveType, u32 battlerDef, uq4_12_t typeEffectivenessModifier, bool32 updateFlags, u32 abilityDef, u32 holdEffectDef) { - u32 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); u32 holdEffectDefParam = GetBattlerHoldEffectParam(battlerDef); u32 itemDef = gBattleMons[battlerDef].item; - u32 abilityDef = GetBattlerAbility(battlerDef); switch (holdEffectDef) { @@ -9727,9 +9718,9 @@ static inline uq4_12_t GetDefenderItemsModifier(u32 moveType, u32 battlerDef, uq // https://bulbapedia.bulbagarden.net/wiki/Damage#Generation_V_onward // Please Note: Fixed Point Multiplication is not associative. // The order of operations is relevant. -static uq4_12_t GetOtherModifiers(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 isCrit, uq4_12_t typeEffectivenessModifier, bool32 updateFlags) +static inline uq4_12_t GetOtherModifiers(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 isCrit, uq4_12_t typeEffectivenessModifier, bool32 updateFlags, + u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk, u32 holdEffectDef) { - u32 abilityAtk = GetBattlerAbility(battlerAtk); uq4_12_t finalModifier = UQ_4_12(1.0); u32 battlerDefPartner = BATTLE_PARTNER(battlerDef); u32 unmodifiedAttackerSpeed = gBattleMons[battlerAtk].speed; @@ -9739,24 +9730,24 @@ static uq4_12_t GetOtherModifiers(u32 move, u32 moveType, u32 battlerAtk, u32 ba DAMAGE_MULTIPLY_MODIFIER(GetUndergroundModifier(move, battlerDef)); DAMAGE_MULTIPLY_MODIFIER(GetDiveModifier(move, battlerDef)); DAMAGE_MULTIPLY_MODIFIER(GetAirborneModifier(move, battlerDef)); - DAMAGE_MULTIPLY_MODIFIER(GetScreensModifier(move, battlerAtk, battlerDef, isCrit)); + DAMAGE_MULTIPLY_MODIFIER(GetScreensModifier(move, battlerAtk, battlerDef, isCrit, abilityAtk)); DAMAGE_MULTIPLY_MODIFIER(GetCollisionCourseElectroDriftModifier(move, typeEffectivenessModifier)); if (unmodifiedAttackerSpeed >= unmodifiedDefenderSpeed) { - DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit)); - DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier)); + DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner)); - DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier)); - DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(moveType, battlerDef, typeEffectivenessModifier, updateFlags)); + DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier, holdEffectAtk)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(moveType, battlerDef, typeEffectivenessModifier, updateFlags, abilityDef, holdEffectDef)); } else { - DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderAbilitiesModifier(move, moveType, battlerAtk, battlerDef, typeEffectivenessModifier, abilityDef)); DAMAGE_MULTIPLY_MODIFIER(GetDefenderPartnerAbilitiesModifier(battlerDefPartner)); - DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit)); - DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(moveType, battlerDef, typeEffectivenessModifier, updateFlags)); - DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier)); + DAMAGE_MULTIPLY_MODIFIER(GetAttackerAbilitiesModifier(battlerAtk, typeEffectivenessModifier, isCrit, abilityAtk)); + DAMAGE_MULTIPLY_MODIFIER(GetDefenderItemsModifier(moveType, battlerDef, typeEffectivenessModifier, updateFlags, abilityDef, holdEffectDef)); + DAMAGE_MULTIPLY_MODIFIER(GetAttackerItemsModifier(battlerAtk, typeEffectivenessModifier, holdEffectAtk)); } return finalModifier; } @@ -9767,7 +9758,7 @@ static uq4_12_t GetOtherModifiers(u32 move, u32 moveType, u32 battlerAtk, u32 ba dmg = uq4_12_multiply_by_int_half_down(modifier, dmg); \ } while (0) -static s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, +static inline s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags, uq4_12_t typeEffectivenessModifier) { s32 dmg; @@ -9776,6 +9767,7 @@ static s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveTy u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE); u32 holdEffectDef = GetBattlerHoldEffect(battlerDef, TRUE); u32 abilityAtk = GetBattlerAbility(battlerAtk); + u32 abilityDef = GetBattlerAbility(battlerDef); if (typeEffectivenessModifier == UQ_4_12(0.0)) return 0; @@ -9783,10 +9775,10 @@ static s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveTy if (fixedBasePower) gBattleMovePower = fixedBasePower; else - gBattleMovePower = CalcMoveBasePowerAfterModifiers(move, battlerAtk, battlerDef, moveType, updateFlags); + gBattleMovePower = CalcMoveBasePowerAfterModifiers(move, battlerAtk, battlerDef, moveType, updateFlags, abilityAtk, abilityDef, holdEffectAtk); - userFinalAttack = CalcAttackStat(move, battlerAtk, battlerDef, moveType, isCrit, updateFlags); - targetFinalDefense = CalcDefenseStat(move, battlerAtk, battlerDef, moveType, isCrit, updateFlags); + userFinalAttack = CalcAttackStat(move, battlerAtk, battlerDef, moveType, isCrit, updateFlags, abilityAtk, abilityDef, holdEffectAtk); + targetFinalDefense = CalcDefenseStat(move, battlerAtk, battlerDef, moveType, isCrit, updateFlags, abilityAtk, abilityDef, holdEffectDef); dmg = CalculateBaseDamage(gBattleMovePower, userFinalAttack, gBattleMons[battlerAtk].level, targetFinalDefense); DAMAGE_APPLY_MODIFIER(GetTargetDamageModifier(move, battlerAtk, battlerDef)); @@ -9804,7 +9796,7 @@ static s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveTy DAMAGE_APPLY_MODIFIER(typeEffectivenessModifier); DAMAGE_APPLY_MODIFIER(GetBurnOrFrostBiteModifier(battlerAtk, move, abilityAtk)); DAMAGE_APPLY_MODIFIER(GetZMoveAgainstProtectionModifier(battlerDef)); - DAMAGE_APPLY_MODIFIER(GetOtherModifiers(move, moveType, battlerAtk, battlerDef, isCrit, typeEffectivenessModifier, updateFlags)); + DAMAGE_APPLY_MODIFIER(GetOtherModifiers(move, moveType, battlerAtk, battlerDef, isCrit, typeEffectivenessModifier, updateFlags, abilityAtk, abilityDef, holdEffectAtk, holdEffectDef)); if (dmg == 0) dmg = 1; @@ -9813,20 +9805,20 @@ static s32 DoMoveDamageCalc(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveTy #undef DAMAGE_APPLY_MODIFIER -s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags) +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)); } // for AI - get move damage and effectiveness with one function call -s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, uq4_12_t *typeEffectivenessModifier) +s32 CalculateMoveDamageAndEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t *typeEffectivenessModifier) { *typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE); return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, FALSE, FALSE, FALSE, *typeEffectivenessModifier); } -static void MulByTypeEffectiveness(uq4_12_t *modifier, u16 move, u8 moveType, u8 battlerDef, u8 defType, u8 battlerAtk, bool32 recordAbilities) +static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 moveType, u32 battlerDef, u32 defType, u32 battlerAtk, bool32 recordAbilities) { uq4_12_t mod = GetTypeModifier(moveType, defType); @@ -9866,7 +9858,7 @@ static void MulByTypeEffectiveness(uq4_12_t *modifier, u16 move, u8 moveType, u8 *modifier = uq4_12_multiply(*modifier, mod); } -static void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) +static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, uq4_12_t resultingModifier, u32 illusionSpecies) { // Check if the type effectiveness would've been different if the pokemon really had the types as the disguise. uq4_12_t presumedModifier = UQ_4_12(1.0); @@ -9901,10 +9893,9 @@ static void UpdateMoveResultFlags(uq4_12_t modifier) } } -static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities, uq4_12_t modifier) +static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities, uq4_12_t modifier, u32 defAbility) { u32 illusionSpecies; - u16 defAbility = GetBattlerAbility(battlerDef); MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type1, battlerAtk, recordAbilities); if (gBattleMons[battlerDef].type2 != gBattleMons[battlerDef].type1) @@ -9974,15 +9965,16 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat return modifier; } -uq4_12_t CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities) +uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities) { uq4_12_t modifier = UQ_4_12(1.0); if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { - modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier); + u32 defAbility = GetBattlerAbility(defAbility); + modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); if (gBattleMoves[move].effect == EFFECT_TWO_TYPED_MOVE) - modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier); + modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); } if (recordAbilities) @@ -10026,7 +10018,7 @@ static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) } } -uq4_12_t GetTypeModifier(u8 atkType, u8 defType) +uq4_12_t GetTypeModifier(u32 atkType, u32 defType) { #if B_FLAG_INVERSE_BATTLE != 0 if (FlagGet(B_FLAG_INVERSE_BATTLE)) @@ -10959,7 +10951,7 @@ bool32 TryRoomService(u8 battler) } } -bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 checkTarget) +bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u32 battlerDef, bool32 checkTarget) { #if B_PRANKSTER_DARK_TYPES >= GEN_7 if (!gProtectStructs[battlerPrankster].pranksterElevated) @@ -11009,7 +11001,7 @@ u32 GetBattlerMoveTargetType(u8 battler, u16 move) return gBattleMoves[move].target; } -bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move) +bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move) { if (gBattleMoves[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY && GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)