Better scrolling?

Yan

Member
On the MetroidVania module the scrolling is only activated by the "do_simpleScrollLeft.asm" and "do_simpleScrollRight.asm" input scripts, right? This can cause problems with anything that makes the player move without him activating those scripts I guess (even the recoil after getting hurt?). Does anyone know a good / simple way to implement scrolling which doesn't cause this kind of problem?
 

AllDarnDavey

Active member
Yan said:
On the MetroidVania module the scrolling is only activated by the "do_simpleScrollLeft.asm" and "do_simpleScrollRight.asm" input scripts, right? This can cause problems with anything that makes the player move without him activating those scripts I guess (even the recoil after getting hurt?). Does anyone know a good / simple way to implement scrolling which doesn't cause this kind of problem?

I have a few thoughts along these lines. You could try incorporating the simpleScroll code into the recoil of hurt player, so it still triggers scrolling.

I did a rough prototype for an idea for large background tile based bosses. I put a scroll left & scroll right as AI scripts to a invisible monster object to scroll the scene instead of the player (think giant vehicle bosses like the technodrome in TMNT). You could do a similar thing, make an invisible object that repeats an AI script every frame to track the player's X position and control the scrolling (moving that away from the player inputs, like an invisible camera man).

I haven't really tried any of these ideas however, and I wouldn't call them simple unfortunately. But feel free to steal them if you want to try and flesh them out. Inserting the scroll code into the hurtPlayer recoil is probably the easiest (the recoil is around line 72 in hurtPlayer and already has separate left and right areas). I am worried that the hurt code only executes once when the player gets hit, and this might need something that updates over a few frames to work.
 

TakuikaNinja

Active member
I've already shared a fix for the scrolling when the player stops moving, but I hadn't considered recoil at all.
I'm sure it's just a matter of putting the scroll check code into whatever script handles the recoil.
 

Yan

Member
Thanks everyone! I will definitely test that stuff out Davey

Jonny said:
Would you be able to post a video of the issue happening?

I haven't been running into any issues actually, I was just wondering if there could be some :lol:
 

AllDarnDavey

Active member
Okay, this seems to work for me.

Make a file call it something like hurtPlayer_metriodVania.asm, and assign it as the hurt player script. Use this code:
Code:
	;;;;;;;;;;;;;;;;;; Presumes there is a variable called myLives defined in user variables.
	;;;;;;;;;;;;;;;;;; You could also create your own variable for this.

	LDA gameHandler
	AND #%10000000
	BEQ +canHurtPlayer
		JMP +skipHurt
+canHurtPlayer:
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;;;;;;;;;; is the monster below our feet?
	;;;;;;;;;; and are we moving downward?

+doHurtPlayer	
	TXA
	STA temp
	GetActionStep temp
	CMP #$07
	BNE +canHurtPlayer
		JMP +skipHurt
	+canHurtPlayer
	;;; will presume there is a variable myHealth
	;;; and that player hurt state is action state 7.
	GetActionStep player1_object
	CMP #$07 ;; hurt state.
	BEQ +notAlreadyInHurtState
		DEC myHealth
		
		BMI +healthBelowZero
		BEQ +healthBelowZero
			JMP +notDeadYet
		+healthBelowZero
			
			JMP +playerHealthIsZero
		+notDeadYet
		PlaySound #sfx_damage
		UpdateHudElement #$02
		ChangeActionStep player1_object, #$07
			;; recoil
			LDA #$00
			STA Object_h_speed_hi,x
			STA Object_h_speed_lo,x
			STA Object_v_speed_hi,x
			STA Object_v_speed_lo,x
			LDA xPrev
			STA Object_x_hi,x
			LDA yPrev
			STA Object_y_hi,x
	+notAlreadyInHurtState
		LDA Object_x_hi,x
		CLC
		ADC self_center_x
		STA tempA
		LDA Object_y_hi,x
		CLC
		ADC self_center_y
		STA tempB
		TXA 
		PHA
			LDX otherObject
			LDA Object_x_hi,x
			CLC
			ADC other_center_x
			STA tempC
			LDA Object_y_hi,x
			CLC
			ADC other_center_y
			STA tempD
		PLA
		TAX
	
		;;; RECOIL L/R
			;+recoilHor
				LDA tempA
				CMP tempC
				BCS +recoilRight
					LDA Object_direction,x
					AND #%00000010
					ORA #%10000000
					STA Object_direction,x
					StartMoving temp, #LEFT
					LDA #%10000000  ;; bit one forces an update.
					STA scrollByte					
					JMP +skipHurt

				+recoilRight
					LDA Object_direction,x
					AND #%00000110
					ORA #%11000000
					STA Object_direction,x
					StartMoving temp, #RIGHT
					LDA #%11000000 
					STA scrollByte					
					JMP +skipHurt
	
+playerHealthIsZero:
	PlaySound #sfx_dead

	LDA continueMap
	STA warpMap
	
	LDA continueX
	STA newX
	LDA continueY
	STA newY
	
	LDA continueScreen
	STA warpToScreen
	STA camScreen
	

	LDA myMaxHealth
	STA myHealth
	
	LDA #$00			;;reset and turn off the scroll byte if dead.
	STA camX
	STA camY
	LDA #%00000000  
	STA scrollByte	
	
	WarpToScreen warpToMap, warpToScreen, #$02
		;; arg0 = warp to map.  0= map1.  1= map2.
		;; arg1 = screen to warp to.
		;; arg2 = screen transition type - most likely use 1 here.
			;; 1 = warp, where it observes the warp in position for the player.

	
+skipHurt

It'll make sure that scroll is enabled when doing player recoil.
 

TakuikaNinja

Active member
I implemented the new recoil script and it seems to work fine.
I've noticed the player run animation doesn't start again if you keep the d-pad held during the recoil, though. (Why do I keep finding such minor issues? lol)

Oh yeah, derexgar brought up another scrolling issue in the discord server.
If you spawn/warp into a screen with the right screen edge enabled, it will still "update" the scroll column when you move past the scroll pad.
Here's a screenshot to show what I mean (I use the PPU masking feature, so it's sort of hidden here):
7r7Wn9w.png
 

AllDarnDavey

