Resources for a deep dive into the FE7/FE8 Enemy Control Glitch?

Edit: A very detailed breakdown was posted below that describes some of the internals of this.

On a whim I decided to pick up FE8 again after a solid decade+ of the cartridge sitting in my closet as I have a friend who is interested in doing a playthrough. Way back when I had last played (late 2000’s/early 2010’s), the enemy control glitch was already pretty well known, but there were a bunch of other claims on various forums that were never proven. For example:

  1. “You can do enemy control without a PWASE; it is just frame perfect and difficult to do.'“
  2. “There is a method to do it with Phantoms instead of a PWASE.”
  3. “You can perform the glitch on the last chapter to grab Wretched Air and Naglfar.”

Back in the day I wrote all of these off as people trying to get attention, so imagine my surprise a year or two ago when I stumbled across a YouTube video that described the top-left tile of a map could be converted into a PWASE if some other tile is changed.

This was pretty wild to me to see one of these childhood rumors come to life, and it got me thinking: what is actually going on under the hood? And more importantly, were the other rumors actually true as well? Perhaps there was some other roundabout way to recreate the same set of circumstances to corrupt turn order - how would that work? Given how much time had elapsed, I figured this would already be science’d to death and back, however I haven’t found a deep dive into the assembly that explains why this happens.

For fun I grabbed FEBuilder and and emulator to see if I could diagnose this myself, but then I realized it is probably better not to reinvent the wheel; I am sure there are others who could help move me from “blind research” to “hey look at these specific functions”. So with that in mind…does anyone know what is going on from a hardware perspective?

This is the obvious stuff. You can perform the enemy control glitch reliably if you:

  1. Have an enemy stand on a PWASE.
  2. Have the enemy attack you from that tile.
  3. Soft/hard reset the game right as their sprite changes from active to greyed out.
  4. When re-entering the game, control is passed back to the player, despite being the wrong team.

Given that this works on a hard reset, and you can remove the cartridge from the GBA entirely (glitch remains across power cycles), the corruption is entirely contained to the cartridge itself and must be stored in persistent Flash ROM or EEPROM at address at 0x0EXXXXXX (cartridge memory). Unfortunately, the Memory Viewer of Virtual Boy only goes to 0x09XXXXXX, so I haven’t found a convenient way to view it yet.

Unconfirmed/speculation on my part: I have heard from others that the reason this occurs is because FE8 has a slightly different way of handling maps with “traps”. When figuring out what to do next, it creates an array of pointers to various functions and then steps through that array, executing each function in order. If this is true, then I assume that the very last pointer in that array is aimed at the “return control to enemy” function, and by resetting the game we are interrupting the execution control before it has a chance to run everything in that list, so upon loading back into the game it defaults to player control.

Another option for us is simply: “Can we find some other way to create a very long to-do list for the game to work on, so that there is more time to interrupt the turn order?”

This all sounds good in theory, but I have no proof. But if this is true: is there another way we can corrupt/bypass that array? What mechanic is changing the top-left tile into a PWASE? Can we turn other tiles into a PWASE?

For example, there is a ROM patch that fixes the enemy control glitch by editing memory address 0x377A0 from value 0x0320 to 0x07E0. (For some reason I can’t link to the thread.) What does that address have to do with this process, and what do these specific values “fix”?

Any pointers (hah) would be greatly appreciated.

The enemy control glitch arises due to a bug in the suspend code here.

To quote @Sme’s excellent explanation on the Discord:

the value of SAVE_ID_SUSPEND is 3 , it does the same thing either way

the behavior when resuming from suspend is determined by this switch statement,

each of the functions here will go to a different part of the BMapMain proc; the value of SUSPEND_POINT_DURINGACTION is 1 and sends it to label 6 (link)

which, in order, draws the map, starts the bgm, fades in from black, and starts the player phase control proc at label 7 , which is the part that handles completing a unit’s action.

the reason that the enemy control glitch happens is that there is no check when resuming with gActionData.suspendPointType set to 1 for what phase it is and it always assumes player phase and gives the player control. This only occurs in the function PlayerPhase_PrepareAction , which is only run on player phase anyways, and in HandlePostActionTraps , which can be run on any phase.

The prerequisites for that function not ending before it makes the suspend save you can ECG off of are that the active unit has >0 HP, if the active unit has access to Canto but isn’t currently doing so their action was either waiting, combat, or using a staff, that they’re standing on a trap that isn’t a ballista, if they’re standing on a mine and are an assassin there’s room in their inventory to pick up the mine, and if they’re standing on a mine they aren’t a thief or rogue. If all of these conditions are fulfilled, it will make a suspend save with suspendPointType of 1

the set of things that count as traps for the purposes of these checks are tilechanges, ballistas, breakable terrain, fire traps, gas traps, light arrow traps, torch staff light sources, mines, unhatched gorgon eggs, and light runes; ballistas are specifically exempt from working though as previously mentioned

tilechange traps are unique in that they don’t actually do anything besides denote that a tilechange is active and as such most of the regular information like location on the map is just set to 0; in practice this means that if any tilechanges have been activated on the current map there’s always a trap at (0,0)

light arrow traps are also set at a single location and applied to the column that location is in and iirc the point the actual trap sits at is never accessible on any maps that they’re used

2 Likes

Oh that is exactly the kind of breakdown I was looking for! That’s super interesting. Thanks for pasting that here; I’m not on any FE Discord servers and I doubt I would have found it otherwise. I’ll update my first post to reflect that info.