Skip to main content

Generation 1 & 2 Save Files

Save file implementations for Game Boy Pokemon games (Red, Blue, Yellow, Gold, Silver, Crystal).

SAV1

Generation 1 save file object for Red, Blue, and Yellow versions.

Class Definition

public sealed class SAV1 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWorkArray<byte>, 
    IBoxDetailNameRead, IDaycareStorage
Source: PKHeX.Core/Saves/SAV1.cs

Storage Specifications

PropertyJapaneseInternational
Box Count812
Box Slot Count3020
Party Size66
Daycare Slots11

Key Properties

Version Detection

public bool Japanese { get; } // True for Japanese saves
public bool IsVirtualConsole { get; } // True if from Virtual Console
public string SaveRevisionString { get; } // "J" or "U" + "VC" or "GB"

Trainer Information

public override string OT { get; set; }
public override ushort TID16 { get; set; }
public override byte Gender { get; set; } // Always 0 (male)
public string Rival { get; set; }
public byte Starter { get; set; } // Starting Pokemon

Game Progress

public int Badges { get; set; } // Badge bitflags
public bool PlayedMaximum { get; set; } // 255:00:00.00 flag
public byte PlayedFrames { get; set; }
public byte GBPrinterBrightness { get; set; } // Yellow only

Currency

public override uint Money { get; set; } // Max: 999,999
public uint Coin { get; set; } // Max: 9,999
public uint PikaBeachScore { get; set; } // Yellow only

Special Features

// Yellow-specific
public byte PikaFriendship { get; set; }
public bool IsSilphLaprasReceived { get; set; }

// Hall of Fame
public HallOfFameReader1 HallOfFame { get; }
public byte HallOfFameCount { get; set; }

Event System

public int EventFlagCount { get; } // 2,560 flags
public int EventWorkCount { get; } // 256 work variables
public bool GetEventFlag(int flagNumber)
public void SetEventFlag(int flagNumber, bool value)
public byte GetWork(int index)
public void SetWork(int index, byte value)

Box Management

public override int CurrentBox { get; set; }
public bool BoxesInitialized { get; set; }
public string GetBoxName(int box) // Returns default names

SAV2

Generation 2 save file object for Gold, Silver, and Crystal versions.

Class Definition

public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWorkArray<byte>, 
    IBoxDetailName, IDaycareStorage, IDaycareEggState
Source: PKHeX.Core/Saves/SAV2.cs

Storage Specifications

PropertyJapaneseInternationalKorean
Box Count91414
Box Slot Count302020
Party Size666
Daycare Slots2 + Egg2 + Egg2 + Egg

Key Properties

Version Detection

public bool Japanese { get; }
public bool Korean { get; }
public bool IsVirtualConsole { get; }
public string SaveRevisionString { get; } // "J", "U", or "K" + "VC" or "GB"

Trainer Information

public override string OT { get; set; }
public string Rival { get; set; }
public override byte Gender { get; set; } // Crystal only
public byte Palette { get; set; }
public int Badges { get; set; } // 16-bit for both regions

Options

public bool BattleEffects { get; set; }
public bool BattleStyleSwitch { get; set; }
public int Sound { get; set; } // Stereo/Mono
public int TextSpeed { get; set; }
public int TextBoxFrame { get; set; }
public byte GBPrinterBrightness { get; set; }
public bool MenuAccountOn { get; set; }

Currency

public override uint Money { get; set; } // Max: 999,999
public uint Coin { get; set; } // Max: 9,999
public byte BlueCardPoints { get; set; } // Crystal only

Event System

public int EventFlagCount { get; } // 2,000 flags
public int EventWorkCount { get; } // 256 work variables
public bool GetEventFlag(int flagNumber)
public void SetEventFlag(int flagNumber, bool value)
public byte GetWork(int index)
public void SetWork(int index, byte value)

Daycare System

public int DaycareSlotCount { get; } // 2
public Memory<byte> GetDaycareSlot(int slot)
public Memory<byte> GetDaycareEgg()
public bool IsDaycareOccupied(int slot)
public void SetDaycareOccupied(int slot, bool occupied)
public bool IsEggAvailable { get; set; }

Pokedex - Unown Features

public int UnownUnlocked { get; set; } // Bitflags for letter groups
public void UnownUnlockAll() // Unlock all 4 groups
public bool UnownUnlocked0 { get; set; } // A-K
public bool UnownUnlocked1 { get; set; } // L-R
public bool UnownUnlocked2 { get; set; } // S-W
public bool UnownUnlocked3 { get; set; } // X-Z
public int UnownFirstSeen { get; set; } // Form shown in Pokedex

Box Management

public override int CurrentBox { get; set; }
public string GetBoxName(int box)
public void SetBoxName(int box, ReadOnlySpan<char> value)

Mystery Gift (Crystal)

public byte MysteryGiftItem { get; set; }
public bool IsMysteryGiftUnlocked { get; set; }
public void EnableGSBallMobileEvent() // Virtual Console feature
public bool IsEnabledGSBallMobileEvent { get; }

GB Mobile (Japanese Crystal)

public bool IsGBMobileAvailable { get; }
public bool IsGBMobileEnabled { get; }
public GBMobileCableColor GBMobileCable { get; set; }

Miscellaneous

public ushort ResetKey { get; } // Password for clock reset
public void ResetRTC() // Set "Time Not Set" flag
public void UnlockAllDecorations()

Technical Notes

String Handling

Both Gen 1 and Gen 2 use custom character encodings:
  • Gen 1: Uses StringConverter1 with special terminator handling
  • Gen 2: Uses StringConverter2 with ligature support (non-Korean)
  • Gen 2 Korean: Uses separate StringConverter2KOR

Data Storage

Gen 1 and Gen 2 use compressed list formats for Pokemon storage:
  • PokeList1: Gen 1 list packing/unpacking
  • PokeList2: Gen 2 list packing/unpacking
  • Stores species count, species list, then Pokemon data
  • Separate formats for box storage vs party storage

Checksums

  • Gen 1: Single 8-bit inverted sum checksum
  • Gen 2: Dual 16-bit checksums stored in two locations

Build docs developers (and LLMs) love