Emi's Blog

<- Back to blog

Trainer AI in Crystal Kaizo+

Pokemon Crystal Kaizo+ is a romhack and spiritual successor to Pokemon Crystal Kaizo, a romhack of Pokemon Crystal, and the sequel to Pokemon Blue Kaizo. Crystal Kaizo was made by the developer SinisterHoodedFigure, and is designed to be a more challenging version of Crystal. Crystal Kaizo+, on the other hand, was designed to focus more tightly on the core gameplay elements of battling, taking major inspiration from SHF's later work, Pokemon Emerald Kaizo.

Both games are broadly similar, but they do have some notable differences. Crystal Kaizo was made using rudimentary tools and raw hex editing, meaning while a lot of the game was available to be tweaked, plenty of changes were simply infeasible. Crystal Kaizo+, made 8 years later by a different team, utilized the pokecrystal disassembly project. This disassembly, crucially, meant while anything that was accomplished in CK was possible, and often easier, there were significantly fewer limitations. One of the most significant changes CK+ was able to make that CK couldn't was adjusting the AI of the enemy trainers.

My role

I was not involved when CK+ was developed, unfortunately. My primary contribution to the community of players is my damage calculator, which is more than just that, but out of scope to go over. Beyond this, I've been responsible for a vast amount of technical investigations and experiments in the community. My analysis of the assembly code responsible for trainer AI, both original and added by CK+, has been crucial for informing how players play the game.

In this post, I'll be going over a hefty chunk of the game's AI behaviors, detouring to explain both intended behaviors and the real, bugged behavior that has plagued runners for years. Many of the quirks the AI maintains are interesting both behaviorally and from a design perspective. A decent technical knowledge base is not expected, but may make certain parts easier to grasp.

Why is this important?

Oh, right, motivation. CK+ was designed to be played under Hardcore Nuzlocke Rules, a variant of standard gameplay that restricts the player's team members and resources to hopefully create gameplay that is both difficult and engaging. Under these rules, CK+ is a very difficult game. At the time of writing, CK+ has been out for over 2 years and, despite this, only 27 players have beaten the game (while recording). Players use resources, like documentation and damage calculators, to engage with a full information puzzle game.

A skilled player will plan out entire fights based on all the possibilities that can occur in game, down to precise damage numbers, and execute their plans. The goal is to not lose team members and beat every fight, which is not something that can be guaranteed. Creatively finding interesting interactions to optimize away risk and making value calls when otherwise necessary is engaging for a certain kind of person.

To this end, players find it valuable to understand what the enemy can do every turn, given some game state. Fortunately, in game AI is quite predictable. There is a good bit of chance to play around, but being able to assess that chance and play around it possible.

AI Basics

When deciding what to do in a turn, the trainer AI assigns each of its moves a score through a variety of processes, and picks the lowest value, resolving ties randomly. Scores start at 20, and a variety of "AI layers" compound on the score. Let's take a look at an example. Most everything here won't be super clear, but it'll make sense by the end of all of this.

Move Damage Roll Basic Aggressive Smart Status Score
Psychic 83-98 96 - +2 - 0 22
Thunderbolt 88-104 99 - 0 - 0 20
Hypnosis - - 0 +2 0 0 22
Shadow Ball 36-43 37 - +2 - 0 22

If we ignore most everything, we can see that Thunderbolt has is always going to be scored as 20, the lowest score. In reality, the rolls chosen for Psychic and Thunderbolt may be different, and the scores would look different if Psychic if was the highest damaging move. But that's a discussion for later. Runners can figure out these AI scores, or at least some representation of them, by just seeing the two columns on the left, which a damage calculator can output.

AI Layers

An AI layer is a routine run on all moves that scores them given some criteria. Many routines are only applicable to a subset of moves, such as only caring about damaging moves, or only caring about moves with type interactions. Every trainer class in the game, represented as a unique sprite and title for the trainers, has a list of AI layers that apply to them in battle. Pokemon Crystal has 10 unique AI layers, which were named in the pokecrystal disassembly based on their behaviors.

AI Layer Description
Basic Avoid using moves that would be contextually useless
Setup Use moves that modify stats early, avoid using them later on
Aggressive Use the strongest attacks, rather than the weaker ones
Smart Look up one of 77 unique, short, move-specific scoring contexts
Status Avoid moves that would be ineffective on the target
Types Use the type chart, super-effective is king
Offensive Avoid moves that don't deal damage
Opportunist Avoid "stall" moves more and more as the AI's health gets low
Cautious Avoid moves with "residual effects" after the AI's first turn
Risky Use moves that can KO the player, unless they're "risky"

This is a lot of routines, and a lot of them are vague. As said, they are layers which can be applied individually and in combination with others, vanilla Crystal has a variety of groups of them for every trainer class. So let's take a look at a table of what trainer classes use what AI layers.

