Actions

SCHG How-to

Difference between revisions of "Fix bugs relating to Super Sonic"

From Sonic Retro

(Created page with "{{GuideBy|MoDule}} Super Sonic from ''Sonic 2'' comes with quite a few bugs, some minor, while others [[Sonic_the_Hedgehog_2_%2816-bit%29_bug_lā€¦")
 
(added a few more bugs)
Line 29: Line 29:
  
 
===The bug explained===
 
===The bug explained===
āˆ’
the main offender is this line in the above routine.
+
The main offender is this line in the above routine.
 
<asm> move.b #$81,obj_control(a0) ; lock Sonic in place
 
<asm> move.b #$81,obj_control(a0) ; lock Sonic in place
 
</asm>
 
</asm>
Line 67: Line 67:
 
</asm>
 
</asm>
 
What's happening is that first Sonic jumps and starts the transformation sequence. This stops his movement. Then, since the timer has stopped, his palette cycle is set to fade out, but since it hasn't finished fading in, Sonic's movement is never restored. Thus he just hangs there forever.
 
What's happening is that first Sonic jumps and starts the transformation sequence. This stops his movement. Then, since the timer has stopped, his palette cycle is set to fade out, but since it hasn't finished fading in, Sonic's movement is never restored. Thus he just hangs there forever.
 +
 +
==Ring countdown too slow==
 +
