Save data structure (Generation I)
This article is incomplete. Please feel free to edit this article to add missing information and complete it. |
This article does not yet meet the quality standards of Bulbapedia. Please feel free to edit this article to make it conform to Bulbapedia norms and conventions. |
The save data structure for Generation I is stored in the cartridge's volatile battery-backed RAM chip (SRAM), or as a ".sav" file by most emulators. The structure consists of 32 KB of data divided between 4 banks each 8KB, or 0x2000, and overall contains potentially hundreds of variables, though there are quite a few areas that are either completely left alone, only read from, or only written to. There are also a number of areas that are only used in certain game states that can't be saved to, including various runtime-only data.
Most areas can freely be written to with custom data or at the very least cleared out. Most of these areas will not be altered by the game unless the "Clear Save Dialog" is triggered on the title screen. Some sections of the data will load untouched into the in-game memory during gameplay and re-saved back on each save.
Sections of the data are protected with a simple integrity check using a checksum to verify data corruption in cases such as the power being lost during the saving process. PC boxes have additional checksums for each box's contents on the bank in addition to the normal whole-bank checksum. The Hall of Fame is the only section of used data which doesn't have a checksum and furthermore lies on an unusual bank number because it's so large.
Save Data Structure
Banks Overview
Note: These values apply to the North American Pokémon Red, Blue, and Yellow games. They could be different for other releases.
The 32KB save data is divided into 4 banks each 8KB in size or 0x2000
Bank | Offset | Name |
---|---|---|
0 | 0x0000 | Scratch and Hall of Fame |
1 | 0x2000 | Main |
2 | 0x4000 | Boxes 1-6 |
3 | 0x6000 | Boxes 7-12 |
Bank 0 - Scratch and Hall of Fame
Consists of 3 sprite buffers which seem to contain misc or varying data and the Hall of Fame because of its size (4,800 bytes).
Bank 1 - Main
The primary bank for just about all data across the game, most is directly loaded into the in-game memory byte-by-byte. It contains hundreds of variables including a full byte-by-byte copy of the current PC box.
Bank 2 - Boxes 1-6
Storage for PC boxes 1-6
Bank 3 - Boxes 7-12
Storage for PC Boxes 7-12
Loading
When it comes to loading, the game only mainly focuses on bank #1, and much of it's contents are directly loaded byte-by-byte directly into WRAM at different addresses, as such, different offsets can be applied to convert from WRAM to the save data and back. Those are provided where possible.
Other banks are loaded either on certain game states, on certain events, or as needed. Upon switching Pokémon boxes, for example, the contents of the new bank are copied to bank 1 from either bank 2 or 3 and events that use hall of fame data causes either one of or the latest Hall of Fame record to be loaded into WRAM.
Checksum
Used to validate the integrity of saved data.
The checksum in Generation I is only 8 bits and has a single copy of it. If this value is incorrect, the error message "The file data is destroyed!" will appear after the title screen, and the continue option will not appear in the menu.
The algorithm used to calculate the checksum is as follows:
- Initialize the checksum to 0
- For every byte from 0x2598 to 0x3522, inclusive, add its value to the checksum
- Invert the bits of the result
An equivalent way to achieve the same result is:
- Initialize the checksum to 255
- For every byte from 0x2598 to 0x3522, inclusive, subtract its value from the checksum
The checksum neatly validates the data it encomapsses but there are several checksums for different sections of data in different banks. Those are all described below.
Bank 0
This is the Hall of Fame and scratch bank. It can essentially be regarded mostly as a misc bank with some large data, various scratch buffers used only occasionally during run-time, and lots and lots of unused space. None of the data in this bank is validated or checked for corruption.
The bank starts at address 0x0000 and is 0x2000 in size.
Offset | Size | Contents |
---|---|---|
0x0000 | 0x188 | Sprite Buffer 0 |
0x0188 | 0x188 | Sprite Buffer 1 |
0x0310 | 0x188 | Sprite Buffer 2 |
0x0498 | 0x100 | Unused |
0x0598 | 0x12C0 | Hall of Fame |
0x1858 | 0x7A8 | Unused |
Scratch Buffers
During gameplay, the game sometimes uses these buffers as extra graphical buffers for misc stuff. As far as has been observed, they can safely by cleared, although they are used occasionally during gameplay so anything cleared or written to them will just be overwritten.
Unused
Unused here refers to data that the game completely does not touch in any way. Also none of the data is ever loaded from or saved to. The only way the game can ever be made to wipe or do anything to these areas is by invoking the hidden "Clear Save File" dialog manually yourself at the title screen.
Hall of Fame
Refer to the Hall of Fame data structure above which goes into all the detail. The Hall of Fame code is a bit messy and it's memory structure the same, memory load addresses can't be provided well.
Bank 1
This is the prime bank that all of the information is stored in that's ever needed or used in gameplay. Bank 2 and 3 really pull into data into Bank 1 when needed or are occasionally updated.
Furthermore most sections in this bank directly correspond byte-by-byte to their counterparts in in-game memory meaning you can apply a simple offset to translate the save data address to and from the in-game memory address. It also means unused areas in such sections will be loaded and available in-game and even saved back to save data.
As such, this is a mammoth of a bank and contains hundreds of variables.
The bank starts at address 0x2000 and is 0x2000 in size.
Offset | Size | Contents | Copied To | Diff |
---|---|---|---|---|
0x2000 | 0x598 | Unused | ||
0x2598 | 0xB | Player Name | 0xD158 | 0xABC0 |
0x25A3 | 0x789 | Main Data | 0xD2F7 | 0xAD54 |
0x2D2C | 0x200 | Sprite Data | 0xC100 | 0x93D4 |
0x2F2C | 0x194 | Party Data | 0xD163 | 0xA237 |
0x30C0 | 0x462 | Current Box Data | 0xDA80 | 0xA9C0 |
0x3522 | 0x1 | Tileset Type | 0xD0D4 | 0x9BB2 |
0x3523 | 0x1 | Main Data Checksum | ||
0x3524 | 0xADC | Unused |
Unused
Unused here refers to data that the game completely does not touch in any way. Also none of the data is ever loaded from or saved to. The only way the game can ever be made to wipe or do anything to these areas is by invoking the hidden "Clear Save File" dialog manually yourself at the title screen.
Player Name
Player name, even though the game allocates space for 10 characters + Terminator, oddly enough, the in-game prompt only allows typing 7 possibly to fit within certain dialogue maybe.
Main Data
This area contains most of the entire memory state from WRAM and is copied byte-by-byte.
Sprite Data
This area contains detailed sprite information in 2 section for the map and is copied byte-by-byte. It's not the only sprite information, there are actually 2 other areas which contain more sprite information for the current map located in "Main Data"
Party Data
Contains information on the players current party and is copied byte-by-byte
Current box data
A byte-by-byte copy of the current PC box from either bank 2 or 3 and is byte-by-byte copied to memory on each load. In this way, the game only deals with 1 PC box in-memory at anytime and that PC box is copied here for easy and quick transfer back to memory on each load.
Tileset Type
The current tileset of where you are such as a specific place, store, dungeon, or just in the outside world.
Main Data Checksum
This checksums from Player Name to Tileset Type, basically the only things which are not checksummed is the unused areas.
Main Data
Goes over all the elements inside of Main Data, one of the most comprehensive areas in the save data. To translate the offset to in-game memory and/or back simply use the difference number mentioned in the above table, 0xAD54.
Padding
Padding is essentially extra space assigned to an area in memory. In other words, the space is larger than the variables makeup and it could be at the start, end, middle, or some combination. It's unknown truly if the padding is ever used, there are certainly many ways for it to be used such as in various game unions with shared space. Therefore it could be considered possibly unused.
Pokédex Seen/Owned
Represents the specific Pokédex entries that have been either seen or owned during gameplay.
Pokémon are indexed by their usual Pokédex order, meaning the order is the same as in the National Pokédex. However, indexes begin counting at 0, rather than 1.
1 bit is used to represent whether a given Pokémon has been seen/owned. Bits are ordered within bytes from lowest to highest, starting with the first byte. Therefore, the exact bit can be extracted from the list using the following formula:
Bit = ( Data[ RoundDown(PokéNum / 8) ] / 2 ^ (PokéNum Mod 8) ) AND 1
Or in C-style code (shift occurs before other bitwise operations):
Bit = Data[PokéNum >> 3] >> (PokéNum & 7) & 1;
Example:
Let us say that we want to know whether #120 Staryu has been seen/owned:
- PokéNum becomes 119, since it is 0-based.
- The byte of the list in which bit 119 is located is = 119 / 8 = 14
- The bit within that byte is = 119 Mod 8 = 7
- Dividing the byte value by 2 ^ Bit, or shifting right by Bit, moves the bit to the least-significant position
- Performing a bitwise AND with 1 will remove all but the least-significant bit
Entry #152:
As the bit lists are packed into 19 bytes, there is actually space for 152 entries. The last entry, bit 7 of byte 18, does in fact represent an entry #152 in the Pokédex. However, it is simply a copy of Kangaskhan.
Bag Items
Follows Item List Data Structure with a capacity of 20.
Money
This is in Binary Coded Decimal, in other words, it's interpreted as decimal even if viewed as hexadecimal so don't use Hexadecimal A-F.
Represents how much money the character has. The figure is a 6-digit number, 2 digits per byte, encoded as binary-coded decimal, where each digit is allocated a full 4 bits.
This figure is still big-endian.
Essentially it's interpreted as decimal even if viewed as hexadecimal so don't use Hexadecimal A-F.
Rival Name
Rival name, even though the game allocates space for 10 characters + Terminator, oddly enough, the in-game prompt only allows typing 7 possibly to fit within certain dialogue maybe.
Game Options
Options are stored in one byte:
- bit 7 (MSB): battle effects ('1' for No, '0' for Yes)
- bit 6: battle style ('1' for Set, '0' for Switch)
- bit 4: sound ('0' for Mono, '1' for Stereo)
- bit 2-0: text speed ('001' for Fast, '011' for Normal, '101' for Slow)
In Pokémon Yellow:
- bit 5-4: sound ('00' for Mono, '01' for Earphone1, '10' for Earphone2, '11' for Earphone3)
Badges
The eight badges are stored on eight bits, one bit for each badge, being '1' is the badge is acquired, '0' otherwise.
From MSB to LSB, badges are in this order: Boulder, Cascade, Thunder, Rainbow, Soul, Marsh, Volcano, Earth.
Pikachu Friendship
Represents the friendship level of the starter Pikachu. For Red and Blue, this value is unused.
Letter Delay
bit 0: If 0, limit the delay to 1 frame. Note that this has no effect if the delay has been disabled entirely through bit 1 of this variable or bit 6 of Various Flags 5 bit 1: If 0, no delay.
Player ID
Randomly generated 16-bit id for the player and their Pokémon most used in Trades and whatnot.
Music ID
Which music or sound plays in this map
Music Bank
Which bank the music or sound is in
Contrast ID
The game contrast, really it's ever only used for the one cave that requires flash because without flash in the cave the contrast would be really bad.
Offset subtracted from FadePal4 to get the background and object palettes for
the current map.
Normally, it is 0. it is 6 when Flash is needed, causing FadePal2 to be used
instead of FadePal4
Current Map
Current Map ID the player was last at
UL Corner Cur View Tile Block Ptr
pointer to the upper left corner of the current view in the tile block map
X/Y Coord
Player X & Y Coordinates
X/Y Block Coord
Same as X & Y Coord but in blocks instead
Last Map
Last map the player visited
Current Tileset
Current tileset in map
Map Height/Width Blocks
Height and width of the map in blocks
Map Data/Text/Script Pointers
Pointers to various code for the current map to function as expected
Map Connections and NSEW Connections
A bit field describing the connections for the current map, are there any connecting maps to the map your on?
If there are, the details will be in the specific connection data mentioned in the connection data structure.
I must forewarn that maps and map connections can be a very complicated subject and often requiring some specific math formulas.
Sprite Set ID(s)
Sprite set for the current map (11 sprite picture ID's)
followed by
sprite set ID for the current map
Object Data Pointers Tmp
Unknown, most likely just a scratch 16-bit value for various object pointers.
Out of Bounds Tile
You have a map defined and then you have the are outside the map that will crash the game if moved to. This is the tile used to fill in all invalid areas of the current map.
The tile shown outside the boundaries of the map
Warp Count
Number of warps on the current map
Warp Entries
List of warp entries on the current map, specific format unknown
Warp Destination ID
Unknown but here's the description which talks about a particular value of this id.
If $ff, the player's coordinates are not updated when entering the map
Sign Count
Number of signs on the map, up to 16
Coordinates of the signs
Follows sign coordinate data structure, allows for up to 16 signs.
Sign Text Ids
Text ID of each sign, format is unknown but there are 16 bytes so it's assumed that each byte refers to a single text block.
Sprite Count
Number of sprites on the current map
X/Y Offset since last special warp
These two variables track the X and Y offset in blocks from the last special
warp used they don't seem to be used for anything
Sprite Data/Extra
Various sprite data for up to 16 sprites, follows data structure on sprite data.
Map 2x2 Meta Height and Width
Map height and width in 2x2 meta tiles
Map View VRAM Pointer
The address of the upper left corner of the visible portion of the BG tile
map in VRAM
Player Direction
"moving" refers to both walking and changing facing direction without taking a step.
Player Moving
if the player is moving, the current direction. If the player is not moving,
zero. Map scripts write to this in order to change the player's facing
direction
Plater Last Stop Direction
The direction in which the player was moving before the player last
stopped
Player Direction
If the player is moving, the current direction, if the player is not moving,
the last the direction in which the player moved
Tileset Bank
Bank current tileset can be found in
Tileset Pointers
Various pointers to how the tiles should be managed and treated in-game. Some extra descriptions are quoted below:
Tileset Block Pointer
Maps blocks (4x4 tiles) to tiles
Tileset Collision Pointer
List of all walkable tiles
Tileset Talking over Tiles
Tiles that can be talked over, as in, a tile between you and an NPC where you can still interact with the NPC even though your not directly in front of them. List of such valid tiles.
Tileset Grass Tiles
Unknown, presumably tiles where wild Pokémon can be found and which engages in a battle since more than just grass triggers a wild battle such as the mansion floor or cave floor.
Box Items
Items found in your PC's item box, follows the item box data structure and has a capacity of 50.
Current PC Box
Indicates which PC box is currently selected, minus 1. That is to say, box 1 is represented as 0, and box 12 is represented as 11.
bits 0-6: box number bit 7: whether the player has changed boxes before
Hall of Fame Record Count
Hall many hall of fame victories you've had in this save file. The game can have up to 50 before it starts over and begins erasing the oldest records.
When loading the hall of fame record data it only pulls this record number temporarily into RAM and clears it out when done since it shares data space with important variables.
Slot Coins
How much coins player has left to gamble with
Represents how much coins the character has. The figure is a 4-digit number, 2 digits per byte, encoded as binary-coded decimal, where each digit is allocated a full 4 bits.
This figure is still big-endian.
Essentially it's interpreted as decimal even if viewed as hexadecimal so don't use Hexadecimal A-F.
Missable Objects
bit array of missable objects. set = removed
Scratch
Temp copy of c1x2 (sprite facing/anim)
Missable List
Follows the missable list data structure
Completed Scripts
Long array of completed scripts for all maps and even some NPCs, broken down further below.
Owned Hidden Items/Coins
Bit array of hidden items and coins player has found
Walking, Biking, or Surfing
Is the player walking, biking, or surfing currently?
Towns visited
Bit array of towns player has ever visited
Safari Steps
Number of steps for the safari zone taken so far
Starts at 502
Fossil Given and Result
Item given to cinnabar lab
and Pokémon that will result from the
item
Enemy Pokémon or Trainer Class
Shared space between 2 variables
- Enemy Pokémon ID in Wild Pokémon Battle
- Trainer class of Trainer Battle
Player Jumping Y Screen Coords
Unknown really, pertains to the sections of code that deal with the jumping mechanic.
Rival Starter
Pokémon Rival Picked
Player Starter
Pokémon Player Picked
Boulder Sprite Index
Sprite index of the boulder the player is trying to push
Last Blackout Map
Unknown
Destination Map
Destination map (for certain types of special warps, not ordinary walking)
Tile in front of Boulder or Collision
Used to store the tile in front of the boulder when trying to push a boulder.
Also used to store the result of the collision check ($ff for a collision and
$00 for no collision)
Dungeon Warp Destination
Destination map for dungeon warps
Which dungeon warp used
Which dungeon warp within the source map was used
Various Flags 1
bit 0: using Strength outside of battle bit 1: set by IsSurfingAllowed when surfing's allowed, but the caller resets it after checking the result bit 3: received Old Rod bit 4: received Good Rod bit 5: received Super Rod bit 6: gave one of the Saffron guards a drink bit 7: set by ItemUseCardKey, which is leftover code from a previous implementation of the Card Key
Defeated Gyms
Redundant because it matches Earned Badges used to determine whether to
show name on statue and in two NPC text scripts
Various Flags 2
Bit 0: if not set, the 3 minimum steps between random battles have passed Bit 1: prevent audio fade out
Various Flags 3
This variable is used for temporary flags and as the destination map when warping to the Trade Center or Colosseum. bit 0: sprite facing directions have been initialised in the Trade Center bit 3: do scripted warp (used to warp back to Lavender Town from the top of the Pokémon tower) bit 4: on a dungeon warp bit 5: don't make NPCs face the player when spoken to Bits 6 and 7 are set by scripts when starting major battles in the storyline, but they do not appear to affect anything. Bit 6 is reset after all battles and bit 7 is reset after trainer battles (but it's only set before trainer battles anyway).
Various Flags 4
bit 0: the player has received Lapras in the Silph Co. building bit 1: set in various places, but doesn't appear to have an effect bit 2: the player has healed Pokémon at a Pokémon center at least once bit 3: the player has a received a Pokémon from Prof. Oak bit 4: disable battles bit 5: set when a battle ends and when the player blacks out in the overworld due to poison bit 6: using the link feature bit 7: set if scripted NPC movement has been initialised
Various Flags 5
bit 0: NPC sprite being moved by script bit 5: ignore joypad input bit 6: print text with no delay between each letter bit 7: set if joypad states are being simulated in the overworld or an NPC's movement is being scripted
Various Flags 6
bit 0: play time being counted bit 1: remnant of debug mode? not set by the game code. if it is set 1. skips most of Prof. Oak's speech, and uses NINTEN as the player's name and SONY as the rival's name 2. does not have the player start in floor two of the player's house (instead sending them to Last Map) 3. allows wild battles to be avoided by holding down B bit 2: the target warp is a fly warp (bit 3 set or blacked out) or a dungeon warp (bit 4 set) bit 3: used warp pad, escape rope, dig, teleport, or fly, so the target warp is a "fly warp" bit 4: jumped into hole (Pokémon Mansion, Seafoam Islands, Victory Road) or went down waterfall (Seafoam Islands), so the target warp is a "dungeon warp" bit 5: currently being forced to ride bike (cycling road) bit 6: map destination is Last Blackout Map (usually the last used Pokémon center, but could be the player's house)
I will say don't get your hopes up with debug mode, it may work by setting it here given the timeline it loads the save data but the game may try to unset it since there are numerous measures in place particular when starting the game to ensure it's not set.
Various flags 7
bit 0: running a test battle bit 1: prevent music from changing when entering new map bit 2: skip the joypad check in CheckWarpsNoCollision (used for the forced warp down the waterfall in the Seafoam Islands) bit 3: trainer wants to battle bit 4: use variable Current Map Script instead of the provided index for next frame's map script (used to start battle when talking to trainers) bit 7: used fly out of battle
Defeated Lorelei
Bit 1: set when you beat Lorelei and reset in Indigo Plateau lobby, the game
uses this to tell when Elite 4 events need to be reset
Various Flags 8
bit 0: check if the player is standing on a door and make him walk down a step if so bit 1: the player is currently stepping down from a door bit 2: standing on a warp bit 6: jumping down a ledge / fishing animation bit 7: player sprite spinning due to spin tiles (Rocket hideout / Viridian Gym)
In-Game Trades
Bitset of completed in-game trades
Warped from warp/map
The warp or map you warped from
Card key door x/y
Unknown
First/Second Trash Can Lock
Lt. Surge Trash Can lock puzzle to battle surge, these are where the switches are located. It's unknown the data format or even if they'll regenerate upon reloading the game.
Completed Game Events
Bitfield of game events completed
Grass Rate
Wild Pokémon encounter rate for the "grass" areas of the game
Link Trainer
Unknown
Grass Pokémon
This is actually a 20 byte list of Wild Pokémon in order from most common to least common (Rarest) but the last 9 bytes cross-over into a shared space used for link battles using the game link since you're obviously not going to find wild battles there.
Link Data
Unknown
Enemy Party Count
How many Pokémon does the enemy have
Enemy Party Pokémon
Unknown since it's only 7 bytes. Perhaps the Species ID's
Water Rate
Chance of running into a wild Pokémon battle in the water areas of the current map.
Water Pokémon
Unknown since it's only 1 byte
Enemy partial party data
This follows the enemy partial party data structure
Trainer Header Pointer
Unknown
Opponent ID after wrong answer
The trainer the player must face after getting a wrong answer in the Cinnabar
gym quiz
Current Map Script
Index of current map script, mostly used as index for function pointer array
and mostly copied from map-specific map script pointer and written back later.
Playtime
Counts Hours, Minutes, Seconds, and Frames of playtime and includes a byte that determines whether the counter has hit the maximum time and therefore no longer counts. The maximum time countable is
- 255 Hours, 59 Minutes, 59 Seconds, and 59 Frames or
- 10 days, 15 hours, 59 minutes, 59 seconds, and 59 frames.
The maximum byte can be any number, if the game detects it's not zero it essentially disables the counter entirely. Internally the game sets it to 255 when the timer has reached the maximum count. Whatever value set here only effects enabling or disabling the playtime and is not calculated into the playtime.
Setting Minutes, Seconds, or Frames 60 or above will simply increment the next byte by 1 and reset the value. In other words setting seconds to 120 will only increment minutes by 1, not 2.
It's also important to note that the timer is always ticking even on the initial load/new game menu or when it's paused.
Safari Game Over
Safari Game over or not, the format and any further details are unknown
Safari Ball Count
Amount of Safari Balls the player has
Daycare
The daycare has 4 variables
- In-Use to determine if it's in use or not
- Pokémon Name following standard naming
- Original Trainer name - follow standard naming of the Original Trainer
- Pokémon - Pokémon stored in the daycare, just uses the Box Data format alone
Completed Scripts
The details aren't fully understood but for all areas of the game it covers the completed scripts and is possibly bit flags.
Offset | Size | Contents |
---|---|---|
0x289C | 0x1 | Oaks Lab |
0x289D | 0x2 | Palette Town |
0x289F | 0x1 | Rival's House |
0x28A0 | 0x3 | Viridian City |
0x28A3 | 0x1 | Pewter City |
0x28A4 | 0x1 | Route 3 |
0x28A5 | 0x2 | Route 4 |
0x28A7 | 0x1 | Viridian Gym |
0x28A8 | 0x1 | Pewter Gym |
0x28A9 | 0x1 | Cerulean Gym |
0x28AA | 0x1 | Vermilion Gym |
0x28AB | 0x1 | Celadon Gym |
0x28AC | 0x1 | Route 6 |
0x28AD | 0x1 | Route 8 |
0x28AE | 0x1 | Route 24 |
0x28AF | 0x1 | Route 25 |
0x28B0 | 0x1 | Route 9 |
0x28B1 | 0x1 | Route 10 |
0x28B2 | 0x1 | Mt. Moon 1 |
0x28B3 | 0x1 | Mt. Moon 3 |
0x28B4 | 0x1 | S.S. Anne 8 |
0x28B5 | 0x1 | S.S. Anne 9 |
0x28B6 | 0x2 | Route 22 |
0x28B8 | 0x1 | Player's House 2 |
0x28B9 | 0x1 | Viridian Market |
0x28BA | 0x1 | Route 22 Gate |
0x28BB | 0x8 | Cerulean City |
0x28C3 | 0x1 | S.S. Anne 5 |
0x28C4 | 0x1 | Viridian Forest |
0x28C5 | 0x1 | Museum 1 |
0x28C6 | 0x1 | Route 13 |
0x28C7 | 0x1 | Route 14 |
0x28C8 | 0x1 | Route 17 |
0x28C9 | 0x1 | Route 19 |
0x28CA | 0x1 | Route 21 |
0x28CB | 0x1 | Safari Zone Entrance |
0x28CC | 0x1 | Rock Tunnel 2 |
0x28CD | 0x2 | Rock Tunnel 1 |
0x28CF | 0x1 | Route 11 |
0x28D0 | 0x1 | Route 12 |
0x28D1 | 0x1 | Route 15 |
0x28D2 | 0x1 | Route 16 |
0x28D3 | 0x1 | Route 18 |
0x28D4 | 0x1 | Route 20 |
0x28D5 | 0x1 | S.S. Anne 10 |
0x28D6 | 0x1 | Vermilion City |
0x28D7 | 0x1 | Pokémon tower 2 |
0x28D8 | 0x1 | Pokémon tower 3 |
0x28D9 | 0x1 | Pokémon tower 4 |
0x28DA | 0x1 | Pokémon tower 5 |
0x28DB | 0x1 | Pokémon tower 6 |
0x28DC | 0x1 | Pokémon tower 7 |
0x28DD | 0x1 | Rocket Hideout 1 |
0x28DE | 0x1 | Rocket Hideout 2 |
0x28DF | 0x1 | Rocket Hideout 3 |
0x28E0 | 0x2 | Rocket Hideout 4 |
0x28E2 | 0x1 | Route 6 Gate |
0x28E3 | 0x2 | Route 8 Gate |
0x28E5 | 0x1 | Cinnabar Island |
0x28E6 | 0x2 | Mansion 1 |
0x28E8 | 0x1 | Mansion 2 |
0x28E9 | 0x1 | Mansion 3 |
0x28EA | 0x1 | Mansion 4 |
0x28EC | 0x2 | Victory Road 3 |
0x28EE | 0x1 | Fighting Dojo |
0x28EF | 0x1 | Silph Co 2 |
0x28F0 | 0x1 | Silph Co 3 |
0x28F1 | 0x1 | Silph Co 4 |
0x28F2 | 0x1 | Silph Co 5 |
0x28F3 | 0x1 | Silph Co 6 |
0x28F4 | 0x1 | Silph Co 7 |
0x28F5 | 0x1 | Silph Co 8 |
0x28F6 | 0x1 | Silph Co 9 |
0x28F7 | 0x1 | Hall of Fame Room |
0x28F8 | 0x1 | Rival |
0x28F9 | 0x1 | Lorelei |
0x28FA | 0x1 | Bruno |
0x28FB | 0x1 | Agatha |
0x28FC | 0x1 | Unknown Dungeon 3 |
0x28FD | 0x1 | Victory Road 1 |
0x28FF | 0x5 | Lance |
0x2904 | 0x1 | Silph Co 10 |
0x2905 | 0x2 | Silph Co 11 |
0x2907 | 0x1 | Fuchsia Gym |
0x2908 | 0x2 | Saffron Gym |
0x290A | 0x1 | Cinnabar Gym |
0x290B | 0x1 | Celadon Game Corner |
0x290C | 0x1 | Route 16 Gate |
0x290D | 0x1 | Bill's House |
0x290E | 0x1 | Route 5 Gate |
0x290F (U) | 0x2 | Power Plant |
0x290F (U) | 0x2 | Route 7 Gate |
0x2911 | 0x1 | S.S. Anne 2 |
0x2912 | 0x1 | Seafoam Islands 4 |
0x2913 | 0x1 | Route 23 |
0x2914 | 0x1 | Seafoam Islands 5 |
0x2915 | 0x1 | Route 18 Gate |
0x2916 | 0x78 | Padding |
0x2964 | 0x56 | Completed Scripts End Padding |
Sprite Data
Covers sprite data on map. To translate the offset to in-game memory and/or back simply use the difference number mentioned in the above table, 0x93D4.
This goes into quite a bit more detail than some of the other sprite data in Main Data.
These follow the Sprite Data Structure
Offset | Size | Contents | Amount |
---|---|---|---|
0x2D2C | 0x10 | Player | |
0x2D3C | 0xF0 | Sprite | 15 |
These follow the Sprite Extra Data Structure
Offset | Size | Contents | Amount |
---|---|---|---|
0x2E2C | 0x10 | Player | |
0x2E3C | 0xF0 | Sprite | 15 |
Party Data
Trainers current party. To translate the offset to in-game memory and/or back simply use the difference number mentioned in the above table, 0xA237.
Basically refer to the full party data structure
Offset | Size | Contents |
---|---|---|
0x2F2C | 0x194 | Party Data |
Current Box Data
a full byte-by-byte copy of the current box which is then loaded directly into memory every time for quick access. To translate the offset to in-game memory and/or back simply use the difference number mentioned in the above table, 0xA9C0.
Basically refer to the full box data structure
Offset | Size | Contents |
---|---|---|
0x30C0 | 0x462 | Box Data |
Normally, Pokémon are deposited and withdrawn from the Current Box data, which is within the checksum-validated region of the save data. When switching boxes, the data from the Current Box is copied to the corresponding PC Box data, then the data from the switched-to PC Box is transferred into the Current Box data.
Bank 2
This bank only contains boxes 1-6, when a box is selected its contents are copied and cached in bank 1. Think of bank 2 and 3 as warehouses where information is copied over to the more important areas when needed and only updated on save in case anything changed in the copied versions. Furthermore Bank 2 and 3 and completely 100% identical in structure.
Bank 2 and 3 have 2 different checksums, theres a whole-bank checksum similar to bank 1 that encompasses all used data on the bank and 6 individual checksums for the individual boxes data.
All Pokémon boxes follow the full box data structure
Bank 2 starts at address 0x4000 and is 0x2000 in size.
Offset | Size | Contents |
---|---|---|
0x4000 | 0x462 | Pokémon Box 1 |
0x4462 | 0x462 | Pokémon Box 2 |
0x48C4 | 0x462 | Pokémon Box 3 |
0x4D26 | 0x462 | Pokémon Box 4 |
0x5188 | 0x462 | Pokémon Box 5 |
0x55EA | 0x462 | Pokémon Box 6 |
0x5A4C | 0x1 | All Checksums |
0x5A4D | 0x6 | Individual Checksums |
0x5A53 | 0x5AD | Unused |
Unused
Unused here refers to data that the game completely does not touch in any way. Also none of the data is ever loaded from or saved to. The only way the game can ever be made to wipe or do anything to these areas is by invoking the hidden "Clear Save File" dialog manually yourself at the title screen.
Bank 3
This bank only contains boxes 7-12, when a box is selected its contents are copied and cached in bank 1. Think of bank 2 and 3 as warehouses where information is copied over to the more important areas when needed and only updated on save in case anything changed in the copied versions. Furthermore Bank 2 and 3 and completely 100% identical in structure.
Bank 2 and 3 have 2 different checksums, theres a whole-bank checksum similar to bank 1 that encompasses all used data on the bank and 6 individual checksums for the individual boxes data.
All Pokémon boxes follow the full box data structure
Bank 3 starts at address 0x6000 and is 0x2000 in size.
Offset | Size | Contents |
---|---|---|
0x6000 | 0x462 | Pokémon Box 7 |
0x6462 | 0x462 | Pokémon Box 8 |
0x68C4 | 0x462 | Pokémon Box 9 |
0x6D26 | 0x462 | Pokémon Box 10 |
0x7188 | 0x462 | Pokémon Box 11 |
0x75EA | 0x462 | Pokémon Box 12 |
0x7A4C | 0x1 | All Checksums |
0x7A4D | 0x6 | Individual Checksums |
0x7A53 | 0x5AD | Unused |
Unused
Unused here refers to data that the game completely does not touch in any way. Also none of the data is ever loaded from or saved to. The only way the game can ever be made to wipe or do anything to these areas is by invoking the hidden "Clear Save File" dialog manually yourself at the title screen.
Data Types
There are a few notable data types found in the save data, Unless otherwise noted, integer values occupy the specified number of bytes, and are big-endian and either unsigned or two's complement.
Text
Text data is stored in a proprietary encoding. Fixed-length user-input strings are terminated with 0x50. If a fixed-length string is terminated before using its full capacity, the contents of the remaining space are ignored and can be considered unused.
Hall of Fame
The Hall of Fame has an interesting data structure because it's the only Pokémon data structure that's so stripped down.
The game allocates space for 50 Hall of Fame Records, each record contains 6 entries for each Pokémon and each Pokémon entry contains 16 bytes. In code, it only uses the first 13 bytes out of 16 so it's assumed the last 3 are unused or padding.
Hall of Fame Structure
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x60 | Hall of Fame Records | 50 |
Hall of Fame Record Entry Structure
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x10 | Pokémon | 6 |
Hall of Fame Pokémon Structure
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Species ID | |
0x01 | 0x1 | Level | |
0x02 | 0xB | Pokémon Name | |
0x02 | 0x3 | Padding |
Lists
Lists have 3 parts to them, a count of list entries, the list entries themselves, and the list ending. If the list has a count of 0 then there won't be a list of entries and thus the list count will read 0 followed immediately by the terminator which is 0xFF
A list entry consists of 2 bytes, the item id and the amount of such item from 1-99.
List
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Count | |
0x01 | 0x2 | Entries | ...20 |
0x01 or <0x01 + 2 * Count> | 0x1 | End (0xFF) |
List Entry
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Index | |
0x01 | 0x1 | Amount |
Index refers to the item's index number.
Amount refers to the amount of the item that the player possesses and has valid values from 1 to 99.
Missable Lists
There is a varion of the standard list format above for the missable lists, it's the same as above only instead of id and amount it's instead id and index. Furthermore there's no count byte and thus there may not be a terminator byte. The details aren't fully understood beyond the list structure and it's found in only 1 place in the code within bank 1.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | ID | |
0x01 | 0x1 | Index |
Map Connection Entry
A great deal of various map information is stored within the Save Data, in 1 place there exists connection data for North, South, East, and West connecting maps where applicable.
Note: Maps can be a very complicated subject most especially when it comes to connecting maps. Instead the data structure will simply be presented as-is.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Map Pointer | |
0x01 | 0x2 | Strip Source | |
0x03 | 0x2 | Strip Destination | |
0x05 | 0x1 | Strip Width | |
0x06 | 0x1 | Connected Map Width | |
0x07 | 0x1 | Connected Map Y Align | |
0x08 | 0x1 | Connected Map X Align | |
0x09 | 0x2 | Connected Map View Pointer |
Sign Coordinates
Amongst the map information is a section to hold the locations of signs, this is the data format for that.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Y | |
0x01 | 0x1 | X |
Sprite Data
The save data has an entire section dedicated to the current state of the sprites on screen. Furthermore there are a couple of extra areas for sprites on the map noted further below. Here is the 2 structures found in the sprite section.
Note: Sprite Data is also a pretty complicated topic, and like maps, the data structure itself will just be given here.
Basic Sprite Data
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Picture ID | |
0x01 | 0x1 | Movement Status | |
0x02 | 0x1 | Image Index | |
0x03 | 0x1 | Y Step Vector | |
0x04 | 0x1 | Y Pixels | |
0x05 | 0x1 | X Step Vector | |
0x06 | 0x1 | X Pixels | |
0x07 | 0x1 | Intra Animation Frame Counter | |
0x08 | 0x1 | Animation Frame Counter | |
0x09 | 0x1 | Facing Direction | |
0x0A | 0x6 | Unused padding |
Extra Sprite Data
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Walk Animation Counter | |
0x01 | 0x1 | Unused padding | |
0x02 | 0x1 | Y Disp | |
0x03 | 0x1 | X Disp | |
0x04 | 0x1 | Map Y | |
0x05 | 0x1 | Map X | |
0x06 | 0x1 | Movement Byte | |
0x07 | 0x1 | Grass Priority | |
0x08 | 0x1 | Movement Delay | |
0x09 | 0x5 | Unused Padding | |
0x0E | 0x1 | Image Base Offset | |
0x0F | 0x6 | Unused padding |
Map Sprite Data
There are 2 kinds of sprite data structures the map uses, one for basic information and one for extended information. They're always side-by-side.
Sprite Basic Data Entry
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Movement | |
0x01 | 0x1 | Text ID |
Sprite Extended Data Entry
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Trainer Class or Item ID | |
0x01 | 0x1 | Trainer Set ID |
Pokémon
Pokémon data structures is quite large and comprehensive and there are actually 2 kinds of Pokémon data structures.
When a Pokémon is in a PC or in the Day Care (Since the Daycare follows the same PC Box data structure), it's given the base data structure which is 33 bytes and contains base information needed to calculate other information (To save space).
When you withdraw a Pokémon out of the PC that information is calculated and placed in an extended data structure that's a total of 44 bytes from the original 33 so it's immediately ready when needed. This calculated information gets destroyed when the Pokémon is placed back into the PC.
Lists of Pokémon in the save data follow the same basic format, but there are slight variations of the list that are found in the save data. These types differ in their maximum capacity and in the way they store the main Pokémon data.
- The player's party and has a capacity of 6 and uses the full Pokémon data structure (with a size of 44 bytes).
- A PC Box and has a capacity of 20 and uses a truncated version of the Pokémon data structure (only the first 33 bytes).
- The Daycare is treated as a single Pokémon capacity box and thus contains only the Pokémon Data structure and none of the "list" aspects to it.
Full Box Data
Pokémon Box Data Structures is sometimes used alone such as at the Daycare however when dealing with a PC that can handle 20 Pokémon per box, there is some additional data around that.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Pokémon Count | |
0x01 | 0x1 | Species ID | 20 |
0x15 | 0x1 | Unused Padding | |
0x16 | 0x21 | Pokémon Box Data | 20 |
0x2AA | 0xB | Original Trainer Names | 20 |
0x386 | 0xB | Pokémon Names | 20 |
Pokémon count This is the number of Pokémon entries actually being used in the list.
Species ID
This is a list of
species indexes for each
Pokémon in this list, 1 byte per index, with a 0xFF
terminator
following the last used entry in the list.
This list of species is used by the party screen and the PC's Box management interface.
Pokémon Box Data This is a list of Pokémon data structures for each Pokémon in this list, 44 or 33 bytes per index depending on if the whole list is for the party or a PC Box.
OT names
This is a list of text strings for the
Original Trainer of each Pokémon in this list, 11 bytes per name. Each name
can contain from 1 to 10 characters, terminated by 0x50
.
Name
Pokémon Nicknames is any name given to the Pokémon, if the name perfectly matches up with the species name (case-sensitive) it will be treated as if it had no nickname.
This is a list of text strings for the
name of each Pokémon in this list, 11 bytes per name. Each name can contain from
1 to 10 characters, terminated by 0x50
.
A Pokémon's name is a nickname if it does not perfectly match the default
name for a Pokémon (typically all uppercase) with any unused bytes of the
entry's 11-byte capacity filled with 0x50
terminators.
Full Party Data
This is exactly the same as the Full Box data but formatted for a party of up to 6.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Pokémon Count | |
0x01 | 0x1 | Species ID | 6 |
0x7 | 0x1 | Unused Padding | |
0x8 | 0x2C | Pokémon Party Data | 6 |
0x110 | 0xB | Original Trainer Names | 6 |
0x152 | 0xB | Pokémon Names | 6 |
Pokémon Party Data This is a list of Pokémon data structures for each Pokémon in this list, 44 or 33 bytes per index depending on if the whole list is for the party or a PC Box.
OT names
This is a list of text strings for the
Original Trainer of each Pokémon in this list, 11 bytes per name. Each name
can contain from 1 to 10 characters, terminated by 0x50
.
Name
Pokémon Nicknames is any name given to the Pokémon, if the name perfectly matches up with the species name (case-sensitive) it will be treated as if it had no nickname.
This is a list of text strings for the
name of each Pokémon in this list, 11 bytes per name. Each name can contain from
1 to 10 characters, terminated by 0x50
.
A Pokémon's name is a nickname if it does not perfectly match the default
name for a Pokémon (typically all uppercase) with any unused bytes of the
entry's 11-byte capacity filled with 0x50
terminators.
Partial Party Data
There does exist one area which features a stripped down full party data. It's mostly just missing much of the upper data.
Offset | Size | Contents | Amount |
---|---|---|---|
0x0 | 0x21 | Pokémon Party Data | 6 |
0xC6 | 0xB | Original Trainer Names | 6 |
0x108 | 0xB | Pokémon Names | 6 |
Pokémon Party Data This is a list of Pokémon data structures for each Pokémon in this list, 44 or 33 bytes per index depending on if the whole list is for the party or a PC Box.
OT names
This is a list of text strings for the
Original Trainer of each Pokémon in this list, 11 bytes per name. Each name
can contain from 1 to 10 characters, terminated by 0x50
.
Name
Pokémon Nicknames is any name given to the Pokémon, if the name perfectly matches up with the species name (case-sensitive) it will be treated as if it had no nickname.
This is a list of text strings for the
name of each Pokémon in this list, 11 bytes per name. Each name can contain from
1 to 10 characters, terminated by 0x50
.
A Pokémon's name is a nickname if it does not perfectly match the default
name for a Pokémon (typically all uppercase) with any unused bytes of the
entry's 11-byte capacity filled with 0x50
terminators.
Item Box
The PC Box for items follows the same rules as a regular list only instead of 20 items, it's space allotted for 50 items with 50 being the maximum count.
Offset | Size | Contents | Amount |
---|---|---|---|
0x00 | 0x1 | Count | |
0x01 | 0x2 | Entries | ...50 |
0x01 or <0x01 + 2 * Count> | 0x1 | End (0xFF) |
Credits
Massive credit goes to the Pokémon Red/Blue source code found here. Specifically 2 files greatly helped wram and sram. But several source code files needed to be referenced in the project for better understanding.
Much of the descriptions were also used from there and those 2 files.
Permission was directly obtained from the team and project admins for these references.
Apart from educational references to the project and the references descriptions all other content is completely original.
|
This data structure article is part of Project Games, a Bulbapedia project that aims to write comprehensive articles on the Pokémon games. |