Save Format

From CloudModding OoT Wiki
Jump to: navigation, search

Basic Structure

Ocarina of Time comes with a 0x8000 byte SRAM unit for storing data.

Offset Size Description
0x0000 0x0020 Header Data
0x0020 0x1450 Primary File 1
0x1470 0x1450 Primary File 2
0x28C0 0x1450 Primary File 3
0x3D10 0x1450 Back-up File 1
0x5160 0x1450 Back-up File 2
0x65B0 0x1450 Back-up File 3

The back-up save files exist to prevent data loss in the event of an untimely power loss. When saving the game, the primary file will be written to first before the secondary back-up file, while when loading the game (done during the file select screen), the game will always attempt to load the primary save file before the back-up.

Header Data

Offset Data Type Usage Additional Info
0x00 byte Sound Options
0x01 byte Z-Target Options 0 for Switch, 1 for Hold
0x07 char[5]  ? Contains the string "ZELDA"
0x0C byte[5] Padding Commercial releases padded with 0x00, debug with 0xAB

RAM Offsets

Saves are created by simply copying a specific block of ram. Therefore, it's possible to determine what the values stored in the save file do by peeking into the RAM in-game instead of making multiple saves. To convert an offset from the start of the save file to a ram address, simply take the appropriate offset for your game (ex. 1.0 U, 11A5D0), and an offset from the following table (ex. Respawn Point, 0x0002), and add them together (11A5D2). To convert it into a cheat, prefix it with either 80 (modify 1 byte) or 81 (modify 2 bytes), and assign a value to it (ex. 8111A5D2 0000)

Location in Ram
Debug 8015E660
NTSC 1.0 8011A5D0
NTSC 1.1 8011A790
NTSC 1.2 8011AC80
PAL 1.0 801183D0
PAL 1.1 80118410
PAL MQ 80118938

Checksum

Each segment of game data has a 16 bit checksum at offset 0x1352. It is generated by adding all previous 0x9A9 shorts together, and simply allowing the count to roll over. Values located past the checksum are stored to sram but are not copied back when loading the save, and thus go unused.

Save File Data

code (File)
Save File Data
VersionOffsetVRomVRam
Debug10D68000BA1680?8012A4E0?
NTSC 1.00EAE6000B71E60?800FBF00?
NTSC 1.20EAE7000B71E70?800FC550?

In code, there's a structure that contains a collection of data relevant to file creation and management.

Offset Type Description
0000 u16[6] Save File Offsets
000C u32  ?
0013 struct New File Save Data (ZELDA)
00D8 struct Title Screen/Dev Test Save Data (ZELDAZ)
0190 u16[16] Either savewarp or death respawns (likely save warp)

At 106D93 in code (BA1693 in VROM), there is a string that says "ZELDA." This string is the start of a Default Save Data table, which allows the first few bytes of a save file to be written. This data is basically copied to a brand new save file. Using this, you can set certain flags, such as how much health you start with, how many keys you start with in each dungeon, etc.

Game Data Format

