mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
final ai optimizations
This commit is contained in:
parent
5ea66f3c0c
commit
bb9501449c
@ -32,10 +32,10 @@ u32 GetHealthPercentage(u32 battler);
|
|||||||
bool32 IsBattlerTrapped(u32 battler, bool32 switching);
|
bool32 IsBattlerTrapped(u32 battler, bool32 switching);
|
||||||
u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
|
u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
|
||||||
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
|
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
|
||||||
bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
|
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
|
||||||
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
|
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
|
||||||
s32 AI_GetAbility(u32 battlerId);
|
s32 AI_GetAbility(u32 battlerId);
|
||||||
u16 AI_GetHoldEffect(u32 battlerId);
|
u32 AI_GetHoldEffect(u32 battlerId);
|
||||||
u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u32 move);
|
u32 AI_GetMoveAccuracy(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||||
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
|
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
|
||||||
u32 AI_GetWeather(struct AiLogicData *aiData);
|
u32 AI_GetWeather(struct AiLogicData *aiData);
|
||||||
|
@ -57,7 +57,7 @@ void SwitchInClearSetData(u32 battler);
|
|||||||
void FaintClearSetData(u32 battler);
|
void FaintClearSetData(u32 battler);
|
||||||
void BattleTurnPassed(void);
|
void BattleTurnPassed(void);
|
||||||
u8 IsRunningFromBattleImpossible(u32 battler);
|
u8 IsRunningFromBattleImpossible(u32 battler);
|
||||||
void SwitchPartyOrder(u8 battlerId);
|
void SwitchPartyOrder(u32 battlerId);
|
||||||
void SwapTurnOrder(u8 id1, u8 id2);
|
void SwapTurnOrder(u8 id1, u8 id2);
|
||||||
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
|
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
|
||||||
u32 GetBattlerTotalSpeedStat(u32 battler);
|
u32 GetBattlerTotalSpeedStat(u32 battler);
|
||||||
@ -69,7 +69,7 @@ u32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
|
|||||||
void RunBattleScriptCommands_PopCallbacksStack(void);
|
void RunBattleScriptCommands_PopCallbacksStack(void);
|
||||||
void RunBattleScriptCommands(void);
|
void RunBattleScriptCommands(void);
|
||||||
void SpecialStatusesClear(void);
|
void SpecialStatusesClear(void);
|
||||||
void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk);
|
void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk);
|
||||||
bool32 IsWildMonSmart(void);
|
bool32 IsWildMonSmart(void);
|
||||||
u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags);
|
u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags);
|
||||||
void ModifyPersonalityForNature(u32 *personality, u32 newNature);
|
void ModifyPersonalityForNature(u32 *personality, u32 newNature);
|
||||||
|
@ -16,8 +16,9 @@ struct StatFractions
|
|||||||
u8 divisor;
|
u8 divisor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility);
|
||||||
s32 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move);
|
s32 GetCritHitChance(s32 critChanceIndex);
|
||||||
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||||
u8 GetBattlerTurnOrderNum(u8 battlerId);
|
u8 GetBattlerTurnOrderNum(u8 battlerId);
|
||||||
bool32 NoAliveMonsForEitherParty(void);
|
bool32 NoAliveMonsForEitherParty(void);
|
||||||
|
@ -174,7 +174,7 @@ u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter);
|
|||||||
s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags);
|
s32 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,
|
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);
|
u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef);
|
||||||
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities);
|
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 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||||
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
|
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
|
||||||
s32 GetStealthHazardDamage(u8 hazardType, u32 battler);
|
s32 GetStealthHazardDamage(u8 hazardType, u32 battler);
|
||||||
|
@ -698,12 +698,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
|||||||
u32 weather;
|
u32 weather;
|
||||||
u16 predictedMove = aiData->predictedMoves[battlerDef];
|
u16 predictedMove = aiData->predictedMoves[battlerDef];
|
||||||
|
|
||||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
|
||||||
GET_MOVE_TYPE(move, moveType);
|
|
||||||
|
|
||||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||||
return score;
|
return score;
|
||||||
|
|
||||||
|
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||||
GET_MOVE_TYPE(move, moveType);
|
GET_MOVE_TYPE(move, moveType);
|
||||||
|
|
||||||
// check non-user target
|
// check non-user target
|
||||||
@ -3757,10 +3755,9 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
|||||||
if (gLastMoves[battlerDef] != MOVE_NONE
|
if (gLastMoves[battlerDef] != MOVE_NONE
|
||||||
&& gLastMoves[battlerDef] != 0xFFFF)
|
&& gLastMoves[battlerDef] != 0xFFFF)
|
||||||
{
|
{
|
||||||
/* TODO predicted moves
|
|
||||||
if (gLastMoves[battlerDef] == predictedMove)
|
if (gLastMoves[battlerDef] == predictedMove)
|
||||||
score += 3;
|
score += 3;
|
||||||
else */if (CanMoveFaintBattler(gLastMoves[battlerDef], battlerDef, battlerAtk, 1))
|
else if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1))
|
||||||
score += 2; //Disable move that can kill attacker
|
score += 2; //Disable move that can kill attacker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,7 +723,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split)
|
|||||||
{
|
{
|
||||||
SetTypeBeforeUsingMove(moves[i], attacker);
|
SetTypeBeforeUsingMove(moves[i], attacker);
|
||||||
GET_MOVE_TYPE(moves[i], moveType);
|
GET_MOVE_TYPE(moves[i], moveType);
|
||||||
if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, FALSE) != 0)
|
if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0)
|
||||||
usable |= gBitTable[i];
|
usable |= gBitTable[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -731,41 +731,6 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split)
|
|||||||
return (usable == 0);
|
return (usable == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool32 AI_GetIfCrit(u32 move, u32 battlerAtk, u32 battlerDef)
|
|
||||||
{
|
|
||||||
bool32 isCrit;
|
|
||||||
|
|
||||||
switch (CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE))
|
|
||||||
{
|
|
||||||
case -1:
|
|
||||||
case 0:
|
|
||||||
default:
|
|
||||||
isCrit = FALSE;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (gBattleMoves[move].highCritRatio && (Random() % 5 == 0))
|
|
||||||
isCrit = TRUE;
|
|
||||||
else
|
|
||||||
isCrit = FALSE;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (gBattleMoves[move].highCritRatio && (Random() % 2 == 0))
|
|
||||||
isCrit = TRUE;
|
|
||||||
else if (!(gBattleMoves[move].highCritRatio) && (Random() % 4) == 0)
|
|
||||||
isCrit = TRUE;
|
|
||||||
else
|
|
||||||
isCrit = FALSE;
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
isCrit = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isCrit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To save computation time this function has 2 variants. One saves, sets and restores battlers, while the other doesn't.
|
// 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)
|
s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower)
|
||||||
{
|
{
|
||||||
@ -776,8 +741,9 @@ s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *type
|
|||||||
|
|
||||||
s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather)
|
s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather)
|
||||||
{
|
{
|
||||||
s32 dmg, moveType, critDmg, normalDmg, fixedBasePower, n;
|
s32 dmg, moveType;
|
||||||
uq4_12_t effectivenessMultiplier;
|
uq4_12_t effectivenessMultiplier;
|
||||||
|
struct AiLogicData *aiData = AI_DATA;
|
||||||
|
|
||||||
SetBattlerData(battlerAtk);
|
SetBattlerData(battlerAtk);
|
||||||
SetBattlerData(battlerDef);
|
SetBattlerData(battlerDef);
|
||||||
@ -797,14 +763,12 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
|
|||||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||||
GET_MOVE_TYPE(move, moveType);
|
GET_MOVE_TYPE(move, moveType);
|
||||||
|
|
||||||
effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE);
|
effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE);
|
||||||
if (gBattleMoves[move].power)
|
if (gBattleMoves[move].power)
|
||||||
{
|
{
|
||||||
s32 critChance;
|
s32 critChanceIndex, normalDmg, fixedBasePower, n;
|
||||||
struct AiLogicData *aiData = AI_DATA;
|
|
||||||
|
|
||||||
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
ProteanTryChangeType(battlerAtk, aiData->abilities[battlerAtk], move, moveType);
|
||||||
critChance = GetInverseCritChance(battlerAtk, battlerDef, move);
|
|
||||||
// Certain moves like Rollout calculate damage based on values which change during the move execution, but before calling dmg calc.
|
// Certain moves like Rollout calculate damage based on values which change during the move execution, but before calling dmg calc.
|
||||||
switch (gBattleMoves[move].effect)
|
switch (gBattleMoves[move].effect)
|
||||||
{
|
{
|
||||||
@ -823,15 +787,22 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes
|
|||||||
effectivenessMultiplier, weather, FALSE,
|
effectivenessMultiplier, weather, FALSE,
|
||||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||||
critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
|
||||||
|
critChanceIndex = CalcCritChanceStageArgs(battlerAtk, battlerDef, move, FALSE, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], aiData->holdEffects[battlerAtk]);
|
||||||
|
if (critChanceIndex > 1) // Consider crit damage only if a move has at least +1 crit chance
|
||||||
|
{
|
||||||
|
s32 critDmg = CalculateMoveDamageVars(move, battlerAtk, battlerDef, moveType, fixedBasePower,
|
||||||
effectivenessMultiplier, weather, TRUE,
|
effectivenessMultiplier, weather, TRUE,
|
||||||
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef],
|
||||||
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
aiData->abilities[battlerAtk], aiData->abilities[battlerDef]);
|
||||||
|
u32 critChance = GetCritHitChance(critChanceIndex);
|
||||||
if (critChance == -1)
|
// With critChance getting closer to 1, dmg gets closer to critDmg.
|
||||||
dmg = normalDmg;
|
|
||||||
else
|
|
||||||
dmg = (critDmg + normalDmg * (critChance - 1)) / (critChance);
|
dmg = (critDmg + normalDmg * (critChance - 1)) / (critChance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dmg = normalDmg;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gBattleStruct->zmove.active)
|
if (!gBattleStruct->zmove.active)
|
||||||
{
|
{
|
||||||
@ -1056,7 +1027,7 @@ uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef)
|
|||||||
gBattleStruct->dynamicMoveType = 0;
|
gBattleStruct->dynamicMoveType = 0;
|
||||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||||
GET_MOVE_TYPE(move, moveType);
|
GET_MOVE_TYPE(move, moveType);
|
||||||
typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE);
|
typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], FALSE);
|
||||||
|
|
||||||
RestoreBattlerData(battlerAtk);
|
RestoreBattlerData(battlerAtk);
|
||||||
RestoreBattlerData(battlerDef);
|
RestoreBattlerData(battlerDef);
|
||||||
@ -1191,18 +1162,14 @@ bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool32 CanMoveFaintBattler(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits)
|
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits)
|
||||||
{
|
{
|
||||||
s32 i, dmg;
|
u32 indexSlot = GetMoveSlot(GetMovesArray(battlerDef), move);
|
||||||
u8 effectiveness;
|
if (indexSlot < MAX_MON_MOVES)
|
||||||
u32 unusable = AI_DATA->moveLimitations[battlerDef];
|
{
|
||||||
|
if (GetNoOfHitsToKO(AI_DATA->simulatedDmg[battlerDef][battlerAtk][indexSlot], gBattleMons[battlerAtk].hp) <= nHits)
|
||||||
if (move != MOVE_NONE
|
|
||||||
&& move != 0xFFFF
|
|
||||||
&& !(unusable & gBitTable[i])
|
|
||||||
&& AI_CalcDamageSaveBattlers(move, battlerDef, battlerAtk, &effectiveness, FALSE) >= gBattleMons[battlerAtk].hp)
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,7 +1249,7 @@ s32 AI_GetAbility(u32 battlerId)
|
|||||||
return ABILITY_NONE; // Unknown.
|
return ABILITY_NONE; // Unknown.
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 AI_GetHoldEffect(u32 battlerId)
|
u32 AI_GetHoldEffect(u32 battlerId)
|
||||||
{
|
{
|
||||||
u32 holdEffect;
|
u32 holdEffect;
|
||||||
|
|
||||||
|
@ -751,7 +751,7 @@ static void SetAllPlayersBerryData(void)
|
|||||||
{
|
{
|
||||||
s32 numPlayers;
|
s32 numPlayers;
|
||||||
struct BattleEnigmaBerry *src;
|
struct BattleEnigmaBerry *src;
|
||||||
u8 battler;
|
u32 battler;
|
||||||
|
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||||
{
|
{
|
||||||
@ -2268,7 +2268,7 @@ static void EndLinkBattleInSteps(void)
|
|||||||
case 2:
|
case 2:
|
||||||
if (!gPaletteFade.active)
|
if (!gPaletteFade.active)
|
||||||
{
|
{
|
||||||
u8 battlerCount;
|
u32 battlerCount;
|
||||||
|
|
||||||
gMain.anyLinkBattlerHasFrontierPass = RecordedBattle_GetFrontierPassFlag();
|
gMain.anyLinkBattlerHasFrontierPass = RecordedBattle_GetFrontierPassFlag();
|
||||||
|
|
||||||
@ -4021,11 +4021,10 @@ u8 IsRunningFromBattleImpossible(u32 battler)
|
|||||||
return BATTLE_RUN_SUCCESS;
|
return BATTLE_RUN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchPartyOrder(u8 battler)
|
void SwitchPartyOrder(u32 battler)
|
||||||
{
|
{
|
||||||
s32 i;
|
s32 i;
|
||||||
u8 partyId1;
|
u32 partyId1, partyId2;
|
||||||
u8 partyId2;
|
|
||||||
|
|
||||||
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
||||||
gBattlePartyCurrentOrder[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders));
|
gBattlePartyCurrentOrder[i] = *(battler * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders));
|
||||||
@ -5589,7 +5588,7 @@ void RunBattleScriptCommands(void)
|
|||||||
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
|
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk)
|
void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk)
|
||||||
{
|
{
|
||||||
u32 moveType, ateType, attackerAbility;
|
u32 moveType, ateType, attackerAbility;
|
||||||
u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
|
u16 holdEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
|
||||||
@ -5728,8 +5727,8 @@ void SetTypeBeforeUsingMove(u16 move, u32 battlerAtk)
|
|||||||
// var8001 - var8007: stat changes
|
// var8001 - var8007: stat changes
|
||||||
void SetTotemBoost(void)
|
void SetTotemBoost(void)
|
||||||
{
|
{
|
||||||
u8 battler = gSpecialVar_0x8000;
|
u32 battler = gSpecialVar_0x8000;
|
||||||
u8 i;
|
u32 i;
|
||||||
|
|
||||||
for (i = 0; i < (NUM_BATTLE_STATS - 1); i++)
|
for (i = 0; i < (NUM_BATTLE_STATS - 1); i++)
|
||||||
{
|
{
|
||||||
|
@ -1752,10 +1752,11 @@ static void Cmd_accuracycheck(void)
|
|||||||
{
|
{
|
||||||
CMD_ARGS(const u8 *failInstr, u16 move);
|
CMD_ARGS(const u8 *failInstr, u16 move);
|
||||||
|
|
||||||
u16 type, move = cmd->move;
|
u32 type, move = cmd->move;
|
||||||
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
|
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
|
||||||
u16 gBattlerAttackerAbility = GetBattlerAbility(gBattlerAttacker);
|
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
||||||
u8 gBattlerAttackerHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
||||||
|
u32 holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
|
||||||
|
|
||||||
if (move == ACC_CURR_MOVE)
|
if (move == ACC_CURR_MOVE)
|
||||||
move = gCurrentMove;
|
move = gCurrentMove;
|
||||||
@ -1771,7 +1772,7 @@ static void Cmd_accuracycheck(void)
|
|||||||
}
|
}
|
||||||
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|
else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT
|
||||||
|| (gSpecialStatuses[gBattlerAttacker].multiHitOn
|
|| (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))))
|
|| !(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
|
// No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb
|
||||||
@ -1791,16 +1792,16 @@ static void Cmd_accuracycheck(void)
|
|||||||
gBattlerAttacker,
|
gBattlerAttacker,
|
||||||
gBattlerTarget,
|
gBattlerTarget,
|
||||||
move,
|
move,
|
||||||
gBattlerAttackerAbility,
|
abilityAtk,
|
||||||
GetBattlerAbility(gBattlerTarget),
|
abilityDef,
|
||||||
gBattlerAttackerHoldEffect,
|
holdEffectAtk,
|
||||||
GetBattlerHoldEffect(gBattlerTarget, TRUE)
|
GetBattlerHoldEffect(gBattlerTarget, TRUE)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!RandomPercentage(RNG_ACCURACY, accuracy))
|
if (!RandomPercentage(RNG_ACCURACY, accuracy))
|
||||||
{
|
{
|
||||||
gMoveResultFlags |= MOVE_RESULT_MISSED;
|
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
|
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
|
||||||
|
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
|
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
|
||||||
@ -1810,7 +1811,7 @@ static void Cmd_accuracycheck(void)
|
|||||||
gBattleCommunication[MISS_TYPE] = B_MSG_MISSED;
|
gBattleCommunication[MISS_TYPE] = B_MSG_MISSED;
|
||||||
|
|
||||||
if (gBattleMoves[move].power)
|
if (gBattleMoves[move].power)
|
||||||
CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, TRUE);
|
CalcTypeEffectivenessMultiplier(move, type, gBattlerAttacker, gBattlerTarget, abilityDef, TRUE);
|
||||||
}
|
}
|
||||||
JumpIfMoveFailed(7, move);
|
JumpIfMoveFailed(7, move);
|
||||||
}
|
}
|
||||||
@ -1907,24 +1908,15 @@ static void Cmd_ppreduce(void)
|
|||||||
#endif // B_CRIT_CHANCE
|
#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))
|
#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(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility)
|
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk)
|
||||||
{
|
{
|
||||||
s32 critChance = 0;
|
s32 critChance = 0;
|
||||||
u32 abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
|
||||||
u32 abilityDef = GetBattlerAbility(gBattlerTarget);
|
|
||||||
u32 holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
|
|
||||||
|
|
||||||
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT
|
if (gSideStatuses[battlerDef] & SIDE_STATUS_LUCKY_CHANT
|
||||||
|| gStatuses3[gBattlerAttacker] & STATUS3_CANT_SCORE_A_CRIT)
|
|| gStatuses3[battlerAtk] & STATUS3_CANT_SCORE_A_CRIT)
|
||||||
{
|
{
|
||||||
critChance = -1;
|
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
|
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|
||||||
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|
||||||
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
|
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
|
||||||
@ -1934,27 +1926,41 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
critChance = 2 * ((gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) != 0)
|
critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0)
|
||||||
+ (gBattleMoves[gCurrentMove].highCritRatio)
|
+ (gBattleMoves[gCurrentMove].highCritRatio)
|
||||||
+ (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
|
+ (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)
|
+ 2 * BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk)
|
||||||
#if B_AFFECTION_MECHANICS == TRUE
|
#if B_AFFECTION_MECHANICS == TRUE
|
||||||
+ 2 * (GetBattlerFriendshipScore(gBattlerAttacker) >= FRIENDSHIP_200_TO_254)
|
+ 2 * (GetBattlerFriendshipScore(battlerAtk) >= FRIENDSHIP_200_TO_254)
|
||||||
#endif
|
#endif
|
||||||
+ (abilityAtk == ABILITY_SUPER_LUCK);
|
+ (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))
|
if (critChance >= ARRAY_COUNT(sCriticalHitChance))
|
||||||
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
|
critChance = ARRAY_COUNT(sCriticalHitChance) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return critChance;
|
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
|
#undef BENEFITS_FROM_LEEK
|
||||||
|
|
||||||
s32 GetInverseCritChance(u32 battlerAtk, u32 battlerDef, u32 move)
|
s32 GetCritHitChance(s32 critChanceIndex)
|
||||||
{
|
{
|
||||||
s32 critChanceIndex = CalcCritChanceStage(battlerAtk, battlerDef, move, FALSE);
|
|
||||||
if (critChanceIndex < 0)
|
if (critChanceIndex < 0)
|
||||||
return -1;
|
return -1;
|
||||||
else
|
else
|
||||||
@ -2005,7 +2011,7 @@ static void Cmd_typecalc(void)
|
|||||||
u8 moveType;
|
u8 moveType;
|
||||||
|
|
||||||
GET_MOVE_TYPE(gCurrentMove, moveType);
|
GET_MOVE_TYPE(gCurrentMove, moveType);
|
||||||
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, TRUE);
|
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE);
|
||||||
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
|
@ -4368,7 +4368,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
|
|||||||
{
|
{
|
||||||
move = gBattleMons[i].moves[j];
|
move = gBattleMons[i].moves[j];
|
||||||
GET_MOVE_TYPE(move, moveType);
|
GET_MOVE_TYPE(move, moveType);
|
||||||
if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, FALSE) >= UQ_4_12(2.0))
|
if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, ABILITY_ANTICIPATION, FALSE) >= UQ_4_12(2.0))
|
||||||
{
|
{
|
||||||
effect++;
|
effect++;
|
||||||
break;
|
break;
|
||||||
@ -9827,7 +9827,8 @@ static u32 GetWeather(void)
|
|||||||
s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 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,
|
return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, randomFactor,
|
||||||
updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags), GetWeather());
|
updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerDef), updateFlags),
|
||||||
|
GetWeather());
|
||||||
}
|
}
|
||||||
|
|
||||||
// for AI so that typeEffectivenessModifier, weather, abilities and holdEffects are calculated only once
|
// for AI so that typeEffectivenessModifier, weather, abilities and holdEffects are calculated only once
|
||||||
@ -9985,13 +9986,12 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov
|
|||||||
return modifier;
|
return modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, bool32 recordAbilities)
|
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities)
|
||||||
{
|
{
|
||||||
uq4_12_t modifier = UQ_4_12(1.0);
|
uq4_12_t modifier = UQ_4_12(1.0);
|
||||||
|
|
||||||
if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY)
|
if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY)
|
||||||
{
|
{
|
||||||
u32 defAbility = GetBattlerAbility(defAbility);
|
|
||||||
modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility);
|
modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility);
|
||||||
if (gBattleMoves[move].effect == EFFECT_TWO_TYPED_MOVE)
|
if (gBattleMoves[move].effect == EFFECT_TWO_TYPED_MOVE)
|
||||||
modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier, defAbility);
|
modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier, defAbility);
|
||||||
|
Loading…
Reference in New Issue
Block a user