|
GuyPerfect Catgirl Level: 68 Posts: 819/1096 EXP: 2665654 For next: 63146 Since: 07-23-07 Since last post: 1.7 years Last activity: 219 days |
|
| I'm working on a project right now where I needed to extract some information from F-Zero Maximum Velocity. A few select individuals might remember that I previously hacked the game in 2005. Well, after looking over some old Acmlm archives, and doing a fair amount of new reverse engineering, I've got the goods. The following are the goods. These goods apply to the North American/PAL version of the game, which has product code AFZE. Most of it still applies to the original Japanese release AFZJ though (just not the ROM offsets).
A reminder that GBA cartridge ROM is mapped to the CPU memory bus starting at address 0x08000000. So when reading a pointer from the ROM, you need to subtract that to yield the actual location in the file. Also, a reminder that GBA is little-endian. Course Data There are 22 courses in the game, and they're indexed 0 to 21. Handy! 0x2C2F20 - Course Info Table A The primary course info table contains 22 entries, each 28 bytes in size. The entries have the following format:
The order of courses in this table is as follows: 0 - Knight 1 1 - Knight 2 2 - Queen 4 3 - Pawn 5 4 - Bishop 4 5 - Bishop 2 6 - Bishop 1 7 - Queen 1 8 - Pawn 2 9 - Knight 3 10 - Bishop 3 11 - Pawn 1 12 - Pawn 3 13 - Queen 3 14 - Pawn 4 15 - Knight 4 16 - Queen 2 17 - Queen 5 18 - Knight 5 19 - Bishop 5 20 - Championship 21 - Single-Pak Path Coordinates, Path Definition There are two paths for every course, and you can switch between them freely. They define the direction in which the course is intended to proceed, as well as give coordinates for the CPU opponents to follow. All of the coordinates are defined in a big chunk (Path Coordinates), and then individual coordinates are referenced by parallel lists of indexes into that chunk (Path Definition). Path Coordinates has the following format:
Both coordinates are actually bit-packed fields of the following format:
u - Unknown c - Multiply by 4 to yield the coordinate, in pixels Path Definition has the following format:
Both indexes are relative to the start of Path Coordinates. For any given Index, multiply it by 4 to yield the offset within Path Coordinates where the coordinates are located. The first entry in Path Definition is the location of the starting line. The path cycles back to this first entry when an Index of 0 is read from the data. Because of this, the first 4 bytes in Path Coordinates are always zero and are never read: the first Index used by the game is always 1. Map Graphics These are 64 standard-issue 4-bit GBA character units. Characters are 8x8 pixels, and the first byte represents the leftmost two pixels of the top row (low bits first). Palette-wise, the map graphics only ever have the following values: 0 = Transparent 8 = Green 15 = Black Maps are always 64 characters in size, and are arranged as 8x8 as well (for a total of 64x64 pixels). Here's a sample of what one looks like:
0x360AAC - Track Data This is a list of 22 track data pointers (of type u32). These are the addresses within the ROM where the actual track data is located. The value in Track Info Table A is an index into this list. Multiply the Index by 4 to yield the offset relative to the start of the pointer table. For the format of the track data itself, scroll down to the Compression Format section of this post. 0x2B4EC4 - Course Info Table B The secondary course info table contains entries that are 76 bytes in size. The value in Track Info Table A is an index into this list. Multiply the Index by 76 to yield the offset relative tot he start of this info table. The entries have the following format:
Name An ASCII name for the course, which is used to display the course name in game. Course names less than 32 characters in size are padded with zeroes. As these are ASCII, the Track Info Table B can pretty easily be found by searching the file for "ANCIENT MESA" Music An AGB MP2000/M4A audio track. I don't know the details of the format, but it's all over the place out there. Just do a web search for "gba sappy" Track Graphics, Horizon Graphics, Floor Graphics These are all standard GBA character units. The formats and number of tiles for each data element are as follows: Track: 8bpp, 256 characters Horizon: 4bpp, 240 characters Floor: 8bpp, 192 characters Track Palette, Horizon Palette, Floor Palette These are all standard GBA palette entry definitions. Palette entries are 16 bits with the following format:
u - Unused b - Blue intensity (0-31) g - Green intensity (0-31) r - Red intensity (0-31) The base color indexes to load into, as well as the number of colors to load, are as follows: Track: 128 entries starting at 0x00 Horizon: 128 entries starting at 0x80 Floor: 256 entries starting at 0x00 As you can see, the floor palette shares the same indexes as the track and horizon palettes. The game cleverly dances around the issue to produce a 512-color image. Horizon Layers Horizons are two-layer images that scroll left and right depending on what direction the player is facing in the game. They are some number of characters wide and 4 characters tall. The background layer is 96 characters wide and the foreground layer is 128 characters wide. The data that defines the layers are simple 96x4- and 128x4-entry lists, starting with the leftmost character of the top row, and proceeding to the right for each row. Entries are standard GBA 4-bit BG cell entries and have the following format:
p - Palette index (or, if you prefer, the upper 4 bits of color indexes) v - If set, the character is flipped vertically h - If set, the character is flipped horizontally c - The character index It's important to note that at runtime, the horizon characters begin at index 0x0180 relative to their background's character base, so that amount should be subtracted from c to yield the offset relative to the first byte of horizon character data. Here's a sample of what one set of horizon layers looks like:
0x3BB20C - Floor Mosaic, Floor Layout Some courses have full character maps for "floors", the graphics off to the sides of the track, and other courses have a repeating pattern that may or may not be animated. These are mutually exclusive, and whichever one is not in use will be stored as NULL in the ROM data. When a repeating mosaic is present, the data represents the character indexes for a 16x16-character image. Depending on the level, the image might scroll horizontally beneath the track. When a mosaic is in use, up to 256 characters can be used, rather than the 192 used by all maps. When a layout map is present, it represents a signed index relative to 0x3BB20C. Multiply the Index by 4 to yield the location of the layout address (of type u32). The layout is stored in the same format as the Track Data from Track Info Table A. For the format, scroll down to the Compression Format section of this post. Compression Format Tracks and floor layouts are both stored as 512x512-character images, for a total of 4096x4096 pixels each. Data is stored in an orders-of-magnitude hierarchy: • A number of 8x8-pixel characters are loaded into character memory. • A number of 8x8-character "panels" are stored in the ROM data. • A BG map is a 64x64-panel arrangement. Panels are stored as 64 bytes, each a character index. The first 8 bytes of each panel represent the top row, starting on the left, and so-on for each group of 8 pixels for each subsequent row. Similarly, the BG map is stored as 4096 16-bit indexes referencing panels. The first 64 indexes are the top row, starting on the left, etc. Track panels are located at 0x1D43FC, and there are 3,070 of them. Floor panels are located at 0x2815B4, and there are 3,297 of them. Note - The X and Y "pixel coordinates" from the pathing information refer to pixels in the final 4096x4096 map, relative to the top-left corner. The 16-bit indexes of the panel arrangement are compressed. To unpack the data:
Vermillion Code The game has 10 racers, though only four are available at the start. You unlock additional machines by completing Grand Prix under various circumsances. The tenth machine, Jet Vermillion, is unlocked by completing every series (Pawn, Knight, Bishop and Queen) with all nine of the other machines, each on the hardest difficulty Master. Alternately, you can complete the Championship circuit 255 times. Either way, you've got a lot of racing ahead of you. Due to the nature of the machine, most players will never see it. So Nintendo implemented a secret code to unlock it: on the machine select screen in Grand Prix mode, press L, R, Start, R, L, Select. This brings up a password screen, and doesn't say what it's for. If you enter the correct password, you unlock the Jet Vermillion early. The password is officially known as the Vermillion Code, and it was only distributed in Japan for a time. The code is dependent on the name of the save file. On the Japanese website, you could enter your player name and get the corresponding Vermillion Code. Internationally, only the code for the name YAZOO JR (the name of the Jet Vermillion's pilot) was distributed, along with instructions to start a new save file with that name. For whatever reason, the game decrypts the Vermillion Code to produce the corresponding player name, which it then checks against the name of the save file. This makes the game's programming less than helpful for producing the code in the first place. So I spent hours and hours in front of that Japanese web form, analyzing it until I finally found a simple algorithm to produce a Vermillion Code given the name of a save file. Player names can be anywhere from 1 to 8 characters in length. There are 46 valid characters for player names, as follows (including the space character):
Vermillion Codes contain characters from a different set of 32, as follows:
Each character in the Vermillion Code corresponds with a 5-bit numerical value, in the order listed above. For example, "0" represents value 0, "?" represents value 11, and "+" represents value 31. Vermillion Codes are 12 characters long, but only the first 10 are generated algorithmically. The initial value of the first 10 correspond with the characters for the code "9+7N-6V9A-" and have the following hexadecimal values:
To calculate the Vermillion Code, the player name and code characters are both processed as numbers. Let each of the 8 characters of the player name be indexed left-to-right, from 0 to 7. Let the 10 characters of the Vermillion Code be 0 to 9. Lastly, let binary digits be numbered with the least significant bit being bit 0. For each character in the player name, take the ASCII value of the character and subtract 32. This will yield a 6-bit number in the range of 0 for " " and 63 for "_". For each bit in that value, zeroes do not modify the Vermillion Code, but ones do. Each bit of each character in the player name can only modify one character in the Vermillion Code by a certain amount. The characters modified and the amount by which they are modified are listed in the table below. The "In" column represents the character and bit from the player name (that is, "0.3" means character 0, bit 3). The "Char" column represents the index of the character in the Vermillion Code that will be modified if the bit is a one. The "Mod" column denotes the amount by which to change the character in the Vermillion Code for that bit. As the Vermillion Code characters are 5-bit, they can only contain values from 0 to 31.
After all characters from the player name have been processed, the final Vermillion Code string can be constructed using the 32-character alphabet from above. Lastly, all Vermillion Codes end with "30", which needs to be appended after calculation is complete. To help illustrate the algorithm, let's put it against the player name NINTENDO:
Only the first 11 characters of the password are validated: anything the user enters starting at and including the last "0" will have no effect on whether the Vermillion Code is accepted. Additionally, here's a JavaScript function to do all the heavy lifting:
|




