Actions

SCHG How-to

Difference between revisions of "Port the Sonic 2 Clone Sound Driver to the HG version of Sonic 2"

From Sonic Retro

(Step 2 - Deleting leftovers)
(Step 3 - Replace a bunch of stuff.)
Line 57: Line 57:
 
We've effectively deleted the old sound driver entirely from our game... Now it's time we implemented a new one.. But first, we need to prepare S2.Constants.asm
 
We've effectively deleted the old sound driver entirely from our game... Now it's time we implemented a new one.. But first, we need to prepare S2.Constants.asm
  
==Step 3 - Replace a bunch of stuff.==
+
==Step 3 - Overhauling Constants, fixing RAM==
Search for the routine VintRet (Search for "VintRet:"), and you'll have something like this:
+
Open s2.constants.asm, and find the following line:
  
<asm>VintRet:
+
Find the line "<b>; Music IDs</b>". You'll see this:
    addq.l    #1,(Vint_runcount).w
 
    movem.l    (sp)+,d0-a6
 
    rte</asm>
 
  
Replace it with this:
+
<asm>; Music IDs
 +
offset :=    zMasterPlaylist
 +
ptrsize :=    1
 +
idstart :=    $81
 +
; $80 is reserved for silence, so if you make idstart $80 or less,
 +
; you may need to insert a dummy zMusIDPtr in the $80 slot</asm>
  
<asm>VintRet:
+
delete everything from there down to "<b>MusID__End = id(zMusIDPtr__End) ; A0</b>", and paste the following where it used to be:
    jsr    Init_Sonic1_Sound_Driver    ; init Sonic 1 sound driver
 
    addq.l    #1,(Vint_runcount).w
 
    movem.l    (sp)+,d0-a6
 
    rte</asm>
 
  
Next, go to JmpTo_SoundDriverLoad, and find all of this:
+
<asm>; Music IDs
 +
idstart :=    $81
 +
; $80 is reserved for silence, so if you make idstart $80 or less,
 +
; you may need to insert a dummy zMusIDPtr in the $80 slot
 +
 +
MusID__First =          idstart
 +
MusID_2PResult =      $81
 +
MusID_EHZ =              $82
 +
MusID_MCZ_2P =          $83
 +
MusID_OOZ =              $84
 +
MusID_MTZ =              $85
 +
MusID_HTZ =              $86
 +
MusID_ARZ =              $87
 +
MusID_CNZ_2P =          $88
 +
MusID_CNZ =              $89
 +
MusID_DEZ =              $8A
 +
MusID_MCZ =              $8B
 +
MusID_EHZ_2P =          $8C
 +
MusID_SCZ =              $8D
 +
MusID_CPZ =              $8E
 +
MusID_WFZ =              $8F
 +
MusID_HPZ =              $90
 +
MusID_Options =          $91
 +
MusID_SpecStage =      $92
 +
MusID_Boss =            $93
 +
MusID_EndBoss =          $94
 +
MusID_Ending =          $95
 +
MusID_SuperSonic =    $96
 +
MusID_Invincible =    $97
 +
MusID_ExtraLife =      $98
 +
MusID_Title =            $99
 +
MusID_EndLevel =      $9A
 +
MusID_GameOver =      $9B
 +
MusID_Continue =      $9C
 +
MusID_Emerald =          $9D
 +
MusID_Credits =          $9E
 +
MusID_Countdown =      $9F
 +
MusID__End  =      $A0</asm>
  
<asm>JmpTo_SoundDriverLoad
+
The music is all fixed, now all that's left is the sound effects:
  
    nop
+
Find the line "<b>; Sound IDs</b>", and delete everything down to the line "<b>; Special sound IDs</b>". Leave the special IDs alone.
  
    jmp    (SoundDriverLoad).l
+
In place of the text you deleted, just paste this:
; End of function JmpTo_SoundDriverLoad
 
  
; ===========================================================================
+
<asm>; Sound IDs
 +
idstart :=   $A0
 +
 +
SndID__First = idstart
 +
SndID_Jump =                   $A0                ; A0
 +
SndID_Checkpoint =            $A1              ; A1
 +
SndID_SpikeSwitch =            $A2              ; A2
 +
SndID_Hurt =                    $A3                ; A3
 +
SndID_Skidding =              $A4                ; A4
 +
SndID_BlockPush =              $A5              ; A5
 +
SndID_HurtBySpikes =          $A6      ; A6
 +
SndID_Sparkle =                $A7
 +
SndID_Beep =                 $A8
 +
SndID_Bwoop =                 $A9
 +
SndID_Splash =               $AA
 +
