Fix Scattered Rings Underwater Physics
From Sonic Retro
(Original guide for all 3 games 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 HiveBrain fix
(Addition by Luigi Hero)
First, in your disassembly, go to "Obj37_MakeRings:" 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 $C(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w d1 ; Half d1. Makes the ring's y_vel bounce up/down slower
@skiphalvingvel:
You should end up with something looking like this:
Obj37_MakeRings: ; XREF: Obj37_CountRings
move.b #$37,0(a1) ; load bouncing ring object
addq.b #2,$24(a1)
move.b #8,$16(a1)
move.b #8,$17(a1)
move.w 8(a0),8(a1)
move.w $C(a0),$C(a1)
move.l #Map_obj25,4(a1)
move.w #$27B2,2(a1)
move.b #4,1(a1)
move.b #3,$18(a1)
move.b #$47,$20(a1)
move.b #8,$19(a1)
move.b #-1,($FFFFFEC6).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 $C(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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 "Obj37_Bounce:" and under this...
move.b ($FFFFFEC7).w,$1A(a0)
bsr.w SpeedToPos
addi.w #$18,$12(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 $C(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skipbounceslow ; If not, branch and skip underwater commands
subi.w #$E,$12(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:
Obj37_Bounce: ; XREF: Obj37_Index
move.b ($FFFFFEC7).w,$1A(a0)
bsr.w SpeedToPos
addi.w #$18,$12(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 $C(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skipbounceslow ; If not, branch and skip underwater commands
subi.w #$E,$12(a0) ; Reduce gravity by $E ($18-$E=$A), giving the underwater effect
@skipbounceslow:
bmi.s Obj37_ChkDel
move.b ($FFFFFE0F).w,d0
add.b d7,d0
andi.b #3,d0
bne.s Obj37_ChkDel
jsr ObjHitFloor
tst.w d1
bpl.s Obj37_ChkDel
add.w d1,$C(a0)
move.w $12(a0),d0
asr.w #2,d0
sub.w d0,$12(a0)
neg.w $12(a0)
This ensures that, 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 1 Git fix
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 $C(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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 obY(a0),d6 ; Is the ring object underneath the water level?
bgt.s @skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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 this...
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 obY(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 obY(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 that, 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 fix
This guide uses the Xenowhirl disassembly, but notes for Git users are available.
First, go to "loc_120BA:" (part of the scattered rings object code. Git users, Obj37_Init, three '+'s down) and find this bit of coding:
bsr.w JmpTo4_CalcSine
move.w d4,d2
lsr.w #8,d2
Just underneath, paste this:
tst.b (Water_flag).w ; Does the level have water?
beq.s .skiphalvingvel ; 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 .skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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_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 .skiphalvingvel ; 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 .skiphalvingvel ; If not, branch and skip underwater commands
asr.w d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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_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.
Next, go to label "Obj_37_sub_2:" and under this...
move.b (Ring_spill_anim_frame).w,mapping_frame(a0)
bsr.w ObjectMove
addi.w #$18,y_vel(a0)
...put this:
tst.b (Water_flag).w ; Does the level have water?
beq.s .skipbounceslow ; 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 .skipbounceslow ; 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
.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:
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 .skipbounceslow ; 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 .skipbounceslow ; 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
.skipbounceslow:
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 that, 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 3&K fix
This guide uses the SVN disassembly.
Go to "off_1A658:" (the routines of the scattered rings). You'll see that its first job is to go to "loc_1A67A". That needs changing to "loc_1A68C". So, find 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
...and replace it with this:
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
This will skip "loc_1A67A" commands. This is because this location pushes the scattered rings object (or the reverse scattered rings object) to d6. For our water code, we need d6, because all other data registers are being used. It doesn't do this in Sonic 1 or 2 because there's no such thing as "reverse gravity". The scattered rings object needs to be moved to a1, but we can't do it here, because shortly after, a1 is being used for the amount of rings.
Next, go to "off_1A670:" This is extremely similar to what we just done, but for reverse gravity, so there's no point explaining what it's doing here as I just did that. Anyway, you should see this...
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
...replace it with:
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
Again, this will skip "loc_1A67A" commands. Explained why above.
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
Notice "Bouncing_Ring" (and the reverse one) is being pushed to d6. We need d6, so, delete it. It's no longer needed. Trust me. We have now freed d6, although we've lost pushing the scattered rings into place. Do not worry, that's next.
Next, go to "loc_1A6B6:". The very first command should be "addq.b #2,5(a1)" Just before that, add this:
move.l #Obj_Bouncing_Ring,(a1)
tst.b (Reverse_gravity_flag).w
beq.s .notreverse
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
.notreverse:
Yes, you might recognize this. It's part of that code you'd just 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 .notreverse
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
.notreverse:
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
Just underneath, paste this:
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 d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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 .notreverse
move.l #Obj_Bouncing_Ring_Reverse_Gravity,(a1)
.notreverse:
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 d0 ; Half d0. Makes the ring's x_vel bounce to the left/right slower
asr.w 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
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 "loc_1A75C:" and under this...
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite2
addi.w #$18,$1A(a0)
...put this:
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:
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:
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)
This ensures that, when underwater, the gravity is not as great. Otherwise, the rings will gain speed and then it won't give the desired underwater effect.
This last bit is optional. You only need to do this if you're planning to have reverse gravity underwater. You'd be a bit mental if you do have this, but you never know =P
Go to label "loc_1A7E8:" and under this...
move.b (Ring_spill_anim_frame).w,$22(a0)
bsr.w MoveSprite_TestGravity2
addi.w #$18,$1A(a0)
...put this:
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:
Again, you can change the value of the reverse gravity if you like.
So, you should have something looking like this:
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)
This ensures that, when underwater, the gravity is not as great when it's in reverse gravity mode.
SCHG How-To Guide: Sonic the Hedgehog 3 and Knuckles |
---|
Fixing Bugs |
Fix Blue Knuckles | Fix Tails' Respawn Speeds | Fix Super Sonic Bugs |
Design Choices |
Fix Scattered Rings' Underwater Physics | Edit Level Select Text & Pointers | Work with Water | Make the Slots Bonus Game Rotate Smoothly |
Adding Features |
Restore (Sonic 2) Options Menu |
|Fix Scattered Rings Underwater Physics]]