diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index afd468fbb6..700527dbeb 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -3,8 +3,6 @@ #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. #define MAX_ROLL_PERCENTAGE 100 #define MIN_ROLL_PERCENTAGE 85 @@ -16,6 +14,8 @@ enum 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 IsAiVsAiBattle(void); bool32 BattlerHasAi(u32 battlerId); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index fcf56363db..862d575c00 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -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])) 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); 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) { 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 break; 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) && !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) 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) && !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) 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; case EFFECT_SPITE: 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 || gLastMoves[battlerDef] == 0xFFFF) @@ -2068,7 +2068,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (isDoubleBattle) { 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); 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; case EFFECT_SEMI_INVULNERABLE: if (predictedMove != MOVE_NONE - && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + && AI_IsSlower(battlerAtk, battlerDef, move) && gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE) 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: 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 else return AI_CheckBadMove(battlerAtk, battlerDef, predictedMove, score); @@ -2463,7 +2463,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; 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 || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_SCORE(-10); @@ -2492,7 +2492,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + if (AI_IsSlower(battlerAtk, battlerDef, move)) instructedMove = predictedMove; else instructedMove = gLastMoves[battlerDef]; @@ -2531,21 +2531,21 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_QUASH: if (!isDoubleBattle - || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + || AI_IsSlower(battlerAtk, battlerDef, move) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_SCORE(-10); break; case EFFECT_AFTER_YOU: if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef) || !isDoubleBattle - || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER + || AI_IsSlower(battlerAtk, battlerDef, move) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_SCORE(-10); break; case EFFECT_SUCKER_PUNCH: 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); } break; @@ -2587,8 +2587,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-1); break; case EFFECT_FLAIL: - if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER // Opponent should go first - || aiData->hpPercents[battlerAtk] > 50) + if (AI_IsSlower(battlerAtk, battlerDef, move) // Opponent should go first + || aiData->hpPercents[battlerAtk] > 50) ADJUST_SCORE(-4); break; //TODO @@ -2624,7 +2624,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) else if (CanAIFaintTarget(battlerAtk, battlerDef, 0)) ADJUST_SCORE(-10); else if (CanTargetFaintAi(battlerDef, battlerAtk) - && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + && AI_IsSlower(battlerAtk, battlerDef, move)) ADJUST_SCORE(-10); break; case EFFECT_JUNGLE_HEALING: @@ -2652,7 +2652,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; 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); break; 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 (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + if (AI_IsFaster(battlerAtk, battlerDef, move)) ADJUST_SCORE(FAST_KILL); else 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 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 if (IsAttackBoostMoveEffect(effect)) @@ -3023,7 +3023,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_INSTRUCT: { u16 instructedMove; - if (AI_WhoStrikesFirst(battlerAtk, battlerAtkPartner, move) == AI_IS_FASTER) + if (AI_IsFaster(battlerAtk, battlerAtkPartner, move)) instructedMove = aiData->partnerMove; else instructedMove = gLastMoves[battlerAtkPartner]; @@ -3037,8 +3037,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_AFTER_YOU: - if (AI_WhoStrikesFirst(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) == AI_IS_SLOWER // Opponent mon 1 goes before partner - || AI_WhoStrikesFirst(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove) == AI_IS_SLOWER) // Opponent mon 2 goes before partner + if (AI_IsSlower(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) // Opponent mon 1 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) break; // These moves need to go last @@ -3047,9 +3047,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_HEAL_PULSE: case EFFECT_HIT_ENEMY_HEAL_ALLY: - if (AI_WhoStrikesFirst(battlerAtk, FOE(battlerAtk), move) == AI_IS_FASTER - && AI_WhoStrikesFirst(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move) == AI_IS_FASTER - && gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2) + if (AI_IsFaster(battlerAtk, FOE(battlerAtk), move) + && AI_IsFaster(battlerAtk, BATTLE_PARTNER(FOE(battlerAtk)), move) + && gBattleMons[battlerAtkPartner].hp < gBattleMons[battlerAtkPartner].maxHP / 2) RETURN_SCORE_PLUS(WEAK_EFFECT); break; } // attacker move effects @@ -3343,7 +3343,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + if (AI_IsFaster(battlerAtk, battlerDef, move)) ADJUST_SCORE(-3); else if (!AI_RandLessThan(70)) ADJUST_SCORE(DECENT_EFFECT); @@ -3558,7 +3558,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(WEAK_EFFECT); break; 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) 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] != 0xFFFF) && (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)) 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: if (IsDynamaxed(battlerDef)) 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); break; case EFFECT_SPITE: @@ -3848,7 +3848,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_SEMI_INVULNERABLE: 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)) ADJUST_SCORE(GOOD_EFFECT); 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; case EFFECT_ATTRACT: if (!isDoubleBattle - && (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) + && (AI_IsSlower(battlerAtk, battlerDef, move)) && BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef])) break; // Don't use if the attract won't have a change to activate if (gBattleMons[battlerDef].status1 & STATUS1_ANY @@ -3924,7 +3924,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (isDoubleBattle) { 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 } 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); break; 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 else if (HasHealingEffect(battlerDef) || aiData->holdEffects[battlerDef] == HOLD_EFFECT_LEFTOVERS || (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); break; 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 break; case EFFECT_TAILWIND: @@ -4397,7 +4397,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (IsBattlerGrounded(battlerAtk) && HasDamagingMoveOfType(battlerDef, TYPE_ELECTRIC) && !(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) 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; 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) ADJUST_SCORE(DECENT_EFFECT); break; @@ -4448,7 +4448,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; 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); break; case EFFECT_REVIVAL_BLESSING: @@ -4708,7 +4708,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) case MOVE_EFFECT_THROAT_CHOP: 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); else ADJUST_SCORE(DECENT_EFFECT); @@ -4759,7 +4759,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score return score; 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) && GetMovePriority(battlerAtk, move) == 0) { diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 2dac845c47..5aee43b8bf 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -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 if(damageDealt > gBattleMons[opposingBattler].hp) { - if (AI_WhoStrikesFirst(battler, opposingBattler, aiBestMove) == AI_IS_FASTER) + if (AI_IsFaster(battler, opposingBattler, aiBestMove)) return FALSE; } @@ -569,7 +569,7 @@ static bool32 ShouldSwitchIfGameStatePrompt(u32 battler, bool32 emitResult) && AnyStatIsRaised(battler)) switchMon = FALSE; if (AiExpectsToFaintPlayer(battler) - && !AI_STRIKES_FIRST(battler, opposingBattler, 0) + && AI_IsSlower(battler, opposingBattler, 0) && !AI_OpponentCanFaintAiWithMod(battler, 0)) switchMon = FALSE; } @@ -2019,7 +2019,7 @@ static bool32 AiExpectsToFaintPlayer(u32 battler) if (GetBattlerSide(target) != GetBattlerSide(battler) && 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 return TRUE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 9d4f03fb6e..7a39d15c69 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -35,6 +35,16 @@ static u32 AI_GetEffectiveness(uq4_12_t multiplier); // 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) { return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]); @@ -311,7 +321,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i]; if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE) 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 FALSE; @@ -1614,7 +1624,7 @@ bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat) return !(battlerAbility == ABILITY_BIG_PECKS); case STAT_SPEED: // 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 && !HasMoveEffect(sBattler_AI, EFFECT_ELECTRO_BALL)); case STAT_ACC: @@ -1683,7 +1693,7 @@ u32 CountNegativeStatStages(u32 battlerId) 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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_CLEAR_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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) { - 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) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) 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) 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 { @@ -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)) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK || 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; } @@ -2906,7 +2916,7 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION || 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 } @@ -3024,7 +3034,7 @@ bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 mo 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 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) { - 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 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) { 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); 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) 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); if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE) ADJUST_SCORE_PTR(GOOD_EFFECT); @@ -3890,6 +3900,6 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st } return (preventsStatLoss - && AI_STRIKES_FIRST(battlerAtk, battlerAtkPartner, TRUE) + && AI_IsFaster(battlerAtk, battlerAtkPartner, TRUE) && HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)); }