SndID_Swish =                 $AB
 +
SndID_BossHit =               $AC
 +
SndID_InhalingBubble =       $AD
 +
SndID_ArrowFiring =           $AE
 +
SndID_LavaBall =             $AE
 +
SndID_Shield =               $Af
 +
SndID_LaserBeam =             $B0
 +
SndID_Zap =                   $B1
 +
SndID_Drown =                 $B2
 +
SndID_FireBurn =             $B3
 +
SndID_Bumper =               $B4
 +
SndID_Ring =                 $B5    ; B5
 +
SndID_RingRight =             $B5
 +
SndID_SpikesMove =           $B6
 +
SndID_Rumbling =             $B7
 +
SndID_Smash =                 $B9
 +
SndID_DoorSlam =             $BB
 +
SndID_SpindashRelease =       $BC    ; BC
 +
SndID_Hammer =               $BD
 +
SndID_Roll =                 $BE
 +
SndID_ContinueJingle =       $BF
 +
SndID_CasinoBonus =           $C0
 +
SndID_Explosion =             $C1
 +
SndID_WaterWarning =         $C2
 +
SndID_EnterGiantRing =       $C3
 +
SndID_BossExplosion =         $C4
 +
SndID_TallyEnd =             $C5
 +
SndID_RingSpill =             $C6
 +
SndID_Flamethrower =         $C8
 +
SndID_Bonus =                 $C9
 +
SndID_SpecStageEntry =       $CA
 +
SndID_SlowSmash =             $CB
 +
SndID_Spring =               $CC
 +
SndID_Blip =                 $CD
 +
SndID_RingLeft =             $B5
 +
SndID_Signpost =             $CF
 +
SndID_CNZBossZap =           $D0
 +
SndID_Signpost2P =           $D3
 +
SndID_OOZLidPop =               $D4
 +
SndID_SlidingSpike =         $D5
 +
SndID_CNZElevator =           $D6
 +
SndID_PlatformKnock =         $D7
 +
SndID_BonusBumper =           $D8
 +
SndID_LargeBumper =           $D9
 +
SndID_Gloop =                 $DA
 +
SndID_PreArrowFiring =       $DB
 +
SndID_Fire =                 $DC
 +
SndID_ArrowStick =           $DD
 +
SndID_Helicopter =           $DE
 +
SndID_SuperTransform =       $DF
 +
SndID_SpindashRev =           $E0
 +
SndID_Rumbling2 =             $E1
 +
SndID_CNZLaunch =             $E2
 +
SndID_Flipper =               $E3
 +
SndID_HTZLiftClick =         $E4
 +
SndID_Leaves =               $E5
 +
SndID_MegaMackDrop =         $E6
 +
SndID_DrawbridgeMove =       $E7
 +
SndID_QuickDoorSlam =         $E8
 +
SndID_DrawbridgeDown =       $E9
 +
SndID_LaserBurst =           $EA
 +
SndID_Scatter =               $EB
 +
SndID_LaserFloor =           $EB
 +
SndID_Teleport =             $EC
 +
SndID_Error =                 $ED
 +
SndID_MechaSonicBuzz =       $EE
 +
SndID_LargeLaser =           $EF
 +
SndID_OilSlide =             $F0
 +
SndID__End    =           $F7</asm>
  
; unused mostly-leftover subroutine to load the sound driver
+
The following are the lines you should NOT have deleted, just for reference:
  
; SoundDriverLoadS1:
+
<asm>MusID_StopSFX = $78+$80 ; F8
    move.w    #$100,(Z80_Bus_Request).l ; stop the Z80
+
MusID_FadeOut = $79+$80 ; F9
    move.w    #$100,(Z80_Reset).l; reset the Z80
+
SndID_SegaSound = $7A+$80 ; FA
    lea    (Z80_RAM).l,a1
+
MusID_SpeedUp = $7B+$80 ; FB
    move.b    #$F3,(a1)+
+
MusID_SlowDown = $7C+$80 ; FC
    move.b    #$F3,(a1)+
+
MusID_Stop = $7D+$80 ; FD
    move.b    #$C3,(a1)+
+
MusID_Pause = $7E+$80 ; FE
    move.b    #0,(a1)+
+
MusID_Unpause = $7F+$80 ; FF</asm>
    move.b    #0,(a1)+
 
    move.w    #0,(Z80_Reset).l
 
    nop
 
    nop
 
    nop
 
    nop
 
    move.w    #$100,(Z80_Reset).l ; reset the Z80
 
    move.w    #0,(Z80_Bus_Request).l ; start the Z80
 
    rts</asm>
 
  
