Hacking Final Fantasy 1 on the NES

Jeff DeWall 9 min read March 19, 2017 #RetroGaming #Hacking

A few years ago I was inspired to hack around on some of my old favorite NES games after watching the video from Double Fine where the developer Brandon Dillon hacks around on the original Legend of Zelda. You can watch the video here.

I decided I wanted to hack Final Fantasy 1, one of my favorite games growing up, that I put in more than 100 hours playing. I used fceux as my NES emulator, same as in the video and followed mostly the same patterns.

I kept some notes on how I did it and thought others might find the process as interesting and fun as I did. I ended up losing most of the notes from a few years ago, so I went back and rediscovered the different memory locations and values to use again.

I searched in the RAM Search window for values, particularly as something in-game would change, such as when you buy a weapon or a spell, in order to track down the correct memory locations. Then I would use the Hex Editor tool to look at the NES RAM and try poking different locations.

Note that values that need more than one byte are stored little-endian, so the lower byte shows up first in memory.

Character Data and Stats

The character data is organized into four blocks, once for each character, one after the other starting at 0x6100. I was able to find this by searching for my character's names in RAM. The trick is finding the value associated with the letters, which you can do by looking at the PPU memory and determining what tile goes to what letter.

ff1_hack_ppu

You can see that a capital 'A' is mapped to 0x8A. I named my first character 'AAAA' so searching through the Hex Editor in FCEUX for the hex "8a8a8a8a" brings us right to the first character's block of data:

Character Name in Hex Editor
AddressCharacter Data
0x6100 - 0x613f1st character
0x6140 - 0x617f2nd character
0x6180 - 0x61bf3rd character
0x61c0 - 0x61ff4th character

Some interesting locations within a character block:

AddressAttribute
0x0character type
0x1character alive state (0: alive, 1:dead)
0x2 - 0x5character name (using PPU tile indices)
0x7 - 0x9experience points
0xa - 0xbcurrent hit points
0xc - 0xdmax hit points
0x10 - 0x14Str, Agl, Int, Vit, Luck
0x20 - 0x23Damage, Hit%, Absorb, Evade %

I found many of the above locations by looking at the Stats section for a character and then looking for the hex converted values within the block. For instance, looking for my first character's Str and Agl of 20, and 5 was a matter of looking for the hex values 14, 05 and finding them on the second line of the data block. Then I messed with the values and saw what changed.

When you start the game, you characters are child versions of their classes: fighter, black mage, etc. Later in the game, after you get the Rat's Tail, they become adults: knight, black wizard etc. You can increase the character's type value by 6 (the total number of character classes), and they will change to their adult version right away.

Magic

What magic spells a character has, and the current/max number of spells per level are stored in blocks for each character starting at 0x6300:

AddressCharacter Magic Data
0x6300 - 0x632f1st character
0x6340 - 0x636f2nd character
0x6380 - 0x63af3rd character
0x63c0 - 0x63ef4th character

The first 32 bytes are what spells the character has for each level. Each level gets 4 bytes, with the first 3 being the spell in that level's slot, and the 4th byte being 0. White spells for a level are numbered 0-4 and black spells are 5-8.

The last 16 bytes within the block are 2 bytes for each level, with the first byte being the current number of casts left for the level, with the 2nd byte being the max.

Here you can see a white wizard that I've given the first 3 spells of each level to (the repeating 01 02 03) and that has 9 / 9 casts for each level:

Character Magic Data in Hex Editor

And the white wizard's magic table in-game looks like:

Character Magic Table in Game

White Magic Spell table

| 1 | 2 | 3 | 4 --- | --- | --- | --- | --- Lvl 1 | cure | harm | fog | ruse Lvl 2 | lamp | mute | alit | invs Lvl 3 | cur2 | hrm2 | afir | heal Lvl 4 | pure | fear | aice | amut Lvl 5 | cur3 | life | hrm3 | hel2 Lvl 6 | soft | exit | fog2 | inv2 Lvl 7 | cur4 | hrm4 | arub | hel3 Lvl 8 | lif2 | fade | wall | xfer

Black Magic Spell table

| 5 | 6 | 7 | 8 --- | --- | --- | --- | --- Lvl 1 | fire | slep | lcok | lit Lvl 2 | ice | dark | tmpr | slow Lvl 3 | fir2 | hold | lit2 | lok2 Lvl 4 | slp2 | fast | conf | ice2 Lvl 5 | fir3 | bane | warp | slo2 Lvl 6 | lit3 | rub | qake | stun Lvl 7 | ice3 | brak | sabr | blnd Lvl 8 | nuke | stop | zap! | xxxx

