From 6cb18f2048480522d75c657cee36220b976cf185 Mon Sep 17 00:00:00 2001 From: surskitty Date: Fri, 8 Aug 2025 03:53:13 -0400 Subject: [PATCH] Fiddling with CanLowerStat. (#7510) --- include/battle_ai_util.h | 2 +- src/battle_ai_main.c | 30 ++++++++-------- src/battle_ai_util.c | 76 +++++++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 49 deletions(-) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 52b5764b00..b6b16524af 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -144,7 +144,7 @@ bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move); // stat stage checks bool32 AnyStatIsRaised(u32 battlerId); -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat); +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat); bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat); bool32 AreBattlersStatsMaxed(u32 battler); u32 CountPositiveStatStages(u32 battlerId); diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 2fbe68f0ee..4b7f8bddd9 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1585,40 +1585,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 (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ATK)) ADJUST_SCORE(-10); break; case EFFECT_DEFENSE_DOWN: case EFFECT_DEFENSE_DOWN_2: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_DEF)) ADJUST_SCORE(-10); break; case EFFECT_SPEED_DOWN: case EFFECT_SPEED_DOWN_2: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPEED)) ADJUST_SCORE(-10); break; case EFFECT_SPECIAL_ATTACK_DOWN: case EFFECT_SPECIAL_ATTACK_DOWN_2: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPATK)) ADJUST_SCORE(-10); break; case EFFECT_SPECIAL_DEFENSE_DOWN: case EFFECT_SPECIAL_DEFENSE_DOWN_2: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPDEF)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPDEF)) ADJUST_SCORE(-10); break; case EFFECT_ACCURACY_DOWN: case EFFECT_ACCURACY_DOWN_2: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ACC)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ACC)) ADJUST_SCORE(-10); break; case EFFECT_EVASION_DOWN: case EFFECT_EVASION_DOWN_2: case EFFECT_TICKLE: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ATK)) ADJUST_SCORE(-10); - else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_DEF)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_DEF)) ADJUST_SCORE(-8); break; case EFFECT_VENOM_DRENCH: @@ -1628,18 +1628,18 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } else { - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPEED)) ADJUST_SCORE(-10); - else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPATK)) ADJUST_SCORE(-8); - else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ATK)) ADJUST_SCORE(-6); } break; case EFFECT_NOBLE_ROAR: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPATK)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPATK)) ADJUST_SCORE(-10); - else if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ATK)) ADJUST_SCORE(-8); break; case EFFECT_CAPTIVATE: @@ -1703,7 +1703,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_TOXIC_THREAD: - if (!CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_SPEED)) + if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_SPEED)) ADJUST_SCORE(-1); // may still want to just poison //fallthrough case EFFECT_LIGHT_SCREEN: @@ -2112,7 +2112,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 (!CanLowerStat(battlerAtk, battlerDef, aiData->abilities[battlerDef], STAT_ATK)) + else if (!CanLowerStat(battlerAtk, battlerDef, aiData, STAT_ATK)) ADJUST_SCORE(-10); break; case EFFECT_COPYCAT: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0f6fc16fb7..229a9a8c68 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1079,7 +1079,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 (CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1) return TRUE; break; case MOVE_EFFECT_ATK_MINUS_2: @@ -1089,7 +1089,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 (CanLowerStat(battlerAtk, battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) + if (CanLowerStat(battlerAtk, battlerDef, gAiLogicData, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1) return TRUE; break; default: @@ -1967,49 +1967,59 @@ s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove) } // stat stages -bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 stat) +bool32 CanLowerStat(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData, u32 stat) { if (gBattleMons[battlerDef].statStages[stat] == MIN_STAT_STAGE) return FALSE; - if (gAiLogicData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) + if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_CLEAR_AMULET) return FALSE; - switch (abilityDef) - { - case ABILITY_SPEED_BOOST: - if (stat == STAT_SPEED) - return FALSE; - case ABILITY_HYPER_CUTTER: - if (stat == STAT_ATK) - return FALSE; - case ABILITY_BIG_PECKS: - if (stat == STAT_DEF) - return FALSE; - case ABILITY_ILLUMINATE: - if (B_ILLUMINATE_EFFECT < GEN_9) - break; - case ABILITY_KEEN_EYE: - case ABILITY_MINDS_EYE: - if (stat == STAT_ACC) - return FALSE; - case ABILITY_FLOWER_VEIL: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS)) - return FALSE; - break; - case ABILITY_CONTRARY: - case ABILITY_CLEAR_BODY: - case ABILITY_WHITE_SMOKE: - case ABILITY_FULL_METAL_BODY: + u32 move = gAiThinkingStruct->moveConsidered; + u32 abilityAtk = aiData->abilities[battlerAtk]; + + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_MIST && abilityAtk != ABILITY_INFILTRATOR) return FALSE; + + if (!DoesBattlerIgnoreAbilityChecks(battlerAtk, abilityAtk, move)) + { + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) && AI_IsAbilityOnSide(battlerDef, ABILITY_FLOWER_VEIL)) + return FALSE; + + switch (aiData->abilities[battlerDef]) + { + case ABILITY_SPEED_BOOST: + if (stat == STAT_SPEED) + return FALSE; + case ABILITY_HYPER_CUTTER: + if (stat == STAT_ATK) + return FALSE; + case ABILITY_BIG_PECKS: + if (stat == STAT_DEF) + return FALSE; + case ABILITY_ILLUMINATE: + if (B_ILLUMINATE_EFFECT < GEN_9) + break; + case ABILITY_KEEN_EYE: + case ABILITY_MINDS_EYE: + if (stat == STAT_ACC) + return FALSE; + case ABILITY_CONTRARY: + case ABILITY_CLEAR_BODY: + case ABILITY_WHITE_SMOKE: + case ABILITY_FULL_METAL_BODY: + return FALSE; + default: + break; + } } if (stat == STAT_SPEED) { // If AI is faster and doesn't have any mons left, lowering speed doesn't give any - return !(AI_IsFaster(battlerAtk, battlerDef, gAiThinkingStruct->moveConsidered, GetIncomingMove(battlerAtk, battlerDef, gAiLogicData), DONT_CONSIDER_PRIORITY) + return !(AI_IsFaster(battlerAtk, battlerDef, move, GetIncomingMove(battlerAtk, battlerDef, gAiLogicData), DONT_CONSIDER_PRIORITY) && CountUsablePartyMons(battlerAtk) == 0 - && !HasMoveWithEffect(battlerAtk, EFFECT_ELECTRO_BALL)); + && !HasBattlerSideMoveWithEffect(battlerAtk, EFFECT_ELECTRO_BALL)); } return TRUE; @@ -2027,7 +2037,7 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) if (GetBattlerSecondaryDamage(battlerDef) >= gBattleMons[battlerDef].hp) return NO_INCREASE; - // Don't decrese stat if opposing battler has Encore + // Don't decrease stat if opposing battler has Encore if (HasBattlerSideMoveWithEffect(battlerDef, EFFECT_ENCORE)) return NO_INCREASE;