Submission Text Full Submission Page
The first game in the Mario & Luigi series, Superstar Saga, follows Mario and Luigi as they travel to the Beanbean Kingdom in order to combat Cackletta and Fawful, who stole Princess Peach's voice for the purpose of harnessing the power of a special artifact called the Beanstar. The game is largely set in the Beanbean Kingdom, a country neighboring the Mario series' usual setting of the Mushroom Kingdom, mainly populated by Beanish people and Hoohooligans, with many locations named after onamotapoeia representing laughter. The player characters are brothers Mario and Luigi, who travel to the Beanbean Kingdom to return the voice of Peach, the princess of the Mushroom Kingdom, after it is stolen by the Beanish witch Cackletta and her henchman Fawful. Among other characters are Queen Bean and Prince Peasley of the Beanbean Kingdom, who assist Mario and Luigi; and the thief Popple, who crosses paths with them throughout the game.

Game objectives

  • Beats the game as fast as possible
  • Major skip glitch
  • Final boss skip glitch
  • Uses game restart sequences
  • Heavy glitch abuse
  • Corrupts memory
  • Corrupts save data

Context

Potato: During the summer of last year, me alongside fellow glitch hunter RETIRE started doing research on this game trying to figure out if Arbitrary Code Execution (and more specifically, credits warp) would actually be possible for this game. We quickly confirmed by changing the byte at $2336 to 0x10 that credits warp was at least theoretically possible, so it seemed like only a matter of time until we would find a way to actually pull it off in a real TAS. We then realized that ACE is most likely impossible to do, as we found a way to trigger and make the game execute instructions but the values that we needed to change were stored in the BIOS of the GBA, meaning we couldn't access them. However, while Arbitrary Code Execution was already ruled out, we found out that Arbitrary Script Execution was possible to do, but after coding a bruteforcing script and letting it run for 24 hours we hadn't been able to generate a single string of inputs that would yield credits warp, so we abandoned the idea altogether.
This TAS, however, makes use of a brand new overpowered glitch called "Savegame Corruption", discovered by MUGG near the end of September of this year. Note that this glitch only works because all of the SRAM memory domain is 0xFF whereas on the real console, the memory is most likely shipped with random values until first saved or wiped over, meaning there is a high chance this isn't possible at all on real hardware, although we currently don't have enough information to know for sure.

Version choice

This movie uses the Japanese version of the game despite it being the slowest of the 3 (US, PAL/European, JP) as far as the beginning of the run goes, however that timeloss is more than made up for with the use of "Firedash glitch" and its other variation "Firedash speed glitch".

Route overview

Before even selecting any files, we immediately wipe all saves. The run starts like normal, until we reach the second room of Toad Town, the first area of the game. There, instead of going to the end of the room, we head immediately for the save box, initializing the "Savegame Corruption" glitch. Once the glitch is over, we continue on with the run "normally", except now most storyline flags were already set while performing the glitch. This means that in the final room of Toad Town, the Baddie NPC is already there even though we never talked to it, and in Koopa Cruiser we are able to skip not only taking the photos for Mario and Luigi's passports, but also skip past both Goomba tutorial fights. In room 2 of Koopa Cruiser, we open the suitcase and equip a glitched badge so that we can kill Fawful in 1 jump from each bro. Note that depending on the room we open the suitcase in, we would have different glitched badges to choose from.
We take the normal route through Stardust, making use of Firedash speed glitch and Firedash glitch throughout. As expected, we are able to skip Tolstar altogether because the game thinks we already completed it. Once we arrive in Hoohoo Village, we find Blablanadon already in his nest, however, we can't take him right away to Bowser's Castle. The reason for it is because 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, which you can only bypass that if you make sure the event timer is non-zero. This is done by entering a minigame that has a timer active and leaving right away. Of all the options that we had, the Hoohooros minigame is the fastest one to reach and come back from, so we make our way towards Hoohooros.
Through the use of Firedash glitch, we are able to teleport to the end of every room on the way to Hoohooros. We enter the minigame, then immediately walk off to fail it, and head back to Blablanadon to be able to actually enter Bowser's Castle. Once there, all we need to do is talk to him again to enter the ending cinematics, however that is trickier than it sounds. In the initial stuck position, Mario has to be behind and use Spin Jump. Mario will zip upwards. Then by pausing and unpausing, it makes Mario fall down and Luigi can walk forward and talk to the dino. After that, the run ends normally.

Savegame Corruption

General

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". Not much is known about this currently 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.
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:
  • Saving - copies values to SRAM, 8 bytes per frame, from top to bottom.
  • Copying - copies values to SRAM like saving does.
  • Deleting - sets values in SRAM to 0, 8 bytes per frame, from top to bottom.
  • "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 this 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).

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.

