Fix the death boundary bug
From Sonic Retro
(Original guide by MarkeyJester)
In Sonic 1, if Sonic is at the top of a level, and he dies causing him to fly up and above the top of the screen, rather than dropping back down to the bottom of the screen before resetting the level, or bringing in the Game Over/Time Over text, he will simply disappear. This bug is mostly noticeable in Labyrinth Zone, Act 1 at the beginning. This quick fix will ensure that Sonic drops back down before ending the level.
Explaining the issue
At the routine named "GameOver:", you will see the following code:
move.w ($FFFFF72E).w,d0 addi.w #$100,d0 cmp.w $C(a0),d0 bcc.w locret_13900
What happens here is that it checks to see if Sonic has dropped 100 (hex) pixels below the Y boundary, however, the comparison here is "unsigned", meaning that if Sonic were to fall above the screen, and his Y position were to wrap around to FFFF and below to 8000, the engine believes that FFFF below to 8000 is a higher number than the level's Y boundary.
Fixing the issue
Traditionally, here, what you will want to do is treat FFFF - 8000 as a negative representative, to do that, you'll need to simply change the branch condition flag:
"bcc", this is Branch on Carry Clear, it is equivalent to bhs (Branch on Higher than or the Same), this however is an unsigned condition, we need a signed condition, the following branches are signed equivalences of "bcc" and "bhs":
- bge - Branch on Greater than or Equal
- bpl - Branch on PLus
Using either bge or bpl instead of bcc, will ensure that if Sonic is to move out of the screen above, it will not count as wrapping to a higher Y position, but rather dropping to a lower negative Y position.
Another optional fix
As explained, the comparison is made with the level's Y boundary position, the problem with using the lower Y boundary is that if Sonic is to die at the top of the level, it will take a short while longer for the level to fade out and reset, than if he had died at the bottom of the level. Whether this is intentional or not, doesn't reflect the fact that it is rather odd considering you do not see the character falling all the way to the bottom.
To set it so that the level resets at the same rate regardless of the position, simply changing the RAM address FFFFF72E to RAM address FFFFF704 will check the screen's position, rather than the lower boundary of the level, as shown below:
move.w ($FFFFF704).w,d0 addi.w #$100,d0 cmp.w $C(a0),d0 bge.w locret_13900
Again, this is an optional fix, as it isn't known whether dropping to the bottom of the entire level, is in fact intentional or not.