and replace it like this:
+
Now, find these lines:
  
<asm>JmpTo_SoundDriverLoad
+
<asm>Underwater_palette_2: ds.w palette_line_size ; not sure what it's used for but it's only used when there's water
    move.w   #$100,(Z80_Bus_Request).l ; stop the Z80
+
Underwater_palette_2_line2: ds.w palette_line_size
    move.w    #$100,(Z80_Reset).l ; reset the Z80
+
Underwater_palette_2_line3: ds.w palette_line_size
    lea    (Kos_Z80).l,a0
+
Underwater_palette_2_line4: ds.w palette_line_size
    lea    (Z80_RAM).l,a1
 
    bsr.w    KosDec
 
    move.b    #$F3,(a1)+
 
    move.b    #$F3,(a1)+
 
    move.b    #$C3,(a1)+
 
    move.b    #0,(a1)+
 
    move.b    #0,(a1)+
 
    move.w   #0,(Z80_Reset).l
 
    nop
 
    nop
 
    nop
 
    nop
 
    move.w   #$100,(Z80_Reset).l ; reset the Z80
 
    move.w   #0,(Z80_Bus_Request).l ; start the Z80
 
    rts</asm>
 
  
Next, find PlayMusic, which should look like this this:
+
Underwater_palette: ds.w palette_line_size ; main palette for underwater parts of the screen
 +
Underwater_palette_line2: ds.w palette_line_size
 +
Underwater_palette_line3: ds.w palette_line_size
 +
Underwater_palette_line4: ds.w palette_line_size</asm>
  
<asm>; sub_135E:
+
Copy these lines to the clipboard (Or better yet, to a separate text document), we are going to be moving them in a moment.
PlayMusic:
 
    tst.b    (Music_to_play).w
 
    bne.s    +
 
    move.b    d0,(Music_to_play).w
 
    rts
 
+
 
    move.b    d0,(Music_to_play_2).w
 
    rts
 
; End of function PlayMusic</asm>
 
  
And replace it with this:
+
Immediately below where those lines used to be is a line like this:
<asm>; sub_135E:
 
PlayMusic:
 
;    tst.b    ($FFFFFFE0).w
 
;    bne.s    +
 
;    move.b    d0,($FFFFFFE0).w
 
    move.b    d0,($FFFFF00A).w
 
    rts
 
+
 
    move.b    d0,($FFFFF00A).w
 
    rts
 
; End of function PlayMusic</asm>
 
  
Right beneath that should be PlaySound. Replace PlaySound with this:
+
<asm> ds.b $500 ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to Sonic 2)</asm>
<asm>; sub_1370
+
PlaySound:
+
Change it to this:
    move.b   d0,($FFFFF00B).w
 
    rts
 
; End of function PlaySound</asm>
 
  
Now we need to change PlaySoundStereo, which should be right beath PlaySound.
+
<asm> ds.b $600 ; $FFFFF000-$FFFFF5FF ; Used by the Sonic 2 Clone Driver.</asm>
Replace it with this:
+
<asm>; sub_1376:
+
The underwater palettes were overwriting some RAM that the Sonic 1/Sonic2 Clone Driver use, so we need to move them somewhere safer. Fortunately, such a place in RAM exists.
PlaySoundStereo:
 
    bra.s    PlayMusic    ; skip over routine (For S1 driver)
 
    move.b    d0,(SFX_to_play_2).w
 
    rts
 
; End of function PlaySoundStereo</asm>
 
  
Now PlaySoundLocal is the next thing to edit, and again, it should be right below PlaySoundStereo.
+
What we need, are $100 free bytes. So, first off, find the line:
Replace it with this:
 
<asm>; sub_137C:
 
PlaySoundLocal:
 
    tst.b    render_flags(a0)
 
    bpl.s    +
 
    move.b    d0,($FFFFF00B).w
 
+
 
    rts</asm>
 
  
Below this is the routine PauseGame. Rather than replacing that entire routine, we are simply going to find this:
+
<asm>Normal_palette:     ds.w palette_line_size</asm>
  
<asm>+
+
Paste the underwater_palette lines  right above it.
    move.w    #1,(Game_paused).w    ; freeze time
 
    move.b    #MusID_Pause,(Music_to_play).w    ; pause music</asm>
 
  
And replace it with this:
+
Right above the lines you just pasted, you should see the following:
  
<asm>+
+
<asm>Sprite_Table: ds.b $280 ; Sprite attribute table buffer
    move.w    #1,(Game_paused).w    ; freeze time