Class Basic Setup Aggressive Smart Status Types Offensive Opportunist Cautious Risky
All Used - Used Used Used - - - - -

Cool, we can discard more than half of them and only discuss the 4 AI layers that every trainer uses, Basic, Aggressive, Smart, and Status. This style of AI design is pretty common in difficulty hacks. It's easier to design one set of cohesive AI that is difficult to play around than to design several interesting layers. Additionally, a lot of hacks devs don't have the ability to write their own AI routines, and a lot of the vanilla ones aren't particularly useful. In CK+'s case, the devs did write custom modifications to the AI layers they used.

Choosing a Move

After all the AI layers have scored moves, the AI additionally does a pass checking to see if moves are either out of PP or disabled. Moves that are get assigned a flat score of 80. There is no way to get anywhere near this high with normal AI layers, so these effectively make moves unselectable. After this, the lowest score is determined, and a random move of that score is selected randomly. If a single move has the lowest score, it will always be selected, if multiple moves have the lowest score, they each have an equal chance of being selected.

It is notable that AI layers do not check to see if a move is usable before scoring it, leading to situations where certain layers, like Aggressive, will pick a move as the strongest move, and then have that move set to 80 at the end.

Basic AI

Basic AI has 2 relatively simple parts. For each move on the AI's set, it checks if it's in one of 2 categories: potentially redundant, or status.

Redundant

Potentially redundant moves are status moves which have active effects that would not do anything if used while already active. Some examples are weather setting moves like rain dance which would do nothing in the rain, nightmare and dream eater which can only be used on sleeping targets, healing moves like recover which can't heal a full HP pokemon, and hazards like spikes or screens like reflect, which can only be set up once. There are a handful more, and all of their redundant conditions should be straightforward.

Full List Dream Eater, Nightmare, Snore, Sleep Talk, Recover, Milk Drink, Softboiled, Rest, Morning Sun, Synthesis, Moonlight, Sandstorm, Rain Dance, Sunny Day, Light Screen, Reflect, Safeguard, Mist, Focus Energy, Transform, Substitute, Leech Seed, Disable, Encore, Mean Look, Spikes, Foresight, Perish Song, Attract, Teleport, Swagger, Future Sight

Moves that are determined to be redundant based on their conditions are dismissed (+10).

Status

If a move is not potentially redundant and is, instead, a status move, that is, directly causes poisoning, toxic poisoning, paralysis, or sleep, then it goes through the status check.

Full List PoisonPowder, Poison Gas, Toxic, Stun Spore, Thunder Wave, Glare, Sleep Powder, Sing, Hypnosis, Lovely Kiss, Spore

If the player is either already statused, or has set up safeguard (which would prevent the status), moves that match this check are dismissed (+10).

Summary

And... that's it for Basic! CK+ seems to not have changed Basic AI from vanilla Crystal. This is pretty reasonable, Basic AI is, tastefully, basic. All the decisions the AI makes are very clearly correct, assuming the player doesn't switch out (which no AI routine takes into consideration).

Status AI

Jumping forward to the next simple AI, Status AI is a bit misnamed and improperly documented. It is responsible for making the AI avoid ineffective moves. A lot of these checks target moves that do not deal damage, but, it does additionally handle damaging moves. Below are the rules and their applications

Poisoning moves

Moves that cause poisoning or toxic poisoning (PoisonPowder, Poison Gas, Toxic) will be dismissed (+10) if the player is using a poison type. Otherwise, they will progress on to the type immunity section.

Leech Seed

Leech Seed will be dismissed (+10) if the player is using a grass type. Otherwise, Leech Seed will progress on to the type immunity section.

Type Immunity

Several types of moves progress on to checking type immunity.

These moves will be dismissed (+10) if the player's pokemon is immune to the type of the move. It is important to note, while these immunities are real for a majority of the moves checked (including all damaging moves), there are a handful of moves checked that produce incorrect behavior. Hypnosis is a psychic type move, and dark types are immune to psychic type attacks. Despite this, since Hypnosis is a status move, it is able to be used on dark types, and Status AI will dismiss the move. Similarly, Sing and Lovely Kiss are normal type moves, and ghost types are immune to normal type attacks. Again, despite this, these moves are status moves and would be able to hit ghost types, despite being dismissed here. Interestingly, Glare is also a normal type status move, but is affected by type immunity until later games in the series, so this behavior is correct for it here.

Status moves that are not dismissed by this step progress on to the substitute section.

Substitute

In addition to all the status moves from the previous section, any status move that confuses the target or directly lowers stats are checked for and dismissed (+10) if the player's pokemon is behind a substitute.

