Difference between revisions of "Fix Accidental Deletion of Scattered Rings"
From Sonic Retro
m (Replaced spaces with tabs in code, fixed typos, added missing images) |
|||
Line 1: | Line 1: | ||
− | + | {{GuideBy|redhotsonic}} | |
=The Problem= | =The Problem= | ||
− | + | There is a glitch within the scattered rings. Let me explain. In the scattered rings code, there is a check to see if rings have reached the bottom of the level and if so, to delete themselves. Here is some code from Sonic 2's scattered rings object. | |
<asm> | <asm> | ||
Line 18: | Line 18: | ||
Easy example: Sonic 2's [[Metropolis Zone]], Act 2. | Easy example: Sonic 2's [[Metropolis Zone]], Act 2. | ||
− | |||
− | NOTE: This bug is also present in Sonic | + | |
+ | [[File:FixDeletionOfScatteredRings_Image1.png]] | ||
+ | |||
+ | If you go to these co-ordinates in MTZ2, you will see Asteron (starfish badnik) to the right. Go to him and let him hurt you. | ||
+ | |||
+ | |||
+ | |||
+ | [[File:FixDeletionOfScatteredRings_Image2.png]] | ||
+ | |||
+ | I've just got hurt, look at all the rings that are about to scatter. But, the bottom line of the level is right above me. | ||
+ | |||
+ | |||
+ | |||
+ | [[File:FixDeletionOfScatteredRings_Image3.png]] | ||
+ | |||
+ | Look at that! Most of my rings have suddenly vanished! To help, I've drawn a red line. That's the line where if the rings reach, to delete themselves. The rings think that that line is the bottom of the level, but because this level is y-wrapped, technically, there is no "bottom of level". So we still want the rings to be there so we can collect them. | ||
+ | |||
+ | |||
+ | |||
+ | NOTE: This bug is also present in Sonic 1 & 3K, but it is quite hard to pull the glitch off. Generally because the only time you're passing the y-wrap in S1 and S3K, is when you're in the water slide in LZ Act 3, or in the ice tunnel in ICZ Act 1. | ||
But if you're editing these level layouts to cross the y-wrap quite often, the glitch may become more apparent. And you might want to fix it. Therefore, we will cover fixing this for ALL 3 games! Lets start with Sonic 1, and work our way forward... | But if you're editing these level layouts to cross the y-wrap quite often, the glitch may become more apparent. And you might want to fix it. Therefore, we will cover fixing this for ALL 3 games! Lets start with Sonic 1, and work our way forward... | ||
Line 31: | Line 49: | ||
Go to "@chkdel:" and you'll see this: | Go to "@chkdel:" and you'll see this: | ||
<asm> | <asm> | ||
− | + | @chkdel: | |
− | + | tst.b (v_ani3_time).w | |
− | + | beq.s RLoss_Delete | |
− | + | move.w (v_limitbtm2).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w obY(a0),d0 ; has object moved below level boundary? | |
− | + | bcs.s RLoss_Delete ; if yes, branch | |
− | + | bra.w DisplaySprite | |
</asm> | </asm> | ||
− | Right after the | + | Right after the first branch to "RLoss_Delete", insert this: |
<asm> | <asm> | ||
− | + | cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? | |
− | + | beq.w DisplaySprite ; if so, branch | |
</asm> | </asm> | ||
So, you have something like this: | So, you have something like this: | ||
<asm> | <asm> | ||
− | + | @chkdel: | |
− | + | tst.b (v_ani3_time).w | |
− | + | beq.s RLoss_Delete | |
− | + | cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? | |
− | + | beq.w DisplaySprite ; if so, branch | |
− | + | move.w (v_limitbtm2).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w obY(a0),d0 ; has object moved below level boundary? | |
− | + | bcs.s RLoss_Delete ; if yes, branch | |
− | + | bra.w DisplaySprite | |
</asm> | </asm> | ||
Line 65: | Line 83: | ||
Go to "Obj37_ChkDel:" and you'll see this: | Go to "Obj37_ChkDel:" and you'll see this: | ||
<asm> | <asm> | ||
− | + | Obj37_ChkDel: ; XREF: Obj37_Bounce | |
tst.b ($FFFFFEC6).w | tst.b ($FFFFFEC6).w | ||
beq.s Obj37_Delete | beq.s Obj37_Delete | ||
Line 75: | Line 93: | ||
</asm> | </asm> | ||
− | Right after the | + | Right after the first branch to "Obj37_Delete", insert this: |
<asm> | <asm> | ||
− | + | cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? | |
− | + | beq.w DisplaySprite ; if so, branch | |
</asm> | </asm> | ||
So, you have something like this: | So, you have something like this: | ||
<asm> | <asm> | ||
− | + | Obj37_ChkDel: ; XREF: Obj37_Bounce | |
tst.b ($FFFFFEC6).w | tst.b ($FFFFFEC6).w | ||
beq.s Obj37_Delete | beq.s Obj37_Delete | ||
− | + | cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? | |
− | beq.w | + | beq.w DisplaySprite ; if so, branch |
move.w ($FFFFF72E).w,d0 | move.w ($FFFFF72E).w,d0 | ||
addi.w #$E0,d0 | addi.w #$E0,d0 | ||
Line 101: | Line 119: | ||
<asm> | <asm> | ||
loc_121B8: | loc_121B8: | ||
− | + | tst.b (Ring_spill_anim_counter).w | |
− | + | beq.s BranchTo5_DeleteObject | |
− | + | move.w (Camera_Max_Y_pos_now).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w y_pos(a0),d0 | |
− | + | bcs.s BranchTo5_DeleteObject | |
− | + | bra.w DisplaySprite | |
</asm> | </asm> | ||
− | Right after the | + | Right after the first branch to "BranchTo5_DeleteObject", insert this: |
<asm> | <asm> | ||
− | + | cmpi.w #$FF00,($FFFFEECC).w ; is vertical wrapping enabled? | |
− | + | beq.w DisplaySprite ; if so, branch | |
</asm> | </asm> | ||
Line 119: | Line 137: | ||
<asm> | <asm> | ||
loc_121B8: | loc_121B8: | ||
− | + | tst.b (Ring_spill_anim_counter).w | |
− | + | beq.s BranchTo5_DeleteObject | |
− | + | cmpi.w #$FF00,($FFFFEECC).w ; is vertical wrapping enabled? | |
− | + | beq.w DisplaySprite ; if so, branch | |
− | + | move.w (Camera_Max_Y_pos_now).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w y_pos(a0),d0 | |
− | + | bcs.s BranchTo5_DeleteObject | |
− | + | bra.w DisplaySprite | |
</asm> | </asm> | ||
Line 136: | Line 154: | ||
<asm> | <asm> | ||
loc_1A79C: | loc_1A79C: | ||
− | + | tst.b (Ring_spill_anim_counter).w | |
− | + | beq.s loc_1A7E4 | |
− | + | move.w (Camera_max_Y_pos).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w $14(a0),d0 | |
− | + | bcs.s loc_1A7E4 | |
</asm> | </asm> | ||
− | Right after the | + | Right after the first branch to "loc_1A7E4", insert this: |
<asm> | <asm> | ||
− | + | cmpi.w #$FF00,($FFFFEE18).w ; is vertical wrapping enabled? | |
− | + | beq.w loc_1A7B0 ; if so, branch | |
</asm> | </asm> | ||
Line 153: | Line 171: | ||
<asm> | <asm> | ||
loc_1A79C: | loc_1A79C: | ||
− | + | tst.b (Ring_spill_anim_counter).w | |
− | + | beq.s loc_1A7E4 | |
− | + | cmpi.w #$FF00,($FFFFEE18).w ; is vertical wrapping enabled? | |
− | + | beq.w loc_1A7B0 ; if so, branch | |
− | + | move.w (Camera_max_Y_pos).w,d0 | |
− | + | addi.w #$E0,d0 | |
− | + | cmp.w $14(a0),d0 | |
− | + | bcs.s loc_1A7E4 | |
</asm> | </asm> | ||
Revision as of 11:56, 13 September 2014
(Original guide by redhotsonic)
Contents
The Problem
There is a glitch within the scattered rings. Let me explain. In the scattered rings code, there is a check to see if rings have reached the bottom of the level and if so, to delete themselves. Here is some code from Sonic 2's scattered rings object.
<asm> loc_121B8:
tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject move.w (Camera_Max_Y_pos_now).w,d0 ; HERE addi.w #$E0,d0 ; HERE cmp.w y_pos(a0),d0 ; HERE bcs.s BranchTo5_DeleteObject ; HERE bra.w DisplaySprite
</asm>
It has this code because when rings reach to the bottom of the level, they delete themselves, so they do not spawn at the top of the level (they won't loop). This is a good thing, as we don't want rings looping, right? But there is an issue with levels that are y-wrapped enabled. Easy example: Sonic 2's Metropolis Zone, Act 2.
If you go to these co-ordinates in MTZ2, you will see Asteron (starfish badnik) to the right. Go to him and let him hurt you.
I've just got hurt, look at all the rings that are about to scatter. But, the bottom line of the level is right above me.
Look at that! Most of my rings have suddenly vanished! To help, I've drawn a red line. That's the line where if the rings reach, to delete themselves. The rings think that that line is the bottom of the level, but because this level is y-wrapped, technically, there is no "bottom of level". So we still want the rings to be there so we can collect them.
NOTE: This bug is also present in Sonic 1 & 3K, but it is quite hard to pull the glitch off. Generally because the only time you're passing the y-wrap in S1 and S3K, is when you're in the water slide in LZ Act 3, or in the ice tunnel in ICZ Act 1.
But if you're editing these level layouts to cross the y-wrap quite often, the glitch may become more apparent. And you might want to fix it. Therefore, we will cover fixing this for ALL 3 games! Lets start with Sonic 1, and work our way forward...
The Fix
NOTE: The fix I have added, I've not equated. That way, the fix is compatible with any disassembly you are using. I've told what disassembly for which game I'm going by, but if you're using any other disassembly, you can still use my fix. Credit to Berserker6 for adding the Hivebrain 2005 instructions.
Sonic 1 fix- SVN
Go to "@chkdel:" and you'll see this: <asm> @chkdel: tst.b (v_ani3_time).w beq.s RLoss_Delete move.w (v_limitbtm2).w,d0 addi.w #$E0,d0 cmp.w obY(a0),d0 ; has object moved below level boundary? bcs.s RLoss_Delete ; if yes, branch bra.w DisplaySprite </asm>
Right after the first branch to "RLoss_Delete", insert this: <asm> cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch </asm>
So, you have something like this: <asm> @chkdel: tst.b (v_ani3_time).w beq.s RLoss_Delete cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch move.w (v_limitbtm2).w,d0 addi.w #$E0,d0 cmp.w obY(a0),d0 ; has object moved below level boundary? bcs.s RLoss_Delete ; if yes, branch bra.w DisplaySprite </asm>
Sonic 1 fix- Hivebrain's 2005 Disassembly
Go to "Obj37_ChkDel:" and you'll see this: <asm> Obj37_ChkDel: ; XREF: Obj37_Bounce tst.b ($FFFFFEC6).w beq.s Obj37_Delete move.w ($FFFFF72E).w,d0 addi.w #$E0,d0 cmp.w $C(a0),d0 ; has object moved below level boundary? bcs.s Obj37_Delete ; if yes, branch bra.w DisplaySprite </asm>
Right after the first branch to "Obj37_Delete", insert this: <asm> cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch </asm>
So, you have something like this: <asm> Obj37_ChkDel: ; XREF: Obj37_Bounce tst.b ($FFFFFEC6).w beq.s Obj37_Delete cmpi.w #$FF00,($FFFFF72C).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch move.w ($FFFFF72E).w,d0 addi.w #$E0,d0 cmp.w $C(a0),d0 ; has object moved below level boundary? bcs.s Obj37_Delete ; if yes, branch bra.w DisplaySprite </asm>
Sonic 2 fix
This guide uses Xenowhirl's 2007 disassembly.
Go to "loc_121B8:" and you'll see this: <asm> loc_121B8: tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject move.w (Camera_Max_Y_pos_now).w,d0 addi.w #$E0,d0 cmp.w y_pos(a0),d0 bcs.s BranchTo5_DeleteObject bra.w DisplaySprite </asm>
Right after the first branch to "BranchTo5_DeleteObject", insert this: <asm> cmpi.w #$FF00,($FFFFEECC).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch </asm>
So, you have something like this: <asm> loc_121B8: tst.b (Ring_spill_anim_counter).w beq.s BranchTo5_DeleteObject cmpi.w #$FF00,($FFFFEECC).w ; is vertical wrapping enabled? beq.w DisplaySprite ; if so, branch move.w (Camera_Max_Y_pos_now).w,d0 addi.w #$E0,d0 cmp.w y_pos(a0),d0 bcs.s BranchTo5_DeleteObject bra.w DisplaySprite </asm>
Sonic 3K fix
This guide uses the SVN disassembly.
Go to "loc_1A79C" and you'll see this: <asm> loc_1A79C: tst.b (Ring_spill_anim_counter).w beq.s loc_1A7E4 move.w (Camera_max_Y_pos).w,d0 addi.w #$E0,d0 cmp.w $14(a0),d0 bcs.s loc_1A7E4 </asm>
Right after the first branch to "loc_1A7E4", insert this: <asm> cmpi.w #$FF00,($FFFFEE18).w ; is vertical wrapping enabled? beq.w loc_1A7B0 ; if so, branch </asm>
So, you have something like this: <asm> loc_1A79C: tst.b (Ring_spill_anim_counter).w beq.s loc_1A7E4 cmpi.w #$FF00,($FFFFEE18).w ; is vertical wrapping enabled? beq.w loc_1A7B0 ; if so, branch move.w (Camera_max_Y_pos).w,d0 addi.w #$E0,d0 cmp.w $14(a0),d0 bcs.s loc_1A7E4 </asm>
The bug explained
Basically, whenever rings fall to the bottom of the level, they delete themselves to stop from looping and coming from the top of the screen (like Sonic does on y-wrapped levels). But with levels with y-wrap enabled, the rings would still delete themselves when they reached those same co-ordinates. In the pictures provided as examples (In the OP), those rings reached the co-ordinates and deleted themselves, which we don't want theoretically, there is no bottom of level and you want your rings back!
So, all we've done here to all 3 games, is if y-wrap is enabled, do not delete the rings if they've reached the co-ordinates. Only if y-wrap is disabled, will the game delete the rings once they've reached the bottom of the level.
The rings itself will still delete themselves after a certain amount of time, so, you do not need to worry about them being around forever if y-wrap is enabled.