+
ds.b $80 ; unused, but SAT buffer can spill over into this area when there are too many sprites on-screen</asm>
    move.b   #1,($FFFFF003).w    ; pause music</asm>
+
 +
Replace them both with just this:
  
Now go to Pause_Resume, which should look like this:
+
<asm>Sprite_Table: ds.b $200 ; Sprite attribute table buffer</asm>
 
 
<asm>; loc_13F2:
 
Pause_Resume:
 
    move.b    #MusID_Unpause,(Music_to_play).w</asm>
 
 
 
Replace it with this:
 
 
 
<asm>; loc_13F2:
 
Pause_Resume:
 
    move.b   #$80,($FFFFF003).w</asm>
 
 
 
Now, find Pause_SlowMo, which should be this:
 
 
 
<asm>; loc_1400:
 
Pause_SlowMo:
 
    move.w    #1,(Game_paused).w
 
    move.b
 
    #MusID_Unpause,(Music_to_play).w
 
    rts</asm>
 
Replace it with the following:
 
 
 
<asm>; loc_1400:
 
Pause_SlowMo:
 
    move.w    #1,(Game_paused).w
 
    move.b    #1,($FFFFF003).w
 
    rts</asm>
 
 
 
Next, find SpecialStage_Unpause, which should be this:
 
 
 
<asm>; loc_541A:
 
SpecialStage_Unpause:
 
    move.b    #MusID_Unpause,(Music_to_play).w
 
    move.b    #8,(Vint_routine).w
 
    bra.w    WaitForVint</asm>
 
 
 
And replace it with this:
 
 
 
<asm>; loc_541A:
 
SpecialStage_Unpause:
 
    move.b    #1,($FFFFF003).w
 
    move.b    #8,(Vint_routine).w
 
    bra.w    WaitForVint</asm>
 
 
 
Finally, we're going to do something that will clean up some RAM for us later in the guide.
 
Do a search and replace (Usually CTRL+H) for "Underwater_palette_2". Replace all with "Underwater_palette".
 
I don't know why the game used two different section for underwater palettes, but I've done this change in my hack and it did no
 
 
 
harm.
 
 
 
We're done with the first part of this guide! Try to build your Rom, and you'll get some errors! Fun!
 
Next up, we'll be fixing these errors.
 
  
 
==Step 4 - Break it until it's fixed!==
 
==Step 4 - Break it until it's fixed!==

Revision as of 12:07, 11 September 2013

(Original guide by Caverns4)

Summary

Please note that this guide is currently in need of a few teaks, which I will be implementing once I get the chance. In the meantime, use this guide at your own risk. ~ Caverns4

The Sonic 2 Clone Driver is simply a modified version of the Sonic 1 Sound driver, designed to work with Sonic 2. The advantages to using this over the Sound Driver in Sonic 2 normally are numerous; It will be easier to modify existing songs as you won't have to worry about compressing and decompressing the music, and your music will be supported by more up to date Music editor programs.

There are a few bugs I have noticed. One is that the spindash sound will not raise pitch. The music is not a perfect adaptation of Sonic 2's music, particularly sometimes the PSG channels sound slightly different. This is most noticeable in Emerald Hill's music. Besides this, there are no problems.

If the above bugs will not bother you too badly, then you'll like using the Sonic 2 Clone Driver after working with Sonic 2's own sound driver. The Clone Driver is much easier to port music to, and in fact, Sonic 1 music can even just be bincluded into the ROM. This is because it's based on the Sonic 1 sound driver, and uses similar (if not the same) formatting. With this out of the way, now it's time to edit the Sonic 2 HG Dissasembly!

Before begining, you will need the following file:

Download.svg Download Sonic 2 Clone Driver Files
File: Sonic 2 Clone Driver.7z (78 kB) (info)

Step 1 - getting started

Back up your dissasembly if you haven't already.

To start, go into your sound folder, where you'll have a DAC folder, a music folder, and a PCM folder.

DELETE THEM ALL!

Also delete s2.sounddriver.asm. That's the Sonic 2 Sound Driver, so it's not necessary.

and then extract "Sonic 2 Clone Driver_fixed.7z" into the main folder of your dissasembly.

Step 2 - Deleting leftovers

Now open up s2.asm, and find the label 'SoundDriverLoad:'. Delete everything from that, up to and including:

<asm>'Mus_Continue: BINCLUDE "sound/music/Continue.bin"'</asm>

What we have done here is deleted the routines to load and decompress the Sound Driver. We don't need this anymore.

Next up, find this line:

<asm>cnop -Size_of_SEGA_sound, $8000</asm>

and delete everything from there up to (but not including) the line:

