Merge pull request #1875 from BuffelSaft/fix_ai_status_logic2

Fix AI status logic and CanAttackerFaintTarget
This commit is contained in:
ghoulslash 2021-11-08 10:34:10 -05:00 committed by GitHub
commit 4f56d0a2b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 37 deletions

View File

@ -35,7 +35,8 @@ u16 AI_GetHoldEffect(u32 battlerId);
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move); u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move);
bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move); bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move);
bool32 AI_WeatherHasEffect(void); bool32 AI_WeatherHasEffect(void);
bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits); bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits);
bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits);
bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags); bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags);
bool32 AI_IsBattlerGrounded(u8 battlerId); bool32 AI_IsBattlerGrounded(u8 battlerId);
bool32 HasDamagingMove(u8 battlerId); bool32 HasDamagingMove(u8 battlerId);

View File

@ -1473,7 +1473,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
else if (move == MOVE_FAKE_OUT) // filter out first impression else if (move == MOVE_FAKE_OUT) // filter out first impression
{ {
if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS) if ((AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND || AI_DATA->atkAbility == ABILITY_GORILLA_TACTICS)
&& (CountUsablePartyMons(battlerDef) > 0 || !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))) && (CountUsablePartyMons(battlerDef) > 0 || !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)))
{ {
if (CountUsablePartyMons(battlerAtk) == 0) if (CountUsablePartyMons(battlerAtk) == 0)
score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards. score -= 10; // Don't lock the attacker into Fake Out if they can't switch out afterwards.
@ -1714,7 +1714,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) if (AI_DATA->defAbility == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2)
score -= 10; score -= 10;
else if (AI_DATA->atkAbility != ABILITY_TRUANT else if (AI_DATA->atkAbility != ABILITY_TRUANT
&& !CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) && !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
score -= 2; score -= 2;
break; break;
case EFFECT_SPITE: case EFFECT_SPITE:
@ -2465,7 +2465,7 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
if (gBattleMoves[move].power == 0) if (gBattleMoves[move].power == 0)
return score; // can't make anything faint with no power return score; // can't make anything faint with no power
if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION) if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0) && gBattleMoves[move].effect != EFFECT_EXPLOSION)
{ {
// this move can faint the target // this move can faint the target
if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 || GetMovePriority(battlerAtk, move) > 0) if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0 || GetMovePriority(battlerAtk, move) > 0)
@ -2707,7 +2707,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
&& !IS_MOVE_STATUS(move) && !IS_MOVE_STATUS(move)
&& HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL)
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
&& !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1))
{ {
RETURN_SCORE_PLUS(1); RETURN_SCORE_PLUS(1);
} }
@ -2716,7 +2716,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
if (!IS_MOVE_STATUS(move) if (!IS_MOVE_STATUS(move)
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG) && (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG)
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED)
&& !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1)) && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1))
{ {
RETURN_SCORE_PLUS(1); RETURN_SCORE_PLUS(1);
} }
@ -2782,7 +2782,7 @@ static s16 AI_DoubleBattle(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
&& !IS_MOVE_STATUS(move) && !IS_MOVE_STATUS(move)
&& HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL) && HasMoveWithSplit(battlerAtkPartner, SPLIT_PHYSICAL)
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK) && BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
&& !CanAttackerFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0)) && !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0))
{ {
RETURN_SCORE_PLUS(1); RETURN_SCORE_PLUS(1);
} }
@ -2971,7 +2971,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case ABILITY_BEAST_BOOST: case ABILITY_BEAST_BOOST:
if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // attacker should go first
{ {
if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
score += 8; // prioritize killing target for stat boost score += 8; // prioritize killing target for stat boost
} }
break; break;
@ -3772,7 +3772,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case EFFECT_FELL_STINGER: case EFFECT_FELL_STINGER:
if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE if (gBattleMons[battlerAtk].statStages[STAT_ATK] < MAX_STAT_STAGE
&& AI_DATA->atkAbility != ABILITY_CONTRARY && AI_DATA->atkAbility != ABILITY_CONTRARY
&& CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) && CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
{ {
if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first
score += 9; score += 9;
@ -4923,7 +4923,7 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
} }
// consider target HP // consider target HP
if (CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
{ {
score += 2; score += 2;
} }

View File

@ -660,9 +660,9 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split)
for (i = 0; i < MAX_MON_MOVES; i++) for (i = 0; i < MAX_MON_MOVES; i++)
{ {
if (moves[i] != MOVE_NONE if (moves[i] != MOVE_NONE
&& moves[i] != 0xFFFF && moves[i] != 0xFFFF
&& GetBattleMoveSplit(moves[i]) == split && GetBattleMoveSplit(moves[i]) == split
&& !(unusable & gBitTable[i])) && !(unusable & gBitTable[i]))
{ {
SetTypeBeforeUsingMove(moves[i], attacker); SetTypeBeforeUsingMove(moves[i], attacker);
GET_MOVE_TYPE(moves[i], moveType); GET_MOVE_TYPE(moves[i], moveType);
@ -1033,7 +1033,7 @@ bool32 IsAiFaster(u8 battler)
bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk) bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk)
{ {
s32 i, dmg; s32 i, dmg;
u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF);
u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef];
for (i = 0; i < MAX_MON_MOVES; i++) for (i = 0; i < MAX_MON_MOVES; i++)
@ -1048,10 +1048,36 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk)
return FALSE; return FALSE;
} }
// Check if AI mon has the means to faint the target with any of its moves.
// If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects)
bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits)
{
s32 i, dmg;
u32 moveLimitations = CheckMoveLimitations(battlerAtk, 0, 0xFF);
u16 *moves = gBattleMons[battlerAtk].moves;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(moveLimitations & gBitTable[i]))
{
// Use the pre-calculated value in simulatedDmg instead of re-calculating it
dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i];
if (numHits)
dmg *= numHits;
if (gBattleMons[battlerDef].hp <= dmg)
return TRUE;
}
}
return FALSE;
}
bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits) bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits)
{ {
s32 i, dmg; s32 i, dmg;
u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF);
if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp) if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk) >= gBattleMons[battlerAtk].hp)
return TRUE; return TRUE;
@ -1063,7 +1089,7 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits)
bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod) bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod)
{ {
u32 i; u32 i;
u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF & ~MOVE_LIMITATION_PP); u32 unusable = CheckMoveLimitations(battlerDef, 0, 0xFF);
u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef]; u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef];
for (i = 0; i < MAX_MON_MOVES; i++) for (i = 0; i < MAX_MON_MOVES; i++)
@ -1677,7 +1703,7 @@ u32 CountNegativeStatStages(u8 battlerId)
bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (gBattleMons[battlerDef].statStages[STAT_ATK] > 4 if (gBattleMons[battlerDef].statStages[STAT_ATK] > 4
@ -1685,7 +1711,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
&& defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_WHITE_SMOKE
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_HYPER_CUTTER) && defAbility != ABILITY_HYPER_CUTTER)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1693,7 +1719,7 @@ bool32 ShouldLowerAttack(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (gBattleMons[battlerDef].statStages[STAT_DEF] > 4 if (gBattleMons[battlerDef].statStages[STAT_DEF] > 4
@ -1701,7 +1727,7 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
&& defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_WHITE_SMOKE
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_BIG_PECKS) && defAbility != ABILITY_BIG_PECKS)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1709,13 +1735,13 @@ bool32 ShouldLowerDefense(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (IsAiFaster(AI_CHECK_SLOWER) if (IsAiFaster(AI_CHECK_SLOWER)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_WHITE_SMOKE) && defAbility != ABILITY_WHITE_SMOKE)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1723,14 +1749,14 @@ bool32 ShouldLowerSpeed(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4 if (gBattleMons[battlerDef].statStages[STAT_SPATK] > 4
&& HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) && HasMoveWithSplit(battlerDef, SPLIT_SPECIAL)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_WHITE_SMOKE) && defAbility != ABILITY_WHITE_SMOKE)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1738,14 +1764,14 @@ bool32 ShouldLowerSpAtk(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4 if (gBattleMons[battlerDef].statStages[STAT_SPDEF] > 4
&& HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_WHITE_SMOKE) && defAbility != ABILITY_WHITE_SMOKE)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1753,13 +1779,13 @@ bool32 ShouldLowerSpDef(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (defAbility != ABILITY_CONTRARY if (defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
&& defAbility != ABILITY_WHITE_SMOKE && defAbility != ABILITY_WHITE_SMOKE
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_KEEN_EYE) && defAbility != ABILITY_KEEN_EYE)
return TRUE; return TRUE;
return FALSE; return FALSE;
@ -1767,19 +1793,19 @@ bool32 ShouldLowerAccuracy(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility) bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility)
{ {
if (IsAiFaster(AI_CHECK_FASTER) && CanAttackerFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0)) if (IsAiFaster(AI_CHECK_FASTER) && 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 (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE if (gBattleMons[battlerDef].statStages[STAT_EVASION] > DEFAULT_STAT_STAGE
&& defAbility != ABILITY_CONTRARY && defAbility != ABILITY_CONTRARY
&& defAbility != ABILITY_CLEAR_BODY && defAbility != ABILITY_CLEAR_BODY
//&& defAbility != ABILITY_FULL_METAL_BODY && defAbility != ABILITY_FULL_METAL_BODY
&& defAbility != ABILITY_WHITE_SMOKE) && defAbility != ABILITY_WHITE_SMOKE)
return TRUE; return TRUE;
return FALSE; return FALSE;
} }
bool32 CanAttackerFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits) bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits)
{ {
s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index]; s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index];
@ -2433,9 +2459,9 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first if (GetWhoStrikesFirst(battlerAtk, battlerDef, TRUE) == 0) // Attacker goes first
{ {
if (!CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) // Can't KO foe otherwise if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise
{ {
if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 2)) if (CanAIFaintTarget(battlerAtk, battlerDef, 2))
{ {
// attacker can kill target in two hits (theoretically) // attacker can kill target in two hits (theoretically)
if (CanTargetFaintAi(battlerDef, battlerAtk)) if (CanTargetFaintAi(battlerDef, battlerAtk))
@ -2500,7 +2526,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
} }
else if (CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 2)) // Foe can 2HKO AI else if (CanTargetFaintAiWithMod(battlerDef, battlerAtk, 0, 2)) // Foe can 2HKO AI
{ {
if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
{ {
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility)) if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility))
return CAN_TRY_PIVOT; // Use this move to KO if you must return CAN_TRY_PIVOT; // Use this move to KO if you must
@ -2512,7 +2538,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
} }
else // Foe can 3HKO+ AI else // Foe can 3HKO+ AI
{ {
if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
{ {
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO
&& !hasStatBoost) //You're not wasting a valuable stat boost && !hasStatBoost) //You're not wasting a valuable stat boost
@ -2520,7 +2546,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
return CAN_TRY_PIVOT; return CAN_TRY_PIVOT;
} }
} }
else if (CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 2)) else if (CanAIFaintTarget(battlerAtk, battlerDef, 2))
{ {
// can knock out foe in 2 hits // can knock out foe in 2 hits
if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move
@ -2904,7 +2930,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI
if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker if (recoilDmg >= gBattleMons[battlerAtk].hp //Recoil kills attacker
&& CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left && CountUsablePartyMons(battlerDef) != 0) //Foe has more than 1 target left
{ {
if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAttackerFaintTarget(battlerAtk, battlerDef, moveIndex, 0)) if (recoilDmg >= gBattleMons[battlerDef].hp && !CanAIFaintTarget(battlerAtk, battlerDef, 0))
return TRUE; //If it's the only KO move then just use it return TRUE; //If it's the only KO move then just use it
else else
return FALSE; //Not as good to use move if you'll faint and not win return FALSE; //Not as good to use move if you'll faint and not win