Skip to content

Commit

Permalink
Minor switch AI refactor (#4849)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pawkkie authored Jun 22, 2024
1 parent 87b21c2 commit 2640bcd
Showing 1 changed file with 27 additions and 41 deletions.
68 changes: 27 additions & 41 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,7 @@ static bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2)
static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon)
{
u8 defType1 = battleMon->type1, defType2 = battleMon->type2, tSpikesLayers;
u16 heldItemEffect = gItemsInfo[battleMon->item].holdEffect;
u16 heldItemEffect = ItemId_GetHoldEffect(battleMon->item);
u32 maxHP = battleMon->maxHP, ability = battleMon->ability, status = battleMon->status1;
u32 spikesDamage = 0, tSpikesDamage = 0, hazardDamage = 0;
u32 hazardFlags = gSideStatuses[GetBattlerSide(battler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES | SIDE_STATUS_SAFEGUARD);
Expand Down Expand Up @@ -1372,7 +1372,7 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
static s32 GetSwitchinWeatherImpact(void)
{
s32 weatherImpact = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
u32 holdEffect = gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect;
u32 holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);

if (WEATHER_HAS_EFFECT)
{
Expand Down Expand Up @@ -1436,7 +1436,7 @@ static s32 GetSwitchinWeatherImpact(void)
static u32 GetSwitchinRecurringHealing(void)
{
u32 recurringHealing = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
u32 holdEffect = gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect;
u32 holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);

// Items
if (ability != ABILITY_KLUTZ)
Expand Down Expand Up @@ -1470,7 +1470,7 @@ static u32 GetSwitchinRecurringHealing(void)
static u32 GetSwitchinRecurringDamage(void)
{
u32 passiveDamage = 0, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, ability = AI_DATA->switchinCandidate.battleMon.ability;
u32 holdEffect = gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect;
u32 holdEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);

// Items
if (ability != ABILITY_MAGIC_GUARD && ability != ABILITY_KLUTZ)
Expand Down Expand Up @@ -1502,7 +1502,7 @@ static u32 GetSwitchinStatusDamage(u32 battler)
{
u8 defType1 = AI_DATA->switchinCandidate.battleMon.type1, defType2 = AI_DATA->switchinCandidate.battleMon.type2;
u8 tSpikesLayers = gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount;
u16 heldItemEffect = gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect;
u16 heldItemEffect = ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item);
u32 status = AI_DATA->switchinCandidate.battleMon.status1, ability = AI_DATA->switchinCandidate.battleMon.ability, maxHP = AI_DATA->switchinCandidate.battleMon.maxHP;
u32 statusDamage = 0;

Expand Down Expand Up @@ -1580,8 +1580,8 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler)
u32 recurringHealing = GetSwitchinRecurringHealing();
u32 statusDamage = GetSwitchinStatusDamage(battler);
u32 hitsToKO = 0, singleUseItemHeal = 0;
u16 maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, item = AI_DATA->switchinCandidate.battleMon.item, heldItemEffect = gItemsInfo[item].holdEffect;
u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = gItemsInfo[item].holdEffectParam;
u16 maxHP = AI_DATA->switchinCandidate.battleMon.maxHP, item = AI_DATA->switchinCandidate.battleMon.item, heldItemEffect = ItemId_GetHoldEffect(item);
u8 weatherDuration = gWishFutureKnock.weatherDuration, holdEffectParam = ItemId_GetHoldEffectParam(item);
u32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler)));
u32 opposingAbility = gBattleMons[opposingBattler].ability;
bool32 usedSingleUseHealingItem = FALSE;
Expand Down Expand Up @@ -1803,7 +1803,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,

InitializeSwitchinCandidate(&party[i]);

// While not really invalid per say, not really wise to switch into this mon
// While not really invalid per se, not really wise to switch into this mon
if (AI_DATA->switchinCandidate.battleMon.ability == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))
continue;