<asm> ; end of 'ROM'</asm>

Also, on the line above the 'EndOfRom:' label, you should see this:

<asm> shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic,movewZ80CompSize</asm>

Change it to this:

<asm> shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic</asm>

Finally, find the label 'sndDriverInput:'

Delete the entire function, which starts there, and ends at this line:

<asm>; End of function sndDriverInput</asm>

Now search in your assembly for "sndDriverInput", and delete any lines that point to it. There will be quite a few, but it won't hurt anything.

We've effectively deleted the old sound driver entirely from our game... Now it's time we implemented a new one.. But first, we need to prepare S2.Constants.asm

Step 3 - Overhauling Constants, fixing RAM

Open s2.constants.asm, and find the following line:

Find the line "; Music IDs". You'll see this:

<asm>; Music IDs offset := zMasterPlaylist ptrsize := 1 idstart := $81

$80 is reserved for silence, so if you make idstart $80 or less,
you may need to insert a dummy zMusIDPtr in the $80 slot</asm>

delete everything from there down to "MusID__End = id(zMusIDPtr__End)  ; A0", and paste the following where it used to be:

<asm>; Music IDs idstart := $81

$80 is reserved for silence, so if you make idstart $80 or less,
you may need to insert a dummy zMusIDPtr in the $80 slot

MusID__First = idstart MusID_2PResult = $81 MusID_EHZ = $82 MusID_MCZ_2P = $83 MusID_OOZ = $84 MusID_MTZ = $85 MusID_HTZ = $86 MusID_ARZ = $87 MusID_CNZ_2P = $88 MusID_CNZ = $89 MusID_DEZ = $8A MusID_MCZ = $8B MusID_EHZ_2P = $8C MusID_SCZ = $8D MusID_CPZ = $8E MusID_WFZ = $8F MusID_HPZ = $90 MusID_Options = $91 MusID_SpecStage = $92 MusID_Boss = $93 MusID_EndBoss = $94 MusID_Ending = $95 MusID_SuperSonic = $96 MusID_Invincible = $97 MusID_ExtraLife = $98 MusID_Title = $99 MusID_EndLevel = $9A MusID_GameOver = $9B MusID_Continue = $9C MusID_Emerald = $9D MusID_Credits = $9E MusID_Countdown = $9F MusID__End = $A0</asm>

The music is all fixed, now all that's left is the sound effects:

Find the line "; Sound IDs", and delete everything down to the line "; Special sound IDs". Leave the special IDs alone.

In place of the text you deleted, just paste this:

<asm>; Sound IDs idstart := $A0

SndID__First = idstart SndID_Jump = $A0  ; A0 SndID_Checkpoint = $A1  ; A1 SndID_SpikeSwitch = $A2  ; A2 SndID_Hurt = $A3  ; A3 SndID_Skidding = $A4  ; A4 SndID_BlockPush = $A5  ; A5 SndID_HurtBySpikes = $A6  ; A6 SndID_Sparkle = $A7 SndID_Beep = $A8 SndID_Bwoop = $A9 SndID_Splash = $AA SndID_Swish = $AB SndID_BossHit = $AC SndID_InhalingBubble = $AD SndID_ArrowFiring = $AE SndID_LavaBall = $AE SndID_Shield = $Af SndID_LaserBeam = $B0 SndID_Zap = $B1 SndID_Drown = $B2 SndID_FireBurn = $B3 SndID_Bumper = $B4 SndID_Ring = $B5  ; B5 SndID_RingRight = $B5 SndID_SpikesMove = $B6 SndID_Rumbling = $B7 SndID_Smash = $B9 SndID_DoorSlam = $BB SndID_SpindashRelease = $BC  ; BC SndID_Hammer = $BD SndID_Roll = $BE SndID_ContinueJingle = $BF SndID_CasinoBonus = $C0 SndID_Explosion = $C1 SndID_WaterWarning = $C2 SndID_EnterGiantRing = $C3 SndID_BossExplosion = $C4 SndID_TallyEnd = $C5 SndID_RingSpill = $C6 SndID_Flamethrower = $C8 SndID_Bonus = $C9 SndID_SpecStageEntry = $CA SndID_SlowSmash = $CB SndID_Spring = $CC SndID_Blip = $CD SndID_RingLeft = $B5 SndID_Signpost = $CF SndID_CNZBossZap = $D0 SndID_Signpost2P = $D3 SndID_OOZLidPop = $D4 SndID_SlidingSpike = $D5 SndID_CNZElevator = $D6 SndID_PlatformKnock = $D7 SndID_BonusBumper = $D8 SndID_LargeBumper = $D9 SndID_Gloop = $DA SndID_PreArrowFiring = $DB SndID_Fire = $DC SndID_ArrowStick = $DD SndID_Helicopter = $DE SndID_SuperTransform = $DF SndID_SpindashRev = $E0 SndID_Rumbling2 = $E1 SndID_CNZLaunch = $E2 SndID_Flipper = $E3 SndID_HTZLiftClick = $E4 SndID_Leaves = $E5 SndID_MegaMackDrop = $E6 SndID_DrawbridgeMove = $E7 SndID_QuickDoorSlam = $E8 SndID_DrawbridgeDown = $E9 SndID_LaserBurst = $EA SndID_Scatter = $EB SndID_LaserFloor = $EB SndID_Teleport = $EC SndID_Error = $ED SndID_MechaSonicBuzz = $EE SndID_LargeLaser = $EF SndID_OilSlide = $F0 SndID__End = $F7</asm>