Firedash Glitch

Usually, when you use the Firedash ability and you end up walking off a ledge, Luigi stops as soon as he touches the ground and can't start moving until Mario has also landed on the ground. However, by using Firedash while Luigi is extremely close to the end of the ledge, while Luigi falls he can actually start moving before Mario lands on the ground, which enables Mario to keep walking at the speed he had before running off the ledge. Depending on how big the surface is, the bros can get up to 0x400 speed, however, no matter how close Luigi is to falling off the ledge, Mario will always get up to at least 0x300 speed. When both bros land on the ground, they are walking at the same speed, however, when we switch to Mario being in front, Mario moves at his default speed of 0x200, while Luigi moves at 0x300 speed. Therefore, this glitch is used to get glitched movement to occur for the bros.

Firedash speed glitch

When doing a firedash that has Luigi fall off a ledge, if Luigi gets boosted by an adjacent ledge as he's falling, then it is possible that the brothers will be allowed to move around the room at 0x300 or even 0x400 speed (0x200 speed is the normal walking speed). Generating 0x400 speed boosts happen under very specific conditions though, so we mostly get 0x300 speed boosts.

Teleportation

Teleporting was discovered in order to go past walls both horizontally and vertically. A teleport happens on the frame the back bro's position gets ahead of the front bro's position in order to prevent weird interactions between the bros. During normal gameplay, if a scenario like this happens, both bros will simply get warped back a few tiles, however, with clever exploiting it is possible to make the game teleport them anywhere. The first requirement for teleporting is having glitched movement, which in this run is done by using the Firedash glitch.

Follow Path

The follow path is a list of the most recent 256 x,y positions the front bro has been. On a frame of normal movement, each bro advances 8 indices on the follow path. The back bro goes to the position 8 indices ahead in the list, then the front bro moves 512 units, divides this movement into 8 64-unit intervals, and writes the endpoints of these intervals to the follow path. They stay 64 indices, or 8 frames apart, and the whole list is looped every 32 frames. When Luigi is underground, they walk at half speed so they only advance 4 indices per frame.
The follow path is "reset" when you enter a loading zone, switch places, or use a bros move like dunking Luigi, spin jump, high jump or using Hand with the back bro. This means the front bro is moved to index 64, back bro to index 0, and indices 1-64 are filled with 64 positions between them. Indices 65-256 are untouched, so you can store positions later in the follow path by resetting it.
When you have glitched movement, Mario advances by 4 indices while Luigi advances by 8. The follow path is reset when using Firedash glitch to activate glitched movement. After 16 frames of movement, they both reach index 128. The next frame of walking, Luigi goes to the position at index 136, which can be stored from earlier. Furthermore if Mario jumps when you have glitched movement, he'll advance by 8 indices per frame like normal. So if you move for n frames in the air, they will coincide at entry 128+8n instead, and warp to entry 136+8n. In this way, we can warp to any entry (that's a multiple of 8) from 129 to 256. Entries 1-128 will always be overwritten before the teleport so are useless to teleport to.
Luigi doesn't warp to the exact position in the follow path: he only warps to the closest position that matches the lower 2 bytes of the follow path position. In other words he can't move more than 0x8000 units in any direction. Also, teleports will sometimes be blocked by walls - Mario will end up teleporting to the wall's position instead of going through it. However if the lower 2 bytes of the follow path position is exactly 0x8000 away, Mario's position will decrease and this "exact warp" always goes through walls.

Teleports explained

