|
|
SCHG How-to:Fix Scattered Rings Underwater Physics(Difference between revisions)
From Sonic Retro
Revision as of 01:34, 7 August 2012(Original Guide for all 3 games written by redhotsonic.) Quote from redhotsonic, - "Ah, the scattered rings when you get hurt. It can cause slowdown to your game, and even mess up the underwater palette. Now, when Sonic is underwater, his movement and his gravity is changed so he moves slower to act like he's in water. But when he is hurt under water, isn't it funny that the scattered rings still act the same as if you weren't in water?" This is something that occurs in all 3 Sonic the Hedgehog Mega Drive games (and by 3, that IS counting S3&K as one game, though S&K has no water anyway, so it wouldn't be included regardless... but I digress). But is it really a bug? or is it merely a design choice? In either case, it's something that could stand to be fixed, and this guide tells you how to fix the ring physics in all of the games. First off... let's start with the original...
Sonic 1 fixThis guide uses the SVN disassembly. First, In your disassembly, go to "_incObj\25 & 37 Rings.asm" Go to @makerings: (part of the scattered rings object code) and find this bit of coding:
bsr.w CalcSine
move.w d4,d2
lsr.w #8,d2
Just underneath, paste this:
tst.b ($FFFFF64C).w ; Does the level have water?
beq.s @skiphalvingvel ; If not, branch and skip underwater checks
move.w ($FFFFF646).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
@skiphalvingvel:
'You should end up with something looking like this:'
@makerings:
move.b #id_RingLoss,0(a1) ; load bouncing ring object
addq.b #2,obRoutine(a1)
move.b #8,obHeight(a1)
move.b #8,obWidth(a1)
move.w obX(a0),obX(a1)
move.w obY(a0),obY(a1)
move.l #Map_Ring,obMap(a1)
move.w #$27B2,obGfx(a1)
move.b #4,obRender(a1)
move.b #3,obPriority(a1)
move.b #$47,obColType(a1)
move.b #8,obActWid(a1)
move.b #-1,(v_ani3_time).w
tst.w d4
bmi.s @loc_9D62
move.w d4,d0
bsr.w CalcSine
move.w d4,d2
lsr.w #8,d2
tst.b ($FFFFF64C).w ; Does the level have water?
beq.s @skiphalvingvel ; If not, branch and skip underwater checks
move.w ($FFFFF646).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
@skiphalvingvel:
asl.w d2,d0
asl.w d2,d1
move.w d0,d2
move.w d1,d3
addi.b #$10,d4
bcc.s @loc_9D62
subi.w #$80,d4
bcc.s @loc_9D62
move.w #$288,d4
This ensures that when underwater, the rings x_vel and y_vel are halved so they appear to be moving slower. Next, go to label "RLoss_Bounce:" and under
move.b (v_ani3_frame).w,obFrame(a0)
bsr.w SpeedToPos
addi.w #$18,obVelY(a0)
place this:
tst.b ($FFFFF64C).w ; Does the level have water?
beq.s @skipbounceslow ; If not, branch and skip underwater checks
move.w ($FFFFF646).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skipbounceslow ; If not, branch and skip underwater commands
subi.w #$E,obVelY(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
@skipbounceslow:
You can change the value of the gravity if you like, but I found $E to suit. Anyway, you should have something looking like this: RLoss_Bounce: ; Routine 2 move.b (v_ani3_frame).w,obFrame(a0) bsr.w SpeedToPos addi.w #$18,obVelY(a0) tst.b ($FFFFF64C).w ; Does the level have water? beq.s @skipbounceslow ; If not, branch and skip underwater checks move.w ($FFFFF646).w,d6 ; Move water level to d6 cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level? bgt.s @skipbounceslow ; If not, branch and skip underwater commands subi.w #$E,obVelY(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect @skipbounceslow: bmi.s @chkdel move.b (v_vbla_byte).w,d0 add.b d7,d0 andi.b #3,d0 bne.s @chkdel jsr ObjFloorDist tst.w d1 bpl.s @chkdel add.w d1,obY(a0) move.w obVelY(a0),d0 asr.w #2,d0 sub.w d0,obVelY(a0) neg.w obVelY(a0) This ensures when underwater, the gravity is not as great. Otherwise, the rings will gain speed and then it won't give the desired underwater effect.
Sonic 2 fixThis guide uses the Xenowhirl disassembly. See below for the SVN fix. First, go to "loc_120BA:" (part of the scattered rings object code) and find this bit of coding: bsr.w JmpTo4_CalcSine move.w d4,d2 lsr.w #8,d2
tst.b (Water_flag).w ; Does the level have water?
beq.s + ; If not, branch and skip underwater checks
move.w (Water_Level_2).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s + ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
+
So, you should end up with something looking like this:
loc_120BA:
_move.b #$37,0(a1) ; load obj37
addq.b #2,routine(a1)
move.b #8,y_radius(a1)
move.b #8,x_radius(a1)
move.w x_pos(a0),x_pos(a1)
move.w y_pos(a0),y_pos(a1)
move.l #Obj25_MapUnc_12382,mappings(a1)
move.w #$26BC,art_tile(a1)
bsr.w Adjust2PArtPointer2
move.b #$84,render_flags(a1)
move.b #3,priority(a1)
move.b #$47,collision_flags(a1)
move.b #8,width_pixels(a1)
move.b #-1,(Ring_spill_anim_counter).w
tst.w d4
bmi.s loc_12132
move.w d4,d0
bsr.w JmpTo4_CalcSine
move.w d4,d2
lsr.w #8,d2
tst.b (Water_flag).w ; Does the level have water?
beq.s + ; If not, branch and skip underwater checks
move.w (Water_Level_2).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s + ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
+
asl.w d2,d0
asl.w d2,d1
move.w d0,d2
move.w d1,d3
addi.b #$10,d4
bcc.s loc_12132
subi.w #$80,d4
bcc.s loc_12132
move.w #$288,d4
This ensures that when underwater, the rings x_vel and y_vel are halved so they appear to be moving slower.
move.b (Ring_spill_anim_frame).w,mapping_frame(a0)
bsr.w ObjectMove
addi.w #$18,y_vel(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s + ; If not, branch and skip underwater checks
move.w (Water_Level_2).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s + ; If not, branch and skip underwater commands
subi.w #$E,y_vel(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect for the rings
+
You can change the value of the gravity if you like, but I found $E to suit. Anyway, you should have something looking like this:
Obj_37_sub_2:
move.b (Ring_spill_anim_frame).w,mapping_frame(a0)
bsr.w ObjectMove
addi.w #$18,y_vel(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s + ; If not, branch and skip underwater checks
move.w (Water_Level_2).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s + ; If not, branch and skip underwater commands
subi.w #$E,y_vel(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect for the rings
+
bmi.s loc_121B8
move.b ($FFFFFE0F).w,d0
add.b d7,d0
andi.b #7,d0
bne.s loc_121B8
tst.b render_flags(a0)
bpl.s loc_121D0
jsr (RingCheckFloorDist).l
tst.w d1
bpl.s loc_121B8
add.w d1,y_pos(a0)
move.w y_vel(a0),d0
asr.w #2,d0
sub.w d0,y_vel(a0)
neg.w y_vel(a0)
This ensures when underwater, the gravity is not as great. Otherwise, the rings will gain speed and then it won't give the desired underwater effect. Sonic 2 SVN fix(SVN fix by KingofHarts) There is ONE small hiccup when trying to apply this to the SVN disassembly of Sonic 2. If you go ahead and apply the above changes to the corresponding code, and build & run, you will find that there is a SERIOUS error with your ring loss. This is due to the way that the SVN disassembly is labeled, compared to the original Xenowhirl disassembly, and is a REALLY EASY thing to fix. I'll take a second to show you what you need to do. After you have finished applying the steps above, please go back to the first section you edited. It should now look something like this, perhaps minus the extra comments I made to guide me. ; loc_120B2: - bsr.w SingleObjLoad bne.w +++ ; loc_120BA: + _move.b #ObjID_LostRings,id(a1) ; load obj37 addq.b #2,routine(a1) move.b #8,y_radius(a1) move.b #8,x_radius(a1) move.w x_pos(a0),x_pos(a1) move.w y_pos(a0),y_pos(a1) move.l #Obj25_MapUnc_12382,mappings(a1) move.w #make_art_tile(ArtTile_ArtNem_Ring,1,0),art_tile(a1) bsr.w Adjust2PArtPointer2 move.b #$84,render_flags(a1) move.b #3,priority(a1) move.b #$47,collision_flags(a1) move.b #8,width_pixels(a1) move.b #-1,(Ring_spill_anim_counter).w tst.w d4 bmi.s + ; <- This line is incorrectly branching. move.w d4,d0 bsr.w JmpTo4_CalcSine move.w d4,d2 lsr.w #8,d2 ; RHS FIX tst.b (Water_flag).w ; Does the level have water? beq.s + ; If not, branch and skip underwater checks move.w (Water_Level_2).w,d6 ; Move water level to d6 cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level? bgt.s + ; If not, branch and skip underwater commands asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower + ; RHS FIX asl.w d2,d0 asl.w d2,d1 move.w d0,d2 move.w d1,d3 addi.b #$10,d4 bcc.s + ; <- This line is branching correctly, BUT we will need to change it. subi.w #$80,d4 bcc.s + ; <- This line is branching correctly, BUT we will need to change it. move.w #$288,d4 ;loc_12132 + move.w d2,x_vel(a1) move.w d3,y_vel(a1) ... Now, as you can see, the SVN has relabeled a LOT of these sections of code with "+". This is all well and good, BUT it causes problems for us when applying this fix. Note the first line I marked. It is supposed to branch to the former "loc_12132". Instead it branches to "+". But there is a "+" section BEFORE that, causing the issue. My fix is to relabel "loc_12132" back to its former label, and then I want you to edit all 3 lines I marked, and have them branch to this label. That's it! Everything SHOULD work out fine now for your SVN disassembly. Sonic 3&K fixThis guide uses the SVN disassembly. Go to "off_1A658:" (the routines of the scattered rings). You'll see that it's first job is to go to "loc_1A67A". That needs changing to "loc_1A68C". So, from this: off_1A658: dc.w loc_1A67A-off_1A658 dc.w loc_1A75C-off_1A658 dc.w loc_1A7C2-off_1A658 dc.w loc_1A7D6-off_1A658 dc.w loc_1A7E4-off_1A658
off_1A658: dc.w loc_1A68C-off_1A658 dc.w loc_1A75C-off_1A658 dc.w loc_1A7C2-off_1A658 dc.w loc_1A7D6-off_1A658 dc.w loc_1A7E4-off_1A658
Next, go to "off_1A670:" This is extremely similar to what we just done, but for reverse gravity. so no point explaining what it's doing here as I just did that. Anyway, you should see: off_1A670: dc.w loc_1A67A-off_1A670 dc.w loc_1A7E8-off_1A670 dc.w loc_1A7C2-off_1A670 dc.w loc_1A7D6-off_1A670 dc.w loc_1A7E4-off_1A670
off_1A670: dc.w loc_1A68C-off_1A670 dc.w loc_1A7E8-off_1A670 dc.w loc_1A7C2-off_1A670 dc.w loc_1A7D6-off_1A670 dc.w loc_1A7E4-off_1A670
Next, go to "loc_1A67A:" and you should see this.
loc_1A67A:
move.l #Obj_Bouncing_Ring,d6
tst.b (Reverse_gravity_flag).w
beq.s loc_1A68C
move.l #Obj_Bouncing_Ring_Reverse_Gravity,d6
move.l #Obj_Bouncing_Ring,(a1)
tst.b (Reverse_gravity_flag).w
beq.s loc_1A6B6CONTINUE
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
loc_1A6B6CONTINUE:
Yes, you might recognize this. It's part of that code you just this second deleted. We're pushing the scattered rings back into place. But instead of putting it to d6, we're putting it to a1. a1 is now available as it's not being used again for a while. So you have something looking at this:
loc_1A6B6:
move.l #Obj_Bouncing_Ring,(a1)
tst.b (Reverse_gravity_flag).w
beq.s loc_1A6B6CONTINUE
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
loc_1A6B6CONTINUE:
addq.b #2,5(a1)
move.b #8,$1E(a1)
move.b #8,$1F(a1)
move.w $10(a0),$10(a1)
move.w $14(a0),$14(a1)
move.l #Map_Ring,$C(a1)
move.w #$A6BC,$A(a1)
move.b #$84,4(a1)
move.w #$180,8(a1)
move.b #$47,$28(a1)
move.b #8,7(a1)
move.b #-1,(Ring_spill_anim_counter).w
tst.w d4
bmi.s loc_1A728
move.w d4,d0
jsr (GetSineCosine).l
move.w d4,d2
lsr.w #8,d2
asl.w d2,d0
asl.w d2,d1
move.w d0,d2
move.w d1,d3
addi.b #$10,d4
bcc.s loc_1A728
subi.w #$80,d4
bcc.s loc_1A728
move.w #$288,d4
Still looking at "loc_1A6B6:" look and find this bit of coding:
jsr (GetSineCosine).l
move.w d4,d2
lsr.w #8,d2
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvingvel ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvingvel ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
skiphalvingvel:
So, you should end up with something looking like this:
loc_1A6B6:
move.l #Obj_Bouncing_Ring,(a1)
tst.b (Reverse_gravity_flag).w
beq.s loc_1A6B6CONTINUE
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
loc_1A6B6CONTINUE:
addq.b #2,5(a1)
move.b #8,$1E(a1)
move.b #8,$1F(a1)
move.w $10(a0),$10(a1)
move.w $14(a0),$14(a1)
move.l #Map_Ring,$C(a1)
move.w #$A6BC,$A(a1)
move.b #$84,4(a1)
move.w #$180,8(a1)
move.b #$47,$28(a1)
move.b #8,7(a1)
move.b #-1,(Ring_spill_anim_counter).w
tst.w d4
bmi.s loc_1A728
move.w d4,d0
jsr (GetSineCosine).l
move.w d4,d2
lsr.w #8,d2
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvingvel ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvingvel ; If not, branch and skip underwater commands
asr.w #$1,d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w #$1,d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
skiphalvingvel:
asl.w d2,d0
asl.w d2,d1
move.w d0,d2
move.w d1,d3
addi.b #$10,d4
bcc.s loc_1A728
subi.w #$80,d4
bcc.s loc_1A728
move.w #$288,d4
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite2
addi.w #$18,$1A(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvinggrav ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvinggrav ; If not, branch and skip underwater commands
subi.w #$E,$1A(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
skiphalvinggrav:
loc_1A75C:
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite2
addi.w #$18,$1A(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvinggrav ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvinggrav ; If not, branch and skip underwater commands
subi.w #$E,$1A(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
skiphalvinggrav:
bmi.s loc_1A7B0
move.b (V_int_run_count+3).w,d0
add.b d7,d0
andi.b #7,d0
bne.s loc_1A7B0
tst.b 4(a0)
bpl.s loc_1A79C
jsr (sub_F994).l
tst.w d1
bpl.s loc_1A79C
add.w d1,$14(a0)
move.w $1A(a0),d0
asr.w #2,d0
sub.w d0,$1A(a0)
neg.w $1A(a0)
Go to label "loc_1A7E8:" and under
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite_TestGravity2
addi.w #$18,$1A(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvingrevgrav ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvingrevgrav ; If not, branch and skip underwater commands
subi.w #$E,$1A(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
skiphalvingrevgrav:
loc_1A7E8:
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite_TestGravity2
addi.w #$18,$1A(a0)
tst.b (Water_flag).w ; Does the level have water?
beq.s skiphalvingrevgrav ; If not, branch and skip underwater checks
move.w (Water_level).w,d6 ; Move water level to d6
cmp.w y_pos(a0),d6 ; Is the ring object underneath the water level?
bgt.s skiphalvingrevgrav ; If not, branch and skip underwater commands
subi.w #$E,$1A(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
skiphalvingrevgrav:
bmi.s loc_1A83C
move.b (V_int_run_count+3).w,d0
add.b d7,d0
andi.b #7,d0
bne.s loc_1A83C
tst.b 4(a0)
bpl.s loc_1A828
jsr (sub_FCA0).l
tst.w d1
bpl.s loc_1A828
sub.w d1,$14(a0)
move.w $1A(a0),d0
asr.w #2,d0
sub.w d0,$1A(a0)
neg.w $1A(a0)
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