The following are the lines you should NOT have deleted, just for reference:

<asm>MusID_StopSFX = $78+$80 ; F8 MusID_FadeOut = $79+$80 ; F9 SndID_SegaSound = $7A+$80 ; FA MusID_SpeedUp = $7B+$80 ; FB MusID_SlowDown = $7C+$80 ; FC MusID_Stop = $7D+$80 ; FD MusID_Pause = $7E+$80 ; FE MusID_Unpause = $7F+$80 ; FF</asm>

Now, find these lines:

<asm>Underwater_palette_2: ds.w palette_line_size ; not sure what it's used for but it's only used when there's water Underwater_palette_2_line2: ds.w palette_line_size Underwater_palette_2_line3: ds.w palette_line_size Underwater_palette_2_line4: ds.w palette_line_size

Underwater_palette: ds.w palette_line_size ; main palette for underwater parts of the screen Underwater_palette_line2: ds.w palette_line_size Underwater_palette_line3: ds.w palette_line_size Underwater_palette_line4: ds.w palette_line_size</asm>

Copy these lines to the clipboard (Or better yet, to a separate text document), we are going to be moving them in a moment.

Immediately below where those lines used to be is a line like this:

<asm> ds.b $500 ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to Sonic 2)</asm>

Change it to this:

<asm> ds.b $600 ; $FFFFF000-$FFFFF5FF ; Used by the Sonic 2 Clone Driver.</asm>

The underwater palettes were overwriting some RAM that the Sonic 1/Sonic2 Clone Driver use, so we need to move them somewhere safer. Fortunately, such a place in RAM exists.

What we need, are $100 free bytes. So, first off, find the line:

<asm>Normal_palette: ds.w palette_line_size</asm>

Paste the underwater_palette lines right above it.

Right above the lines you just pasted, you should see the following:

<asm>Sprite_Table: ds.b $280 ; Sprite attribute table buffer ds.b $80 ; unused, but SAT buffer can spill over into this area when there are too many sprites on-screen</asm>

Replace them both with just this:

<asm>Sprite_Table: ds.b $200 ; Sprite attribute table buffer</asm>

Step 4 - Break it until it's fixed!

If you look at the log, you'll see a lot of errors like this one:

> > >Sonic 2 Clone Driver.asm(42): error: unknown opcode > > > INCBIN > > > PSG7: incbin sound\psg7.bin

Luckily, this is a simple fix. Open up Sonic 2 Clone Driver.asm, anf find and replace (CRTL+H usually) all instances of "INCBIN" with

"BINCLUDE" (Without the quotes, obviously).

Now repeat the process, replacing all intances of "@loc" with "Lloc". The HG dissasembly does not like local routines, so this

converts them into normal routines to avoid errors.

Save the file, and compile the ROM again. I got 437 errors, and of course, they need to be fixed as well.

On the bright side, you can close s2.asm and Sonic 2 Clone Driver.asn, they are all fixed.

Step 5 - Strippers

Re-Open s2.sounddriver.asm, because we need to strip it down even more.

Find zDACPtrTbl, and delete everything down to the line "idstart := 81h"