Offset Data Type Usage Additional Info
0x0000 int32 Entrance index Stores the entrance Link starts/respawns at. Check the Entrance Table for a listing of all values.
0x0004 int32 Age Modifier 0 = Adult Link, 1 = Child Link
0x000A int16 Cutscene Number Used to trigger cutscenes. Values FFF0 - FFFF trigger cutscenes 0-F.
0x000C int16 World Time Sets the current time for the world clock
0x0010 int32 Night Flag Denotes that it's night time.
0x001C char[6] Unknown Contains the string "ZELDAZ". If different, the save will be considered corrupt even if the checksum is valid
0x0022 int16 Death Counter
0x0024 char[8] Player Name If the player name is less than 8 characters, the remaining char values will be DF. NTSC and PAL use different character sets to represent player name.
0x002C int16 Disk Drive Only flag Setting to 1+ will flag the save as a Disk Drive only file. The file cannot be accessed normally (but can be forced), and will crash on copy attempt on a release build
0x002E int16 Heart containers 0x10 is equivalent to 1 heart container
0x0030 int16 Health 0x10 is equivalent to 1 full heart
0x0034 uint16_t Rupees
0x0035  ? Biggoron's Sword Flag #1 Set to 01 in conjunction with Biggoron's Sword Flag #2 to prevent having to do the Biggoron's Sidequest
0x0038 int16_t Navi Timer Increments every cycle, unless the game is paused. Resets whenever a new map is loaded when under a certain value
0x003E  ? Biggoron's Sword Flag #2
0x0066 int16 Saved Scene Index Only set on saving. Used to determine where to spawn when reloading a save.
0x0068 byte[7] Current Button Equips Stores what items are currently equipped to the buttons. Indexes 0x00-0x03 store B, C-Left, C-Down, C-Right item indexes in that order, while indexes 0x04-0x06 store the offset into the inventory that the C-Left/Down/Right equips are stored at.
0x0070 uint16 Currently Equipped Equipment & 0x000F = Swords
& 0x00F0 = Shields
& 0x0F00 = Tunics
& 0xF000 = Boots
0x0074 byte[24] Inventory Stores obtained items, from top left to bottom right.
0x008C byte[0xF] Item Amounts Stores ammo counts for inventory items, following the same order as the inventory slots. Thus, some are left unused
0x009B byte Magic Beans Bought Stores number of Magic Beans that have been bought by the Bean Seller
0x009C uint16 Obtained Equipment & 0x000F = Swords
& 0x0070 = Shields
& 0x0700 = Tunics
& 0x7000 = Boots
0x00A0 uint32 Obtained Equipment Deku Stick/Nut capacities, Dive Meter, Wallet, Bullet Bag, Quiver, Bomb Bag, Strength Upgrades
0x00A4 uint32 Quest Status Items
0x00A8 byte[0x14] Dungeon Items Indexed by the Scene Index. Each byte contains the following:
& 0x01 = Boss Key
& 0x02 = Compass
& 0x04 = Dungeon Map
0x00BC byte[0x14] Small Key Amounts Initialized to 0xFF to not display key icon
0x00CF byte Double Defense Hearts Sets how many hearts should be displayed as being "Double Defense" hearts.
0x00D0 int16 Gold Skulltula Tokens
0x00D4 struct[101] (0x1C bytes) Permanent Scene Flags Stores the permanent flags for all scenes. See below.
0x0E64 struct (0x20? bytes) Farore's Wind Warp If modifying values in-game, the warp point must be unloaded for the new values to take effect
0x0E64 long X Coordinate
0x0E68 long Y Coordinate
0x0E6B long Z Coordinate
0x0E72 short Y-Axis Rotation Direction that Link Faces on returning
0x0E7A int16 Entrance Index Determines which scene Link is transported to. See the Entrance Table.
0x0E7F Map Number Determines which map of the scene to load
0x0E83 Warp Point Set 1 = Warp point set, 0 = unset.
0x0ED4 uint16_t[14] event_chk_inf flags for various events (entrance cutscenes)
0x0EF0 uint16_t[4] item_get_inf likely flags for checking that certain items have been obtained for the first time
0x0EF8 uint16_t[30] inf_table unknown flags
0x1352 uint16_t Checksum Checksum of previous 0x9A9 shorts (0x1352 bytes)
0x1354 int32 File Index Save File Index. Valid values between 0 and 2 for files 1-3, 0xFF to prevent saving

Structs

Permanent Scene Flags

The structure for the scene related save data. Located at offset 0xD4 into the save file. Each record is 0x1C bytes long. There are 101 records, one for each scene.

