ROM Hacking – Battletoads

One of my preferred games as a kid was the NES version of Battletoads.  NES games are hard, but Battletoads was almost impossible. I remember I got pretty good at it, managed to get to level 10 or so. I thought I’d give it another chance, but this time over, I did not manage to get over level three. Since I barely have the time or the will to replay a game hundreds of times, I decided to get into ROM hacking, see if I can make my own cheats and finish the game.

While there are many emulators out there, it seems that the best tool if you are into ROM hacking/modding is . The nice twist is that the emulator can load Lua scripts that allow you to manipulate the game. You launch Fceux (via wine if not a Windows user), load the ROM and load your scripts. My “IDE” for the day looks like this:

Our dev env....png

Now, for the “Hello World” script:

while true do
 emu.message('Hello World!') 

The principle is pretty simple. The script is a while loop. You add your code, then call emu.frameadvance() to pass control to the emulator and render the next frame. The code above simply displays “Hello World” on the screen all the time:


Let’s do something interesting. ROM hacking is about finding where in the memory a value is stored (i.e. number of lifes)  and changing it. Here is someone hacking Mario:


This guy makes it look easy. The truth is that you can spend countless hours trying to look for a certain value. In the end, you have a memory address that you can change. For Battletoads, I got a bit lucky as someone already found some useful addresses –

So, to add infinite lives, it looks like I need to put in 05 in the 0011 address. My Lua cheat can simply be:

memory.writebyte(0x0011, 0x05)

That might work for a normal game, but Battletoads is incredibly hard. Having infinite lives is not enough. In most levels, when you die you restart from a checkpoint, having to redo part of the level, which can be very frustrating.

Another cheat caught my eye – invulnerability. Since I cannot be killed, I don’t have to restart from a checkpoint. Our lua script can now become:

-- infinte lives
memory.writebyte(0x0011, 0x05)
-- invulnerability
memory.writebyte(0x0574, 0x7E)

My joy was very short lived. About half way through level 1, I met one enemy that won’t attack me:

wont-go down

The flying monster won’t come down and is to high up to be hit, so I cannot progress further. I guess somewhere in the game logic this enemy does not attack you until it can see you. And since I am invulnerable, it cannot see me. What I need at this point is a way to enable/disable the invisibility/invulnerability. Pressing the “select” button would do, as I don’t use it for anything. Ended up with this hackish script:

--infinte lifes. Can be called once at the start
memory.writebyte(0x0011, 0x05)

invisibility_enabled = false
while true do
  jp =
  if( then
    invisibility_enabled = not invisibility_enabled

  if invisibility_enabled then
    memory.writebyte(0x0574, 0x7F)
    memory.writebyte(0x0574, 0x00) 



Roughly, for each game cycle I am checking whether the select button was pressed. If so, I toggle the invisibility. I also display it on the screen (as true/false) so I keep track of the status.

This got me over level 1 easily. However, I realised that being invincible breaks the game easily. You can fall over the edges of the level or end up in places you cannot get out of. I guess that’s the reward for cheating. You can of course restart the game, but playing again through a number of levels does not sound fun. Luckly, it looks like there is a cheat to start from a specific level. You just add the level number at the 8320 memory location. However, this one needs to be timed to happen somewhere between pressing start on the main screen and starting level 1. While I guess there is a way to do it in the Lua script, I discovered a quick solution via Game Genie. Game Genie was an interesting device, better explained here . Roughly, this device would stay between your NES console and the ROM cartridge, sniff on all communication, look for specific memory address and change the values on the fly, allowing you to do short modifications, like infinite lives.

Fceux also “emulates” Game Genie, allowing you to generate codes. At Debugger > Game Genie Decoder/Encoder, you can transform an address/value/cmp into a genie code. Still from , I was able to generate a genie code that would allow me to start from any level. It is a bit manual, i.e. I have to regen the code if I want a different level, but it works fine. Overall, the game genie is a lot simpler to use than the Lua scripts, but also a lot more limited.

With all this in place, I was able to have infinite lives, toggle invisibility and start the game from any level. However, even with all this in place, the game was still very hard. While some levels, like the cave or the hole were extremely easy, there were others, like the snake pit, where you had the same hardcore NES experience. Using the invisibility was impossible since every wrong turn would send you in an unplayable state. Not using it would result in restarting the game tens or hundreds of times from the same checkpoint. In the end, I decided to watch a YouTube speed run and concentrate on easier games.