Skip to content

Fix AI's Switch In Battle

voloved edited this page Feb 1, 2023 · 4 revisions

by devolov

You may notice that battle_ai_switch_items.c has this comment:

/* Possible bug: this comparison gives the type that takes the most damage, when
a "good" AI would want to select the type that takes the least damage. Unknown if this
is a legitimate mistake or if it's an intentional, if weird, design choice */

Let's get rid of that possible bug.

The Current Switch-In AI Logic:

  1. Check for worst type Pokémon. So prioritize Charmander over Bulbasaur if the opponent has a Squirtle out.
  2. See if it has a super effective move
  3. If not, then remove it from the options.
  4. repeat 1-3.
  5. If none have a super effective move, then use the one with the most damaging attack.

Fixing the Main Possible Bug.

There are a few issues I see with this. The largest is Check for worst type Pokémon. Obviously, we'd like to prioritize sending out the best typing.
The change below makes it so we check if Pokemon that have super effective typing have a super-effective move first.

@@ -688,9 +691,12 @@ u8 GetMostSuitableMonToSwitchInto(void)
     invalidMons = 0;
 
     while (invalidMons != 0x3F) // All mons are invalid.
     {
+#ifdef BUGFIX
+        bestDmg = 255;
+#else
         bestDmg = TYPE_MUL_NO_EFFECT;
+#endif

         bestMonId = PARTY_SIZE;
         // Find the mon whose type is the most suitable offensively.
         for (i = firstId; i < lastId; i++)
         {
@@ -711,9 +717,10 @@ u8 GetMostSuitableMonToSwitchInto(void)
 
                 /* Possible bug: this comparison gives the type that takes the most damage, when
                 a "good" AI would want to select the type that takes the least damage. Unknown if this
                 is a legitimate mistake or if it's an intentional, if weird, design choice */
+#ifdef BUGFIX
+                if (bestDmg > typeDmg)
+#else
                 if (bestDmg < typeDmg)
+#endif
                 {
                     bestDmg = typeDmg;
                     bestMonId = i;

Adding Logic to Still Prioritize Super Effective Typing if None Have a Super Effective Move

This is not as crucial, but we'd still like to prioritize a super effective typing regardless of strongest move. If we have a Squirtle out and faint the AI's Pokemon, it'd make sense for them to send out a Bulbasaur with no super-strong moves than a Charmander or Porygon with a stronger move.

 // this file's functions
@@ -641,8 +642,10 @@ u8 GetMostSuitableMonToSwitchInto(void)
     struct Pokemon *party;
     s32 i, j;
     u8 invalidMons;
     u16 move;
+    bool8 checkedAllMonForSEMoves = FALSE;  // We have checked all Pokemon in the party for if they have a super effective move
 
     if (*(gBattleStruct->monToSwitchIntoId + gActiveBattler) != PARTY_SIZE)
         return *(gBattleStruct->monToSwitchIntoId + gActiveBattler);
     if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
@@ -733,12 +740,17 @@ u8 GetMostSuitableMonToSwitchInto(void)
                 if (move != MOVE_NONE && TypeCalc(move, gActiveBattler, opposingBattler) & MOVE_RESULT_SUPER_EFFECTIVE)
                     break;
             }
 
-            if (i != MAX_MON_MOVES)
+            if (i != MAX_MON_MOVES || (checkedAllMonForSEMoves && bestDmg <= TYPE_MUL_NOT_EFFECTIVE))
                 return bestMonId; // Has both the typing and at least one super effective move.

 
             invalidMons |= gBitTable[bestMonId]; // Sorry buddy, we want something better.
+            if (invalidMons == 0x3F && !checkedAllMonForSEMoves)  // If we already checked all for a super effective move, then use the one with the best typing
+            {
+                invalidMons = 0;
+                checkedAllMonForSEMoves = TRUE;
+            }
         }
         else
         {
             invalidMons = 0x3F; // No viable mon to switch.

With these two changes, my Logic is now:

-1. Check for worst type pokemon.
+1. Check for best type pokemon.
 2. See if it has a super effective move
 3. If not, then remove it from the options.
 4. repeat 1-3.
+5. if none have a super effective move, then flag that no pokemon have a super effective move and find the best type pokemon again.
+6 If it's typing is super effective or better, then send it out.
-5. If none have a super effective move, then use the one with the most damaging attack.
+7. If none have a super effective type, then use the one with the most damaging attack.
Clone this wiki locally