XMAP Chapters [FE6]

What are XMAP Chapters?

XMAP is the name given to the system in FE6 by which a 6th trial map can be loaded from save data. This was used for 4 promotional trial maps released in limited quantities in official giveaways in June and July 2002, though as this is baked into the save file and none of the giveaway cartridges have surfaced in the years since the specifics of the promotional chapters are unknown; the most we know about them is what can be seen in this picture.

As it is unlikely an official chapter will surface to use as an example, a year or so in the making, I have reverse-engineered the system and present you with the structure of XMAP data such that you can create your own XMAP chapters.

Making an XMAP Chapter

The data for XMAP chapters goes in the save file at +0x7000 and is laid out as follows:

The very first word of the header is always 0x50414D58 - the ASCII string β€œXMAP”, and the namesake of this system.

Next comes a checksum but because of how it works it can easily be circumvented by setting the next short as 0x0002 and the following as 0x0223; the first short tells how big the data to get the checksum of is, and the second short is the value to compare the calculated checksum to. Because the very next short is is where it starts counting from and it is always the same value, by setting the length to 2 bytes the correct checksum becomes the constant value immediately following the checksum.

The next short, as alluded to before, is also always the value 0x0223.

The next byte is always 0x02.

The next byte is the language setting. Because this is FE6, the language is always going to be 0 for japanese; the language is set to 1 for english games.

The next word is always 0x00000000.

Everything up to this point is going to be identical regardless of any further data included; it should look like so in a hex editor:

58 4D 41 50 02 00 23 02 23 02 02 00 00 00 00 00

Now’s when the fun part starts: space management. I’ll explain what these all are now, but we’ll come back to actually putting values here later because they can vary.
The next word is a relative pointer to compressed map data. Note that by relative pointer, here that means distance from the beginning of the header; it gets 0x7000 added to it so you don’t need to include that here. Compressed map data is identical to how it is in the ROM, and any existing map tool can produce it for you (e.g. tmx2ea outputs it as the _data.dmp file).
The next 2 shorts are data lengths: before the game decompresses each of the two pieces of compressed data that are included in the save file, it first copies them into RAM. In order to do this, it needs to know how long each is when copying it. The first short is the length of the compressed map data, and the second short is the length of the compressed pointer data.
The next word is a relative pointer to compressed pointer data; we’ll cover what this is when we get to it in a bit.

This ends the header data, and the rest of the data has no fixed offset to be included at which means doing some math to figure out where they are for the header.

The first valid offset for this data is at +0x20. The order doesn’t really matter, but for the sake of this explanation we’ll start with the compressed map data, which means the relative offset for it is going to be 0x20. Set the relative offset in the header and map data is done.

Next we’ll handle the compressed pointer data. This contains 5 fixed pointers (and unused room for a 6th) to various components. Because they are fixed pointers you can have them point to ROM if you want to, but they’re perfectly valid being in SRAM. Note that to pointerize an offset in SRAM you add 0x0E000000 to it, and because these do not work like the relative pointers you’ll really need to do (0x0E007000 + offset in this data) to get the pointer to write. There is no dedicated utility for getting the compressed form of this data, though any generic lz77 compressor should work (one comes with Event Assembler even). The pointer data goes as so:

+0x00 - Pointer to Chapter Data
+0x04 - Nothing
+0x08 - Pointer to Chapter Events
+0x0C - Pointer to raw text data of chapter name
+0x10 - Pointer to raw text data of chapter objective
+0x14 - Pointer to raw text data of chapter description

Each of these pointers are fixed offsets, and what they point to is not compressed data; nothing else gets compressed beyond the 2 existing things.

Chapter Data is structured like a chapter data table entry in the ROM verbatim. Again, it’s uncompressed, so you can just place it in exactly as it is.

Chapter Events too are structured like chapter events in the ROM. Something like the output of a chapter assembled with Event Assembler can be used verbatim.

Raw text data is what you would expect, though note that it is not ASCII text as this is a japanese GBAFE game with 2-byte characters.

Place all of your pieces in, point to them, and if you did it right you’ll find a 6th chapter on the Trial Map menu. Note that you need a cleared file to access trial maps.

Here’s my example XMAP version of the FE6 tutorial map, and the final save file from my testing:

m1zZGA7XOu

FE8 XMAP

The XMAP system was removed for FE7, but was brought back in some form in FE8 (can tell simply by looking for the string XMAP in each game’s ROM). As there are no trial maps in FE8, the XMAP chapter would instead be accessed by going to chapter 0x7F. My preliminary looks at the FE8 system suggest that in addition to being unused it is also non-functional, as it appears to reference header data incorrectly such that it gets compressed data relative pointer and compressed data length backwards in one instance, though I have not attempted anything with it since figuring out the FE6 system so it could be more functional than I initially thought. Should there be findings related to FE8 XMAP chapters, they would likely recieve their own documentation thread.

────────────────────────────────────────────────────────────────

Please let me know if any part of this is incorrect or unclear and I’ll be happy to elaborate or correct as needed.

12 Likes