Hey! Pikmin save file

From Pikmin Technical KB

This article is a stub.

The file format for a Hey! Pikmin saved game. Note: this comes from analyses of the .sav files generated by Citra.

Format[edit | edit source]

The save data is split into several blocks that start with 4-byte magic words.

SAVE[edit | edit source]

Offset Length Field Notes
File Block
0x0000 0x0000 4 bytes Block magic word Always SAVE.
0x000C 0x000C 4 bytes Save data checksum Calculated using this method.

NEWS[edit | edit source]

What "news" the player has seen. "News" are the cutscenes that take place inside the S.S. Dolphin II, where the ship explains something to Olimar.

Offset Length Field Notes
File Block
0x0010 0x0000 4 bytes Block magic word Always NEWS.
0x0014 0x0004 4 bytes Unknown
0x0018 0x0008 4 bytes Unknown news controller 1 0 when the player hasn't heard the news about 1-A yet, 1 when they have.
0x001C 0x000C 4 bytes Unknown news controller 2 0 when the player hasn't heard the news about 1-A yet, 8 when they have.

OPTI[edit | edit source]

The player's preferences in the options menu.

Offset Length Field Notes
File Block
0x0020 0x0000 4 bytes Block magic word Always OPTI.
0x0024 0x0004 4 bytes Unknown[unsure]
0x0028 0x0008 1 byte Music volume 0 to 3.
0x0029 0x0009 1 byte Sound effects volume 0 to 3.
0x002A 0x000A 2 bytes Unknown[unsure]

PBUF[edit | edit source]

Offset Length Field Notes
File Block
0x002C 0x0000 4 bytes Block magic word Always PBUF.

PARK[edit | edit source]

Offset Length Field Notes
File Block
0x0080 0x0000 4 bytes Block magic word Always PARK.

MINI[edit | edit source]

Offset Length Field Notes
File Block
0x04A4 0x0000 4 bytes Block magic word Always MINI.

CRNT[edit | edit source]

Offset Length Field Notes
File Block
0x0588 0x0000 4 bytes Block magic word Always CRNT.

GAME[edit | edit source]

Offset Length Field Notes
File Block
0x09A8 0x0000 4 bytes Block magic word Always GAME.
0x09AC 0x0004 4 bytes Unknown[unsure]
0x09B0 0x0008 4 bytes Sparklium total Values over 99999 will make the game assume it's just 99999
0x09B4 0x000C 44 bytes Unknown[unsure]

EVNT[edit | edit source]

Offset Length Field Notes
File Block
0x09E0 0x0000 4 bytes Block magic word Always EVNT.

HELP[edit | edit source]

Offset Length Field Notes
File Block
0x0AE8 0x0000 4 bytes Block magic word Always HELP.

RINF[edit | edit source]

Offset Length Field Notes
File Block
0x0BF0 0x0000 4 bytes Block magic word Always 0xRINF.

RSLT[edit | edit source]

Offset Length Field Notes
File Block
0x0C2C 0x0000 4 bytes Block magic word Always RSLT.

SPER[edit | edit source]

Offset Length Field Notes
File Block
0x0C38 0x0000 4 bytes Block magic word Always SPER.

STRE[edit | edit source]

Offset Length Field Notes
File Block
0x0C48 0x0000 4 bytes Block magic word Always STRE.

PLRP[edit | edit source]

Offset Length Field Notes
File Block
0x0C90 0x0000 4 bytes Block magic word Always PLRP.

DATE[edit | edit source]

Time at which the save was made.

Offset Length Field Notes
File Block
0x0CE0 0x0000 4 bytes Block magic word Always DATE.
0x0CE4 0x0004 8 bytes Unknown[unsure]
0x0CEC 0x000C 1 byte Month 1 to 12.
0x0CED 0x000D 1 byte Day 1 to 31.
0x0CEE 0x000E 1 byte Hours 0 to 23.
0x0CEF 0x000F 1 byte Minutes 0 to 59.
0x0CF0 0x0010 1 byte Seconds 0 to 59.
0x0CF1 0x0011 11 bytes Unknown[unsure]

TTDS[edit | edit source]

Offset Length Field Notes
File Block
0x0CFC 0x0000 4 bytes Block magic word Always TTDS.

WMAP[edit | edit source]

Offset Length Field Notes
File Block
0x0D08 0x0000 4 bytes Block magic word Always WMAP.

SAMI[edit | edit source]

Offset Length Field Notes
File Block
0x0D80 0x0000 4 bytes Block magic word Always SAMI.

Checksum[edit | edit source]

The checksum seems to be a CRC32 of the 0xd87 bytes that follow after the checksum (i.e. just one byte short of the entire remaining data), with crc32 as implemented by e.g. zlib.

The following python code can recalculate the checksum if the data after the checksum is modified:

import struct
from zlib import crc32

filepath = "radish0.sav"  # put the script in the same folder as the save file
with open(filepath, "rb") as f:
    header = f.read(0xC)
    chksum = struct.unpack("I", f.read(4))[0]
    
    data = f.read()

calculated_chksum = crc32(data[0:0xd87])
with open(filepath, "wb") as f:
    f.write(header)
    f.write(struct.pack("I", calculated_chksum))
    f.write(data)

Tools[edit | edit source]