Greatly reduce AI lag (#3308)

This commit is contained in:
Eduardo Quezada D'Ottone 2023-09-26 07:28:18 -03:00 committed by GitHub
commit de577f955a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1616 additions and 1621 deletions

View File

@ -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];
@ -286,11 +287,14 @@ struct AiLogicData
u16 predictedMoves[MAX_BATTLERS_COUNT];
u8 hpPercents[MAX_BATTLERS_COUNT];
u16 partnerMove;
u16 speedStats[MAX_BATTLERS_COUNT]; // Speed stats for all battles, calculated only once, same way as damages
u8 moveDmgResult[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // MOVE_POWER defines for GetMoveDamageResult ; attacker, target, moveIndex
s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
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; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
};
struct AI_ThinkingStruct
@ -298,7 +302,7 @@ struct AI_ThinkingStruct
u8 aiState;
u8 movesetIndex;
u16 moveConsidered;
s8 score[MAX_MON_MOVES];
s32 score[MAX_MON_MOVES];
u32 funcResult;
u32 aiFlags;
u8 aiAction;
@ -640,7 +644,7 @@ struct BattleStruct
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk
bool8 spriteIgnore0Hp;
struct Illusion illusion[MAX_BATTLERS_COUNT];
s8 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
u8 aiMoveOrAction[MAX_BATTLERS_COUNT];
u8 aiChosenTarget[MAX_BATTLERS_COUNT];
u8 soulheartBattlerId;

View File

@ -19,15 +19,15 @@
return score; \
}
u8 ComputeBattleAiScores(u8 battler);
u32 ComputeBattleAiScores(u32 battler);
void BattleAI_SetupItems(void);
void BattleAI_SetupFlags(void);
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler);
u8 BattleAI_ChooseMoveOrAction(void);
u32 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;

View File

@ -7,184 +7,186 @@
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
bool32 AI_RandLessThan(u8 val);
void RecordLastUsedMoveByTarget(void);
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
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 RecordAllMoves(u32 battler);
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 SaveBattlerData(u8 battlerId);
void SetBattlerData(u8 battlerId);
void RestoreBattlerData(u8 battlerId);
u16 GetAIChosenMove(u8 battlerId);
bool32 WillAIStrikeFirst(void);
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);
u32 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);
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 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 CanTargetMoveFaintAi(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(u8 battlerAtk, u8 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 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(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move);
bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 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 IsRecycleEncouragedItem(u16 item);
bool32 ShouldRestoreHpBerry(u8 battlerAtk, u16 item);
bool32 IsStatBoostingBerry(u16 item);
bool32 CanKnockOffItem(u8 battler, u16 item);
bool32 IsAbilityOfRating(u16 ability, s8 rating);
s8 GetAbilityRating(u16 ability);
u32 AI_GetHoldEffect(u32 battlerId);
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, 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(u32 item);
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
bool32 IsStatBoostingBerry(u32 item);
bool32 CanKnockOffItem(u32 battler, u32 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 ShouldUseZMove(u8 activeId, u8 targetId, u16 chosenMove);
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move);
u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move);
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 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(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 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_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 weather);
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);
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(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(u8, u8, u8, bool32, u16, u16, u16, u16);
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 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);
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 IsHealingMoveEffect(u16 effect);
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(u32 effect);
bool32 HasHealingEffect(u32 battler);
bool32 IsTrappingMoveEffect(u16 effect);
bool32 HasTrappingMoveEffect(u8 battler);
bool32 ShouldFakeOut(u8 battlerAtk, u8 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 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(u8 battlerAtk, u8 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 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 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);
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
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);
#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK))
u32 GetAllyChosenMove(u32 battlerId);
bool32 IsValidDoubleBattle(u32 battlerAtk);
bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef);
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(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, 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

View File

@ -57,17 +57,19 @@ void SwitchInClearSetData(u32 battler);
void FaintClearSetData(u32 battler);
void BattleTurnPassed(void);
u8 IsRunningFromBattleImpossible(u32 battler);
void SwitchPartyOrder(u8 battlerId);
void SwitchPartyOrder(u32 battlerId);
void SwapTurnOrder(u8 id1, u8 id2);
u32 GetBattlerTotalSpeedStat(u8 battlerId);
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
u32 GetBattlerTotalSpeedStat(u32 battler);
s8 GetChosenMovePriority(u32 battlerId);
s8 GetMovePriority(u32 battlerId, u16 move);
u8 GetWhoStrikesFirst(u8 battlerId1, u8 battlerId2, bool8 ignoreChosenMoves);
u32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2);
u32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
void RunBattleScriptCommands_PopCallbacksStack(void);
void RunBattleScriptCommands(void);
bool8 TryRunFromBattle(u8 battlerId);
void SpecialStatusesClear(void);
void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk);
void SetTypeBeforeUsingMove(u32 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);

