Remove redundancy for ShouldLowerStat functions (#6577)

This commit is contained in:
Alex 2025-06-10 03:47:16 +02:00 committed by GitHub
parent 260813fc3f
commit cb4ef705f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 100 additions and 223 deletions

View File

@ -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);

View File

@ -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:

View File

@ -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;