Flashing Lost Rings - RetroKoH/S1Fixed GitHub Wiki

(Original guide by Mercury; Bugfix by RetroKoH)
Source: ReadySonic
Commit: aa0974a

So, S1Fixed has addressed a couple of bugs with Lost Rings, but this one can actually help you see the second bug, this one, in action. We are going to make the lost rings flash prior to deletion. I'm going to show what this change looks like, both pre- and post- timer fix. Both versions aren't all that different, but I want to show both because I think it's better to add this change first before tackling that bug, so you can understand that bug a little easier.

Whether you choose to take my advice, or steamroll ahead, we are going to go to the object file _incObj\25 & 37 Rings.asm, and find the routine label: RLoss_Bounce. From there, find .chkdel, and look at the last line: bra.w DisplaySprite. We are going to replace this one line Basically, for every frame that the ring is out there bouncing around, its sprite is queued up to be displayed. All we need to do is make it only display sometimes, once it nears deletion.

Here's what you are going to replace that DisplaySprite line with:

	move.w	(v_limitbtm2).w,d0
	addi.w	#$E0,d0
	cmp.w	obY(a0),d0			; has object moved below level boundary?
	blo.s	RLoss_Delete			; if yes, branch
-	bra.w	DisplaySprite			; DELETE THIS LINE
+	move.b	(v_ani3_time).w,d0		; load timer to d0 (accessing d0 later saves cycles)
+	btst	#0,d0				; Test the first bit of the timer, so rings flash every other frame.
+	beq.w	DisplaySprite			; If the bit is 0, the ring will appear.
+	cmpi.b	#80,d0				; Rings will flash during last 80 steps of their life.
+	bhi.w	DisplaySprite			; If the timer is higher than 80, obviously the rings will STAY visible.
+	rts

If you have already applied the Ring Timers bugfix, you simply need to change this one line, to use the local timer:

	move.w	(v_limitbtm2).w,d0
	addi.w	#$E0,d0
	cmp.w	obY(a0),d0			; has object moved below level boundary?
	blo.s	RLoss_Delete			; if yes, branch
!	move.b	obDelayAni(a0),d0		; load timer to d0 (accessing d0 later saves cycles)
	btst	#0,d0				; Test the first bit of the timer, so rings flash every other frame.
	beq.w	DisplaySprite			; If the bit is 0, the ring will appear.
	cmpi.b	#80,d0				; Rings will flash during last 80 steps of their life.
	bhi.w	DisplaySprite			; If the timer is higher than 80, obviously the rings will STAY visible.
	rts

BUG ALERT: This section assumes that you've already applied BOTH of these bugfixes to the Lost Rings. If you haven't yet, then this section is useless. Go do that first, then come back. There is a bug that occurs in vertically wrapping levels (LZ3 and SBZ2) that causes Lost Rings to not flash as intended. This bug is actually the result of the Accidental Ring Loss Deletion bugfix applied to the Lost Rings. Let's fix this bug. Go to .chkdel and find this code (again):

.chkdel:
	subq.b	#1,obDelayAni(a0)	; Subtract 1
	beq.s	RLoss_Delete		; If 0, delete
	cmpi.w	#$FF00,(v_limittop2).w	; is vertical wrapping enabled?
!	beq.s	.chkflash		; if so, branch (Branch ahead to flash effect instead of to DisplaySprite)
	move.w	(v_limitbtm2).w,d0
	addi.w	#$E0,d0
	cmp.w	obY(a0),d0		; has object moved below level boundary?
	blo.s	RLoss_Delete		; if yes, branch

+.chkflash:
	move.b	obDelayAni(a0),d0	; load timer to d0 (accessing d0 later saves cycles)
	btst	#0,d0			; Test the first bit of the timer, so rings flash every other frame.
	beq.w	DisplaySprite		; If the bit is 0, the ring will appear.
	cmpi.b	#80,d0			; Rings will flash during last 80 steps of their life.
	bhi.w	DisplaySprite		; If the timer is higher than 80, obviously the rings will STAY visible.
	rts
; ===========================================================================

All we need to do is change the noted branch to DisplaySprite into a short branch to the flash routine, now labeled .chkflash. Now we're done!