Ocarina of time

From ZFGCpedia
Jump to: navigation, search

Ocarina of time saves are still a tad unknown however thanks to spinout i have this:

Info

The Ocarina of Time save file consists of a simple 32 byte long header, and six 5200 byte long game files, in the order 1,2,3/1,2,3. The header can be freely edited. The individual game files cannot however, as the game will reject them if they've been modified, unless the checksum is manually recalculated.

File Header

Offset Data Type Length Usage Additional Info
0x00 Sound Options
0x01 Z-Target Options 0 for Switch, 1 for Hold
0x07 String 5 Contains the text "ZELDA"
0x0C uint32_t 4 0xABABABAB if debug, 0x00000000 if 1.0U+ (may be different for J/E)

Game Data

After the file header, there are 6 different game files

RAM Offsets

The save data format seems to match up to a portion of ram in game. Therefore, it's possible to determine what the values stored in the save file do by peeking into the RAM in-game. You can also use this table, along with the following table, to generate cheat codes. Simply take the appropriate offset for your game (ex. 1.0 U, 11A5D0), take an offset from the following table (ex. Respawn Point, 0x0002), and add them together (11A5D2). Then prefix it with either 80 (modify 1 byte) or 81 (modify 2 bytes), and assign a value to it (ex. 8111A5D2 0000)

Save Data Relative to Ram
Debug E 1.0U 1.1U 1.2U 1.0E 1.1E
15E660 11A5D0 11A790 11AC80 1183D0 118410

Checksum

Each segment of game data has a 16 bit checksum at offset 0x1352. It is generated by adding all previous 0x9A9 shorts together (overflowing to 0 when 0xFFFF is reached).

Game Data Format

Offset Data Type Length Usage Additional Info
0x0002 uint16_t 2 Entrance index Stores the entrance Link starts/respawns at. See Debug ROM: Exit List for a listing of all values. If not inside a dungeon when loading a save from file, this value defaults back to either 00BB (Deku Tree) or 0053 (Temple of Time)
0x0004 uint32_t 4 Age Modifier 0 = Adult Link, 1 = Child Link
0x001C String 6 Unknown Contains the string "ZELDAZ". If different, the save will be considered corrupt even if the checksum is valid
0x0022 Short 2 Death Counter
0x0024 String 8 Player Name If the player name is less than 8 characters, the remaining char values will be DF. Charsets vary by language.
0x002C uint32_t 4 Heart containers 0x10 is equivalent to 1 heart container
0x0030? ??? 1-2? 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/erase attempt on a release build
0x0032 uint32_t 4 Health 0x10 is equivalent to 1 full heart
0x0036 uint32_t 4 Rupees
0x003A uint16_t 2 Some clock? Increments every cycle, unless the game is paused. Resets whenever a new map is loaded
0x0E64 32? 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 uint16_t Entrance Index Determines which scene Link is transported to. See Zelda 64 Scene Listings.
0x0E7F Map Number Determines which map of the scene to load
0x0E83 Warp Point Set 1 = Warp point set, 0 = unset.
0x1352 uint16_t 2 Checksum Checksum of previous 0x9A9 shorts (0x1352 bytes)

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;
}