Go to "zBankSwitchToMusic:", and delete the contents of that routine.(Everything between "zBankSwitchToMusic:" and "ret" Go to "zUpdateDAC:" and again delete everything down to "ret".

Now find this line:

<asm>ensure1byteoffset macro maxsize</asm>

Delete everything between that and endm, but leave those two lines, otherwise you will get errors.

If you build the ROM now, you will get 393 errors, but almost all of these are duplicates or fixed just by fixing another. Don't close s2.sounddriver.asm just yet, we'll be stripping more content from that later. Right now however, we're going to fix the

bulk of these errors.

Step 6 - Identity Crisis

Open s2.constants.asm. 393 is a lot of errors, but all it takes to fix them is a copy+paste job for you.

Find the line "; Music IDs". You'll see this:

<asm>; Music IDs offset := zMasterPlaylist ptrsize := 1 idstart := $81

$80 is reserved for silence, so if you make idstart $80 or less,
you may need to insert a dummy zMusIDPtr in the $80 slot</asm>

delete everything from there down to "MusID__End = id(zMusIDPtr__End)  ; A0", and paste the following where it used to be:

<asm>; Music IDs offset := MusicIndex ptrsize := 1 idstart := $81

$80 is reserved for silence, so if you make idstart $80 or less,
you may need to insert a dummy zMusIDPtr in the $80 slot

MusID__First = idstart MusID_2PResult = $81 MusID_EHZ = $82 MusID_MCZ_2P = $83 MusID_OOZ = $84 MusID_MTZ = $85 MusID_HTZ = $86 MusID_ARZ = $87 MusID_CNZ_2P = $88 MusID_CNZ = $89 MusID_DEZ = $8A MusID_MCZ = $8B MusID_EHZ_2P = $8C MusID_SCZ = $8D MusID_CPZ = $8E MusID_WFZ = $8F MusID_HPZ = $90 MusID_Options = $91 MusID_SpecStage = $92 MusID_Boss = $93 MusID_EndBoss = $94 MusID_Ending = $95 MusID_SuperSonic = $96 MusID_Invincible = $97 MusID_ExtraLife = $98 MusID_Title = $99 MusID_EndLevel = $9A MusID_GameOver = $9B MusID_Continue = $9C MusID_Emerald = $9D MusID_Credits = $9E MusID_Countdown = $9F MusID__End = $A0</asm>

The music is all fixed, now all that's left is the sound effects:

Find the line "; Sound IDs", and delete everything down to the line "; Special sound IDs". Leve the special IDs alone.

In place of the text you deleted, just paste this:

<asm>; Sound IDs offset := SoundIndex ptrsize := 2 idstart := $A0

SndID__First = idstart SndID_Jump = $A0  ; A0 SndID_Checkpoint = $A1  ; A1 SndID_SpikeSwitch = $A2  ; A2 SndID_Hurt = $A3  ; A3 SndID_Skidding = $A4  ; A4 SndID_BlockPush = $A5  ; A5 SndID_HurtBySpikes = $A6  ; A6 SndID_Sparkle = $A7 SndID_Beep = $A8 SndID_Bwoop = $A9 SndID_Splash = $AA SndID_Swish = $AB SndID_BossHit = $AC SndID_InhalingBubble = $AD SndID_ArrowFiring = $AE SndID_LavaBall = $AE SndID_Shield = $Af SndID_LaserBeam = $B0 SndID_Zap = $B1 SndID_Drown = $B2 SndID_FireBurn = $B3 SndID_Bumper = $B4 SndID_Ring = $B5  ; B5 SndID_RingRight = $B5 SndID_SpikesMove = $B6 SndID_Rumbling = $B7 SndID_Smash = $B9 SndID_DoorSlam = $BB SndID_SpindashRelease = $BC  ; BC SndID_Hammer = $BD SndID_Roll = $BE SndID_ContinueJingle = $BF SndID_CasinoBonus = $C0 SndID_Explosion = $C1 SndID_WaterWarning = $C2 SndID_EnterGiantRing = $C3 SndID_BossExplosion = $C4 SndID_TallyEnd = $C5 SndID_RingSpill = $C6 SndID_Flamethrower = $C8 SndID_Bonus = $C9 SndID_SpecStageEntry = $CA SndID_SlowSmash = $CB SndID_Spring = $CC SndID_Blip = $CD SndID_RingLeft = $B5 SndID_Signpost = $CF SndID_CNZBossZap = $D0 SndID_Signpost2P = $D3 SndID_OOZLidPop = $D4 SndID_SlidingSpike = $D5 SndID_CNZElevator = $D6 SndID_PlatformKnock = $D7 SndID_BonusBumper = $D8 SndID_LargeBumper = $D9 SndID_Gloop = $DA SndID_PreArrowFiring = $DB SndID_Fire = $DC SndID_ArrowStick = $DD SndID_Helicopter = $DE SndID_SuperTransform = $DF SndID_SpindashRev = $E0 SndID_Rumbling2 = $E1 SndID_CNZLaunch = $E2 SndID_Flipper = $E3 SndID_HTZLiftClick = $E4 SndID_Leaves = $E5 SndID_MegaMackDrop = $E6 SndID_DrawbridgeMove = $E7 SndID_QuickDoorSlam = $E8 SndID_DrawbridgeDown = $E9 SndID_LaserBurst = $EA SndID_Scatter = $EB SndID_LaserFloor = $EB SndID_Teleport = $EC SndID_Error = $ED SndID_MechaSonicBuzz = $EE SndID_LargeLaser = $EF SndID_OilSlide = $F0 SndID__End = $F7</asm>

Step 7 - I am Error

Now we are going back to s2.sounddriver.asm. There are 4 more errors here. As before, we're going to solve this by simply emptying out the relavent routines. We can't just delete stuff because a few things in it

are still going to be referenced. So the first Routine to clean out is zDACAfterDur. change that and remove zloc_22A inside it so it looks like this:

<asm>zDACAfterDur:

   ret</asm>
 

There is one more routine to empty. That routine is zloc_78E, or zBGMLoad. Starting at this line:

<asm>zBGMLoad:</asm>

delete everything down to here:

<asm>  ; End of DAC/FM init, begin PSG init</asm>

And there you have it! Close s2.sounddriver.asm, Build you ROM and test it!

Additional Step

Uh-oh! if you've played up to Chemical Plant Zone Act 2, you'll notice the driver crashes on that level!

This is because of water. In Sonic 2, the underwater palettes are stored in a section of RAM that is now used by the sound driver,

because it's based on Sonic 1's sound driver. What we need to do now is relocate the water palette table in RAM, so the Sound Driver can do what it likes. I am going to assume

you haven't modified the RAM allocation in your hack here, and go step by step. If you have modifying the RAM in your game, you

are probably on your own.

Let's go back to s2.constants.asm, and find these lines:

<asm>Underwater_palette_2: ds.w palette_line_size  ; not sure what it's used for but it's only used when there's water Underwater_palette_2_line2: ds.w palette_line_size Underwater_palette_2_line3: ds.w palette_line_size Underwater_palette_2_line4: ds.w palette_line_size

Underwater_palette: ds.w palette_line_size  ; main palette for underwater parts of the screen Underwater_palette_line2: ds.w palette_line_size Underwater_palette_line3: ds.w palette_line_size Underwater_palette_line4: ds.w palette_line_size

               ds.b    $500    ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to 

Sonic 2) </asm> The last four lines before the ds.b $500 are used by the sound driver now, in addition to the 500 that is labeled as such.

