mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-16 11:37:40 +01:00
optimize dmg move result and ai who is faster
This commit is contained in:
parent
406209f738
commit
1a64938c9b
@ -289,6 +289,8 @@ 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];
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
|
||||
|
||||
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
|
||||
|
||||
bool32 AI_RandLessThan(u8 val);
|
||||
bool32 IsAiVsAiBattle(void);
|
||||
bool32 BattlerHasAi(u32 battlerId);
|
||||
@ -23,13 +25,12 @@ void SetBattlerData(u32 battlerId);
|
||||
void RestoreBattlerData(u32 battlerId);
|
||||
u16 GetAIChosenMove(u8 battlerId);
|
||||
|
||||
bool32 WillAIStrikeFirst(void);
|
||||
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);
|
||||
u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
|
||||
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
|
||||
bool32 CanMoveFaintBattler(u16 move, u32 battlerDef, u32 battlerAtk, u8 nHits);
|
||||
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
|
||||
@ -87,7 +88,8 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split);
|
||||
s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower);
|
||||
s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower);
|
||||
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
|
||||
u8 GetMoveDamageResult(u16 move);
|
||||
void SetMoveDamageResult(u32 battlerAtk, u16 *moves);
|
||||
u32 GetMoveDamageResult(u32 battlerAtk, u32 battlerDef, u32 moveIndex);
|
||||
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef);
|
||||
uq4_12_t AI_GetTypeEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef);
|
||||
u32 AI_GetMoveEffectiveness(u16 move, u32 battlerAtk, u32 battlerDef);
|
||||
|
@ -59,10 +59,13 @@ void BattleTurnPassed(void);
|
||||
u8 IsRunningFromBattleImpossible(u32 battler);
|
||||
void SwitchPartyOrder(u8 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);
|
||||
void SpecialStatusesClear(void);
|
||||
|
@ -167,7 +167,7 @@ u32 GetBattlerHoldEffectParam(u32 battler);
|
||||
bool32 IsMoveMakingContact(u32 move, u32 battlerAtk);
|
||||
bool32 IsBattlerGrounded(u32 battler);
|
||||
bool32 IsBattlerAlive(u32 battler);
|
||||
u32 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u32 move);
|
||||
u32 GetMoveSlot(u16 *moves, u32 move);
|
||||
u32 GetBattlerWeight(u32 battler);
|
||||
u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer);
|
||||
u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter);
|
||||
|
@ -338,18 +338,55 @@ void Ai_UpdateFaintData(u32 battler)
|
||||
|
||||
static void SetBattlerAiData(u32 battler)
|
||||
{
|
||||
AI_DATA->abilities[battler] = AI_GetAbility(battler);
|
||||
u32 ability, holdEffect;
|
||||
|
||||
ability = AI_DATA->abilities[battler] = AI_GetAbility(battler);
|
||||
AI_DATA->items[battler] = gBattleMons[battler].item;
|
||||
AI_DATA->holdEffects[battler] = AI_GetHoldEffect(battler);
|
||||
holdEffect = AI_DATA->holdEffects[battler] = AI_GetHoldEffect(battler);
|
||||
AI_DATA->holdEffectParams[battler] = GetBattlerHoldEffectParam(battler);
|
||||
AI_DATA->predictedMoves[battler] = gLastMoves[battler];
|
||||
AI_DATA->hpPercents[battler] = GetHealthPercentage(battler);
|
||||
AI_DATA->moveLimitations[battler] = CheckMoveLimitations(battler, 0, MOVE_LIMITATIONS_ALL);
|
||||
AI_DATA->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect);
|
||||
}
|
||||
|
||||
static void SetBattlerAiMovesData(u32 battlerAtk, u32 battlersCount)
|
||||
{
|
||||
u32 battlerDef, i;
|
||||
u16 *moves;
|
||||
|
||||
// Simulate dmg for both ai controlled mons and for player controlled mons.
|
||||
SaveBattlerData(battlerAtk);
|
||||
moves = GetMovesArray(battlerAtk);
|
||||
for (battlerDef = 0; battlerDef < battlersCount; battlerDef++)
|
||||
{
|
||||
if (battlerAtk == battlerDef)
|
||||
continue;
|
||||
|
||||
SaveBattlerData(battlerDef);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
s32 dmg = 0;
|
||||
u8 effectiveness = AI_EFFECTIVENESS_x0;
|
||||
u32 move = moves[i];
|
||||
|
||||
if (move != 0
|
||||
&& move != 0xFFFF
|
||||
//&& gBattleMoves[move].power != 0 /* we want to get effectiveness of status moves */
|
||||
&& !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) {
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE);
|
||||
}
|
||||
|
||||
AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg;
|
||||
AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness;
|
||||
}
|
||||
}
|
||||
SetMoveDamageResult(battlerAtk, moves);
|
||||
}
|
||||
|
||||
void SetAiLogicDataForTurn(void)
|
||||
{
|
||||
u32 battlerAtk, battlerDef, i, battlersCount;
|
||||
u32 battlerAtk, battlersCount;
|
||||
|
||||
memset(AI_DATA, 0, sizeof(struct AiLogicData));
|
||||
|
||||
@ -366,33 +403,7 @@ void SetAiLogicDataForTurn(void)
|
||||
continue;
|
||||
|
||||
SetBattlerAiData(battlerAtk);
|
||||
if (!IsAiBattlerAware(battlerAtk))
|
||||
continue;
|
||||
|
||||
SaveBattlerData(battlerAtk);
|
||||
for (battlerDef = 0; battlerDef < battlersCount; battlerDef++)
|
||||
{
|
||||
if (battlerAtk == battlerDef)
|
||||
continue;
|
||||
|
||||
SaveBattlerData(battlerDef);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
s32 dmg = 0;
|
||||
u8 effectiveness = AI_EFFECTIVENESS_x0;
|
||||
u32 move = gBattleMons[battlerAtk].moves[i];
|
||||
|
||||
if (move != 0
|
||||
&& move != 0xFFFF
|
||||
//&& gBattleMoves[move].power != 0 /* we want to get effectiveness of status moves */
|
||||
&& !(AI_DATA->moveLimitations[battlerAtk] & gBitTable[i])) {
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE);
|
||||
}
|
||||
|
||||
AI_DATA->simulatedDmg[battlerAtk][battlerDef][i] = dmg;
|
||||
AI_DATA->effectiveness[battlerAtk][battlerDef][i] = effectiveness;
|
||||
}
|
||||
}
|
||||
SetBattlerAiMovesData(battlerAtk, battlersCount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,6 +726,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
u32 i;
|
||||
u16 predictedMove = AI_DATA->predictedMoves[battlerDef];
|
||||
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
GET_MOVE_TYPE(move, moveType);
|
||||
|
||||
@ -2616,7 +2628,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
score--;
|
||||
break;
|
||||
case EFFECT_VITAL_THROW:
|
||||
if (WillAIStrikeFirst() && AI_DATA->hpPercents[battlerAtk] < 40)
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move) && AI_DATA->hpPercents[battlerAtk] < 40)
|
||||
score--; // don't want to move last
|
||||
break;
|
||||
case EFFECT_FLAIL:
|
||||
@ -2688,16 +2700,20 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
|
||||
static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
{
|
||||
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
|
||||
bool32 aiFaster;
|
||||
|
||||
if (IsTargetingPartner(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (gBattleMoves[move].power == 0)
|
||||
return score; // can't make anything faint with no power
|
||||
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION)
|
||||
aiFaster = AI_STRIKES_FIRST(battlerAtk, battlerDef, move);
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION)
|
||||
{
|
||||
// this move can faint the target
|
||||
if (WillAIStrikeFirst() || GetMovePriority(battlerAtk, move) > 0)
|
||||
if (aiFaster || GetMovePriority(battlerAtk, move) > 0)
|
||||
score += 4; // we go first or we're using priority move
|
||||
else
|
||||
score += 2;
|
||||
@ -2708,10 +2724,10 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
if (gBattleMoves[move].highCritRatio)
|
||||
score += 2; // crit makes it more likely to make them faint
|
||||
|
||||
if (GetMoveDamageResult(move) == MOVE_POWER_OTHER)
|
||||
if (GetMoveDamageResult(battlerAtk, battlerDef, movesetIndex) == MOVE_POWER_OTHER)
|
||||
score--;
|
||||
|
||||
switch (AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex])
|
||||
switch (AI_DATA->effectiveness[battlerAtk][battlerDef][movesetIndex])
|
||||
{
|
||||
case AI_EFFECTIVENESS_x8:
|
||||
score += 8;
|
||||
@ -2729,9 +2745,9 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
}
|
||||
|
||||
//AI_TryToFaint_CheckIfDanger
|
||||
if (!WillAIStrikeFirst() && CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
if (!aiFaster && CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
{ // AI_TryToFaint_Danger
|
||||
if (GetMoveDamageResult(move) != MOVE_POWER_BEST)
|
||||
if (GetMoveDamageResult(battlerAtk, battlerDef, movesetIndex) != MOVE_POWER_BEST)
|
||||
score--;
|
||||
else
|
||||
score++;
|
||||
@ -2793,7 +2809,6 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
}
|
||||
} // check partner move effect
|
||||
|
||||
|
||||
// consider our move effect relative to partner state
|
||||
switch (effect)
|
||||
{
|
||||
@ -2815,7 +2830,6 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
break;
|
||||
} // our effect relative to partner
|
||||
|
||||
|
||||
// consider global move effects
|
||||
switch (effect)
|
||||
{
|
||||
@ -2853,11 +2867,10 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
break;
|
||||
} // global move effect check
|
||||
|
||||
|
||||
// check specific target
|
||||
if (IsTargetingPartner(battlerAtk, battlerDef))
|
||||
{
|
||||
if (GetMoveDamageResult(move) == MOVE_POWER_OTHER)
|
||||
if (GetMoveDamageResult(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == MOVE_POWER_OTHER)
|
||||
{
|
||||
// partner ability checks
|
||||
if (!partnerProtecting && moveTarget != MOVE_TARGET_BOTH && !DoesBattlerIgnoreAbilityChecks(AI_DATA->abilities[battlerAtk], move))
|
||||
@ -2900,7 +2913,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u16 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case ABILITY_WATER_COMPACTION:
|
||||
if (moveType == TYPE_WATER && GetMoveDamageResult(move) == MOVE_POWER_WEAK)
|
||||
if (moveType == TYPE_WATER && GetMoveDamageResult(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == MOVE_POWER_WEAK)
|
||||
{
|
||||
RETURN_SCORE_PLUS(1); // only mon with this ability is weak to water so only make it okay if we do very little damage
|
||||
}
|
||||
@ -3161,6 +3174,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
u32 effectiveness = AI_DATA->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
|
||||
u8 atkPriority = GetMovePriority(battlerAtk, move);
|
||||
u16 predictedMove = AI_DATA->predictedMoves[battlerDef];
|
||||
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
// We only check for moves that have a 20% chance or more for their secondary effect to happen because moves with a smaller chance are rather worthless. We don't want the AI to use those.
|
||||
@ -3203,7 +3217,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
}
|
||||
|
||||
// check damage
|
||||
if (gBattleMoves[move].power != 0 && GetMoveDamageResult(move) == MOVE_POWER_WEAK)
|
||||
if (gBattleMoves[move].power != 0 && GetMoveDamageResult(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == MOVE_POWER_WEAK)
|
||||
score--;
|
||||
|
||||
// check status move preference
|
||||
@ -3334,7 +3348,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
break;
|
||||
case EFFECT_SPEED_UP:
|
||||
case EFFECT_SPEED_UP_2:
|
||||
if (!WillAIStrikeFirst())
|
||||
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
{
|
||||
if (!AI_RandLessThan(70))
|
||||
score += 3;
|
||||
@ -3432,7 +3446,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN:
|
||||
case EFFECT_SPEED_DOWN_2:
|
||||
if (WillAIStrikeFirst())
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
score -= 3;
|
||||
else if (!AI_RandLessThan(70))
|
||||
score += 2;
|
||||
@ -3675,7 +3689,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
score += 2;
|
||||
break;
|
||||
case EFFECT_SPEED_DOWN_HIT:
|
||||
if (WillAIStrikeFirst())
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
score -= 2;
|
||||
else if (!AI_RandLessThan(70))
|
||||
score++;
|
||||
@ -3819,7 +3833,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
score++;
|
||||
break;
|
||||
case EFFECT_SPEED_UP_HIT:
|
||||
if (sereneGraceBoost && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY && !WillAIStrikeFirst())
|
||||
if (sereneGraceBoost && AI_DATA->abilities[battlerDef] != ABILITY_CONTRARY && !AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
|
||||
score += 3;
|
||||
break;
|
||||
case EFFECT_DESTINY_BOND:
|
||||
@ -4432,7 +4446,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
if (IsStatBoostingBerry(item) && AI_DATA->hpPercents[battlerAtk] > 60)
|
||||
score++;
|
||||
else if (ShouldRestoreHpBerry(battlerAtk, item) && !CanAIFaintTarget(battlerAtk, battlerDef, 0)
|
||||
&& ((GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0))
|
||||
&& ((GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == 0 && CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 0))
|
||||
|| !CanTargetFaintAiWithMod(battlerDef, battlerAtk, toHeal, 0)))
|
||||
score++; // Recycle healing berry if we can't otherwise faint the target and the target wont kill us after we activate the berry
|
||||
}
|
||||
@ -4865,7 +4879,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
{
|
||||
if (gDisableStructs[battlerDef].tauntTimer != 0)
|
||||
score++; // target must use damaging move
|
||||
if (GetMoveDamageResult(predictedMove) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_PHYSICAL)
|
||||
if (GetMoveDamageResult(battlerDef, battlerAtk, predictedMoveSlot) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_PHYSICAL)
|
||||
score += 3;
|
||||
}
|
||||
break;
|
||||
@ -4874,7 +4888,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u16 move, s32 score
|
||||
{
|
||||
if (gDisableStructs[battlerDef].tauntTimer != 0)
|
||||
score++; // target must use damaging move
|
||||
if (GetMoveDamageResult(predictedMove) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_SPECIAL)
|
||||
if (GetMoveDamageResult(battlerDef, battlerAtk, predictedMoveSlot) >= MOVE_POWER_GOOD && GetBattleMoveSplit(predictedMove) == SPLIT_SPECIAL)
|
||||
score += 3;
|
||||
}
|
||||
break;
|
||||
@ -5111,7 +5125,7 @@ static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u16 move, s32
|
||||
if (IsTargetingPartner(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (GetMoveDamageResult(move) == MOVE_POWER_BEST)
|
||||
if (GetMoveDamageResult(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == MOVE_POWER_BEST)
|
||||
score += 2;
|
||||
|
||||
return score;
|
||||
@ -5124,7 +5138,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u16 move, s32 scor
|
||||
|
||||
if (IsTargetingPartner(battlerAtk, battlerDef)
|
||||
|| CountUsablePartyMons(battlerAtk) == 0
|
||||
|| GetMoveDamageResult(move) != MOVE_POWER_OTHER
|
||||
|| GetMoveDamageResult(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) != MOVE_POWER_OTHER
|
||||
|| !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS)
|
||||
|| IsBattlerTrapped(battlerAtk, TRUE))
|
||||
return score;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -424,11 +424,6 @@ u16 GetAIChosenMove(u8 battlerId)
|
||||
return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]);
|
||||
}
|
||||
|
||||
bool32 WillAIStrikeFirst(void)
|
||||
{
|
||||
return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER);
|
||||
}
|
||||
|
||||
bool32 AI_RandLessThan(u8 val)
|
||||
{
|
||||
if ((Random() % 0xFF) < val)
|
||||
@ -945,85 +940,91 @@ u32 GetNoOfHitsToKO(u32 dmg, s32 hp)
|
||||
return hp / (dmg + 1) + 1;
|
||||
}
|
||||
|
||||
u8 GetMoveDamageResult(u16 move)
|
||||
void SetMoveDamageResult(u32 battlerAtk, u16 *moves)
|
||||
{
|
||||
s32 i, checkedMove, bestId, currId, hp;
|
||||
s32 i, j, battlerDef, bestId, currId, hp, result;
|
||||
s32 moveDmgs[MAX_MON_MOVES];
|
||||
u8 result;
|
||||
bool8 isNotConsidered[MAX_MON_MOVES];
|
||||
|
||||
for (i = 0; sIgnoredPowerfulMoveEffects[i] != IGNORED_MOVES_END; i++)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (gBattleMoves[move].effect == sIgnoredPowerfulMoveEffects[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (gBattleMoves[move].power != 0 && sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END)
|
||||
{
|
||||
// Considered move has power and is not in sIgnoredPowerfulMoveEffects
|
||||
// Check all other moves and calculate their power
|
||||
for (checkedMove = 0; checkedMove < MAX_MON_MOVES; checkedMove++)
|
||||
u16 move = moves[i];
|
||||
for (j = 0; sIgnoredPowerfulMoveEffects[j] != IGNORED_MOVES_END; j++)
|
||||
{
|
||||
for (i = 0; sIgnoredPowerfulMoveEffects[i] != IGNORED_MOVES_END; i++)
|
||||
{
|
||||
if (gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].effect == sIgnoredPowerfulMoveEffects[i])
|
||||
break;
|
||||
}
|
||||
if (gBattleMoves[move].effect == sIgnoredPowerfulMoveEffects[j])
|
||||
break;
|
||||
}
|
||||
if (move == 0 || move == 0xFFFF || gBattleMoves[move].power == 0 || sIgnoredPowerfulMoveEffects[j] != IGNORED_MOVES_END)
|
||||
isNotConsidered[i] = TRUE;
|
||||
else
|
||||
isNotConsidered[i] = FALSE;
|
||||
|
||||
if (gBattleMons[sBattler_AI].moves[checkedMove] != MOVE_NONE
|
||||
&& sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END
|
||||
&& gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power != 0)
|
||||
for (battlerDef = 0; battlerDef < MAX_BATTLERS_COUNT; battlerDef++)
|
||||
{
|
||||
if (battlerDef == battlerAtk)
|
||||
continue;
|
||||
|
||||
if (isNotConsidered[i])
|
||||
{
|
||||
moveDmgs[checkedMove] = AI_DATA->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove];
|
||||
AI_DATA->moveDmgResult[battlerAtk][battlerDef][i] = MOVE_POWER_OTHER; // Move has a power of 0/1, or is in the group sIgnoredPowerfulMoveEffects
|
||||
}
|
||||
else
|
||||
{
|
||||
moveDmgs[checkedMove] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
hp = gBattleMons[gBattlerTarget].hp + (20 * gBattleMons[gBattlerTarget].hp / 100); // 20 % add to make sure the battler is always fainted
|
||||
// If a move can faint battler, it doesn't matter how much damage it does
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moveDmgs[i] > hp)
|
||||
moveDmgs[i] = hp;
|
||||
}
|
||||
|
||||
for (bestId = 0, i = 1; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moveDmgs[i] > moveDmgs[bestId])
|
||||
bestId = i;
|
||||
if (moveDmgs[i] == moveDmgs[bestId])
|
||||
{
|
||||
switch (WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[i]))
|
||||
// Considered move has power and is not in sIgnoredPowerfulMoveEffects
|
||||
// Check all other moves and calculate their power
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
case 2:
|
||||
if (Random() & 1)
|
||||
break;
|
||||
case 1:
|
||||
bestId = i;
|
||||
break;
|
||||
if (!isNotConsidered[j])
|
||||
moveDmgs[j] = AI_DATA->simulatedDmg[battlerAtk][battlerDef][j];
|
||||
else
|
||||
moveDmgs[j] = 0;
|
||||
}
|
||||
|
||||
hp = gBattleMons[battlerDef].hp + (20 * gBattleMons[battlerDef].hp / 100); // 20 % add to make sure the battler is always fainted
|
||||
// If a move can faint battler, it doesn't matter how much damage it does
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
if (moveDmgs[j] > hp)
|
||||
moveDmgs[j] = hp;
|
||||
}
|
||||
|
||||
for (bestId = 0, j = 1; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
if (moveDmgs[j] > moveDmgs[bestId])
|
||||
bestId = j;
|
||||
if (moveDmgs[j] == moveDmgs[bestId])
|
||||
{
|
||||
switch (WhichMoveBetter(gBattleMons[battlerAtk].moves[bestId], gBattleMons[battlerAtk].moves[j]))
|
||||
{
|
||||
case 2:
|
||||
if (Random() & 1)
|
||||
break;
|
||||
case 1:
|
||||
bestId = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currId = i;
|
||||
if (currId == bestId)
|
||||
result = MOVE_POWER_BEST;
|
||||
else if ((moveDmgs[currId] >= hp || moveDmgs[bestId] < hp) // If current move can faint as well, or if neither can
|
||||
&& GetNoOfHitsToKO(moveDmgs[currId], hp) - GetNoOfHitsToKO(moveDmgs[bestId], hp) <= 2 // Consider a move weak if it needs to be used at least 2 times more to faint the target, compared to the best move.
|
||||
&& WhichMoveBetter(gBattleMons[battlerAtk].moves[bestId], gBattleMons[battlerAtk].moves[currId]) != 0)
|
||||
result = MOVE_POWER_GOOD;
|
||||
else
|
||||
result = MOVE_POWER_WEAK;
|
||||
|
||||
AI_DATA->moveDmgResult[battlerAtk][battlerDef][i] = result;
|
||||
}
|
||||
}
|
||||
|
||||
currId = AI_THINKING_STRUCT->movesetIndex;
|
||||
if (currId == bestId)
|
||||
AI_THINKING_STRUCT->funcResult = MOVE_POWER_BEST;
|
||||
else if ((moveDmgs[currId] >= hp || moveDmgs[bestId] < hp) // If current move can faint as well, or if neither can
|
||||
&& GetNoOfHitsToKO(moveDmgs[currId], hp) - GetNoOfHitsToKO(moveDmgs[bestId], hp) <= 2 // Consider a move weak if it needs to be used at least 2 times more to faint the target, compared to the best move.
|
||||
&& WhichMoveBetter(gBattleMons[sBattler_AI].moves[bestId], gBattleMons[sBattler_AI].moves[currId]) != 0)
|
||||
AI_THINKING_STRUCT->funcResult = MOVE_POWER_GOOD;
|
||||
else
|
||||
AI_THINKING_STRUCT->funcResult = MOVE_POWER_WEAK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move has a power of 0/1, or is in the group sIgnoredPowerfulMoveEffects
|
||||
AI_THINKING_STRUCT->funcResult = MOVE_POWER_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
return AI_THINKING_STRUCT->funcResult;
|
||||
u32 GetMoveDamageResult(u32 battlerAtk, u32 battlerDef, u32 moveIndex)
|
||||
{
|
||||
return AI_DATA->moveDmgResult[battlerAtk][battlerDef][moveIndex];
|
||||
}
|
||||
|
||||
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef)
|
||||
@ -1090,7 +1091,7 @@ static u32 AI_GetEffectiveness(uq4_12_t multiplier)
|
||||
* AI_IS_FASTER: is user(ai) faster
|
||||
* AI_IS_SLOWER: is target faster
|
||||
*/
|
||||
u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 moveConsidered)
|
||||
u32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered)
|
||||
{
|
||||
u32 fasterAI = 0, fasterPlayer = 0, i;
|
||||
s8 prioAI = 0;
|
||||
@ -1126,7 +1127,11 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 moveConsidered)
|
||||
if (prioAI > prioBattler2)
|
||||
return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move
|
||||
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
|
||||
if (GetWhoStrikesFirst(battlerAI, battler2, TRUE) == 0)
|
||||
if (GetWhichBattlerFasterArgs(battlerAI, battler2, TRUE,
|
||||
AI_DATA->abilities[battlerAI], AI_DATA->abilities[battler2],
|
||||
AI_DATA->holdEffects[battlerAI], AI_DATA->holdEffects[battler2],
|
||||
AI_DATA->speedStats[battlerAI], AI_DATA->speedStats[battler2],
|
||||
prioAI, prioBattler2) == 0)
|
||||
return AI_IS_FASTER;
|
||||
else
|
||||
return AI_IS_SLOWER;
|
||||
@ -1795,7 +1800,7 @@ u32 CountNegativeStatStages(u8 battlerId)
|
||||
|
||||
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u16 defAbility)
|
||||
{
|
||||
if (WillAIStrikeFirst() && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4
|
||||
@ -1812,7 +1817,7 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4
|
||||
@ -1829,10 +1834,10 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (!WillAIStrikeFirst()
|
||||
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
|
||||
&& defAbility != ABILITY_CONTRARY
|
||||
&& defAbility != ABILITY_CLEAR_BODY
|
||||
&& defAbility != ABILITY_FULL_METAL_BODY
|
||||
@ -1844,7 +1849,7 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4
|
||||
@ -1860,7 +1865,7 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4
|
||||
@ -1876,7 +1881,7 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (defAbility != ABILITY_CONTRARY
|
||||
@ -1891,7 +1896,7 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 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))
|
||||
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) && (AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
|
||||
return FALSE; // Don't bother lowering stats if can kill enemy.
|
||||
|
||||
if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE
|
||||
@ -3637,7 +3642,7 @@ void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u8 statId, s32 *score)
|
||||
}
|
||||
break;
|
||||
case STAT_SPEED:
|
||||
if (!WillAIStrikeFirst())
|
||||
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered))
|
||||
{
|
||||
if (gBattleMons[battlerAtk].statStages[STAT_SPEED] < STAT_UP_2_STAGE)
|
||||
*score += 2;
|
||||
|
@ -3771,7 +3771,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);
|
||||
}
|
||||
}
|
||||
@ -4598,11 +4598,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
|
||||
@ -4669,6 +4668,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;
|
||||
@ -4733,17 +4739,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;
|
||||
@ -4754,8 +4756,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;
|
||||
@ -4765,14 +4765,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
|
||||
@ -4835,6 +4827,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;
|
||||
@ -4928,7 +4942,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);
|
||||
}
|
||||
}
|
||||
@ -5092,7 +5106,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);
|
||||
}
|
||||
}
|
||||
|
@ -875,12 +875,12 @@ void HandleAction_ActionFinished(void)
|
||||
// have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder
|
||||
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);
|
||||
}
|
||||
else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH))
|
||||
{
|
||||
if (GetWhoStrikesFirst(battler1, battler2, TRUE)) // If the actions chosen are switching, we recalc order but ignoring the moves
|
||||
if (GetWhichBattlerFaster(battler1, battler2, TRUE)) // If the actions chosen are switching, we recalc order but ignoring the moves
|
||||
SwapTurnOrder(i, j);
|
||||
}
|
||||
}
|
||||
@ -2043,7 +2043,7 @@ u8 DoFieldEndTurnEffects(void)
|
||||
{
|
||||
if (!gProtectStructs[i].quash
|
||||
&& !gProtectStructs[j].quash
|
||||
&& GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE))
|
||||
&& GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE))
|
||||
SwapTurnOrder(i, j);
|
||||
}
|
||||
}
|
||||
@ -8259,13 +8259,13 @@ bool32 IsBattlerAlive(u32 battler)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u32 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u32 move)
|
||||
u32 GetMoveSlot(u16 *moves, u32 move)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (battleMon->moves[i] == move)
|
||||
if (moves[i] == move)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
@ -8555,8 +8555,8 @@ static inline u32 CalcMoveBasePower(u32 move, u32 battlerAtk, u32 battlerDef, u3
|
||||
basePower *= 2;
|
||||
break;
|
||||
case EFFECT_TRUMP_CARD:
|
||||
i = GetBattleMonMoveSlot(&gBattleMons[battlerAtk], move);
|
||||
if (i != 4)
|
||||
i = GetMoveSlot(gBattleMons[battlerAtk].moves, move);
|
||||
if (i != MAX_MON_MOVES)
|
||||
{
|
||||
if (gBattleMons[battlerAtk].pp[i] >= ARRAY_COUNT(sTrumpCardPowerTable))
|
||||
basePower = sTrumpCardPowerTable[ARRAY_COUNT(sTrumpCardPowerTable) - 1];
|
||||
|
Loading…
Reference in New Issue
Block a user