Different Music Per Act In Sonic 2 (With 2 Player VS)

Discussion in 'Tutorials' started by RobiWanKenobi, Aug 26, 2023.

  1. RobiWanKenobi

    RobiWanKenobi Python Developer and ASM enthusiast Member

    Joined:
    Sep 10, 2022
    Messages:
    84
    Location:
    United States
    While other people have made guides on how to add different music per act in Sonic 2, I have not seen a guide do it the way I do it here.

    Replace the Old Level_GetBgm code with this:

    Code:
    Level_GetBgm:
        moveq    #0,d0
        move.w   (Current_ZoneAndAct).w,d0
           ror.b    #1,d0
           lsr.w    #7,d0
        lea_    MusicList,a1        ;Go To The Playlist
        tst.w    (Two_player_mode).w    ;Test if we are in 2 Player VS Mode
        beq.s    Level_PlayBgm        ;If not, branch
        lea_    MusicList2P,a1        ;Go To The 2 Player Playlist
    
    
    What it does is instead of checking the current zone, it checks the Current Act and The Current Zone, and it removes some old sonic 1 leftovers.

    However, the playlists are not set up to use this, so we need to make new playlists:

    In General, every 2 lines is a new zone, and every line is an act.

    (Make Sure To Replace The Labels Too!)

    Firstly, The zoneOrderedTable has to have 1,2 and not 1,1, otherwise it won't be able to handle all of the entries

    For the 1 Player Music Playlists, replace all of it with:

    Code:
    ;----------------------------------------------------------------------------
    ; 1P Music Playlist
    ;----------------------------------------------------------------------------
    ; byte_3EA0:
    MusicList: zoneOrderedTable 1,2
        zoneTableEntry.b MusID_EHZ    ; 0 ; EHZ Act 1
        zoneTableEntry.b MusID_EHZ    ; 0 ; EHZ Act 2
        zoneTableEntry.b MusID_EHZ    ; 1 ; Unused Zone 1 Act 1
        zoneTableEntry.b MusID_EHZ    ; 1 ; Unused Zone 1 Act 2
        zoneTableEntry.b MusID_MTZ    ; 2 ; WZ Act 1
        zoneTableEntry.b MusID_MTZ    ; 2 ; WZ Act 2
        zoneTableEntry.b MusID_OOZ    ; 3 ; Unused Zone 2 Act 1
        zoneTableEntry.b MusID_OOZ    ; 3 ; Unused Zone 2 Act 2
        zoneTableEntry.b MusID_MTZ    ; 4 ; MTZ Act 1
        zoneTableEntry.b MusID_MTZ    ; 4 ; MTZ Act 2
        zoneTableEntry.b MusID_MTZ    ; 5 ; MTZ Act 3
        zoneTableEntry.b MusID_MTZ    ; 5 ; MTZ Act 4 (unused)
        zoneTableEntry.b MusID_WFZ    ; 6 ; WFZ Act 1
        zoneTableEntry.b MusID_WFZ    ; 6 ; WFZ Act 2
        zoneTableEntry.b MusID_HTZ    ; 7 ; HTZ Act 1
        zoneTableEntry.b MusID_HTZ    ; 7 ; HTZ Act 2
        zoneTableEntry.b MusID_HPZ    ; 8 ; HPZ Act 1
        zoneTableEntry.b MusID_HPZ    ; 8 ; HPZ Act 2
        zoneTableEntry.b MusID_SCZ    ; 9  ; Unused Zone 9 Act 1
        zoneTableEntry.b MusID_SCZ    ; 9  ; Unused Zone 9 Act 2
        zoneTableEntry.b MusID_OOZ    ; 10 ; OOZ Act 1
        zoneTableEntry.b MusID_OOZ    ; 10 ; OOZ Act 2
        zoneTableEntry.b MusID_MCZ    ; 11 ; MCZ Act 1
        zoneTableEntry.b MusID_MCZ    ; 11 ; MCZ Act 2
        zoneTableEntry.b MusID_CNZ    ; 12 ; CNZ Act 1
        zoneTableEntry.b MusID_CNZ    ; 12 ; CNZ Act 2
        zoneTableEntry.b MusID_CPZ    ; 13 ; CPZ Act 1
        zoneTableEntry.b MusID_CPZ    ; 13 ; CPZ Act 2
        zoneTableEntry.b MusID_DEZ    ; 14 ; DEZ Act 1
        zoneTableEntry.b MusID_DEZ    ; 14 ; DEZ Act 2
        zoneTableEntry.b MusID_ARZ    ; 15 ; ARZ Act 1
        zoneTableEntry.b MusID_ARZ    ; 15 ; ARZ Act 2
        zoneTableEntry.b MusID_SCZ    ; 16 ; SCZ Act 1
        zoneTableEntry.b MusID_SCZ    ; 16 ; SCZ Act 2
        zoneTableEnd
        even
    For MusicList2, replace all of it with:
    Code:
    ;----------------------------------------------------------------------------
    ; 2P Music Playlist
    ;----------------------------------------------------------------------------
    ; byte_3EA0:
    MusicList2P: zoneOrderedTable 1,2
        zoneTableEntry.b MusID_EHZ_2P    ; 0 ; EHZ Act 1
        zoneTableEntry.b MusID_EHZ_2P    ; 0 ; EHZ Act 2
        zoneTableEntry.b MusID_EHZ    ; 1 ; Unused Zone 1 Act 1
        zoneTableEntry.b MusID_EHZ    ; 1 ; Unused Zone 1 Act 2
        zoneTableEntry.b MusID_MTZ    ; 2 ; WZ Act 1
        zoneTableEntry.b MusID_MTZ    ; 2 ; WZ Act 2
        zoneTableEntry.b MusID_OOZ    ; 3 ; Unused Zone 2 Act 1
        zoneTableEntry.b MusID_OOZ    ; 3 ; Unused Zone 2 Act 2
        zoneTableEntry.b MusID_MTZ    ; 4 ; MTZ Act 1
        zoneTableEntry.b MusID_MTZ    ; 4 ; MTZ Act 2
        zoneTableEntry.b MusID_MTZ    ; 5 ; MTZ Act 3
        zoneTableEntry.b MusID_MTZ    ; 5 ; MTZ Act 4 (unused)
        zoneTableEntry.b MusID_WFZ    ; 6 ; WFZ Act 1
        zoneTableEntry.b MusID_WFZ    ; 6 ; WFZ Act 2
        zoneTableEntry.b MusID_HTZ    ; 7 ; HTZ Act 1
        zoneTableEntry.b MusID_HTZ    ; 7 ; HTZ Act 2
        zoneTableEntry.b MusID_HPZ    ; 8 ; HPZ Act 1
        zoneTableEntry.b MusID_HPZ    ; 8 ; HPZ Act 2
        zoneTableEntry.b MusID_SCZ    ; 9  ; Unused Zone 9 Act 1
        zoneTableEntry.b MusID_SCZ    ; 9  ; Unused Zone 9 Act 2
        zoneTableEntry.b MusID_OOZ    ; 10 ; OOZ Act 1
        zoneTableEntry.b MusID_OOZ    ; 10 ; OOZ Act 2
        zoneTableEntry.b MusID_MCZ_2P    ; 11 ; MCZ Act 1
        zoneTableEntry.b MusID_MCZ_2P    ; 11 ; MCZ Act 2
        zoneTableEntry.b MusID_CNZ_2P    ; 12 ; CNZ Act 1
        zoneTableEntry.b MusID_CNZ_2P    ; 12 ; CNZ Act 2
        zoneTableEntry.b MusID_CPZ    ; 13 ; CPZ Act 1
        zoneTableEntry.b MusID_CPZ    ; 13 ; CPZ Act 2
        zoneTableEntry.b MusID_DEZ    ; 14 ; DEZ Act 1
        zoneTableEntry.b MusID_DEZ    ; 14 ; DEZ Act 2
        zoneTableEntry.b MusID_ARZ    ; 15 ; ARZ Act 1
        zoneTableEntry.b MusID_ARZ    ; 15 ; ARZ Act 2
        zoneTableEntry.b MusID_SCZ    ; 16 ; SCZ Act 1
        zoneTableEntry.b MusID_SCZ    ; 16 ; SCZ Act 2
        zoneTableEnd
        even
    Now, all that is left to do is add new music and music pointers!

    Thanks to Devon for pointing out some issues!
     
    Last edited: Aug 27, 2023
  2. Devon

    Devon I'm a loser, baby, so why don't you kill me? Member

    Joined:
    Aug 26, 2013
    Messages:
    1,376
    Location:
    your mom
    This guide has some problems. First off, there's this minor thing:
    Code:
    zoneOrderedTable 2,2
    It should be "1,2", because the first parameter defines the number of bytes per entry, and the second parameter defines the number of entries per zone, so you're actually quadrupling (2*2) the size of the table instead of merely doubling (1*2).

    The second one problem actually pretty much makes this not properly work at all:
    Code:
       move.w    (Current_ZoneAndAct).w,d0    ;Get Current Zone and Current Act
    You forgot to convert that into a linear index value for the table. The reason why you need to do that is because the value read into D0 is ZZAA, high byte containing the zone ID, and the lower byte containing the act ID. So, if you were in zone 01, act 00, then d0 would contain 0100, which would then be added onto the table address to retrieve the music ID, so it'd be like MusicList+$100, which is completely wrong (and zone 01 act 01 would get you 0101, etc.).

    This is the line of code that actually performs the read:
    Code:
        move.b    (a1,d0.w),d0        ; load from music playlist
    It reads a byte from (a1+d0), again, the reason why you need to convert the zone and act ID value into a linear index that can be used for the table.

    The idea is to shift the act ID value towards the zone ID, and then shift the whole thing down to fit the table. Sonic 2 does this for the water table, for instance:
    Code:
        ror.b    #1,d0
        lsr.w    #6,d0
    It performs a rotation of 1 bit to the right for just the act ID, so if the act ID is 1, then it'll rotate all the way to the top of the byte, putting it right next to the zone ID.

    Zone 00 Act 01: 0000000000000001 -> 0000000010000000
    Zone 01 Act 01: 0000000100000001 -> 0000000110000000

    Then it shifts the entire thing down by 6 bits, so zone 00 act 01 would get you 0002, zone 01 act 00 would get you 0004, etc.

    Zone 00 Act 01: 0000000010000000 -> 0000000000000010
    Zone 01 Act 00: 0000000100000000 -> 0000000000000100
    Zone 01 Act 01: 0000000110000000 -> 0000000000000110

    Of course, each entry in the song ID table is just 1 byte, and the water table has 2 bytes per entry (hence why it uses multiples of 2), so in this case, you'd wanna shift right 7 times instead of 6:
    Code:
        move.w    (Current_ZoneAndAct).w,d0
        ror.b    #1,d0
        lsr.w    #7,d0
    Be sure that you're testing your stuff, especially in other stages outside of Emerald Hill!
     
    ProjectFM and Trance like this.
  3. RobiWanKenobi

    RobiWanKenobi Python Developer and ASM enthusiast Member

    Joined:
    Sep 10, 2022
    Messages:
    84
    Location:
    United States
    Thanks! Fixes have been uploaded in.