[Sonic 1 Github] Per Act Level Header (Final Patch for Clone Driver V2 users)

Discussion in 'Tutorials' started by Carlos Iagnecz, Feb 5, 2024.

  1. Carlos Iagnecz

    Carlos Iagnecz Newcomer Trialist

    Joined:
    Jun 16, 2023
    Messages:
    5
    Location:
    Brazil
    04/03/2024: Bugfix, turns out sound effect 96 wasn't the root of the issue, apparetly the Clone Driver's 'SMPS_Asserts' crashed the game, turn that off and turn on 'SMPS_SoundTest'
    29/02/2024: Bugfix, replace the LevelHeader entries from Scrap Brain with the new ones, the original guide did not account for the act 2 pallete
    25/02/2024: Issue Solved, sound effect 96 crashes the game in Clone Driver, replace it or change the settings to fix it

    This guide will use Inferno's Bit Math calculations as reference, it doesn't aim to just adding it
    but explaining the method and routines a bit in depth.

    Step 1: Level Data Load
    Open 'sonic.asm' and go to 'LevelDataLoad'.

    What this does is, get the info from the header after the pre level loop
    (16x16 & 256x256 tiles, pallete and 2nd Pattern Load Cue).

    Now find this part:

    Code:
    move.b    (v_zone).w,d0
    lsl.w    #4,d0
    Here we load 'v_zone' and Logical Shift Left 4 times that multiplies the value by 2 to the power of operand,
    the equivalent of (Zone * 16) because of the 'LevelHeader' having that ammount of items per entry

    Step 2: Allowing acts in the calculation
    swap the '.b' to a '.w', since the act is placed right after, however the mixing of both has some consequences.
    I am gonna use Labyrinth Zone Act 2 (v_zone = 1 & v_act = 1) as reference:

    Code:
    v_zone 00000001 v_act 00000001
    
    0*32768 0*16384 0*8192 0*4096 0*2048 0*1024 0*512 1*256 0*128 0*64 0*32 0*16 0*8 0*4 0*2 1*1
    

    257...

    so what is happening is: ((Zone * 256) + Act) * 16

    Step 3: Fixing the Zone's impact
    Place inbetween both instructions ROtate Right:

    Code:
    ror.b   #2,d0
    What this does is fix it by dividing the bits that belong to v_zone by 64:
    ((Zone * (256/64)) + Act * 64) * 16 -> ((Zone * 4) + Act * 64) * 16
    However as seen, the v_act section is also shifted, giving a simmilar issue.

    Step 4: Fixing the Act's impact
    Replace 'lsl.w #4,d0' with 'lsr.w #2,d0'

    If Logical Shift Left multiplies by 2^Op. the Logical Shift Right divides by 2^Op. So in a clean slate, we use 6 (2~6=64)
    However due to the lsl, we subtract both opperands and only shift it by 2.
    Making it: ((Zone * 4) + Act * 64) / 4 -> (Zone * 4) + Act) * 16

    Step 5: Hardcoded stuff
    Still in 'LevelDataLoad' remove this hardcoded thing:

    Code:
    cmpi.w    #(id_LZ<<8)+3,(v_zone).w ; is level SBZ3 (LZ4) ?
            bne.s    .notSBZ3    ; if not, branch
            moveq    #palid_SBZ3,d0    ; use SB3 palette
    
    .notSBZ3:
            cmpi.w    #(id_SBZ<<8)+1,(v_zone).w ; is level SBZ2?
            beq.s    .isSBZorFZ    ; if yes, branch
            cmpi.w    #(id_SBZ<<8)+2,(v_zone).w ; is level FZ?
            bne.s    .normalpal    ; if not, branch
    
    .isSBZorFZ:
            moveq    #palid_SBZ2,d0    ; use SBZ2/FZ palette
    
    .normalpal:
    Step 6: Copies of the code
    There is another method for loading the level, before the Title Cards even show in 'Level_NoMusicFade'
    It loads the standard and level PLCs and it uses the same method.'GM_Credits' also has that.

    Make the same changes in both places.

    Step 7: Collision Loading
    If you try to make a act standalone from the rest, you might want to edit the collision separately. Go to 'ColIndexLoad' and apply the same method, however since its 'lsl.w #2,d0' and not 4. change the lsr's operand to 4

    Code:
    move.w    (v_zone).w,d0
    ror.b   #2,d0
    lsr.w    #4,d0

    Step 8: Extending 'ColPointers'
    Since we are having a single item per act, it will need 4x as much entries. Replace the contents of 'ColPointers' with this:

    Code:
    ColPointers:
        dc.l Col_GHZ
        dc.l Col_GHZ
        dc.l Col_GHZ
        dc.l Col_GHZ
        dc.l Col_LZ
        dc.l Col_LZ
        dc.l Col_LZ
        dc.l Col_LZ
        dc.l Col_MZ
        dc.l Col_MZ
        dc.l Col_MZ
        dc.l Col_MZ
        dc.l Col_SLZ
        dc.l Col_SLZ
        dc.l Col_SLZ
        dc.l Col_SLZ
        dc.l Col_SYZ
        dc.l Col_SYZ
        dc.l Col_SYZ
        dc.l Col_SYZ
        dc.l Col_SBZ
        dc.l Col_SBZ
        dc.l Col_SBZ
        dc.l Col_SBZ
    Step 9: Hardcoded collision for ending
    be aware that the ending uses a hardcoded method, specifically this line in 'End_LoadData':

    Code:
    'move.l    #Col_GHZ,(v_collindex).w'

    If you want to split the ending swap that to a copy, i wont dive much into making the ending independant since it is a separate thing from regular level loading in the game's code.

    Step 10: Extending 'LevelHeaders'
    Open '_inc/LevelHeaders.asm' , the same issue on 'ColPointers' happens here so, replace the main header with this:


    Code:
        lhead    plcid_GHZ,    Nem_GHZ_2nd,    plcid_GHZ2,    Blk16_GHZ,    Blk256_GHZ,    bgm_GHZ,    palid_GHZ    ; Green Hill Act 1
        lhead    plcid_GHZ,    Nem_GHZ_2nd,    plcid_GHZ2,    Blk16_GHZ,    Blk256_GHZ,    bgm_GHZ,    palid_GHZ    ; Act 2
        lhead    plcid_GHZ,    Nem_GHZ_2nd,    plcid_GHZ2,    Blk16_GHZ,    Blk256_GHZ,    bgm_GHZ,    palid_GHZ    ; Act 3
        lhead    plcid_GHZ,    Nem_GHZ_2nd,    plcid_GHZ2,    Blk16_GHZ,    Blk256_GHZ,    bgm_GHZ,    palid_GHZ    ; Act 4 (Unused)
        lhead    plcid_LZ,    Nem_LZ,        plcid_LZ2,    Blk16_LZ,    Blk256_LZ,    bgm_LZ,        palid_LZ    ; Labyrinth Act 1
        lhead    plcid_LZ,    Nem_LZ,        plcid_LZ2,    Blk16_LZ,    Blk256_LZ,    bgm_LZ,        palid_LZ    ; Act 2
        lhead    plcid_LZ,    Nem_LZ,        plcid_LZ2,    Blk16_LZ,    Blk256_LZ,    bgm_LZ,        palid_LZ    ; Act 3
        lhead    plcid_LZ,    Nem_LZ,        plcid_LZ2,    Blk16_LZ,    Blk256_LZ,    bgm_LZ,        palid_SBZ3    ; Scrap Brain Act 3
        lhead    plcid_MZ,    Nem_MZ,        plcid_MZ2,    Blk16_MZ,    Blk256_MZ,    bgm_MZ,        palid_MZ    ; Marble Act 1
        lhead    plcid_MZ,    Nem_MZ,        plcid_MZ2,    Blk16_MZ,    Blk256_MZ,    bgm_MZ,        palid_MZ    ; Act 2
        lhead    plcid_MZ,    Nem_MZ,        plcid_MZ2,    Blk16_MZ,    Blk256_MZ,    bgm_MZ,        palid_MZ    ; Act 3
        lhead    plcid_MZ,    Nem_MZ,        plcid_MZ2,    Blk16_MZ,    Blk256_MZ,    bgm_MZ,        palid_MZ    ; Act 4 (Unused)
        lhead    plcid_SLZ,    Nem_SLZ,    plcid_SLZ2,    Blk16_SLZ,    Blk256_SLZ,    bgm_SLZ,    palid_SLZ    ; Star Light Act 1
        lhead    plcid_SLZ,    Nem_SLZ,    plcid_SLZ2,    Blk16_SLZ,    Blk256_SLZ,    bgm_SLZ,    palid_SLZ    ; Act 2
        lhead    plcid_SLZ,    Nem_SLZ,    plcid_SLZ2,    Blk16_SLZ,    Blk256_SLZ,    bgm_SLZ,    palid_SLZ    ; Act 3
        lhead    plcid_SLZ,    Nem_SLZ,    plcid_SLZ2,    Blk16_SLZ,    Blk256_SLZ,    bgm_SLZ,    palid_SLZ    ; Act 4 (Unused)
        lhead    plcid_SYZ,    Nem_SYZ,    plcid_SYZ2,    Blk16_SYZ,    Blk256_SYZ,    bgm_SYZ,    palid_SYZ    ; Spring Yard Act 1
        lhead    plcid_SYZ,    Nem_SYZ,    plcid_SYZ2,    Blk16_SYZ,    Blk256_SYZ,    bgm_SYZ,    palid_SYZ    ; Act 2
        lhead    plcid_SYZ,    Nem_SYZ,    plcid_SYZ2,    Blk16_SYZ,    Blk256_SYZ,    bgm_SYZ,    palid_SYZ    ; Act 3
        lhead    plcid_SYZ,    Nem_SYZ,    plcid_SYZ2,    Blk16_SYZ,    Blk256_SYZ,    bgm_SYZ,    palid_SYZ    ; Act 4 (Unused)
        lhead    plcid_SBZ,    Nem_SBZ,    plcid_SBZ2,    Blk16_SBZ,    Blk256_SBZ,    bgm_SBZ,    palid_SBZ1    ; Scrap Brain Act 1
        lhead    plcid_SBZ,    Nem_SBZ,    plcid_SBZ2,    Blk16_SBZ,    Blk256_SBZ,    bgm_SBZ,    palid_SBZ2    ; Act 2
        lhead    plcid_SBZ,    Nem_SBZ,    plcid_SBZ2,    Blk16_SBZ,    Blk256_SBZ,    bgm_FZ,    palid_SBZ2    ; Final Zone
        lhead    plcid_SBZ,    Nem_SBZ,    plcid_SBZ2,    Blk16_SBZ,    Blk256_SBZ,    bgm_SBZ,    palid_SBZ2    ; Act 4 (Unused)
        lhead    0,        Nem_GHZ_2nd,    0,        Blk16_GHZ,    Blk256_GHZ,    bgm_SBZ,    palid_Ending    ; Ending Act 1
        lhead    0,        Nem_GHZ_2nd,    0,        Blk16_GHZ,    Blk256_GHZ,    bgm_SBZ,    palid_Ending    ; Act 2 (Unused)
        lhead    0,        Nem_GHZ_2nd,    0,        Blk16_GHZ,    Blk256_GHZ,    bgm_SBZ,    palid_Ending    ; Act 3 (Unused)
        lhead    0,        Nem_GHZ_2nd,    0,        Blk16_GHZ,    Blk256_GHZ,    bgm_SBZ,    palid_Ending    ; Act 4 (Unused)
        even
    Now you can edit most aspects of a act, except for music separate from the zone. The reason why i did'nt use the 'saved_music' variable from the 'Per Act Music by Bit Math' guide is, what if you wanted to change the music mid level? It would screw the entire level and also, it is only calculated once.
     
    Last edited: Mar 4, 2024
  2. Red2010 is now

    Red2010 is now Active Member Member

    Joined:
    Apr 24, 2023
    Messages:
    31
    Location:
    Somewhere in Spain
  3. B.T.H Yeehaw!

    B.T.H Yeehaw! Newcomer Member

    Joined:
    Jun 20, 2020
    Messages:
    15
    Location:
    City Streets Zone
    I gotta say, even though I haven't implemented this into any of my hacks, this looks like it's going to be very cool!
     
  4. Red2010 is now

    Red2010 is now Active Member Member

    Joined:
    Apr 24, 2023
    Messages:
    31
    Location:
    Somewhere in Spain
    Good. I detected several problems when following this guide, I contacted the creator and there is nothing but...

    When you finish following this guide, the credits will cause your game to crash in marble zone