Active member
TakuikaNinja said:
I implemented the new recoil script and it seems to work fine.
I've noticed the player run animation doesn't start again if you keep the d-pad held during the recoil, though. (Why do I keep finding such minor issues? lol)
That's an easy fix, make the move input scripts activate on 'hold' instead of 'press', and then add a check in the change to move input script to check if you are already in the move action state and skip resetting the action state if you are. To keep the animation from getting reset constantly and just showing the first frame. I think the intermediate brawler tutorial does this.

TakuikaNinja said:
Oh yeah, derexgar brought up another scrolling issue in the discord server.
If you spawn/warp into a screen with the right screen edge enabled, it will still "update" the scroll column when you move past the scroll pad.
Here's a screenshot to show what I mean (I use the PPU masking feature, so it's sort of hidden here):
Huh... never tested this. I was always respawning or warping on a left edge. Thanks for the heads up, I'll have to take a look.
 

AllDarnDavey

Active member
TakuikaNinja said:
Oh yeah, derexgar brought up another scrolling issue in the discord server.
If you spawn/warp into a screen with the right screen edge enabled, it will still "update" the scroll column when you move past the scroll pad.
Here's a screenshot to show what I mean (I use the PPU masking feature, so it's sort of hidden here):
7r7Wn9w.png
Oh yeah, I'm getting the same thing. It doesn't always happen, but it happens quite often. A work around I found is to warp into a position with an extra screen to the right as a buffer, but that's a bummer. Seems like it handles not having a half screen buffer to the left just fine, but not if there isn't half a screen to the right.

It seems like the best way to repro it, is to just move a little bit, enough to trigger the scroll update, but not enough for it to grab the right tile data maybe, so it's dumping whatever it has saved currently? Not sure where to start on that one.
 

AllDarnDavey

Active member
Okay, I might have a fix... but I need someone to confirm.

Copy this code into a new file named doUpdateCamera_RightEdgeFix.asm and assign it in place of the normal doUpdateCamera.asm:
Code:
doUpdateCamera:	
	
	LDX camObject
	LDA Object_h_speed_lo,x
	STA tempA
	LDA Object_h_speed_hi,x
	STA tempB
	
	LDA camX
	AND #%11110000
	STA tempz

	LDA scrollByte
	AND #%10100000
	BNE +scrollEngaged
		JMP skipScrollUpdate
+scrollEngaged:
	LDA camX_hi
	STA tempD ;; will hold.  If this is changed by the end of the routine
			;; then we need to update anything that should change when our camera
			;; has crossed the screen boundary, such as screenFlags.

	LDA scrollByte
	AND #%10000000
	BNE doHorizontalCameraUpdate
		JMP noHorizontalCameraUpdate
	doHorizontalCameraUpdate:

	LDA scrollByte
	AND #%01000000
	BNE doRightCameraUpdate
	
		LDA camX_lo
		SEC
		SBC tempA
		LDA camX
		SBC tempB
		SBC #$FF
			 BEQ +skipCheckForScrollScreenEdge
			 BCS +skipCheckForScrollScreenEdge
				LDA ScreenFlags00
				AND #%00100000
				BEQ +skipCheckForScrollScreenEdge
					JMP skipAllScrollSeamUpdate
		+skipCheckForScrollScreenEdge
		;; is left camera update
		LDA camX_lo
		sec
		sbc tempA
		STA camX_lo
		LDA camX
		sbc tempB
		STA camX
		
		LDA camX_hi
		sbc #$00
		STA camX_hi
		JSR getCamSeam
		JMP noHorizontalCameraUpdate ;; jump to update the column.
	doRightCameraUpdate
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;;; Here, we have to check the right side of the screen
	;;; to see if we're lined up with the edge.
		LDA camX_lo
		CLC
		ADC tempA
		LDA camX_hi
		LDA camX
		ADC tempB
		ADC #$FF
			BCc +skipCheckForScrollScreenEdge
				LDA ScreenFlags00
				AND #%00010000
				BEQ +skipCheckForScrollScreenEdge
					JMP skipAllScrollSeamUpdate
		+skipCheckForScrollScreenEdge
	
		LDA camX_lo
		clc
		adc tempA
		STA camX_lo
		LDA camX
		adc tempB
		STA camX
		LDA camX_hi
		adc #$00
		STA camX_hi
		JSR getCamSeam
	noHorizontalCameraUpdate:


	
	LDA scrollByte
	AND #%00000001
	BEQ +canUpdateScrollColumn
		JMP skipScrollUpdate
+canUpdateScrollColumn
	LDA scrollByte
	AND #%00000010
	BNE forceScrollColumnUpdate
	LDA camX
	AND #%11110000
	CMP tempz
	BNE +canUpdateScrollColumn2
		JMP skipScrollUpdate
forceScrollColumnUpdate:
	LDA scrollByte
	AND #%11111101
	STA scrollByte