View File

@ -16,8 +16,9 @@ struct StatFractions
u8 divisor;
};
s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility);
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move);
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk);
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility);
s32 GetCritHitChance(s32 critChanceIndex);
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 +29,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);
@ -47,6 +48,7 @@ u32 GetHighestStatId(u32 battlerId);
bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType);
bool32 DoSwitchInAbilitiesItems(u32 battlerId);
u8 GetFirstFaintedPartyIndex(u8 battlerId);
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler);
extern void (* const gBattleScriptingCommandsTable[])(void);
extern const u8 gBattlePalaceNatureToMoveGroupLikelihood[NUM_NATURES][4];

View File

@ -102,6 +102,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
void HandleAction_UseMove(void);
void HandleAction_Switch(void);
void HandleAction_UseItem(void);
bool32 TryRunFromBattle(u32 battler);
void HandleAction_Run(void);
void HandleAction_WatchesCarefully(void);
void HandleAction_SafariZoneBallThrow(void);
@ -116,106 +117,106 @@ u8 GetBattlerForBattleScript(u8 caseId);
void PressurePPLose(u8 target, u8 attacker, u16 move);
void PressurePPLoseOnUsingPerishSong(u8 attacker);
void PressurePPLoseOnUsingImprison(u8 attacker);
bool32 IsBattlerMarkedForControllerExec(u8 battler);
void MarkBattlerForControllerExec(u8 battler);
void MarkBattlerReceivedLinkData(u8 battler);
void CancelMultiTurnMoves(u8 battler);
bool8 WasUnableToUseMove(u8 battler);
void PrepareStringBattle(u16 stringId, u8 battler);
bool32 IsBattlerMarkedForControllerExec(u32 battler);
void MarkBattlerForControllerExec(u32 battler);
void MarkBattlerReceivedLinkData(u32 battler);
void CancelMultiTurnMoves(u32 battler);
bool32 WasUnableToUseMove(u32 battler);
void PrepareStringBattle(u16 stringId, u32 battler);
void ResetSentPokesToOpponentValue(void);
void OpponentSwitchInResetSentPokesToOpponentValue(u8 battler);
void UpdateSentPokesToOpponentValue(u8 battler);
void OpponentSwitchInResetSentPokesToOpponentValue(u32 battler);
void UpdateSentPokesToOpponentValue(u32 battler);
void BattleScriptPush(const u8 *bsPtr);
void BattleScriptPushCursor(void);
void BattleScriptPop(void);
u32 TrySetCantSelectMoveBattleScript(u32 battler);
u8 CheckMoveLimitations(u8 battler, u8 unusableMoves, u16 check);
u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check);
bool32 AreAllMovesUnusable(u32 battler);
u8 GetImprisonedMovesCount(u8 battler, u16 move);
u8 GetImprisonedMovesCount(u32 battler, u16 move);
u8 DoFieldEndTurnEffects(void);
s32 GetDrainedBigRootHp(u32 battler, s32 hp);
u8 DoBattlerEndTurnEffects(void);
bool8 HandleWishPerishSongOnTurnEnd(void);
bool8 HandleFaintedMonActions(void);
bool32 HandleWishPerishSongOnTurnEnd(void);
bool32 HandleFaintedMonActions(void);
void TryClearRageAndFuryCutter(void);
u8 AtkCanceller_UnableToUseMove(u32 moveType);
void SetAtkCancellerForCalledMove(void);
u8 AtkCanceller_UnableToUseMove2(void);
bool8 HasNoMonsToSwitch(u8 battler, u8 r1, u8 r2);
bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility);
u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 moveArg);
bool32 TryPrimalReversion(u8 battler);
bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2);
bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility);
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg);
bool32 TryPrimalReversion(u32 battler);
bool32 IsNeutralizingGasOnField(void);
u32 GetBattlerAbility(u8 battler);
u32 GetBattlerAbility(u32 battler);
u32 IsAbilityOnSide(u32 battler, u32 ability);
u32 IsAbilityOnOpposingSide(u32 battler, u32 ability);
u32 IsAbilityOnField(u32 ability);
u32 IsAbilityOnFieldExcept(u32 battler, u32 ability);
u32 IsAbilityPreventingEscape(u32 battler);
bool32 IsBattlerProtected(u8 battler, u16 move);
bool32 IsBattlerProtected(u32 battler, u32 move);
bool32 CanBattlerEscape(u32 battler); // no ability check
void BattleScriptExecute(const u8 *BS_ptr);
void BattleScriptPushCursorAndCallback(const u8 *BS_ptr);
u8 ItemBattleEffects(u8 caseID, u8 battler, bool8 moveTurn);
void ClearFuryCutterDestinyBondGrudge(u8 battler);
u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn);
void ClearFuryCutterDestinyBondGrudge(u32 battler);
void HandleAction_RunBattleScript(void);
u32 SetRandomTarget(u32 battler);
u32 GetMoveTarget(u16 move, u8 setTarget);
u8 IsMonDisobedient(void);
u32 GetBattlerHoldEffect(u8 battler, bool32 checkNegating);
u32 GetBattlerHoldEffectParam(u8 battler);
bool32 IsMoveMakingContact(u16 move, u8 battlerAtk);
bool32 IsBattlerGrounded(u8 battler);
bool32 IsBattlerAlive(u8 battler);
u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move);
u32 GetBattlerWeight(u8 battler);
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
u32 GetBattlerHoldEffectParam(u32 battler);
bool32 IsMoveMakingContact(u32 move, u32 battlerAtk);
bool32 IsBattlerGrounded(u32 battler);
bool32 IsBattlerAlive(u32 battler);
u32 GetMoveSlot(u16 *moves, u32 move);
u32 GetBattlerWeight(u32 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 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier,
u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef);
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities);
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
uq4_12_t GetTypeModifier(u8 atkType, u8 defType);
s32 GetStealthHazardDamage(u8 hazardType, u8 battler);
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
s32 GetStealthHazardDamage(u8 hazardType, u32 battler);
s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp);
bool32 CanMegaEvolve(u8 battler);
bool32 CanUltraBurst(u8 battler);
bool32 IsBattlerMegaEvolved(u8 battler);
bool32 IsBattlerPrimalReverted(u8 battler);
bool32 IsBattlerUltraBursted(u8 battler);
u16 GetBattleFormChangeTargetSpecies(u8 battler, u16 method);
bool32 TryBattleFormChange(u8 battler, u16 method);
bool32 CanMegaEvolve(u32 battler);
bool32 CanUltraBurst(u32 battler);
bool32 IsBattlerMegaEvolved(u32 battler);
bool32 IsBattlerPrimalReverted(u32 battler);
bool32 IsBattlerUltraBursted(u32 battler);
u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method);
bool32 TryBattleFormChange(u32 battler, u16 method);
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u8 battler, u16 itemId);
bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId);
u32 GetIllusionMonSpecies(u32 battler);
struct Pokemon *GetIllusionMonPtr(u32 battler);
void ClearIllusionMon(u32 battler);
bool32 SetIllusionMon(struct Pokemon *mon, u32 battler);
bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battler);
bool32 ShouldGetStatBadgeBoost(u16 flagId, u32 battler);
u8 GetBattleMoveSplit(u32 moveId);
bool32 CanFling(u32 battler);
bool32 IsTelekinesisBannedSpecies(u16 species);
bool32 IsHealBlockPreventingMove(u32 battler, u32 move);
bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId);
bool32 IsPartnerMonFromSameTrainer(u8 battler);
u8 GetSplitBasedOnStats(u8 battler);
bool32 TestSheerForceFlag(u8 battler, u16 move);
bool32 IsPartnerMonFromSameTrainer(u32 battler);
u8 GetSplitBasedOnStats(u32 battler);
bool32 TestSheerForceFlag(u32 battler, u16 move);
void TryRestoreHeldItems(void);
bool32 CanStealItem(u8 battlerStealing, u8 battlerItem, u16 item);
void TrySaveExchangedItem(u8 battler, u16 stolenItem);
bool32 IsPartnerMonFromSameTrainer(u8 battler);
u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute);
bool32 IsBattlerAffectedByHazards(u8 battler, bool32 toxicSpikes);
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);
u16 GetUsedHeldItem(u8 battler);
bool32 IsBattlerWeatherAffected(u8 battler, u32 weatherFlags);
u32 GetBattlerMoveTargetType(u8 battler, u16 move);
bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move);
bool8 IsMoveAffectedByParentalBond(u16 move, u8 battler);
bool32 CanStealItem(u32 battlerStealing, u32 battlerItem, u16 item);
void TrySaveExchangedItem(u32 battler, u16 stolenItem);
bool32 IsPartnerMonFromSameTrainer(u32 battler);
u8 TryHandleSeed(u32 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute);
bool32 IsBattlerAffectedByHazards(u32 battler, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool32 slowToFast);
bool32 CompareStat(u32 battler, u8 statId, u8 cmpTo, u8 cmpKind);
bool32 TryRoomService(u32 battler);
void BufferStatChange(u32 battler, u8 statId, u8 stringId);
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);
u16 GetUsedHeldItem(u32 battler);
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags);
u32 GetBattlerMoveTargetType(u32 battler, u32 move);
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon);
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
void RecalcBattlerStats(u32 battler, struct Pokemon *mon);
@ -231,21 +232,21 @@ bool32 IsGastroAcidBannedAbility(u16 ability);
bool32 IsEntrainmentBannedAbilityAttacker(u16 ability);
bool32 IsEntrainmentTargetOrSimpleBeamBannedAbility(u16 ability);
bool32 CanSleep(u8 battler);
bool32 CanBePoisoned(u8 battlerAttacker, u8 battlerTarget);
bool32 CanBeBurned(u8 battler);
bool32 CanBeParalyzed(u8 battler);
bool32 CanBeFrozen(u8 battler);
bool32 CanGetFrostbite(u8 battler);
bool32 CanBeConfused(u8 battler);
bool32 IsBattlerTerrainAffected(u8 battler, u32 terrainFlag);
u32 GetBattlerFriendshipScore(u8 battler);
u32 CountBattlerStatIncreases(u8 battler, bool32 countEvasionAcc);
bool32 CanSleep(u32 battler);
bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget);
bool32 CanBeBurned(u32 battler);
bool32 CanBeParalyzed(u32 battler);
bool32 CanBeFrozen(u32 battler);
bool32 CanGetFrostbite(u32 battler);
bool32 CanBeConfused(u32 battler);
bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag);
u32 GetBattlerFriendshipScore(u32 battler);
u32 CountBattlerStatIncreases(u32 battler, bool32 countEvasionAcc);
bool32 IsMyceliumMightOnField(void);
bool8 ChangeTypeBasedOnTerrain(u8 battler);
void RemoveConfusionStatus(u8 battler);
u8 GetBattlerGender(u8 battler);
bool8 AreBattlersOfOppositeGender(u8 battler1, u8 battler2);
u32 CalcSecondaryEffectChance(u8 battler, u8 secondaryEffectChance);
bool32 ChangeTypeBasedOnTerrain(u32 battler);
void RemoveConfusionStatus(u32 battler);
u8 GetBattlerGender(u32 battler);
bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2);
u32 CalcSecondaryEffectChance(u32 battler, u8 secondaryEffectChance);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -63,8 +63,8 @@ bool8 AddPyramidBagItem(u16 itemId, u16 count);
bool8 RemovePyramidBagItem(u16 itemId, u16 count);
const u8 *ItemId_GetName(u16 itemId);
u16 ItemId_GetPrice(u16 itemId);
u8 ItemId_GetHoldEffect(u16 itemId);
u8 ItemId_GetHoldEffectParam(u16 itemId);
u32 ItemId_GetHoldEffect(u32 itemId);
u32 ItemId_GetHoldEffectParam(u32 itemId);
const u8 *ItemId_GetDescription(u16 itemId);
u8 ItemId_GetImportance(u16 itemId);
u8 ItemId_GetPocket(u16 itemId);
@ -72,7 +72,7 @@ u8 ItemId_GetType(u16 itemId);
ItemUseFunc ItemId_GetFieldFunc(u16 itemId);
u8 ItemId_GetBattleUsage(u16 itemId);
u8 ItemId_GetSecondaryId(u16 itemId);
u8 ItemId_GetFlingPower(u16 itemId);
u32 ItemId_GetFlingPower(u32 itemId);
u32 GetItemStatus1Mask(u16 itemId);
u32 GetItemStatus2Mask(u16 itemId);

