Difference between revisions of "Fix the Special Stage jumping physics"
From Sonic Retro
Scarred Sun (talk | contribs) |
Scarred Sun (talk | contribs) m (Text replacement - "</asm>" to "</syntaxhighlight>") |
||
Line 6: | Line 6: | ||
Open ''sonic1.asm'' and go to '''Obj09_InAir'''. Replace this: | Open ''sonic1.asm'' and go to '''Obj09_InAir'''. Replace this: | ||
<asm> | <asm> | ||
− | bsr.w nullsub_2</ | + | bsr.w nullsub_2</syntaxhighlight> |
With this: | With this: | ||
− | <asm> bsr.w Obj09_JumpHeight</ | + | <asm> bsr.w Obj09_JumpHeight</syntaxhighlight> |
Now, find the '''nullsub_2''' label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, '''Obj09_JumpHeight'''. So replace all this: | Now, find the '''nullsub_2''' label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, '''Obj09_JumpHeight'''. So replace all this: | ||
Line 28: | Line 28: | ||
locret_1BBB4: | locret_1BBB4: | ||
− | rts</ | + | rts</syntaxhighlight> |
With this: | With this: | ||
<asm>; =========================================================================== | <asm>; =========================================================================== | ||
Line 69: | Line 69: | ||
locret_1BBB4: | locret_1BBB4: | ||
− | rts</ | + | rts</syntaxhighlight> |
Next, go to the '''Obj09_OnWall''' label, and add this line directly after it: | Next, go to the '''Obj09_OnWall''' label, and add this line directly after it: | ||
− | <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</ | + | <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</syntaxhighlight> |
Now, go to the '''Obj09_Jump''' label, and after this line: | Now, go to the '''Obj09_Jump''' label, and after this line: | ||
− | <asm> bset #1,$22(a0)</ | + | <asm> bset #1,$22(a0)</syntaxhighlight> |
Add this one: | Add this one: | ||
− | <asm> bset #7,$22(a0) ; set "Sonic has jumped" flag</ | + | <asm> bset #7,$22(a0) ; set "Sonic has jumped" flag</syntaxhighlight> |
Finally, go to the '''Obj09_ChkBumper''' label, and after this line: | Finally, go to the '''Obj09_ChkBumper''' label, and after this line: | ||
− | <asm> bset #1,$22(a0)</ | + | <asm> bset #1,$22(a0)</syntaxhighlight> |
Add this one: | Add this one: | ||
− | <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</ | + | <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</syntaxhighlight> |
== Sonic 1 disassembly ([[Sonic Retro on GitHub|GitHub]] version) == | == Sonic 1 disassembly ([[Sonic Retro on GitHub|GitHub]] version) == | ||
Open ''_incObj\09 Sonic in Special Stage.asm'' and go to '''Obj09_InAir'''. Replace this: | Open ''_incObj\09 Sonic in Special Stage.asm'' and go to '''Obj09_InAir'''. Replace this: | ||
− | <asm> bsr.w nullsub_2</ | + | <asm> bsr.w nullsub_2</syntaxhighlight> |
With this: | With this: | ||
− | <asm> bsr.w Obj09_JumpHeight</ | + | <asm> bsr.w Obj09_JumpHeight</syntaxhighlight> |
Now, find the ''nullsub_2'' label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, ''Obj09_JumpHeight''. So replace all this: | Now, find the ''nullsub_2'' label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, ''Obj09_JumpHeight''. So replace all this: | ||
Line 108: | Line 108: | ||
locret_1BBB4: | locret_1BBB4: | ||
− | rts</ | + | rts</syntaxhighlight> |
With this: | With this: | ||
<asm>; =========================================================================== | <asm>; =========================================================================== | ||
Line 151: | Line 151: | ||
locret_1BBB4: | locret_1BBB4: | ||
− | rts</ | + | rts</syntaxhighlight> |
Next, go to the "Obj09_OnWall" label, and add this line directly after it: | Next, go to the "Obj09_OnWall" label, and add this line directly after it: | ||
− | <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</ | + | <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</syntaxhighlight> |
Now, go to the "Obj09_Jump" label, and after this line: | Now, go to the "Obj09_Jump" label, and after this line: | ||
− | <asm> bset #1,obStatus(a0)</ | + | <asm> bset #1,obStatus(a0)</syntaxhighlight> |
Add this one: | Add this one: | ||
− | <asm> bset #7,obStatus(a0) ; set "Sonic has jumped" flag</ | + | <asm> bset #7,obStatus(a0) ; set "Sonic has jumped" flag</syntaxhighlight> |
Finally, go to the "Obj09_ChkBumper" label, and after this line: | Finally, go to the "Obj09_ChkBumper" label, and after this line: | ||
− | <asm> bset #1,obStatus(a0)</ | + | <asm> bset #1,obStatus(a0)</syntaxhighlight> |
Add this one: | Add this one: | ||
− | <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</ | + | <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</syntaxhighlight> |
Revision as of 21:30, 20 December 2015
(Original guide by Mercury)
The jumping physics in the Special Stages in Sonic 1 are very unfair designed. Unlike the physics you have in the levels, where you can variable your jump height by releasing the jump button at any time, the Special Stage will always bring you to the very top of your jump height.
Hivebrain's Sonic 1 disassembly (2005)
Open sonic1.asm and go to Obj09_InAir. Replace this: <asm> bsr.w nullsub_2</syntaxhighlight> With this: <asm> bsr.w Obj09_JumpHeight</syntaxhighlight>
Now, find the nullsub_2 label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, Obj09_JumpHeight. So replace all this: <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 $12(a0),d1 ble.s locret_1BBB4 move.b ($FFFFF602).w,d0 andi.b #$70,d0 bne.s locret_1BBB4 move.w d1,$12(a0)
locret_1BBB4: rts</syntaxhighlight> With this: <asm>; ===========================================================================
- ---------------------------------------------------------------------------
- Subroutine to limit Sonic's upward vertical speed
- ---------------------------------------------------------------------------
Obj09_JumpHeight: ; XREF: Obj09_InAir move.b ($FFFFF602).w,d0 ; is the jump button up? andi.b #$70,d0 bne.s locret_1BBB4 ; if not, branch to return btst #7,$22(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 ($FFFFF780).w,d0 ; get SS angle andi.b #$FC,d0 neg.b d0 subi.b #$40,d0 jsr (CalcSine).l move.w $12(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 $10(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 ($FFFFF780).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,$10(a0) muls.w #$400,d0 asr.l #8,d0 move.w d0,$12(a0) ; set the speed to the jump release speed bclr #7,$22(a0) ; clear "Sonic has jumped" flag
locret_1BBB4: rts</syntaxhighlight>
Next, go to the Obj09_OnWall label, and add this line directly after it: <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</syntaxhighlight>
Now, go to the Obj09_Jump label, and after this line: <asm> bset #1,$22(a0)</syntaxhighlight> Add this one: <asm> bset #7,$22(a0) ; set "Sonic has jumped" flag</syntaxhighlight>
Finally, go to the Obj09_ChkBumper label, and after this line: <asm> bset #1,$22(a0)</syntaxhighlight> Add this one: <asm> bclr #7,$22(a0) ; clear "Sonic has jumped" flag</syntaxhighlight>
Sonic 1 disassembly (GitHub version)
Open _incObj\09 Sonic in Special Stage.asm and go to Obj09_InAir. Replace this: <asm> bsr.w nullsub_2</syntaxhighlight> With this: <asm> bsr.w Obj09_JumpHeight</syntaxhighlight>
Now, find the nullsub_2 label, which should be only a few lines below. This is the deprecated routine, and we need to replace it with a new one, custom one, Obj09_JumpHeight. So replace all this: <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</syntaxhighlight> With this: <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</syntaxhighlight>
Next, go to the "Obj09_OnWall" label, and add this line directly after it: <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</syntaxhighlight>
Now, go to the "Obj09_Jump" label, and after this line: <asm> bset #1,obStatus(a0)</syntaxhighlight> Add this one: <asm> bset #7,obStatus(a0) ; set "Sonic has jumped" flag</syntaxhighlight>
Finally, go to the "Obj09_ChkBumper" label, and after this line: <asm> bset #1,obStatus(a0)</syntaxhighlight> Add this one: <asm> bclr #7,obStatus(a0) ; clear "Sonic has jumped" flag</syntaxhighlight>
“ | 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 GitHub disassembly:
Here's the built rom with the fix applied. |
„ |
— Mercury |