+canUpdateScrollColumn2

		LDA scrollByte
		ORA #%00000101
		STA scrollByte
		;;;;;;;;;; DO SCROLL UPDATE.
		SwitchBank #$16
			LDY scrollUpdateScreen
			LDA warpMap
			BEQ +loadFromMap1
				;; load from map 2
				
				LDA NameTablePointers_Map2_lo,y
				STA temp16
				LDA NameTablePointers_Map2_hi,y
				STA temp16+1
				

				LDA AttributeTables_Map2_Lo,y
				STA pointer
				LDA AttributeTables_Map2_Hi,y
				STA pointer+1
				
				
				LDA CollisionTables_Map2_Lo,y
				STA pointer6
				LDA CollisionTables_Map2_Hi,y
				STA pointer6+1
				
				LDY camScreen
				LDA CollisionTables_Map2_Lo,y
				STA pointer2
				LDA CollisionTables_Map2_Hi,y
				STA pointer2+1
				JMP +doneWithGettingOffset
			+loadFromMap1
			
				LDA NameTablePointers_Map1_lo,y
				STA temp16
				LDA NameTablePointers_Map1_hi,y
				STA temp16+1
				

				LDA AttributeTables_Map1_Lo,y
				STA pointer
				LDA AttributeTables_Map1_Hi,y
				STA pointer+1
				
				
				LDA CollisionTables_Map1_Lo,y
				STA pointer6
				LDA CollisionTables_Map1_Hi,y
				STA pointer6+1
				
				LDY camScreen
				LDA CollisionTables_Map1_Lo,y
				STA pointer2
				LDA CollisionTables_Map1_Hi,y
				STA pointer2+1
			+doneWithGettingOffset:
		ReturnBank
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; now we have pointers for the fetch.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; We can read from the pointers to get metatile data.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; jump to the bank
		LDA scrollUpdateScreen	
		LSR
		LSR
		LSR
		LSR
		LSR
		STA temp ; bank
		LDA warpMap
		BEQ +gotWarpMap
			LDA temp
			;; it was underground, add 8 to warp map
			CLC
			ADC #$08
			sta temp
		+gotWarpMap
		
		SwitchBank temp
			; LDX screenState
			; LDY Mon1SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation
			
			; LDY Mon2SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+1
			
			; LDY Mon3SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+2
			
			; LDY Mon4SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+3
			
			LDX screenState
			LDY Mon1SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon2SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon3SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon4SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			
		
		
			LDA scrollUpdateScreen
			AND #%00000001
			ASL
			ASL
			ORA #%00100000
			STA temp1 ;; temp 1 now represents the high byte of the address to place 
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			AND #%00011111
			STA temp2 ;; temp 2 now represents the low byte of the pushes.
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			LSR
			STA temp3
			
			LDA #$00
			STA scrollOffsetCounter			
					
			LDX #$00 ;; will keep track of scroll update ram.
			LDA #$0F
			STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
			loop_LoadNametableMeta_column:
				LDY temp3
				LDA (temp16),y
				STA temp
				JSR doGetSingleMetaTileValues
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				STA scrollUpdateRam,x
				INX
				LDA updateTile_00
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$01
				STA scrollUpdateRam,x
				INX
				LDA updateTile_01
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$20
				STA scrollUpdateRam,x
				INX
				LDA updateTile_02
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$21
				STA scrollUpdateRam,x
				INX
				LDA updateTile_03
				STA scrollUpdateRam,x
				INX 
				
				DEC tempA
				LDA tempA
				BEQ +doneWithNtLoad
					;; not done with NT load.  Need more tiles.
					;;;;;;;;;;;;;;;;;;;;;;;;;;
					;; update the 16 bit position of the new place to push tiles to.
					LDA temp2
					CLC
					ADC #$40
					STA temp2
					LDA temp1
					ADC #$00
					STA temp1
					;; update the tile read location.
					LDA temp3
					CLC
					ADC #$10
					STA temp3
					JMP loop_LoadNametableMeta_column	
			+doneWithNtLoad
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;;;;; add attributes to the update list.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;; 23 = 00100011
		;;;; 27 = 00100111
		;;;; so the last bit of scrollUpdateScreen and shift it twice to the left
		;;;; then or it with 00100000 to get the high byte of the attribute update table.
				LDA scrollUpdateScreen
				AND #%00000001
				ASL
				ASL
				;ASL
				ORA #%00100011
				STA temp1 ;; this is now the high byte of the attribute table update
				
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR
				LSR
	
				STA temp2 ;; temp 2 now represents the low byte of the pushes.
				;; don't need a temp3 to keep track of pull position, because it will be 1 to 1.
				
				LDA #$08
				STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
				loop_LoadAttribute_column:
			
					LDY temp2
					LDA (pointer),y
					STA temp
					
					LDA temp1
					STA scrollUpdateRam,x
					INX
					LDA temp2
					CLC
					ADC #$c0
					STA scrollUpdateRam,x
					INX
					LDA temp
					STA scrollUpdateRam,x
					INX 
					DEC tempA
					LDA tempA
					BEQ +doneWithAtLoad
						LDA temp2
						CLC
						ADC #$08
						STA temp2
						JMP loop_LoadAttribute_column
					+doneWithAtLoad
					
					
				TXA
				STA maxScrollOffsetCounter

				LDA updateScreenData
				ORA #%00000100
				STA updateScreenData

		
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR 
				STA temp1 ;; keeps track of where to place on the collision table.
				LSR 
				STA temp2 ;; keeps track of the nubble being pulled from.
				LDX #$0F ;; keep track of how many values to load are left.
			
				LDA scrollUpdateScreen
				AND #%00000001
				BNE +doUpdateOddCt
					;; do update even CT
					;; to ct table 1
					doUpdateCtLoop
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop
							JMP +doneWithCtLoad
				+doUpdateOddCt
					;; do update odd ct
					;; to ct table 2
					doUpdateCtLoop2
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable2,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop2
							JMP +doneWithCtLoad
				+doneWithCtLoad
		LDA tempD
		CMP camX_hi
		BEQ +skipUpdatingScreenFlags
	
				;; update screen flags.
				LDY #124
				LDA (pointer2),y
				STA ScreenFlags00
				LDY #182
				LDA (pointer2),y
				STA ScreenFlags01
			+skipUpdatingScreenFlags
			;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		ReturnBank
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; here check camX_hi against tempD
		;;; if they are the same, that means we haven't changed screen boundaries.
		;;; if they have changed, it means we have changed screen boundaries, so 
		;;; we should load in the new screenFlags data.

		
		
skipScrollUpdate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure we always update camScreen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	JSR checkForMonsterCameraClipping
skipAllScrollSeamUpdate:	
	RTS
	
	
	
getCamSeam:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Since we use camScreen in this subroutine, we'll have to make sure it's properly updated
;;; before get our column and screen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
	
	LDA scrollByte
	AND #%01000000
	BNE +getRightScrollUpdate
		;; get left scroll update
		
		
		LDA camX
		AND #%11110000
		sec
		sbc #$70
		STA scrollUpdateColumn
		LDA camScreen
		sbc #$00
		STA scrollUpdateScreen

	RTS
	+getRightScrollUpdate

		LDA camX
		AND #%11110000
		CLC
		ADC #$80
		STA scrollUpdateColumn
		LDA camScreen
		ADC #$01
		STA scrollUpdateScreen

	RTS
	
	
	
checkForMonsterCameraClipping:

;;; use temp16 to check for cam clips
	LDA camX_hi
	AND #%00001111
	BNE notOnZeroScreen
	LDA #$00
	STA temp16
	LDA camX_hi
	STA temp16+1
	JMP +gotIt
notOnZeroScreen:

	LDA camX
	SEC
	SBC #$80
	STA temp16 ;; low left cam clip
	LDA camX_hi
	;AND #%00001111
	SBC #$00
	AND #%00001111
	STA temp16+1 ;; high left cam clip