Full List PoisonPowder, Poison Gas, Toxic, Leech Seed, Stun Spore, Thunder Wave, Glare, Sleep Powder, Sing, Hypnosis, Lovely Kiss, Spore, Supersonic, Confuse Ray, Sweet Kiss, Growl, Charm, Tail Whip, Leer, Screech, String Shot, Cotton Spore, Scary Face, Flash, Sand Attack, Smokescreen, Kinesis, Sweet Scent

Summary

Status AI (or, probably better called "Immunity AI"), for the most part, avoids using moves that would do nothing on the target. This is with the exception of Hypnosis being dismissed against dark types and sing or lovely kiss being dismissed against ghost types. Status AI mostly exists as is in Crystal. CK+, however, was responsible for both leech seed and substitute checking. Both of these additions make Status AI more effective in its goal.

Smart AI

Smart AI consists of 77 small routines. Going over all of them would take quite a while, so here are brief descriptions of several. Some complex routines are not fully summarized, and more may be added to properly fill out the list in the future. Identical routines are merged together. I honestly don't recommend reading them all, if you'd like, you can skip past the table to the interesting one.

Moves Effect
Sleep Powder
Sing
Hypnosis
Lovely Kiss
Spore
If the AI also knows Dream Eater or Nightmare, it has a 50% chance to greatly encourage (-2) the move
SelfDestruct
Explosion
See Boom AI below
Dream Eater 90% chance to very greatly encourage (-3)
Mirror Move If the player did not use a move last turn, dismiss (+10) if the AI is faster than the player
If the player did use a move last turn and it was useful, 50% chance to encourage (-1) with a further 90% chance to encourage again (-1) if the AI is faster
Double Team
Minimize
If the AI can't raise evasion further, dismiss (+10)
Otherwise, move is encouraged or discouraged through a lengthy comparison of current player and AI HP, player toxic/leech seed status, and if the player is locked in to Fury Cutter or Rollout, scores anywhere from +2 to -2
Flash
Sand Attack
Smokescreen
Kinesis
Lengthy comparison of player and AI HP, player toxic/leech seed status, and if the player is locked in to Fury Cutter or Rollout, scores anywhere from +2 to -2
Swift
Faint Attack
Vital Throw
If the AI's accuracy has been lowered, or the player's evasion has been raised, 80% chance to greatly encourage (-2)
Haze If either any of the AI's stats are lower than -2 or any of the player's stats are higher than +2, 85% chance to encourage (-1)
Otherwise, discourage (+1)
Bide If the AI's HP is not full, 90% chance to discourage (+1)
Roar
Whirlwind
If the AI would like to switch more than neutral, encourage (-1)
Recover
Milk Drink
Softboiled
Rest
Morning Sun
Synthesis
Moonlight
If the AI's HP is above 50%, discourage (+1)
If the AI is below 25% HP, 90% chance to greatly encourage (-2)
Toxic
Leech Seed
If the player is below 50% HP, discourage (+1)
Reflect
Light Screen
If the AI's HP is not full, 50% chance to discourage (+1)
Horn Drill
Fissure
Guillotine
If the AI's level is lower than the player's, dismiss (+10), otherwise, if the player's HP is below 50%, discourage (+1)
Razor Wind If the Player has Protect, dismiss (+6)
If the AI will faint from Perish Song this turn, discourage (+1)
If the AI is confused, 20% chance to discourage (+1)
Super Fang If the player's HP is below 25%, discourage (+1)
Bind
Wrap
Fire Spin
Whirlpool
Clamp
If the player is not already trapped and it is either the AI's first turn, or the player is affected by toxic, attract, nightmare, is stuck in Rollout, or is identified, 50% chance to greatly encourage (-2)
Otherwise, 50% chance to discourage (+1)
Supersonic
Confuse Ray
Sweet Kiss
If the player has less than 50% HP, 90% chance to discourage (+1)
Additionally, if the player has less than 25% HP, discourage again (+1)
Icy Wind
Constrict
Bubble
Bubblebeam
If it is the player's pokemon's first turn out, the AI has more than 25% HP, and the player is faster than the AI, 90% chance to greatly encourage (-2)
Substitute If the AI has less than 50% HP, dismiss (+10)
Hyper Beam If the AI has less than 25% HP, 50% chance to encourage (-1)
If the AI has more than 50% HP, 42.5% chance to discourage (+1) or 42.5% chance to greatly discourage (+2)
Rage If the AI has not used Rage yet and has less than 50% HP, discourage (+1)
Otherwise, if the AI has used Rage, 50% chance to encourage (-1), plus an additional encourage (-1) for each having a rage counter above 2 and 3
Earthquake
Magnitude
If the player is currently underground and the AI is faster than the player, greatly encourage (-2)
Future Sight If the player is currently flying or underground and slower than the AI, greatly encourage (-2)
Gust
Twister
If the player is currently flying and the AI is faster than the player, greatly encourage (-2)
Otherwise, if the enemy is slower than the player and just used Fly, 50% chance to encourage (-1)
Stomp If the player has used Minimize, 80% chance to encourage (-1)
SolarBeam If it is sunny, 80% chance to greatly encourage (-2)
If it is raining, 90% chance to greatly discourage (+2)
Thunder If it is sunny, 90% chance to discourage (+1)
Fly
Dig
If the enemy is currently flying or underground and slower than the AI, very greatly encourage (-3)