The counter that keeps track of when to subtract a ring while super counts for 61 frames instead of 60 as seen explained [[Sonic_the_Hedgehog_2_(16-bit)_bug_list#Super_Sonic_countdown|here]].
 +
 +
===Fixing the bug===
 +
Locate the '''Sonic_Super''' routine. It should look like this:
 +
<asm>; loc_1ABA6:
 +
Sonic_Super:
 +
tst.b (Super_Sonic_flag).w ; Ignore all this code if not Super Sonic
 +
beq.w return_1AC3C
 +
tst.b (Update_HUD_timer).w ; has level ended?
 +
beq.s Sonic_RevertToNormal ; if yes, branch
 +
subq.w #1,(Super_Sonic_frame_count).w
 +
bpl.w return_1AC3C ; <--
 +
move.w #60,(Super_Sonic_frame_count).w ; <-- Reset frame counter to 60
 +
 +
[...]
 +
</asm>
 +
Here '''either''' change the ''bpl'' to a ''bhi'' '''or''' the ''60'' to a ''59''.
 +
 +
===The bug explained===
 +
The branch condition used allows for a range of 0 to 60, which is 61 elements long, thus the timer runs for 61 frames, instead of the intended 60.
 +
 +
==Transforming twice in the same level==
 +
If during the same level and on the same life Sonic reverts and transforms a second time his transformation sequence will be wrong. He won't be suspended in mid air long enough and his palette cycle will show one incorrect color.
 +
 +
===Fixing the bug===
 +
Locate the label '''PalCycle_SuperSonic_revert'''. The code should look like this:
 +
<asm>; loc_2188:
 +
PalCycle_SuperSonic_revert: ; runs the fade in transition backwards
 +
; run frame timer
 +
subq.b #1,(Palette_timer).w
 +
bpl.s - ; rts
 +
move.b #3,(Palette_timer).w
 +
 +
; decrement palette frame and update Sonic's palette
 +
lea (CyclingPal_SSTransformation).l,a0
 +
move.w (Palette_frame).w,d0
 +
subq.w #8,(Palette_frame).w ; previous frame
 +
bcc.s + ; branch, if it isn't the first frame
 +
move.b #0,(Palette_frame).w ; <--
 +
move.b #0,(Super_Sonic_palette).w ; stop palette cycle
 +
+
 +
lea (Normal_palette+4).w,a1
 +
move.l (a0,d0.w),(a1)+
 +
move.l 4(a0,d0.w),(a1)
 +
</asm>
 +
Change the ''move.b'' at the indicated line to ''move.w''. That's it.
 +
 +
===The bug explained===
 +
The palette cycle frame counter is reset incorrectly. Due to the way the routine handles the counter, on the last iteration it turns negative. The code attempts to fix this, but it does it wrong. Since only the first byte of the word length counter is set to zero, the next time it's read the game will get a wrong palette index that's far too high, accounting for both the wrong palette and the missing movement lock.

Revision as of 17:49, 15 May 2011

(Original guide by MoDule)

Super Sonic from Sonic 2 comes with quite a few bugs, some minor, while others can render the game unbeatable. This guide will show how to fix some of them.

Stuck at the end of a level

At the end of a level, after reverting back to normal, if Sonic jumps he will trigger his transformation again and get stuck in the air. A full description of the bug can be found here.

Fixing the bug

Locate the Sonic_CheckGoSuper routine and add the following two lines at the beginning: <asm> tst.b (Update_HUD_timer).w ; has Sonic reached the end of the act? beq.s return_1ABA4 ; if yes, branch </asm> The code should now look something like this: <asm>; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||

loc_1AB38
test_set_SS:

Sonic_CheckGoSuper: tst.b (Update_HUD_timer).w ; has Sonic reached the end of the act? beq.s return_1ABA4 ; if yes, branch

tst.b (Super_Sonic_flag).w ; is Sonic already Super? bne.s return_1ABA4 ; if yes, branch cmpi.b #7,(Emerald_count).w ; does Sonic have exactly 7 emeralds? bne.s return_1ABA4 ; if not, branch cmpi.w #50,(Ring_count).w ; does Sonic have at least 50 rings? blo.s return_1ABA4 ; if not, branch </asm> All this does is skip Sonic's transformation check if the level timer has stopped, which happens at the end of a level.

The bug explained

The main offender is this line in the above routine. <asm> move.b #$81,obj_control(a0) ; lock Sonic in place </asm> What this does is stop Sonic's movement completely for the duration of his transformation sequence. This isn't usually a problem, because his movement is restored once the transformation is done. The other part of the problem comes from here: <asm>; loc_1ABA6: Sonic_Super: tst.b (Super_Sonic_flag).w ; Ignore all this code if not Super Sonic beq.w return_1AC3C tst.b (Update_HUD_timer).w ; has level ended? beq.s Sonic_RevertToNormal ; <-- if yes, branch

;[...]

Sonic_RevertToNormal: move.b #2,(Super_Sonic_palette).w ; <-- remove rotating palette

;[...] </asm> and here: <asm>; sub_213E: PalCycle_SuperSonic: move.b (Super_Sonic_palette).w,d0 beq.s ++ ; rts ; return, if Sonic isn't super bmi.w PalCycle_SuperSonic_normal ; branch, if fade-in is done subq.b #1,d0 bne.s PalCycle_SuperSonic_revert ; <-- branch for values greater than 1

;[...]

move.b #-1,(Super_Sonic_palette).w ; mark fade-in as done move.b #0,(MainCharacter+obj_control).w ; <-- restore Sonic's movement

;[...]

loc_2188

PalCycle_SuperSonic_revert: ; runs the fade in transition backwards </asm> What's happening is that first Sonic jumps and starts the transformation sequence. This stops his movement. Then, since the timer has stopped, his palette cycle is set to fade out, but since it hasn't finished fading in, Sonic's movement is never restored. Thus he just hangs there forever.

Ring countdown too slow

The counter that keeps track of when to subtract a ring while super counts for 61 frames instead of 60 as seen explained here.

Fixing the bug

Locate the Sonic_Super routine. It should look like this: <asm>; loc_1ABA6: Sonic_Super: tst.b (Super_Sonic_flag).w ; Ignore all this code if not Super Sonic beq.w return_1AC3C tst.b (Update_HUD_timer).w ; has level ended? beq.s Sonic_RevertToNormal ; if yes, branch subq.w #1,(Super_Sonic_frame_count).w bpl.w return_1AC3C ; <-- move.w #60,(Super_Sonic_frame_count).w ; <-- Reset frame counter to 60

[...] </asm> Here either change the bpl to a bhi or the 60 to a 59.

The bug explained

The branch condition used allows for a range of 0 to 60, which is 61 elements long, thus the timer runs for 61 frames, instead of the intended 60.

Transforming twice in the same level

If during the same level and on the same life Sonic reverts and transforms a second time his transformation sequence will be wrong. He won't be suspended in mid air long enough and his palette cycle will show one incorrect color.

Fixing the bug

Locate the label PalCycle_SuperSonic_revert. The code should look like this: <asm>; loc_2188: PalCycle_SuperSonic_revert: ; runs the fade in transition backwards ; run frame timer subq.b #1,(Palette_timer).w bpl.s - ; rts move.b #3,(Palette_timer).w

; decrement palette frame and update Sonic's palette lea (CyclingPal_SSTransformation).l,a0 move.w (Palette_frame).w,d0 subq.w #8,(Palette_frame).w ; previous frame bcc.s + ; branch, if it isn't the first frame move.b #0,(Palette_frame).w ; <-- move.b #0,(Super_Sonic_palette).w ; stop palette cycle + lea (Normal_palette+4).w,a1 move.l (a0,d0.w),(a1)+ move.l 4(a0,d0.w),(a1) </asm> Change the move.b at the indicated line to move.w. That's it.

The bug explained

The palette cycle frame counter is reset incorrectly. Due to the way the routine handles the counter, on the last iteration it turns negative. The code attempts to fix this, but it does it wrong. Since only the first byte of the word length counter is set to zero, the next time it's read the game will get a wrong palette index that's far too high, accounting for both the wrong palette and the missing movement lock.