+gotIt:	
	LDA camX
	CLC
	ADC #$80
	STA pointer ;; low right cam clip
	LDA camX_hi
	
	ADC #$01
	AND #%00001111
	STA pointer+1 ;; high right cam clip

	LDX #$00
	skipCheckingThisObject_forEraseColumnLoop
		cpx player1_object
		BEQ doEraseNonPlayerObjectsInThisColumnLoop
			LDA Object_status,x
			AND #%10000000
			BEQ doEraseNonPlayerObjectsInThisColumnLoop
			;; check this monster's position
			LDA Object_x_hi,x
			STA temp
			LDA Object_screen,x
			AND #%00001111
			STA temp1
			Compare16 temp16+1, temp16, temp1, temp
			+	
				DestroyObject
		
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
		skipCheckingThisObject_forEraseColumnLoop2:
			Compare16 pointer+1, pointer, temp1, temp
			+
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
				DestroyObject
		
			doEraseNonPlayerObjectsInThisColumnLoop
				INX
				CPX #TOTAL_MAX_OBJECTS
				BNE skipCheckingThisObject_forEraseColumnLoop

	RTS
	
checkSeamForMonsterPosition:
	;; y is loaded before subroutine.
			LDA (pointer6),y
			STA temp
			ASL
			ASL
			ASL
			ASL
			STA temp2
			LDA scrollUpdateColumn
			AND #%11110000
			CMP temp2
			BNE +noMonsterToLoadInThisColumn
				LDA temp
				AND #%11110000
				STA temp1
				CMP #%11110000
				BEQ +noMonsterToLoadInThisColumn
					CreateObjectOnScreen temp2, temp1, #$10, #$00, scrollUpdateScreen
			+noMonsterToLoadInThisColumn:
	RTS

I say this MIGHT be a fix because it started working for me after I made this change and I can no longer repo the left edge glitch at all. But when I reverted the change back, it kept working. So I need someone else to confirm this fixed it, or that it doesn't and something else I did that I don't remember and now need to track down fixed it instead.
 

TakuikaNinja

Active member
AllDarnDavey said:
I say this MIGHT be a fix because it started working for me after I made this change and I can no longer repo the left edge glitch at all. But when I reverted the change back, it kept working. So I need someone else to confirm this fixed it, or that it doesn't and something else I did that I don't remember and now need to track down fixed it instead.

NESmaker sometimes fails to update the used scripts when you change them. Just make sure you're saving the project after every change you do and it should be fine.
I'll have a go at implementing your script right away.
 

TakuikaNinja

Active member
I've just implemented the new script. The glitch is gone now, but now the game stops scrolling to the left before reaching the screen with "left edge for scroll" enabled.
 

TakuikaNinja

Active member
Ok, it seems like the original script detects the left edge for scroll just fine, so I've put that part back into your script.
Code:
doUpdateCamera:	
	
	LDX camObject
	LDA Object_h_speed_lo,x
	STA tempA
	LDA Object_h_speed_hi,x
	STA tempB
	
	LDA camX
	AND #%11110000
	STA tempz

	LDA scrollByte
	AND #%10100000
	BNE +scrollEngaged
		JMP skipScrollUpdate
+scrollEngaged:
	LDA camX_hi
	STA tempD ;; will hold.  If this is changed by the end of the routine
			;; then we need to update anything that should change when our camera
			;; has crossed the screen boundary, such as screenFlags.

	LDA scrollByte
	AND #%10000000
	BNE doHorizontalCameraUpdate
		JMP noHorizontalCameraUpdate
	doHorizontalCameraUpdate:

	LDA scrollByte
	AND #%01000000
	BNE doRightCameraUpdate
	
		;; is left camera update
		LDA camX_lo
		sec
		sbc tempA
		STA camX_lo
		LDA camX
		sbc tempB
		STA temp
			BCS +skipCheckForScrollScreenEdge
				LDA ScreenFlags00
				AND #%00100000
				BEQ +skipCheckForScrollScreenEdge
					JMP noHorizontalCameraUpdate
		+skipCheckForScrollScreenEdge
		LDA temp
		STA camX
		
		LDA camX_hi
		sbc #$00
		STA camX_hi
		JSR getCamSeam
		JMP noHorizontalCameraUpdate
	doRightCameraUpdate
	;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;;; Here, we have to check the right side of the screen
	;;; to see if we're lined up with the edge.
		LDA camX_lo
		CLC
		ADC tempA
		LDA camX_hi
		LDA camX
		ADC tempB
		ADC #$FF
			BCc +skipCheckForScrollScreenEdge
				LDA ScreenFlags00
				AND #%00010000
				BEQ +skipCheckForScrollScreenEdge
					JMP skipAllScrollSeamUpdate
		+skipCheckForScrollScreenEdge
	
		LDA camX_lo
		clc
		adc tempA
		STA camX_lo
		LDA camX
		adc tempB
		STA camX
		LDA camX_hi
		adc #$00
		STA camX_hi
		JSR getCamSeam
	noHorizontalCameraUpdate:


	
	LDA scrollByte
	AND #%00000001
	BEQ +canUpdateScrollColumn
		JMP skipScrollUpdate
+canUpdateScrollColumn
	LDA scrollByte
	AND #%00000010
	BNE forceScrollColumnUpdate
	LDA camX
	AND #%11110000
	CMP tempz
	BNE +canUpdateScrollColumn2
		JMP skipScrollUpdate
forceScrollColumnUpdate:
	LDA scrollByte
	AND #%11111101
	STA scrollByte