offset type use description
0000 Int32 Chest Flags Set exclusively by chest actors. see actor list for setting this value
0004 Int32 Switches Stores most other other dungeon progression related flags such as locked doors, switches.
0008 Int32 Room Clear Flags Stores the room clear flags, preventing most enemies from spawning. One bit is reserved for each room, thus giving a limit of 32 rooms.
000C Int32 Collectible Flags Stores whether a particular collectable item (like Heart Containers, Key Item) has been obtained permanently
0010 Int32 Unused
0014 Int64 Visited Rooms Stores what rooms have been visited, for when displaying the map screen in dungeons.

Event Flags

Orange rows indicate bytes for which no event flags have (yet) been identified.

All event flags are implemented as an array of u16 values.

A byte value between 00-DF is used to access this set of flags. For example:

  • 00-07 flips a bit at offset 0ED5.
  • 08-0F flips a bit at offset 0ED4.

To figure out what byte is set, divide the flag by 0x10, drop remainder for later (for now), multiply by 2, and add 0ED4 to find the offset to the halfword our byte is in.

0xB5 / 0x10 = 0x0B
0x0B * 0x02 = 0x16
0x16 + 0ED4 = 0EEA

Then, divide the original flag by 10h again, keeping only the remainder, and add to the offset based on the following:

  • 00-07 = +1.
  • 08-0F = +0.
0xB5 % 0x10 = 0x05. Since 5 falls within 0-7, the modified byte is 0xEEB

Once you've found the right byte, figuring out the right bit is easy. Just take the right digit of the flag's value, divide it by 2 if it's larger than 7, giving you a value between 0 and 7

0 flips the rightmost bit (00 becomes 01)
1 flips the second rightmost bit (00 becomes 02)
2 flips the third rightmost bit (00 becomes 04) etc.

event_chk_inf

Offset Bit Number
7 6 5 4 3 2 1 0
0ED4 Met Deku Tree Played Saria's Song for Mido as Adult Took Blue Warp inside Deku Tree
0ED5 Deku Tree has given Emerald and Died Spoke to Saria After Deku Tree's Death Deku Tree Opened His Mouth Showed Mido Sword & Shield Complained About Mido to Saria Met Mido
0ED6 Destroyed the Royal Family's Tomb Spoke to Mido After Deku Tree's Death Rented Horse From Ingo Obtained Kokiri's Emerald Obtained Epona
0ED7 Great Deku Tree Is Dead Invited to Sing With Child Malon Met Child Malon at Ranch Talon Fled Hyrule Castle Woke up Talon Obtained Pocket Egg Met Ingo at Ranch before Talon returns Met Child Malon at Castle or Market
0ED8 Death Mountain Erupted
0ED9 Obtained Goron's Ruby Bombed Dodongo's Cavern Rock Barrier
0EDA Finished Nabooru Battle Began Nabooru Battle Jabu-Jabu Swallowed the Fish Opened Entrance to Zora's Domain Won the first Diving Game
0EDB Obtained Zora's Sapphire King Zora Moved Aside Obtained Ruto's Letter Spoke to your first Zora
0EDC Entered the Master Sword Chamber Caught by Hyrule Castle Guards Rainbow Bridge Built by Sages Opened the Door of Time Obtained Water Medallion Obtained Fire Medallion Obtained Forest Medallion
0EDD Pulled Master Sword First Time Obtained Ocarina of Time Obtained Zelda's Letter
0EDE Learned Song of Storms Learned Sun's Song Learned Zelda's Lullaby
0EDF Sheik Moves From Sword Pedestal Learned Nocturne of Shadow Learned Serenade of Water Learned Bolero of Fire Learned Minuet of Forest
0EE0 Spoke to Kaepora Gaebora Near Lost Woods Spoke to Talon After Saving Ranch Woke Talon in Kakariko House Lake Hylia's Water Level Is Restored Gerudo Archery Minigame
0EE1 Drained Well in Kakariko Village Sped Up Windmill With Song of Storms
0EE2 Began Ganondorf Battle
0EE3 Began Bongo Bongo Battle Began Barinade Battle Began Twinrova Battle Began Morpha Battle Began Volvagia Battle Began Phantom Ganon Battle Began King Dodongo Battle Began Gohma Battle
0EE4 Paid Back for Bunny Hood Paid Back for Spooky Mask Paid Back for Skull Mask Paid Back for Keaton Mask
0EE5 Bridge Unlocked (After Zelda Escape Cutscene) Zelda Fled Hyrule Castle
0EE6 Played Song for Scarecrow as Adult
0EE7 Started Gold Skulltula Collection Quest Nabooru Captured by Twinrova Met Nabooru in Spirit Temple Rescued Green Carpenter Rescued Blue Carpenter Rescued Yellow Carpenter Rescued Red Carpenter
0EE8 Completed Spirit Trial Learned Requiem of Spirit Saw Shadow Spirit in Kakariko Learned Song of Time Entered Deku Tree
0EE9 Entered Temple of Time Entered Goron City Entered Hyrule Castle Entered Zora's Domain Entered Kakariko Village Entered Death Mountain Trail Entered Hyrule Field
0EEA Completed Light Trial Completed Fire Trial Completed Shadow Trial Completed Water Trial Completed Forest Trial Entered Ganon's Castle (Exterior) Entered Death Mountain Crater Entered Desert Colossus
0EEB Entered Zora's Fountain Entered Graveyard Entered Jabu-Jabu's Belly Entered Lon Lon Ranch Entered Gerudo's Fortress Entered Gerudo Valley Entered Lake Hylia Entered Dodongo's Cavern
0EEC Returned to Temple of Time Obtained Spirit Medallion
0EED Watched Tower Collapse / 1st Jailed by Gerudo Met & Spoke to Deku Tree Sprout Returned to Temple of Time by Rauru Returned to Temple of Time with all Medallions Ganon's Tower Barrier Dispelled Bid Farewell to Saria Twinrova Commands Nabooru to Fight
0EEE Obtained Skulltula House Heart Piece Obtained Skulltula House Bombchu Obtained Giant's Wallet Obtained Stone of Agony Obtained Adult's Wallet
0EEF Played Song of Storms for Frogs Played Song of Time for Frogs Played Saria's Song for Frogs Played Sun's Song for Frogs Played Epona's Song for Frogs Played Zelda's Lullaby for Frogs Obtained Frogs' Butterfly Heart Piece

