I explored the possibility of savegame corruption.
General info
Checksum is 1 byte at $0016 (SRAM) for file 1, $0016+0x6F8 for file 2, $0016+0x6F8*2 for file 3.
The checksum is the sum all bytes at $0010 ~ $0013 and $0018 ~ $0707. (Add 0x06F8 for file 2 and 0x06F8*2 for file 3)
When saving a file, at the very start, checksum is written to $0016 and then all the values are written over the previous savegame.
When booting the game, the game checks if the checksum is indeed the sum of all bytes inside the savegame, otherwise the savegame is invalid and will be treated as empty.
If you hard-reset in the middle of saving and the sum of all bytes still matches the checksum, the savegame will be treated as valid.
Demonstration bk2 input file
My luascript can show savegame values and checksum, but it is very old.
I only managed to make v0.11 r4 of my script run in Bizhawk 1.13.2 (mGBA core) and had to modify the script so the "auto apply checksum" feature would run every frame while the client is paused, rather than "every second or so".
https://tasvideos.org/UserFiles/Info/638628517930104241
https://youtu.be/mzqw3qauXBA
This is from a bare-bones playthrough which used the luascript's "run event" feature to directly go to Little Fungitown.
I gave myself 256 items and 0 coins.
At the beginning of the movie, I save the game, then go to sell my items.
When saving, I did a bit of trial and error, since things like Mario and Luigi's pixel position are saved, too, and can mess with the checksum calculation...
First, I save and see what checksum the game writes to the savegame at $0016 (SRAM) at the beginning of the saving procedure, then I repeat (saving at the same positioning) and let my script's modified "auto-apply checksum" feature run. At the frame the coins are written to the savegame, I check if the new calculated checksum matches the previous checksum.
If not, I try to save at a different positioning and repeat the above steps.
If yes, success - I repeat without the "auto-apply checksum" feature and hard-reset at the frame the coins are written.
The savegame will show up in the file select screen.
The movie demonstrates that I gained coins but kept my items.
Possible uses
In theory this could be used for:
- Advancing in the game and reset flags later (blocks could be hit again, events could take place again, etc.)
- You could gain stats while staying at current level
- Visiting test rooms 0x00 and 0x01 (US or EU version only)
- Visiting room 0x00 to trigger the opening cutscene (JP only) but game soft-locks after the cutscene.
- You can set your pants and badges to 0, which makes it so you can select glitched pants or badges in your inventory. Possibly applies for coffee items, too.
I did not explore hard-resetting while copying a savegame yet.
But in theory, some shenanigans are possible. E.g.
- Save in slot 1 in room A
- Copy slot 1 to slot 2
- Continue and save to slot 1 in room B
- Delete slot 1 (hard-reset at the beginning of the procedure to avoid actually setting everything to 0)
- Copy slot 2 to 1 and hard-reset
- You are now in room A with things accomplished from slot 2.
(I was thinking about this as a timesaver to go to Hoohoo Mountain Base during the endgame quicker, but it looks unlikely and slow.)
I had no success when deleting a savegame. Even with the "auto-apply checksum" feature, savegame would not show up...
For speedrun purposes, since room id gets wiped first, it would not be useful since room id 0 is intro cutscene (JP) or test room (US/EU).
Order of values in savegames
While saving, values are written from top to bottom in chunks.
Roughtly speaking, at the very top is the room id,
followed by Mario and Luigi's position and "who is active" flag,
then stats (first the experience, then the level, then the stats),
then money( + all types of mushrooms, nuts and super nuts - all in the same frame)
then rest of items,
then flags (who learned what move, which blocks you hit in each room etc.).
The ingame time is saved at the very end.
Subframes?
I shall mention that in theory, you could reset at subframes so you have more precision when to interrupt the saving procedure.
But I have no experience with this.
Maybe you can come out with new values if you reset in the middle of saving a value (such as in the middle of the CPU instruction).
For example, resetting while the value for the room id gets written to come out with a new room id.
(Room 30, 455, 478 and 479 are good for reaching the ending cinematics.)