Save data structure (Generation IV)
|
This article is incomplete. Please feel free to edit this article to add missing information and complete it. |
The save data structure in the Nintendo DS is stored as a .SAV file, which is broken up into two pairs of blocks. Each pair has one general (small) block, and one storage (big) block. The offsets for Platinum are different from Diamond and Pearl.
In Diamond and Pearl, the first small block starts at 0x00000 and ends at 0x0C0FF, the first big block starts at 0x0C100 and ends at 0x1E2DF. In Platinum, the first small block starts at 0x00000 and ends at 0x0CF2B, the first big block starts at 0x0CF2C and ends at 0x1F10F. The second pair of blocks are at the same address plus 0x40000 for all the three games.
In HeartGold and SoulSilver, the first small block starts at 0x00000 and ends at 0x0F6FF, the first big block starts at 0x0F700 and ends at 0x21A10.
One block pair is always a backup of the other block pair.
General (small) block
The small block has the following data:
| Offset | Length (bytes) | Type | Contents | Notes |
|---|---|---|---|---|
| 0x00 | 8 | i64 | RTC Offset | |
| 0x08 | 6 | u8[6] | DS MAC Address | This is always set, even if you have never used networking |
| 0x0E | 1 | u8 | DS Profile birthday month | |
| 0x0F | 1 | u8 | DS Profile birthday date | |
| 0x10 | 4 | bool | Canary | This is always set to 1 |
| 0x14 | 4 | u32 | RTC Year | |
| 0x18 | 4 | u32 | RTC Month | |
| 0x1C | 4 | u32 | RTC Date | |
| 0x20 | 4 | u32 | RTC Weekday | 0 = Sunday, 1 = Monday ... |
| 0x24 | 4 | u32 | RTC Hour | |
| 0x28 | 4 | u32 | RTC Minute | |
| 0x2C | 4 | u32 | RTC Second | |
| 0x30 | 4 | u32 | Day | |
| 0x34 | 8 | i64 | Timestamp when the save started | Number of seconds since 2000-01-01T00:00:00Z |
| 0x3C | 8 | i64 | Timestamp of first Hall of Fame entrance | Number of seconds since 2000-01-01T00:00:00Z |
| 0x44 | 4 | u32 | Clock change penalty | This is a number of minutes set when you load your save and the RTC mismatches |
| 0x48 | 1 | bool | Mystery Gift unlocked | |
| 0x49 | 1 | Unused? | ||
| 0x4A | 4 | s32 | Network profile ID | This is only set after an initial connection to DS WiFi Communications |
| 0x68 | 16 | string | Trainer Name | See Character Encoding (Generation IV) to convert each u16 into a character |
| 0x78 | 2 | u16 | Trainer ID | |
| 0x7A | 2 | u16 | Secret ID | |
| 0x7C | 4 | u32 | Money | Capped at 999,999 |
| 0x80 | 1 | u8 | Gender | 0 = Male, 1 = Female |
| 0x81 | 1 | u8 | Cartridge Locale | 1 = Japan, 2 = Western English (US/UK/AU),
3 = French, 4 = Italian, 5 = German, 6 = Spanish, 7 = South Korean |
| 0x82 | 1 | bool[8] | Badges | Stored as a bitfield:
(value & 1) = Coal; (value & 2) = Forest; (value & 4) = Cobble; (value & 8) = Fen; (value & 16) = Relic; (value & 32) = Mine; (value & 64) = Icicle; (value & 128) = Beacon |
| 0x83 | 1 | u8 | Avatar | 0 = None; 3 = School Kid; 5 = Bug Catcher; 6 = Lass; 7 = Battle Girl; 11 = Ace Trainer Male;
13 = Beauty; 14 = Ace Trainer Female; 15 = Roughneck; 20 = Pop Idol; 35 = Social; 37 = Cowgirl; 42 = Ruin Maniac; 50 = Black Belt; 62 = Rich Boy; 63 = Lady; 70 = Psychic |
| 0x88 | 2 | u16 | Game Corner coins | |
| 0x8A | 2 | u16 | Hours played | |
| 0x8C | 1 | u8 | Minutes played | |
| 0x8D | 1 | u8 | Seconds played | |
| 0x9C | 1 | u8 | Number of Pokémon in Party | |
| 0xA0 - 0x627 | 1416 | pkmn[6] | Party Pokémon blocks | See Pokémon data structure (Generation IV) to decrypt and parse these entries.
NOTE: Party Pokémon include Battle stats which takes up an extra 100 bytes. |
| 0x00630 - 0x008C3 | 660 | item[165] | Items placeholder | |
| 0x008C4 - 0x0098B | 200 | item[50] | Key Items placeholder | |
| 0x0098C - 0x00B4B | 400 | item[100] | TMs & HMs placeholder | |
| 0x00B4C - 0x00BEB | 160 | item[40] | Medicines placeholder | |
| 0x00BDC - 0x00CEB | 256 | item[64] | Berries placeholder | |
| 0x00CEC - 0x00D27 | 60 | item[15] | Poké Balls placeholder | |
| 0x00D28 - 0x00D5B | 52 | item[13] | Battle Items placeholder | |
| 0x00D5C - 0x00D8B | 48 | item[12] | Mail placeholder | |
| 0x0CF18 - 0x0CF2B | 20 | Footer |
Item placeholders
In these placeholders, each item takes 4 bytes with the following structure:
| Offset | Contents |
|---|---|
| 0x00 - 0x01 | Item ID |
| 0x02 - 0x03 | Item amount |
Each item has a unique ID to get identified. See the list of items by index number in Generation IV for these IDs.
Storage (big) block
The storage block contains information regarding your boxes. In generation 4, you have 18 boxes, each with 30 Pokémon.
Diamond / Pearl / Platinum
| Offset | Length (bytes) | Type | Contents | Notes |
|---|---|---|---|---|
| 0x00 | 4 | u32 | Last selected box index | 0 = Box 1 ... |
| 0x04 | 73,440 | box[18] | Box Pokémon | See Pokémon data structure (Generation IV) to decrypt and parse these entries.
NOTE: each Pokémon is 136 bytes. |
| 0x11EE4 | 720 | string[18] | Box names | See Character Encoding (Generation IV) to convert each u16 into a character |
| 0x121B4 | 18 | u8[18] | Box wallpapers | |
| 0x121C6 | 20 | Footer |
HeartGold / SoulSilver
NOTE: exclusive to HGSS, box data is padded. The last 0x10 (16) bytes of each box are empty, making each box 0x1000 (4096) bytes long. In addition, the last 0x16 bytes of the storage block are unused.
| Offset | Length (bytes) | Type | Contents | Notes |
|---|---|---|---|---|
| 0x00 | 73,728 | box[18] | Box Pokémon | See Pokémon data structure (Generation IV) to decrypt and parse these entries.
NOTE: each Pokémon is 136 bytes. |
| 0x12000 | 4 | u32 | Last selected box index | 0 = Box 1 ... |
| 0x12004 | 4 | u32 | Total number of Pokémon stored in boxes | This value may not always be set? |
| 0x12008 | 720 | string[18] | Box names | See Character Encoding (Generation IV) to convert each u16 into a character |
| 0x122D8 | 18 | u8[18] | Box wallpapers | |
| 0x122EA | 22 | Unused | ||
| 0x122FE | 20 | Footer |
The last 0x14 bytes of each block (small and big) are used as a footer. It has the following structure:
| Offset | Contents |
|---|---|
| 0x00 - 0x03 | Used to connect a small block with a big block |
| 0x04 - 0x07 | Number of the save |
| 0x08 - 0x0B | Size of the block |
| 0x0C - 0x0F | K |
| 0x10 - 0x11 | T |
| 0x12 - 0x13 | Checksum of the block |
Checksum
The game uses a CRC-16-CCITT algorithm for the checksums. These checksums are calculated from a whole block without taking the footer.
Example
SMALL BLOCK 1 D1 01 00 00 | 42 04 00 00 | 00 C1 00 00 | 23 06 06 20 | 00 00 | 7E 7A BIG BLOCK 1 D0 01 00 00 | F1 02 00 00 | E0 21 01 00 | 23 06 06 20 | 01 00 | 0D 39
SMALL BLOCK 2 D0 01 00 00 | 41 04 00 00 | 00 C1 00 00 | 23 06 06 20 | 00 00 | 0C 7F BIG BLOCK 2 D1 01 00 00 | F2 02 00 00 | E0 21 01 00 | 23 06 06 20 | 01 00 | F6 8A
Since the value of 0x0C0F0 - 0x0C0F3 is higher in small block 1 (42 04 00 00 > 41 04 00 00), that is the current small block. Then, by matching the value of 0x0C0EC - 0x0C0EF (which is D1 01 00 00) to the big block. This means that the current big block is actually big block 2 (assuming the big block's checksum is correct).
Related articles
| |||||||||||||||||||||||||||||||||
|
This data structure article is part of Project Games, a Bulbapedia project that aims to write comprehensive articles on the Pokémon games. |

