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
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 ....
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.
is there some way to stop those code boxes changing when I am trying to read them? great guide apart from that !!!
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.
Sorry for double posting, but will you teach how to edit the heights in hex and fixing the surface? That would be awesome.
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.
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?
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
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?
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
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?!
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).