File diff suppressed because it is too large Load Diff

View File

@ -400,7 +400,7 @@ static bool8 ShouldSwitchIfGameStatePrompt(u32 battler)
&& AnyStatIsRaised(battler))
switchMon = FALSE;
if (AiExpectsToFaintPlayer(battler)
&& !WillAIStrikeFirst()
&& !AI_STRIKES_FIRST(battler, opposingBattler, 0)
&& !AI_OpponentCanFaintAiWithMod(battler, 0))
switchMon = FALSE;
}

File diff suppressed because it is too large Load Diff

View File

@ -750,7 +750,7 @@ static void SetAllPlayersBerryData(void)
{
s32 numPlayers;
struct BattleEnigmaBerry *src;
u8 battler;
u32 battler;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
@ -2267,7 +2267,7 @@ static void EndLinkBattleInSteps(void)
case 2:
if (!gPaletteFade.active)
{
u8 battlerCount;
u32 battlerCount;
gMain.anyLinkBattlerHasFrontierPass = RecordedBattle_GetFrontierPassFlag();
@ -3723,7 +3723,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;
}
@ -3770,7 +3770,7 @@ static void TryDoEventsBeforeFirstTurn(void)
{
for (j = i + 1; j < gBattlersCount; j++)
{
if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) != 0)
if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) != 0)
SwapTurnOrder(i, j);
}
}
@ -3856,7 +3856,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)
{
@ -3948,7 +3948,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();
@ -4020,11 +4020,10 @@ u8 IsRunningFromBattleImpossible(u32 battler)
return BATTLE_RUN_SUCCESS;
}
void SwitchPartyOrder(u8 battler)
void SwitchPartyOrder(u32 battler)
{
s32 i;
u8 partyId1;
u8 partyId2;
u32 partyId1, partyId2;
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
gBattlePartyCurrentOrder[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders));
@ -4070,7 +4069,7 @@ static void HandleTurnActionSelectionState(void)
gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0;
for (battler = 0; battler < gBattlersCount; battler++)
{
u8 position = GetBattlerPosition(battler);
u32 position = GetBattlerPosition(battler);
switch (gBattleCommunication[battler])
{
case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn.
@ -4083,7 +4082,7 @@ static void HandleTurnActionSelectionState(void)
{
gBattleStruct->aiMoveOrAction[battler] = ComputeBattleAiScores(battler);
}
break;
// fallthrough
case STATE_BEFORE_ACTION_CHOSEN: // Choose an action.
*(gBattleStruct->monToSwitchIntoId + battler) = PARTY_SIZE;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI
@ -4597,11 +4596,10 @@ void SwapTurnOrder(u8 id1, u8 id2)
SWAP(gBattlerByTurnOrder[id1], gBattlerByTurnOrder[id2], temp);
}
u32 GetBattlerTotalSpeedStat(u8 battler)
// For AI, so it doesn't 'cheat' by knowing player's ability
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect)
{
u32 speed = gBattleMons[battler].speed;
u32 ability = GetBattlerAbility(battler);
u32 holdEffect = GetBattlerHoldEffect(battler, TRUE);
u32 highestStat = GetHighestStatId(battler);
// weather abilities
@ -4668,6 +4666,13 @@ u32 GetBattlerTotalSpeedStat(u8 battler)
return speed;
}
u32 GetBattlerTotalSpeedStat(u32 battler)
{
u32 ability = GetBattlerAbility(battler);
u32 holdEffect = GetBattlerHoldEffect(battler, TRUE);
return GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect);
}
s8 GetChosenMovePriority(u32 battler)
{
u16 move;
@ -4732,17 +4737,13 @@ s8 GetMovePriority(u32 battler, u16 move)
return priority;
}
u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
// Function for AI with variables provided as arguments to speed the computation time
u32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2)
{
u8 strikesFirst = 0;
u32 speedBattler1 = 0, speedBattler2 = 0;
u32 holdEffectBattler1 = 0, holdEffectBattler2 = 0;
s8 priority1 = 0, priority2 = 0;
u16 ability1 = GetBattlerAbility(battler1), ability2 = GetBattlerAbility(battler2);
u32 strikesFirst = 0;
// Battler 1
speedBattler1 = GetBattlerTotalSpeedStat(battler1);
holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE);
// Quick Draw
if (!ignoreChosenMoves && ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && Random() % 100 < 30)
gProtectStructs[battler1].quickDraw = TRUE;
@ -4753,8 +4754,6 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
gProtectStructs[battler1].usedCustapBerry = TRUE;
// Battler 2
speedBattler2 = GetBattlerTotalSpeedStat(battler2);
holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE);
// Quick Draw
if (!ignoreChosenMoves && ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && Random() % 100 < 30)
gProtectStructs[battler2].quickDraw = TRUE;
@ -4764,14 +4763,6 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
|| (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, 4, gBattleMons[battler2].item))))
gProtectStructs[battler2].usedCustapBerry = TRUE;
if (!ignoreChosenMoves)
{
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
priority1 = GetChosenMovePriority(battler1);
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
priority2 = GetChosenMovePriority(battler2);
}
if (priority1 == priority2)
{
// QUICK CLAW / CUSTAP - always first
@ -4834,6 +4825,28 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
return strikesFirst;
}
u32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves)
{
s32 priority1 = 0, priority2 = 0;
u32 ability1 = GetBattlerAbility(battler1);
u32 speedBattler1 = GetBattlerTotalSpeedStat(battler1);
u32 holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE);
u32 speedBattler2 = GetBattlerTotalSpeedStat(battler2);
u32 holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE);
u32 ability2 = GetBattlerAbility(battler2);
if (!ignoreChosenMoves)
{
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
priority1 = GetChosenMovePriority(battler1);
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
priority2 = GetChosenMovePriority(battler2);
}
return GetWhichBattlerFasterArgs(battler1, battler2, ignoreChosenMoves, ability1, ability2,
holdEffectBattler1, holdEffectBattler2, speedBattler1, speedBattler2, priority1, priority2);
}
static void SetActionsAndBattlersTurnOrder(void)
{
s32 turnOrderId = 0;
@ -4927,7 +4940,7 @@ static void SetActionsAndBattlersTurnOrder(void)
&& gActionsByTurnOrder[i] != B_ACTION_THROW_BALL
&& gActionsByTurnOrder[j] != B_ACTION_THROW_BALL)
{
if (GetWhoStrikesFirst(battler1, battler2, FALSE))
if (GetWhichBattlerFaster(battler1, battler2, FALSE))
SwapTurnOrder(i, j);
}
}
@ -5091,7 +5104,7 @@ static void TryChangeTurnOrder(void)
if (gActionsByTurnOrder[i] == B_ACTION_USE_MOVE
&& gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)
{
if (GetWhoStrikesFirst(battler1, battler2, FALSE))
if (GetWhichBattlerFaster(battler1, battler2, FALSE))
SwapTurnOrder(i, j);
}
}
@ -5574,7 +5587,7 @@ void RunBattleScriptCommands(void)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk)
void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
{
u32 moveType, ateType, attackerAbility;
u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
@ -5713,8 +5726,8 @@ void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk)
// var8001 - var8007: stat changes
void SetTotemBoost(void)
{
u8 battler = gSpecialVar_0x8000;
u8 i;
u32 battler = gSpecialVar_0x8000;
u32 i;
for (i = 0; i < (NUM_BATTLE_STATS - 1); i++)
{

View File

@ -1753,10 +1753,11 @@ static void Cmd_accuracycheck(void)
{
CMD_ARGS(const u8 *failInstr, u16 move);
u16 type, move = cmd->move;
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
u16 gBattlerAttackerAbility = GetBattlerAbility(gBattlerAttacker);
u8 gBattlerAttackerHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
u32 type, move = cmd->move;
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
if (move == ACC_CURR_MOVE)
move = gCurrentMove;
@ -1772,7 +1773,7 @@ static void Cmd_accuracycheck(void)
}
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|| (gSpecialStatuses[gBattlerAttacker].multiHitOn
&& (gBattlerAttackerAbility == ABILITY_SKILL_LINK || gBattlerAttackerHoldEffect == HOLD_EFFECT_LOADED_DICE
&& (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE
|| !(gBattleMoves[move].effect == EFFECT_TRIPLE_KICK || gBattleMoves[move].effect == EFFECT_POPULATION_BOMB))))
{
// No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb
@ -1792,16 +1793,16 @@ static void Cmd_accuracycheck(void)
gBattlerAttacker,
gBattlerTarget,
move,
gBattlerAttackerAbility,
GetBattlerAbility(gBattlerTarget),
gBattlerAttackerHoldEffect,
abilityAtk,
abilityDef,
holdEffectAtk,
GetBattlerHoldEffect(gBattlerTarget, TRUE)
);
if (!RandomPercentage(RNG_ACCURACY, accuracy))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
if (gBattlerAttackerHoldEffect == HOLD_EFFECT_BLUNDER_POLICY)
if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
@ -1811,7 +1812,7 @@ static void Cmd_accuracycheck(void)
gBattleCommunication[MISS_TYPE] = B_MSG_MISSED;
if (gBattleMoves[move].power)
CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, TRUE);
CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, abilityDef, TRUE);
}
JumpIfMoveFailed(7, move);
}
@ -1908,24 +1909,15 @@ 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 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
{
s32 critChance = 0;
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT
|| gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
|| gStatuses3[battlerAtk] & STATUS3_CANT_SCORE_A_CRIT)
{
critChance = -1;
}
else if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{
if (recordAbility)
RecordAbilityBattle(battlerDef, abilityDef);
critChance = -1;
}
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
@ -1935,27 +1927,41 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
}
else
{
critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0)
+ (gBattleMoves[gCurrentMove].highCritRatio)
+ (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
+ 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[gBattlerAttacker].species == SPECIES_CHANSEY)
+ 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY)
+ 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)
#if B_AFFECTION_MECHANICS == TRUE
+ 2 * (GetBattlerFriendshipScore(gBattlerAttacker) >= FRIENDSHIP_200_TO_254)
+ 2 * (GetBattlerFriendshipScore(battlerAtk) >= FRIENDSHIP_200_TO_254)
#endif
+ (abilityAtk == ABILITY_SUPER_LUCK);
if (abilityDef == ABILITY_BATTLE_ARMOR || abilityDef == ABILITY_SHELL_ARMOR)
{
if (recordAbility && critChance >= 2) // Record ability only if move had at least +1 chance to get a crit.
RecordAbilityBattle(battlerDef, abilityDef);
critChance = -1;
}
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
}
return critChance;
}
s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility)
{
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
return CalcCritChanceStageArgs(battlerAtk, battlerDef, move, recordAbility, abilityAtk, abilityDef, holdEffectAtk);
}
#undef BENEFITS_FROM_LEEK
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move)
s32 GetCritHitChance(s32 critChanceIndex)
{
s32 critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE);
if (critChanceIndex < 0)
return -1;
else
@ -2006,7 +2012,7 @@ static void Cmd_typecalc(void)
u8 moveType;
GET_MOVE_TYPE(gCurrentMove, moveType);
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, TRUE);
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE);
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -5679,6 +5685,7 @@ static void Cmd_moveend(void)
if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove)
{
gLastMoves[gBattlerAttacker] = gChosenMove;
RecordKnownMove(gBattlerAttacker, gChosenMove);
gLastResultingMoves[gBattlerAttacker] = gCurrentMove;
}
}
@ -8197,7 +8204,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++)
@ -14703,7 +14710,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;
@ -14719,7 +14726,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
@ -15781,7 +15788,7 @@ static const u16 sParentalBondBannedEffects[] =
EFFECT_UPROAR,
};
bool8 IsMoveAffectedByParentalBond(u16 move, u8 battler)
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler)
{
if (move != MOVE_NONE && move != MOVE_STRUGGLE
&& gBattleMoves[move].split != SPLIT_STATUS

File diff suppressed because it is too large Load Diff

View File

@ -884,12 +884,12 @@ u16 ItemId_GetPrice(u16 itemId)
return gItems[SanitizeItemId(itemId)].price;
}
u8 ItemId_GetHoldEffect(u16 itemId)
u32 ItemId_GetHoldEffect(u32 itemId)
{
return gItems[SanitizeItemId(itemId)].holdEffect;
}
u8 ItemId_GetHoldEffectParam(u16 itemId)
u32 ItemId_GetHoldEffectParam(u32 itemId)
{
return gItems[SanitizeItemId(itemId)].holdEffectParam;
}
@ -956,7 +956,7 @@ u8 ItemId_GetSecondaryId(u16 itemId)
return gItems[SanitizeItemId(itemId)].secondaryId;
}
u8 ItemId_GetFlingPower(u16 itemId)
u32 ItemId_GetFlingPower(u32 itemId)
{
return gItems[SanitizeItemId(itemId)].flingPower;
}