+canUpdateScrollColumn2

		LDA scrollByte
		ORA #%00000101
		STA scrollByte
		;;;;;;;;;; DO SCROLL UPDATE.
		SwitchBank #$16
			LDY scrollUpdateScreen
			LDA warpMap
			BEQ +loadFromMap1
				;; load from map 2
				
				LDA NameTablePointers_Map2_lo,y
				STA temp16
				LDA NameTablePointers_Map2_hi,y
				STA temp16+1
				

				LDA AttributeTables_Map2_Lo,y
				STA pointer
				LDA AttributeTables_Map2_Hi,y
				STA pointer+1
				
				
				LDA CollisionTables_Map2_Lo,y
				STA pointer6
				LDA CollisionTables_Map2_Hi,y
				STA pointer6+1
				
				LDY camScreen
				LDA CollisionTables_Map2_Lo,y
				STA pointer2
				LDA CollisionTables_Map2_Hi,y
				STA pointer2+1
				JMP +doneWithGettingOffset
			+loadFromMap1
			
				LDA NameTablePointers_Map1_lo,y
				STA temp16
				LDA NameTablePointers_Map1_hi,y
				STA temp16+1
				

				LDA AttributeTables_Map1_Lo,y
				STA pointer
				LDA AttributeTables_Map1_Hi,y
				STA pointer+1
				
				
				LDA CollisionTables_Map1_Lo,y
				STA pointer6
				LDA CollisionTables_Map1_Hi,y
				STA pointer6+1
				
				LDY camScreen
				LDA CollisionTables_Map1_Lo,y
				STA pointer2
				LDA CollisionTables_Map1_Hi,y
				STA pointer2+1
			+doneWithGettingOffset:
		ReturnBank
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; now we have pointers for the fetch.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; We can read from the pointers to get metatile data.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; jump to the bank
		LDA scrollUpdateScreen	
		LSR
		LSR
		LSR
		LSR
		LSR
		STA temp ; bank
		LDA warpMap
		BEQ +gotWarpMap
			LDA temp
			;; it was underground, add 8 to warp map
			CLC
			ADC #$08
			sta temp
		+gotWarpMap
		
		SwitchBank temp
			; LDX screenState
			; LDY Mon1SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation
			
			; LDY Mon2SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+1
			
			; LDY Mon3SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+2
			
			; LDY Mon4SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+3
			
			LDX screenState
			LDY Mon1SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon2SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon3SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon4SpawnLocation,x
			JSR checkSeamForMonsterPosition
			
			
		
		
			LDA scrollUpdateScreen
			AND #%00000001
			ASL
			ASL
			ORA #%00100000
			STA temp1 ;; temp 1 now represents the high byte of the address to place 
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			AND #%00011111
			STA temp2 ;; temp 2 now represents the low byte of the pushes.
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			LSR
			STA temp3
			
			LDA #$00
			STA scrollOffsetCounter			
					
			LDX #$00 ;; will keep track of scroll update ram.
			LDA #$0F
			STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
			loop_LoadNametableMeta_column:
				LDY temp3
				LDA (temp16),y
				STA temp
				JSR doGetSingleMetaTileValues
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				STA scrollUpdateRam,x
				INX
				LDA updateTile_00
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$01
				STA scrollUpdateRam,x
				INX
				LDA updateTile_01
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$20
				STA scrollUpdateRam,x
				INX
				LDA updateTile_02
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$21
				STA scrollUpdateRam,x
				INX
				LDA updateTile_03
				STA scrollUpdateRam,x
				INX 
				
				DEC tempA
				LDA tempA
				BEQ +doneWithNtLoad
					;; not done with NT load.  Need more tiles.
					;;;;;;;;;;;;;;;;;;;;;;;;;;
					;; update the 16 bit position of the new place to push tiles to.
					LDA temp2
					CLC
					ADC #$40
					STA temp2
					LDA temp1
					ADC #$00
					STA temp1
					;; update the tile read location.
					LDA temp3
					CLC
					ADC #$10
					STA temp3
					JMP loop_LoadNametableMeta_column	
			+doneWithNtLoad
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;;;;; add attributes to the update list.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;; 23 = 00100011
		;;;; 27 = 00100111
		;;;; so the last bit of scrollUpdateScreen and shift it twice to the left
		;;;; then or it with 00100000 to get the high byte of the attribute update table.
				LDA scrollUpdateScreen
				AND #%00000001
				ASL
				ASL
				;ASL
				ORA #%00100011
				STA temp1 ;; this is now the high byte of the attribute table update
				
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR
				LSR
	
				STA temp2 ;; temp 2 now represents the low byte of the pushes.
				;; don't need a temp3 to keep track of pull position, because it will be 1 to 1.
				
				LDA #$08
				STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
				loop_LoadAttribute_column:
			
					LDY temp2
					LDA (pointer),y
					STA temp
					
					LDA temp1
					STA scrollUpdateRam,x
					INX
					LDA temp2
					CLC
					ADC #$c0
					STA scrollUpdateRam,x
					INX
					LDA temp
					STA scrollUpdateRam,x
					INX 
					DEC tempA
					LDA tempA
					BEQ +doneWithAtLoad
						LDA temp2
						CLC
						ADC #$08
						STA temp2
						JMP loop_LoadAttribute_column
					+doneWithAtLoad
					
					
				TXA
				STA maxScrollOffsetCounter

				LDA updateScreenData
				ORA #%00000100
				STA updateScreenData

		
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR 
				STA temp1 ;; keeps track of where to place on the collision table.
				LSR 
				STA temp2 ;; keeps track of the nubble being pulled from.
				LDX #$0F ;; keep track of how many values to load are left.
			
				LDA scrollUpdateScreen
				AND #%00000001
				BNE +doUpdateOddCt
					;; do update even CT
					;; to ct table 1
					doUpdateCtLoop
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop
							JMP +doneWithCtLoad
				+doUpdateOddCt
					;; do update odd ct
					;; to ct table 2
					doUpdateCtLoop2
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable2,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop2
							JMP +doneWithCtLoad
				+doneWithCtLoad
		LDA tempD
		CMP camX_hi
		BEQ +skipUpdatingScreenFlags
	
				;; update screen flags.
				LDY #124
				LDA (pointer2),y
				STA ScreenFlags00
				LDY #182
				LDA (pointer2),y
				STA ScreenFlags01
			+skipUpdatingScreenFlags
			;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		ReturnBank
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; here check camX_hi against tempD
		;;; if they are the same, that means we haven't changed screen boundaries.
		;;; if they have changed, it means we have changed screen boundaries, so 
		;;; we should load in the new screenFlags data.

		
		
skipScrollUpdate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure we always update camScreen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	JSR checkForMonsterCameraClipping
skipAllScrollSeamUpdate:	
	RTS
	
	
	