Useful Moves

This is a collection of moves some Smart AI routines consider "useful". It is mostly a subset of high damaging moves and decent status options.

Full List Flamethrower, Fire Blast, Ice Beam, Blizzard, Thunderbolt, Thunder, Surf, Hydro Pump, Earthquake, Psychic, Hyper Beam, Double Edge, Super Fang, Sing, Hypnosis, Sleep Powder, Toxic, Recover, Softboiled

Boom AI

Smart AI runs "Boom AI" for SelfDestruct and Explosion. This is an entirely custom routine added to CK+. There are a handful of conditions that will cause Boom AI to dismiss (+10) SelfDestruct or Explosion.

Additionally, if the AI's HP is between 50% and full and *doesn't* dismiss the move, it will be instead greatly encouraged (-2). Most of these conditions make sense, as the AI's HP goes down, its chance to boom goes up. There is a notable quirk with encouraging only occurring between 50% and 100% which was likely an oversight. However, there are 2 large problems with Boom AI.

First and foremost, the AI's condition of dismissing boom if there are any moves that can OHKO is flawed. Obviously, it was intended to not have the AI blow up its pokemon if it has another option that can handle the player's pokemon. However, as will be gone over later in Aggressive AI, the game will happily score SelfDestruct and Explosion as OHKOs if they deal enough damage. This means, if either move will always deal all of the player's remaining HP or more, it will dismiss the move, and never choose it outside of rare circumstances where all other options are exhausted. This was not intended, trainers in game who used pokemon with SelfDestruct and Explosion were intended to be difficult challenges where the player had limited tools to prevent them from using those moves, which can KO a majority of the player's team.

More minorly, due to an unknowable reason, each time SelfDestruct or Explosion is dismissed, the game will run a copy of Aggressive AI with tweaks that do nothing except, ironically, not count SelfDestruct or Explosion as OHKOs, which would have fixed bug if used in place of normal Aggressive AI. This second pass of Aggressive AI does not often impact the results of a turn, but it certainly makes exhaustively calculating possibilities more tedious.

Conclusion

Smart AI is, overall, mostly reasonable. Many of the rules seem to follow inconsistent priorities and levels of complexity, but overall encourage enemy trainers to use their moves effectively. However, Boom AI in particular would ironically achieve the goals of its designers better were it to simply not exist. It is competing for most broken AI routine in the game and, were this page to end on this sentence, would easily claim the title. Unfortunately, that was not the last sentence, so I'll need to go into Aggressive AI, the most important routine in the game.

Aggressive AI

Core to a threatening AI and the bread and butter of hardcore nuzlocke gameplay, Aggressive AI is responsible for making sure the AI uses the damaging move that does the most damage. Most every iteration of Pokemon has a routine for this, and Crystal is no different. However, CK+ modified Aggressive AI to further encourage OHKO moves over status moves.

Intention

Briefly, Aggressive AI intends to greatly encourage (-2) every move that OHKOs the player and, unless there are multiple moves that OHKO, discourage (+2) every damaging move except the highest damaging move. Vanilla Crystal only discouraged (+2) moves that weren't the highest damaging. CK+'s Aggressive AI almost works.

Procedure

The first part of Aggressive AI, common for all iterations, is to take every damaging move the AI has, and calculate how much damage it will do. This is done using the standard damage calculation in the engine. Double hit moves double the move's power, and multi hit moves triple it. This is distinct from the actual game's effect of calculating each hit independently, which, due to rounding, will result in some slight differences. Magnitude assumes a power of 70.

Moves calculated by the AI will never be a critical hit, however, they still will be affected by the random damage variation, the multiplier between 85% and 100% of the move's damage. Players often call the different values damage can take on after the random variation "rolls". Interestingly, Flail and Reversal are calculated by AI this way, including a damage variation, despite the fact that in battle, these moves both cannot be a critical hit and are unaffected by damage variation.

After rolling damage, the game will determine if that damage is enough to KO the player's pokemon. If so, the move is immediately encouraged based on its accuracy and the counter for number of moves that OHKO the player is incremented. Moves that have 100% accuracy are greatly encouraged (-2). Moves that have less than 100% accuracy but at least 75% accuracy are encouraged (-1). Moves that have less than 75% accuracy are unmodified (0). This is the crux of Boom AI's biggest flaw, both SelfDestruct and Explosion can get this far and get scored as an OHKO. The modified version of Aggressive AI that Boom AI calls will correctly not count SelfDestruct and Explosion as OHKOs. If the move is not SelfDestruct or Explosion, the AI will then compare it against the highest damaging move so far, breaking ties with the latest move, keeping track of both the damage the move did, and what slot it is in.