Weapons and Armor

By buying a rapier and then equipping/unequipping I found the equip memory to be at 0x0300, there are 16 bytes available, matching the 4 slots for each character. Each weapon and armor has a number and to be equipped is a matter of setting the highest bit. For example, if the rapier is 04, then 84 means an equipped rapier.

Interestingly, the memory seems to be used for the equip menu, and is mirrored at 0x0b00, 0x1300, and 0x1b00 as well. This same memory is used when equipping armor, so you can set the values while equipping, and they will stick when you leave the menu.

Weapons List

Hex CodeWeaponHex CodeWeapon
00Nothing15Ice Sword
01Wooden Nunchucks16Dragon sword
02Small dagger17Giant sword
03Wooden staff18Sun Sword
04Rapier19Coral sword
05Iron Hammer1aWere Sword
06Short Sword1bRune sword
07Hand Axe1cPower staff
08Scimatar1dLight Axe
09Iron Nunchucks1eHeal staff
0aLarge Knfie1fMage staff
0bIron Staff20Defense ?
0cSabre21Wizard staff
0dLong Sword22Vorpal
0eGreat Axe23CatClaw
0fFalchon24Thor Hammer
10Silver dagger25Bane Sword
11Silver Sword26Katana
12Silver Hammer27XCalber
13Silver Axe28Masmune
14Flame sword

Armor List

Hex ValueArmorHex ValueArmor
01Cloth15Ice shield
02Wooden Armor16Opal shield
03Chain Armor17Aegis Shield
04Iron Armor18Buckler
05Steel Armor19ProCape
06Silver Armor1aCap
07Flame Armor1bWooden helmet
08Ice Armor1cIron helmet
09Opal Armor1dSilver helmet
0ADragon Armor1eOpal helmet
0bCopper ring1fHeal helmet
0cSilver ring20Ribbon
0dGold ring21Gloves
0eOpal Ring22Copper bracer
0fWhite Shirt23Iron bracer
10Black shirt24Silver bracer
11Wooden shield25Zeus bracer
12Iron shield26Power bracer
13Silver shield27Opal bracer
14Flame shield28ProRing

Playing around with the values, I ended up with weapons like:

Weapons in Game

and my armor setup looked like this, although I wasn't trying to find the best setup:

Armor in Game

Other Misc Game Data

I ended up finding some general game data by searching for the gold amount of my party. Gold is stored in at least 3 bytes at 0x601c - 0x601e (highest byte is 601e). Setting the value above 0x0F423F (999,999) will cause you to have more gold when buying items, but sometimes the display value can be messed up and display some random letters like 999,9N2. I didn't dig much more into this as having more gold wasn't necessary.

Memory location 0x6016, when changed to non-zero, triggers the cut scene when the heroes first cross the bridge after defeating Garland.

By writing 1's to the values in the generic game data block. I narrowed down the light orb booleans to the addresses: 0x6032-0x6035. A zero means the orb has not yet been obtained, and any other values shows the orb as shining.

The character's world position: 0x0027 xpos, 0x0028 ypos. You can teleport the player around by changing these values. If you do so the map doesn't update automatically, but you'll see the new location tiles scroll in as you start to walk around or you can do a screen refresh by going into the party menu and then leaving.

If you teleport onto a location, like a mountain or water, you'll be stuck, but then you just need to teleport yourself by changing the world position some more.

I wanted to find the airship right away, so I looked at a map online of FF1 and guesstimated where the world pos should be. I teleported myself in the desert where the airship is, placing myself nearby at 0xD1, 0xE5 for the x and y coordinates respectively.

Then looking back at the general game data block at 0x6000, I noticed a pair of coordinates DD, ED at 0x6005-0x6006 that looked like they could belong to the airship world position. So I tried setting the values around that to 1 to see if that would enable to the airship and setting the byte just before, which was 0, to 1, caused it to increment to 1f and the airship to appear at 0xDD, 0xED.

In a new game, you could simply move the airship to your world position and enable it and it will appear right next to you.

Wrapping up

This was a fun way to spend a few hours on a rainy Saturday revisiting one of my favorite games from my youth without investing as many hours playing. It does make me feel a bit less inclined to play old RPGs now, knowing that I'm grinding just to increase a few bytes of memory.

I hope you've found this interesting and try hacking around on an old game from your past and share the details. Happy hacking!