Due to some recent developments, we now have a faster way to "break the lock-on" that was featured in last year's TAS, allowing us to save just shy of 2 minutes. The new star of the show is a glitch called the ORT Desync (Object Respawn Table Desynchronization). This lets us spawn several copies of the Angel Island 2 boss, which we defeat in a specific way to trigger the same buffer overflow from the previous TAS that temporarily tricks the game into thinking it is just Sonic & Knuckles without changing or adjusting cartridges. Combining this with an intentional game over lets us jump to the Sonic & Knuckles stages, skipping the remainder of the Sonic 3 half.
Much of what is explained in the Author notes on that TAS is still relevant, and those notes will cover everything that happens in the Sonic & Knuckles half (though time-wise it's much more than half!).
Bizhawk technically is no longer required as we don't need the perform a crash setup from the previous TAS that requires a soft reset input (something that is not possible using Gens). We nonetheless ported the .tasproj file from Bizhawk 2.9 to BizHawk 2.11 to better reflect the state of the art in Genesis emulation, copying inputs from the previous TASes where appropriate.
Emulators and Tools used (for new inputs only):
Bizhawk 2.11.
Minerva (Chrezm's overlay and scripting framework that works in both Bizhawk and Gens). It has been updated for helping with several concepts used in the TAS, and is available here
Glossary
For several of the concepts used in this document, we adopted the name or description given either by the S3K Ram Editing page of Sonic Retro or the Sonic 3 & Knuckles Disassembly, which is easily searchable. Thank you Sonic Retro for these references!
AI, AI1, AI2 - Angel Island Zone in general, Angel Island Act 1, and Angel Island Act 2 respectively.
Level's object placement - Each stage maintains a list of objects that it will spawn alongside with their X and Y coordinates. These generally are your average objects you will find on any stage once you approach a particular area (e.g. enemies, monitors, platforms, path swappers). Objects that are NOT part of the level's object placement are created otherwise by direct player action (e.g. scattered rings, lightning shield sparkles, dust caused by braking, any object created using debug mode).
Dynamic Objects, Dynamic Object Sprite Status Table (DOSST) - The game allocates enough memory to have up to 90 simultaneous "dynamic" objects simultaneously. Dynamic objects are any object that is either part of the level's object placement or is otherwise created by player action. This does not count objects such as Sonic, COM Tails, and other general purpose control objects (such as the water height manager or invincibility stars). Generally, dynamic objects once spawned will despawn after having the camera move away from them far enough.
Object Respawn Table - The game keeps track for each object part of the level's object placement whether it should spawn the object the next time it would be "due to spawn". For this TAS, an object is due to spawn if it is not currently spawned but the camera X position rounded down to the nearest 128 pixels has just moved close enough from the right or from the left to the object's intended X position. This mechanism allows for certain stage objects to respawn if they spawned once but later despawned (e.g. an unbeaten enemy, path swappers), while preventing others from respawning after they spawned but later despawned (e.g. a beaten enemy, monitors spawned via signpost).
Object Respawn Table Desynchronization (ORT Desync) - After having the camera pan across a 128 pixel boundary where it rechecks for new objects to spawn, have the game attempt to load new objects due to spawn but fail to do so for the DOSST becomes full halfway through the process. We perform three ORT Desyncs in the TAS to spawn a total of four bosses. A more thorough explanation is available further below.
Object slot - Each of the 74-byte wide sections of memory that the game uses to store each object that currently has spawned, dynamic or not. In this document, they are numbered starting from 0.
Memory manipulation - Playing through a section of stage in a particular way in such a way that some stage objects of interest, when they spawn, are placed or not placed at particular object slots. This concept has been used several times in prior TASes (e.g. bridge skip in Angel Island 2, being able to spindash with slope glitch in Flying Battery 1, etc.), but we add a few memory manipulations during the AI2 boss fight to delay triggering Bridge Skip.
Bridge Skip - The bridge at the end of Angel Island 2 is controlled by a button that cutscene Knuckles jumps onto. The button uses a separately maintained value in RAM to decide which Object slot Knuckles is at to be able to do some distance computations to determine whether Knuckles is close enough to the button to thus trigger. Due to a game oversight courtesy of a Knuckles cutscene playing at the beginning in AI1, with some appropriate memory manipulation, we can trick the button into thinking that Knuckles is the button, and because the button is no distance away from itself, trick it into pushing itself and trigger the bridge collapsing and returning of control to us early. This concept is used in previous TASes to skip the AI2 cutscene and either advance to Hydrocity 1 or be able to take a death at the end of AI2. We continue to use this strategy in the TAS, but we change the moment where Bridge Skip is triggered and provide it the additional use of helping fill up memory.
Object slot #6 - Associated with Bridge Skip, it references what object the end-of-stage button thinks is Knuckles to then decide whether "Knuckles" pressed the button. If this button spawns in Object slot #6, the button will think that it itself is Knuckles and thus push itself, triggering Bridge Skip. The new memory manipulations performed in the TAS are done to keep this section of memory clear of the button (to avoid triggering Bridge Skip early) and other persistent objects (e.g. some auxiliary boss objects that a boss spawns). This is done so that, when it is beneficial in the TAS, we can have Object slot #6 be taken up by the button to trigger Bridge Skip.
Boss 1, Boss 2, Boss 3, Boss 4 - The four bosses spawned in Angel Island 2 by spawn order. Each boss individually takes 8 hits to be defeated.
Boss pattern - When AI2 Robotnik goes behind a waterfall, it invokes the game's RNG routine to decide which of four spots on the boss arena to navigate to. A more thorough explanation is available further below.
KosinskiM decompression and DMA queue (KMDDQ) - A small section of memory that the game uses to decompress art resources used by some objects. This buffer can hold up to 4 items, but the game does not properly check if it has any space left before adding items to this buffer. This oversight allows a buffer overflow which, if done right, tricks Sonic 3 & Knuckles into thinking it is just Sonic & Knuckles. A more thorough explanation is available in a section further below.
Chaos slot/Ozone slot - Each of the contiguous 6-byte wide sections of memory beyond the place in memory where the KosinskiM decompression and DMA queue is kept. One such Chaos slot contains a memory address that has a flag that the game uses to decide whether Sonic & Knuckles is locked in to Sonic 3 or not (i.e. "Sonic & Knuckles mode" versus "Sonic 3 & Knuckles mode"). It is this memory address that is corrupted via a buffer overflow to activate Sonic & Knuckles and thus break lock-on. This concept was used in the previous TAS (back then named "Ozone slots") but we now fill in this critical Chaos slot with a different buffer overflow. A more thorough explanation is available in a section further below.
Pity shield - The very first time that player respawns from a death after performing some of the known Sonic & Knuckles buffer overflow setups, Sonic will spawn with a shield (in this TAS, a lightning shield), even though logically a player should not have a shield when respawning from a death. A more thorough explanation is available in a section further below.
Some glitch explanations involve numbers in hex. To denote numbers in this document, we follow these conventions:
Memory addresses in RAM are denoted in hex using $ followed by the four hex digits that represent the address. For example, $FF7C is the memory address whose hex representation is the decimal number sixty-five thousand four hundred and four (65404). How many bytes to read from a memory address will generally be included when introducing a memory address of interest for the first time.
Values read from RAM are denoted in hex using 0x followed by hex digits that represent the value. For example, 0x2A is the hex representation of the decimal number forty-two (42).
Other numerical values that do not have a leading $ or 0x are your regular decimal numbers. For example, 15 is the decimal representation of the decimal number fifteen.
Main Changes
Only Chrezm and Ben have provided new inputs for this TAS, eandis and kaan's are from the previous TASes.
Time references are IGT.
Angel Island 1
0:10 - We still want to avoid the extra life. However, we save some time as we no longer need to delay activating the cutscene for the crash setup, for this TAS no longer does that setup.
0:34 - This is the first instance of an ORT Desync. We fill the DOSST almost to the brim using scattered rings (courtesy of hitting the spikes), the collapsing platform, and various other objects present in the area (such as the fire shield, spikes, and the flame objects that decorate the stage layout), and then have the camera pan left with a spindash to trigger an ORT Desync, courtesy of five stage objects the game would like to spawn but fails to do. This ORT Desync will let us spawn Boss 2 later on.
0:35 - We do a subpixel manipulation here to stop us from breaking the monitor, as we don't want the fire shield (as it makes the subsequent miniboss fight slower). One other side effect that can happen due to the ORT Desync is you can break the monitor but don't get the shield.
Rest is resyncing back to the previous TAS for keeping previous AI2 in sync.
Angel Island 2
Back to the original TAS route with taking the fire shield into the boss.
0:12 - Eagle-eyed viewers will spot that there is a spring missing here - a result of the ORT Desync from Act 1. Moreover, you'll notice after we press the switch and come back it is where it should be. This is an early example of the ORT Desync in action.
0:30 - Hitting this checkpoint (already commonly hit in the TAS) is now a required step, as it will allow for the fastest way to die during Angel Island 2.2 to be executed. However, hitting this checkpoint (or the one earlier in Act 2) will have the side effect of introducing the pity shield.
1:02 and 1:07 - We still want Sonic to brake at these spots in order to later trigger Bridge skip. However, for the new setup, we actually want to be able to move right in the boss arena without triggering bridge skip, instead triggering bridge skip later on. This requirement will drive some of the unusual steps we take later on.
1:08 - This is where the fun begins.
1:10 - We only want to get a few hits on Boss 1, as we want it hanging around to help set up more ORT Desyncs. We also create dust by braking to prevent some auxiliary boss objects for Boss 1 from taking Object slot #6. That is because these auxiliary boss objects are persistent so if they take Object slot #6, the button will never be able to take that slot for Bridge Skip.
1:16 - More dust to protect Object slot #6, and prevent Bridge Skip from activating here.
1:18 - By virtue of having moved right enough, once we move back left, Boss 2 will spawn. In order to synchronize the firing attack patterns on the two bosses, we intentionally wait several seconds before spawning Boss 2.
1:25 - If we go too far left, we despawn a button on the right side which we use as an object for the next ORT Desync setup shortly. Thus, we are forced to remain in place at the cost of being unable to get some initial hits on Boss 2.
1:34 - We need to lose the Fire Shield, so we can lose rings. This is the earliest opportunity.
1:37 - With several fireballs present, we lose the rings to help fill in the DOSST. We do a 1-tap spindash straight after landing which pans the camera left enough to trigger the ORT Desync, courtesy of two objects that the game wants to spawn but finds itself unable to (an off-camera path swapper and the bridge post to the left of the bridge). This ORT Desync will let us spawn Boss 3.
1:39 - We get another hit in on Boss 2 while spawning Boss 3. We get seven hits on Boss 3 while we wait with the camera locked.
1:51 - While getting four more hits on Boss 2, we move right just enough to finally activate bridge skip (the camera starts to pan down). This activates the bridge collapsing objects to the right, adding in more dynamic objects when we move to the right.
1:53 - We kill all 3 bosses on screen, and along with the fireballs they have created, this gives us enough objects to do another ORT Desync, courtesy again of the same two objects from before that the game wants to spawn but finds itself unable to. This ORT Desync will let us spawn Boss 4.
The IGT stops at 1:53 due to defeating one of the bosses, the true final boss is now active - the capsules, which we need to hit in the same jump.
We need to dispatch of Boss 4 without triggering the capsule buttons. We use well timed jumps to keep the capsules high (because they will target to settle around half way down the camera viewport), so they are out of the way, and also don't get too low when we want to hit all 4 capsules. Hitting all four capsules in a single jump and falling to some junk platforms at the very bottom of the stage fills in all the Chaos slots. We do a bit of optimisation by falling to the edge of a junk platform at the very bottom of the stage, so that when the end-of-stage cutscene starts Sonic can walk off and do the first death needed for a game over.
Angel Island 2.2
We end up with a Pity Lightning Shield here (a by-product of a Chaos slot filling a particular address with a certain pattern, see below), so we need to lose that before we can lose the remainder of our lives.
Getting a game over allows us to - like in the previous TAS - skip to the Sonic & Knuckles half of the game.
Sonic & Knuckles half
We took the Sonic & Knuckles input from the previous TAS and appended them to our new Sonic 3 half. However, we had to implement these minor changes, all of them to resynchronize.
Minor lag frame changes due to moving from Bizhawk 2.9.1 to 2.11.
Resync Mecha Sonic by creating some pause frames before entering the arena to deal with differences in RNG pattern.
Red Eye needed some minor changes due to a different RNG pattern, but we actually finish Death Egg 1 with the same IGT frame timing as the previous TAS
A few minor changes to UwUBall to sync up.
Glitch Explanation
We wrote a lot here, but there may still be some holes. Please let us know if we made any mistakes, thanks!
Spawning four bosses
How objects spawn in a stage
As described before, each stage in the game maintains its own "level's object placement" list: list of objects that it will spawn in the stage alongside with their X and Y coordinates. These are generally your average objects you will find on any stage once you approach a particular area (e.g. enemies, monitors, platforms, path swapper). Objects that are NOT part of the level's object placement are created otherwise by direct player action (e.g. scattered rings, lightning shield sparkles, braking dust, any object created using debug mode). The objects in the list are sorted in ascending order according to their X coordinate.
These object lists are hardcoded in ROM, so for the game to access them, it maintains the following RAM addresses (all ranges inclusive):
$EF5A-$EF5D: 4-byte pointer to the address in ROM of the object lists of the Sonic 3 stages (if playing a Sonic 3 stage) or the one for Sonic & Knuckles stages (if playing a Sonic & Knuckles stage)
$F772-$F775: 4-byte pointer to the address in ROM of the next object to spawn if the player were to move right "enough" (where "enough" is defined momentarily).
$F776-$F779: 4-byte pointer to the address in ROM of the next object to spawn if the player were to move left "enough" (where "enough" is defined momentarily).
For the purposes of this TAS, to decide if a player has moved to an area where there should be new objects to spawn (that is, it has moved "enough"), the game compares two values: the current camera X value rounded down to the nearest 128 pixel (in the disassembly called CoarseCameraX), and the camera X value rounded down to the nearest 128 pixel from the frame before (which we refer to as PreviousCoarseCameraX).
If CoarseCameraX and PreviousCoarseCameraX are the same, the game will not spawn any new objects from the level's object placement
If CoarseCameraX is greater than PreviousCoarseCameraX, the game will assume that the player has moved right enough and go on to spawn new stage objects that would logically be right. The first such object to consider is given by the 4-byte pointer value at $F772-$F775, and the game will spawn as many such objects that "should be spawned" (defined momentarily) until it reaches an object in the list whose X coordinate is at least CoarseCameraX + 128*5, at which point it will stop.
If CoarseCameraX is less than PreviousCoarseCameraX, the game will assume that the player has moved left enough and go on to spawn new stage objects that would logically be left. The first such object to consider is given by the 4-byte pointer value at $F776-$F779, and the game will spawn as many such objects that "should be spawned" (defined momentarily) until it reaches an object in the list whose X coordinate is at most CoarseCameraX - 128, at which point it will stop.
In other words, there are invisible 128 pixel "coarse camera boundaries" that the camera must cross in order for the game to decide to spawn new stage objects, and those objects themselves to be spawned follow some multiples of these coarse camera boundaries.
Additionally, it is generally the case that objects from the level's object placement that are spawned in a stage will typically despawn if they are too far away from the camera. For the purposes of this TAS, the camera X rounded down comparison described earlier is a good enough approximation. However, it is possible that the player may reapproach the area enough that the game needs to decide whether to spawn said object again or not. The easiest example that shows why this decision is not trivial are badniks: badniks that have not been defeated before despawning should respawn if the player approaches the area again, but if they have been defeated they should not respawn if the player approaches the area again. This allows the game to display the idea that certain actions have consequences and cannot be repeated (like defeating a previously defeated badnik) or reversed (like restoring some destroyed terrain) by just having the player move away from the area with the object of interest and coming back. For the purposes of this TAS, this is the concept of "should be spawned" brought up earlier.
To implement this idea, the game maintains a 768-byte-wide section of RAM from $EB00 to $EDFF inclusive called the Object Respawn Table (ORT). The game uses the ORT to determine whether such objects that spawned and have since despawned, should be spawned again if the player has since left the area and approaches the area where the object should spawn. Here is a more complete description of the ORT given by Sonic Retro (and slightly modified):
Object respawn table. Each object which is part of a level's object placement gets a 1-byte entry in this table, and whenever the objects manager creates a new object, it sets bit 7 of the object's entry in the object respawn table. While bit 7 is set, the object will not be loaded again by the objects manager. The other seven bits of the entry are free for use by the object - for example, monitors set bit 0 to signify a broken monitor. Since every object which is part of the level's object placement has an entry in this table, the maximum number of objects any level can have in its object placement is 768, although the only level that gets close to that number is AIZ2, with 751 objects.
One particular example in Sonic 3 & Knuckles are the stage bosses. Whenever a stage boss is part of the level's object placement (as opposed to being spawned some different way, like as a consequence of a level resize or screen event routine like the Mushroom Hill 1 miniboss), it will generally have it written for its index in the object respawn table that it should not be loaded again by the objects manager. As a consequence, the boss would not be duplicated if the player moves according to the rules far away and then back.
For the game to know where to look in the table to decide whether an object should be (re)spawned or not, the game maintains the following addresses:
$F77A-$F77B: 2-byte pointer corresponding to the address in the ORT of the next object to spawn if the player were to move right enough.
$F77C-$F77D: 2-byte pointer corresponding to the address in the ORT of the next object to spawn if the player were to move left enough.
These indices are designed to be updated at the same time and by effectively the same amount as the RAM addresses associated with the level's object placement. In other words, the game makes it so that $F772-$F775 and $F77A-$F77B will always end up referring to the same object, and $F776-$F779 and $F77C-$F77D will always end up referring to the same object. For example, if $F776-$F779 refers to the 78th object in the level's object placement, $F77C-$F77D will point to the 78th entry in the ORT and thus decide the "should be spawned" status of the 78th object.
With that invariant kept, the game can correctly decide for each object in a stage that is due to spawn whether to actually spawn it or not. And indeed this invariant is kept, until it is not.
The first ORT Desync and thus Boss 2
An ORT Desync occurs when we break the invariant that the next object to spawn as given by the level's object placement set of address and the next object to spawn as given by the ORT is the same object; that is, the game will now use these two tables improperly so it now references two different objects (hence why we call this a desync). Following the example from the previous section, an ORT Desync may end up having $F776-$F779 referring to the 78th object in the level's object placement but $F77C-$F77D referring to the 77th object. For this TAS, the desync that we will be performing is indeed based on desynchronizing $F776-$F779 and $F77C-$F77D, and to do that we will need the camera to move left enough while satisfying some conditions.
The objects in the level's object placement are generally dynamic objects, so they will be stored in the dynamic object sprite status table (DOSST). The DOSST is capable of storing up to 90 dynamic objects concurrently. Unlike another section of memory in the TAS that we will break (the KosinskiM decompression and DMA queue, more on that later), the DOSST has some protection against the game attempting to add in new objects when the DOSST is full. In particular, when the camera moves left enough that the game decides there are new objects to spawn, if the DOSST holds 90 dynamic objects already, the game will outright refuse to spawn in these objects, and in doing so will maintain the invariant.
However, the game fails to maintain that invariant under this other circumstance: when the game decides it needs to spawn in new objects from the level's object placement, the DOSST is not full, but it would be filled before the game is done spawning all the objects it needs. To give a numerical example, assume the game currently has 87 objects in the DOSST (so in theory has space for 3 more objects), but the camera moves enough to an area where it needs to spawn 4 objects. If this were to happen, the game actually has a failsafe code to abort creating new objects, restore memory to a nice state, and carry on. However, the implementation of "restoring memory to a nice state" is buggy, as due to some implementation details the value of the ORT index at $F77C-$F77D is restored to be a number smaller than the value that it should be. With this, the invariant is broken and now the two sections of memory now refer to different objects. In particular, the level's object placement section is pointing to one object, whereas the ORT section is pointing to an earlier object; and because the game will carry on updating these two values in tandem (even though they are already desynchronized), the desynchronization will carry on through the rest of the zone.
With the desync in mind, we can use that to trick the game into thinking it should respawn some objects that it otherwise should not (and similarly to not respawn some objects that it otherwise should). To explain, let's assume the ORT is currently pointing to object A and the level's object placement is pointing to object B (which by construction is an object that appears later than A). We have four possible cases when the game checks to see whether to respawn object B.
Should object A normally respawn?
Should object B normally respawn?
Net effect
Is this expected?
Yes
Yes
Object B respawns
Yes
No
No
Object B does not respawn
Yes
Yes
No
Object B abnormally respawns
No
No
Yes
Object B abnormally does not respawn
No
The Angel Island 2 boss is an object in the level's object placement, the 746th to be precise. As a result, when this boss spawns normally, because of the invariant, the ORT will have its 746th index be written in such a way that the game will NOT attempt to respawn the boss. Angel Island 2 is one of the few stages in the game that has a boss fight that allows the player to move further right from where the boss spawns and then left enough back to where in theory the boss should spawn following the rules laid out earlier. Therefore, if this was not handled properly, the boss could be duplicated by having the game interpret the boss as an object that should respawn. The game handles it properly like this: the case that once the camera crosses the boundary at position 0x4980 to the left (which coincidentally also happens to be the furthest the camera can go during the boss fight), the game will attempt to load the AI2 boss again but choose not to do so for the boss was marked as an object that should not respawn.
We nonetheless would like to duplicate the bosses in Angel Island 2 using this ORT Desync. Conveniently, it happens to be the case that the 699th through the 745th object in the level's object placement are all "should be spawned" objects and thus when they spawn would write to its corresponding slot in the ORT that they should respawn. Because we didn't desync the pair $F772-$F775 and $F77A-$F77B (the ones controlling object spawning when the player moves right enough) and the first time we spawn these objects is by going right (because of the airship cutscene), the ORT has the 699th through 745th index correctly set to respawn their associated object. Therefore, if we do one ORT Desync as described above, and then move right enough and then left enough so the game needs to decide whether to spawn the boss or not (which again, happens when we have the camera cross the boundary at 0x4980 to the left, which is a multiple of 128), the game will use the (746-1=)745th value in the ORT (or perhaps even a slightly lower index), see that this object is meant to respawn, and thus decide the boss should respawn. And voila, a second boss.
We found several places in fiery Act 1 and in Act 2 that lend themselves to ORT Desyncs, but the fastest one we found is right before the Act 1 miniboss. We have Sonic take intentional damage against a projectile fired by the Bloominator enemy to spawn 32 scattered rings (the maximum the game will spawn), while simultaneously triggering the collapsible platform and spindashing to the left towards the Fire Shield Monitor in an area where there are otherwise plenty of stage objects (mostly in the form of decorative flames). These additional objects, combined with the fact that there is the opportunity to cross a 128 pixel camera boundary a bit to the left of the Bloominator and thus an opportunity for the game to spawn in new objects and the fact that indeed the game needs to spawn in 5 objects at this camera boundary, leads to the DOSST becoming full halfway through spawning those 5 objects, which causes the ORT Desync. The ORT Desync we cause in the TAS actually offsyncs the ORT by two places, so through to the Act 2 boss arena, the ORT is 2 less than what it should be, and thus when Boss 2 spawns, it writes to the (746-2=)744th ORT slot that it should not spawn.
This ORT Desync, once active, will indeed persist until the stage restarts or we somehow fix it using a setup out of scope for this TAS. Since we do not want to fix this ORT Desync, it will indeed be active from that point all the way to the Act 2 boss. In the TAS, we see this manifest itself with certain stage objects appearing to be missing whenever we have Sonic go left. For example, halfway through the stage after an S tube, there normally is meant to be an underwater spring but it actually fails to spawn; however, it does spawn after walking a bit to the right and then back left. The exact reason why this particular behavior of "not spawn first and spawn later" happens as opposed to one of "spawn first and not spawn later" is out of scope for this TAS.
Additional note 1: When we move right to be able to have the camera later be able to cross 0x4980 to the left, we actually do some minor memory manipulation by braking. This is intentional, for we are trying to delay Bridge Skip. Bridge Skip will happen the moment that the end-of-stage cutscene button spawns taking Object slot #6. The reason why we want to delay Bridge Skip will be explained further below, but for now, the explanation given so far is sufficient. The dust objects that are generated when Sonic brakes happen to take up Object slot #6 just as the game is trying to spawn the end-of-stage cutscene button. As a result, this button takes up some other harmless slot (in the TAS, slot #8).
Additional note 2: The reason why we chose to duplicate the AI2 boss as opposed to the earlier AI1 boss is due to a difference in how these two objects are spawned. The AI2 boss is part of the level's object placement, thus vulnerable to ORT Desyncs; whereas the AI1 boss is not part of the level's object placement and it is instead spawned with a different unrelated method (via a stage resize event). Therefore, an ORT Desync will not let us duplicate the AI1 boss.
The second ORT Desync and thus Boss 3
For reasons explained later in this document, for this TAS it is not enough to spawn a total of two bosses: we actually need to spawn four bosses. However, as a consequence of spawning a boss, the 744th slot now technically correctly asserts that the boss should not respawn (for the boss marks itself as an object that should not respawn). Then, if we have Sonic move right and then left enough in order to see if another boss would spawn, that would not happen. Therefore, we need to do a second ORT Desync to spawn a third boss.
The way we achieve this in the TAS is at the boss fight itself. Taking advantage of the firing patterns of the two bosses (firing horizontally), there are a few frames where, if we have Sonic take a hit and scatter 32 rings, those rings, in conjunction with the fireballs fired by the two bosses, all of the auxiliary boss objects, and some stage layout objects, are enough to put the DOSST in a state where it is almost full. Afterwards, having the camera pan to the left across a 128 pixel boundary in such a way that it would attempt to spawn in more objects that could fit in memory would thus activate another ORT Desync. The way we achieve that is by charging and releasing a spindash to the right with the camera at a position where it is just before crossing the camera boundary at 0x4900 (a multiple of 128) to the right. The game has a mechanic where if a spindash is done in a particular way, the camera will pan forward a bit and then pan backward to its original location. Because of our choice of where to charge the spindash (just before crossing a boundary), this has the effect of allowing the camera to cross the camera boundary to the right and then, most importantly, from the right towards the left, thus invoking the game behavior that attempts to spawn objects when moving left enough. And indeed crossing the camera boundary at 0x4900 (another multiple of 128) to the left will have the game attempt to spawn two objects (a path swapper and the bridge post to the left of the bridge), and in the TAS we have the DOSST filled just enough for these two objects due to spawn to cause the ORT Desync. Needing to use projectiles from two bosses explains why we have kept these 2 bosses intentionally alive for now, but we nonetheless are able to get some hits on Boss 1 for a later setup.
For this second ORT Desync to happen such that it also allows for a third ORT Desync to happen (more on that later), we were forced to keep one object of interest in memory: the end-of-stage cutscene button that Knuckles pushes to blow up the bridge. That button will despawn if we have the camera move to the left too far. We were unable to find a setup that did not require keeping the button spawned and still allowed for both this second and a future ORT Desync to happen. We would have loved to be able to get some hits on Boss 2 when it spawned, but doing so would have moved the camera too much and thus despawned the button. Therefore, we were forced to stand in place when Boss 2 spawned and wait until it moved to a more favorable position before we could have any hits on it.
Regardless, with this second ORT Desync done, it is now enough to have the camera to cross 0x4980 to the left to spawn Boss 3. Fortunately, the spindash to the right we had just released already helped out partially, once we land we need only turn back at this point for Boss 3 to spawn. In this TAS, the game will have the decision to spawn Boss 3 rely on the 743th slot in the ORT, which originally was marked as "should be spawned".
The third ORT Desync and thus Boss 4
We still need a fourth boss for this TAS. Since we cannot reuse the current 743th slot in the ORT for this objective (similar to how in the previous ORT Desync we could not use the 744th slot), we need to perform yet another ORT Desync. However, unlike last time, there are two major differences:
We do not have 32 rings, for we lost most of them when we did the second ORT Desync. In this TAS, we managed to pick back up 6.
There are now three bosses active, each potentially firing their own sets of fireballs.
At least in a speedy manner, it does not seem that the number of objects spawned from the second difference compensates for the number of objects that no longer spawn due to the first difference. Moreover, we were unable to find a setup that instead fully relied on defeating the three bosses and had the explosion objects fill DOSST enough. As a result, we had to rely on a novel approach.
This is where our decision to delay Bridge Skip comes in handy. Once Bridge Skip is activated, several mini-explosion objects will spawn representing the blown up bridge. The amount of such explosion objects that spawn, in conjunction with the explosion objects from the bosses and some well timed braking, is actually barely enough to attempt an ORT Desync. And indeed we do, we can have the camera cross the X boundary 0x4900 to the left with just enough objects present that the 2 additional objects due to spawn are enough to cause an ORT Desync. As a result, we do that in the TAS, then have the camera cross the X boundary 0x4980 to the left to spawn Boss 4. In this TAS, the game will have the decision to spawn Boss 4 rely on the 742th slot in the ORT, which originally was marked as "should be spawned". Needing to use 3 boss objects and their 3 sets of destruction explosions to fill the DOSST enough also explains why we have kept 3 bosses alive until now; but having performed this third ORT Desync, we do not need to do any more, so it is indeed fine to have defeated these bosses.
At this point, we just need to defeat Boss 4 as efficiently as possible to spawn the fourth capsule. No longer restricted to needing to perform some memory manipulations or having to keep specific bosses alive, we are free to approach Boss 4 in any way we'd like. We would have loved to been able to get 8 hits in one cycle with one well timed jump to get all 8 hits as bounce hits to then land back to safety to the platform, as opposed to the 7 hits we get in the TAS with 7 spindashes and jumps plus an additional one after the boss moves to a different position. Unfortunately, while we can indeed get 8 hits with one jump, we have been unable to find a setup to land back on the platform such that we do not activate any of the 3 capsules we have spawned as those same capsules now get in the way and prevent us from landing back to safety. In particular, Sonic would die after getting all 8 hits if we do not activate any of the 3 capsules, which is bad as we would then need to play through to the end of Act 2 and spawn 3 bosses again; and we would be unable to engage Sonic & Knuckles if we instead hit some of the capsules while getting the 8 hits, more on that later. Therefore, we are forced to take the second fastest approach, which is to get 7 hits with 7 spindashes and 7 jumps while getting an eighth hit elsewhere, and indeed it turns out it is just barely possible to do these 7 spindashes without triggering any of the capsules.
AI2 Boss Pattern RNG
Sonic 3 & Knuckles has a general-purpose pseudo-random number generator (the RNG routine) that, given a 4-byte seed value, computes a new random 4-byte value and sets that to be the seed for the next time the generator is invoked. This computed seed can then be interpreted by function callers as a random value of sorts. Generally, this seed is set to zero at the start of each stage, but several objects may directly set the seed to some other value (e.g. Mecha Sonic in Sky Sanctuary). For Angel Island (which is the zone of concern for this section), no such objects exist, so playthroughs of the zone with the same inputs will have invoked the RNG routine from zero an equal number of times, and thus should expect the same random numbers be generated whenever it is invoked.
After an AI2 boss spawns, it will periodically go behind the waterfall, move to a different "target position", and start a new attack cycle of firing projectiles. There are four possible target positions where the AI2 boss will go to, which we label in a way that will make sense in a bit
0x0: Bottom left, boss will fire horizontal projectiles towards the right.
0x4: Top left, boss will fire vertical projectiles downwards.
0x8: Top right, boss will fire vertical projectiles downwards.
0xc: Bottom right, boss will fire horizontal projectiles towards the left.
The way that each boss decides where to move to is the following
(1) Invoke the RNG routine to get a random value, as well as advance the RNG routine.
(2) Reduce the random value using the and operator against the value 0xc to obtain one of four values: 0x0, 0x4, 0x8, 0xc. These computed values correspond to the positions listed above.
(3) If the computed value mandates that the boss move to the same position it currently is, repeat from step 1. Otherwise, move to this new position.
In other words, the boss will invoke the RNG routine, advancing the seed as many times as necessary, in order to compute a different position to go to. For completeness sake, when an AI2 boss spawns, its initial position is 0x4 (even though technically the boss is in a completely different fifth position: on top of the bridge). As a result, the first target position the boss chooses will never be 0x4 (in other words, it will never first go top left).
Each boss does this computation of which position to move to independently from one another, but they all continue to use the same RNG routine and thus advance the same RNG seed. This has two consequences that drive our TAS:
Two bosses may simultaneously decide to go to the same position. This behavior is actually beneficial for the TAS: the projectiles will continue to be in memory so long as they are on screen. It is generally the case that vertically fired projectiles will despawn faster than horizontally fired ones (for the distance to travel vertically is shorter than the horizontal one, and we even have the ability to move the camera horizontally to keep the projectiles in memory for longer). Therefore, when attempting an ORT Desync in the boss arena, it is convenient that as many bosses are possible are in positions that fire projectiles horizontally (that is, 0x0 and 0xc), as that will keep these projectiles in the DOSST for longer, thus making it more likely that an ORT Desync is possible when panning the camera left. In fact, it is even beneficial to have these bosses fire these projectiles as synchronized as possible, as it thus guarantees the two projectiles will remain spawned in memory for longer.
Once there are two or more bosses, the order in which they decide which position to go to starts to matter. Normally this would not matter beyond needing to keep track of which boss is which to avoid defeating one of them too early for the RNG routine is shared, so in theory two bosses deciding which position to go to should in theory only invoke the RNG routine twice. However, this is not necessarily accurate: depending on the order of RNG routine calls, a boss may decide it needs to "reroll" for a new position under one order but not the other. If this were to happen, now RNG has advanced a different number of times across these two scenarios, so the bosses will appear to move differently in the future across scenarios.
Here is an example illustrating the point above with two scenarios. In scenario A, boss 1 will attempt to move first before boss 2; whereas in scenario B, boss 2 will attempt to move first before boss 1. Assume in both scenario A and scenario B the following points are true: boss 1 is at position 0x0, boss 2 is at position 0x4, and the RNG routine had been invoked prior to either boss moving the same number of times.
Scenario A
Scenario B
Boss 1 rolls to find which new position to go to from 0x0.
Boss 2 rolls to find which new position to go to from 0x4.
Game decides it should go to position 0xc.
Game decides it should go to position 0xc.
0x0 is not 0xc, so boss 1 moves to 0xc.
0x4 is not 0xc, so boss 2 moves to 0xc.
Boss 2 rolls to find which new position to go to from 0x4.
Boss 1 rolls to find which new position to go to from 0x0.
Game decides it should go to position 0x0.
Game decides it should go to position 0x0.
0x4 is not 0x0, so boss 2 moves to 0x0.
0x0 is 0x0, so boss 1 does not move yet.
Boss 1 rolls again to find which new position to go to from 0x0.
Game decides it should go to position 0x8.
0x0 is not 0x8, so boss 1 moves to 0x8.
Scenario A ends up having invoked the RNG routine twice with boss 1 ending at position 0xc and boss 2 ending at position 0x0. Meanwhile, scenario B ends up completely different having invoked the RNG routine thrice with boss 1 ending at position 0x8 and boss 2 ending at position 0xc. As a consequence, we must be very careful to spawn new bosses in such a way that the order in which they invoke the RNG routine to move is beneficial. We are in control of when to spawn new bosses, for it will only happen after both the ORT Desync is done and having moved again far enough left.
The following objects in Angel Island invoke the RNG routine (and thus advance the RNG)
(1) Monkeydude badniks in either act creating a timer to decide how long to swing an arm before switching direction (clockwise to counterclockwise, counterclockwise to clockwise)
(2) A flicky being released from killing a badnik.
(3) The explosion sprites from the fiery Act 1 cutscene.
(4) The explosion sprites from defeating a boss.
(5) The sparkles from the falling signpost at the end of Act 1.
(6) A player or COM character producing bubbles from being underwater without a bubble shield in either act.
(7) A boss in Act 2 deciding which new position to move to.
Generally, only (1), (2), (5) and (7) are under the player's control in a speedrun setting. In this TAS, we were content with a playthrough that started the Act 2 sequence of boss fights with the same RNG as the previous TAS. A different TAS that attempts to improve the boss fight by using a different sequence of boss movements must either manipulate one of the 7 items listed above, or change the order in which subsequent bosses invoke the RNG routine to select which new position to go to.
New way of activating Sonic & Knuckles mode
Chaos Slots and the Buffer Overflow for Sonic & Knuckles mode.
While this is not an entirely new concept for it was heavily used in the previous TAS, it is useful to fully document this concept. Several assets in Sonic 3 & Knuckles encode their art resources in ROM using an algorithm called Kosinski Moduled (or KosinskiM) compression to save on ROM space. Some examples include several of the bosses and minibosses in the game, the title cards for each stage, and some miscellaneous objects like the cutscene plane in Angel Island 1, some Carnival Night balloons, and the end-of-stage spiral ramp in Sky Sanctuary. For the game to use these compressed resources, it must first decompress them.
To perform this decompression, the game allocates a specific section of memory, the KosinskiM decompression and DMA queue (hereinafter KMDDQ), to send this compressed data to. Values added to the KMDDQ (hereinafter referred to as "pieces") are 6 bytes wide, composed of one 4 byte component (the "Source Kosinski Module location") and one 2 byte component (the "Destination VRAM address to DMA the decompressed module to"). The critical observation is that this queue can only hold four pieces simultaneously (that is, the game can only decompress four values simultaneously) but the game does not check first if the queue has used up all its slots before adding another piece to the queue. The net effect of this is that, if there are four pieces in the queue simultaneously and a fifth one is added, the game will add this fifth piece at the next empty valid section of memory, regardless of that empty section of memory being part of the actual KMDDQ or not. In computer science terms, this is a buffer overflow by trying to fit in five items in a buffer that can hold four items and is currently holding four items, thus this fifth item overflows the buffer.
The way the game decides that a "queue slot" is empty or not (regardless of the queue slot being part of the actual section of the memory the game allocated for the KMDDQ or not) for the purposes of placing a piece in the buffer is the following. If it currently is looking at a "candidate" 6-byte-wide memory address $FFXY in the "queue", it will read the first 4 bytes at $FFXY. If those 4 bytes are zero, the game will determine the slot starting at memory address $FFXY is empty, thus use it to hold another piece, and therefore it is done. Otherwise, it will then move on to the next candidate memory address $(FFXY+6), and repeat. Note the game advances by 6 bytes instead of 4 bytes as each piece in the queue is meant to be 6 bytes wide. As a side effect, if at a particular memory address $FFXY the first 4 bytes are empty but the subsequent 2 bytes are not, the game will claim this slot is empty even if it logically has some data in it, thus overwriting those values.
In the previous TAS, we managed to trigger this buffer overflow by filling the KMDDQ with five pieces: four coming from the Hydrocity Act 2.2 title card and one coming the vertical geyser part of the Hydrocity Act 2 end-of-stage cutscene. We deliberately played through Angel Island and Hydrocity in a specific way to have this buffer overflow be done such that the earliest queue slot the game detects is available to hold this 5th piece is a 6-byte slot starting at $FFAC. This slot contains the memory address $FFAE, which determines whether Sonic & Knuckles believes it is locked in to Sonic 3 or not; and with this buffer overflow we write a value to it that tricks the game into now thinking it is no longer locked on to Sonic 3. In this new TAS, we perform an overflow of this same buffer to trick the game into thinking it is no longer locked in to Sonic 3, but instead rely on a brand new technique that relies on the fact we defeated more than one boss. A description is available in the next section.
Once Sonic 3 & Knuckles thinks it is no longer locked on to Sonic 3, the next time the game would load a title screen, it would load the Sonic & Knuckles title screen. At that point, we can select "Sonic", jump straight to Mushroom Hill, and carry on with the rest of the game. The fastest way to get to a title screen is by restarting the console. Unfortunately by doing so, the game reruns the checks to determine whether it is locked on to Sonic 3, correctly determines it is, sets the Sonic & Knuckles mode flag back to 0 and shows the Sonic 3 & Knuckles, effectively killing the glitch. Fortunately, another way to get to the title screen exists, a game over. This is the next fastest known way of getting to a title screen and does not actually run this check, which is what we employ in the TAS. Once Sonic & Knuckles mode is active, we take intentional deaths to get a Game Over, thus being able to go to the Sonic & Knuckles title screen and skip the remaining Sonic 3 stages.
Four score tallies to trigger Sonic & Knuckles mode
Each score tally is composed of three independent assets that individually need to be decompressed in the KosinskiM decompression and DMA queue (KMDDQ):
Art for the text "GOT THROUGH", with value to decompress 0x000D6A64A400 or 0x000D6A62A400.
Art for the player name ("SONIC", "MILES", "TAILS", or "KNUCKLES"), with value to decompress 0x000D6E46AD00.
Art for the act number ("ACT 1" or "ACT 2"), with value to decompress 0x0015B95CB400.
As mentioned before, the game does not check to see if this queue actually has space to add more pieces to it before adding them to the queue anyway, which results in the game loading these pieces in subsequent sections of memory (the "Chaos slots") it determines are empty. Chaos slot 9 contains the memory address holding the "Sonic & Knuckles mode" flag, so a buffer overflow that writes to this slot would generally activate Sonic & Knuckles mode. Therefore, to reach Chaos slot 9, the game would need to have needed to add 4+9=13 items to the queue (4 items for the original queue, 9 to make it to this slot containing this critical memory address).
Once the score tally spawns, its 3 required assets (or pieces) will be added to the KMDDQ simultaneously, each one taking 1 slot. Then, if 4 score tallies spawn simultaneously, all of their required assets would mean there would be 3*4=12 items in the queue. This number in theory is not enough to reach Chaos slot 9, it would only reach Chaos slot (4+4)=8. However, when adding items to the queue, the game skips slots that it determines are not empty. Conveniently due to earlier playthrough, two of said slots are actually not empty before we spawn the tally:
Chaos slot 4 - Not empty due to the 2-byte value of the memory address $FF90 it contains. This memory address holds the numerical ID of the soundtrack to play if the player were to trigger the drowning music and then exit the water. At this point, the music to restore would be the Angel Island 2 music, which has ID 0002, which is not zero.
Chaos slot 6 - Not empty due to the 2-byte value of the memory address $FF9A it contains. This memory address holds the "apparent" ID of the stage (zone+act) where the player last hit a checkpoint. These are labeled "apparent" because these are the values the game uses to display to the player information about the current stage such as the stage title card; and these values may not necessarily match how the game internally treats which stage the character is at (e.g. latter half of Icecap 1 is internally part of Act 2, so it has apparent stage value 0500 but actual value 0501). At this point, we had hit some checkpoints in Act 2, so the apparent stage value is 0001, which is not zero.
As a consequence, the game will skip over these two slots when attempting to place the 12 pieces and thus fill up to Chaos slot (4+2+4)=10, so Chaos slot 9 is filled. In this TAS, the value that ends up being written to the "Sonic & Knuckles mode flag" at 2-byte-wide $FFAE is 0x6E46, which is not zero, and thus valid for tricking the game into thinking it is no longer locked in to Sonic 3.
As a side effect, the TAS does end up writing values to Chaos slot 10. The 6 bytes affected correspond in order to the completion status of Special Stages 1, 2, 3, 4, 5, and 6. Valid byte values for each of these slots can only be: 0x00 (Chaos Emerald not collected), 0x01 (Chaos Emerald collected), 0x02 (Super Emerald created but not collected), 0x03 (Super Emerald collected). This buffer overflow fills those six bytes in with values 0x00, 0x15, 0xB9, 0x5C, 0xB4, 0x00. As some of these values are invalid, if they are not somehow fixed by the time the game attempts to render the Super Emeralds in Hidden Palace (either by virtue of entering a Big Ring in Sonic & Knuckles half, or playing through Hidden Palace normally), the game will crash. Fortunately for the TAS, these values are actually cleared once we select a player in the Sonic & Knuckles title screen, and clear values are perfectly acceptable for the game. Ultimately, Chaos slot 10 being filled is not necessary to engage Sonic & Knuckles mode, and because it is reset when choosing a character in the Sonic & Knuckles title screen, it is a harmless side effect for the TAS.
Activating four score tallies to trigger Sonic & Knuckles mode
Each boss once defeated will spawn a floating capsule. Each capsule, once hit, will start a 64-frame timer independent of any other capsules. This capsule will then spawn a score tally of its own immediately once all of these conditions are simultaneously true:
Its own 64-frame timer expired.
Player is not airborne.
Player is not dead.
To fully take advantage of each of the 4 score tallies being able to activate Sonic & Knuckles mode, we would like for these tallies to spawn simultaneously (to be more precise, it is roughly within 4-6 frames of the "first" score tally posting art in the decompression queue). The easiest way to achieve this is to hit all 4 capsules simultaneously, as then all 64-frame timers would expire almost simultaneously, guaranteeing that the 4 tallies would appear simultaneously. This simultaneity requirement explains why earlier we stated we could not defeat Boss 4 with one jump and 8 bounce hits while opening some of the capsules: if we were to do that, the 64-frame timers for such capsules would have elapsed by the time Sonic was on the ground again before we even get a chance to even hit the fourth capsule, which would trigger a buffer overflow that was not large enough to activate Sonic & Knuckles mode.
With that simultaneity requirement in mind, in the TAS we intentionally choose to approach it in a nontrivial way: we charge a spindash, jump to hit 3 capsules simultaneously first and several frames later from the same jump hit the 4th capsule, and then land at the bottom of some junk terrain very far down the stage. The first 3 capsules would then trigger their own 64-frame timer, then several frames later the 4th capsule would trigger its own 64-frame timer, which would thus expire later than those first three timers. The reason why these timers from the earliest opened capsules are now not a problem is because of the second condition listed above: the tallies will not appear as long as Sonic is airborne, which happens because we make Sonic take a long fall down to the junk terrain at the bottom. In particular, all timers even if not synchronized with one another will end up expiring while Sonic is airborne, so the moment Sonic is no longer airborne by landing on the junk terrain all 4 capsules will simultaneously satisfy the requirement to spawn in their own score tally, which is sufficient for our purposes.
The reason why we decide to go with this approach as opposed to one where Sonic hits all 4 capsules simultaneously or one where Sonic remains on the boss arena platform while the tallies play is a timing issue. Once the tallies complete, the end-of-stage cutscene will play, which locks controls and forces Sonic to walk to the right until he reaches the point where in the cutscene he would look up to see Knuckles push the button. Because the bridge collapsed already due to Bridge Skip, Sonic will start falling already, but still at the point where Sonic reaches the point where he looks up to see Knuckles the cutscene partially triggers in the form of resetting his vertical velocity. This effectively has Sonic stop mid-air and start falling again halfway through from 0 vertical speed which negates the earlier momentum and overall contributes to a slower fall. By having Sonic fully fall to this lower junk terrain before the cutscene starts in such a way that he would then die before reaching the look-up X coordinate, we negate the vertical speed reset, which actually compensates for the fact that we start the tally later (as the 64-frame timers had long since expired) by a few seconds.
The Pity Shield
The buffer overflow described in the previous section also accounts for why Sonic spawns from the AI2 death with a lightning shield (a phenomenon RTA runners have affectionately dubbed "the pity shield"). Chaos slot 5 contains memory address $FF96, whose 1-byte value the game uses to determine which shield to give to a player when restarting a stage having come back from a Special Stage. However, the requirement of "having come back from a Special Stage" is not properly implemented, for the value at $FF96 is modified under these circumstances:
(1) It is cleared if (re)starting an act in Sky Sanctuary, Death Egg, or a zone up to Lava Reef having both not hit any checkpoints on the way or just come out of a Special Stage.
(2) If it was not cleared by the first point, it is then cleared if (re)starting an act in Sky Sanctuary, Death Egg, or a zone up to Lava Reef after deciding which shield to grant a player and then granting said shield.
(3) It is set when entering a Big Ring to store the shield the player has.
(4) It is set when entering a Bonus Stage to store the shield the player has (although later behavior makes this behavior unused).
(5) It is set when starting Lava Reef 3 (the boss fight act of Lava Reef) to store the shield the player has.
(6) It is set when starting Death Egg 3 (the boss fight act of Death Egg) to store the shield the player has.
(7) It is set when entering a Super Emerald Special Stage from "Special Stage Hidden Palace" to store the shield the player has (as due to the first point it is currently cleared).
(8) It is set when activating the teleporter from "Special Stage Hidden Palace" to warp back to whatever zone player was prior to entering the Big Ring (as due to the first point it is currently cleared).
In particular for this setup, it is the case that $FF96 happens to be set via the buffer overflow to some non-zero value. Since we hit a checkpoint in Act 2 to allow for the quicker deaths, the clearing of point (1) does not happen. Instead, the clearing of point (2) happens, which also grants the shield to Sonic. $FF96 in the TAS happens to be the value 0x6E, which due to an internal implementation detail the game interprets to be a lightning shield, thus granting a lightning shield to Sonic. Because $FF96 is now cleared, subsequent deaths performed for the setup will not have a Pity Shield present.
For completeness, how the game interprets values of $FF96 to grant a shield is by following a bitmask that can be interpreted as follows:
Lower Bound (inclusive)
Upper Bound (inclusive)
Result
0x00
0x0F
No shield
0x10
0x1F
Fire shield
0x20
0x2F
Lightning shield
0x30
0x3F
Fire shield
0x40
0x4F
Bubble shield
0x50
0x5F
Fire shield
0x60
0x6F
Lightning shield
0x70
0x7F
Fire shield
0x80
0x8F
No shield
0x90
0x9F
Fire shield
0xA0
0xAF
Lightning shield
0xB0
0xBF
Fire shield
0xC0
0xCF
Bubble shield
0xD0
0xDF
Fire shield
0xE0
0xEF
Lightning shield
0xF0
0xFF
Fire shield
An ideal speedrun would actually not have the player spawn with a Pity Shield. This is because we have to spend some extra seconds manually losing the shield first and waiting out the 120 invulnerability frames before being able to die to most objects, like the spikes, enemies or the monkey projectiles. Other methods that do not involve getting hit twice (crush death, drowning, time over) take too long.
We also currently do not know of a way of achieving an equally fast buffer overflow that does not come with a pity lightning shield. The two plausible alternatives are:
Find a way of partially filling Chaos slot 5 before triggering the buffer overflow in such a way that $FF96 contains a value that would grant no shield. The only known way to do that involve either entering and exiting a bonus/special stage with a shield, but that messes up Bridge Skip, which requires that the playthrough from Angel Island 1 be continuous.
Get a pity fire shield. Technically one of the pieces put in the "queue" by the score tally could end up writing to $FF96 the value 0xB9 if placed appropriately in the queue, which would grant the player a pity fire shield. The fire shield could be useful in the sense that there is an opportunity for a crush death by running into some platforms that protrude in front of and behind waterfalls that could be reached by using the fire dash. However, we do not know of a setup to get this piece to land there, and even if it existed, it requires maneuvering the player to the crush death location fast enough with the cycles of the protruding platform aligning.
Table summary
Here's a handy reference table that summarizes how we use this buffer overflow to activate Sonic & Knuckles mode. For each slot, we list the addresses of the 3 words (groups of 2 bytes) that make up the 6 bytes for each slot, what purpose the address serves in Sonic 3 & Knuckles, and how we end up filling these slots in the TAS to activate Sonic & Knuckles mode. Some observations:
Some of the words use their 2 bytes for two different purposes, we include these two uses in the Description field separated by a + symbol. For the purpose of the buffer overflow, it is only sufficient that any of the first 2 words have a non-zero value, hence why some items in the "How it is filled" column have a "(not applicable)" or "(not necessary)" annotations.
"KMDDQ" refers to KosinskiM decompression and DMA queue slots, that is, the section of memory the game normally uses for decompression; whereas "Chaos" refers to Chaos slots, that is, the section of the memory that is filled with buffer overflows for KMDDQ is full.
The letters "A", "B", and "C" next to terms "Score Tally 1", "Score Tally 2", "Score Tally 3", "Score Tally 4" indicate which of the three pieces that required decompression was used. For example, "Score Tally 2C" refers to the "Act 2" text that the second score tally loads; and "Score Tally 4B" refers to the "SONIC" text that the fourth score tally loads. More information is available in an earlier section.
Filling in "Chaos 10" is technically unnecessary for the purposes of breaking the lock-on technology, but it is a side effect of the fourth score tally needing that extra queue slot. More information is available in an earlier section.
Slot Name
Address
Description
How it is filled
Notes
KMDDQ 1
$FF64
KMDQQ: Buffer Slot 1
Score Tally 1A
Used to claim this slot as non-empty
$FF66
KMDQQ: Buffer Slot 1
Score Tally 1A
Not necessary
$FF68
KMDQQ: Buffer Slot 1
Score Tally 1A
Not applicable
KMDDQ 2
$FF6A
KMDQQ: Buffer Slot 2
Score Tally 1B
Used to claim this slot as non-empty
$FF6C
KMDQQ: Buffer Slot 2
Score Tally 1B
Not necessary
$FF6E
KMDQQ: Buffer Slot 2
Score Tally 1B
Not applicable
KMDDQ 3
$FF70
KMDQQ: Buffer Slot 3
Score Tally 1C
Used to claim this slot as non-empty
$FF72
KMDQQ: Buffer Slot 3
Score Tally 1C
Not necessary
$FF74
KMDQQ: Buffer Slot 3
Score Tally 1C
Not applicable
KMDDQ 4
$FF76
KMDQQ: Buffer Slot 4
Score Tally 2A
Used to claim this slot as non-empty
$FF78
KMDQQ: Buffer Slot 4
Score Tally 2A
Not necessary
$FF7A
KMDQQ: Buffer Slot 4
Score Tally 2A
Not applicable
Chaos 1
$FF7C
Related to Competition Mode
Score Tally 2B
Used to claim this slot as non-empty
$FF7E
Related to Competition Mode
Score Tally 2B
Not necessary
$FF80
Related to Level Select
Score Tally 2B
Not applicable
Chaos 2
$FF82
Level Select: selected stage
Score Tally 2C
Used to claim this slot as non-empty
$FF84
Level Select: selected sound
Score Tally 2C
Not necessary
$FF86
Title screen: selected option + Unused
Score Tally 2C
Not applicable
Chaos 3
$FF88
Unused
Score Tally 3A
Used to claim this slot as non-empty
$FF8A
Competition Mode: monitor selection + type
Score Tally 3A
Not necessary
$FF8C
Competition Mode: type
Score Tally 3A
Not applicable
Chaos 4
$FF8E
Score Tally: Value of "Total"/10
Zeroed just as tallies spawn
Not necessary
$FF90
Music to use when surviving drowning
AI2 music ID is 2, which is not zero
Used to claim this slot as non-empty
$FF92
Special Stage: Bitmask for having entered some of the zone's big rings
Not modified in the TAS
Not applicable
Chaos 5
$FF94
Special Stage: Bitmask for having entered some of the zone's big rings
Score Tally 3B
Used to claim this slot as non-empty
$FF96
Shield to restore coming from a Special or Bonus Stage + Flag to keep or reset ORT on stage restart
Score Tally 3B
Not necessary
$FF98
Unused
Score Tally 3B
Not applicable
Chaos 6
$FF9A
Apparent Zone and Act where last checkpoint was hit
Hit a checkpoint in AI2
Used to claim this slot as non-empty
$FF9C
Apparent Zone and Act where last special stage was entered
Not modified in the TAS
Not necessary
$FF9E
Unused + Blue Sphere: Flag for expected ROM header value
Not modified in the TAS
Not applicable
Chaos 7
$FFA0
Blue Sphere: Flag for allowing all stages to be played versus just one+Menu state
Score Tally 3C
Used to claim this slot as non-empty
$FFA2
Blue Sphere: Map section ID
Score Tally 3C
Not necessary
$FFA4
Blue Sphere: Map section ID
Score Tally 3C
Not applicable
Chaos 8
$FFA6
Blue Sphere: Level number
Score Tally 4A
Used to claim this slot as non-empty
$FFA8
Blue Sphere: Level number
Score Tally 4A
Not necessary
$FFAA
Blue Sphere: Menu state 2 + Progress Flag
Score Tally 4A
Not applicable
Chaos 9
$FFAC
Blue Sphere: Difficulty + Target Difficulty
Score Tally 4B
Not necessary
$FFAE
Sonic & Knuckles mode flag
Score Tally 4B
This activates Sonic & Knuckles mode
$FFB0
Chaos Emerald Count + Super Emerald Count
Score Tally 4B
Not applicable
Chaos 10
$FFB2
Special Stage: Completion state of Special Stages 1 + 2
Score Tally 4C
Not necessary
$FFB4
Special Stage: Completion state of Special Stages 3 + 4
Score Tally 4C
Not necessary
$FFB6
Special Stage: Completion state of Special Stages 5 + 6
However, as original footage of both Angel Island 1 & 2 wasn't available, despite attempts to reproduce it over the years, nobody could, that was until the 1st of June 2025, when Chrezm started looking again at it, and managed to get the duplicate boss. This resulted in the mystery of the duplicate boss being solved, but there was no known way of exploiting it in a speedrun to be useful.
In September 2025, whilst doing a casual speedrun of Sonic 3 & Knuckles, Robblehead had a spike platform spawn twice in Lava Reef 1. This became the 2nd known instance of an ORT Desync without debug mode. With assistance of a recorded complete playthrough of the stage, we determined that Robblehead had indeed triggered an ORT Desync: during the driller cutscene halfway through Act 1, Robbblehead managed to trigger an ORT Desync accidentally by crossing a 128-pixel camera boundary while simultaneously braking and having the platform objects collapse courtesy of the driller in such a way that the DOSST filled up. It went on to become an - albeit slower - alternative to skipping Lava Reef 2.
This also caused Chrezm to take another look at the duplicate AI2 boss, and discovered that hitting the 2 capsules together, would fill 2 Chaos slots. This meant that Angel Island could be faster than the previously known Hydrocity Zone's single Chaos slot, but this alone would unfortunately not prove to be faster for the TAS.
3 Bosses and thus 3 capsules was theorised, which would fill 5 Chaos slots, and was found to be possible by triggering an ORT Desync in the Act 2 boss arena itself. This meant we could fill 2 of the 9 Chaos slots with some other in game actions (Chaos slot 6 by entering any big ring in Angel Island, Chaos slot 3 by activating "No Monitor" in Competition mode), which in conjunction with the 2 other much more easily filled slots of Chaos 4 and Chaos 6, would lead to the (2+3)+2+2=9 Chaos slots needed for a buffer overflow that engages Sonic & Knuckles mode.
Soon after the idea of 4 bosses was floated by triggering another ORT Desync in the Act 2 boss arena itself. The theoretical upside was very promising: if fast enough, having 4 capsules and thus 4 score tallies would negate the need for diverting to blue spheres and the competition menu, as it would ultimately cause (2+3+3)+2+2=10 Chaos slots to be filled, which works for our purposes as the critical ninth Chaos slot would indeed be filled. However, it was going to be tight, as it meant keeping the first two bosses alive to activate Boss 3, and since we needed to lose rings for the activation of Boss 3, it wouldn't be a viable option for a Boss 4. Therefore, we'd need to use the extra objects created from killing all 3 bosses simultaneously, along with the bridge objects from activating bridge skip, to do one final ORT Desync to spawn Boss 4.
After dispatching Boss 4, it was just a matter of figuring out the fastest way to open the 4 capsules correctly to engage Sonic & Knuckles mode. After some trial and error, we determined that such way involved a spindash and a jump to open the 4 capsules and then land at some junk terrain at the bottom, which after the score tallies completed, would lead to a death due to the end-of-stage cutscene activating that forces Sonic to walk right. At that point, minus the pity shield, we are back to matching the actions of the previous TAS of triggering a Game Over to go to the Sonic & Knuckles title screen and thus continue from the Sonic & Knuckles stages.
Having enough objects for the ORT Desync for Boss 3 without killing the other two was by far the hardest part of this TAS, which required coordinating fireball objects, and timing getting hit for the rings - which can quickly dissipate and reduce the amount of objects in memory whilst attempting to move the camera over a boundary.
Potential Improvements
Using a different RNG when entering the AI2 boss arena could provide a more beneficial pattern. As mentioned earlier however, the only ways to generally advance RNG in Angel Island are:
Juggling the sign post at the end of Act 1.
Killing more enemies.
Waiting by the monkey enemies, as their arm swing advances the RNG about once every 30 frames.
Activating Boss 2 earlier would potentially lead to a faster time, but the fireball launches are further out of sync adding further difficulty to finding a set up for the Desync to cause the Boss 3 activation (if even possible), and also potentially causing issues with being able to kill all 3 bosses in quick succession for Boss 4. Given it took Ben 3 evenings trying to set up the Boss 3 activation without killing any of the bosses, we didn't like the chances.
You may be wondering if this could be furthered with activating more bosses past Boss 4. The answer is yes it is possible, but from a Chaos slot perspective, it doesn't provide any benefit (the "slots" after aren't useful, e.g. slow-mo mode, or demo-mode - where controls are disabled). With the right RNG, a Boss 5 could potentially be used to kill Sonic sooner, but that would require a rewrite.
Suggested Frames for Screenshot
Recommended frame: 11959 or 14769 (there are plenty of good frames during the boss/capsule madness, any from that area would be acceptable).
Other character possibilities
Whilst Tails can perform the boss duplication glitch, he can't be chosen in S&K, so for him it would be a multi-character style run.
Knuckles is also able to use this glitch in one of the other places found in act 1, it still needs to be investigated whether he can spawn 3 or 4 bosses to maximise the timesave.
CoolHandMike: This is a wild technique to spawn multiple bosses to do a buffer overflow to advance further in the game skipping the rest of Sonic 3. Nearly spit out my drink once I saw multiple bosses on screen! This is a highly technical tas with an extremely in-depth explanation in the submission notes. Congrats to everyone involved for yet again pushing this game further! As a note there are about 250 frames for entertainment at the end. The authors expressed their wish to leave this in the movie.
Joined: 1/24/2018
Posts: 371
Location: Stafford, NY
The previous TAS completely eliminated three zones from the Sonic 3 part of the combined game (Carnival Night, Ice Cap and Launch Base) and reduced Marble Garden to a bit role. Now - I'm presuming due to the hedgehog's famous distaste for watery environments as well as Robotnik's robotic duplicating machine going horribly wrong - only Angel Island zone itself of the original Sonic 3 now stands. Well done you guys! (Yes vote.)
c-square wrote:
Yes, standard runs are needed and very appreciated here too
Dylon Stejakoski wrote:
Me and the boys starting over our games of choice for the infinityieth time in a row because of just-found optimizations
^ Why I don't have any submissions despite being on the forums for years now...
Joined: 2/11/2019
Posts: 15
Location: 🇳🇿 New Zealand
I laughed pretty hard when I saw the duplicated Robotniks, and then even harder once I realised it allows skipping the remaining Sonic 3 zones. Absolutely a yes vote!
Don't mind me, I was born on Friday the 13th.
(I'm not TASing that NES game, okay?)
Is there any chance it would be possible to get an overflow write into the save data and, instead of restarting in unlocked S&K mode, writing values that let you go back to the main menu and level select directly to CLEAR as a functional credits warp?
Looked at the movie file at the end and there appears to be 250 frames of additional frames that look like for entertainment. Do you still wish to keep those? I did not see anything in the submission notes about that (although I might have missed it).
Looked at the movie file at the end and there appears to be 250 frames of additional frames that look like for entertainment. Do you still wish to keep those? I did not see anything in the submission notes about that (although I might have missed it).
Yes, please. Chrezm and I have considered removing them in both this and last year's TAS, but ultimately decided against it. They originate from [4266] Genesis Sonic 3 & Knuckles "Sonic" by kaan55 in 28:24.76, and it's clear it was a deliberate stylistic choice - which is likely because Sonic dies on the last frame, but Chrezm and I like the assumption/coincidence that it makes the TAS end timing coincide with when we stop the timer in RTA runs.
Both times we've discussed it, we've always came to the same conclusion - it's a cheap time save that feels rather disrespectful to the work we're building upon.
Mr._Pwnage wrote:
Is there any chance it would be possible to get an overflow write into the save data and, instead of restarting in unlocked S&K mode, writing values that let you go back to the main menu and level select directly to CLEAR as a functional credits warp?
Unfortunately, that would likely require ACE, which hasn't been found yet. I'm not entirely sure it's possible with the limited amount of memory we have to play with, and most, if not all of it, is determined by the game, e.g. we can't control that we get the pity shield from 4 capsules.
The only useful (or in most cases detrimental) Save Ram Manipulation we are currently aware of in this game is the Emerald Copy glitch, where there is 1 non-lag frame available in the loading of the data select screen, that if you press Start on that frame, it will have the emerald data from the last (8th) save slot still in memory. You can then go into a Blue Sphere stage, and irrespective of the outcome, the emeralds from that last slot will be saved to your file. SuperSonic has a video demonstration here:
Link to video - the detrimental outcome is if you're going for collecting emeralds, and you perform the glitch, if your last save file is empty, then your emerald progress is lost.