After the first stage of aggressive AI, the moves have been scored for being OHKOs, the number of moves that OHKO has been counted, and the highest damaging move's damage and move slot are recorded. Moving on, the final stage, in both Crystal and CK+, is supposed to go through each move and, if it deals damage and was not determined to be the highest damaging, discourage (+2) it. There is an exception to this, moves which are "reckless" will not be discouraged. In Crystal, this is a medium sized list, however, in CK+, it only contains SelfDestruct, Explosion, and Destiny Bond. It is worth mentioning that Destiny Bond is not a damaging move, and would've not been discouraged regardless. CK+ has a check before this step, skipping it entirely if multiple moves were scored as OHKOs, to prevent discouraging one of the moves that OHKOs.

The Mistake

So far, CK+'s AI has been mostly serviceable. Any errors or quirks were isolated to individual moves. That's going to change.

Crystal's discourage phase works correctly. Every move that's not the highest damaging and not reckless is discouraged (+2). CK+'s changes cause some confusion. If the AI attempts to discourage a move, it will succeed, however, it will misalign its variables. The game keeps track of 3 variables when it's iterating moves.

Variable Uses Alignment
Move Slot Determines whether or not move is the highest damaging Always iterated correctly
Move Determines if the move is damaging or reckless Not incremented if move gets discouraged
Move Score Determines what move is being scored Always iterated correctly

Here's a more clear example from earlier, annotated with info relevant to Aggressive AI.

Real Move Damage Roll Slot Seen Move Real Score Correct Score
Psychic 83-98 96 1 Psychic (+0) +2 +2
Thunderbolt 88-104 99 2 Psychic (+1) 0 0
Hypnosis - - 3 Thunderbolt (+0) +2 -
Shadow Ball 36-43 37 4 Thunderbolt (+0) +2 +2

As seen, Aggressive AI will always correctly skip the highest damaging move, since the slot number always increments correctly. However, whenever Aggressive AI encounters a damaging move that not reckless or highest damaging, it will get stuck. The move will be correctly discouraged, but every move afterwards will be treated as if it was that same move. There is one exception, if the first non-reckless damaging move is before the highest damaging move, it will remain stuck until the highest damaging move. At this point, the move pointer will increment, but it will already be misaligned and will continue smearing the incorrect moves down the list once it settles on another damaging move. It is worth noting that the AI got stuck on Thunderbolt, despite it being the highest damaging move, because it only ever checks the move slot to determine highest damaging move.

Let's take a look at further examples.

Real Move Damage Roll Slot Seen Move Real Score Correct Score
Waterfall 32-38 33 1 Waterfall (+0) +2 +2
Toxic - - 2 Waterfall (+0) +2 -
HP Grass 32-38 38 3 Waterfall (+1) 0 0
Ice Beam 21-25 24 4 Toxic (+1) - +2

Here something very incorrect happens. Toxic, which should be ignored (-), is being seen as Waterfall and being greatly discouraged (+2). At the same time, Ice Beam is being seen as Toxic and being ignored (-) instead of being greatly discouraged (+2). If Pokemon had 5 or more moves, the smearing would continue, every move afterwards being seen as HP Grass and being greatly discouraged (+2) with no way to break out.

Shorthand Rules

Aggressive AI is far from intuitive. Shorthand rules help for understanding it, so, here are some. All rules assume fewer than 2 moves OHKO the player.

Summary

Aggressive AI is highly broken. While it's possible to organize any moveset to not run into any issues, many of the game's movesets are not organized like this.

Additional Quirks

Outside of AI layers, CK+ also has a custom anti-stall mechanism built in. If the player goes 4 turns in a row without taking damage from moves, the AI will ignore its move scores and pick its move randomly. If this is triggered, the AI is also skips some checks discouraging it from switching.

Layer Examples

Now that most everything has been illuminated, let's go over a handful of examples.

Move Damage Roll Basic Aggressive Smart Status Score
Razor Leaf 49-58 50 - +2 - 0 22
Lovely Kiss - - 0 +2 - +10 32
Steel Wing 65-77 75 - 0 - 0 20
Substitute - - - - 0 - 20

AI is at 100% HP and player's pokemon is Gengar at 200 (100%) HP.

In this example, Lovely Kiss is improperly discouraged (+2) by Aggressive AI, and Substitute is correctly but accidentally ignored (-) by Aggressive AI, as it is seen as Lovely Kiss, which is a status move. Lovely Kiss is additionally seen as ineffective against Gengar, being a ghost type, despite Lovely Kiss being able to affect ghost types.

