Final Fantasy IV Technical Documentation¶
Introduction¶
This project attempts to document the technical workings of Final Fantasy IV, which was originally relased in the United States as Final Fantasy II. At this time, the focus is on the US release Rev A (or 1.1). Eventually, however, the goal is to document all SNES or SFC versions, and the differences among them.
The information in this documentation comes primarily from two sources:
- Analysis of the disassembled code from the ROM itself.
- Observation of how things operate using a debugger.
Some well-known trivial information may be included as well to the extent that it is not contradicted by either of the two previous sources. In contrast, anecdotes, statistical sampling, or other published technical documentation are not used as sources, though they may be used for confirmation or indications of areas that merit further research.
Ultimately, I want this to be the most accurate resource regarding the inner workings of Final Fantasy IV. Incomplete information is acceptable, but incorrect information is not. If you do find any errors, please contact the author. Please be prepared to back up any non-trivial corrections with either your own code analysis or other compelling evidence.
Conventions¶
Numbers¶
Unless otherwise specified, all numbers are decimal. Hexadecimal numbers are prefixed with a dollar sign: $. Binary numbers are prefixed with a percent sign: %.
Bits within a byte (or double byte, etc.) are numbered starting from the least significant bit, which is numbered zero. The highest bit in a byte, therefore, is numbered 7. The remaining bits are numbered according to that pattern. The correct value for a byte wherein a single bit is set can be determined by the formula \(2^x\) where \(x\) is the bit number. (For example, \(2^0 = 1 = \$01\) and \(2^7 = 128 = \$80\).
Addresses¶
All addresses are given as if they were being accessed on the SNES system bus. Full 24-bit addresses are given as $BB:XXXX where BB is the bank and XXXX is the address within that bank.
When accessing an actual ROM image outside of an SNES system, these addresses should be converted according to the following formula:
(bank * $10000) // 2 + (address - $8000)
If for whatever reason, the ROM is headered, an additional $200 bytes should be added for the header.
For example, $12:8200 corresponds to $090200 in an unheadered ROM image and $13:EF00 corresponds to $09EF00.
Unless otherwise specified, all addresses refer to USA Rev 1. This is important when discussing changes between versions, where offsets have shifted.
Data Structures¶
This chapter details the various data structures used by the game.
Events¶
Caution
This section is a draft based on current reverse engineering work. Some of the information may be inaccurate or incomplete.
The game uses a simple virtual machine for scripting event sequences. The data discovered for this so far exists in bank 12 ($12:XXXX on the system bus). There are 256 event numbers. $12:8000 to $12:8200 is a series of 256 2-byte indexes. These indexes subsequently indicate the beginning of each event’s script in the data array extending from $12:8200 to $12:EFFF. The event commands have variable lengths depending on the nature of the command.
$FA: Play Song¶
Bytes: | 2 |
---|---|
Parameter 1: | Desired track number. |
This instruction causes to play the song identified by the given track number.
$FE: Warp to Map¶
Bytes: | ? |
---|---|
Parameter 1: | Target map ID. |
Parameter 2: | %DDXXXXXX where DD is the target direction and XXXXXX is the target X coordinate. |
Parameter 3: | Target Y coordinate. |
Parameter 4: | %P??????? where P is the target map plane. |
Map IDs from $00 to $FA act as expected and transport the player to that map. Maps $FB to $FF have special behavior:
$FF: End Event¶
Bytes: | 1 |
---|
This instruction ends the event. It automatically makes sure the visible player field sprite corresponds with the active character.
Character Records¶
Character records are stored in two separate areas in RAM. The first set is made up of five 64-byte records located at $7E1000. The second set of is five 128-byte records located at $7E2000. The second set of records is used in-battle and is a strict superset of the first set. The individual bytes can be interpreted as follows:
$00: Character Byte 1¶
Bitmask: | %RL?CCCCC |
---|---|
R: | Right-hand weapons |
L: | Left-hand weapons |
C: | Character ID |
The lowest five bits define the character ID. Therefore, the game supports up to \(2^5\) or 32 unique character IDs. One of these is reserved for indicating an empty slot. Each instance of a character has its own ID. (For example, Kain leaves the party and rejoins twice. All three instances of Kain have a separate ID. The values used in game are as follows:
ID | Character |
---|---|
$00 | <empty slot> |
$01 | Cecil (dark knight) |
$02 | Kain (until Mist) |
$03 | Rydia (child) |
$04 | Tellah (until Damcyan) |
$05 | Edward (until Leviatan) |
$06 | Rosa (until Fabul) |
$07 | Yang (until Leviatan) |
$08 | Palom |
$09 | Porom |
$0A | Tellah (until Cecil becomes a Paladin) |
$0B | Cecil (paladin) |
$0C | Tellah (until Tower of Zot cutscene) |
$0D | Yang (until Super Cannon) |
$0E | Cid |
$0F | Kain (until Sealed Cave) |
$10 | Rosa (final) |
$11 | Rydia (adult) |
$12 | Edge |
$13 | FuSoYa |
$14 | Kain (final) |
$15 | Golbez |
$16 | Anna |
The two highest bits determine the character’s handedness. If the uppermost bit is set, the character can equip weapons on their right hand, and if the second highest bit is set, they can equip weapons on their left hand.
The remaining bit’s function is currently unknown.
$01: Character Byte 2¶
Bitmask: | %B?L?SSSS |
---|---|
B: | Back row |
L: | Long range |
S: | Sprite/Class |
The lowest four bits determine the sprite and class of the character. These two properties are inextricably tied together and are defined using one value. The known values are as follows:
ID | Sprite | Class |
---|---|---|
$00 | Cecil (dark knight) | DKnight |
$01 | Kain | Dragoon |
$02 | Rydia (child) | Caller |
$03 | Tellah | Sage |
$04 | Edward | Bard |
$05 | Rosa | Wh.Wiz |
$06 | Yang | Karate |
$07 | Palom | Bl.Wiz |
$08 | Porom | Wh.Wiz |
$09 | Cecil (paladin) | Paladin |
$0A | Cid | Chief |
$0B | Rydia (adult) | Caller |
$0C | Edge | Ninja |
$0D | FuSoYa | Lunar |
$0E | *Various | <garbage> |
$0F | *Golbez | <garbage> |
$0E appears to be garbage data and is not actually used in the game. The portrait is that of a solid black pig, the overworld sprite is a mini and the in-battle sprite is a green pig. $0F provides an in-battle sprite of Golbez, but the rest of the data is not usefully defined.
Bit 5 is the so-called long range bit, which determines whether or not the character is capable of performing long range attacks without having their accuracy reduced. This bit is especially notable because the game has a bug that results in this bit never being reset. In other words, once a character equips a back row weapon (and the game is given an opportunity to recalculate stats), the character will retain that status forever.
Bit 7 is the back row bit and is set when the character is in the back row and unset when the character is in the front row. This does not affect the display of party members and appears to be used only for calculations.
The functions of the remaining two bits are currently unknown.
$03-$06: Status¶
Bitmask: | %SSSSSSSS %SSSSSSSS %SSSSSSSS %SSSSSSSS |
---|---|
S: | Status effects |
These bytes encode the following status effects:
Byte | Bit | Hex | Binary | In-Game | Description |
---|---|---|---|---|---|
$03 | 7 | $80 | %10000000 | Swoon | Swoon/Death |
$03 | 6 | $40 | %01000000 | Stone | Stone |
$03 | 5 | $20 | %00100000 | Toad | Toad |
$03 | 4 | $10 | %00010000 | Small | Small/Mini |
$03 | 3 | $08 | %00001000 | Pig | Pig |
$03 | 2 | $04 | %00000100 | Mute | Mute/Silence |
$03 | 1 | $02 | %00000010 | Darkness | Darkness/Blindness |
$03 | 0 | $01 | %00000001 | Poison | Poison |
Byte | Bit | Hex | Binary | In-Game | Description |
---|---|---|---|---|---|
$04 | 7 | $80 | %10000000 | Curse | Curse |
$04 | 6 | $40 | %01000000 | Float | Float |
$04 | 5 | $20 | %00100000 | Paralyze | Paralysis |
$04 | 4 | $10 | %00010000 | Sleep | Sleep |
$04 | 3 | $08 | %00001000 | Charm | Charm/Confuse |
$04 | 2 | $04 | %00000100 | Berserk | Berserk |
$04 | 1 | $02 | %00000010 | Petrify | Gradual petrification (2/3) |
$04 | 0 | $01 | %00000001 | D | Gradual petrification (1/3) |
Byte | Bit | Hex | Binary | In-Game | Description |
---|---|---|---|---|---|
$05 | 7 | $80 | %10000000 | D | Magnetized |
$05 | 6 | $40 | %01000000 | Stop | Stop |
$05 | 5 | $20 | %00100000 | <unknown> | |
$05 | 4 | $10 | %00010000 | <unknown> | |
$05 | 3 | $08 | %00001000 | <unknown> | |
$05 | 2 | $04 | %00000100 | <unknown> | |
$05 | 1 | $02 | %00000010 | <unknown> | |
$05 | 0 | $01 | %00000001 | Count | Count/Doom |
Byte | Bit | Hex | Binary | In-Game | Description |
---|---|---|---|---|---|
$06 | 7 | $80 | %10000000 | <unknown> | |
$06 | 6 | $40 | %01000000 | <unknown> | |
$06 | 5 | $20 | %00100000 | Wall | Wall/Reflect |
$06 | 4 | $10 | %00010000 | Barrier | Barrier |
$06 | 3 | $08 | %00001000 | Image (two hits) | |
$06 | 2 | $04 | %00000100 | Image (one hit) | |
$06 | 1 | $02 | %00000010 | <unknown> | |
$06 | 0 | $01 | %00000001 | HP Critical |
$07-$08: Current HP¶
These two bytes contain the character’s current HP, encoded in low-endian format. (In other words, the first byte is the low byte and the second byte is the high byte.
$09-$0A: Maximum HP¶
These two bytes contain the chracter’s maximum HP, encoded in low-endian format.
$0B-$0C: Current MP¶
These two bytes contain the character’s current MP, encoded in low-endian format.
$0D-$0E: Maximum MP¶
These two bytes contain the character’s maximum MP, encoded in low-endian format.
$0F: Base Strength¶
The character’s base strength.
$10: Base Agility¶
The character’s base agility.
$11: Base Vitality¶
The character’s base vitality.
$12: Base Wisdom¶
The character’s base wisdom.
$13: Base Will¶
The character’s base will.
$14: Strength¶
The character’s base strength plus any bonuses from their equipment. If the value is $B6 or greater (essentially -74 to -1, as this is signed), the value is replaced with 1. This almost sets up a lower bound for the stat at 1, but 0 itself is allowed to pass through.
The upper bound is set to 99.
$15: Agility¶
(calculated the same as strength)
$16: Vitality¶
(calculated the same as strength)
$17: Wisdom¶
(calculated the same as strength)
$18: Will¶
(calculated the same as strength)
$19: Elemental Attack¶
These are the elements associated with the character’s physical attack. It is set as the union of the attack elements of their weapons.
$1A: Racial Attack¶
The character’s physical attack will do extra damage against the races indicated in this variable. It is determined by the union of the race property of each of their weapons.
$1B: Physical Attack Multiplier¶
This is calculated with the following formula:
strength // 8 + agility // 16 + 1
$1C: Physical Attack Accuracy¶
There are a number of ways this might be calculated, depending on what the character has equipped:
- No Weapons
- 50 + level // 4
- One Weapon or Bow+Arrow
- (weapon or bow accuracy) + level // 4
- Two Weapons
- (level // 4 + level // 4 + sum(weapon accuracies)) // 2
If only a bow or only an arrow is equipped, they are ignored.
This value is capped at 99.
$1D: Physical Attack Base¶
Like with accuracy, there are a few possibilities:
- Yang (specifically class is Karate)
- level * 2 + strength // 4 + 2
- Bow+Arrow
- bow_power // 2 + arrow_power + strength // 4
- No Weapon
- level // 4 + strength // 4
- One Weapon
- level // 4 + strength // 4 + weapon_power
- Two Weapons
- (level // 4 + strength // 4) * 2 + sum(weapon powers)
If the player has a bow and arrow equipped and the bow is in the primary hand, then the value is modified as follows:
value = value - (value // 5)
If only a bow or only an arrow is equipped, it is treated as a single weapon with a power of 1.
This value is capped at 255.
$1E-$1F: Physical Attack Status¶
This determines the status that physical attacks potentially carry. It is set to the union of the status property of the character’s weapons.
$20: Elemental Weakness¶
This byte controls the elements the character is weak to. This is set by taking the opposite of the elements they are resistant to. The only pairs of opposite elements are fire/ice and holy/darkness. Lightning and the pseudo-elements do not have opposites.
For example, if the character resists fire and holy, they will have a weakness to ice and darkness.
$21: Elemental Strong Weakness¶
This byte determines which elements the character is strongly weak too. This results in double the damage, versus a regular weakness. This value is set as the opposite of any elemental immunities the character has.
This property is bugged. Once it is set, it will never be unset as the game has no code to do so. Immunities and resistances take precedence over weaknesses in general, so as long as that armor is equipped, there will be no problem. However, once the character removes the equipment that gave the immunity, they will retain a permanent strong weakness unless they re-equip the armor.
$22: Magical Defense Multiplier¶
This is calculated using the following formula:
(wisdom + will) // 32 + (agility // 32)
$23: Magical Defense Evasion¶
This is calculated using the following formula:
(wisdom + will) // 8 + sum(equipment magic evasion)
This is capped at 99.
$24: Magical Defense Base¶
This is calculated as the sum of the magical defense of the character’s equipment.
It is capped at 255.
$25: Elemental Resistance¶
The character resists these elements and takes reduced damage. This is calculated by combining any resistances from all equipped equipment.
$26: Elemental Immunity¶
The character is completely immune to these elements. This is calculated by combining any immunities from all equipped equipment.
$27: Race Resistance¶
The character will take reduced damage from attacks by the races encoded in this byte. Again, this is calculated by combining any race resistance properties from the character’s equipment.
$28: Physical Defense Multiplier¶
This is calculated according to the following formula:
\(\left \lfloor \frac{level}{16} \right \rfloor \cdot shields + \left \lfloor \frac{agility}{8} \right \rfloor\)
$29: Physical Defense Evasion¶
This is set to the sum of the physical evade values of all the character’s equipment. An empty armor slot is considered to have an evade of 10. An empty hand does not confer this bonus.
This value is capped at 99.
$2A: Physical Defense Base¶
This is calculated as the sum of the physical defense of all the character’s equipment, plus half their vitality.
This value is capped at 255.
$2B-$2C: Status Immunity¶
These two bytes determine which statuses the character is immune to. It is determined by combining the status immunities of all the character’s equipment.
$2D: Critical Rate¶
This is the rate at which a character does critical hits. It is derived from the character’s base critical rate as follows:
- No Weapon or Two Weapons
- Set to base_critical_rate
- One Weapon
- base_critical_rate * 2
- Bow+Arrow
- base_critical_rate * 3
This value is mostly capped at 99. Technically, in the single weapon case, it is only capped if the base value is 128 or greater.
This value and the next value are an exception to the records at $2000 being a strict superset of the records at $1000. In particular, these values in the records at $1000 are always the base values. The derived values are only stored in the in-battle records at $2000.
$2E: Critical Bonus¶
This is a bonus applied to critical hits. It is derived from the character’s base critical bonus as follows:
- Bow+Arrow
- base_critical_bonus + arrow_power
- One Weapon
- base_critical_bonus + weapon_power // 2
- Two Weapons or No Weapon
- base_critical_bonus
This value is capped at 255.
Graphics¶
This chapter discusses the location and formats of the various forms of graphical data used in the game.
Field Sprites¶
Field sprites are those used on the field. In particular, they are generally used to display the player and the NPCs.
Player¶
The field sprites for party members are made up of several components. First, the actual graphical data is stored in $300 byte arrays at $1B:8000. Each sheet is composed of 32 8x8 tiles. The data is stored with 3 bits per pixel.
These sheets are composed into 16 different frames using the OAM flags stored at $15:C0C4. Each frame has eight bytes of data, where the even bytes are the tile numbers for the upper left, upper right, lower left and lower right component tiles, respectively, and the odd bytes are the tile flags for the same tiles. In the default data, the flags are used to set the horizontal flip bit if appropriate and to set the priority for each tile to 2.
The coordinates for the four tiles of the player sprite are determined by the data at $15:C0B4, which consists of four bytes per tile (corresponding to the full OAM entry). Only the X and Y coordinates are set, with both the flags and tile bytes being set to zero. Note that the base coordinates for the player sprite are 112, 109, which is neither centered nor exactly aligned with a tile boundary. In addition, on the second frame of horizontal movement, the Y coordinate is reduced further by one.
The palette for each class’s sprite is stored in the array at $15:B2FA. Each class receives one byte, which determines which of the four player sprite palettes to use.
The palettes themselves are stored at $0D:8000, which consists of four separate eight color palettes, with each palette potentially being shared by multiple characters (only the paladin Cecil palette is unique).
Title Screen¶
The title screen is a simple static image displayed at the start of the game. Do note that the title screen in the original Japanese release has some form of animation. That is not currently documented here.
Tiles¶
The title screen tile data is stored with 4 bits per pixel at $08:C000. There is room for 256 tiles, though not all 256 are used in this release.
Tilemap¶
A standard SNES tilemap is stored in the 2048 bytes starting at $08:E000. The data is sufficient to render a 256x256 image.
Palette¶
The eight 16-color palettes used by the screen are stored at $08:E800.
Outdoor Maps¶
Outdoor maps are composed from a set of 128 16x16 composed tiles, each created by drawing from a pool of 256 8x8 base tiles.
Base Tiles¶
The outdoor maps are implemented via mode 7, so each pixel is represented by a single byte, which directly indexes the palette data in CG-RAM.
Each 8x8 tile uses a single 16-color palette, with the upper four bits of each pixel in that tile determined by the data in the following table, where each 8x8 tile is one byte (even though only the upper four bits are used):
Map | Address |
---|---|
Overworld | $14:8600 |
Underworld | $14:8700 |
Moon | $14:8800 |
The lower four bits of each pixel’s value are loaded from a separate table:
Map | Address |
---|---|
Overworld | $1D:8000 |
Underworld | $1D:A000 |
Moon | $1D:C000 |
In this table, two pixels are defined per byte, with the first pixel of each pair using the lower four bits, and the second pixel using the upper four bits. These four bits are extracted, shifted to the correct location, and combined with the previously-specified bits for the tile to determine the final index into the palette.
The tables for the overworld and underworld are both 8192 bytes each, but the table for the moon is only 5056 bytes (158 tiles instead of 256).
The palette data itself is standard SNES palette data, loaded from the offset listed in the following table:
Map | Address |
---|---|
Overworld | $14:8900 |
Underworld | $14:8980 |
Moon | $14:8A00 |
Each palette consists of 128 bytes, making up 64 colors.
Composed Tiles¶
The 16x16 composed tiles are composed from the 8x8 tiles via the data in the following tables:
Map | Address |
---|---|
Overworld | $14:8000 |
Underworld | $14:8200 |
Moon | $14:8400 |
Each 512 byte block is actually composed of four separate 128-byte arrays. The four arrays, in order, specify the tiles to use in the upper left, upper right, lower left and lower right segments of the composed tile, in that order. In other words, the first 128 bytes determine the upper left tile for each of the 128 composed tiles, and so on.
Tilemaps¶
The tilemaps for the outdoor maps are stored in a slightly compressed form at the following addresses:
Map | Row Offsets | Compressed Tilemap |
---|---|---|
Overworld | $16:8000 | $16:8480 |
Underworld | $16:8200 | $16:C480 |
Moon | $16:8400 | $16:E180 |
The row offset data is a series of 16-bit offsets for each row of tiles, allowing one to index directly to a particular row (which allows the game to avoid loading all rows into memory at once, as that would be extremely expensive in terms of memory usage.
The actual compressed tilemap data is a mostly basic run-length encoding scheme. If the high bit of the value is not set, the value is directly copied to the tilemap, except potentially for the values of $00, $10, $20 and $30. In those cases, if the map is the overworld, a four byte sequence will instead be written. The first byte in the sequence is the specified value. The following three bytes are equal to $70 plus the value divided by 16 and multiplied by 3 plus either 0, 1 or 2.
If the high bit of the value is set, the low seven bits determine the tile number, and the following byte is the number of tiles to write minus one. (This allows a value of $FF, for instance, to encode a full row of 256 tiles.)
All tile numbers refer to the 16x16 composed tiles.
Each row of data in the compressed tilemap is additionally terminated with a single $FF.
Animation¶
There are two classes of animated outdoor tiles: ocean tiles and waterfall tiles. Both of these are animated in similar fashions, with custom code directly manipulating the tiles as stored in RAM.
For the ocean tiles, every other frame, a row selected based on a frame counter and the data table at $00:8E8C is rotated to the right, with each pixel moving once to the right, except for the final pixel, which is rotated back to the far left. Within the tiles, the ocean tiles make up tiles $80 through $83.
For the waterfall tiles, once per frame, a column selected via the frame counter and the data table at $00:8E7C is rotated downward, though the process is repeated so each pixel moves two spots per frame. The waterfall tiles range from $7A to $7D.
Versions¶
Over the course of development, several versions of the game were released. In terms of apparent code progression (but not release date), the different versions are:
- Japan
- Japan (Rev 1)
- USA
- USA (Rev 1)
- Japan (Easytype)
As such, this document will discuss the changes between versions in this order. Unless otherwise mentioned, assume a given version retains all changes made in previous versions (for example, the first USA release is based on the second Japanese release). The Japan (Easytype) release is something of a special case, but it will be discussed in more detail later. This list is not necessarily exhaustive, and some things may have been missed, primarily if they are changes to data, rather than code.
Japan¶
This is the originally released version of the game in Japan.
Japan (Rev 1)¶
This is the second and more common Japanese release.
Battle Scripts¶
A bug was fixed regarding underworld battle scripts. Previously, the scripts on the underworld map would be incorrect if the most recently visited dungeon map was in a certain ID range.
USA¶
This is the baseline USA release, often referred to as 1.0. Several changes were made from the Japanese releases. Some minor changes that were related to the translation process may not be listed here.
Title Screen¶
The title screen was changed, is no longer animated, and transparency effects were removed.
Text¶
Many changes were made to facilitate the translation of the game from Japanese to English. This is not necessarily an exhaustive list.
Support for the diacritic tile row above text (used for voiced kana) was largely replaced with a row of blank tiles instead. One of the instances of this is at $00:B2A8, and leads to a rare bug involving a blank text box when a fanfare is played by the dialog.
The legend display sequence saw minor coding changes.
Cycling between character sets in the Namingway screen was removed.
Support for dual-tile encoding was added. (The Japanese release had a very limited DTE for the two-tile ellipsis.)
Display of the first character of item names (the icon) was added to the field dialogs (including the item selection dialog).
The dialog opcodes handling the end of lines were changed slightly.
Battle Commands¶
Armor, Shell and Dispel are no longer added to Tellah at Mt.Ordeals.
Sylph¶
A bug with Sylph that caused it to incorrectly count the number of restored targets by only ever checking the middle character was fixed.
Some code that superfluously updated the HP of the restored characters was removed, but in the process, they accidentally added another bug that results in the spell only costing MP if Rydia is in the middle slot.
Miscellaneous¶
The ability to customize joypad configuration was removed.
The limited multiplayer support was removed. (The Japanese release allowed different characters to be controlled by different controllers in battle.) Which character used which controller was fully configurable.
The active/wait ATB mode selection was removed and wait was made the default. (However, the code to handle active mode was not removed.)
Outdoor trigger data was moved from bank $15 to bank $19.
When updating an inventory entry in battle (used at least when successfully sneaking an item), code was removed that previously set the dartable bit of the item.
The Warp color effect was changed slighty.
The statistics for various monsters were changed.
USA Rev 1¶
This is the second and seemingly less common USA release, often referred to as 1.1. There were several minor changes made to the game:
Command Delay¶
The delay for the Kick command was changed from the character’s relative speed to half their relative speed.
The delay for the “Release” command (the finishing counterpart of Yang’s Build Up command) was changed from twice his relative speed to his relative speed. Since the command is unavailable in the USA version, this change is effectively pointless.
The delay for the finishing part of the Twin command was changed from the relative speed to half the relative speed.
To summarize, Kick, Build Up, and Twin all had their respective delays halved.
Inventory¶
When entering battle, code was added to the routine at $03:8929 to reset the item ID and count in both the field and battle inventories to zero if the item count is zero.
The primary effect of this change is to prevent the player from being able to duplicate consumables using the out-of-battle technique that uses the treasure overflow screen. It does nothing, however, to prevent the more common method used in battle to duplicate weapons.
Twin Mimic Glitch¶
Code was added to the routine at $03:A3ED (which processes the menu queue) to reset the currently active slot to $FF if the current slot being processed is flagged as the “other” twin. This effectively prevents the mimic glitch as associated with Twin. Without this fix, during the next time through the loop, that slot will be processed as if it has queued an action, which will repeat the previous action.
This fix, however, does nothing to fix the Avenger mimic, which operates on a similar principle.
Stop¶
A line of code was removed from the routine at $03:D8EE (which handles the Stop spell effect) that originally reset the target’s action timer flags to zero. It is currently unknown what the impact of this change is.
Explode¶
Code was added to the Explode routine at $03:DD12 to cap the damage at 9999, even if the actor has more than 9999 HP.
Auto-Actions¶
A single byte was changed in the routine at $03:AAF2 (which queues automatic actions) to prevent the auto-actions from being queued if the slot has the jumping status.
Address Offset Changes¶
As a result of these changes, several offsets in the files changed. The offset changes are all confined to bank $03. The table of corresponding ranges is listed below (this table only documents changes that affect offsets–sections with only byte-for-byte changes are listed as similar):
USA | USA Rev 1 | Classification | Delta |
---|---|---|---|
$03:8000 - $03:8A85 | $03:8000 - $03:8A85 | Similar | 0 ($00) |
N/A | $03:8A86 - $03:8A8F | Added | N/A |
$03:8A86 - $03:A4A7 | $03:8A90 - $03:A4B1 | Similar | 10 ($0A) |
$03:A4A8 - $03:A4A9 | $03:A4B2 - $03:A4B9 | Changed | N/A |
$03:A4AA - $03:D906 | $03:A4BA - $03:D916 | Similar | 16 ($10) |
$03:D907 - $03:D909 | N/A | Removed | N/A |
$03:D90A - $03:DD0E | $03:D917 - $03:DD1B | Similar | 13 ($0D) |
N/A | $03:DD1C - $03:DD23 | Added | N/A |
$03:DD0F - $03:F26A | $03:DD24 - $03:F27F | Similar | 21 ($15) |
$03:F26B - $03:F27F | N/A | Removed ($FF) | N/A |
$03:F280 - $03:FFFF | $03:F280 - $03:FFFF | Similar | 0 ($00) |
Japan (Easytype)¶
This was the final version of the game released in Japan. While it was seemingly released before any of the USA versions, its codebase is clearly further along than even USA (Rev 1). You can generally assume that it is the same as USA (Rev 1), except regarding any text code (which is still based on the latest Japanese release), or other changes listed below.
NOTE: Some of the below code changes have not been fully analyzed for their implications in fixing bugs.
While the script and other text was based on the Japanese release, it was modified and simplified, presumably to be more accessible to the intended younger audience.
In the save/load menu, the check for the player pressing the B button occurs earlier in the loop.
A wait for vblank call was removed from the Namingway character selection screen.
Some dead code regarding custom joypad support was removed.
The item exchange screen added additional code to zero out the ID number of an item in the spoils inventory to avoid leaving a glitched entry.
Additional code was added at the end of battle to copy hand inventory back to the character records. The original version of the copying routine would zero out the item ID if the count was zero. The Easytype version was modified to instead zero out the count if the item ID was zero. This effectively fixes the item duplication glitch by preventing the player from leaving the battle with 1 or 255 nothings (item ID 0) in their hand.
ROM Map¶
This chapter provides a detailed map of the ROM layout, organized by bank.
Bank $00¶
Address | File Offset | Type | Name | Description |
---|---|---|---|---|
$00:8000.8301 | $000000.0301 | Code | main | First entry point for the game. |
Bank $14¶
Address | File Offset | Type | Name | Description |
---|---|---|---|---|
$14:8000.81FF | $0A0000.0A01FF | Data | outdoor_tile_composition_data | Tile composition data for the overworld. |