Adds AI_IsFaster and AI_IsSlower functions (#4671)

This commit is contained in:
Alex 2024-05-31 12:55:15 +02:00 committed by GitHub
parent bebc13b5a1
commit d55e072747
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 72 additions and 62 deletions

View File

@ -3,8 +3,6 @@
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE) #define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
// Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt. // Roll boundaries used by AI when scoring. Doesn't affect actual damage dealt.
#define MAX_ROLL_PERCENTAGE 100 #define MAX_ROLL_PERCENTAGE 100
#define MIN_ROLL_PERCENTAGE 85 #define MIN_ROLL_PERCENTAGE 85
@ -16,6 +14,8 @@ enum
DMG_ROLL_HIGHEST, DMG_ROLL_HIGHEST,
}; };
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move);
bool32 AI_RandLessThan(u32 val); bool32 AI_RandLessThan(u32 val);
bool32 IsAiVsAiBattle(void); bool32 IsAiVsAiBattle(void);
bool32 BattlerHasAi(u32 battlerId); bool32 BattlerHasAi(u32 battlerId);

View File

@ -834,7 +834,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (gMovesInfo[move].powderMove && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) if (gMovesInfo[move].powderMove && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))
RETURN_SCORE_MINUS(10); RETURN_SCORE_MINUS(10);
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move))
RETURN_SCORE_MINUS(10); RETURN_SCORE_MINUS(10);
if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk))
@ -1079,7 +1079,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
switch (moveEffect) switch (moveEffect)
{ {
case EFFECT_HIT: // only applies to Vital Throw case EFFECT_HIT: // only applies to Vital Throw
if (gMovesInfo[move].priority < 0 && AI_STRIKES_FIRST(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40) if (gMovesInfo[move].priority < 0 && AI_IsFaster(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40)
ADJUST_SCORE(-2); // don't want to move last ADJUST_SCORE(-2); // don't want to move last
break; break;
default: default:
@ -1523,7 +1523,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)) && !PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
{ {
if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF)
ADJUST_SCORE(-10); // no anticipated move to disable ADJUST_SCORE(-10); // no anticipated move to disable
@ -1545,7 +1545,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) && !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
{ {
if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF) if (gLastMoves[battlerDef] == MOVE_NONE || gLastMoves[battlerDef] == 0xFFFF)
ADJUST_SCORE(-10); // no anticipated move to encore ADJUST_SCORE(-10); // no anticipated move to encore
@ -1923,7 +1923,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break; break;
case EFFECT_SPITE: case EFFECT_SPITE:
case EFFECT_MIMIC: case EFFECT_MIMIC:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker should go first
{ {
if (gLastMoves[battlerDef] == MOVE_NONE if (gLastMoves[battlerDef] == MOVE_NONE
|| gLastMoves[battlerDef] == 0xFFFF) || gLastMoves[battlerDef] == 0xFFFF)
@ -2068,7 +2068,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (isDoubleBattle) if (isDoubleBattle)
{ {
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // partner is going to set up hazards if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // partner is going to set up hazards
&& AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove) == AI_IS_FASTER) // partner is going to set up before the potential Defog && AI_IsFaster(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove)) // partner is going to set up before the potential Defog
{ {
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; // Don't use Defog if partner is going to set up hazards break; // Don't use Defog if partner is going to set up hazards
@ -2096,7 +2096,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break; break;
case EFFECT_SEMI_INVULNERABLE: case EFFECT_SEMI_INVULNERABLE:
if (predictedMove != MOVE_NONE if (predictedMove != MOVE_NONE
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && AI_IsSlower(battlerAtk, battlerDef, move)
&& gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) && gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE)
ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you
@ -2280,7 +2280,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_ME_FIRST: case EFFECT_ME_FIRST:
if (predictedMove != MOVE_NONE) if (predictedMove != MOVE_NONE)
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) if (AI_IsSlower(battlerAtk, battlerDef, move))
ADJUST_SCORE(-10); // Target is predicted to go first, Me First will fail ADJUST_SCORE(-10); // Target is predicted to go first, Me First will fail
else else
return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score);
@ -2463,7 +2463,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} }
break; break;
case EFFECT_ELECTRIFY: case EFFECT_ELECTRIFY:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER if (AI_IsSlower(battlerAtk, battlerDef, move)
//|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type //|| GetMoveTypeSpecial(battlerDef, predictedMove) == TYPE_ELECTRIC // Move will already be electric type
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
@ -2492,7 +2492,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_INSTRUCT: case EFFECT_INSTRUCT:
{ {
u16 instructedMove; u16 instructedMove;
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) if (AI_IsSlower(battlerAtk, battlerDef, move))
instructedMove = predictedMove; instructedMove = predictedMove;
else else
instructedMove = gLastMoves[battlerDef]; instructedMove = gLastMoves[battlerDef];
@ -2531,21 +2531,21 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break; break;
case EFFECT_QUASH: case EFFECT_QUASH:
if (!isDoubleBattle if (!isDoubleBattle
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || AI_IsSlower(battlerAtk, battlerDef, move)
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_AFTER_YOU: case EFFECT_AFTER_YOU:
if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef) if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)
|| !isDoubleBattle || !isDoubleBattle
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || AI_IsSlower(battlerAtk, battlerDef, move)
|| PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_SUCKER_PUNCH: case EFFECT_SUCKER_PUNCH:
if (predictedMove != MOVE_NONE) if (predictedMove != MOVE_NONE)
{ {
if (IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent going first if (IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move)) // Opponent going first
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
} }
break; break;
@ -2587,8 +2587,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-1); ADJUST_SCORE(-1);
break; break;
case EFFECT_FLAIL: case EFFECT_FLAIL:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER // Opponent should go first if (AI_IsSlower(battlerAtk, battlerDef, move) // Opponent should go first
|| aiData->hpPercents[battlerAtk] > 50) || aiData->hpPercents[battlerAtk] > 50)
ADJUST_SCORE(-4); ADJUST_SCORE(-4);
break; break;
//TODO //TODO
@ -2624,7 +2624,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
else if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) else if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
else if (CanTargetFaintAi(battlerDef, battlerAtk) else if (CanTargetFaintAi(battlerDef, battlerAtk)
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) && AI_IsSlower(battlerAtk, battlerDef, move))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_JUNGLE_HEALING: case EFFECT_JUNGLE_HEALING:
@ -2652,7 +2652,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_UPPER_HAND: case EFFECT_UPPER_HAND:
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move) || GetMovePriority(battlerDef, move) < 1 || GetMovePriority(battlerDef, move) > 3) // Opponent going first or not using priority move
ADJUST_SCORE(-10); ADJUST_SCORE(-10);
break; break;
case EFFECT_PLACEHOLDER: case EFFECT_PLACEHOLDER:
@ -2677,7 +2677,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION) if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) if (AI_IsFaster(battlerAtk, battlerDef, move))
ADJUST_SCORE(FAST_KILL); ADJUST_SCORE(FAST_KILL);
else else
ADJUST_SCORE(SLOW_KILL); ADJUST_SCORE(SLOW_KILL);
@ -2743,7 +2743,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// Adjust for always crit moves // Adjust for always crit moves
if (gMovesInfo[aiData->partnerMove].alwaysCriticalHit && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT) if (gMovesInfo[aiData->partnerMove].alwaysCriticalHit && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT)
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_SLOWER) // Partner moving first if (AI_IsSlower(battlerAtk, battlerAtkPartner, move)) // Partner moving first
{ {
// discourage raising our attack since it's about to be maxed out // discourage raising our attack since it's about to be maxed out
if (IsAttackBoostMoveEffect(effect)) if (IsAttackBoostMoveEffect(effect))
@ -3023,7 +3023,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_INSTRUCT: case EFFECT_INSTRUCT:
{ {
u16 instructedMove; u16 instructedMove;
if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_FASTER) if (AI_IsFaster(battlerAtk, battlerAtkPartner, move))
instructedMove = aiData->partnerMove; instructedMove = aiData->partnerMove;
else else
instructedMove = gLastMoves[battlerAtkPartner]; instructedMove = gLastMoves[battlerAtkPartner];
@ -3037,8 +3037,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} }
break; break;
case EFFECT_AFTER_YOU: case EFFECT_AFTER_YOU:
if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) == AI_IS_SLOWER // Opponent mon 1 goes before partner if (AI_IsSlower(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) // Opponent mon 1 goes before partner
|| AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove) == AI_IS_SLOWER) // Opponent mon 2 goes before partner || AI_IsSlower(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove)) // Opponent mon 2 goes before partner
{ {
if (gMovesInfo[aiData->partnerMove].effect == EFFECT_COUNTER || gMovesInfo[aiData->partnerMove].effect == EFFECT_MIRROR_COAT) if (gMovesInfo[aiData->partnerMove].effect == EFFECT_COUNTER || gMovesInfo[aiData->partnerMove].effect == EFFECT_MIRROR_COAT)
break; // These moves need to go last break; // These moves need to go last
@ -3047,9 +3047,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break; break;
case EFFECT_HEAL_PULSE: case EFFECT_HEAL_PULSE:
case EFFECT_HIT_ENEMY_HEAL_ALLY: case EFFECT_HIT_ENEMY_HEAL_ALLY:
if (AI_WhoStrikesFirst(battlerAtk, FOE(battlerAtk), move) == AI_IS_FASTER if (AI_IsFaster(battlerAtk, FOE(battlerAtk), move)
&& AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move) == AI_IS_FASTER && AI_IsFaster(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move)
&& gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2) && gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2)
RETURN_SCORE_PLUS(WEAK_EFFECT); RETURN_SCORE_PLUS(WEAK_EFFECT);
break; break;
} // attacker move effects } // attacker move effects
@ -3343,7 +3343,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
break; break;
case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN:
case EFFECT_SPEED_DOWN_2: case EFFECT_SPEED_DOWN_2:
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) if (AI_IsFaster(battlerAtk, battlerDef, move))
ADJUST_SCORE(-3); ADJUST_SCORE(-3);
else if (!AI_RandLessThan(70)) else if (!AI_RandLessThan(70))
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
@ -3558,7 +3558,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(WEAK_EFFECT); ADJUST_SCORE(WEAK_EFFECT);
break; break;
case EFFECT_MIMIC: case EFFECT_MIMIC:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if (AI_IsFaster(battlerAtk, battlerDef, move))
{ {
if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF) if (gLastMoves[battlerDef] != MOVE_NONE && gLastMoves[battlerDef] != 0xFFFF)
return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score); return AI_CheckViability(battlerAtk, battlerDef, gLastMoves[battlerDef], score);
@ -3620,7 +3620,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
&& (gLastMoves[battlerDef] != MOVE_NONE) && (gLastMoves[battlerDef] != MOVE_NONE)
&& (gLastMoves[battlerDef] != 0xFFFF) && (gLastMoves[battlerDef] != 0xFFFF)
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB) && (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)) && (AI_IsFaster(battlerAtk, battlerDef, move)))
{ {
if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1)) if (CanTargetMoveFaintAi(gLastMoves[battlerDef], battlerDef, battlerAtk, 1))
ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker ADJUST_SCORE(GOOD_EFFECT); // Disable move that can kill attacker
@ -3648,7 +3648,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_DESTINY_BOND: case EFFECT_DESTINY_BOND:
if (IsDynamaxed(battlerDef)) if (IsDynamaxed(battlerDef))
break; break;
else if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && CanTargetFaintAi(battlerDef, battlerAtk)) else if (AI_IsFaster(battlerAtk, battlerDef, move) && CanTargetFaintAi(battlerDef, battlerAtk))
ADJUST_SCORE(GOOD_EFFECT); ADJUST_SCORE(GOOD_EFFECT);
break; break;
case EFFECT_SPITE: case EFFECT_SPITE:
@ -3848,7 +3848,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_SEMI_INVULNERABLE: case EFFECT_SEMI_INVULNERABLE:
if (predictedMove != MOVE_NONE && !isDoubleBattle) if (predictedMove != MOVE_NONE && !isDoubleBattle)
{ {
if ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if ((AI_IsFaster(battlerAtk, battlerDef, move))
&& (gMovesInfo[predictedMove].effect == EFFECT_EXPLOSION || gMovesInfo[predictedMove].effect == EFFECT_PROTECT)) && (gMovesInfo[predictedMove].effect == EFFECT_EXPLOSION || gMovesInfo[predictedMove].effect == EFFECT_PROTECT))
ADJUST_SCORE(GOOD_EFFECT); ADJUST_SCORE(GOOD_EFFECT);
else if (gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)) else if (gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
@ -3890,7 +3890,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
break; break;
case EFFECT_ATTRACT: case EFFECT_ATTRACT:
if (!isDoubleBattle if (!isDoubleBattle
&& (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) && (AI_IsSlower(battlerAtk, battlerDef, move))
&& BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef])) && BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef]))
break; // Don't use if the attract won't have a change to activate break; // Don't use if the attract won't have a change to activate
if (gBattleMons[battlerDef].status1 & STATUS1_ANY if (gBattleMons[battlerDef].status1 & STATUS1_ANY
@ -3924,7 +3924,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
if (isDoubleBattle) if (isDoubleBattle)
{ {
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // Partner is going to set up hazards if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // Partner is going to set up hazards
&& AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(battlerAtk), move) == AI_IS_SLOWER) // Partner going first && AI_IsSlower(battlerAtk, BATTLE_PARTNER(battlerAtk), move)) // Partner going first
break; // Don't use Defog if partner is going to set up hazards break; // Don't use Defog if partner is going to set up hazards
} }
if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) if (ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef]))
@ -4350,7 +4350,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
break; break;
case EFFECT_HEAL_BLOCK: case EFFECT_HEAL_BLOCK:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER && predictedMove != MOVE_NONE && IsHealingMove(predictedMove)) if (AI_IsFaster(battlerAtk, battlerDef, move) && predictedMove != MOVE_NONE && IsHealingMove(predictedMove))
ADJUST_SCORE(DECENT_EFFECT); // Try to cancel healing move ADJUST_SCORE(DECENT_EFFECT); // Try to cancel healing move
else if (HasHealingEffect(battlerDef) || aiData->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS else if (HasHealingEffect(battlerDef) || aiData->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS
|| (aiData->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON))) || (aiData->holdEffects[battlerDef] == HOLD_EFFECT_BLACK_SLUDGE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON)))
@ -4382,7 +4382,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(BEST_EFFECT); ADJUST_SCORE(BEST_EFFECT);
break; break;
case EFFECT_QUASH: case EFFECT_QUASH:
if (isDoubleBattle && AI_WhoStrikesFirst(BATTLE_PARTNER(battlerAtk), battlerDef, aiData->partnerMove) == AI_IS_SLOWER) if (isDoubleBattle && AI_IsSlower(BATTLE_PARTNER(battlerAtk), battlerDef, aiData->partnerMove))
ADJUST_SCORE(DECENT_EFFECT); // Attacker partner wouldn't go before target ADJUST_SCORE(DECENT_EFFECT); // Attacker partner wouldn't go before target
break; break;
case EFFECT_TAILWIND: case EFFECT_TAILWIND:
@ -4397,7 +4397,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC)
&& !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move && !(AI_GetTypeEffectiveness(MOVE_EARTHQUAKE, battlerDef, battlerAtk) == AI_EFFECTIVENESS_x0)) // Doesn't resist ground move
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
{ {
if (gMovesInfo[predictedMove].type == TYPE_GROUND) if (gMovesInfo[predictedMove].type == TYPE_GROUND)
ADJUST_SCORE(GOOD_EFFECT); // Cause the enemy's move to fail ADJUST_SCORE(GOOD_EFFECT); // Cause the enemy's move to fail
@ -4412,7 +4412,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
} }
break; break;
case EFFECT_CAMOUFLAGE: case EFFECT_CAMOUFLAGE:
if (predictedMove != MOVE_NONE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER // Attacker goes first if (predictedMove != MOVE_NONE && AI_IsFaster(battlerAtk, battlerDef, move) // Attacker goes first
&& !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0) && !IS_MOVE_STATUS(move) && AI_GetTypeEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
break; break;
@ -4448,7 +4448,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
} }
break; break;
case EFFECT_ENDEAVOR: case EFFECT_ENDEAVOR:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && !CanTargetFaintAi(battlerDef, battlerAtk)) if (AI_IsSlower(battlerAtk, battlerDef, move) && !CanTargetFaintAi(battlerDef, battlerAtk))
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
break; break;
case EFFECT_REVIVAL_BLESSING: case EFFECT_REVIVAL_BLESSING:
@ -4708,7 +4708,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case MOVE_EFFECT_THROAT_CHOP: case MOVE_EFFECT_THROAT_CHOP:
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove) if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove)
{ {
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if (AI_IsFaster(battlerAtk, battlerDef, move))
ADJUST_SCORE(GOOD_EFFECT); ADJUST_SCORE(GOOD_EFFECT);
else else
ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(DECENT_EFFECT);
@ -4759,7 +4759,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
return score; return score;
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER && AI_IsSlower(battlerAtk, battlerDef, move)
&& CanTargetFaintAi(battlerDef, battlerAtk) && CanTargetFaintAi(battlerDef, battlerAtk)
&& GetMovePriority(battlerAtk, move) == 0) && GetMovePriority(battlerAtk, move) == 0)
{ {

View File

@ -162,7 +162,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
// Check if current mon can outspeed and KO in spite of bad matchup, and don't switch out if it can // Check if current mon can outspeed and KO in spite of bad matchup, and don't switch out if it can
if(damageDealt > gBattleMons[opposingBattler].hp) if(damageDealt > gBattleMons[opposingBattler].hp)
{ {
if (AI_WhoStrikesFirst(battler, opposingBattler, aiBestMove) == AI_IS_FASTER) if (AI_IsFaster(battler, opposingBattler, aiBestMove))
return FALSE; return FALSE;
} }
@ -569,7 +569,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult)
&& AnyStatIsRaised(battler)) && AnyStatIsRaised(battler))
switchMon = FALSE; switchMon = FALSE;
if (AiExpectsToFaintPlayer(battler) if (AiExpectsToFaintPlayer(battler)
&& !AI_STRIKES_FIRST(battler, opposingBattler, 0) && AI_IsSlower(battler, opposingBattler, 0)
&& !AI_OpponentCanFaintAiWithMod(battler, 0)) && !AI_OpponentCanFaintAiWithMod(battler, 0))
switchMon = FALSE; switchMon = FALSE;
} }
@ -2019,7 +2019,7 @@ static bool32 AiExpectsToFaintPlayer(u32 battler)
if (GetBattlerSide(target) != GetBattlerSide(battler) if (GetBattlerSide(target) != GetBattlerSide(battler)
&& CanIndexMoveFaintTarget(battler, target, gBattleStruct->aiMoveOrAction[battler], 0) && CanIndexMoveFaintTarget(battler, target, gBattleStruct->aiMoveOrAction[battler], 0)
&& AI_WhoStrikesFirst(battler, target, GetAIChosenMove(battler)) == AI_IS_FASTER) && AI_IsFaster(battler, target, GetAIChosenMove(battler)))
{ {
// We expect to faint the target and move first -> dont use an item // We expect to faint the target and move first -> dont use an item
return TRUE; return TRUE;

View File

@ -35,6 +35,16 @@
static u32 AI_GetEffectiveness(uq4_12_t multiplier); static u32 AI_GetEffectiveness(uq4_12_t multiplier);
// Functions // Functions
bool32 AI_IsFaster(u32 battlerAi, u32 battlerDef, u32 move)
{
return (AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER);
}
bool32 AI_IsSlower(u32 battlerAi, u32 battlerDef, u32 move)
{
return (AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_SLOWER);
}
u32 GetAIChosenMove(u32 battlerId) u32 GetAIChosenMove(u32 battlerId)
{ {
return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]); return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]);
@ -311,7 +321,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i];
if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE)
return TRUE; return TRUE;
if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)) == AI_IS_SLOWER) if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_IsSlower(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)))
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -1614,7 +1624,7 @@ bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat)
return !(battlerAbility == ABILITY_BIG_PECKS); return !(battlerAbility == ABILITY_BIG_PECKS);
case STAT_SPEED: case STAT_SPEED:
// If AI is faster and doesn't have any mons left, lowering speed doesn't give any // If AI is faster and doesn't have any mons left, lowering speed doesn't give any
return !(AI_WhoStrikesFirst(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER return !(AI_IsFaster(sBattler_AI, battler, AI_THINKING_STRUCT->moveConsidered)
&& CountUsablePartyMons(sBattler_AI) == 0 && CountUsablePartyMons(sBattler_AI) == 0
&& !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL)); && !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL));
case STAT_ACC: case STAT_ACC:
@ -1683,7 +1693,7 @@ u32 CountNegativeStatStages(u32 battlerId)
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -1702,7 +1712,7 @@ bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -1721,12 +1731,12 @@ bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
if (!AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsSlower(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
@ -1738,7 +1748,7 @@ bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -1756,7 +1766,7 @@ bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -1774,7 +1784,7 @@ bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -1793,7 +1803,7 @@ bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility)
bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility)
{ {
if (AI_STRIKES_FIRST(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered) if (AI_IsFaster(battlerAtk, battlerDef, AI_THINKING_STRUCT->moveConsidered)
&& (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT)
&& CanAIFaintTarget(battlerAtk, battlerDef, 0)) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return FALSE; // Don't bother lowering stats if can kill enemy. return FALSE; // Don't bother lowering stats if can kill enemy.
@ -2514,7 +2524,7 @@ bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32
/*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost) /*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost)
return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/ return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
{ {
if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise
{ {
@ -2898,7 +2908,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi
if (((!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS)) if (((!IsMoldBreakerTypeAbility(AI_DATA->abilities[battlerAtk]) && (defAbility == ABILITY_SHIELD_DUST || defAbility == ABILITY_INNER_FOCUS))
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move) || DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER)) // Opponent goes first || AI_IsSlower(battlerAtk, battlerDef, move))) // Opponent goes first
{ {
return 0; return 0;
} }
@ -2906,7 +2916,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi
|| gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|| gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|| ((AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) && CanTargetFaintAi(battlerDef, battlerAtk))) || ((AI_IsFaster(battlerAtk, battlerDef, move)) && CanTargetFaintAi(battlerDef, battlerAtk)))
{ {
return 2; // good idea to flinch return 2; // good idea to flinch
} }
@ -3024,7 +3034,7 @@ bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 mo
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage) bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage)
{ {
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move))
{ {
// using item or user goes first // using item or user goes first
u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument; u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument;
@ -3051,7 +3061,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage)
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent) bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent)
{ {
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move))
{ {
// using item or user going first // using item or user going first
s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
@ -3510,7 +3520,7 @@ bool32 IsRecycleEncouragedItem(u32 item)
static void IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score, bool32 considerContrary) static void IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score, bool32 considerContrary)
{ {
u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk); u32 noOfHitsToFaint = NoOfHitsForTargetToFaintAI(battlerDef, battlerAtk);
u32 aiIsFaster = GetWhichBattlerFaster(battlerAtk, battlerDef, TRUE) == AI_IS_FASTER; u32 aiIsFaster = AI_IsFaster(battlerAtk, battlerDef, TRUE);
u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS); u32 shouldSetUp = ((noOfHitsToFaint >= 2 && aiIsFaster) || (noOfHitsToFaint >= 3 && !aiIsFaster) || noOfHitsToFaint == UNKNOWN_NO_OF_HITS);
if (considerContrary && AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY) if (considerContrary && AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)
@ -3844,7 +3854,7 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0) if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0)
ADJUST_SCORE_PTR(-2); ADJUST_SCORE_PTR(-2);
if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_IsFaster(battlerAtk, battlerDef, move))
ADJUST_SCORE_PTR(-10); ADJUST_SCORE_PTR(-10);
if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE) if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE)
ADJUST_SCORE_PTR(GOOD_EFFECT); ADJUST_SCORE_PTR(GOOD_EFFECT);
@ -3890,6 +3900,6 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st
} }
return (preventsStatLoss return (preventsStatLoss
&& AI_STRIKES_FIRST(battlerAtk, battlerAtkPartner, TRUE) && AI_IsFaster(battlerAtk, battlerAtkPartner, TRUE)
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)); && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL));
} }