diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 0a70acce1f..ff9ea73d3b 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -120,18 +120,11 @@ void DecideTerastal(u32 battler); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); -bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat); +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat); bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat); bool32 AreBattlersStatsMaxed(u32 battler); u32 CountPositiveStatStages(u32 battlerId); u32 CountNegativeStatStages(u32 battlerId); -bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility); -bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility); // move checks bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); @@ -152,6 +145,7 @@ bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensiv bool32 HasMoveWithCategory(u32 battler, u32 category); bool32 HasMoveWithType(u32 battler, u32 type); bool32 HasMoveWithEffect(u32 battlerId, enum BattleMoveEffects moveEffect); +bool32 HasBattlerSideMoveWithEffect(u32 battler, u32 effect); bool32 HasNonVolatileMoveEffect(u32 battlerId, u32 effect); bool32 IsPowerBasedOnStatus(u32 battlerId, enum BattleMoveEffects effect, u32 argument); bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect); @@ -245,6 +239,7 @@ bool32 SideHasMoveCategory(u32 battlerId, u32 category); // score increases u32 IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, enum StatChange statId); u32 IncreaseStatUpScoreContrary(u32 battlerAtk, u32 battlerDef, enum StatChange statId); +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat); void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 9924dc74c4..e2d5e52b6f 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1543,40 +1543,40 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // stat lowering effects case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) ADJUST_SCORE(-10); break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) ADJUST_SCORE(-10); break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) ADJUST_SCORE(-10); break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) //|| !HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) ADJUST_SCORE(-10); break; case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPDEF)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPDEF)) ADJUST_SCORE(-10); break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ACC)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ACC)) ADJUST_SCORE(-10); break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: case EFFECT_TICKLE: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) ADJUST_SCORE(-10); - else if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) + else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) ADJUST_SCORE(-8); break; case EFFECT_VENOM_DRENCH: @@ -1586,18 +1586,18 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } else { - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) ADJUST_SCORE(-10); - else if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) ADJUST_SCORE(-8); - else if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) ADJUST_SCORE(-6); } break; case EFFECT_NOBLE_ROAR: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) ADJUST_SCORE(-10); - else if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) ADJUST_SCORE(-8); break; case EFFECT_CAPTIVATE: @@ -1658,7 +1658,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_TOXIC_THREAD: - if (!ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) ADJUST_SCORE(-1); // may still want to just poison //fallthrough case EFFECT_LIGHT_SCREEN: @@ -2066,7 +2066,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_STRENGTH_SAP: if (aiData->abilities[battlerDef] == ABILITY_CONTRARY) ADJUST_SCORE(-10); - else if (!ShouldLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK)) ADJUST_SCORE(-10); break; case EFFECT_COPYCAT: @@ -3940,89 +3940,31 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_ATTACK_DOWN: case EFFECT_ATTACK_DOWN_2: - if (!ShouldLowerAttack(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if (gBattleMons[battlerDef].statStages[STAT_ATK] < DEFAULT_STAT_STAGE) - ADJUST_SCORE(-1); - else if (aiData->hpPercents[battlerAtk] <= 90) - ADJUST_SCORE(-1); - if (gBattleMons[battlerDef].statStages[STAT_ATK] > 3 && !AI_RandLessThan(50)) - ADJUST_SCORE(-2); - else if (aiData->hpPercents[battlerDef] < 70) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_ATK)); break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (!ShouldLowerDefense(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if ((aiData->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) || (gBattleMons[battlerDef].statStages[STAT_DEF] <= 3 && !AI_RandLessThan(50))) - ADJUST_SCORE(-2); - if (aiData->hpPercents[battlerDef] <= 70) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_DEF)); break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (AI_IsFaster(battlerAtk, battlerDef, move)) - ADJUST_SCORE(-3); - else if (!AI_RandLessThan(70)) - ADJUST_SCORE(DECENT_EFFECT); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPEED)); break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (!ShouldLowerSpAtk(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if (gBattleMons[battlerDef].statStages[STAT_SPATK] < DEFAULT_STAT_STAGE) - ADJUST_SCORE(-1); - else if (aiData->hpPercents[battlerAtk] <= 90) - ADJUST_SCORE(-1); - if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 3 && !AI_RandLessThan(50)) - ADJUST_SCORE(-2); - else if (aiData->hpPercents[battlerDef] < 70) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPATK)); break; case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (!ShouldLowerSpDef(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if ((aiData->hpPercents[battlerAtk] < 70 && !AI_RandLessThan(50)) - || (gBattleMons[battlerDef].statStages[STAT_SPDEF] <= 3 && !AI_RandLessThan(50))) - ADJUST_SCORE(-2); - if (aiData->hpPercents[battlerDef] <= 70) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPDEF)); break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - if (ShouldLowerAccuracy(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if ((aiData->hpPercents[battlerAtk] < 70 || aiData->hpPercents[battlerDef] < 70) && AI_RandLessThan(100)) - ADJUST_SCORE(-1); - if (gBattleMons[battlerDef].statStages[STAT_ACC] <= 4 && !AI_RandLessThan(80)) - ADJUST_SCORE(-2); - if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY && !AI_RandLessThan(70)) - ADJUST_SCORE(DECENT_EFFECT); - if (gStatuses3[battlerDef] & STATUS3_LEECHSEED && !AI_RandLessThan(70)) - ADJUST_SCORE(DECENT_EFFECT); - if (gStatuses3[battlerDef] & STATUS3_ROOTED && AI_RandLessThan(128)) - ADJUST_SCORE(WEAK_EFFECT); - if (gBattleMons[battlerDef].status2 & STATUS2_CURSED && !AI_RandLessThan(70)) - ADJUST_SCORE(DECENT_EFFECT); - if (aiData->hpPercents[battlerAtk] > 70 || gBattleMons[battlerDef].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) - break; - else if (aiData->hpPercents[battlerAtk] < 40 || aiData->hpPercents[battlerDef] < 40 || !AI_RandLessThan(70)) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_ACC)); break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: - if (!ShouldLowerEvasion(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(-2); - if ((aiData->hpPercents[battlerAtk] < 70 || gBattleMons[battlerDef].statStages[STAT_EVASION] <= 3) && !AI_RandLessThan(50)) - ADJUST_SCORE(-2); - if (aiData->hpPercents[battlerDef] <= 70) - ADJUST_SCORE(-2); - if (gBattleMons[battlerAtk].statStages[STAT_ACC] < DEFAULT_STAT_STAGE) - ADJUST_SCORE(WEAK_EFFECT); - if (gBattleMons[battlerDef].statStages[STAT_EVASION] < 7 || aiData->abilities[battlerAtk] == ABILITY_NO_GUARD) - ADJUST_SCORE(-2); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_EVASION)); break; case EFFECT_SPICY_EXTRACT: // TODO: Make IncreaseStatDownScore function, just like IncreaseStatUpScore @@ -4543,8 +4485,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) && 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])) - ADJUST_SCORE(DECENT_EFFECT); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_EVASION)); } break; case EFFECT_TORMENT: @@ -4789,11 +4730,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(WEAK_EFFECT); break; case EFFECT_TICKLE: - if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) - && aiData->abilities[battlerDef] != ABILITY_CONTRARY && ShouldLowerDefense(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(DECENT_EFFECT); - else if (ShouldLowerAttack(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - ADJUST_SCORE(DECENT_EFFECT); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_ATK)); + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_DEF)); break; case EFFECT_COSMIC_POWER: ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF)); @@ -5231,8 +5169,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case MOVE_EFFECT_SPD_MINUS_1: case MOVE_EFFECT_SPD_MINUS_2: - if (!ShouldLowerSpeed(battlerAtk, battlerDef, aiData->abilities[battlerDef])) - break; + ADJUST_SCORE(IncreaseStatDownScore(battlerAtk, battlerDef, STAT_SPEED)); + break; case MOVE_EFFECT_ATK_MINUS_1: case MOVE_EFFECT_DEF_MINUS_1: case MOVE_EFFECT_SP_ATK_MINUS_1: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dbbd30c68a..4e01cfb296 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -992,7 +992,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 case MOVE_EFFECT_SP_DEF_MINUS_1: case MOVE_EFFECT_ACC_MINUS_1: case MOVE_EFFECT_EVS_MINUS_1: - if (ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) return TRUE; break; case MOVE_EFFECT_ATK_MINUS_2: @@ -1002,7 +1002,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 case MOVE_EFFECT_SP_DEF_MINUS_2: case MOVE_EFFECT_ACC_MINUS_2: case MOVE_EFFECT_EVS_MINUS_2: - if (ShouldLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) return TRUE; break; } @@ -1928,7 +1928,7 @@ s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove) } // stat stages -bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) { if (gBattleMons[battlerDef].statStages[stat] == MIN_STAT_STAGE) return FALSE; @@ -1965,7 +1965,6 @@ bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) return FALSE; } - // This should be a viability check if (stat == STAT_SPEED) { // If AI is faster and doesn't have any mons left, lowering speed doesn't give any @@ -1977,6 +1976,73 @@ bool32 ShouldLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) return TRUE; } +u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) +{ + u32 tempScore = NO_INCREASE; + + // Don't increase score if target is already -3 stat stage + if (stat != STAT_SPEED && gBattleMons[battlerDef].statStages[stat] <= DEFAULT_STAT_STAGE - 3) + return NO_INCREASE; + + // Don't decrease stat if target will die to residual damage + if (GetBattlerSecondaryDamage(battlerDef) >= gBattleMons[battlerDef].hp) + return NO_INCREASE; + + // Don't decrese stat if opposing battler has Encore + if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) + return NO_INCREASE; + + // TODO: Avoid decreasing stat if + // player can kill ai in 2 hits with decreased attack / sp atk stages + // ai can kill target in 2 hits without decreasing defense / sp def stages + + switch (stat) + { + case STAT_ATK: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL)) + tempScore += DECENT_EFFECT; + break; + case STAT_DEF: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL)) + tempScore += DECENT_EFFECT; + break; + case STAT_SPEED: + if (AI_IsSlower(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered)) + tempScore += DECENT_EFFECT; + break; + case STAT_SPATK: + if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL)) + tempScore += DECENT_EFFECT; + break; + case STAT_SPDEF: + if (HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL)) + tempScore += DECENT_EFFECT; + break; + case STAT_ACC: + if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) + tempScore += WEAK_EFFECT; + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED) + tempScore += WEAK_EFFECT; + if (gStatuses3[battlerDef] & STATUS3_ROOTED) + tempScore += WEAK_EFFECT; + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED) + tempScore += WEAK_EFFECT; + break; + case STAT_EVASION: + if (gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY) + tempScore += WEAK_EFFECT; + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED) + tempScore += WEAK_EFFECT; + if (gStatuses3[battlerDef] & STATUS3_ROOTED) + tempScore += WEAK_EFFECT; + if (gBattleMons[battlerDef].status2 & STATUS2_CURSED) + tempScore += WEAK_EFFECT; + break; + } + + return (tempScore > BEST_EFFECT) ? BEST_EFFECT : tempScore; // don't inflate score so only max +4 +} + bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat) { if ((gBattleMons[battler].statStages[stat] < MAX_STAT_STAGE && battlerAbility != ABILITY_CONTRARY) @@ -2032,128 +2098,6 @@ u32 CountNegativeStatStages(u32 battlerId) return count; } -bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & 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 - && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL) - && defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_WHITE_SMOKE - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_HYPER_CUTTER - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - -bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & 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 - && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_PHYSICAL) - && defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_WHITE_SMOKE - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_BIG_PECKS - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - -bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (defAbility == ABILITY_CONTRARY - || defAbility == ABILITY_CLEAR_BODY - || defAbility == ABILITY_FULL_METAL_BODY - || defAbility == ABILITY_WHITE_SMOKE - || gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) - return FALSE; - - return (AI_IsSlower(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered)); -} - -bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & 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 - && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL) - && defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - -bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & 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 - && HasMoveWithCategory(battlerAtk, DAMAGE_CATEGORY_SPECIAL) - && defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - -bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) - && CanAIFaintTarget(battlerAtk, battlerDef, 0)) - return FALSE; // Don't bother lowering stats if can kill enemy. - - if (defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_WHITE_SMOKE - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_KEEN_EYE - && defAbility != ABILITY_MINDS_EYE - && (B_ILLUMINATE_EFFECT >= GEN_9 && defAbility != ABILITY_ILLUMINATE) - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - -bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility) -{ - if (AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered) - && (gAiThinkingStruct->aiFlags[battlerAtk] & 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 - && defAbility != ABILITY_CONTRARY - && defAbility != ABILITY_CLEAR_BODY - && defAbility != ABILITY_FULL_METAL_BODY - && defAbility != ABILITY_WHITE_SMOKE - && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CLEAR_AMULET) - return TRUE; - return FALSE; -} - bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 moveIndex, enum DamageCalcContext calcContext) { s32 dmg;