Skip to content

Commit

Permalink
Fix Overzealous Absorber Switching (#6318)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pawkkie authored Feb 22, 2025
1 parent 3dd0f95 commit b7df5b8
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
1 change: 1 addition & 0 deletions include/config/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define SHOULD_SWITCH_WONDER_GUARD_PERCENTAGE 100
#define SHOULD_SWITCH_TRUANT_PERCENTAGE 100
#define SHOULD_SWITCH_ALL_MOVES_BAD_PERCENTAGE 100
#define STAY_IN_STATS_RAISED 2 // Number of stat stages that must be raised across any stats before the AI won't switch mon out in certain cases

// AI smart switching chances; if you want more complex behaviour, modify GetSwitchChance
#define SHOULD_SWITCH_ABSORBS_MOVE_PERCENTAGE 100
Expand Down
48 changes: 32 additions & 16 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,20 @@ static bool32 IsAceMon(u32 battler, u32 monPartyId)
return FALSE;
}

static bool32 AreStatsRaised(u32 battler)
{
u8 buffedStatsValue = 0;
s32 i;

for (i = 0; i < NUM_BATTLE_STATS; i++)
{
if (gBattleMons[battler].statStages[i] > DEFAULT_STAT_STAGE)
buffedStatsValue += gBattleMons[battler].statStages[i] - DEFAULT_STAT_STAGE;
}

return (buffedStatsValue > STAY_IN_STATS_RAISED);
}

void GetAIPartyIndexes(u32 battler, s32 *firstId, s32 *lastId)
{
if (BATTLE_TWO_VS_ONE_OPPONENT && (battler & BIT_SIDE) == B_SIDE_OPPONENT)
Expand Down Expand Up @@ -408,7 +422,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
s32 firstId;
s32 lastId;
struct Pokemon *party;
u16 monAbility;
u16 monAbility, aiMove;
u32 opposingBattler = GetOppositeBattler(battler);
u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler];
u32 incomingType = GetMoveType(incomingMove);
Expand All @@ -421,9 +435,25 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
return FALSE;
if (gBattleStruct->prevTurnSpecies[battler] != gBattleMons[battler].species) // AI mon has changed, player's behaviour no longer reliable; note to override this if using AI_FLAG_PREDICT_MOVE
return FALSE;

if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING_STAY_IN, STAY_IN_ABSORBING_PERCENTAGE) || AI_DATA->aiSwitchPredictionInProgress))
return FALSE;
if (AreStatsRaised(battler))
return FALSE;

// Don't switch if mon could OHKO
for (i = 0; i < MAX_MON_MOVES; i++)
{
aiMove = gBattleMons[battler].moves[i];
if (aiMove != MOVE_NONE)
{
// Only check damage if it's a damaging move
if (!IsBattleMoveStatus(aiMove))
{
if (AI_DATA->simulatedDmg[battler][opposingBattler][i].expected > gBattleMons[opposingBattler].hp)
return FALSE;
}
}
}

if (IsDoubleBattle())
{
Expand Down Expand Up @@ -762,20 +792,6 @@ static bool32 HasSuperEffectiveMoveAgainstOpponents(u32 battler, bool32 noRng)
return FALSE;
}

static bool32 AreStatsRaised(u32 battler)
{
u8 buffedStatsValue = 0;
s32 i;

for (i = 0; i < NUM_BATTLE_STATS; i++)
{
if (gBattleMons[battler].statStages[i] > DEFAULT_STAT_STAGE)
buffedStatsValue += gBattleMons[battler].statStages[i] - DEFAULT_STAT_STAGE;
}

return (buffedStatsValue > 3);
}

static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 percentChance)
{
u32 battlerIn1, battlerIn2;
Expand Down

0 comments on commit b7df5b8

Please sign in to comment.