Sonic 3/Sonic 3 & Knuckles Guide - How to modify the ACTUAL level order!

Discussion in 'Tutorials' started by Inferno, Jan 23, 2020.

  1. Inferno

    Inferno Rom Hacker Member

    Joined:
    Oct 27, 2015
    Messages:
    132
    Location:
    Sky Base Zone, South Island
    Well, anyone remember my first post, which sits in the tutorial archive? If not, here's the guide. It was about how to modify the level select. Now, I've located the actual level order! So, if you are interested in changing which zones go to which zones, this guide is for you!

    NOTE: This does not cover actually changing how the level transitions look. All this covers is rerouting some level transitions to bring you to different zones.

    So, if you look around s3k.asm or s3.asm, you'll potentially find StartNewLevel. This is what it looks like in both asm files:
    Code:
    StartNewLevel:
            move.w    d0,(Current_zone_and_act).w
            move.w    d0,(Apparent_zone_and_act).w
            move.w    #1,(Restart_level_flag).w
            clr.b    (Last_star_post_hit).w
            clr.b    (Special_bonus_entry_flag).w
            rts
    As you can see, this code is moving the register d0 to the current zone and act. WAIT A SECOND! This is the main hint as to how the game selects levels. Now, start searching for branches to StartNewLevel. The first thing you should see when going from StartOfRom is this:
    Code:
            move.w    #$A01,d0
            jmp    (StartNewLevel).l
    AHA! All branches to StartNewLevel are in this format, with the next level being loaded into d0 for StartNewLevel. This just so happens to be sending the player character to the 2nd act of Sky Sanctuary, or in other words, Knuckles' SSZ.
    Now, with this knowledge, one may want to restore the original level order. We'll use this as an example. So, search through the StartNewLevel branches until you find this in loc_4C31C for S3 or loc_6E80C for S3K:
    Code:
            move.w    #$500,d0
            jsr    (StartNewLevel).l
            jmp    (Go_Delete_Sprite_2).l
    When looking at the context, this is Sonic and Tails' level transition to Ice Cap. Ice Cap Act 1 is ID $500 when in the format of Current_zone_and_act. Flying Battery Act 1 is ID $400. Change that $500 to $400 so that the code looks like this:
    Code:
            move.w    #$400,d0
            jsr    (StartNewLevel).l
            jmp    (Go_Delete_Sprite_2).l
    Now, the cannon will shoot Sonic and/or Tails onto the Flying Battery (well, they will just be there, but the point still stands). And because this is only Sonic and/or Tails' level transition code, Knuckles will still go to Ice Cap!

    Note that this example will not work in S3A unless you manually readded FBZ somehow, and the rest of this won't either.

    Now, if one wants MHZ to go to SPZ, and FBZ to ICZ, we must look for the same code as above, but pointing to the respective zones and acts.
    If you look for the branch for MHZ to go to FBZ, you'll eventually come across loc_7645E, which looks like this:
    Code:
    loc_7645E:
            move.w    #$400,d0
            jsr    (StartNewLevel).l
            jmp    (Delete_Current_Sprite).l
    Now, do similar as above. It should look like this:
    Code:
    loc_7645E:
            move.w    #$800,d0
            jsr    (StartNewLevel).l
            jmp    (Delete_Current_Sprite).l
    And finally, let's look for FBZ going to SPZ. You should come across loc_70938, which should look like this:
    Code:
    loc_70938:
            move.w    #$800,d0
            jsr    (StartNewLevel).l
            jmp    (Delete_Current_Sprite).l
    When you change it, it should look like this:
    Code:
    loc_70938:
            move.w    #$500,d0
            jsr    (StartNewLevel).l
            jmp    (Delete_Current_Sprite).l
    As such, when Sonic and/or Tails beat CNZ, they'll go to FBZ, land in ICZ, and go from MHZ to SPZ. And Knuckles will skip from CNZ to ICZ, due to Knuckles having a unique CNZ level transition.

    Hopefully this helps you with your future projects.