Actions

SCHG How-to

Remove the Speed Cap

From Sonic Retro

Revision as of 10:39, 18 October 2010 by Selbi (talk | contribs) (I wanted to do this a looong time before.)

(Ground speed cap fix originally by Tweaker; air speed cap fix originally by Puto)

Ground Speed Cap

Removing the speed cap requires taking a look at Sonic 2's version of Sonic_MoveLeft, and Sonic_MoveRight. First off, we should take a look at Sonic_MoveLeft (for example), and look at its code. <asm>Sonic_MoveLeft:  ; XREF: Sonic_Move move.w $14(a0),d0 beq.s loc_13086 bpl.s loc_130B2

loc_13086: bset #0,$22(a0) bne.s loc_1309A bclr #5,$22(a0) move.b #1,$1D(a0)

loc_1309A: sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_130A6 move.w d1,d0

loc_130A6: move.w d0,$14(a0) move.b #0,$1C(a0); use walking animation rts</asm> This is the section we're looking for. Now, let's look up one of the lines in here until we find a matching pattern in S2. <asm>loc_1C2A4:  ; CODE XREF: h+515C p move.w $14(a0),d0 beq.s loc_1C2AC bpl.s loc_1C2DE

loc_1C2AC:  ; CODE XREF: h+5334 j bset #0,$22(a0) bne.s loc_1C2C0 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_1C2C0:  ; CODE XREF: h+533E j sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_1C2D2 add.w d5,d0 cmp.w d1,d0 ble.s loc_1C2D2 move.w d1,d0

loc_1C2D2:  ; CODE XREF: h+5354 j h+535A j move.w d0,$14(a0) move.b #0,$1C(a0) rts</asm> Success! Now, let's compare the differences here. You'll notice S2's routine has 3 extra lines in it: <asm> add.w d5,d0 cmp.w d1,d0 ble.s loc_1C2D2</asm> So, what we want to do is add this code to Sonic 1's routine. Take these 3 lines and modify them to work with S1. You should end up with this: <asm>Sonic_MoveLeft:  ; XREF: Sonic_Move move.w $14(a0),d0 beq.s loc_13086 bpl.s loc_130B2

loc_13086: bset #0,$22(a0) bne.s loc_1309A bclr #5,$22(a0) move.b #1,$1D(a0)

loc_1309A: sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_130A6 add.w d5,d0 cmp.w d1,d0 ble.s loc_130A6 move.w d1,d0

loc_130A6: move.w d0,$14(a0) move.b #0,$1C(a0); use walking animation rts</asm> Now, we have to do the same for Sonic_MoveRight. Once again, let's find the S2 equivalent of the routine using Sonic 1's routine.

Sonic 1's: <asm>Sonic_MoveRight:  ; XREF: Sonic_Move move.w $14(a0),d0 bmi.s loc_13118 bclr #0,$22(a0) beq.s loc_13104 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_13104: add.w d5,d0 cmp.w d6,d0 blt.s loc_1310C move.w d6,d0

loc_1310C: move.w d0,$14(a0) move.b #0,$1C(a0); use walking animation rts</asm> And, with the same amount of backsearching, we can find Sonic 2's, which is the following: <asm>loc_1C32A:  ; CODE XREF: h+5168 p move.w $14(a0),d0 bmi.s loc_1C35E bclr #0,$22(a0) beq.s loc_1C344 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_1C344:  ; CODE XREF: h+53C2 j add.w d5,d0 cmp.w d6,d0 blt.s loc_1C352 sub.w d5,d0 cmp.w d6,d0 bge.s loc_1C352 move.w d6,d0

loc_1C352:  ; CODE XREF: h+53D4 j h+53DA j move.w d0,$14(a0) move.b #0,$1C(a0) rts</asm> Now, once again, you'll notice the difference between the two routines is the following lines: <asm> sub.w d5,d0 cmp.w d6,d0 bge.s loc_1C352</asm> So, once again, let's apply these changes to work with S1, providing our final, result routine for S1: <asm>Sonic_MoveRight:  ; XREF: Sonic_Move move.w $14(a0),d0 bmi.s loc_13118 bclr #0,$22(a0) beq.s loc_13104 bclr #5,$22(a0) move.b #1,$1D(a0)

loc_13104: add.w d5,d0 cmp.w d6,d0 blt.s loc_1310C sub.w d5,d0 cmp.w d6,d0 bge.s loc_1310C move.w d6,d0

loc_1310C: move.w d0,$14(a0) move.b #0,$1C(a0); use walking animation rts</asm>

And that should be it! Build your new ROM, and the infamous (ground) speed cap should be gone!

Air Speed Cap

However, that still keeps the cap in mid-air. So let's adapt that to fix the speed cap in mid-air too.

Here's the original code:

<asm>Sonic_ChgJumpDir: ; XREF: Obj01_MdJump; Obj01_MdJump2 move.w ($FFFFF760).w,d6 move.w ($FFFFF762).w,d5 asl.w #1,d5 btst #4,$22(a0) bne.s Obj01_ResetScr2 move.w $10(a0),d0 btst #2,($FFFFF602).w; is left being pressed? beq.s loc_13278; if not, branch bset #0,$22(a0) sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_13278 move.w d1,d0

loc_13278: btst #3,($FFFFF602).w; is right being pressed? beq.s Obj01_JumpMove; if not, branch bclr #0,$22(a0) add.w d5,d0 cmp.w d6,d0 blt.s Obj01_JumpMove move.w d6,d0</asm>

As you can see, it works exactly the same way as the MoveLeft/Right routines. So let's apply the same fix. After bgt.s loc_13278, add the following lines: <asm> add.w d5,d0 ; +++ remove this frame's acceleration change cmp.w d1,d0 ; +++ compare speed with top speed ble.s loc_13278 ; +++ if speed was already greater than the maximum, branch</asm>

And do a similar thing after blt.s Obj01_JumpMove: <asm> sub.w d5,d0 ; +++ remove this frame's acceleration change cmp.w d1,d0 ; +++ compare speed with top speed bge.s Obj01_JumpMove ; +++ if speed was already greater than the maximum, branch</asm>

Final result: <asm>Sonic_ChgJumpDir: ; XREF: Obj01_MdJump; Obj01_MdJump2 move.w ($FFFFF760).w,d6 move.w ($FFFFF762).w,d5 asl.w #1,d5 btst #4,$22(a0) bne.s Obj01_ResetScr2 move.w $10(a0),d0 btst #2,($FFFFF602).w; is left being pressed? beq.s loc_13278; if not, branch bset #0,$22(a0) sub.w d5,d0 move.w d6,d1 neg.w d1 cmp.w d1,d0 bgt.s loc_13278 add.w d5,d0 ; +++ remove this frame's acceleration change cmp.w d1,d0 ; +++ compare speed with top speed ble.s loc_13278 ; +++ if speed was already greater than the maximum, branch move.w d1,d0

loc_13278: btst #3,($FFFFF602).w; is right being pressed? beq.s Obj01_JumpMove; if not, branch bclr #0,$22(a0) add.w d5,d0 cmp.w d6,d0 blt.s Obj01_JumpMove sub.w d5,d0 ; +++ remove this frame's acceleration change cmp.w d1,d0 ; +++ compare speed with top speed bge.s Obj01_JumpMove ; +++ if speed was already greater than the maximum, branch move.w d6,d0</asm>