getCamSeam:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Since we use camScreen in this subroutine, we'll have to make sure it's properly updated
;;; before get our column and screen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
	
	LDA scrollByte
	AND #%01000000
	BNE +getRightScrollUpdate
		;; get left scroll update
		
		
		LDA camX
		AND #%11110000
		sec
		sbc #$70
		STA scrollUpdateColumn
		LDA camScreen
		sbc #$00
		STA scrollUpdateScreen

	RTS
	+getRightScrollUpdate

		LDA camX
		AND #%11110000
		CLC
		ADC #$80
		STA scrollUpdateColumn
		LDA camScreen
		ADC #$01
		STA scrollUpdateScreen

	RTS
	
	
	
checkForMonsterCameraClipping:

;;; use temp16 to check for cam clips
	LDA camX_hi
	AND #%00001111
	BNE notOnZeroScreen
	LDA #$00
	STA temp16
	LDA camX_hi
	STA temp16+1
	JMP +gotIt
notOnZeroScreen:

	LDA camX
	SEC
	SBC #$80
	STA temp16 ;; low left cam clip
	LDA camX_hi
	;AND #%00001111
	SBC #$00
	AND #%00001111
	STA temp16+1 ;; high left cam clip
+gotIt:	
	LDA camX
	CLC
	ADC #$80
	STA pointer ;; low right cam clip
	LDA camX_hi
	
	ADC #$01
	AND #%00001111
	STA pointer+1 ;; high right cam clip

	LDX #$00
	skipCheckingThisObject_forEraseColumnLoop
		cpx player1_object
		BEQ doEraseNonPlayerObjectsInThisColumnLoop
			LDA Object_status,x
			AND #%10000000
			BEQ doEraseNonPlayerObjectsInThisColumnLoop
			;; check this monster's position
			LDA Object_x_hi,x
			STA temp
			LDA Object_screen,x
			AND #%00001111
			STA temp1
			Compare16 temp16+1, temp16, temp1, temp
			+	
				DestroyObject
		
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
		skipCheckingThisObject_forEraseColumnLoop2:
			Compare16 pointer+1, pointer, temp1, temp
			+
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
				DestroyObject
		
			doEraseNonPlayerObjectsInThisColumnLoop
				INX
				CPX #TOTAL_MAX_OBJECTS
				BNE skipCheckingThisObject_forEraseColumnLoop

	RTS
	
checkSeamForMonsterPosition:
	;; y is loaded before subroutine.
			LDA (pointer6),y
			STA temp
			ASL
			ASL
			ASL
			ASL
			STA temp2
			LDA scrollUpdateColumn
			AND #%11110000
			CMP temp2
			BNE +noMonsterToLoadInThisColumn
				LDA temp
				AND #%11110000
				STA temp1
				CMP #%11110000
				BEQ +noMonsterToLoadInThisColumn
					CreateObjectOnScreen temp2, temp1, #$10, #$00, scrollUpdateScreen
			+noMonsterToLoadInThisColumn:
	RTS
This works on my end, but I just wanna get some confirmation.
 

AllDarnDavey

Active member
TakuikaNinja said:
Ok, it seems like the original script detects the left edge for scroll just fine, so I've put that part back into your script.

This works on my end, but I just wanna get some confirmation.
Yup, that appears to work for me as well. Strange, wonder how that part got changed on my end, pulled it from a different module or older update maybe.
 

drexegar

Member
TakuikaNinja said:
Ok, it seems like the original script detects the left edge for scroll just fine, so I've put that part back into your script.

"the code you did"

This works on my end, but I just wanna get some confirmation.


Im not too great at coding, takes me hours on hours to figure out the simplest things... What are the exact changes you made so I can put them into the shooter scroll, the shooter scroll is a little more simplified with changes.
 

drexegar

Member
AllDarnDavey said:
Okay, I might have a fix... but I need someone to confirm.

Copy this code into a new file named doUpdateCamera_RightEdgeFix.asm and assign it in place of the normal doUpdateCamera.asm:

"the code you did"

I say this MIGHT be a fix because it started working for me after I made this change and I can no longer repo the left edge glitch at all. But when I reverted the change back, it kept working. So I need someone else to confirm this fixed it, or that it doesn't and something else I did that I don't remember and now need to track down fixed it instead.

Nice, Im working on shooter mod, the code is a tad different in a few places, what kind of changes you made for the right scroll?
 

Yan

Member
Ok so I've adapted the left and right scrolling scripts and put them both on the sprite hud script (because it runs all the time and was simple enough not to mess with anything), It works well enough which is a good thing and probably what I'm going to keep using but I'm not completely sure about the drawbacks (more severe slowdowns I guess?).

What about edge reactions? For example a Screen Flag / Screen Type / Screen Speed which determines if the down edge will take you somewhere or be a bottomless pit, also if the side edges will be solid or will warp you to another screen.
 

AllDarnDavey

Active member
Yan said:
Ok so I've adapted the left and right scrolling scripts and put them both on the sprite hud script (because it runs all the time and was simple enough not to mess with anything), It works well enough which is a good thing and probably what I'm going to keep using but I'm not completely sure about the drawbacks (more severe slowdowns I guess?).

What about edge reactions? For example a Screen Flag / Screen Type / Screen Speed which determines if the down edge will take you somewhere or be a bottomless pit, also if the side edges will be solid or will warp you to another screen.

That's clever, making the sprite HUD also act like a virtual camera man tracking the player. It might be a bit more slow, but only when not moving... I'd love to see how well this idea works.

For edge reactions I think vertical edges take you to the next screen vertically. Personally, I'd just use solid tiles, kill tiles, and warp tiles to handle most edge interactions anyway (more failure proof).
 

TakuikaNinja

Active member
drexegar said:
Nice, Im working on shooter mod, the code is a tad different in a few places, what kind of changes you made for the right scroll?

