Drowning Bug Fixes - RetroKoH/S1Fixed GitHub Wiki
(Original Guide by redhotsonic)
Source: SCHG Page
Commit: 582ce06
So, you're underwater, timer starts, can't find air, AND... you drown. But what happens if you get hurt as soon as you're about to drown? Basically, 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, there is another bug, though it's 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 quickly zoom to the top of the screen, then back down again in his death animation. The Time Over graphic then appears.
Now, time to show you how to fix these bugs in Sonic 1 the way Sonic 3 and Knuckles did it.
First, we need to make a little edit to the drowning routine. You need to open _incObj/0A Drowning Countdown.asm. Go to .reduceair and add the two noted lines:
.reduceair:
subq.w #1,(v_air).w ; subtract 1 from air remaining
bcc.w .gotomakenum ; if air is above 0, branch
; Sonic drowns here
bsr.w ResumeMusic
move.b #$81,(f_lockmulti).w ; lock controls
sfx sfx_Drown ; play drowning sound
move.b #$A,objoff_34(a0)
move.w #1,objoff_36(a0)
move.w #$78,objoff_2C(a0)
move.l a0,-(sp)
lea (v_player).w,a0
bsr.w Sonic_ResetOnFloor
move.b #aniID_Drown,obAnim(a0) ; use Sonic's drowning animation
bset #1,obStatus(a0)
bset #7,obGfx(a0)
move.w #0,obVelY(a0)
move.w #0,obVelX(a0)
move.w #0,obInertia(a0)
+ move.b #$A,obRoutine(a0) ; Force the character to drown
move.b #1,(f_nobgscroll).w
+ move.b #0,(f_timecount).w ; Stop the timer immediately
movea.l (sp)+,a0
rts
Next, go to .loc_13F86 and change all this:
.loc_13F86:
subq.w #1,objoff_2C(a0)
bne.s .loc_13F94
move.b #6,(v_player+obRoutine).w
rts
; ===========================================================================
.loc_13F94:
move.l a0,-(sp)
lea (v_player).w,a0
jsr (SpeedToPos).l
addi.w #$10,obVelY(a0)
movea.l (sp)+,a0
bra.s .nochange
into this:
.loc_13F86:
subq.w #1,objoff_2C(a0)
bne.s .nochange
move.b #6,(v_player+obRoutine).w
rts
Right, that's the drowning routine finished. Now, we need to make Sonic adhere to this. Open sonic.asm, go to Sonic_Index, and add this line at the end of the table:
Sonic_Index:
dc.w Sonic_Main-Sonic_Index
dc.w Sonic_Control-Sonic_Index
dc.w Sonic_Hurt-Sonic_Index
dc.w Sonic_Death-Sonic_Index
dc.w Sonic_ResetLevel-Sonic_Index
+ dc.w Sonic_Drowned-Sonic_Index
Next, find include _incObj\Sonic Loops.asm
and just below it, insert include _incObj\Sonic Drowns.asm
.
Then, in the _incObj folder, make a new .asm file called Sonic Drowns.asm and insert this:
; ---------------------------------------------------------------------------
; Sonic when he's drowning
; ---------------------------------------------------------------------------
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
Sonic_Drowned:
bsr.w SpeedToPos ; Make Sonic able to move
addi.w #$10,y_vel(a0) ; Apply gravity
bsr.w Sonic_RecordPosition ; Record position
bsr.s Sonic_Animate ; Animate Sonic
bsr.w Sonic_LoadGfx ; Load Sonic's DPLCs
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 while drowning. This will mess things up considerably if you are playing around in Debug Mode, but worry not, there's a fix for that in another guide!
BUT WAIT! There's one more thing! You'll find that 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. To fix this, go to label loc_D362 and add these two lines at the start:
loc_D362:
+ cmpi.b #$A,(v_player+obRoutine).w ; Has Sonic drowned?
+ beq.s loc_D348 ; If so, run objects a little longer
moveq #(v_lvlobjspace-v_objspace)/object_size-1,d7
bsr.s loc_D348
moveq #(v_lvlobjend-v_lvlobjspace)/object_size-1,d7
Done! This allows objects to run for a little bit longer than normal, allowing the bubbles to run out of Sonic's mouth like normal.