This is a specification for the save file format used by the Sega PC release of Sonic CD, released in 1996 for Windows 95. The format of this file differs significantly from the save files of the original Sega CD game.
This document uses the following terms to represent data sizes, consistent with their use in Win32 API:
Term | Length | Range |
---|---|---|
BYTE | 1 byte (8 bits) | 0–255 |
WORD | 2 bytes (16 bits) | 0–65,535 |
DWORD | 4 bytes (32 bits) | 0–4,294,967,295 |
All numbers are little endian integers, meaning that the word $FF00
has the decimal value of 255 and not 65,280. All text is 7-bit ASCII.
The file is named "s_score.dat" by default and saved in the program directory. The game can save up to 6 different save slots in a single save file. The file is always 4,324 bytes in length.
The first four bytes of the file are an integer indicating the currently selected slot. This value is DWORD-sized and contains a value between $00
and $05
.
Offset | Size | Format | Description |
---|---|---|---|
$0000 –$0003 |
DWORD | Number | Selected slot (between $00 and $05 ) |
$0004 –$02D3 |
720 bytes | Section | Slot 1 |
$02D4 –$05A3 |
720 bytes | Section | Slot 2 |
$05A4 –$0873 |
720 bytes | Section | Slot 3 |
$0874 –$0B43 |
720 bytes | Section | Slot 4 |
$0B44 –$0E13 |
720 bytes | Section | Slot 5 |
$0E14 –$10E3 |
720 bytes | Section | Slot 6 |
Each save slot is encoded using a seeded pseudorandom number sequence for obfuscation. This sequence is generated by the srand
function of C with the seed $0551
. The output of this function is implementation-specific, so to generate the same numbers used by the game, we need to use the msvc
compiler. Since each save slot is 720 bytes long, we need to generate 720 numbers.
The following C code can be compiled in msvc
to generate the correct sequence:
#include <stdio.h>
int main(void) {
size_t i;
srand(0x0551);
for (i = 0; i < 720; i++) {
// rand gives us a word but we only need the low byte
printf("%02x\n", rand() & 0xff);
}
return 0;
}
This gives us a list of bytes that can be used with any other language or compiler to decode save files. Each save slot is encoded individually. To decode a save slot, we need to iterate through each byte and xor it with its corresponding byte in the srand
sequence.
A simple JavaScript function for decoding a slot (given an array SRAND_SEQUENCE
containing the generated numbers):
function encodeFile(bytes) {
return bytes.map(function(value, i) {
return value ^ SRAND_SEQUENCE[i];
});
}
Because xor is its own inverse function, the same algorithm is used to re-encode slots. Note that modified slots also need to have their checksums recalculated to be considered valid by the game.
See Appendix A for a sample standalone C program that reproduces the entire srand
sequence literally (so it works in any C compiler and not only msvc
) and decodes save files by iterating through each of the 6 sections separately.
Each slot is 720 bytes long. Offsets are given relative to the beginning of the slot and not the beginning of the file. The first slot is offset by 4 bytes; the nth slot is offset by 4 + (n − 1) × 720 bytes.
Offset | Size | Format | Description |
---|---|---|---|
$0000 –$0003 |
DWORD | Number | New game |
$0004 –$000F |
12 bytes | Text | Slot name |
$0010 –$0013 |
DWORD | Number | Current Round |
$0014 –$001F |
12 bytes | Section | Date/time (see subsection) |
$0020 –$02BF |
672 bytes | Section | Time Attack (see subsection) |
$02C0 –$02C3 |
DWORD | Number | Total completion time |
$02C4 |
BYTE | Bit field | Time Stones |
$02C5 |
BYTE | Bit field | Good Futures |
$02C6 –$02C7 |
WORD | Number | Next Special Zone |
$02C8 –$02CB |
DWORD | Number | Unknown, usually 0 but not always |
$02CC –$02CF |
DWORD | Number | Checksum |
$00
for new game, $01
otherwise.
Save slots with a value of $00
here are ignored by the game and treated as empty regardless of the contents of the rest of the data.
ASCII text, used by the in-game Saved Games screen. The game limits this field to 10 characters, but it can be up to 12 characters long (though the last two characters will visually overlap the date/time in the interface). If the provided name is less than 12 bytes long, the game pads the last bytes as $20
.
Underscore characters (_
) and spaces are allowed and displayed as blank characters. Only uppercase letters and numerals are allowed. Lowercase letters and all other characters are shown as blank characters.
The current Round. This is used by the Continue option on the title screen as well as for determining which levels are available in Time Attack. Possible values:
Value | Continue Round | Latest Round in Time Attack |
---|---|---|
$00 |
Palmtree Panic | Not available |
$01 |
Collision Chaos | Palmtree Panic |
$02 |
Tidal Tempest | Collision Chaos |
$03 |
Quartz Quadrant | Tidal Tempest |
$04 |
Wacky Workbench | Quartz Quadrant |
$05 |
Stardust Speedway | Wacky Workbench |
$06 |
Metallic Madness | Stardust Speedway |
$07 |
Metallic Madness | Metallic Madness |
Completed games have a value of $07
.
Saves the last modified time of each save slot.
Offset | Size | Format | Description |
---|---|---|---|
$0014 –$0015 |
WORD | Number | Year |
$0016 –$0017 |
WORD | Number | Month, between 1 and 12 |
$0018 –$0019 |
WORD | Number | Day of month, between 1 and 31 |
$001A –$001B |
WORD | Number | Hour, between 0 and 23 |
$001C –$001D |
WORD | Number | Minute, between 0 and 59 |
$001E –$001F |
WORD | Number | Seconds, between 0 and 59 |
Note that the month and day start at 1 and not 0 (as in some programming languages). The year is stored as a full number (for example, 1996 would be stored as $CC07
) and not as an offset from 1900 or similar.
These values are all set to $00
for new games.
The game stores three different time positions for each of the 21 zones and 7 Special Zones, in the order of:
- Palmtree Panic I, 1st place
- Palmtree Panic I, 2nd place
- Palmtree Panic I, 3rd place
- Palmtree Panic II, 1st place
- Palmtree Panic II, 2nd place
- Palmtree Panic II, 3rd place
- ...
- Special Zone 6, 1st place
- Special Zone 6, 2nd place
- Special Zone 6, 3rd place
- Special Zone 7, 1st place
- Special Zone 7, 2nd place
- Special Zone 7, 3rd place
See Appendix B for a complete list of Time Attack position offsets.
Each position consists of 8 bytes:
- A DWORD number for the time in ticks. Default value is
$5046
, representing 5 minutes in ticks (5 × 60 × 60). - A DWORD of text containing three ASCII characters representing the player's initials and one null byte (
$00
). Default value is$414141
, representing "AAA" in ASCII.
Time in Sonic CD is kept in minutes, seconds, and ticks. Ticks are 1/60 of a second but displayed in-game as 1/100 of a second. The formula to convert from the stored form (1/60) to the displayed form (1/100) is ⌊ 100 × tick / 60 ⌋.
Uppercase letters, numerals, and spaces are allowed for initials. All other characters are shown as blank characters.
The sum of all of the first-place times in the Time Attack mode, in ticks. This is used to determine if the Play Music or Visual Mode options are available on the title screen without having to recalculate it every time the game is started.
The total time is computed by adding all of the first-place times (excluding Special Zones) in their original, 1/60 of a second form. Adding times in their converted, 1/100 of a second form results in a slightly different time from the one presented in-game.
Default value is $90C405
, representing 105 minutes in ticks.
Tracks the Time Stones collected by the player. Each Time Stone is associated with a particular Special Zone, so they can be collected out of order if the player fails a Special Zone.
This is stored as a bit field of seven bits, each representing one Time Stone, starting with the least significant bit:
0 1 1 1 1 1 1 1
| | | | | | |
| | | | | | Green
| | | | | Orange
| | | | Yellow
| | | Blue
| | Cyan
| Purple
Red
This can also be expressed as a sum of the powers of 2:
Time Stone | Value |
---|---|
Green | 1 |
Orange | 2 |
Yellow | 4 |
Blue | 8 |
Cyan | 16 |
Purple | 32 |
Red | 64 |
A value of $7F
means that all of the Time Stones have been collected.
Tracks the Good Futures created by the player. A Good Future can be created in a particular Round by traveling to the Past in each of the first two Zones and finding and destroying the robot transporter machine. A Good Future is also created in each Round played after the player collects all of the Time Stones.
This is stored as a bit field of seven bits, each representing one of the game's seven Rounds, starting with the least significant bit:
0 1 1 1 1 1 1 1
| | | | | | |
| | | | | | Palmtree Panic
| | | | | Collision Chaos
| | | | Tidal Tempest
| | | Quartz Quadrant
| | Wacky Workbench
| Stardust Speedway
Metallic Madness
This can also be expressed as a sum of the powers of 2:
Round | Value |
---|---|
Palmtree Panic | 1 |
Collision Chaos | 2 |
Tidal Tempest | 4 |
Quartz Quadrant | 8 |
Wacky Workbench | 16 |
Stardust Speedway | 32 |
Metallic Madness | 64 |
A value of $7F
means that all of the Good Futures have been obtained.
The next Special Zone to be played, between $00
and $06
. The game goes through all of the Special Zones in rotation, skipping the ones that have already been successfully completed. This value is set to $00
once the player has collected all of the Time Stones.
It is possible to set this value to that of a Special Zone that has already been completed. In this case, the selected Special Zone is played next but does not award another Time Stone if completed successfully (since each Special Zone is associated with a particular Time Stone).
The checksum is computed by iterating over the first 716 bytes of the slot (that is, the entire slot except the checksum itself) and adding each byte as a signed integer. In C, it can be calculated with the following function:
int calculate_checksum(signed char bytes[]) {
int checksum = 0;
for (size_t i = 0; i < 716; i++) {
checksum += bytes[i];
}
return checksum;
}
It is significant to note that the algorithm treats each byte as a signed integer, meaning that any value greater than $7F
is treated as a two's complement and reduces the value of the checksum rather than increasing it. If we were to implement the function in a language with no concept of a signed byte type, such as JavaScript, we would need to take this into account:
function calculateChecksum(bytes) {
let checksum = 0;
// adds all bytes of file as signed integers
for (let i = 0; i < bytes.length - 4; i++) {
if (bytes[i] < 0x80) {
checksum += bytes[i];
} else { // converts two's complement
checksum -= 0xff - bytes[i] + 1;
}
}
return checksum;
}
This means that a file can theoretically produce a negative checksum, but this can never happen with a real save file because there are not enough possible bytes in the format with valid values above $7F
.
Slots with invalid checksums are treated as empty and ignored by the game.
#include <stdio.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define HEADER_SIZE 4
#define SAVE_SLOTS 6
#define SLOT_SIZE 720
#define FILE_SIZE 4132
int main(int argc, char *argv[]) {
char *input_file, *output_file;
if (argc != 3) {
puts("Usage: pcdecode <input file> <output file>");
return EXIT_FAILURE;
} else {
input_file = argv[1];
output_file = argv[2];
}
// pseudorandom number sequence is reproduced here so that the program works
// independently of compiler
unsigned char sequence[] = {
0x83, 0x0c, 0x27, 0xdf, 0x0f, 0x2c, 0xbb, 0x88, 0x24, 0xf4, 0x89, 0xf0,
0xb8, 0x17, 0xc6, 0x86, 0x49, 0xa6, 0x8e, 0x0c, 0x66, 0x87, 0x83, 0xa5,
0x71, 0x24, 0xb7, 0x2f, 0xa3, 0x60, 0xcc, 0xd2, 0x50, 0xcf, 0x59, 0xd9,
0x6d, 0x26, 0x90, 0xc1, 0x4f, 0xf0, 0x1e, 0x90, 0xb5, 0x83, 0x53, 0x69,
0x09, 0x33, 0x83, 0x5c, 0xe3, 0xc5, 0xac, 0x82, 0xcf, 0x27, 0x58, 0x4a,
0x50, 0x5e, 0xc5, 0x0e, 0x25, 0xbf, 0x44, 0xea, 0xca, 0x62, 0xdf, 0xcd,
0x42, 0xd4, 0x3e, 0xd0, 0x14, 0x0c, 0xcc, 0xc7, 0x94, 0xa0, 0x15, 0x16,
0x63, 0x39, 0x72, 0xc7, 0x39, 0x45, 0xe9, 0xd9, 0xe2, 0xeb, 0x4f, 0xda,
0x87, 0x44, 0xaf, 0xb8, 0x2f, 0xc8, 0xf0, 0xd4, 0x85, 0x06, 0xb1, 0x58,
0xdc, 0x99, 0x78, 0xcb, 0x70, 0x57, 0x0c, 0xe2, 0xef, 0xcb, 0x1f, 0x99,
0x38, 0xe6, 0x30, 0x83, 0x62, 0xf1, 0xb0, 0x5e, 0x00, 0xc6, 0x64, 0xeb,
0xa3, 0x40, 0x0a, 0xfd, 0xa1, 0xf0, 0x3f, 0xcf, 0x15, 0x11, 0xa0, 0x9a,
0x27, 0xbe, 0x30, 0x67, 0x8e, 0x63, 0xfa, 0x22, 0x53, 0x72, 0xf7, 0xf1,
0xd7, 0x57, 0x31, 0xc4, 0x17, 0xad, 0x29, 0x2c, 0x2f, 0xb2, 0x76, 0x70,
0x1d, 0xf8, 0xb0, 0xde, 0xc8, 0x5e, 0x8c, 0x5f, 0x41, 0x3f, 0x48, 0x4e,
0x48, 0xe9, 0x4a, 0x8a, 0x12, 0x51, 0x04, 0xca, 0x49, 0x05, 0x1a, 0x31,
0x55, 0x61, 0xc7, 0x23, 0xda, 0x06, 0x7d, 0x56, 0x81, 0x88, 0xcb, 0x2c,
0xfc, 0x67, 0x84, 0x40, 0x44, 0x41, 0x1e, 0x3e, 0x25, 0x45, 0x58, 0xf9,
0xfd, 0xeb, 0x1f, 0xb7, 0xc1, 0xe2, 0xb3, 0xcf, 0x40, 0x4a, 0x06, 0x77,
0xac, 0x24, 0x65, 0xd7, 0x56, 0x07, 0x59, 0x62, 0xb9, 0x14, 0xd0, 0x65,
0xba, 0x2c, 0x78, 0xe0, 0x2e, 0x60, 0x6c, 0x96, 0x9d, 0xa8, 0x12, 0x60,
0x45, 0xd8, 0x43, 0xc6, 0x62, 0xd1, 0xad, 0xd0, 0xad, 0xf4, 0x76, 0x1a,
0x23, 0xdd, 0x22, 0x27, 0x07, 0x4d, 0xb7, 0xf7, 0x2a, 0x67, 0x1f, 0xdc,
0x6a, 0x20, 0xcd, 0x89, 0x79, 0xf1, 0xa4, 0x6c, 0xe0, 0xce, 0x14, 0x3e,
0x43, 0x5c, 0x86, 0xd8, 0xe6, 0x5f, 0xfa, 0x48, 0x70, 0x71, 0xee, 0x24,
0xef, 0xfa, 0x82, 0x1e, 0x1d, 0x5c, 0xdb, 0xd9, 0xe2, 0x6e, 0xc5, 0xfb,
0x19, 0x2c, 0x9c, 0x84, 0x97, 0xad, 0x6c, 0x5e, 0x69, 0x55, 0x57, 0x34,
0x5e, 0x4b, 0x37, 0x88, 0xc6, 0x2d, 0x85, 0x00, 0x78, 0x03, 0x7a, 0x01,
0x1a, 0x72, 0x73, 0x7f, 0x9c, 0x33, 0x9a, 0x14, 0x06, 0xc3, 0xc3, 0x4f,
0x74, 0x5b, 0x94, 0x4e, 0x5e, 0x22, 0xe9, 0x8f, 0x1d, 0xa2, 0x76, 0x03,
0xab, 0x78, 0xaf, 0x64, 0xab, 0x50, 0xe4, 0xc9, 0xa9, 0x11, 0xb1, 0x78,
0xa2, 0x55, 0x95, 0xfb, 0xc7, 0x1c, 0xe1, 0x76, 0x7e, 0xc1, 0xd4, 0x37,
0xaa, 0x2d, 0x04, 0x8f, 0x2c, 0x4a, 0xff, 0xe0, 0xaa, 0xba, 0x33, 0xf8,
0x8e, 0xca, 0x0b, 0x9d, 0x52, 0xa1, 0x5b, 0x69, 0xfc, 0xbe, 0xfe, 0xd9,
0xe4, 0xa1, 0xbe, 0xa0, 0xbd, 0xc7, 0x73, 0x41, 0xd3, 0xdc, 0x6f, 0xdc,
0x92, 0x2d, 0x1a, 0x48, 0x48, 0x5c, 0xda, 0x63, 0x2c, 0x57, 0x36, 0xa6,
0x9e, 0x8a, 0x3a, 0xfd, 0xb0, 0x54, 0x1d, 0xd5, 0xe6, 0xb8, 0x21, 0x76,
0x3a, 0x56, 0xbb, 0x93, 0x63, 0x99, 0xf4, 0x1f, 0x57, 0x31, 0x0f, 0x63,
0x0f, 0xc4, 0x6c, 0x4e, 0x8a, 0xe0, 0xac, 0x0c, 0x14, 0x35, 0x16, 0xda,
0xc8, 0x01, 0x39, 0x18, 0x54, 0xcb, 0xd3, 0x9f, 0xfc, 0x54, 0xf2, 0x56,
0xe2, 0xcb, 0x59, 0x00, 0x84, 0x40, 0x25, 0x58, 0x86, 0x5b, 0xb1, 0x60,
0xb2, 0x4e, 0xb6, 0xf6, 0x3d, 0x08, 0xb7, 0xa8, 0x4b, 0xab, 0x9c, 0xc9,
0xb6, 0x41, 0x9d, 0xc4, 0x0b, 0xab, 0x61, 0xb1, 0xd6, 0xd9, 0x67, 0x26,
0x20, 0x41, 0xa6, 0x50, 0x35, 0x89, 0x70, 0x42, 0xab, 0x87, 0x9c, 0x8c,
0x9f, 0x6c, 0xe4, 0x10, 0x42, 0x3c, 0x8c, 0x11, 0x95, 0x82, 0x45, 0x8d,
0x70, 0x41, 0x50, 0xcd, 0xc9, 0x2d, 0xe6, 0x3a, 0x33, 0x1b, 0xd8, 0x72,
0xa5, 0xb7, 0x73, 0x9b, 0x7d, 0x75, 0xa6, 0xf8, 0xc4, 0xca, 0x67, 0xb9,
0xb4, 0x9b, 0x52, 0x18, 0x77, 0xf6, 0x93, 0xa1, 0x32, 0x00, 0x07, 0xd1,
0x42, 0x2e, 0x9e, 0xe3, 0xc6, 0xb8, 0x04, 0xe7, 0x5d, 0x4b, 0x80, 0x14,
0x31, 0xff, 0x1c, 0x5f, 0x34, 0x88, 0x06, 0x4d, 0xa9, 0xb0, 0x36, 0x05,
0xe7, 0x05, 0x51, 0xa9, 0x59, 0xce, 0xcd, 0xe6, 0xca, 0x44, 0x57, 0xca,
0xdf, 0xff, 0x71, 0xd6, 0xe5, 0xaf, 0x60, 0x55, 0xcd, 0x0c, 0x45, 0xec,
0x75, 0x10, 0x8a, 0x71, 0x2a, 0x63, 0x7f, 0x00, 0x6a, 0x17, 0x45, 0x4c,
0xee, 0x95, 0xec, 0x34, 0xe8, 0xd7, 0xd8, 0x97, 0x89, 0xd8, 0x69, 0x68,
0xc6, 0x49, 0xdb, 0x05, 0x5c, 0x86, 0x6a, 0xc4, 0x11, 0xc8, 0xba, 0xcf,
0x3d, 0x9c, 0x77, 0x33, 0x8a, 0x94, 0x38, 0x33, 0xf8, 0x3c, 0xaa, 0xe2,
0x24, 0x4f, 0xea, 0xf1, 0xc9, 0x2b, 0x32, 0xc5, 0x87, 0x83, 0xb8, 0xcc,
0xe3, 0x54, 0xd3, 0x12, 0x90, 0x1a, 0x60, 0x0f, 0xed, 0x43, 0x64, 0xc4,
0xce, 0xe4, 0xf3, 0x06, 0x7f, 0xab, 0x50, 0x19, 0x06, 0x15, 0x55, 0x80,
0xa9, 0xe0, 0x15, 0x14, 0xb0, 0xc4, 0xc1, 0x54, 0x6c, 0x5e, 0xc8, 0xfc
};
FILE *input_handle, *output_handle;
if ((input_handle = fopen(input_file, "rb")) == NULL) {
puts("Could not open input file.");
return EXIT_FAILURE;
}
if ((output_handle = fopen(output_file, "wb")) == NULL) {
puts("Could not open output file.");
return EXIT_FAILURE;
}
// first four bytes of file are copied over exactly
for (size_t i = 0; i < HEADER_SIZE; i++) {
unsigned char buffer[HEADER_SIZE];
fseek(input_handle, 0, SEEK_SET);
fread(&buffer, sizeof(unsigned char), sizeof(buffer), input_handle);
fseek(output_handle, 0, SEEK_SET);
fwrite(buffer, sizeof(unsigned char), sizeof(buffer), output_handle);
}
for (size_t i = 0; i < SAVE_SLOTS; i++) {
unsigned char buffer[SLOT_SIZE];
fseek(input_handle, HEADER_SIZE + i * SLOT_SIZE, SEEK_SET);
fread(&buffer, sizeof(unsigned char), sizeof(buffer), input_handle);
for (size_t j = 0; j < SLOT_SIZE; j++) {
buffer[j] ^= sequence[j];
}
fseek(output_handle, HEADER_SIZE + i * SLOT_SIZE, SEEK_SET);
fwrite(buffer, sizeof(unsigned char), sizeof(buffer), output_handle);
}
fclose(input_handle);
fclose(output_handle);
return EXIT_SUCCESS;
}
Offset | Size | Format | Description |
---|---|---|---|
$0020 –$0023 |
DWORD | Number | Palmtree Panic I, 1st place time |
$0024 –$0027 |
DWORD | Text | Palmtree Panic I, 1st place initials |
$0028 –$002B |
DWORD | Number | Palmtree Panic I, 2nd place time |
$002C –$002F |
DWORD | Text | Palmtree Panic I, 2nd place initials |
$0030 –$0033 |
DWORD | Number | Palmtree Panic I, 3rd place time |
$0034 –$0037 |
DWORD | Text | Palmtree Panic I, 3rd place initials |
$0038 –$003B |
DWORD | Number | Palmtree Panic II, 1st place time |
$003C –$003F |
DWORD | Text | Palmtree Panic II, 1st place initials |
$0040 –$0043 |
DWORD | Number | Palmtree Panic II, 2nd place time |
$0044 –$0047 |
DWORD | Text | Palmtree Panic II, 2nd place initials |
$0048 –$004B |
DWORD | Number | Palmtree Panic II, 3rd place time |
$004C –$004F |
DWORD | Text | Palmtree Panic II, 3rd place initials |
$0050 –$0053 |
DWORD | Number | Palmtree Panic III, 1st place time |
$0054 –$0057 |
DWORD | Text | Palmtree Panic III, 1st place initials |
$0058 –$005B |
DWORD | Number | Palmtree Panic III, 2nd place time |
$005C –$005F |
DWORD | Text | Palmtree Panic III, 2nd place initials |
$0060 –$0063 |
DWORD | Number | Palmtree Panic III, 3rd place time |
$0064 –$0067 |
DWORD | Text | Palmtree Panic III, 3rd place initials |
$0068 –$006B |
DWORD | Number | Collision Chaos I, 1st place time |
$006C –$006F |
DWORD | Text | Collision Chaos I, 1st place initials |
$0070 –$0073 |
DWORD | Number | Collision Chaos I, 2nd place time |
$0074 –$0077 |
DWORD | Text | Collision Chaos I, 2nd place initials |
$0078 –$007B |
DWORD | Number | Collision Chaos I, 3rd place time |
$007C –$007F |
DWORD | Text | Collision Chaos I, 3rd place initials |
$0080 –$0083 |
DWORD | Number | Collision Chaos II, 1st place time |
$0084 –$0087 |
DWORD | Text | Collision Chaos II, 1st place initials |
$0088 –$008B |
DWORD | Number | Collision Chaos II, 2nd place time |
$008C –$008F |
DWORD | Text | Collision Chaos II, 2nd place initials |
$0090 –$0093 |
DWORD | Number | Collision Chaos II, 3rd place time |
$0094 –$0097 |
DWORD | Text | Collision Chaos II, 3rd place initials |
$0098 –$009B |
DWORD | Number | Collision Chaos III, 1st place time |
$009C –$009F |
DWORD | Text | Collision Chaos III, 1st place initials |
$00A0 –$00A3 |
DWORD | Number | Collision Chaos III, 2nd place time |
$00A4 –$00A7 |
DWORD | Text | Collision Chaos III, 2nd place initials |
$00A8 –$00AB |
DWORD | Number | Collision Chaos III, 3rd place time |
$00AC –$00AF |
DWORD | Text | Collision Chaos III, 3rd place initials |
$00B0 –$00B3 |
DWORD | Number | Tidal Tempest I, 1st place time |
$00B4 –$00B7 |
DWORD | Text | Tidal Tempest I, 1st place initials |
$00B8 –$00BB |
DWORD | Number | Tidal Tempest I, 2nd place time |
$00BC –$00BF |
DWORD | Text | Tidal Tempest I, 2nd place initials |
$00C0 –$00C3 |
DWORD | Number | Tidal Tempest I, 3rd place time |
$00C4 –$00C7 |
DWORD | Text | Tidal Tempest I, 3rd place initials |
$00C8 –$00CB |
DWORD | Number | Tidal Tempest II, 1st place time |
$00CC –$00CF |
DWORD | Text | Tidal Tempest II, 1st place initials |
$00D0 –$00D3 |
DWORD | Number | Tidal Tempest II, 2nd place time |
$00D4 –$00D7 |
DWORD | Text | Tidal Tempest II, 2nd place initials |
$00D8 –$00DB |
DWORD | Number | Tidal Tempest II, 3rd place time |
$00DC –$00DF |
DWORD | Text | Tidal Tempest II, 3rd place initials |
$00E0 –$00E3 |
DWORD | Number | Tidal Tempest III, 1st place time |
$00E4 –$00E7 |
DWORD | Text | Tidal Tempest III, 1st place initials |
$00E8 –$00EB |
DWORD | Number | Tidal Tempest III, 2nd place time |
$00EC –$00EF |
DWORD | Text | Tidal Tempest III, 2nd place initials |
$00F0 –$00F3 |
DWORD | Number | Tidal Tempest III, 3rd place time |
$00F4 –$00F7 |
DWORD | Text | Tidal Tempest III, 3rd place initials |
$00F8 –$00FB |
DWORD | Number | Quartz Quadrant I, 1st place time |
$00FC –$00FF |
DWORD | Text | Quartz Quadrant I, 1st place initials |
$0100 –$0103 |
DWORD | Number | Quartz Quadrant I, 2nd place time |
$0104 –$0107 |
DWORD | Text | Quartz Quadrant I, 2nd place initials |
$0108 –$010B |
DWORD | Number | Quartz Quadrant I, 3rd place time |
$010C –$010F |
DWORD | Text | Quartz Quadrant I, 3rd place initials |
$0110 –$0113 |
DWORD | Number | Quartz Quadrant II, 1st place time |
$0114 –$0117 |
DWORD | Text | Quartz Quadrant II, 1st place initials |
$0118 –$011B |
DWORD | Number | Quartz Quadrant II, 2nd place time |
$011C –$011F |
DWORD | Text | Quartz Quadrant II, 2nd place initials |
$0120 –$0123 |
DWORD | Number | Quartz Quadrant II, 3rd place time |
$0124 –$0127 |
DWORD | Text | Quartz Quadrant II, 3rd place initials |
$0128 –$012B |
DWORD | Number | Quartz Quadrant III, 1st place time |
$012C –$012F |
DWORD | Text | Quartz Quadrant III, 1st place initials |
$0130 –$0133 |
DWORD | Number | Quartz Quadrant III, 2nd place time |
$0134 –$0137 |
DWORD | Text | Quartz Quadrant III, 2nd place initials |
$0138 –$013B |
DWORD | Number | Quartz Quadrant III, 3rd place time |
$013C –$013F |
DWORD | Text | Quartz Quadrant III, 3rd place initials |
$0140 –$0143 |
DWORD | Number | Wacky Workbench I, 1st place time |
$0144 –$0147 |
DWORD | Text | Wacky Workbench I, 1st place initials |
$0148 –$014B |
DWORD | Number | Wacky Workbench I, 2nd place time |
$014C –$014F |
DWORD | Text | Wacky Workbench I, 2nd place initials |
$0150 –$0153 |
DWORD | Number | Wacky Workbench I, 3rd place time |
$0154 –$0157 |
DWORD | Text | Wacky Workbench I, 3rd place initials |
$0158 –$015B |
DWORD | Number | Wacky Workbench II, 1st place time |
$015C –$015F |
DWORD | Text | Wacky Workbench II, 1st place initials |
$0160 –$0163 |
DWORD | Number | Wacky Workbench II, 2nd place time |
$0164 –$0167 |
DWORD | Text | Wacky Workbench II, 2nd place initials |
$0168 –$016B |
DWORD | Number | Wacky Workbench II, 3rd place time |
$016C –$016F |
DWORD | Text | Wacky Workbench II, 3rd place initials |
$0170 –$0173 |
DWORD | Number | Wacky Workbench III, 1st place time |
$0174 –$0177 |
DWORD | Text | Wacky Workbench III, 1st place initials |
$0178 –$017B |
DWORD | Number | Wacky Workbench III, 2nd place time |
$017C –$017F |
DWORD | Text | Wacky Workbench III, 2nd place initials |
$0180 –$0183 |
DWORD | Number | Wacky Workbench III, 3rd place time |
$0184 –$0187 |
DWORD | Text | Wacky Workbench III, 3rd place initials |
$0188 –$018B |
DWORD | Number | Stardust Speedway I, 1st place time |
$018C –$018F |
DWORD | Text | Stardust Speedway I, 1st place initials |
$0190 –$0193 |
DWORD | Number | Stardust Speedway I, 2nd place time |
$0194 –$0197 |
DWORD | Text | Stardust Speedway I, 2nd place initials |
$0198 –$019B |
DWORD | Number | Stardust Speedway I, 3rd place time |
$019C –$019F |
DWORD | Text | Stardust Speedway I, 3rd place initials |
$01A0 –$01A3 |
DWORD | Number | Stardust Speedway II, 1st place time |
$01A4 –$01A7 |
DWORD | Text | Stardust Speedway II, 1st place initials |
$01A8 –$01AB |
DWORD | Number | Stardust Speedway II, 2nd place time |
$01AC –$01AF |
DWORD | Text | Stardust Speedway II, 2nd place initials |
$01B0 –$01B3 |
DWORD | Number | Stardust Speedway II, 3rd place time |
$01B4 –$01B7 |
DWORD | Text | Stardust Speedway II, 3rd place initials |
$01B8 –$01BB |
DWORD | Number | Stardust Speedway III, 1st place time |
$01BC –$01BF |
DWORD | Text | Stardust Speedway III, 1st place initials |
$01C0 –$01C3 |
DWORD | Number | Stardust Speedway III, 2nd place time |
$01C4 –$01C7 |
DWORD | Text | Stardust Speedway III, 2nd place initials |
$01C8 –$01CB |
DWORD | Number | Stardust Speedway III, 3rd place time |
$01CC –$01CF |
DWORD | Text | Stardust Speedway III, 3rd place initials |
$01D0 –$01D3 |
DWORD | Number | Metallic Madness I, 1st place time |
$01D4 –$01D7 |
DWORD | Text | Metallic Madness I, 1st place initials |
$01D8 –$01DB |
DWORD | Number | Metallic Madness I, 2nd place time |
$01DC –$01DF |
DWORD | Text | Metallic Madness I, 2nd place initials |
$01E0 –$01E3 |
DWORD | Number | Metallic Madness I, 3rd place time |
$01E4 –$01E7 |
DWORD | Text | Metallic Madness I, 3rd place initials |
$01E8 –$01EB |
DWORD | Number | Metallic Madness II, 1st place time |
$01EC –$01EF |
DWORD | Text | Metallic Madness II, 1st place initials |
$01F0 –$01F3 |
DWORD | Number | Metallic Madness II, 2nd place time |
$01F4 –$01F7 |
DWORD | Text | Metallic Madness II, 2nd place initials |
$01F8 –$01FB |
DWORD | Number | Metallic Madness II, 3rd place time |
$01FC –$01FF |
DWORD | Text | Metallic Madness II, 3rd place initials |
$0200 –$0203 |
DWORD | Number | Metallic Madness III, 1st place time |
$0204 –$0207 |
DWORD | Text | Metallic Madness III, 1st place initials |
$0208 –$020B |
DWORD | Number | Metallic Madness III, 2nd place time |
$020C –$020F |
DWORD | Text | Metallic Madness III, 2nd place initials |
$0210 –$0213 |
DWORD | Number | Metallic Madness III, 3rd place time |
$0214 –$0217 |
DWORD | Text | Metallic Madness III, 3rd place initials |
$0218 –$021B |
DWORD | Number | Special Zone 1, 1st place time |
$021C –$021F |
DWORD | Text | Special Zone 1, 1st place initials |
$0220 –$0223 |
DWORD | Number | Special Zone 1, 2nd place time |
$0224 –$0227 |
DWORD | Text | Special Zone 1, 2nd place initials |
$0228 –$022B |
DWORD | Number | Special Zone 1, 3rd place time |
$022C –$022F |
DWORD | Text | Special Zone 1, 3rd place initials |
$0230 –$0233 |
DWORD | Number | Special Zone 2, 1st place time |
$0234 –$0237 |
DWORD | Text | Special Zone 2, 1st place initials |
$0238 –$023B |
DWORD | Number | Special Zone 2, 2nd place time |
$023C –$023F |
DWORD | Text | Special Zone 2, 2nd place initials |
$0240 –$0243 |
DWORD | Number | Special Zone 2, 3rd place time |
$0244 –$0247 |
DWORD | Text | Special Zone 2, 3rd place initials |
$0248 –$024B |
DWORD | Number | Special Zone 3, 1st place time |
$024C –$024F |
DWORD | Text | Special Zone 3, 1st place initials |
$0250 –$0253 |
DWORD | Number | Special Zone 3, 2nd place time |
$0254 –$0257 |
DWORD | Text | Special Zone 3, 2nd place initials |
$0258 –$025B |
DWORD | Number | Special Zone 3, 3rd place time |
$025C –$025F |
DWORD | Text | Special Zone 3, 3rd place initials |
$0260 –$0263 |
DWORD | Number | Special Zone 4, 1st place time |
$0264 –$0267 |
DWORD | Text | Special Zone 4, 1st place initials |
$0268 –$026B |
DWORD | Number | Special Zone 4, 2nd place time |
$026C –$026F |
DWORD | Text | Special Zone 4, 2nd place initials |
$0270 –$0273 |
DWORD | Number | Special Zone 4, 3rd place time |
$0274 –$0277 |
DWORD | Text | Special Zone 4, 3rd place initials |
$0278 –$027B |
DWORD | Number | Special Zone 5, 1st place time |
$027C –$027F |
DWORD | Text | Special Zone 5, 1st place initials |
$0280 –$0283 |
DWORD | Number | Special Zone 5, 2nd place time |
$0284 –$0287 |
DWORD | Text | Special Zone 5, 2nd place initials |
$0288 –$028B |
DWORD | Number | Special Zone 5, 3rd place time |
$028C –$028F |
DWORD | Text | Special Zone 5, 3rd place initials |
$0290 –$0293 |
DWORD | Number | Special Zone 6, 1st place time |
$0294 –$0297 |
DWORD | Text | Special Zone 6, 1st place initials |
$0298 –$029B |
DWORD | Number | Special Zone 6, 2nd place time |
$029C –$029F |
DWORD | Text | Special Zone 6, 2nd place initials |
$02A0 –$02A3 |
DWORD | Number | Special Zone 6, 3rd place time |
$02A4 –$02A7 |
DWORD | Text | Special Zone 6, 3rd place initials |
$02A8 –$02AB |
DWORD | Number | Special Zone 7, 1st place time |
$02AC –$02AF |
DWORD | Text | Special Zone 7, 1st place initials |
$02B0 –$02B3 |
DWORD | Number | Special Zone 7, 2nd place time |
$02B4 –$02B7 |
DWORD | Text | Special Zone 7, 2nd place initials |
$02B8 –$02BB |
DWORD | Number | Special Zone 7, 3rd place time |
$02BC –$02BF |
DWORD | Text | Special Zone 7, 3rd place initials |
- J.C. Fields jcfields@jcfields.dev
Credit to MainMemory for providing a C decompilation, from which the encoding and checksum algorithms were obtained.