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.
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!
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