We will briefly go over the teleports used in this run. The first one is done in the second to last room of the Koopa Cruiser. We used the Firedash glitch in tandem with Firedash speed glitch on the boxes in order to get both bros to walk at 0x400 speed instead of the regular 0x200. While walking to the end of the room we set the follow path conveniently, and after switching we performed a teleport to entry 136 by simply walking which is just in front of the loading zone to the next room.
The next teleport happens in the first room of Stardust, where we again use Firedash glitch and Firedash speed glitch to move faster and also initiate glitched movement. We switch at a convenient point and we jump with Mario to teleport to 136, closer to the loading zone. Because Luigi is actually walking at 0x400 speed while Mario is only walking at the default speed of 0x200, if we kept walking we would teleport again, except we couldn't reach the next follow path position, meaning we would teleport backwards, so when the bros end up on the same pixel we stop moving for a few frames until they both land to prevent that from happening and simply walk into the loading zone.
We use Firedash glitch again in the third room of Stardust containing the spikes to activate glitched movement. We set the follow path to entry 256 just after going past the final set of spikes, and after switching to Mario we jump and get teleported to it, however we don't teleport exactly on the same position as the follow path because on the way to the follow path, we get blocked by 2 separate walls at the same time, so we only end up teleporting to the X position of the follow path and to the Y of one of the walls. Conveniently, though, it still lets us walk past it after the teleport is over and reach the next room.
Hoohoo Mountain features by far the most teleports in the entire run. First, we set entries 240, 248 and 256 in the first room of Hoohoo Mountain. 240 is set inside one of the walls near the end of the room, while 248 and 256 are set for the next room. We have to use Fire with Mario to preserve this follow path until we reach the first ledge, where we use Firedash glitch yet again to initiate glitched movement. We walk for a bit with Luigi in front, because we need to get closer or else we wouldn't be able to teleport to the right location, then we switch to Mario in front and we teleport to 240, putting us inside the wall. After that, we get out of the wall and immediately switch, while making sure we don't overwrite entries 248 and 256. In the second room, we use Fire again and get on top of a ledge, use Firedash glitch and then teleport to 248 and then to 136 right after, which was set while warping to 248, on top of the platform at the end of the room. We switch back to Luigi and walk to the end of the room. In the third room we override all entries because we don't need them anymore and we use Firedash glitch once again. This firedash is a bit longer than the ones before, so we stop it precisely such that Luigi walks off it with 0x100 speed, enabling glitched movement. After walking right for a bit, we switch to Mario and we teleport to 256, followed by a warp to 136 right after, placing us on the staircase at the end of the room. On the way back from Hoohoo Mountain we perform 1 more teleport, in the second room, except this time we use Firedash glitch differently. Sometimes, you are able to use Firedash glitch and perform a teleport instantly when Mario lands on the ground if he lands ahead of Luigi (which rarely ever happens). This teleports them high in the air, and after landing we switch back to Mario in front and we use Thunder with Luigi to end the glitched movement.

Tricks

NPC Boosts

Whenever you jump into an NPC’s hitbox the game will try to push you out of its hitbox. After being ejected you gain a small speed boost in the direction you were facing which saves a couple of frames.

Ledge boosting

We can use ledges that end in a corner in order to boost Mario or Luigi forward, if you walk off the ledge diagonally and then move towards the corner. The speed that you get from the ledge boost is influenced by !! the angle of movement relative to the angle of the ledge and the distance to the ledge the frame before walking off it.

Instant Switching

If the bros are on the same pixel or the path between the bros is blocked by the corner of a wall, the switching will be finished immediately which saves a few frames per application.

Stair Jumping

Walking on stairs causes you to move at half speed until you’re no longer on them, however by facing perpendicularly to the stair the frame before jumping you keep normal speed in your desired direction before landing on the stair again. While this works for most stairs, some stairs like the ones in the badge shop from Fungitown, the ones in Beanbean Town and the ones in Joke’s End don't let you keep normal speed for long even while stair jumping normally, so you have to move diagonally for a few frames for the first jump in order for the back bro to keep getting zipped to front bro’s position.

Potential Improvements

  • It may be possible to significantly improve the run in the future when subframe resets become possible. It could allow us to interrupt the game while it is writing the room ID to the savegame, possibly leading to different IDs. There are four different IDs that lead right into the ending cinematics (30, 455, 478 or 479), none of which can be achieved without subframe inputs. If this was possible, we could theoretically warp straight to the credits from the moment we opened the save box in Toad Town, skipping essentially everything past that.
  • A few frames could theoretically be saved in the first room of Toad Town by getting better RNG to NPC boost off the blue Toad as well.
  • We omitted going for a 4 frame timesave in the second to last room of Koopa Cruiser before reaching Fawful because the RNG in Hoohoo Mountain wouldn't be favorable at all. With better RNG manipulation, those frames could be saved in theory.
MUGG: I guess this marks the one and perhaps only time where I get to actually (co-)submit a MLSS run, after having studied the game, taking it apart, writing 8500 lines of lua for it, and attempting a run in the early days as well as in 2017 - with the Tunnel Clip found by solidifiedgaming being the reason I didn't continue... So in the end, although it's a gimmick category, I'm happy about this.
Potato: I would like frame 14436 as the thumbnail.


TASVideoAgent
They/Them
Moderator
Joined: 8/3/2004
Posts: 15562
Location: 127.0.0.1
Alyosha
He/Him
Editor, Emulator Coder, Expert player (3810)
Joined: 11/30/2014
Posts: 2829
Location: US
It may be possible to significantly improve the run in the future when subframe resets become possible.
If you are interested, subframe resetting is available in GBAHawk, though I haven't tested it in a while, but I'm pretty sure it's in working order.

1731633296