Expand Down Expand Up @@ -1883,7 +1883,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
// If AI mon outspeeds and doesn't die to hazards
if ((((aiMonSpeed > playerMonSpeed && !(gFieldStatuses & STATUS_FIELD_TRICK_ROOM)) || aiMovePriority > 0) // Outspeed if not Trick Room
|| ((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) // Trick Room
&& (aiMonSpeed < playerMonSpeed || (gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect == HOLD_EFFECT_ROOM_SERVICE && aiMonSpeed * 2 / 3 < playerMonSpeed)))) // Trick Room speeds
&& (aiMonSpeed < playerMonSpeed || (ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item) == HOLD_EFFECT_ROOM_SERVICE && aiMonSpeed * 2 / 3 < playerMonSpeed)))) // Trick Room speeds
&& AI_DATA->switchinCandidate.battleMon.hp > GetSwitchinHazardsDamage(battler, &AI_DATA->switchinCandidate.battleMon)) // Hazards
{
// We have a revenge killer
Expand All @@ -1908,7 +1908,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
// If AI mon outspeeds
if (((aiMonSpeed > playerMonSpeed && !(gFieldStatuses & STATUS_FIELD_TRICK_ROOM)) || aiMovePriority > 0) // Outspeed if not Trick Room
|| (((gFieldStatuses & STATUS_FIELD_TRICK_ROOM) && gFieldTimers.trickRoomTimer > 1) // Trick Room has at least 2 turns left
&& (aiMonSpeed < playerMonSpeed || (gItemsInfo[AI_DATA->switchinCandidate.battleMon.item].holdEffect == HOLD_EFFECT_ROOM_SERVICE && aiMonSpeed * 2/ 3 < playerMonSpeed)))) // Trick Room speeds
&& (aiMonSpeed < playerMonSpeed || (ItemId_GetHoldEffect(AI_DATA->switchinCandidate.battleMon.item) == HOLD_EFFECT_ROOM_SERVICE && aiMonSpeed * 2/ 3 < playerMonSpeed)))) // Trick Room speeds
{
// If AI mon can't be OHKO'd
if (hitsToKOAI > hitsToKOAIThreshold)
Expand Down Expand Up @@ -1949,39 +1949,25 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
// Different switching priorities depending on switching mid battle vs switching after a KO
if (isSwitchAfterKO)
{
// Return Trapper > GetBestMonRevengeKiller > GetBestMonTypeMatchup > GetBestMonBatonPass > GetBestMonDmg
if (trapperId != PARTY_SIZE)
return trapperId;
else if (revengeKillerId != PARTY_SIZE)
return revengeKillerId;
else if (slowRevengeKillerId != PARTY_SIZE)
return slowRevengeKillerId;
else if (fastThreatenId != PARTY_SIZE)
return fastThreatenId;
else if (slowThreatenId != PARTY_SIZE)
return slowThreatenId;
else if (typeMatchupEffectiveId != PARTY_SIZE)
return typeMatchupEffectiveId;
else if (typeMatchupId != PARTY_SIZE)
return typeMatchupId;
else if (batonPassId != PARTY_SIZE)
return batonPassId;
else if (damageMonId != PARTY_SIZE)
return damageMonId;
// Return Trapper > Revenge Killer > Type Matchup > Baton Pass > Best Damage
if (trapperId != PARTY_SIZE) return trapperId;
else if (revengeKillerId != PARTY_SIZE) return revengeKillerId;
else if (slowRevengeKillerId != PARTY_SIZE) return slowRevengeKillerId;
else if (fastThreatenId != PARTY_SIZE) return fastThreatenId;
else if (slowThreatenId != PARTY_SIZE) return slowThreatenId;
else if (typeMatchupEffectiveId != PARTY_SIZE) return typeMatchupEffectiveId;
else if (typeMatchupId != PARTY_SIZE) return typeMatchupId;
else if (batonPassId != PARTY_SIZE) return batonPassId;
else if (damageMonId != PARTY_SIZE) return damageMonId;
}
else
{
// Return Trapper > GetBestMonTypeMatchup > GetBestMonDefensive > GetBestMonBatonPass
if (trapperId != PARTY_SIZE)
return trapperId;
else if (typeMatchupEffectiveId != PARTY_SIZE)
return typeMatchupEffectiveId;
else if (typeMatchupId != PARTY_SIZE)
return typeMatchupId;
else if (defensiveMonId != PARTY_SIZE)
return defensiveMonId;
else if (batonPassId != PARTY_SIZE)
return batonPassId;
// Return Trapper > Type Matchup > Best Defensive > Baton Pass
if (trapperId != PARTY_SIZE) return trapperId;
else if (typeMatchupEffectiveId != PARTY_SIZE) return typeMatchupEffectiveId;
else if (typeMatchupId != PARTY_SIZE) return typeMatchupId;
else if (defensiveMonId != PARTY_SIZE) return defensiveMonId;
else if (batonPassId != PARTY_SIZE) return batonPassId;

// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
else if (aceMonId != PARTY_SIZE
Expand Down Expand Up @@ -2052,7 +2038,7 @@ u8 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|| gBattlerPartyIndexes[battlerIn2] == i
|| i == gBattleStruct->monToSwitchIntoId[battlerIn1]
|| i == gBattleStruct->monToSwitchIntoId[battlerIn2]
|| (GetMonAbility(&party[i]) == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))) // While not really invalid per say, not really wise to switch into this mon.)
|| (GetMonAbility(&party[i]) == ABILITY_TRUANT && IsTruantMonVulnerable(battler, opposingBattler))) // While not really invalid per se, not really wise to switch into this mon.)
{
invalidMons |= gBitTable[i];
}
Expand Down

0 comments on commit 2640bcd

Please sign in to comment.