Play different songs on different acts
From Sonic Retro
(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.
Contents
- 1 Sonic 1
- 1.1 Re-organize the playlists
- 1.2 Change the playlists in the ASM to reflect the new organization
- 1.3 Change the code that picks the song at the beginning of the act
- 1.4 Change the code that picks the new song when invincibility wears off
- 1.5 Change the code which picks the song after the countdown
- 1.6 Fix the playlist entries for Scrap Brain 3 and Final Zone
- 1.7 Find 12 more songs
- 2 Sonic 2
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.
|Play different songs on different acts]]