Replace all of the above lines with this:

<asm> ds.b $100  ; Sonic 1 Sound Driver

                   ds.b    $500    ; Sonic 1 Sound Driver</asm>

After doing that, you will need to find at least $80 free bytes in RAM (besides the space we just put in) Fortunately, there is an area of RAM that has $C0 free bytes, and that is where the four lines we lost will go. Search for this:

<asm>CNZ_saucer_data:</asm>

And you will see this:

<asm>CNZ_saucer_data: ds.b $40  ; the number of saucer bumpers in a group which have been destroyed. Used to decide when to give 500 points instead of 10

               ds.b    $C0    ; $FFFFE740-$FFFFE7FF ; unused as far as I can tell

Ring_Positions: ds.b $600</asm>

Replace it with this:

<asm>CNZ_saucer_data: ds.b $40  ; the number of saucer bumpers in a group which have been destroyed. Used to decide when to give 500 points instead of 10 Underwater_palette: ds.w palette_line_size  ; main palette for underwater parts of the screen Underwater_palette_line2: ds.w palette_line_size Underwater_palette_line3: ds.w palette_line_size Underwater_palette_line4: ds.w palette_line_size

               ds.b    $40    ; $FFFFE740-$FFFFE7FF ; unused as far as I can tell

Ring_Positions: ds.b $600</asm>

Build it, and test!

The sega sound will be glitched up, and you can fix it by following this link. Everything that needs to be fixed will be in "Sonic 2 Clone Driver.asm".

Credits

   Varion Icaria - Puto's sound driver port.
   Esrael - Tweakers driver port, plus fixes for things broken in Puto's port, such as hanging on the title card. Extra thanks for fixing the Sega sound.
   Puto - Fixes for underwater palette stuff, as well as special stage ring stuff, and various other fixes to the original guide.
   Tweaker - Wrote the orignal guide to port Sonic 1's sound driver into Sonic 2.
   ValleyBell - lots of miscallanious help to get this to work, as well as worked on the Sonic 2 Clone Driver.
   ShadowsofYesterday - Telling me the fix for the SEGA sound.
   Caverns4 - I wrote this guide!
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