item_get_inf

Offset Bit Number
7 6 5 4 3 2 1 0
0EF0 Obtained Gerudo Quiver Upgrade Obtained Kakariko Quiver Upgrade Obtained Bottle From Cucco Lady Obtained Heart Piece From Grotto Scrub Bought Upper-Left Bombchu (Right Shelf) Bought Lower-Left Bombchu (Left Shelf) Bought Upper-Right Bombchu (Left Shelf)
0EF1 Bought Lower-Right Bombchu (Right Shelf) Bought Lower-Left Bombchu (Right Shelf) Bought Upper-Left Bombchu (Left Shelf) Bought Lower-Right Bombchu (Left Shelf) Bought Upper-Right Bombchu (Right Shelf) Super Cucco Milk Bottle
0EF2 Obtained Stage Deku Nut Upgrade Obtained Stage Deku Stick Upgrade Obtained Deku Seed Bag Upgrade Obtained Nayru's Love Obtained Din's Fire Obtained Farore's Wind
0EF3 Obtained Heart Piece From Skullkids Obtained Heart Piece From Skullkid Obtained Heart Piece From Man on Roof Item – Deku Seeds Obtained Heart Piece From Lake Researcher
0EF4 Obtained Cojiro From Cucco Lady Obtained Pocket Egg From Cucco Lady Obtained Mask of Truth
0EF5 Obtained Bunny Hood Obtained Spooky Mask Obtained Skull Mask Obtained Keaton Mask
0EF6 Obtained Mask of Truth Sold Bunny Hood / Unlocked Extra Masks Sold Spooky Mask / Unlocked Bunny Hood Sold Skull Mask / Unlocked Spook Mask Sold Keaton Mask / Unlocked Skull Mask
0EF7 Obtained Poacher's Saw From Fado Obtained Odd Potion From Granny

