Editing Hey! Pikmin save file

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 3: Line 3:
  
 
== Format ==
 
== Format ==
The save data is split into several blocks that start with 4-byte magic words. The blocks are ordered in the same order they are presented in this article.
+
The save data is split into several blocks that start with 4-byte magic words.
  
 
=== SAVE ===
 
=== SAVE ===
Line 11: Line 11:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0000</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SAVE</code>.
+
| <code>0000</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAVE</code>.
 
|-
 
|-
| <code>0x000C</code> || <code>0x000C</code> || 4 bytes || Save data checksum || Calculated using [[#Checksum|this method]].
+
| <code>000C</code> || <code>000C</code> || 4 bytes || Save data checksum || {{unsure|Calculated using an unknown algorithm.}}
 
|}
 
|}
  
 
=== NEWS ===
 
=== NEWS ===
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.
 
 
{| class="wikitable sortable"
 
{| class="wikitable sortable"
 
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes
 
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes
Line 23: Line 22:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0010</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>NEWS</code>.
+
| <code>0010</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>NEWS</code>.
 
|-
 
|-
| <code>0x0014</code> || <code>0x0004</code> || 4 bytes || Unknown ||
 
|-
 
| <code>0x0018</code> || <code>0x0008</code> || 4 bytes || Unknown news controller 1 || 0 when the player hasn't heard the news about 1-A yet, 1 when they have.
 
|-
 
| <code>0x001C</code> || <code>0x000C</code> || 4 bytes || Unknown news controller 2 || 0 when the player hasn't heard the news about 1-A yet, 8 when they have.
 
 
|}
 
|}
  
Line 39: Line 33:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0020</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>OPTI</code>.
+
| <code>0020</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>OPTI</code>.
 
|-
 
|-
| <code>0x0024</code> || <code>0x0004</code> || 4 bytes || {{unknown|Unknown}} ||  
+
| <code>0024</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>0x0028</code> || <code>0x0008</code> || 1 byte || Music volume || 0 to 3.
+
| <code>0028</code> || <code>0008</code> || 1 byte || Music volume || <code>00</code> to <code>03</code>.
 
|-
 
|-
| <code>0x0029</code> || <code>0x0009</code> || 1 byte || Sound effects volume || 0 to 3.
+
| <code>0029</code> || <code>0009</code> || 1 byte || Sound effects volume || <code>00</code> to <code>03</code>.
 
|-
 
|-
| <code>0x002A</code> || <code>0x000A</code> || 2 bytes || {{unknown|Unknown}} ||  
+
| <code>002A</code> || <code>000A</code> || 2 bytes || {{unknown|Unknown}} ||  
 
|}
 
|}
  
 
=== PBUF ===
 
=== PBUF ===
Which log entries the player has unlocked, and which they have read.
 
 
{| class="wikitable sortable"
 
{| class="wikitable sortable"
 
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes
 
! colspan="2" | Offset || rowspan="2" | Length || rowspan="2" | Field || rowspan="2" | Notes
Line 57: Line 50:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x002C</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PBUF</code>.
+
| <code>002C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PBUF</code>.
|-
 
| <code>0x0030</code> || <code>0x0004</code> || 4 bytes || Unknown || Messing with it can make the save file be recognized as empty in the title screen.
 
|-
 
| <code>0x0034</code> || <code>0x0008</code> || 36 bytes || Unlocked entries bitfield || The first 11 bits correspond to the Pikmin Logs category (blue pellet, red pellet, rock pellet, winged pellet, yellow pellet, Onion, Red Pikmin, Blue Pikmin, Yellow Pikmin, Rock Pikmin, Winged Pikmin). After that come the enemies, normal treasures, and amiibo treasures, but their order is all over the place.
 
|-
 
| <code>0x0058</code> || <code>0x002C</code> || 4 bytes || Read "Pikmin Logs" entries bitfield ||
 
 
|-
 
|-
| <code>0x005C</code> || <code>0x0030</code> || 36 bytes || Read entries from the other categories bitfield ||
 
 
|}
 
|}
  
Line 74: Line 60:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0080</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PARK</code>.
+
| <code>0080</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PARK</code>.
 
|-
 
|-
 
|}
 
|}
Line 84: Line 70:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x04A4</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>MINI</code>.
+
| <code>04A4</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>MINI</code>.
 
|-
 
|-
 
|}
 
|}
Line 94: Line 80:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0588</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>CRNT</code>.
+
| <code>0588</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>CRNT</code>.
 
|-
 
|-
 
|}
 
|}
Line 104: Line 90:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x09A8</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>GAME</code>.
+
| <code>09A8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>GAME</code>.
 
|-
 
|-
| <code>0x09AC</code> || <code>0x0004</code> || 4 bytes || {{unknown|Unknown}} ||  
+
| <code>09AC</code> || <code>0004</code> || 4 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>0x09B0</code> || <code>0x0008</code> || 4 bytes || Sparklium total || Values over 99999 will make the game assume it's just 99999
+
| <code>09B0</code> || <code>0008</code> || 4 bytes || Sparklium total || Values over 99999 will make the game assume it's just 99999
 