Move Damage Roll Basic Aggressive Smart Status Score
Ice Beam 66-78 70 - +2 - 0 22
Thunderbolt 75-89 89 - +2 - 0 22
Mud Slap 10-12 10 - +2 - 0 22
Flamethrower 150-177 152 - 0 - 0 20

AI is at 100% HP and player's pokemon is at 200 (100%) HP.

This one of the more common situations in CK+. A moveset of four damaging moves. Despite every move being seen as Ice Beam, Aggressive AI correctly dismisses (+2) every move except Flamethrower, which does the most damage. The position of the moves does not matter for the scoring. Though, were Flamethrower in a lower slot, every move after it would be seen as Flamethrower, again to no effect.

Move Damage Roll Basic Aggressive Smart Status Boom Aggressive Score
Explosion 123-145 144 - -2 +10 0 0 28
Acid 0-0 0 - 0 - +10 +2 32
Surf 96-114 112 - -2 - 0 -2 16
Toxic - - +10 - +1 +10 +2 43

AI is at 100% HP and player's pokemon is a burned Magneton at 96 (40%) HP.

This is perhaps the most contrived AI scenario I can create. Going layer by layer, Basic dismisses (+10) Toxic because the player is currently burned. Aggressive sees both Explosion and Surf as OHKOs, greatly encouraging (-2) both and, because multiple moves are OHKO, skips the discourage phase. Smart AI discourages (+1) Toxic because the player's pokemon is below 50% HP, and dismisses (+10) Explosion because there are OHKOs. Because Boom AI dismissed a move, the modified aggressive routine runs. Boom Aggressive doesn't count Explosion as a KO and, thus, only greatly encourages (-2) Surf as an OHKO. Because only one move OHKO'd, the Aggressive discourage phase occurs, skipping Explosion as a reckless move. Acid is greatly discouraged (+2) as a damaging move, smearing the move onto Surf. Surf is seen as Acid but is also the highest damaging move, being ignored and incrementing the move properly. Toxic is seen as Surf, a damaging move, and is greatly discouraged (+2). Finally, Status AI sees both Acid and Toxic as poison moves targeting an immune player, a steel type, and dismisses (+10) both.

Switch AI

Move selection AI is only part of the puzzle when it comes to trainer AI. The rest of the pieces come together with two forms of switch AI: Post-KO and mid-turn switch AI. The former governs what pokemon should come out after the player has defeated one of the AI's pokemon. The latter governs whether the AI should switch out instead of opting to attack, and if so, to which pokemon. Both use completely distinct routines.

Post-KO Switch AI

Post-KO switch AI is the most common form of switch AI the player will interact with. Since every battle with 2 or more pokemon will require it occur at least once, a majority of battles in the game will have it occur 1-5 times. Fortunately, it is by far the simpler AI, basic and stateless enough to allow tools like the damage calculator to indicate it with no trouble.

Every living pokemon is individually assigned a score from -1 to 1. From there, the highest score is determined, and the first pokemon with that score in party order is sent out. In the case that every single living AI pokemon scores -1, the switch becomes random. Each pokemon is scored thusly:

That's it. Two basic super effective checks, considering the enemy's moves and the player's types. There are some obvious flaws here, of course, the consideration of status moves, the lack of consideration for the player's moves. At the very least, it can be assumed that this is slightly smarter than simply going in party order.

Post-KO Switch AI Examples

While it's quite simple, there's no harm going through some basic examples. Suppose the player has out a Growlithe. As we know, its moveset does not matter. Technically the AI cannot have 6 switch candidates, as one pokemon needs to faint to proc this AI. 6 candidates are used here for a better example.

Pokemon Moves Score
Mankey Karate Chop Endure - - 0
Mantine Water Gun Surf Bubble Bubblebeam +1
Meganium Petal Dance Earthquake - - 0
Remoraid Rain Dance - - - +1
Oddish Stun Spore Sleep Powder Moonlight Tackle -1
Magnemite Thunder - - - -1

In this scenario, Mankey has no super effective moves against Growlithe, but Fire is not super effective against Fighting, so Mankey is scored 0. Mantine resist's Growlithe's Fire type and deals super effective damage with all of its attacks, so it is scored +1. Meganium takes super effective damage against Fire, however, it also deals super effective damage back to Growlithe with Earthquake, so, it is scored 0. Remoraid does not take super effective damage, and Rain Dance, as a water type move, is considered to be super effective against Growlithe, so it is scored +1. Oddish is the type of pokemon the AI wants to send out the least, taking super effective damage from fire and not dealing super effective damage against it in return, it is scored -1. Similarly, it also would love to not send out Magnemite, whose Steel typing is weak to Fire and whose Thunder deals neutral damage to Growlithe, earning another score of -1.

With these scores, we can see that Mantine will be sent out first, since it is the first pokemon in party order to have a score of 1. Were Mantine and Remoraid to both be KO'd by Growlithe, the game would then send out Mankey, then Meganium, and with final reluctance, either Oddish or Magnemite would be sent out, randomly.

Hopefully this is simple to understand. Additionally, since the damage calculator handles this simple switch AI, most runners don't even need to consider it.

Mid-Turn Switch AI

Now this is the special one. Of all routines in CK+, mid-turn switch AI survived cloaked in mystery the longest. However, finally, it's untangled and can be laid bare, but be careful, it's a doozy.

Mid-turn switch AI returns 2 separate scores. One score determining the chance that a switch should occur, and one determining, if it were to happen, which target to switch to. The first score comes in a range of 0 to 3. What this score means depends on the the switch flag set on the trainer class the player is facing.

Switch AI Flag Score 0 Score 1 Score 2 Score 3
Never 0% 0% 0% 0%
Rarely 0% 8% 12% 20%
Sometimes 0% 20% 50% 80%
Often 0% 20% 50% 80%

It is worth noting that these values are rounded and Often has very slightly higher chances than Sometimes (by about 0.6%). With this in mind, you might think that you'd have to memorize this table... but fortunately CK+ saves the day again! Every trainer in the game has the switch flag set to Often, unlike in vanilla where only certain classes (like jugglers) would have this elusive flag.

Mid-Turn Switch AI Routine

The first thing the AI does is pick one of 4 sub-routines to use for switch AI based on the current conditions of the battle. The simplest condition is the AI only has 1 pokemon alive, in which case it exits the routine and has no (0%) chance to switch. Using the same logic as move selection AI, if the enemy has not dealt direct damage to the player in 4 consecutive turns, the AI uses Random Switch AI. If the enemy is afflicted with perish song and has 1 turn remaining at time of checking, the AI will use Perish Song AI. Failing this all, the AI continues to Basic Switch AI.

These routines will reuse a handful of concepts. For one, the player's "last attack" is the non-status move used the last time the player had the chance to act. If nothing fits this description, the player has no last attack. Another one of these is the generic switch target.

Generic Switch Target

At several points in routines, the AI will attempt to find a generic switch target. These come in two forms, either a standard generic switch target, or a preferred generic switch target. In order to qualify, four checks are made on each pokemon in the party, and the best candidate is selected in party order.

The first and most basic check is whether this pokemon is alive, having more than 0 HP, and not the current pokemon being used to battle. There are some errors in what the AI will return if it has no actual candidates that match this, spitting out garbage, but later routines accidentally correct this, so it's of no consequence.

The second check is whether the enemy has a "quarter" of its HP remaining. That sounds simple, they made it not simple.

Quarter Mirrored Shifting

In order to determine if a pokemon has at least a quarter of its HP it takes its max HP and compares it against its current HP ran through a formula. It was intended that this formula would quadruple the value. Instead, the formula outputs uncorrelated behavior that even fails for pokemon who have taken no damage. The following formula rounds down after all operations and % represents the modulo operation.

(hp / 256 * 1024) + (hp % 256 / 4) + (hp % 2 * 512) + (hp % 4 / 2 * 256)

Sorry if you were expecting hp * 4. The reason for this happening is not that complicated. HP on the GameBoy Color is stored as 2 separate bytes, a low byte and a high byte. In order to quadruple two bytes, each byte needs to be doubled twice separately and, if the low byte overflows, it should enter in the high byte. This is a common procedure. Shift the low byte left, shift the high byte left with carry, now you've doubled your two byte value. Do this twice to quadruple. The devs of Crystal made a mistake. They, instead, shifted the low byte right, then shifted the high byte left with carry.

Before Intended After Actual After Error
0000000a b000000c - 00000ab0 00000c00 - 00000ac0 00b00000 - -
00000000 00001010 (10) 00000000 00101000 (40) 00000001 00000010 (258) +218
00000000 00001000 (8) 00000000 00100000 (32) 00000000 00000010 (2) -30
00000000 00000001 (1) 00000000 00000100 (4) 00000010 00000000 (512) +508
00000001 00000000 (256) 00000100 00000000 (1024) 00000100 00000000 (1024) 0
00000001 00000010 (258) 00000100 00001000 (1032) 00000101 00000000 (1280) +248

Well oops, that's not quadrupling. As stated, behavior is very erratic, and adjacent values are not correlated. Intuitively, the most important factors are whether the high byte is 0 (HP < 256), and whether either of the two low bits are set (HP % 4 != 0). The behavior can be broadly categorized into 4 groups.

Condition Effect
HP < 256 & HP % 4 == 0 Divides by 4 instead of multiplying by 4
HP < 256 & HP % 4 != 0 Value explodes massively, in the range of 256-831
HP >= 256 & HP % 4 == 0 Multiplies by between 3-4 approximately
HP >= 256 & HP % 4 != 0 Multiplies by between 4-7 approximately

