A lot of people hate the Sonic 1 Special Stages. Watching YouTube playthroughs, you'll hear them profaned quite often.
I'm pretty good at beating them, myself, but I still hate them. Because I'm scientifically minded, I tried to figure out just why this is so.
Then it hit me - Sonic doesn't have a variable jump height. Unlike when he's in the normal zones, you can't just let go of the jump button to mitigate his upward velocity.
Having noticed this, it struck me that it was most likely the largest contributor to the hate for the Special Stages. Because you don't have as much control over Sonic as you've become accustomed to from playing the normal zones, it's frustrating and unfair. Trying to navigate through cramped paths winds up being an exercise in hitting every bumper and and reverse block through no fault of you own - Sonic just makes a full jump no matter what you do.
Well, it was clear - I had to remedy this. I looked in the disassembly, and lo! - there was an unused routine for reducing Sonic's jump height in the Special Stages. Of course, merely reactivating the routine would be far too simple a fix - there had to be more than that. After all, if it worked, why would it be deprecated in the first place?
It turns out the unused routine is the same as the one from Sonic's normal code. It's deprecated because, in the Special Stages, Sonic's in a rotating maze, where up isn't always up. The routine is simply impotent at any angle other than 0.
Well, Yuji Naka might be lazy, but I'm not - so I wrote a new routine that actually does work, at any angle.
This is what I did, and if you follow the steps, you can, too. This is for the SVN disassembly:
First, open "_incObj\09 Sonic in Special Stage.asm" and find the label "Obj09_InAir". Replace this line:
with this one:
Now, find the "nullsub_2" label. This is the deprecated routine, and we need to replace it with the new one I wrote, "Obj09_JumpHeight". So replace these lines:
with these:
Next, go to the "Obj09_OnWall" label, and add this line directly after it:
Now, go to the "Obj09_Jump" label, and after this line:
add this one:
Finally, go to the "Obj09_ChkBumper" label, and after this line:
add this one:
Et voilà! Basically, what it does is it combines the X and Y speed using cos and sin to find how fast he's moving upward at the current angle. It compares this combined speed with the jump release speed ($400) and if it's greater, then it uses similar code to the normal jump to make Sonic move at $400 in the current angle. Simple.
When my friend (who's always been bad at the Sonic 1 Special Stages by her own admission, and hasn't played them in years) tested it out, she got the Chaos Emerald on her first try!
Yuji Naka has had to put up with a lot of shit in his time (not least of which the schoolyard bullies who taunted him in his youth for having a name that sounds for all the world like "huge knocker"), and now it's my turn to rub it in his face:
PWN, Yuji Naka!
The false bravado in this post is for humorous purposes only. I actually admire Yuji Naka a lot, and I'm sure he could improve my code greatly after but a brief glance at it.
So, let me know what you think of this, or if you find any bugs.
Here's the built rom with the fix applied.
I'm pretty good at beating them, myself, but I still hate them. Because I'm scientifically minded, I tried to figure out just why this is so.
Then it hit me - Sonic doesn't have a variable jump height. Unlike when he's in the normal zones, you can't just let go of the jump button to mitigate his upward velocity.
Having noticed this, it struck me that it was most likely the largest contributor to the hate for the Special Stages. Because you don't have as much control over Sonic as you've become accustomed to from playing the normal zones, it's frustrating and unfair. Trying to navigate through cramped paths winds up being an exercise in hitting every bumper and and reverse block through no fault of you own - Sonic just makes a full jump no matter what you do.
Well, it was clear - I had to remedy this. I looked in the disassembly, and lo! - there was an unused routine for reducing Sonic's jump height in the Special Stages. Of course, merely reactivating the routine would be far too simple a fix - there had to be more than that. After all, if it worked, why would it be deprecated in the first place?
It turns out the unused routine is the same as the one from Sonic's normal code. It's deprecated because, in the Special Stages, Sonic's in a rotating maze, where up isn't always up. The routine is simply impotent at any angle other than 0.
Well, Yuji Naka might be lazy, but I'm not - so I wrote a new routine that actually does work, at any angle.
This is what I did, and if you follow the steps, you can, too. This is for the SVN disassembly:
First, open "_incObj\09 Sonic in Special Stage.asm" and find the label "Obj09_InAir". Replace this line:
Syntax Highlighted Code: ASM
bsr.w nullsub_2
with this one:
Syntax Highlighted Code: ASM
bsr.w Obj09_JumpHeight
Now, find the "nullsub_2" label. This is the deprecated routine, and we need to replace it with the new one I wrote, "Obj09_JumpHeight". So replace these lines:
Syntax Highlighted Code: ASM
nullsub_2: ; XREF: Obj09_InAir
rts
; End of function nullsub_2
; ===========================================================================
; ---------------------------------------------------------------------------
; unused subroutine to limit Sonic's upward vertical speed
; ---------------------------------------------------------------------------
move.w #-$400,d1
cmp.w obVelY(a0),d1
ble.s locret_1BBB4
move.b (v_jpadhold2).w,d0
andi.b #btnABC,d0
bne.s locret_1BBB4
move.w d1,obVelY(a0)
locret_1BBB4:
rts
with these:
Syntax Highlighted Code: ASM
; ---------------------------------------------------------------------------
; Subroutine to limit Sonic's upward vertical speed
; ---------------------------------------------------------------------------
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
Obj09_JumpHeight: ; XREF: Obj09_InAir
move.b (v_jpadhold2).w,d0 ; is the jump button up?
andi.b #btnABC,d0
bne.s locret_1BBB4 ; if not, branch to return
btst #7,obStatus(a0) ; did Sonic jump or is he just falling or hit by a bumper?
beq.s locret_1BBB4 ; if not, branch to return
move.b (v_ssangle).w,d0 ; get SS angle
andi.b #$FC,d0
neg.b d0
subi.b #$40,d0
jsr (CalcSine).l
move.w obVelY(a0),d2 ; get Y speed
muls.w d2,d0 ; multiply Y speed by sin
asr.l #8,d0 ; find the new Y speed
move.w obVelX(a0),d2 ; get X speed
muls.w d2,d1 ; multiply X speed by cos
asr.l #8,d1 ; find the new X speed
add.w d0,d1 ; combine the two speeds
cmpi.w #$400,d1 ; compare the combined speed with the jump release speed
ble.s locret_1BBB4 ; if it's less, branch to return
move.b (v_ssangle).w,d0
andi.b #$FC,d0
neg.b d0
subi.b #$40,d0
jsr (CalcSine).l
muls.w #$400,d1
asr.l #8,d1
move.w d1,obVelX(a0)
muls.w #$400,d0
asr.l #8,d0
move.w d0,obVelY(a0) ; set the speed to the jump release speed
bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag
locret_1BBB4:
rts
Next, go to the "Obj09_OnWall" label, and add this line directly after it:
Syntax Highlighted Code: ASM
bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag
Now, go to the "Obj09_Jump" label, and after this line:
Syntax Highlighted Code: ASM
bset #1,obStatus(a0)
add this one:
Syntax Highlighted Code: ASM
bset #7,obStatus(a0) ; set "Sonic has jumped" flag
Finally, go to the "Obj09_ChkBumper" label, and after this line:
Syntax Highlighted Code: ASM
bset #1,obStatus(a0)
add this one:
Syntax Highlighted Code: ASM
bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag
Et voilà! Basically, what it does is it combines the X and Y speed using cos and sin to find how fast he's moving upward at the current angle. It compares this combined speed with the jump release speed ($400) and if it's greater, then it uses similar code to the normal jump to make Sonic move at $400 in the current angle. Simple.
When my friend (who's always been bad at the Sonic 1 Special Stages by her own admission, and hasn't played them in years) tested it out, she got the Chaos Emerald on her first try!
Yuji Naka has had to put up with a lot of shit in his time (not least of which the schoolyard bullies who taunted him in his youth for having a name that sounds for all the world like "huge knocker"), and now it's my turn to rub it in his face:
PWN, Yuji Naka!
The false bravado in this post is for humorous purposes only. I actually admire Yuji Naka a lot, and I'm sure he could improve my code greatly after but a brief glance at it.
So, let me know what you think of this, or if you find any bugs.
Here's the built rom with the fix applied.