inf_table

Offset Bit Number
7 6 5 4 3 2 1 0
0EF8 Met Mido
0EF9 Spoke to Saria in Saria's House Complained About Mido to Saria Spoke to Saria About Obtaining a Fairy Greeted by Saria
0EFA Spoke to Kokiri Girl by Jumping Stones Told Mido Saria Won't Return
0EFB Met Mido in Lost Woods as Adult
0EFC Spoke to Girl About Training Center
0EFD Spoke to Kokiri Girl on Shop Awning Spoke to Kokiri Boy Pulling Grass Spoke to Kokiri Boy Guarding Forest Exit
0EFE
0EFF Spoke to Boy on Bed in Mido's House
0F00
0F01
0F02 Spoke to Know-It-All Bro. About Temple
0F03 Spoke to Girl in Saria's House
0F04 Spoke to Dying Knight
0F05 Spoke to Deku Tree Sprout once (after cutscene) Spoke to Know-It-All Bro. About Saria
0F06 Spoke to Talon in Lon Lon Ranch House
0F07 Soldier Wears Keaton Mask Spoke to Gate Guard About Mask Shop
0F08 Entered Hyrule Castle
0F09 Child Malon Said Epona Was Scared of You Met Child Malon at Castle or Market
0F0A Spoke to Ingo Once as Adult
0F0B Met Ingo at Ranch Met Ingo at Ranch before Talon returns
0F0C Rode any horse at Ingo's Ranch
0F0D
0F0E Spoke to Carpenter Boss by Tent Spoke to Fado in Kokiri Forest as Child Spoke to Malon After Saving Ranch
0F0F Spoke to Fado at the start of the game Met Poe Collector in Ruined Market Met Medigoron as Adult Met Medigoron as Child
0F10 Spoke to Thin Lady After Zelda's Escape (DBG) Spoke to Blue Jokester in Market (DBG) Spoke to Itchy Lady after Malon leaves town Spoke to Blue Jokester in Market (1.0) / Dog Lady as Adult (DBG) Spoke to Red Jokester in Market Spoke to Thin Lady After Zelda's Escape (1.0) Spoke to Thin Lady by Bombchu Bowling
0F11 Spoke to Old Man by Bombchu Bowling Spoke to Old Woman by Market Fountain Spoke to Thin Man by Market Target Shop Spoke to Thief After Zelda's Escape Spoke to Burly Man After Zelda's Escape Spoke to Burly Man About Talon Search Spoke to Fat Woman After Zelda's Escape Spoke to Fat Woman by Market Potion Shop
0F12
0F13
0F14 Spoke to Goron by Bomb Flowers
0F15 Spoke to Goron by Woods Exit Spoke to Goron Hiding Stick Spoke to Goron at Cavern
0F16
0F17 Spoke to Ruby-Crazy Goron Spoke to Goron at Entrance
0F18 Spoke to Goron Link Stopped Goron Link's Rolling Spoke to Goron Link About Volvagia Obtained Fire Tunic from Goron Link
0F19
0F1A Received Goron City Bomb Bag Upgrade Met Darunia in Fire Temple
0F1B Met Darunia in Goron City
0F1C Spoke to Zora Swimming Behind Zora Shop Spoke to Zora Beside Zora Shop?
0F1D Spoke to Zora near Zora Shop
0F1E Obtained Zora Tunic Thawed King Zora
0F1F
0F20
0F21 Ruto in JJ, Spawns on F1 instead of B1 Ruto in JJ (M6) Kidnapped Ruto in JJ (M6) On Sapphire platform Ruto in JJ (?) wants to be thrown to Sapphire Ruto in JJ (M10) Can Be Escorted Ruto in JJ (M3) Talk First Time Ruto in JJ (M2) Meet Ruto Ruto in JJ (M7) On Blue Switch
0F22
0F23
0F24 Refused Nabooru
0F25 Spoke to Carpenter Boss's Wife as Adult Spoke to Carpenter Boss's Wife as Child Spoke to Man in Impa's as Adult Spoke to Man in Impa's at Night Spoke to Man in Impa's in Day
0F26 Running Man Suggested a Race Spoke to Green Carpenter in Tent
0F27 Spoke to Blue Carpenter in Tent Spoke to Carpenter Boss in Kakariko Spoke to Carpenter Boss in Valley
0F28
0F29
0F2A Caught Cucco Behind Potion Shop Caught Cucco Near Skulltula House Caught Cucco in Crate Caught Cucco Behind Windmill Caught Cucco Near Cucco Pen Caught Cucco Near Bazaar Caught Cucco Near Hyrule Field Entrance Get Magic Container
0F2B Spoke to Cursed Man With 10 Tokens Met Cursed Man in Skulltula House Obtained Grotto Deku Nut Upgrade Obtained Lost Woods Deku Stick Upgrade Obtained Heart Piece for Finding Richard Gerudo Archery Heart Piece
0F2C Entered Ganon's Castle (Collapsing) Entered Ganon's Tower (Collapsing) Entered Ganon's Castle Entered Thieves' Hideout Entered Gerudo Training Ground Entered Ganon's Tower Entered Ice Cavern Entered Bottom of the Well
0F2D Entered Shadow Temple Entered Spirit Temple Entered Water Temple Entered Fire Temple Entered Forest Temple Entered Jabu-Jabu's Belly Entered Dodongo's Cavern Entered Deku Tree
0F2E
0F2F
0F30
0F31
0F32 (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword)
0F33 (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) (Reset upon acquiring sword) Swordless (Master Sword Knocked Away)

