Right. However, as I found out, those 4 bytes before the in-game timer can be ignored since they are not counted to the checksum.
I don't know what they are used for...
Link to videoGeneral
The game uses three savegames which are located in the SRAM memory domain.
Savegame 1 is located in $0010-$0707.
Savegame 2 is located in $0708-$0DFF.
Savegame 3 is located in $0E00-$14F7.
Before being saved over or wiped for the first time, the memory in the SRAM memory domain is in an "uninitialized state".
At the time of writing this, not much is known about this but the general sentiment seems to be that the memory inside the SRAM battery in the game's cartridge could have any possible values and Nintendo doesn't actually wipe values to 0xFF or 0x00 nor set the memory to any specific pre-set.
Bizhawk - along with other emulators - sets the SRAM memory to be filled with 0xFF as a measure to be somewhat more deterministic and to do things in a more sane way.
This speedrun is possible if one assumes the SRAM memory starts out like that.
If we were to work with any other "uninitialized state" where the SRAM memory could have any other possible values, a much faster speedrun could be possible in theory.
The memory would have to align in such a way that the game interprets it as a valid savegame with a correct checksum.
The photosprite ID for Mario and Luigi must be a good value so the game doesn't crash on the file select screen.
And the starting room must be one that leads into the ending cinematics (30, 455, 478 or 479).
Then it would be possible to load up the game, see a savegame is already there and loading that savegame places us right at the ending cinematics.
Savegame-corruption!
Each savegame has a 1-byte checksum which is the sum of values in
$0010-$0013, $0018-$06FF and $0704-$0707. (Add 0x06F8 for slot 2 and 0x06F8*2 for slot 3)
Also some bytes need to have certain values for the game to consider a savegame as active and valid.
Because of how the game works, the game keeps savegame memory not only in SRAM but also in EWRAM.
Upon loading up the game, SRAM memory is copied to EWRAM memory and when saving or copying, EWRAM memory is copied to SRAM memory.
Now, in order to corrupt memory in SRAM, these tools are available to us:
1) Saving - copies values to SRAM, 8 bytes per frame, from top to bottom.
2) Copying - copies values to SRAM like saving does.
3) Deleting - sets values in SRAM to 0, 8 bytes per frame, from top to bottom.
4) "wipe all saves" - like a normal delete from top to bottom, but for all three savegames plus the Mario Bros. highscore. Done by holding L+R+A+B+Select when the game starts up and choosing yes twice.
You can interrupt each of these with a hard-reset. It is not recommended to do with the real hardware as it is said that the game cartridge or the battery could take damage, but for all intents and purposes, here, it just interrupts what the game was doing.
If the checksum is still correct and the bytes are telling that the savegame is active*, then the savegame will be valid even though the saving/copying/deletion procedure did not finish.
(*One flag that tells if the savegame is ok is set first thing when saving and copying; said flag is unset first thing when deleting; And said flag is set to 0x00 first thing when "wiping all saves".)How savegame corruption is used in the run
The values inside a savegame are ordered like this (just to give a general idea.):
- Mario current room
- Luigi current room,
- Mario stats, direction, photo sprite ID,
- Luigi stats, direction, photo sprite ID,
- Items
- Bunch of flags, in this order (We are thinking in 8 bytes since the game saves and deletes in 8 byte blocks:)
-- "Can go to Bowser's Castle"
-- "Escaping from Bowser's Castle"
-- current unlocked Action Commands (in $0227~$022F, $0920~$0927 for slot 2)
-- "Can use Bros Attack, items, flee in battle" (in $0230~$0237, $0928~$092F for slot 2)
-- "Block Action Commands" flag (in $0240~$0247, $0938~$093F for slot 2)
-- Green Pipes flag (in $0248~$024F, $0940~$0947 for slot 2)
-- "Loading zone in 3rd room in Koopa Cruiser exists" flag (in $02A8~$02AF, $09A0~$09A7 for slot 2)
-- "Collision box in 3rd room in Koopa Cruiser exists" flag (in $0300~$0307, $09F8~$09FF for slot 2)
-- Splash Bros. Uses, Bounce Bros. Uses, etc. (in $0577~$057F, $0C6F~$0C78 for slot 2)
In Toad Town is where we get our first opportunity to save the game.
The saving is interrupted by hard-reset which allows anything past Luigi's photo sprite ID value to remain as 0xFF.
Since the photo sprite ID must not be 0xFF (to prevent the game from crashing on the file select screen) this is the earliest point we can interrupt the saving procedure.
A few frames are spent waiting before the saving starts so the in-game time advances in order to make the checksum match correctly.
Now, one would think this savegame which has all flags set to 0xFF would be perfect for the purpose of advancing forward and finishing the game.
Most cutscenes won't play since the game thinks we already watched them.
But there were a few hurdles that needed to be gotten rid of, in the form of undesirable flags.
There is a "Block all Action Commands" flag that prevents us from using any action commands on the overworld (even prevents the front brother from jumping) which must be set to 0.
Let's punch smaller 0x00 holes into our savegame
You can punch 256-byte sized "0x00 holes" into a savegame that was filled with 0xFF - by copying, delete & hard-reset, copy& hard-reset - and come out with the correct checksum. That's because the checksum is only 1 byte and overflows (The checksum plus 0x256 is the same value).
Even though you can do that, it is not a viable option here since there are other crucial flags that must not be set to 0, such as one flag that enables the next loading zone in Koopa Cruiser, one flag that disables a collision box in Koopa Cruiser, and of course the "have spinjump / highjump / hammer / hand" flags.
So a special method needed to be used to place 0x00 sections that are smaller than 256-bytes.
A careful eye will have spotted that we were playing on slot 2.
We did a factory wipe at the beginning of the run to set some of slot 1's memory to 0x00, up until $039F.
The savegame we just made in slot 2 is now copied to slot 1 until we interrupt by hard-reset.
This effectively means a small hole of 0x00 was placed in slot 1 in $0308~$039F ($0300~$0307 being the last 8-byte block that needed to be 0xFF, as it contains the "collision box in Koopa Cruiser flag").
At this point, slot 1 is still considered invalid since the checksum is incorrect, but the data remains there indefinitely.
Now, slot 2 is copied to slot 3 completely.
Then, slot 2 is deleted until we interrupt by hard-reset. Slot 2 is invalid.
Then, slot 3 is copied back to slot 2 and we interrupt again. Slot 2 is valid again.
This created a 256 byte sized hole of 0x00 in slot 2, in $0938~$0A37.
Finally, slot 2 is copied to slot 1, which is interrupted, causing slot 1 to have two smaller holes of 0x00, both summing up to 256 bytes of 0x00 which causes its checksum to match and be valid.
The two smaller holes of 0x00 in slot 1 are located in $0240~$02A7 and $0308~$039F.
Any values before $0240 and after $02A7 and before $0308 must be 0xFF because important flags are located there.
And we wanted to squish $0240~$0247 to zero as it contains the bad flag that blocks action commands.
If we hadn't done this, we would have gotten stuck in Koopa Cruiser (missing loading zone or collision box stopping us) or would have had other problems with progression (no action commands, no jumping in Stardust Fields).
Using glitched Badge
When items in memory are set as 0xFF, the game reads that as "the player doesn't have it".
Because all items are set as 0xFF, the player doesn't have any badge or pants but is still allowed to switch them.
In this case, a glitch happens where the player can choose their clothing or badge in a list of glitched options.
Strangely, this list is different depending what room you are in.
I choose a badge for Mario and Luigi that raises Pow and allows me to defeat Fawful by jumping once each.
Choosing this badge turned out to be fastest to do in the 2nd room of Koopa Cruiser.
Why go to Hohooros?
For certain gameplay events, the game uses a special timer (called "event timer").
This timer is used by a surfing minigame in Oho Ocean, a jumping minigame in Guffawha Ruins, a time-limit block in Gwarhar Lagoon, a time-limit block in Bowser's Castle and the escape from Bowser's Castle (there may be more).
If you enter Bowser's Castle when the game thinks you are escaping, it checks for the event timer to trigger a game-over if it reaches 0.
You can bypass that if you make sure the event timer is non-zero, such as when failing the Hohooros minigame and then leaving.
There is no other way around it.
Since most flags are set to 0xFF, Hohooros is considered to be already beaten, but the flag for the check if you are touching the ground is also active, allowing us to do the minigame again.
I was also considering going to the surfing minigame instead (we have set the green pipes flagEdit: Nvm, I lied. But we could set it if we want.), but I think it would take longer.
Firedash glitch
This glitch only works on the Japanese version of the game.
It is used in this run in order to travel through the mountain area faster.
This glitch happens if you use Firedash right before a ledge which causes the brothers to enter a glitched state because Luigi is allowed to move on when Mario behind Luigi is not ready yet.
While working on this run, I found a different Firedash glitch which I will call "Firedash speed glitch".
Firedash speed glitch
When doing a firedash that has Luigi fall off a ledge, if Luigi gets boosted by an adjacent ledge, then it is possible that the brothers will be allowed to move around the room at 768 or even 1024 speed (512 speed is normal walking speed).
Deathwarping?
I tried saving in Hoohoo Village and deathwarping after getting the event timer at Hohooros, but this turned out to be about 10 seconds slower.
Why not submit this
I think some rooms should still be looked at for improvements before this should be submitted to TASvideos.
One NPC boost off a blue Toad couldn't be manipulated at the Toad Town plaza.
One NPC had bad placement in Hoohoo Village so I had to go around.
I didn't spend too much time on optimizing the Firedash glitch in the mountain area.
"Firedash speed glitch" has potential for use in Koopa Cruiser.
New Luascript
Version 0.13 of my luascript, which allows the script to run on the latest Bizhawk and fixes many things, will be released soon™.
I will make a new post when the time comes.
EDIT: I renamed "factory wipe" to "wipe all saves".
The word factory wipe implies that the SRAM battery is shipped with all 0x00, but the game's manual does not mention the word "factory wipe".
Wow, that was quick after finding the save corruption! But I guess there wasn't much to optimize. So those 4 bytes are first set to 0 when you save (or earlier?) and then when you corrupt the save, as long as they stay 0, it works?
I guess you can't change the map you saved on to something useful because you're only writing FF?
I did some optimizing, but a few rooms could probably be improved.
If you are interested, you can help me optimize this run before we are submitting to TASvideos.
I think you are refering to older information. Please read my information write-up in the previous post.
The in-game timer, which is the last 4 bytes of a savegame, is set to 0xFFFF when saving and hard-resetting in Toad Town.
The 4 bytes prior to that have an unknown purpose and are not counted to the savegame's checksum.
I erroneously counted them to the savegame's checksum before, which is why I came up with the wrong assumption that they are used as a counter-measure against savegame corruption.
I have not tried for it extensively but theoretically you can visit map 0, which is useless for a speedrun.
Otherwise, you can only set it to 0xFFFF (65535) which crashes.
Other values may be possible if subframe resets become available.
Changes in 0.13 14th Oct 2024
- The script now runs in Bizhawk 2.9.x.
- The script now uses Arial font by default.
- On displays that use up and down arrows, you can now scroll up or down via mouse wheel.
- The emulator will assume the user's original window size after the script stops.
- Fixed errors arising from loading a branch in TAStudio.
- Fixed that displays could become positioned offscreen if reducing padding in the settings or by closing "Actors"/"Overview".
- The script will recognize the two new E3 proto ROMs but there is currently no support.
- Flags: Added some room-related flags.
- Actors: Added a button to enable viewing collision boxes.
- Actors: Added a button to enable showing loading zones (still in an unfinished state).
- Actors: Fixed issue where the actors list could become empty if loading a state from ingame while on the title screen.
- Run Event: Removed Mine Cart Minigame on the Japanese version (crashes).
- Savegames: "Auto-Apply Checksum" now triggers on each frame when the client is paused
- Savegames: Checksum will be updated each frame when client is paused or when a movie is active.
- Savegames: Now shows the required checksum next to the current checksum.
- Savegames: Valid savegame will be shown with a green mark; invalid savegame will be shown with a red !-sign.
- Savegames: Fixed a problem where the checksum was not calculated correctly if bytes near the end of the file were non-zero.
- Savegames: Added "Auto-Apply Bytes" which continuously sets bytes required for the savegames to be valid on top of a correct checksum.
- Savegames: Added some Item addresses, increasing entries from 107 to 178.
- Notifications: Fixed that value changes were printed when the Actors display was active and loading a state from ingame while on the title screen.
Woah, a glitched run finally exists! I looked through this thread every time it got an update, and I knew a glitched run was attempted for years without success. Congrats!
1. Does save corruption exist for the other Mario & Luigi games?
2. Assuming a run that does this gets published, would you or others still try to do that ACE run as a "no save glitch" category?
3. What other stuff can you do with this? Anything fun?
1. I don't know. The corruption was only possible because bytes get saved in groups of 8 once per frame and the checksum protection is weak.
2. I thought ACE was close but not reached yet. I'm not sure what the progress is on that. Of course that would be a different category.
Remember, this run only works this way because SRAM is full of 0xFF, which is an acceptable "default state" for emulators but the real SRAM battery probably gets shipped with random values. Although not even that is sure, I think.
3. It depends what you want to do. With subframe resets, you might be able to reach an end credits room earlier.
I did not expect to come back to this game and seeing this on the forums. I did read through your posts but I didn't understand much honestly lol. I would be more than happy to help with optimizing the first few rooms though if I can better understand how all of this works.
Edit: I noticed a few potential timesaves over your input file after watching the run a few times. Firstly, you can save a few frames by reducing camera scrolling time before triggering the Bowser airship cutscene by jumping before the cutscene begins. It might also be possible to set up the follow path to warp to the end of the 3rd room in Koopa Cruiser with the use of Firedash glitch, maybe that could also be done in the first room and potentially the spiked room in Stardust as well.
• MLSS Any% TAS out! (link)
• MLSS All Bosses TAS out! (link)
• MLSS Glitchless TAS out! (link)
Did some TASing today. I managed to be 10 frames ahead of your input file going into the Fawful fight, through some optimizations for camera scrolling and better mashing during textboxes. Unfortunately RNG did not change for the Toad in the first room of Toad Town or for the baddie in the last room of Koopa Cruiser to NPC boost off of them.
I will try to see if we can incorporate even more teleports than in your encode with Firedash glitch. From my testing, Firedash glitch works exactly the same as hat teleportation except the setup is a lot faster, as in you don't have to cycle through any of these glitched commands to begin glitched movement. That opens the door to many opportunities for teleports especially in Hoohoo Mountain. The only thing I am curious about is if it's possible to trigger the end credits earlier using the Save block.
Also regarding ACE and our research, RETIRE coded a bruteforcing script and I left it running an entire night a few months ago but even after 2 million attempts it didn't find a single combination of inputs that would yield a credits warp. From our research, the memory addresses that we have to modify are stored in BIOS which means we can't really change them during gameplay.
• MLSS Any% TAS out! (link)
• MLSS All Bosses TAS out! (link)
• MLSS Glitchless TAS out! (link)
Hello Potato,
thank you for the help.
I'm not very good with the teleportation glitch.
About understanding save corruption better:
I have updated my MLSS luascript so it will work on Bizhawk 2.9.1. See here.
When using that script, open the "Savegames" display. It will show two values in the bottom right corner, which is the current checksum and the required checksum. If both match, then the savegame is valid. You can also look at the SRAM memory domain while saving, copying or deletion takes place to better understand what's going on.
For NPC boosting in Toad Town and Koopa Cruiser, I tried delaying 1 or 2 frames on the file select screen which yielded different RNG seeds but the NPCs still didn't cooperate.
Since you came up with improvements in cruiser, maybe it is worth trying this again. If you send me the bk2 or tasproj file, I can try it.
I did try to improve the run myself, came up with 3 frames improvement in the fourth room of Cruiser.
I think because I took a more sharp turn towards the crates at the top of the room and by a better NPC boost after the crates.
Tried firedash speed glitch but did not manage to save time with it.
In Stardust Fields at the first room with spikes to jump across, is where I stopped because I tried firedash glitch with teleportation but couldn't make it work.
Let me know if you have any questions.
Actually I kind of lied, I was 10 frames ahead going into the last room of Cruiser, I tried some different inputs but I somehow lost time over your first input file (was 7f ahead after that room) so I think the best idea would be for you to use the 3 frame improvement you managed to find. Also I think I saved 1f in the first room of Stardust by getting better ledge boosts (you got -1152 for the first frame of both ledge boosts, I spent 1 more frame walking diagonally and I managed to get -1280 instead). That is also where I stopped TASing as I am pretty busy this week.
Regarding some of my ideas for teleports, the one in the spiked room in Stardust will not work because we need an exact warp to teleport through walls and the follow path for that can't be set in any other room before that. The teleports in Cruiser also don't work because of the same issues. I have some ideas for the teleports in Hoohoo Mountain though.
Here is the input file that I TAS'd on if you have time to try squeeze more frames.
• MLSS Any% TAS out! (link)
• MLSS All Bosses TAS out! (link)
• MLSS Glitchless TAS out! (link)
@Potato
I managed to improve by 58 frames.
Bk2here
10f from the jump before the Koopa Cruiser cutscene.
3f from Koopa Cruiser 4th room.
45f by successfully using Firedash speed glitch in the Stardust Fields room with the spikes.
I did not find a 1 frame improvement in the first Stardust Fields room which you mentioned.
The subsequent NPC boosts in Hoohoo Mountain Village needed to be changed but there was neither a time gain nor a loss.
I vaguely remember that I was able to teleport right into the exit in the Stardust Fields spike room but it required a few brother swaps or something... Unfortunately I didn't save the input for that. It might not be worth looking into it since the new improvement I came up with is pretty decent.
Lastly, a few words on Firedash speed glitch.
As explained in a previous post, it works if Luigi in front gets pushed by an adjacent ledge while falling off but it is precise.
You can usually gain the ability to run around at 768 speed.
In order to obtain 1024 speed, I think you have to do it on a ledge that is two units high (requiring high jump to get on it) or on a 1 unit tall ledge that looks like the one in the Stardust Fields spike room (adjacent ledge has a width of 1 tile). I have not been able to get 1024 speed in other scenarios.
I would be happy if you continue looking for improvements when you have time and feel like it.
I did document some of it here if you want to take a look at it.
You do need to swap places in order to not overwrite the follow path as you're walking, which would make sense. But you need to setup the follow path very precisely and you need to warp exactly 8000 units away if you want to pass through a wall, which is usually pretty hard to achieve. I will look more into it when I have the time.
• MLSS Any% TAS out! (link)
• MLSS All Bosses TAS out! (link)
• MLSS Glitchless TAS out! (link)
Did a bit more TASing today, managed to save 72f in the first room of Hoohoo Mountain (not the first room of Hoohoo Village) by using a 240 warp for which I conveniently set the follow path to be very close to the exit. I also set 248 and 256 to use them to warp in the following 2 rooms as well, although I didn't get to test if they actually work or not. Here is the input file.
Edit: I saved a total of 131f over your TAS after improving the other teleports as well. The only place that might still have potential for timesave is probably the spiked room if you can get that teleport to work because I couldn't figure out how to set the follow path accordingly to make it work. Past that I don't really have ideas for any more timesaves, besides somehow saving time during the setup for the corrupted savegame but I don't really understand how to do that even with your lua script.
• MLSS Any% TAS out! (link)
• MLSS All Bosses TAS out! (link)
• MLSS Glitchless TAS out! (link)