Sonic 1 water guide!

Discussion in 'Approved' started by Tornado, Sep 17, 2009.

  1. Tornado

    Tornado Active Member Member

    Joined:
    Dec 1, 2008
    Messages:
    30
    Location:
    Hydrocity - Angel Island
    Surely some of you have tried to add water to another zone in sonic 1 without creating problems in Labirynth Zone .. here I will explain one easy way to do this ..

    Well, well, well .. After 10 long years, I came back to update this code. Let's do this in a more organized way;)
    Note: I know the disassemblies of now are more modern, but I kept
    "S1 Hiverbrain", then find the equivalent addresses in your
    disassemblies and make the changes​

    add these addresses at the beginning of the rom:

    Code:
    Water_Flag         equ       $FFFFFFBC  ; if the level has water
    Saved_Music                 equ       $FFFFFFBD  ; store level music
    Initially search for "loc_B9A:" and you will see:
    Code:
    loc_B9A:
            cmpi.b    #1,($FFFFFE10).w ; is level LZ ?
            bne.w    loc_B5E        ; if not, branch

    Replace this with:
    Code:
    loc_B9A:
            tst.b    (Water_flag).w  ; does level have water ?
            beq.w    loc_B5E        ; if not, branch

    Search for loc_1DFA, loc_1F20, Level_ClrVars3, LZWaterEffects, Sonic_Water and Obj79_LoadInfo and do the same changes in the equivalent lines, changing the check "cmpi.b # 1, ($ FFFFFE10) .w" by "tst.b (Water_flag) .w", always remembering to invert the command on the bottom line: If "beq", replace with "bne" and vice versa.

    Note: There are other checks for Labyrinth Zone remaining, but we will work with them
    more specific way later.

    Now let's create a specific routine to work with water, in a more organized way, like
    in S3K.

    Above "LZWaterEffects:", at the end of the "Level_MainLoop" routine, insert this:
    Code:
    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Subroutine to work with water
    ; ---------------------------------------------------------------------------
    
    LoadWaterLevel:
    ; Initially check which zones work with this
                    cmpi.b    #1,($FFFFFE10).w   ; Check Labyrinth Zone
                    beq.s   LoadWater          ; If LZ, continue
    
                    move.b  #0,(Water_flag).w  ; Prevent water from appearing outside the above stages.
    
                    rts
    ; ===========================================================================
    
    LoadWater:
                    move.b  #1,(Water_flag).w  ; Enable water in the checked level
            moveq    #0,d0
            move.w    ($FFFFFE10).w,d0   ; Now this check every zone and act
            lsl.b    #6,d0
                     lsr.w    #5,d0
            andi.w  #$FFFE,d0
                    lea    (WaterHeight).l,a1 ; load water    height array
            move.w    (a1,d0.w),d0
            move.w    d0,($FFFFF646).w   ; set water heights
            move.w    d0,($FFFFF648).w
            move.w    d0,($FFFFF64A).w
            clr.b    ($FFFFF64D).w       ; clear water routine counter
            clr.b    ($FFFFF64E).w      ; clear water movement
            move.b    #1,($FFFFF64C).w   ; enable water
    
                    ; If you don't want these objects to be read, check your zone here!
                    ;cmpi.b  #X,($FFFFFE10).w
                    ;beq.s   LoadWaterPalette
    
                    move.b    #$1B,($FFFFD780).w ; load water    surface    objects
            move.w    #$60,($FFFFD788).w
            move.b    #$1B,($FFFFD7C0).w
            move.w    #$120,($FFFFD7C8).w
    
    ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    
    ; Load underwater palettes
    LoadWaterPalette:
                    cmpi.b  #1,($FFFFFE10).w          ; check if zone is LZ
            bne.s   .newzone                  ; if not, skip to next zone
                    moveq    #$B,d0                    ; read palette number $B (Normal LZ underwater)
                    cmpi.w  #$103,($FFFFFE10).w       ; check if act number is $103 (SBZ3)
                    bne.s   .newzone                  ; if not, skip to next zone
                    moveq    #$D,d0                    ; read palette number $D (SBZ3 underwater)
                    bra.s   .waterpal                 ; branch to .waterpal routine (read underwater palettes)
    ; ---------------------------------------------------------------------------
    .newzone:       cmpi.b  #XX,($FFFFFE10).w         ; zone is???
            bne.s   .waterpal                 ; not? Skip to the next!
                    moveq    #YY,d0                    ; read palette number X
    ; ---------------------------------------------------------------------------
    
    .waterpal:
                    move.w    d0,d1
            bsr.w    PalLoad3_Water
            move.w    d1,d0
            bsr.w    PalLoad4_Water
                    tst.b    (Water_flag).w
            beq.s    WaterPal_End
                    move.b    ($FFFFFE53).w,($FFFFF64E).w
    WaterPal_End:
                    rts
    
    Now go to Level_ClrVars3 and delete all these lines
    Code:
    moveq    #0,d0
            move.b    ($FFFFFE11).w,d0
            add.w    d0,d0
            lea    (WaterHeight).l,a1 ; load water    height array
            move.w    (a1,d0.w),d0
            move.w    d0,($FFFFF646).w ; set water heights
            move.w    d0,($FFFFF648).w
            move.w    d0,($FFFFF64A).w
            clr.b    ($FFFFF64D).w    ; clear    water routine counter
            clr.b    ($FFFFF64E).w    ; clear    water movement
            move.b    #1,($FFFFF64C).w ; enable water
    and..

    Code:
    cmpi.b    #1,($FFFFFE10).w ; is level LZ?
            bne.s    Level_GetBgm    ; if not, branch
            moveq    #$F,d0        ; pallet number    $0F (LZ)
            cmpi.b    #3,($FFFFFE11).w ; is act number 3?
            bne.s    Level_WaterPal    ; if not, branch
            moveq    #$10,d0        ; pallet number    $10 (SBZ3)
    
    Level_WaterPal:
            bsr.w    PalLoad3_Water    ; load underwater pallet (see d0)
            tst.b    ($FFFFFE30).w
            beq.s    Level_GetBgm
            move.b    ($FFFFFE53).w,($FFFFF64E).w
    
    Level_GetBgm:
    The code should look like this:

    Code:
    Level_ClrVars3:
            move.l    d0,(a1)+
            dbf    d1,Level_ClrVars3 ; clear object variables
    
            move    #$2700,sr
            bsr.w    ClearScreen
            lea    ($C00004).l,a6
            move.w    #$8B03,(a6)
            move.w    #$8230,(a6)
            move.w    #$8407,(a6)
            move.w    #$857C,(a6)
            move.w    #$9001,(a6)
            move.w    #$8004,(a6)
            move.w    #$8720,(a6)
            move.w    #$8ADF,($FFFFF624).w
            move.w    ($FFFFF624).w,(a6)
    ; ---------------------------------------------------------------------------
    ; Water reading routine
                move.w    #$1E,($FFFFFE14).w     ; T: set Sonic air left
            jsr     (LoadWaterLevel).l     ; T: init water
            tst.b    (Water_flag).w         ; T: in water level?
            beq.s    Level_LoadPal          ; T: if not, branch
            move.w    #$8014,(a6)            ; T: load water internal features
            lea    ($FFFFFAA0).w,a1       ; T: fix palette
            moveq    #0,d0
            move.w    #$17,d1
    
    @loop        move.l    d0,(a1)+
            dbf    d1,@loop
    ; ---------------------------------------------------------------------------
    Level_LoadPal:
            move    #$2300,sr
            moveq    #3,d0
            bsr.w    PalLoad2    ; load Sonic's pallet line
    Go to "Level_ChkWater:" and remove these lines:
    Code:
    cmpi.b    #1,($FFFFFE10).w ; is level LZ?
            bne.s    Level_LoadObj    ; if not, branch
            move.b    #$1B,($FFFFD780).w ; load water    surface    object
            move.w    #$60,($FFFFD788).w
            move.b    #$1B,($FFFFD7C0).w
            move.w    #$120,($FFFFD7C8).w
    Now, go to "Level_ChkWaterPal:" and remove these lines:
    Code:
    cmpi.b    #1,($FFFFFE10).w ; is level LZ/SBZ3?
            bne.s    Level_Delay    ; if not, branch
            moveq    #$B,d0        ; pallet $0B (LZ underwater)
            cmpi.b    #3,($FFFFFE11).w ; is level SBZ3?
            bne.s    Level_WaterPal2    ; if not, branch
            moveq    #$D,d0        ; pallet $0D (SBZ3 underwater)
    
    Level_WaterPal2:
            bsr.w    PalLoad4_Water
    
    Level_Delay:
    Done! Now the entire Sonic 1 water system has been modified. Now we just need to make some fixes!

    PROBLEM 1: The dynamic water index!

    This code controls water movements (and changes the layout of the LZ3 at a certain point), but it only works
    on the LZ itself. We need this to be extended to all stages.

    Go to LZDynamicWater and change this:
    Code:
                   moveq    #0,d0
            move.b    ($FFFFFE11).w,d0
            add.w    d0,d0
            move.w    DynWater_Index(pc,d0.w),d0
            jsr    DynWater_Index(pc,d0.w)
    To this:
    Code:
                   moveq    #0,d0
            move.w    ($FFFFFE10).w,d0
            lsl.b    #6,d0
            lsr.w    #5,d0
            andi.w    #$FFFE,d0
                     move.w    DynWater_Index(pc,d0.w),d0
                     jsr    DynWater_Index(pc,d0.w)
    And this:
    Code:
    DynWater_Index:
                    dc.w DynWater_LZ1-DynWater_Index
            dc.w DynWater_LZ2-DynWater_Index
            dc.w DynWater_LZ3-DynWater_Index
            dc.w DynWater_SBZ3-DynWater_Index
    To this:
    Code:
    DynWater_Index:
                     dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
                    dc.w DynWater_LZ1-DynWater_Index    ; LZ is here
            dc.w DynWater_LZ2-DynWater_Index
            dc.w DynWater_LZ3-DynWater_Index
            dc.w DynWater_SBZ3-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
            dc.w locret_3C5A-DynWater_Index
    Done! Each zone has 4 pointers.. each pointer corresponding to an act.

    PROBLEM 2: The wind tunnels and water slides!

    These routines are specific to Labirynth Zone. With all the changes made, they are being loaded on at all stages now. We need to fix this!

    Go to "LZWaterEffects" and insert this under "bcc.s LZMoveWater"
    Code:
                    cmpi.b  #1,(FFFFFE10).w
                    bne.s   LZMoveWater     ; don't load this in any other zone
    move up the "bsr.w LZDynamicWater" to above these lines, like this:
    Code:
                    bsr.w   LZDynamicWater
                    cmpi.b  #1,($FFFFFE10).w
                    bne.s   LZMoveWater     ; don't load this in any other zone
                    bsr.w    LZWindTunnels
            bsr.w    LZWaterSlides
    
    LZMoveWater:
    Done!

    PROBLEM 3: Music restoring!
    You will have problems every time you get out of the water after the drowing countdown music starts playing. this is because Sonic 1 was programmed
    only to load the correct music in LZ, SBZ3 and in the cases of Boss or Invincibility. Let's copy something interesting that Sonic 2 has brought.

    Go to "Level_PlayBgm:" and under "move.b (a1,d0.w),d0", insert this:
    Code:
    move.w    d0,(Saved_Music).w    ; store level music
    Go to "Obj01_ChkInvin:" and replace these lines:
    Code:
                   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    (MusicList).l,a1
            move.b    (a1,d0.w),d0
    With:
    Code:
    move.w    (Saved_Music).w,d0
    Now, go to "ResumeMusic:" and replace this:
    Code:
                   moveq    #$82,d0    ; play LZ music
            cmpi.w    #$103,($FFFFFE10).w ; check if level is    0103 (SBZ3)
            bne.s    loc_140A6
            moveq    #$86,d0    ; play SBZ music
    
    loc_140A6:
    With:
    Code:
    move.w    (Saved_Music).w,d0    ; prepare to play current level's music
    Done! after exiting water during drowning countdown music, the correct bgm will play.

    PROBLEM 4: Water Heights!

    Very Simple! You only need to create 4 entries for each stage.

    Go to "WaterHeight:" and change this:
    Code:
    WaterHeight:    incbin    misc\lz_heigh.bin
            even
    With:
    Code:
    WaterHeight:    dc.w    $600,$600,$600,$600
                 dc.w    $0B8,$328,$900,$228   ; LZ default water heights
                 dc.w    $600,$600,$600,$600
                 dc.w    $600,$600,$600,$600
                 dc.w    $600,$600,$600,$600
                 dc.w    $600,$600,$600,$600
                 dc.w    $600,$600,$600,$600
            even
    I confess that I prefer to deal with this within the asm file itself. If you prefer, you can also include ".bin" extensions instead.
    Done! Sonic 1 work with water perfectly!

    Additional fix (Optional):


    Since our songs can now be saved to be loaded again after some events, we can extend this to other parts of codes that load songs from the stages.

    Find these addresses:

    loc_179E0, loc_18112, loc_1856C, loc_18BB4 and loc_194E0 and replace the "move.w #XX,d0" with:
    Code:
    move.w    (Saved_Music).w,d0
    XX is the music id, restored after a boss fight.

    Be sure to include the pointers of the new color palettes at the end of "PalPointers", and point to them in the "LoadWaterPalette" routine.
    Code:
            dc.l Pal_Ending
        dc.w $FB00
        dc.w $1F
      
        dc.l Pal_NewZoneWater ; $14 - new palette
        dc.w $FB00
        dc.w $1F
    I hope I have not become such an obsolete romhacker all this time :)
     
    Last edited: Jul 25, 2019
    AsuharaMoon and HackGame like this.
  2. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,429
    Location:
    Northern Germany
    I am NOT going to read a single word before you change those codeboxes to ASM boxes.
     
  3. redhotsonic

    redhotsonic Also known as RHS Member

    Joined:
    Aug 10, 2007
    Messages:
    2,969
    Location:
    England
    Eh? What are you on about? It is ASM =P
     
  4. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,429
    Location:
    Northern Germany
    Ugly code box:



    Code:
    loc_B9A:
    		;cmpi.b #1,($FFFFFE10).w
    		;bne.w loc_B5E
    		tst.b (Water_flag).w
    		beq.w loc_B5E ; if not, branch
    		....
    Nice ASM box:



    loc_B9A:
    ;cmpi.b #1,($FFFFFE10).w


    ;bne.w loc_B5E


    tst.b (Water_flag).w


    beq.w loc_B5E ; if not, branch


    ....
     
  5. OrdosAlpha

    OrdosAlpha RIGHT! Naebody move! Root Admin

    Joined:
    Aug 5, 2007
    Messages:
    1,793
    Location:
    Glasgow, Scotland
    Replace the codebox tags with asm tags please.
     
  6. NewSonic

    NewSonic Newcomer Member

    Joined:
    Sep 16, 2008
    Messages:
    19
    This is fantastic!!! It will be very useful for me.


    Nice work. :p
     
  7. bareirito

    bareirito Well-Known Member Member

    Joined:
    Nov 17, 2008
    Messages:
    87
    Location:
    Argentina
    This is what I was searching for so much time ago. Nice work, mate. I always wanted an Green Hill Zone with water. Once again nice work.
     
    Last edited by a moderator: Sep 18, 2009
  8. Dark Lips

    Dark Lips Well-Known Member Member

    Joined:
    Nov 14, 2008
    Messages:
    293
    Location:
    Wolverhampton UK
    is there some way to stop those code boxes changing when I am trying to read them? great guide apart from that !!!
     
  9. EMK-20218

    EMK-20218 The Fuss Maker Exiled

    Joined:
    Aug 8, 2008
    Messages:
    1,067
    Location:
    Jardim Capelinha, São Paulo
    Water surface object causes lag if the level uses lots of sprites at the same place...


    ...But yeah, I have to admit the fact that this is a great work. Certainly I will use it on my hacks.
     
  10. DeoxysKyogre

    DeoxysKyogre No idea what to put here .-. Member

    Joined:
    Jan 31, 2009
    Messages:
    298
    Truly awesome. It's real useful for me. I used it in the ice level in my hack :)
     
  11. DeoxysKyogre

    DeoxysKyogre No idea what to put here .-. Member

    Joined:
    Jan 31, 2009
    Messages:
    298
    Sorry for double posting, but will you teach how to edit the heights in hex and fixing the surface? That would be awesome.
     
  12. shadowbeasts

    shadowbeasts I'm Legend Member

    Joined:
    Jan 5, 2009
    Messages:
    286
    Location:
    Good 'ol USA.
    It's definitely a useful guide especially if you want to flood Labyrinth Zone and keep the bubbles in the same place they were originally without adding more, or you can get rid of all the bubbles and make sonic 1 impossible if you flood every level. I'll do that I'm evil what can I say.
     
  13. Dark Lips

    Dark Lips Well-Known Member Member

    Joined:
    Nov 14, 2008
    Messages:
    293
    Location:
    Wolverhampton UK
    Ok I have followed the guide and its great however - there are a couple of bits i need help understanding - firstly how do i change the pallet used in water? and secondly is there anyway to change the water height?
     
    Last edited by a moderator: Sep 28, 2009
  14. Tornado

    Tornado Active Member Member

    Joined:
    Dec 1, 2008
    Messages:
    30
    Location:
    Hydrocity - Angel Island
    firstly how do i change the pallet used in water?


    I explained in the tutorial, how to change the palette used:


    Go to Level_ChkWaterPal, and change to:



    Level_ChkWaterPal:
    cmpi.b #0,($FFFFFE10).w


    beq.s Ghz_ChkWaterPal


    bne.s Level_ChkWaterPal_Cont


    rts


    ; ===========================================================================


    Ghz_ChkWaterPal:


    moveq #$1E,d0 ; pallet $1E (GHZ underwater)


    bsr.w PalLoad4_Water


    move.w #3,d1


    jmp Level_DelayLoop


    ; ===========================================================================


    Level_ChkWaterPal_Cont:


    ...



    will be including brief tutorial in the guide to change the water line
     
    Last edited by a moderator: Sep 29, 2009
  15. Dark Lips

    Dark Lips Well-Known Member Member

    Joined:
    Nov 14, 2008
    Messages:
    293
    Location:
    Wolverhampton UK
    I really dont want to sound stupid but I dont understand what you are saying? I changed the 1E to something else and stull the underwater pallets dont look right... can you explain in a little more detail please?
     
  16. Tornado

    Tornado Active Member Member

    Joined:
    Dec 1, 2008
    Messages:
    30
    Location:
    Hydrocity - Angel Island
    Open _inc\pallet pointers.asm and you will see:



    ; ---------------------------------------------------------------------------
    ; Pallet pointers


    ; ---------------------------------------------------------------------------


    PalPointers:


    dc.l Pal_SegaBG ;0 ; pallet address


    dc.w $FB00 ; RAM address


    dc.w $1F ; (pallet length / 2) - 1


    dc.l Pal_Title ;1


    dc.w $FB00


    dc.w $1F


    dc.l Pal_LevelSel;2


    dc.w $FB20


    dc.w $17


    dc.l Pal_Sonic ;3


    dc.w $FB00


    dc.w 7


    dc.l Pal_GHZ ;4


    dc.w $FB20


    dc.w $17


    dc.l Pal_LZ ;5


    dc.w $FB20


    dc.w $17


    dc.l Pal_MZ ;6


    dc.w $FB20


    dc.w $17


    dc.l Pal_SLZ ;7


    dc.w $FB20


    dc.w $17


    dc.l Pal_SYZ ;8


    dc.w $FB20


    dc.w $17


    dc.l Pal_SBZ1 ;9


    dc.w $FB20


    dc.w $17


    dc.l Pal_Special ;$A


    dc.w $FB00


    dc.w $1F


    dc.l Pal_LZWater ;$B


    dc.w $FB00


    dc.w $1F


    dc.l Pal_SBZ3 ;$C


    dc.w $FB20


    dc.w $17


    dc.l Pal_SBZ3Water ;$D


    dc.w $FB00


    dc.w $1F


    dc.l Pal_SBZ2 ; $E


    dc.w $FB20


    dc.w $17


    dc.l Pal_LZSonWater ;$F


    dc.w $FB00


    dc.w 7


    dc.l Pal_SBZ3SonWat ;$10


    dc.w $FB00


    dc.w 7


    dc.l Pal_SpeResult ;$11


    dc.w $FB00


    dc.w $1F


    dc.l Pal_SpeContinue ;$12


    dc.w $FB00


    dc.w $F


    dc.l Pal_Ending ;$13


    dc.w $FB00


    dc.w $1F



    Ending Sequence palette is $13, add below:



    dc.l Pal_New_Level_Water ; $14
    dc.w $FB20


    dc.w $17



    change $1E to $14 .. and do not forget to include the palette in the rom
     
  17. theocas

    theocas #! Member

    Joined:
    Apr 10, 2010
    Messages:
    375
    Sorry to bump such an old topic, but where is the little guide on how to change the water height? I have tried HEX-Editing the ghz_heigh.bin file to all possible values, but the water level never changes?!
     
  18. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,429
    Location:
    Northern Germany
    I didn't even know there is a file called ghz_heigh.bin (because there isn't, there is no water in GHZ unless you add it). The file you are looking for is probably lz_heigh.bin (in the misc folder).
     
  19. theocas

    theocas #! Member

    Joined:
    Apr 10, 2010
    Messages:
    375
     
  20. Selbi

    Selbi The Euphonic Mess Member

    Joined:
    Jul 20, 2008
    Messages:
    2,429
    Location:
    Northern Germany
    Oddest reply I ever saw... why did you just quoted my post without a comment?