C structs/functions

Beware of endianess! Big endian (N64 native) assumed.

#define	LINK_ADULT	0
#define LINK_CHILD	1

typedef struct
{
    uint32_t	respawn_exit_n;	/* 0x0004 */
    uint32_t	age;		/* 0x0008 */
    uint8_t	__pad_00[0x014];/* 0x001C */
    char	str[5];		/* 0x0021   "ZELDA" in created file */
    uint8_t	__pad_01[0x001];/* 0x0022 */
    uint16_t	death_count;	/* 0x0024 */
    uint8_t	name[8];	/* 0x002C Special char encoding */
    uint8_t     __pad_02[0x006];/* 0x0032 */
    uint32_t    rupee_count;    /* 0x0036 */
    uint8_t	__pad_03[0x002];/* 0x0038 */
    uint16_t	scene_count;	/* 0x003A May be uint32_t */
    uint8_t	__pad_04[0xE2A];/* 0x0E64 */
    struct
    {
    	float		x, y, z;	/* 0x0E70 */
    	uint16_t	y_rot;		/* 0x0E72 */
    	uint8_t		__pad_00[0x8];	/* 0x0E7A */
    	uint16_t	scene_no;	/* 0x0E7C */
    	uint32_t	map_no;		/* 0x0E80 */
    	uint32_t	isset;		/* 0x0E84 */
    }
    farore_warp;
    uint8_t	__pad_05[0x4CE];/* 0x1352 */
    uint16_t	chksum;		/* 0x1354 */
    uint8_t	__pad_06[0x0FC];/* 0x1540 */
}
z_save_file;

typedef struct
{
    uint8_t sound_opt;
    uint8_t ztarget_opt;
    char tag[5]; /* "ZELDA" (not null terminated) */
    z_save_file files[3];
}
z_save;

void
calc_chksum( z_save_file *f )
{
    int16_t *data = (int16_t*)(f);
    int sum = 0;
    int i;
    
    f->chksum = 0;

    for( i = 0; i < 0x9A9; i++ )
    {
        sum += data[i];
        sum &= 0xFFFF;
    }
    
    f->chksum = (uint16_t)sum;
}