|-
 
|-
| <code>0x09B4</code> || <code>0x000C</code> || 44 bytes || {{unknown|Unknown}} ||  
+
| <code>09B4</code> || <code>000C</code> || 44 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
 
|}
 
|}
Line 120: Line 106:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x09E0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>EVNT</code>.
+
| <code>09E0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>EVNT</code>.
 
|-
 
|-
 
|}
 
|}
Line 130: Line 116:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0AE8</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>HELP</code>.
+
| <code>0AE8</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>HELP</code>.
 
|-
 
|-
 
|}
 
|}
Line 140: Line 126:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0BF0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>RINF</code>.
+
| <code>0BF0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RINF</code>.
 
|-
 
|-
 
|}
 
|}
Line 150: Line 136:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0C2C</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>RSLT</code>.
+
| <code>0C2C</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>RSLT</code>.
 
|-
 
|-
 
|}
 
|}
Line 160: Line 146:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0C38</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SPER</code>.
+
| <code>0C38</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SPER</code>.
 
|-
 
|-
 
|}
 
|}
Line 170: Line 156:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0C48</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>STRE</code>.
+
| <code>0C48</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>STRE</code>.
 
|-
 
|-
 
|}
 
|}
Line 180: Line 166:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0C90</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>PLRP</code>.
+
| <code>0C90</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>PLRP</code>.
 
|-
 
|-
 
|}
 
|}
Line 192: Line 178:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0CE0</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>DATE</code>.
+
| <code>0CE0</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>DATE</code>.
|-
 
| <code>0x0CE4</code> || <code>0x0004</code> || 4 bytes || {{unknown|Unknown}} ||
 
 
|-
 
|-
| <code>0x0CE8</code> || <code>0x0008</code> || 4 bytes || Year || Human format. For instance, 2019 has the actual value "2019".
+
| <code>0CE4</code> || <code>0004</code> || 8 bytes || {{unknown|Unknown}} ||  
 
|-
 
|-
| <code>0x0CEC</code> || <code>0x000C</code> || 1 byte || Month || 1 to 12.
+
| <code>0CEC</code> || <code>000C</code> || 1 byte || Month || 1 to 12.
 
|-
 
|-
| <code>0x0CED</code> || <code>0x000D</code> || 1 byte || Day || 1 to 31.
+
| <code>0CED</code> || <code>000D</code> || 1 byte || Day || 1 to 31.
 
|-
 
|-
| <code>0x0CEE</code> || <code>0x000E</code> || 1 byte || Hours || 0 to 23.
+
| <code>0CEE</code> || <code>000E</code> || 1 byte || Hours || 0 to 23.
 
|-
 
|-
| <code>0x0CEF</code> || <code>0x000F</code> || 1 byte || Minutes || 0 to 59.
+
| <code>0CEF</code> || <code>000F</code> || 1 byte || Minutes || 0 to 59.
 
|-
 
|-
| <code>0x0CF0</code> || <code>0x0010</code> || 1 byte || Seconds || 0 to 59.
+
| <code>0CF0</code> || <code>0010</code> || 1 byte || Seconds || 0 to 59.
 
|-
 
|-
| <code>0x0CF1</code> || <code>0x0011</code> || 11 bytes || {{unknown|Unknown}} ||  
+
| <code>0CF1</code> || <code>0011</code> || 11 bytes || {{unknown|Unknown}} ||  
 
|}
 
|}
  
Line 217: Line 201:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0CFC</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>TTDS</code>.
+
| <code>0CFC</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>TTDS</code>.
 
|-
 
|-
 
|}
 
|}
Line 227: Line 211:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0D08</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>WMAP</code>.
+
| <code>0D08</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>WMAP</code>.
 
|-
 
|-
 
|}
 
|}
Line 237: Line 221:
 
! File || Block
 
! File || Block
 
|-
 
|-
| <code>0x0D80</code> || <code>0x0000</code> || 4 bytes || Block magic word || Always <code>SAMI</code>.
+
| <code>0D80</code> || <code>0000</code> || 4 bytes || Block magic word || Always <code>SAMI</code>.
 
|-
 
|-
 
|}
 
|}
  
 
== Checksum ==
 
== Checksum ==
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 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:
 
 
 
<pre>
 
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)
 
</pre>
 
  
== Tools ==
+
The following python code can recalculate the checksum if the data after the checksum is modified:
* [https://github.com/Espyo/Misc_Pikmin_tools/tree/master/hp_save_editor Hey! Pikmin save editor]
+
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)
  
 
[[Category:File formats]]
 
[[Category:File formats]]
 
[[Category:Hey! Pikmin]]
 
[[Category:Hey! Pikmin]]

Please note that all contributions to Pikmin Technical Knowledge Base are considered to be released under the Creative Commons Attribution-ShareAlike (see Pikmin Technical Knowledge Base:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel Editing help (opens in new window)

Templates used on this page: