Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pret/pokeemerald/llms.txt

Use this file to discover all available pages before exploring further.

pokeemerald saves to a 128 KB flash chip organized as 32 sectors of 4 KB each. The save system rotates between two save slots for corruption protection and stores trainer data, bag contents, Pokémon party, PC storage, Hall of Fame records, and more.

Flash layout

The 32 sectors are divided into fixed-purpose regions. Sector numbers are defined in include/save.h.
Sector(s)ConstantContents
0SECTOR_ID_SAVEBLOCK2SaveBlock2 — trainer info, options, Pokédex
1–4SECTOR_ID_SAVEBLOCK1_STARTSECTOR_ID_SAVEBLOCK1_ENDSaveBlock1 — current map, bag, money, etc.
5–13SECTOR_ID_PKMN_STORAGE_STARTSECTOR_ID_PKMN_STORAGE_ENDPC Pokémon storage (boxes 1–9)
14–27(Save Slot 2 mirror of 0–13)Alternating save slot for corruption recovery
28–29SECTOR_ID_HOF_1 / SECTOR_ID_HOF_2Hall of Fame records
30SECTOR_ID_TRAINER_HILLTrainer Hill data
31SECTOR_ID_RECORDED_BATTLERecorded Battle data
SECTORS_COUNT = 32; NUM_SECTORS_PER_SLOT = 14.

Sector structure

Each 4 KB sector is split into a data region and a footer:
struct SaveSector
{
    u8  data[SECTOR_DATA_SIZE];          // 3968 bytes of save data
    u8  unused[SECTOR_FOOTER_SIZE - 12]; // unused footer padding
    u16 id;                              // sector identifier
    u16 checksum;                        // XOR checksum of data
    u32 signature;                       // must equal SECTOR_SIGNATURE
    u32 counter;                         // incremented on each write
}; // total: SECTOR_SIZE (0x1000 = 4096 bytes)
Key constants from include/save.h:
ConstantValueMeaning
SECTOR_DATA_SIZE3968Usable data bytes per sector
SECTOR_FOOTER_SIZE128Footer size in bytes
SECTOR_SIGNATURE0x8012025Magic number that marks a valid sector
NUM_SAVE_SLOTS2Number of alternating save slots
The game uses approximately 96% of available flash capacity. SaveBlock1 has roughly 84 bytes of headroom and SaveBlock2 has roughly 120 bytes before you must reorganize the sector layout.

Dual-slot rotation

NUM_SAVE_SLOTS = 2. Sectors 0–13 are Save Slot 1 and sectors 14–27 are Save Slot 2. On every normal save the game writes to the slot with the lower counter value. If a write is interrupted the other slot still holds a valid copy, preventing total save loss.
// Save Slot 1: sectors  0-13
// Save Slot 2: sectors 14-27
#define NUM_SECTORS_PER_SLOT 14

Save types

enum
{
    SAVE_NORMAL,                    // standard in-game save
    SAVE_LINK,                      // Link / Battle Frontier save
    SAVE_EREADER,                   // deprecated in Emerald
    SAVE_HALL_OF_FAME,              // writes HOF sectors only
    SAVE_OVERWRITE_DIFFERENT_FILE,  // overwrites without slot check
    SAVE_HALL_OF_FAME_ERASE_BEFORE  // unused
};

Save status codes

ConstantValueMeaning
SAVE_STATUS_EMPTY0No save data found
SAVE_STATUS_OK1Save loaded successfully
SAVE_STATUS_CORRUPT2Checksum or signature mismatch
SAVE_STATUS_NO_FLASH4Flash chip not detected
SAVE_STATUS_ERROR0xFFUnrecoverable error
The current status is stored in gSaveFileStatus (extern u16 gSaveFileStatus).

Key functions

FunctionSignatureDescription
TrySavingDatau8 TrySavingData(u8 saveType)Attempts a full save; returns SAVE_STATUS_*
LoadGameSaveu8 LoadGameSave(u8 saveType)Reads save data from flash into RAM
HandleSavingDatau8 HandleSavingData(u8 saveType)Lower-level save dispatcher
WriteSaveBlock2bool8 WriteSaveBlock2(void)Writes only the SaveBlock2 sector
WriteSaveBlock1Sectorbool8 WriteSaveBlock1Sector(void)Writes one sector of SaveBlock1 incrementally
ClearSaveDatavoid ClearSaveData(void)Erases all save sectors
TryReadSpecialSaveSectoru32 TryReadSpecialSaveSector(u8 sector, u8 *dst)Reads HOF / Trainer Hill / Recorded Battle sectors
TryWriteSpecialSaveSectoru32 TryWriteSpecialSaveSector(u8 sector, u8 *src)Writes to a special sector
For link-cable trades and the Battle Frontier, SaveBlock1 is written incrementally across multiple frames using a task:
bool8 LinkFullSave_Init(void);
bool8 LinkFullSave_WriteSector(void);
bool8 LinkFullSave_ReplaceLastSector(void);
bool8 LinkFullSave_SetLastSectorSignature(void);
void  Task_LinkFullSave(u8 taskId);
Do not expand SaveBlock1 or SaveBlock2 beyond their headroom without updating gRamSaveSectorLocations and auditing every sector’s size field. Exceeding SECTOR_DATA_SIZE (3968 bytes) per sector silently truncates data.

Build docs developers (and LLMs) love