Hacking Final Fantasy 1 on the NES
Jeff DeWall 9 min read March 19, 2017 #RetroGaming #HackingA 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.
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:
Address | Character Data |
---|---|
0x6100 - 0x613f | 1st character |
0x6140 - 0x617f | 2nd character |
0x6180 - 0x61bf | 3rd character |
0x61c0 - 0x61ff | 4th character |
Some interesting locations within a character block:
Address | Attribute |
---|---|
0x0 | character type |
0x1 | character alive state (0: alive, 1:dead) |
0x2 - 0x5 | character name (using PPU tile indices) |
0x7 - 0x9 | experience points |
0xa - 0xb | current hit points |
0xc - 0xd | max hit points |
0x10 - 0x14 | Str, Agl, Int, Vit, Luck |
0x20 - 0x23 | Damage, 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:
Address | Character Magic Data |
---|---|
0x6300 - 0x632f | 1st character |
0x6340 - 0x636f | 2nd character |
0x6380 - 0x63af | 3rd character |
0x63c0 - 0x63ef | 4th 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:
And the white wizard's magic table in-game looks like:
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 Code | Weapon | Hex Code | Weapon |
---|---|---|---|
00 | Nothing | 15 | Ice Sword |
01 | Wooden Nunchucks | 16 | Dragon sword |
02 | Small dagger | 17 | Giant sword |
03 | Wooden staff | 18 | Sun Sword |
04 | Rapier | 19 | Coral sword |
05 | Iron Hammer | 1a | Were Sword |
06 | Short Sword | 1b | Rune sword |
07 | Hand Axe | 1c | Power staff |
08 | Scimatar | 1d | Light Axe |
09 | Iron Nunchucks | 1e | Heal staff |
0a | Large Knfie | 1f | Mage staff |
0b | Iron Staff | 20 | Defense ? |
0c | Sabre | 21 | Wizard staff |
0d | Long Sword | 22 | Vorpal |
0e | Great Axe | 23 | CatClaw |
0f | Falchon | 24 | Thor Hammer |
10 | Silver dagger | 25 | Bane Sword |
11 | Silver Sword | 26 | Katana |
12 | Silver Hammer | 27 | XCalber |
13 | Silver Axe | 28 | Masmune |
14 | Flame sword |
Armor List
Hex Value | Armor | Hex Value | Armor |
---|---|---|---|
01 | Cloth | 15 | Ice shield |
02 | Wooden Armor | 16 | Opal shield |
03 | Chain Armor | 17 | Aegis Shield |
04 | Iron Armor | 18 | Buckler |
05 | Steel Armor | 19 | ProCape |
06 | Silver Armor | 1a | Cap |
07 | Flame Armor | 1b | Wooden helmet |
08 | Ice Armor | 1c | Iron helmet |
09 | Opal Armor | 1d | Silver helmet |
0A | Dragon Armor | 1e | Opal helmet |
0b | Copper ring | 1f | Heal helmet |
0c | Silver ring | 20 | Ribbon |
0d | Gold ring | 21 | Gloves |
0e | Opal Ring | 22 | Copper bracer |
0f | White Shirt | 23 | Iron bracer |
10 | Black shirt | 24 | Silver bracer |
11 | Wooden shield | 25 | Zeus bracer |
12 | Iron shield | 26 | Power bracer |
13 | Silver shield | 27 | Opal bracer |
14 | Flame shield | 28 | ProRing |
Playing around with the values, I ended up with weapons like:
and my armor setup looked like this, although I wasn't trying to find the best setup:
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!