don't click here

How to fix the drowning bugs

Discussion in 'Engineering & Reverse Engineering' started by redhotsonic, Jul 28, 2012.

  1. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    Hello, guys. I come forth with another two (maybe three) bug fixes! These bugs are present in Sonic 1 and Sonic 2, but has been fixed in Sonic 3 (and Knuckles).



    There is a drowning bug. You know, you're underwater, timer starts, can't find air, you drown. But what happens if you get hurt as soon as you're about to drown? Well, this little video will demonstrate:




    If you're hurt and you haven't landed yet, when you drown, Sonic will still be using the gravity from his falling back from hurt state. He will also be able to detect the floors and walls. Hence why in this video, I was able to move about after drowning. However, there is a timer present, and it will force you to the bottom of the screen and restart within seconds.


    Also, in both Sonic 1 and 2, there is another bug, although, hard to pull off. If you drown around the 9:58 mark, then the timer hits 9:59 and you're still drowning, Sonic will all of a sudden zoom to the top of the screen then back down again, really fast, in his death animation. The Time over appears.


    In Sonic 2, there is an extra bug. When you and Tails (sidekick) drowns (normally), when Sonic reaches to the bottom of the screen, if Tails hasn't yet, he will suddenly start flying and move closer to where you drowned, but will continue to fall downwards.


    In Sonic 3 and Knuckles, all of these have been fixed. It doesn't matter if you're in the hurt state, Sonic will still fall normally and will ignore the floor. And unless Tails entered the water at the exact same time as you (like he does at the beginning of HCZ1), Tails will automatically start swimming to where you drowned but will not fall. If he did enter the water at the same time, he will drown with you, but won't have time to do that bug where he would start flying suddenly. Time over will still make an appearance if you drown near the 9:58 mark, but Sonic won't misbehave.



    Today, I'm going to show you how to fix these bugs in Sonic 1 and Sonic 2, the way Sonic 3 and Knuckles did it. It's not that hard, I've done all the research for you.


    I will show you Sonic 1 SVN, and for Sonic 2, both Xenowhirls 2007 and SVN disassembly.



    Sonic 1 fix - SVN Disassembly


    First, we need to make little edit to the drowning-routine. You need to open the "0A - Drowning Countdown.asm".


    Go to "@reduceair:" and just after the "move.w #0,obInertia(a0)" command, insert this:

    Code (ASM):
    1.         move.b  #$A,obRoutine(a0)   ; Force the character to drown

    And just after "move.b #1,(f_nobgscroll).w", insert this:

    Code (ASM):
    1.     move.b  #0,(f_timecount).w  ; Stop the timer immediately

    So you have this:

    Code (ASM):
    1. @reduceair:
    2.         subq.w  #1,(v_air).w    ; subtract 1 from air remaining
    3.         bcc.w   @gotomakenum    ; if air is above 0, branch
    4.  
    5.         ; Sonic drowns here
    6.         bsr.w   ResumeMusic
    7.         move.b  #$81,(f_lockmulti).w ; lock controls
    8.         sfx sfx_Drown   ; play drowning sound
    9.         move.b  #$A,$34(a0)
    10.         move.w  #1,$36(a0)
    11.         move.w  #$78,$2C(a0)
    12.         move.l  a0,-(sp)
    13.         lea (v_player).w,a0
    14.         bsr.w   Sonic_ResetOnFloor
    15.         move.b  #$17,obAnim(a0) ; use Sonic's drowning animation
    16.         bset    #1,obStatus(a0)
    17.         bset    #7,obGfx(a0)
    18.         move.w  #0,obVelY(a0)
    19.         move.w  #0,obVelX(a0)
    20.         move.w  #0,obInertia(a0)
    21.         move.b  #$A,obRoutine(a0)   ; Force the character to drown
    22.         move.b  #1,(f_nobgscroll).w
    23.         move.b  #0,(f_timecount).w  ; Stop the timer immediately
    24.         movea.l (sp)+,a0
    25.         rts


    Next, go to "@loc_13F86:" and change all this:

    Code (ASM):
    1. @loc_13F86:
    2.         subq.w  #1,$2C(a0)
    3.         bne.s   @loc_13F94
    4.         move.b  #6,(v_player+obRoutine).w
    5.         rts
    6. ; ===========================================================================
    7.  
    8.     @loc_13F94:
    9.         move.l  a0,-(sp)
    10.         lea (v_player).w,a0
    11.         jsr SpeedToPos
    12.         addi.w  #$10,obVelY(a0)
    13.         movea.l (sp)+,a0
    14.         bra.s   @nochange
    15.  

    To this:

    Code (ASM):
    1. @loc_13F86:
    2.         subq.w  #1,$2C(a0)
    3.         bne.s   @nochange           ; Make it jump straight to this location
    4.         move.b  #6,(v_player+obRoutine).w
    5.         rts

    Right, that's the drowning-routine finished. Now, we need to make Sonic apply to this.



    Now, open the main ASM file. Go to "Sonic_Index:" and add this line at the end of the table:

    Code (ASM):
    1.         dc.w Sonic_Drowned-Sonic_Index

    So you have:

    Code (ASM):
    1. Sonic_Index:    dc.w Sonic_Main-Sonic_Index
    2.         dc.w Sonic_Control-Sonic_Index
    3.         dc.w Sonic_Hurt-Sonic_Index
    4.         dc.w Sonic_Death-Sonic_Index
    5.         dc.w Sonic_ResetLevel-Sonic_Index
    6.         dc.w Sonic_Drowned-Sonic_Index

    Next, find "include "_incObj\Sonic Loops.asm"" and just below it, insert this:

    Code (ASM):
    1.         include "_incObj\Sonic Drowns.asm"

    Then, in the "_incObj" folder, make a new ASM file called "Sonic Drowns.asm" and insert this:


    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Sonic when he's drowning
    3. ; ---------------------------------------------------------------------------
    4.  
    5. ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
    6.  
    7.  
    8. Sonic_Drowned:
    9.     bsr.w   SpeedToPos      ; Make Sonic able to move
    10.     addi.w  #$10,y_vel(a0)      ; Apply gravity
    11.     bsr.w   Sonic_RecordPosition    ; Record position
    12.     bsr.s   Sonic_Animate       ; Animate Sonic
    13.     bsr.w   Sonic_LoadGfx       ; Load Sonic's DPLCs
    14.     bra.w   DisplaySprite       ; And finally, display Sonic




    There, all done. When you drown, everything will be normal. If you got hurt then drown, everything will still be normal and you won't be able to hit the floor, nor will you fall fast. Also, as soon as Sonic drowns, the timer will stop immediately, rather than continuing to countdown. Because of this, there is no way you can get Time Over when drowning.






    Sonic 2 fix - XenoWhirl's Disassembly


    First, we need to make little edit to the drowning-routine. Go to "Obj0A_ReduceAir:" and just after the "move.w #0,inertia(a0)" command, insert this:

    Code (ASM):
    1.     move.b  #$C,routine(a0) ; Force the character to drown

    And just after "move.b #1,($FFFFEEDC).w", insert this:

    Code (ASM):
    1.     move.b  #0,(Update_HUD_timer).w ; Stop the timer immediately

    So you have this:

    Code (ASM):
    1. Obj0A_ReduceAir:
    2.     subq.b  #1,air_left(a2)     ; subtract 1 from air remaining
    3.     bcc.w   BranchTo_Obj0A_MakeItem ; if air is above 0, branch
    4.     move.b  #$81,obj_control(a2)    ; lock controls
    5.     move.w  #$32+$80,d0
    6.     jsr (PlaySound).l       ; play drowning sound
    7.     move.b  #$A,objoff_34(a0)
    8.     move.w  #1,objoff_36(a0)
    9.     move.w  #$78,objoff_2C(a0)
    10.     movea.l a2,a1
    11.     bsr.w   ResumeMusic
    12.     move.l  a0,-(sp)
    13.     movea.l a2,a0
    14.     bsr.w   Sonic_ResetOnFloor_Part2
    15.     move.b  #$17,anim(a0)   ; use Sonic's drowning animation
    16.     bset    #1,status(a0)
    17.     bset    #7,art_tile(a0)
    18.     move.w  #0,y_vel(a0)
    19.     move.w  #0,x_vel(a0)
    20.     move.w  #0,inertia(a0)
    21.     move.b  #$C,routine(a0) ; Force the character to drown
    22.     movea.l (sp)+,a0 ; load 0bj address ; restore a0 = obj0A
    23.     cmpa.w  #MainCharacter,a2
    24.     bne.s   +   ; if it isn't player 1, branch
    25.     move.b  #1,($FFFFEEDC).w
    26.     move.b  #0,(Update_HUD_timer).w ; Stop the timer immediately
    27. +
    28.     rts


    Next, go to "loc_1D708:" and change all this:

    Code (ASM):
    1. loc_1D708:
    2.     subq.w  #1,objoff_2C(a0)
    3.     bne.s   +
    4.     move.b  #6,routine(a2)
    5.     rts
    6. ; ---------------------------------------------------------------------------
    7. +   move.l  a0,-(sp)
    8.     movea.l a2,a0
    9.     jsr ObjectMove
    10.     addi.w  #$10,y_vel(a0)
    11.     movea.l (sp)+,a0 ; load 0bj address
    12.     bra.s   loc_1D72C

    To this:

    Code (ASM):
    1. loc_1D708:
    2.     subq.w  #1,objoff_2C(a0)
    3.     bne.s   loc_1D72C       ; Make it jump straight to this location
    4.     move.b  #6,routine(a2)
    5.     rts

    Right, that's the drowning-routine finished. Now, we need to make the characters apply to this.



    Sonic. Go to "Obj01_States:" and add this line at the end of the table:

    Code (ASM):
    1.     dc.w    Obj01_Drowned - Obj01_States    ;$C

    So you have:

    Code (ASM):
    1. Obj01_States:
    2.     dc.w    Obj01_Init - Obj01_States   ; 0
    3.     dc.w    Obj01_Control - Obj01_States    ; 2
    4.     dc.w    Obj01_Hurt - Obj01_States   ; 4
    5.     dc.w    Obj01_Dead - Obj01_States   ; 6
    6.     dc.w    Obj01_Gone - Obj01_States   ; 8
    7.     dc.w    Obj01_Respawning - Obj01_States ;$A
    8.     dc.w    Obj01_Drowned - Obj01_States    ;$C

    Next, go to "Sonic_Animate:" and just above it, insert this:

    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Sonic when he's drowning
    3. ; ---------------------------------------------------------------------------
    4. Obj01_Drowned:
    5.     bsr.w   ObjectMove  ; Make Sonic able to move
    6.     addi.w  #$10,y_vel(a0)  ; Apply gravity
    7.     bsr.w   Sonic_RecordPos ; Record position
    8.     bsr.w   Sonic_Animate   ; Animate Sonic
    9.     bsr.w   LoadSonicDynPLC ; Load Sonic's DPLCs
    10.     bra.w   DisplaySprite   ; And finally, display Sonic


    That's Sonic done. Tails is next. Go to "Obj02_States:" and again, insert this line at the end of the table:

    Code (ASM):
    1.     dc.w Obj02_Drowned - Obj02_States   ;$C

    So you have:

    Code (ASM):
    1. Obj02_States:
    2.     dc.w Obj02_Init - Obj02_States      ; 0
    3.     dc.w Obj02_Control - Obj02_States   ; 2
    4.     dc.w Obj02_Hurt - Obj02_States      ; 4
    5.     dc.w Obj02_Dead - Obj02_States      ; 6
    6.     dc.w Obj02_Gone - Obj02_States      ; 8
    7.     dc.w Obj02_Respawning - Obj02_States    ;$A
    8.     dc.w Obj02_Drowned - Obj02_States   ;$C

    Next, go to "Tails_Animate:" and just above it, insert this:

    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Tails when he's drowning
    3. ; ---------------------------------------------------------------------------
    4. Obj02_Drowned:
    5.     bsr.w   ObjectMove  ; Make Tails able to move
    6.     addi.w  #$10,y_vel(a0)  ; Apply gravity
    7.     bsr.w   Tails_RecordPos ; Record position
    8.     bsr.s   Tails_Animate   ; Animate Tails
    9.     bsr.w   LoadTailsDynPLC ; Load Tails's DPLCs
    10.     bra.w   DisplaySprite   ; And finally, display Tails


    There, all done. When you drown, everything will be normal. If you got hurt then drown, everything will still be normal and you won't be able to hit the floor, nor will you fall fast. If Tails is with you, he will fly out of the water as soon as you drown. Unless he entered the water at the exact same time as you; then he will drown with you, but won't have time to suddenly fly again.

    Now, as soon as Sonic drowns, the timer will stop immediately, rather than continuing to countdown. Because of this, there is no way you can get Time Over when drowning.













    Sonic 2 fix - SVN Disassembly


    First, we need to make little edit to the drowning-routine. Go to "Obj0A_ReduceAir:" and just after the "move.w #0,inertia(a0)" command, insert this:

    Code (ASM):
    1.     move.b  #$C,routine(a0) ; Force the character to drown

    And just after "move.b #1,(Deform_lock).w", insert this:

    Code (ASM):
    1.     move.b  #0,(Update_HUD_timer).w ; Stop the timer immediately

    So you have this:

    Code (ASM):
    1. Obj0A_ReduceAir:
    2.     subq.b  #1,air_left(a2)     ; subtract 1 from air remaining
    3.     bcc.w   BranchTo_Obj0A_MakeItem ; if air is above 0, branch
    4.     move.b  #$81,obj_control(a2)    ; lock controls
    5.     move.w  #SndID_Drown,d0
    6.     jsr (PlaySound).l       ; play drowning sound
    7.     move.b  #$A,objoff_34(a0)
    8.     move.w  #1,objoff_36(a0)
    9.     move.w  #$78,objoff_2C(a0)
    10.     movea.l a2,a1
    11.     bsr.w   ResumeMusic
    12.     move.l  a0,-(sp)
    13.     movea.l a2,a0
    14.     bsr.w   Sonic_ResetOnFloor_Part2
    15.     move.b  #$17,anim(a0)   ; use Sonic's drowning animation
    16.     bset    #1,status(a0)
    17.     bset    #high_priority_bit,art_tile(a0)
    18.     move.w  #0,y_vel(a0)
    19.     move.w  #0,x_vel(a0)
    20.     move.w  #0,inertia(a0)
    21.     move.b  #$C,routine(a0) ; Force the character to drown
    22.     movea.l (sp)+,a0 ; load 0bj address ; restore a0 = obj0A
    23.     cmpa.w  #MainCharacter,a2
    24.     bne.s   +   ; if it isn't player 1, branch
    25.     move.b  #1,(Deform_lock).w
    26.     move.b  #0,(Update_HUD_timer).w ; Stop the timer immediately
    27. +
    28.     rts


    Next, go to "loc_1D708:" and change all this:

    Code (ASM):
    1. loc_1D708:
    2.     subq.w  #1,objoff_2C(a0)
    3.     bne.s   +
    4.     move.b  #6,routine(a2)
    5.     rts
    6. ; ---------------------------------------------------------------------------
    7. +   move.l  a0,-(sp)
    8.     movea.l a2,a0
    9.     jsr (ObjectMove).l
    10.     addi.w  #$10,y_vel(a0)
    11.     movea.l (sp)+,a0 ; load 0bj address
    12.     bra.s   loc_1D72C

    To this:

    Code (ASM):
    1. loc_1D708:
    2.     subq.w  #1,objoff_2C(a0)
    3.     bne.s   loc_1D72C       ; Make it jump straight to this location
    4.     move.b  #6,routine(a2)
    5.     rts

    Right, that's the drowning-routine finished. Now, we need to make the characters apply to this.



    Sonic. Go to "Obj01_Index:" and add this line at the end of the table:

    Code (ASM):
    1.         offsetTableEntry.w Obj01_Drowned    ; $C

    So you have:

    Code (ASM):
    1. Obj01_Index:    offsetTable
    2.         offsetTableEntry.w Obj01_Init       ;  0
    3.         offsetTableEntry.w Obj01_Control    ;  2
    4.         offsetTableEntry.w Obj01_Hurt       ;  4
    5.         offsetTableEntry.w Obj01_Dead       ;  6
    6.         offsetTableEntry.w Obj01_Gone       ;  8
    7.         offsetTableEntry.w Obj01_Respawning ; $A
    8.         offsetTableEntry.w Obj01_Drowned    ; $C

    Next, go to "Sonic_Animate:" and just above it, insert this:

    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Sonic when he's drowning
    3. ; ---------------------------------------------------------------------------
    4. Obj01_Drowned:
    5.     bsr.w   ObjectMove  ; Make Sonic able to move
    6.     addi.w  #$10,y_vel(a0)  ; Apply gravity
    7.     bsr.w   Sonic_RecordPos ; Record position
    8.     bsr.w   Sonic_Animate   ; Animate Sonic
    9.     bsr.w   LoadSonicDynPLC ; Load Sonic's DPLCs
    10.     bra.w   DisplaySprite   ; And finally, display Sonic


    That's Sonic done. Tails is next. Go to "Obj02_Index:" and again, insert this line at the end of the table:

    Code (ASM):
    1.         offsetTableEntry.w Obj02_Drowned    ; $C

    So you have:

    Code (ASM):
    1. Obj02_Index:    offsetTable
    2.         offsetTableEntry.w Obj02_Init       ;  0
    3.         offsetTableEntry.w Obj02_Control    ;  2
    4.         offsetTableEntry.w Obj02_Hurt       ;  4
    5.         offsetTableEntry.w Obj02_Dead       ;  6
    6.         offsetTableEntry.w Obj02_Gone       ;  8
    7.         offsetTableEntry.w Obj02_Respawning ; $A
    8.         offsetTableEntry.w Obj02_Drowned    ; $C

    Next, go to "Tails_Animate:" and just above it, insert this:

    Code (ASM):
    1. ; ---------------------------------------------------------------------------
    2. ; Tails when he's drowning
    3. ; ---------------------------------------------------------------------------
    4. Obj02_Drowned:
    5.     bsr.w   ObjectMove  ; Make Tails able to move
    6.     addi.w  #$10,y_vel(a0)  ; Apply gravity
    7.     bsr.w   Tails_RecordPos ; Record position
    8.     bsr.s   Tails_Animate   ; Animate Tails
    9.     bsr.w   LoadTailsDynPLC ; Load Tails's DPLCs
    10.     bra.w   DisplaySprite   ; And finally, display Tails


    There, all done. When you drown, everything will be normal. If you got hurt then drown, everything will still be normal and you won't be able to hit the floor, nor will you fall fast. If Tails is with you, he will fly out of the water as soon as you drown. Unless he entered the water at the exact same time as you; then he will drown with you, but won't have time to suddenly fly again.

    Now, as soon as Sonic drowns, the timer will stop immediately, rather than continuing to countdown. Because of this, there is no way you can get Time Over when drowning.






    There you have it! All fixed! Enjoy!
     
  2. Alriightyman

    Alriightyman

    I am back... from the dead! Tech Member
    357
    11
    18
    Somewhere in hot, death Florida
    0101001101101111011011100110100101100011 00000010: 0101001100000011 01000101011001000110100101110100011010010110111101101110
    I don't think I have ever come across those bugs before! Awesome!!!
     
  3. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    Thanks. My sister was playing my hack the night before the contest updates were due, then ran into this bug. I then checked Sonic 1 and 2 and realised it was a bug there too, but fixed in S3K. I came up with a very very quick shitty fix for it and submitted my hack. So in the contest, my hack has the bug fixed, but Sonic zooms to the bottom. It looks weird, but it works.


    The day after, I had time to investigate it properly, and then came up with proper fixes. This works perfectly now in my hack and Sonic drowns like normal no matter what, shame it wasn't in time. Sorry I couldn't come up with this quicker, guys!
     
  4. RetroKoH

    RetroKoH

    Member
    1,661
    18
    18
    Project Sonic 8x16
    This reminds me of a bug in both Sonic's 1 & 2. I don't know if it is caused by the same EXACT bug you just covered... BUT, to see it, go to Chemical Plant Zone Act 2, and go to the lower spike section with the extra life. Wait underwater just before you drown, and get hit by the spikes. As you mentioned, when drowning in the hurt animation, things go awry... well, spikes make it even worse. If done right, you will drown, then die due to being hit by the spikes... losing 2 lives. One could pull this off and underflow the lives counter, setting it to a glitchy 255. I do this all the time to keep a high number of lives, but it'd be nice to fix.
     
  5. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    Yes, this does fix this glitch. But this glitch you mention is heavily misunderstood. When you're drowning, you can't hit any more objects, even from the hurt state. It's impossible to hit them spikes when you're drowning.

    If you try it again, if you look very closely, Sonic actually drowns through the spikes just fine. It's the bottom of the screen that is causing it. If you get hurt, then drown, then hit the bottom of the screen, this will cause the losing 2 lives glitch; not the spikes itself. Try it. Use debug, make a spike or badnik underwater right by the bottom of the screen (CPZ or ARZ), then get hurt then drown; same thing will happen.


    Anyway, this glitch will now be fixed. I should explain how and why my fixes helps.



    Before the fix

    Object 0A (Small bubbles from Sonic's face while underwater), also controls the timer for when the drown jingle should start and when you should drown (Obj0A_ReduceAir:).

    "Obj0A_ReduceAir:" will make you drown, and once your time was up, it just pretty much do these commands:

    Code (ASM):
    1.     jsr ObjectMove
    2.     addi.w  #$10,y_vel(a0)
    This code is in the Obj0A object. So, it would basically make Sonic move downwards, and that's it. There is a quick timer running, and when it reaches 0, it will change Sonic's routine to dead, taking a life. That's how the drowning system works in Sonic 1 and 2, and it normally works fine.


    Because it's in the Obj0A code, Sonic's original code was still running. When Sonic gets hurt, his routine changes (to his hurt routine), and this is what causes the trouble. So, when Sonic now drowns, his hurt routine will still run.

    In Sonic's hurt routine, he can check for floors and walls. So if you get hurt, and then drown, he will wait 'til he hits the floor, and when he does, Sonic's routine will go back to normal, making Sonic himself normal and able to move. The Obj0A code is still running, so when that quick timer is up, it will force sonic to die and take a life.

    In his hurt state, Sonic will still check for boundaries, so if hurt then drown, as soon as he hits the bottom of the screen, Sonic will change to his dead routine instantly. The dead routine will take 1 life. That quick timer is still running and once up, it will restarts Sonic dead routine, so it will take another life.

    The reason why he moves so fast in these glitches is because his hurt/dead routine and Obj0A are both adding to his gravity, a bit too much.

    Sonic's hurt routine does not do the checks for Touch_Response, so even in his hurt routine, he can't interact with many objects, and that's why it wasn't the spikes causing the 2-lives glitch.




    With the fix

    With the fix above, we gave Sonic himself a brand new routine (Obj01_Drowned). Sonic's new routine, only contains this code:

    Code (ASM):
    1.        bsr.w   ObjectMove      ; Make Sonic able to move
    2.         addi.w  #$10,y_vel(a0)  ; Apply gravity
    3.         bsr.w   Sonic_RecordPos ; Record position
    4.         bsr.w   Sonic_Animate   ; Animate Sonic
    5.         bsr.w   LoadSonicDynPLC ; Load Sonic's DPLCs
    6.         bra.w   DisplaySprite   ; And finally, display Sonic

    As you can see, there are no checks for floors, no checks for walls, no checks for level boundaries, etc. All it simply does is make Sonic move, add a little gravity, and display him. Because of this, there is NO WAY Sonic can now interact with anything.


    Then at the "Obj0A_ReduceAir:", we made it so as soon as Sonic drowns, it will force Sonic to his new routine (so if Sonic is hurt, the routine will be changed to the new drown routine anyway). Then in "Obj0A_ReduceAir:" we took out the code where it applies gravity to Sonic (no point now as Sonic has his routine).



    So now, hurt or not, when Sonic drowns, it will force Sonic to his new routine no matter what. His new routine has no checks for floors or boundaries, so Sonic can just fall and drown peacefully. The quick timer from Obj0A is still running, and once up, it will change to Sonic's dead routine, and take 1 life only.
     
  6. RetroKoH

    RetroKoH

    Member
    1,661
    18
    18
    Project Sonic 8x16
    Implemented this in my Sonic 1 REV C rom.

    Works great, only 1 nitpick. No bubbles come from Sonic's mouth when he is in his drowning animation. Bubbles come out of his mouth normally, and the countdown numbers work fine... but after he drowns, no bubbles come out.

    Haven't tried for Sonic 2, but I'd assume it would be a similar result.
     
  7. redhotsonic

    redhotsonic

    Also known as RHS Tech Member
    1,587
    9
    18
    United Kingdom
    YouTuber
    Gah, sorry about that. In Sonic 2 Recreation, objects never freeze, so this wasn't a problem for me. Anyway, the fix is extremely simple.






    Sonic 1 fix - SVN Disassembly


    Go to label "loc_D362:" and between the label and it's first command, insert this:

    Code (ASM):
    1.         cmpi.b  #$A,(v_player+obRoutine).w  ; Has Sonic drowned?
    2.         beq.s   loc_D348            ; If so, run objects a little longer

    So you have this:

    Code (ASM):
    1. loc_D362:
    2.         cmpi.b  #$A,(v_player+obRoutine).w  ; Has Sonic drowned?
    3.         beq.s   loc_D348            ; If so, run objects a little longer
    4.         moveq   #$1F,d7
    5.         bsr.s   loc_D348
    6.         moveq   #$5F,d7

    Done.






    Sonic 2 fix - XenoWhirl's Disassembly AND SVN Disassembly


    Go to label "RunObjectsWhenPlayerIsDead:" and between the label and it's first command, insert this:

    Code (ASM):
    1.     cmpi.b  #$C,(MainCharacter+routine).w   ; Has Sonic drowned?
    2.     beq.s   RunObject           ; If so, run objects a little longer

    Done.






    Explanation


    "RunObjects:" is always running during a level. It asks the game every single frame, "Is Sonic's routine #6 or higher?" and if so, to branch to a newer routine. Otherwise, it will go onto the "RunObject" routine. The routine it branches to is "RunObjectsWhenPlayerIsDead". The routine to freeze all objects when Sonic dies.


    So, at this routine, we've made it ask, "Has Sonic drowned?" and if so, to continue running the objects a bit longer. So now, the bubbles have a chance to come out of Sonic when he drowns. Remember, that quick timer is still running, which will change Sonic's routine to his dead routine, and that's when finally, "RunObjectsWhenPlayerIsDead" will start running.



    The reason why we've put the new command here, is because then it only asks this question when Sonic is dead or drowned. You can put it in the "Runobjects" routine instead, but that means it asks it every single frame when playing the game normally. And that's just a waste of time on the processor. So it is not recommended. Asking it at "RunObjectsWhenPlayerIsDead" is much better, because it then only asks it when Sonic is dead or drowned, which is what we want. So basically, this new fix won't slow your game down at all.
     
  8. RetroKoH

    RetroKoH

    Member
    1,661
    18
    18
    Project Sonic 8x16
    Sweet deal, I'm now ready to implement this in the SCHG... along with a few others that slipped by lately. I just barely got to Esrael's Sonic 2 Starpost fix...
    I'll get to it this afternoon... got another question for you though RHS, but I'll PM this to you later.

    http://info.sonicretro.org/SCHG_How-to:Correct_Drowning_Bugs_in_Sonic_1
    http://info.sonicretro.org/SCHG_How-to:Correct_Drowning_Bugs_in_Sonic_2


    Oh, and I figured it out on my own so no need to ask, but if you could check the post I made for any errors, would be grand. :)
    That right there is my first ever fix. Kinda owe you thanks though, for pointing out the particular code I was looking for, in THIS guide.