Practically, about 1/4 pokemon cannot be selected as generic switch targets despite being at full health. At least, until base HP starts exceeding 255, past that point all candidates at full HP will be considered healthy enough.

Generic Switch Target Result

After that detour and a good chunk of pokemon arbitrarily discounted, the final 2 checks are comparatively simple. Each pokemon checks its type effectiveness against the player's hypothetical attacks and is removed if it is hit super effective. If the player has a last attack, that type is checked against the AI. Otherwise, the player's types are checked instead.

Finally each remaining candidate checks its moves type effectiveness against the player. During this check, moves with no power are skipped. The first of the AI's pokemon which has a super effective move against the player, if any, is chosen as the preferred generic switch target. Otherwise, the first of the AI's pokemon which has a neutral move against the player, if any, is chosen as the generic switch target. Failing this, no candidate is selected.

Matchup Score

The first task of basic switch AI is determining the "matchup score" of the enemy pokemon against the player's pokemon. This is used to determine if the AI wants to switch and, if so, how much. There are a handful of factors that determine what the matchup score is, which can be split into several simple steps.

Matchup Score Examples

Let's run through some examples.

Player Pokemon Revealed Moves AI Pokemon AI Moves Player Score AI Score Total Score
Cyndaquil - Chikorita Tackle
Razor Leaf
-1 0 9
Cyndaquil Ember Chikorita Tackle
Razor Leaf
-1 0 9
Cyndaquil Tacle Chikorita Tackle
Razor Leaf
0 0 10
Cyndaquil ThunderPunch Chikorita Tackle
Razor Leaf
+1 0 11
Cyndaquil Sunny Day
Ember
Tackle
ThunderPunch
Chikorita Tackle
Razor Leaf
-1 0 9
Cyndaquil Ember
Fire Punch
Flame Wheel
Flamethrower
Chikorita Tackle
Razor Leaf
-4 0 6
Gastly - Togepi Metronome 0 -2 8
Gastly Shadow Ball Togepi Metronome +2 -2 10
Gastly Shadow Ball Togepi Shadow Ball +2 +1 13

Basic Switch AI

With the stage set, here is the routine for basic switch AI.

Basic Switch AI Examples

These examples are a little complicated. For the sake of simplification, all of the matchups will have a pre-calculated matchup score and only show a single option. Additionally, all options will assume to not proc the quarter mirrored shifting bug. It can be assumed that, if there were multiple valid options, the provided option is the best. Because mid-turn switch AI is deterministic, there is no need to worry about ties.

Player Pokemon Last Move Matchup Score AI Pokemon AI Moves Switch chance
Charmander - 9 Unown Hidden Power 0%
Charmander - 9 Chikorita Earthquake 0%
Charmander - 10 Phanpy Mud Slap 0%
Charmander - 9 Phanpy Mud Slap 20%
Charmander Scratch 9 Gastly Mud Slap 50%
Charmander Scratch 9 Gastly Shadow Ball 20%
Charmander Scratch 9 Gastly Confuse Ray 0%

Random Switch AI

Random AI brings with it more confusing behaviors. First, the AI looks for a pokemon to switch to which is immune to the last attack the player used. If present, the first pokemon in party order is sent out with a good (50%) chance. If Random AI does not do this, it falls back to switching to the AI's generic switch target with an unlikely (20%) chance.

This AI routine has a unique bug, however. For all previous routines, it was left unstated that the pokemon that is currently out is not a valid switch target. That is not the case for random switch AI's immunity check. Instead, it dismisses the pokemon before the currently out pokemon, in party order. This means both that an incorrect pokemon gets dismissed, but also that a pokemon can switch into itself in the right scenarios. The game does handle this and treats it as the AI's turn.

Perish Song AI

Perish Song AI is a delight. If the AI has a preferred generic switch target, then the AI will switch to that with a great (80%) chance. Otherwise, the AI will pick the first alive pokemon and switch to that with a great (80%) chance.

However, there is a crucial detail unmentioned. Perish Song AI only triggers if, when switch AI is run, the enemy's perish counter is at 1. Unluckily for the AI, post-turn effects like decrementing perish counters occurs after scoring the next turn's switch. What this means is while the AI is completely capable of recognizing when it is in lethal danger of Perish Song, due to the order of operations, it'll realize it should probably switch out and then immediately faint. So, in practice, this AI routine does nothing.

AI Conclusion

Trainer AI in CK+ is highly broken. This may be an understatement. Despite this, you could fix the largest problems with a single line at the start of Aggressive AI (jumping to the Boom Aggressive routine) and a semicolon at the start of a line in the Aggressive discourage phase (commenting out a jump that misaligns variables).

This page's Smart AI section is incomplete. I'd like to include more information in this post in the future.

Hopefully you fall into one of the categories below.

Fate permitting, games like CK+ will continue being released with a bunch of broken mechanics and quirks to be investigated. Until then.