Actions

SCHG How-to

Play different songs on different acts

From Sonic Retro

Revision as of 23:19, 23 February 2023 by JGMR (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

(Original guide by nineko)

(S2 addition by Shadow05)

Everyone's hack was using different songs in different acts (think Sonic Megamix and Sonic 1 Remastered, just to name two), and I wanted to add this feature to my soniNeko as well, so I searched the forums and the wiki for a guide or something. With much surprise, I found nothing. So I tried to do it by myself, and I'm happy to say that I succeeded! Yep guys, my first ASM edit all by myself! To be honest, I had to ask Puto what bhi.s does (since I didn't know if it was involved in the music process), but that's pretty much it, ASM isn't as hard as it seems!

So here is the result of my work, to use with the ASM68K version of Hivebrain's split disassembly.

Sonic 1

Re-organize the playlists

In the disassembly, misc\muslist1.bin is used as the "normal playlist", while misc\muslist2.bin is used when invincibility wears off. This is redundant, not to mention gay, since those playlist are identical, but muslist1.bin has an extra byte for Final Zone + a 00 to make it even. Try to put an invincibility monitor in Final Zone, and when it's done you'll get Scrap Brain music. We don't want that. Delete muslist1.bin, and make FOUR copies of muslist2.bin, named muslist1.bin to muslist4.bin . Each of them should be 6 bytes long: 81 82 83 84 85 86. Save them in this way for now, we're going to edit them later. Now the playlists have a different meaning: muslist1.bin contains the song played on the act 1 of each zone, muslist2.bin contains acts 2, etc. Muslist4.bin isn't really needed, but it will be handy. Keep on reading to find why.

Change the playlists in the ASM to reflect the new organization

Go here:

MusicList:	incbin	misc\muslist1.bin
		even

And change it to:

MusicList1:	incbin	misc\muslist1.bin
		even
MusicList2:	incbin	misc\muslist2.bin
		even
MusicList3:	incbin	misc\muslist3.bin
		even
MusicList4:	incbin	misc\muslist4.bin
		even

Then go here:

MusicList2:	incbin	misc\muslist2.bin
		even

And delete it. Of course, I'm not talking about the one I just told you to add, there is one much below (look for "Music to play after invincibility wears off").

Change the code that picks the song at the beginning of the act

We're now going to use the act byte ($FFFFFE11) to load the correct playlist. Then we'll pick the entry from the playlist according to the zone byte ($FFFFFE10). Go to Level_GetBgm. It should look like:

Level_GetBgm:
		tst.w	($FFFFFFF0).w
		bmi.s	loc_3946
		moveq	#0,d0
		move.b	($FFFFFE10).w,d0
		cmpi.w	#$103,($FFFFFE10).w ; is level SBZ3?
		bne.s	Level_BgmNotLZ4	; if not, branch
		moveq	#5,d0		; move 5 to d0
 
Level_BgmNotLZ4:
		cmpi.w	#$502,($FFFFFE10).w ; is level FZ?
		bne.s	Level_PlayBgm	; if not, branch
		moveq	#6,d0		; move 6 to d0
 
Level_PlayBgm:
		lea	(MusicList).l,a1 ; load	music playlist
		move.b	(a1,d0.w),d0	; add d0 to a1
		bsr.w	PlaySound	; play music
		move.b	#$34,($FFFFD080).w ; load title	card object

Replace it with:

; NineKode begins here - How to play different songs on different acts
 
Level_GetBgm:
		tst.w	($FFFFFFF0).w
		bmi.w	loc_3946	; change from bmi.s to bmi.w or you'll get an error
		moveq	#0,d0
		move.b	($FFFFFE10).w,d0
 
		cmpi.b	#$0,($FFFFFE11).w	; is this act 1?
		bne.s	Level_GetBgm2	; if not, branch
		lea	(MusicList1).l,a1	; load Music Playlist for Acts 1
		bra.s	Level_PlayBgm	; go to PlayBgm
 
Level_GetBgm2:
		cmpi.b	#$1,($FFFFFE11).w	; is this act 2?
		bne.s	Level_GetBgm3	; if not, branch
		lea	(MusicList2).l,a1	; load Music Playlist for Acts 2
		bra.s	Level_PlayBgm	; go to PlayBgm
 
Level_GetBgm3:
		cmpi.b	#$2,($FFFFFE11).w	; is this act 3?
		bne.s	Level_GetBgm4	; if not, branch
		lea	(MusicList3).l,a1	; load Music Playlist for Acts 3
		bra.s	Level_PlayBgm	; go to PlayBgm
 
Level_GetBgm4:
		cmpi.b	#$3,($FFFFFE11).w	; is this act 4?
		bne.s	Level_PlayBgm	; if not, branch
		lea	(MusicList4).l,a1	; load Music Playlist for Acts 4
 
Level_PlayBgm:
		move.b	(a1,d0.w),d0	; get d0-th entry from the playlist
		bsr.w	PlaySound	; play music
		move.b	#$34,($FFFFD080).w ; load title	card object
 
; NineKode ends here


Change the code that picks the new song when invincibility wears off

Remember, the check after the invincibility wears off is done in another section of the code. If you don't fix it, you'll get the wrong song. We just need to copy and paste the code used above, of course with different labels. So, go here:

Obj01_ChkInvin:
		tst.b	($FFFFFE2D).w	; does Sonic have invincibility?
		beq.s	Obj01_ChkShoes	; if not, branch
		tst.w	$32(a0)		; check	time remaining for invinciblity
		beq.s	Obj01_ChkShoes	; if no	time remains, branch
		subq.w	#1,$32(a0)	; subtract 1 from time
		bne.s	Obj01_ChkShoes
		tst.b	($FFFFF7AA).w
		bne.s	Obj01_RmvInvin
		cmpi.w	#$C,($FFFFFE14).w
		bcs.s	Obj01_RmvInvin
		moveq	#0,d0
		move.b	($FFFFFE10).w,d0
		cmpi.w	#$103,($FFFFFE10).w ; check if level is	SBZ3
		bne.s	Obj01_PlayMusic
		moveq	#5,d0		; play SBZ music
 
Obj01_PlayMusic:
		lea	(MusicList2).l,a1
		move.b	(a1,d0.w),d0
		jsr	(PlaySound).l	; play normal music


And replace it with:

; Second part of the NineKode. Play different music on different acts - after invincibility wears off
 
Obj01_ChkInvin:
		tst.b	($FFFFFE2D).w	; does Sonic have invincibility?
		beq.w	Obj01_ChkShoes	; if not, branch	; change to beq.w
		tst.w	$32(a0)		; check	time remaining for invinciblity
		beq.w	Obj01_ChkShoes	; if no	time remains, branch	; change to beq.w
		subq.w	#1,$32(a0)	; subtract 1 from time
		bne.w	Obj01_ChkShoes	; change to bne.w
		tst.b	($FFFFF7AA).w
		bne.w	Obj01_RmvInvin	; change to bne.w
		cmpi.w	#$C,($FFFFFE14).w
		bcs.w	Obj01_RmvInvin	; change to bcs.w
		moveq	#0,d0
		move.b	($FFFFFE10).w,d0
 
		cmpi.b	#$0,($FFFFFE11).w	; is this act 1?
		bne.s	Obj01_GetBgm2	; if not, branch
		lea	(MusicList1).l,a1	; load Music Playlist for Acts 1
		bra.s	Obj01_PlayMusic	; go to PlayMusic
 
Obj01_GetBgm2:
		cmpi.b	#$1,($FFFFFE11).w	; is this act 2?
		bne.s	Obj01_GetBgm3	; if not, branch
		lea	(MusicList2).l,a1	; load Music Playlist for Acts 2
		bra.s	Obj01_PlayMusic	; go to PlayMusic
 
Obj01_GetBgm3:
		cmpi.b	#$2,($FFFFFE11).w	; is this act 3?
		bne.s	Obj01_GetBgm4	; if not, branch
		lea	(MusicList3).l,a1	; load Music Playlist for Acts 3
		bra.s	Obj01_PlayMusic	; go to PlayMusic
 
Obj01_GetBgm4:
		cmpi.b	#$3,($FFFFFE11).w	; is this act 4?
		bne.s	Obj01_PlayMusic	; if not, branch
		lea	(MusicList4).l,a1	; load Music Playlist for Acts 4
 
Obj01_PlayMusic:
		move.b	(a1,d0.w),d0
		jsr	(PlaySound).l	; play normal music
 
; NineKode ends here.


And now you're going to get the correct music even after invincibility wears off. But there is one more instance we need to change or we're going to have problems in Labyrinth Zone after the countdown...

Change the code which picks the song after the countdown

Go here:

ResumeMusic:				; XREF: Obj64_Wobble; Sonic_Water; Obj0A_ReduceAir
		cmpi.w	#$C,($FFFFFE14).w
		bhi.s	loc_140AC
		move.w	#$82,d0		; play LZ music
		cmpi.w	#$103,($FFFFFE10).w ; check if level is	0103 (SBZ3)
		bne.s	loc_140A6
		move.w	#$86,d0		; play SBZ music
 
loc_140A6:
		jsr	(PlaySound).l

And replace it with:

ResumeMusic:				; XREF: Obj64_Wobble; Sonic_Water; Obj0A_ReduceAir
		cmpi.w	#$C,($FFFFFE14).w
 
; Third section of the NineKode - Play correct music after the countdown (if you breathe)
 
		bhi.w	loc_140AC	; change to bhi.w!
 
		cmpi.b	#$0,($FFFFFE11).w	; is this act 1?
		bne.s	Air_GetBgm2	; if not, branch
		lea	(MusicList1).l,a1	; load Music Playlist for Acts 1
		bra.s	Air_PlayMusic	; go to PlayMusic
 
Air_GetBgm2:
		cmpi.b	#$1,($FFFFFE11).w	; is this act 2?
		bne.s	Air_GetBgm3	; if not, branch
		lea	(MusicList2).l,a1	; load Music Playlist for Acts 2
		bra.s	Air_PlayMusic	; go to PlayMusic
 
Air_GetBgm3:
		cmpi.b	#$2,($FFFFFE11).w	; is this act 3?
		bne.s	Air_GetBgm4	; if not, branch
		lea	(MusicList3).l,a1	; load Music Playlist for Acts 3
		bra.s	Air_PlayMusic	; go to PlayMusic
 
Air_GetBgm4:
		cmpi.b	#$3,($FFFFFE11).w	; is this act 4?
		bne.s	Air_PlayMusic	; if not, branch
		lea	(MusicList4).l,a1	; load Music Playlist for Acts 4
 
Air_PlayMusic:
		move.b	1(a1),d0	; load entry $1 from the playlist
 
loc_140A6:
		jsr	(PlaySound).l
 
; NineKode ends here


As you see the code is always the same, recycled each and every time. Now if you try to build your ROM you'll see that it works flawlessly! Well, you're still going to get the same songs, because of how we created the playlists, but if you change a byte in a playlist you'll see that it works. There is only one more small fix to do to make it perfect btw...

Fix the playlist entries for Scrap Brain 3 and Final Zone

You know that Scrap Brain 3 is actually Labyrinth 4, and Final Zone is actually Scrap Brain 3. Way to confuse people. So, hex edit muslist4.bin and change the 82 to 86. Hex edit muslist3.bin and change the 86 to 8D. Now your ROM should sound exactly as before, except that you're given the chance to pick different songs on different acts! Playlist4.bin is also useful if you plan to add acts 4 to other zones, so keep it, it's not a great waste of space.

Find 12 more songs

Good luck on that. Now that I have the code working I can't find good songs D: To add more songs for the Act 2's and 3's, go here, and to add additional music, go here.

Sonic 2

For Sonic 2, the same rules apply in implementing different music in different acts. The main difference with the Sonic 2 implementation is that you don't have to worry about the invincibility music playlist and countdown music, as those are arranged differently in Sonic 2.

Change the playlists in the ASM to reflect the new organization

Go here:

;----------------------------------------------------------------------------
; 1P Music Playlist
;----------------------------------------------------------------------------
; byte_3EA0:
MusicList: zoneOrderedTable 1,1
	zoneTableEntry.b MusID_EHZ	; 0 ; EHZ
	zoneTableEntry.b MusID_EHZ	; 1
	zoneTableEntry.b MusID_MTZ	; 2
	zoneTableEntry.b MusID_OOZ	; 3
	zoneTableEntry.b MusID_MTZ	; 4 ; MTZ1,2
	zoneTableEntry.b MusID_MTZ	; 5 ; MTZ3
	zoneTableEntry.b MusID_WFZ	; 6 ; WFZ
	zoneTableEntry.b MusID_HTZ	; 7 ; HTZ
	zoneTableEntry.b MusID_HPZ	; 8
	zoneTableEntry.b MusID_SCZ	; 9
	zoneTableEntry.b MusID_OOZ	; 10 ; OOZ
	zoneTableEntry.b MusID_MCZ	; 11 ; MCZ
	zoneTableEntry.b MusID_CNZ	; 12 ; CNZ
	zoneTableEntry.b MusID_CPZ	; 13 ; CPZ
	zoneTableEntry.b MusID_DEZ	; 14 ; DEZ
	zoneTableEntry.b MusID_ARZ	; 15 ; ARZ
	zoneTableEntry.b MusID_SCZ	; 16 ; SCZ
    zoneTableEnd
	even
;----------------------------------------------------------------------------
; 2P Music Playlist
;----------------------------------------------------------------------------
; byte_3EB2:
MusicList2: zoneOrderedTable 1,1
	zoneTableEntry.b MusID_EHZ_2P	; 0  ; EHZ 2P
	zoneTableEntry.b MusID_EHZ	; 1
	zoneTableEntry.b MusID_MTZ	; 2
	zoneTableEntry.b MusID_OOZ	; 3
	zoneTableEntry.b MusID_MTZ	; 4
	zoneTableEntry.b MusID_MTZ	; 5
	zoneTableEntry.b MusID_WFZ	; 6
	zoneTableEntry.b MusID_HTZ	; 7
	zoneTableEntry.b MusID_HPZ	; 8
	zoneTableEntry.b MusID_SCZ	; 9
	zoneTableEntry.b MusID_OOZ	; 10
	zoneTableEntry.b MusID_MCZ_2P	; 11 ; MCZ 2P
	zoneTableEntry.b MusID_CNZ_2P	; 12 ; CNZ 2P
	zoneTableEntry.b MusID_CPZ	; 13
	zoneTableEntry.b MusID_DEZ	; 14
	zoneTableEntry.b MusID_ARZ	; 15
	zoneTableEntry.b MusID_SCZ	; 16
    zoneTableEnd
	even

And change it to:

;----------------------------------------------------------------------------
; 1P Music Playlists
;----------------------------------------------------------------------------
; byte_3EA0:
;Act 1
MusicList1: zoneOrderedTable 1,1
	zoneTableEntry.b MusID_EHZ	; 0 ; EHZ
	zoneTableEntry.b MusID_EHZ	; 1
	zoneTableEntry.b MusID_MTZ	; 2
	zoneTableEntry.b MusID_OOZ	; 3
	zoneTableEntry.b MusID_MTZ	; 4 ; MTZ1,2
	zoneTableEntry.b MusID_MTZ	; 5 ; MTZ3
	zoneTableEntry.b MusID_WFZ	; 6 ; WFZ
	zoneTableEntry.b MusID_HTZ	; 7 ; HTZ
	zoneTableEntry.b MusID_HPZ	; 8
	zoneTableEntry.b MusID_SCZ	; 9
	zoneTableEntry.b MusID_OOZ	; 10 ; OOZ
	zoneTableEntry.b MusID_MCZ	; 11 ; MCZ
	zoneTableEntry.b MusID_CNZ	; 12 ; CNZ
	zoneTableEntry.b MusID_CPZ	; 13 ; CPZ
	zoneTableEntry.b MusID_DEZ	; 14 ; DEZ
	zoneTableEntry.b MusID_ARZ	; 15 ; ARZ
	zoneTableEntry.b MusID_SCZ	; 16 ; SCZ
    zoneTableEnd
	even
;Act 2
MusicList2: zoneOrderedTable 1,1
	zoneTableEntry.b MusID_EHZ	; 0 ; EHZ
	zoneTableEntry.b MusID_EHZ	; 1
	zoneTableEntry.b MusID_MTZ	; 2
	zoneTableEntry.b MusID_OOZ	; 3
	zoneTableEntry.b MusID_MTZ	; 4 ; MTZ1,2
	zoneTableEntry.b MusID_MTZ	; 5 ; MTZ3
	zoneTableEntry.b MusID_WFZ	; 6 ; WFZ
	zoneTableEntry.b MusID_HTZ	; 7 ; HTZ
	zoneTableEntry.b MusID_HPZ	; 8
	zoneTableEntry.b MusID_SCZ	; 9
	zoneTableEntry.b MusID_OOZ	; 10 ; OOZ
	zoneTableEntry.b MusID_MCZ	; 11 ; MCZ
	zoneTableEntry.b MusID_CNZ	; 12 ; CNZ
	zoneTableEntry.b MusID_CPZ	; 13 ; CPZ
	zoneTableEntry.b MusID_DEZ	; 14 ; DEZ
	zoneTableEntry.b MusID_ARZ	; 15 ; ARZ
	zoneTableEntry.b MusID_SCZ	; 16 ; SCZ
    zoneTableEnd
	even
;----------------------------------------------------------------------------
; 2P Music Playlist
;----------------------------------------------------------------------------
; byte_3EB2:
MusicList2P: zoneOrderedTable 1,1
	zoneTableEntry.b MusID_EHZ_2P	; 0  ; EHZ 2P
	zoneTableEntry.b MusID_EHZ	; 1
	zoneTableEntry.b MusID_MTZ	; 2
	zoneTableEntry.b MusID_OOZ	; 3
	zoneTableEntry.b MusID_MTZ	; 4
	zoneTableEntry.b MusID_MTZ	; 5
	zoneTableEntry.b MusID_WFZ	; 6
	zoneTableEntry.b MusID_HTZ	; 7
	zoneTableEntry.b MusID_HPZ	; 8
	zoneTableEntry.b MusID_SCZ	; 9
	zoneTableEntry.b MusID_OOZ	; 10
	zoneTableEntry.b MusID_MCZ_2P	; 11 ; MCZ 2P
	zoneTableEntry.b MusID_CNZ_2P	; 12 ; CNZ 2P
	zoneTableEntry.b MusID_CPZ	; 13
	zoneTableEntry.b MusID_DEZ	; 14
	zoneTableEntry.b MusID_ARZ	; 15
	zoneTableEntry.b MusID_SCZ	; 16
    zoneTableEnd
	even

Change the code that picks the song at the beginning of the act

We're now going to use the act byte (Current_Act) to load the correct playlist. Then we'll pick the entry from the playlist according to the zone byte (Current_Zone). Since Sonic 2 uses only two acts instead of three (excluding MTZ since MTZ3 uses a different level zone and act), the code is much more simplified. Go to Level_GetBgm. It should look like:

Level_GetBgm:
	tst.w	(Demo_mode_flag).w
	bmi.s	+
	moveq	#0,d0
	move.b	(Current_Zone).w,d0
	lea_	MusicList,a1
	tst.w	(Two_player_mode).w
	beq.s	Level_PlayBgm
	lea_	MusicList2,a1
; loc_40C8:
Level_PlayBgm:
	move.b	(a1,d0.w),d0		; load from music playlist
	move.w	d0,(Level_Music).w	; store level music
	bsr.w	PlayMusic		; play level music
	move.b	#ObjID_TitleCard,(TitleCard+id).w ; load Obj34 (level title card) at $FFFFB080

Replace it with:

Level_GetBgm:
	tst.w	(Demo_mode_flag).w
	bmi.w	+
	moveq	#0,d0
	move.b	(Current_Zone).w,d0
	cmpi.b	#$0,(Current_Act).w	; is this act 1?
	bne.s	Level_GetBgm2	; if not, branch
	lea	(MusicList1).l,a1	; load Music Playlist for Acts 1
	tst.w	(Two_player_mode).w
	beq.s	Level_PlayBgm
	lea_	MusicList2P,a1
	bra.s	Level_PlayBgm	; go to PlayBgm
 
Level_GetBgm2:
	cmpi.b	#$1,(Current_Act).w	; is this act 2?
	bne.s	+	; if not, branch
	lea	(MusicList2).l,a1	; load Music Playlist for Acts 2
	bra.s	Level_PlayBgm

; loc_40C8:
Level_PlayBgm:
	move.b	(a1,d0.w),d0		; load from music playlist
	move.w	d0,(Level_Music).w	; store level music
	bsr.w	PlayMusic		; play level music
	move.b	#ObjID_TitleCard,(TitleCard+id).w ; load Obj34 (level title card) at $FFFFB080
	jmp	Level_TtlCard
+
	rts

Once that's done, compile the ROM and you're all set to go!

Find more songs

Good luck on that. To add more songs, go here.

SCHG How-To Guide: Sonic the Hedgehog (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix the SEGA Sound | Display the Press Start Button Text | Fix the Level Select Menu | Fix the Hidden Points Bug | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix the Walk-Jump Bug | Correct Drowning Bugs | Fix the Death Boundary Bug | Fix the Camera Follow Bug | Fix Song Restoration Bugs | Fix the HUD Blinking | Fix the Level Select Graphics Bug | Fix a remember sprite related bug
Changing Design Choices
Change Spike Behavior | Collide with Water After Being Hurt | Fix Special Stage Jumping Physics | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Remove the Speed Cap | Port the REV01 Background Effects | Port Sonic 2's Level Art Loader | Retain Rings Between Acts | Add Sonic 2 (Simon Wai Prototype) Level Select | Improve ObjectMove Subroutines | Port Sonic 2 Level Select
Adding Features
Add Spin Dash ( Part 1 (GitHub)/(Hivebrain) / Part 2 / Part 3 / Part 4 ) | Add Eggman Monitor | Add Super Sonic | Add the Air Roll
Sound Features
Expand the Sound Index | Play Different Songs Per Act | Port Sonic 2 Final Sound Driver | Port Sonic 3's Sound Driver | Port Flamewing's Sonic 3 & Knuckles Sound Driver | Change The SEGA Sound
Extending the Game
Load Chunks From ROM | Add Extra Characters | Make an Alternative Title Screen | Use Dynamic Tilesets | Make GHZ Load Alternate Art | Make Ending Load Alternate Art | Add a New Zone | Set Up the Goggle Monitor | Add New Moves | Add a Dynamic Collision System | Dynamic Special Stage Walls System | Extend Sprite Mappings and Art Limit | Enigma Credits | Use Dynamic Palettes
Miscellaneous
Convert the Hivebrain 2005 Disassembly to ASM68K
Split Disassembly Guides
Set Up a Split Disassembly | Basic Level Editing | Basic Art Editing | Basic ASM Editing (Spin Dash)
SCHG How-To Guide: Sonic the Hedgehog 2 (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix Super Sonic Bugs | Use Correct Height When Roll Jumping | Fix Jump Height Bug When Exiting Water | Fix Screen Boundary Spin Dash Bug | Correct Drowning Bugs | Fix Camera Y Position for Tails | Fix Tails Subanimation Error | Fix Tails' Respawn Speeds | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix Rexon Crash | Fix Monitor Collision Bug | Fix EHZ Deformation Bug | Correct CPZ Boss Attack Behavior | Fix Bug in ARZ Boss Arrow's Platform Behavior | Fix ARZ Boss Walking on Air Glitch | Fix ARZ Boss Sprite Behavior | Fix Multiple CNZ Boss Bugs | Fix HTZ Background Scrolling Mountains | Fix OOZ Launcher Speed Up Glitch | Fix DEZ Giant Mech Collision Glitch | Fix Boss Deconstruction Behavior | Fix Speed Bugs | Fix 14 Continues Cheat | Fix Debug Mode Crash | Fix 99+ Lives | Fix Sonic 2's Sega Screen
Design Choices
Remove the Air Speed Cap | Disable Floor Collision While Dying | Modify Super Sonic Transformation Methods & Behavior | Enable/Disable Tails in Certain Levels | Collide with Water After Being Hurt | Retain Rings When Returning at a Star Post | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Insert LZ Water Ripple Effect | Restore Lost CPZ Boss Feature | Prevent SCZ Tornado Spin Dash Death | Improve ObjectMove Subroutines | Port S3K Rings Manager | Port S3K Object Manager | Port S3K Priority Manager | Edit Level Order with ASM‎ | Alter Ring Requirements in Special Stages | Make Special Stage Characters Use Normal DPLCs | Speed Up Ring Loss Process | Change spike behaviour in Sonic 2
Adding Features
Create Insta-kill and High Jump Monitors | Create Clone and Special Stage Monitors | Port Knuckles
Sound Features
Expand Music Index to Start at $00 | Port Sonic 1 Sound Driver | Port Sonic 2 Clone Driver | Port Sonic 3 Sound Driver | Port Flamewing's Sonic 3 & Knuckles Sound Driver | Expand the Music Index to Start at $00 (Sonic 2 Clone Driver Version) | Play Different Songs Per Act
Extending the Game
Extend the Level Index Past $10 | Extend the Level Select | Extend Water Tables | Add Extra Characters | Free Up 2 Universal SSTs

|Play different songs on different acts]]