Basically, it checks for the "right edge for scroll" screen flag (by ANDing ScreenFlags00 with #%00010000) and skips the rest of the scroll update routine if it's set.
Anyways, I've managed to apply this fix to the shooter module. I've already tested it on my end, so this should work:
Code:
doUpdateCamera:	
	
	LDA gameHandler
	AND #%10000000 ;;; this will skip object handling.
	BEQ +dontSkipCamHandling
		RTS
dontSkipCamHandling:

	LDA scrollByte
	ORA #%11000000 
	STA scrollByte
	
	LDA #$00
	STA tempA
	LDA #$01
	STA tempB
	
	LDA camX
	AND #%11110000
	STA tempz

	LDA scrollByte
	AND #%10100010
	BNE +scrollEngaged
		JMP skipScrollUpdate
+scrollEngaged:

	LDA scrollByte
	AND #%10000000
	BNE doHorizontalCameraUpdate
		JMP noHorizontalCameraUpdate
	doHorizontalCameraUpdate:
	
		LDA camX_lo
		CLC
		ADC tempA
		LDA camX_hi
		LDA camX
		ADC tempB
		ADC #$FF
			BCc +dontSkipCheckForScrollScreenEdge
				LDA ScreenFlags00
				AND #%00010000
				BEQ +dontSkipCheckForScrollScreenEdge
					JMP skipAllScrollSeamUpdate
		+dontSkipCheckForScrollScreenEdge
		
			;; here we have cross the screen boundary
		;;; so if there is anything that needs updating for scrolling
		;;; update it here.
			
					SwitchBank #$16
						LDA camScreen
						CLC
						ADC #$01
						TAY
						LDA CollisionTables_Map1_Lo,y
						STA temp16
						LDA CollisionTables_Map1_Hi,y
						STA temp16+1
					ReturnBank
					LDA camScreen
					CLC
					ADC #$01
					LSR
					LSR
					LSR
					LSR
					LSR
					STA temp ; bank
					SwitchBank temp
						LDY #124
						LDA (temp16),y
						STA ScreenFlags00
						
						ReturnBank
						
						CountObjects #%00001000
						BNE +dontTurnOffMonsterChecker
							
							
							;; turn off monster checker.
							;; because you already killed the monsters
							;; before getting lined up to the screen.
							
							;; unless it is a boss screen
							LDA ScreenFlags00
							AND #%00001000 ;; is it a boss flag?
							BNE +dontTurnOffMonsterChecker
							LDA ScreenFlags00
							AND #%11101111
							STA ScreenFlags00
						+dontTurnOffMonsterChecker
						
		+skipCheckForScrollScreenEdge
		
		
		; LDA temp
		; STA camX
		; LDA camX_hi
		; adc #$00
		; STA camX_hi
		
		LDA camX_lo
		clc
		adc tempA
		STA camX_lo
		LDA camX
		adc tempB
		STA camX
		LDA camX_hi
		ADC #$00
		STA camX_hi
		JSR getCamSeam
	noHorizontalCameraUpdate:


		
+skipSettingScreenFlag

	
	LDA scrollByte
	AND #%00000001
	BEQ +canUpdateScrollColumn
		JMP skipScrollUpdate
+canUpdateScrollColumn
	LDA scrollByte
	AND #%00000010
	BNE forceScrollColumnUpdate
	LDA camX
	AND #%11110000
	CMP tempz
	BNE +canUpdateScrollColumn2
		JMP skipScrollUpdate
forceScrollColumnUpdate:
	LDA scrollByte
	AND #%11111101
	STA scrollByte
+canUpdateScrollColumn2

		LDA scrollByte
		ORA #%00000101
		STA scrollByte
		;;;;;;;;;; DO SCROLL UPDATE.
		SwitchBank #$16
			LDY scrollUpdateScreen
			LDA NameTablePointers_Map1_lo,y
			STA temp16
			LDA NameTablePointers_Map1_hi,y
			STA temp16+1
			

			LDA AttributeTables_Map1_Lo,y
			STA pointer
			LDA AttributeTables_Map1_Hi,y
			STA pointer+1
			
			
			LDA CollisionTables_Map1_Lo,y
			STA pointer6
			LDA CollisionTables_Map1_Hi,y
			STA pointer6+1
		ReturnBank
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; now we have pointers for the fetch.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; We can read from the pointers to get metatile data.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;; jump to the bank
		LDA scrollUpdateScreen	
		LSR
		LSR
		LSR
		LSR
		LSR
		STA temp ; bank
		
		SwitchBank temp
			; LDX screenState
			; LDY Mon1SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation
			
			; LDY Mon2SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+1
			
			; LDY Mon3SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+2
			
			; LDY Mon4SpawnLocation,x
			; LDA (pointer6),y
			; STA scrollUpdateObjectLocation+3
			
			LDX screenState
			LDY Mon1SpawnLocation,x
			LDA Monster1ID,x
			STA tempD
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon2SpawnLocation,x
			LDA Monster2ID,x
			STA tempD
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon3SpawnLocation,x
			LDA Monster3ID,x
			STA tempD
			JSR checkSeamForMonsterPosition
			
			LDX screenState
			LDY Mon4SpawnLocation,x
			LDA Monster4ID,x
			STA tempD
			JSR checkSeamForMonsterPosition
			
			
		
		
			LDA scrollUpdateScreen
			AND #%00000001
			ASL
			ASL
			ORA #%00100000
			STA temp1 ;; temp 1 now represents the high byte of the address to place 
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			AND #%00011111
			STA temp2 ;; temp 2 now represents the low byte of the pushes.
			
			LDA scrollUpdateColumn
			LSR
			LSR
			LSR
			LSR
			STA temp3
			
			LDA #$00
			STA scrollOffsetCounter			
					
			LDX #$00 ;; will keep track of scroll update ram.
			LDA #$0F
			STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
			loop_LoadNametableMeta_column:
				LDY temp3
				LDA (temp16),y
				STA temp
				JSR doGetSingleMetaTileValues
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				STA scrollUpdateRam,x
				INX
				LDA updateTile_00
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$01
				STA scrollUpdateRam,x
				INX
				LDA updateTile_01
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$20
				STA scrollUpdateRam,x
				INX
				LDA updateTile_02
				STA scrollUpdateRam,x
				INX 
				
				LDA temp1
				STA scrollUpdateRam,x
				INX
				LDA temp2
				CLC
				ADC #$21
				STA scrollUpdateRam,x
				INX
				LDA updateTile_03
				STA scrollUpdateRam,x
				INX 
				
				DEC tempA
				LDA tempA
				BEQ +doneWithNtLoad
					;; not done with NT load.  Need more tiles.
					;;;;;;;;;;;;;;;;;;;;;;;;;;
					;; update the 16 bit position of the new place to push tiles to.
					LDA temp2
					CLC
					ADC #$40
					STA temp2
					LDA temp1
					ADC #$00
					STA temp1
					;; update the tile read location.
					LDA temp3
					CLC
					ADC #$10
					STA temp3
					JMP loop_LoadNametableMeta_column	
			+doneWithNtLoad
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;;;;; add attributes to the update list.
		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		;;;; 23 = 00100011
		;;;; 27 = 00100111
		;;;; so the last bit of scrollUpdateScreen and shift it twice to the left
		;;;; then or it with 00100000 to get the high byte of the attribute update table.
				LDA scrollUpdateScreen
				AND #%00000001
				ASL
				ASL
				;ASL
				ORA #%00100011
				STA temp1 ;; this is now the high byte of the attribute table update
				
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR
				LSR
	
				STA temp2 ;; temp 2 now represents the low byte of the pushes.
				;; don't need a temp3 to keep track of pull position, because it will be 1 to 1.
				
				LDA #$08
				STA tempA ;; will keep the track of how many tiles to draw.
					;; #$0f is an entire column.
				loop_LoadAttribute_column:
			
					LDY temp2
					LDA (pointer),y
					STA temp
					
					LDA temp1
					STA scrollUpdateRam,x
					INX
					LDA temp2
					CLC
					ADC #$c0
					STA scrollUpdateRam,x
					INX
					LDA temp
					STA scrollUpdateRam,x
					INX 
					DEC tempA
					LDA tempA
					BEQ +doneWithAtLoad
						LDA temp2
						CLC
						ADC #$08
						STA temp2
						JMP loop_LoadAttribute_column
					+doneWithAtLoad
					
					
				TXA
				STA maxScrollOffsetCounter

				LDA updateScreenData
				ORA #%00000100
				STA updateScreenData

		
				LDA scrollUpdateColumn
				LSR
				LSR
				LSR
				LSR 
				STA temp1 ;; keeps track of where to place on the collision table.
				LSR 
				STA temp2 ;; keeps track of the nubble being pulled from.
				LDX #$0F ;; keep track of how many values to load are left.
			
				LDA scrollUpdateScreen
				AND #%00000001
				BNE +doUpdateOddCt
					;; do update even CT
					;; to ct table 1
					doUpdateCtLoop
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop
							JMP +doneWithCtLoad
				+doUpdateOddCt
					;; do update odd ct
					;; to ct table 2
					doUpdateCtLoop2
						LDA temp1
						AND #%00000001
						BNE +oddCol
							LDY temp2
							LDA (pointer6),y
							LSR
							LSR
							LSR
							LSR
							JMP +pushToCol
						+oddCol
							LDY temp2	
							LDA (pointer6),y
							AND #%00001111
						
						+pushToCol:
							LDY temp1
							STA collisionTable2,y
							LDA temp1
							CLC
							ADC #$10
							STA temp1
							LDA temp2
							CLC
							ADC #$08
							STA temp2
							DEX
							BNE doUpdateCtLoop2
							JMP +doneWithCtLoad
				+doneWithCtLoad

		;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

		ReturnBank
		

skipScrollUpdate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Make sure we always update camScreen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	;JSR checkForMonsterCameraClipping
skipAllScrollSeamUpdate:
	RTS
	
	
	
getCamSeam:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Since we use camScreen in this subroutine, we'll have to make sure it's properly updated
;;; before get our column and screen.
	LDA camY_hi
	ASL
	ASL
	ASL
	ASL
	CLC
	ADC camX_hi
	STA camScreen
	
	LDA scrollByte
	AND #%01000000
	BNE +getRightScrollUpdate
		;; get left scroll update
		LDA camX
		AND #%11110000
		sec
		sbc #$70
		STA scrollUpdateColumn
		LDA camScreen
		sbc #$00
		STA scrollUpdateScreen

	RTS
	+getRightScrollUpdate

		LDA camX
		AND #%11110000
		CLC
		ADC #$80
		STA scrollUpdateColumn
		LDA camScreen
		ADC #$01
		STA scrollUpdateScreen

	RTS
	
	
	
checkForMonsterCameraClipping:

RTS
;;; use temp16 to check for cam clips
	LDA camX_hi
	AND #%00001111
	BNE notOnZeroScreen
	LDA #$00
	STA temp16
	LDA camX_hi
	STA temp16+1
	JMP +gotIt
notOnZeroScreen:
	;;; For this type of game, anything that reaches the left seam should be destroyed.
	LDA camX
	; SEC
	; SBC #$80
	STA temp16 ;; low left cam clip
	LDA camX_hi
	;AND #%00001111
	; SBC #$00
	AND #%00001111
	STA temp16+1 ;; high left cam clip
+gotIt:	
	LDA camX
	CLC
	ADC #$90
	STA pointer ;; low right cam clip
	LDA camX_hi
	
	ADC #$01
	AND #%00001111
	STA pointer+1 ;; high right cam clip

	LDX #$00
	skipCheckingThisObject_forEraseColumnLoop
		cpx player1_object
		BEQ doEraseNonPlayerObjectsInThisColumnLoop
			LDA Object_status,x
			AND #%10000000
			BEQ doEraseNonPlayerObjectsInThisColumnLoop
			;; check this monster's position
			LDA Object_x_hi,x
			STA temp
			LDA Object_screen,x
			AND #%00001111
			STA temp1
			Compare16 temp16+1, temp16, temp1, temp
			+	
				DestroyObject
				
		
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
		;; skip erasing from rightmost column.
		skipCheckingThisObject_forEraseColumnLoop2:
			Compare16 pointer+1, pointer, temp1, temp
			+
				JMP doEraseNonPlayerObjectsInThisColumnLoop
			++
				DestroyObject
		
			doEraseNonPlayerObjectsInThisColumnLoop
				INX
				CPX #TOTAL_MAX_OBJECTS
				BNE skipCheckingThisObject_forEraseColumnLoop

	RTS
	
checkSeamForMonsterPosition:
	;; y is loaded before subroutine.
			LDA (pointer6),y
			STA temp
			ASL
			ASL
			ASL
			ASL
			STA temp2
			LDA scrollUpdateColumn
			AND #%11110000
			CMP temp2
			BNE +noMonsterToLoadInThisColumn
				LDA temp
				AND #%11110000
				STA temp1
				CMP #%11110000
				BEQ +noMonsterToLoadInThisColumn
					LDY tempD
					LDA (pointer6),y
					STA tempD
					CreateObjectOnScreen temp2, temp1, tempD, #$00, scrollUpdateScreen
			+noMonsterToLoadInThisColumn:
	RTS
 
Top Bottom