;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; A projectile that will keep moving at the speed set when it's spawned, or switch directions
; to aim at Mario after some time has passed.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

			!FreeRAM		= $7EC400	; needs to be at least 20 (decimal) bytes
								; THIS MUST BE SET TO THE SAME VALUE AS THE DEFINE IN doccroc.asm!

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

			!RAM_FrameCounterB	= $14

			!RAM_MarioPowerUp	= $19

			!RAM_ScreenBndryXLo	= $1A
			!RAM_ScreenBndryXHi	= $1B
			!RAM_ScreenBndryYLo	= $1C
			!RAM_ScreenBndryYHi	= $1D

			!RAM_IsDucking		= $73

			!RAM_MarioXPos		= $94
			!RAM_MarioXPosHi	= $95
			!RAM_MarioYPos		= $96
			!RAM_MarioYPosHi	= $97

			!RAM_SpritesLocked	= $9D

			!OAM_DispX		= $0200
			!OAM_DispY		= $0201
			!OAM_Tile		= $0202
			!OAM_Prop		= $0203
			!OAM_TileSize		= $0420

			!RAM_ClusterYPosLo	= $1E02
			!RAM_ClusterYPosHi	= $1E2A
			!RAM_ClusterXPosLo	= $1E16
			!RAM_ClusterXPosHi	= $1E3E
			!RAM_ClusterYSpeed	= $1E52
			!RAM_ClusterXSpeed	= $1E66
			!RAM_ClusterYSpeedFrac	= $1E7A
			!RAM_ClusterXSpeedFrac	= $1E8E
			!RAM_DirectionTimer	= !FreeRAM

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

OAMIndexes:		db $40,$44,$48,$4C,$D0,$D4,$D8,$DC,$80,$84
			db $88,$8C,$B0,$B4,$B8,$BC,$C0,$C4,$C8,$CC

Tilemap:		db $2C,$2E,$4C,$4E

Properties:		db $25,$2B

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

Main:			JSR Graphics
			JSR SubOffScreen
			LDA !RAM_SpritesLocked
			BNE .Return
			TYX
			LDA !RAM_DirectionTimer,x
			BEQ .DontChangeDir
			DEC A
			STA !RAM_DirectionTimer,x
			CMP #$01
			BNE .DontChangeDir
			JSR AimAtMario

.DontChangeDir		JSR UpdatePos
			JSR MarioInteract
			BCS .Return
			PHY
			JSL $00F5B7
			PLY

.Return			RTS

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

Graphics:		LDX.w OAMIndexes,y

			LDA !RAM_ClusterXPosLo,y
			SEC
			SBC !RAM_ScreenBndryXLo
			STA !OAM_DispX,x

			LDA !RAM_ClusterYPosLo,y
			SEC
			SBC !RAM_ScreenBndryYLo
			STA !OAM_DispY,x

			PHY
			TYA
			CLC
			ADC !RAM_FrameCounterB
			LSR
			LSR
			AND #$03
			TAY
			LDA.w Tilemap,y
			STA !OAM_Tile,x
			PLY

			PHX
			PHY
			TYX
			LDY #$00
			LDA !RAM_DirectionTimer,x
			BEQ .Normal
			INY
.Normal			LDA Properties,y
			PLY
			PLX
			STA !OAM_Prop,x

			PHX
			TXA
			LSR
			LSR
			TAX
			LDA #$02
			STA !OAM_TileSize,x
			PLX

			LDA $1493
			BEQ .Return

			LDA !OAM_DispY,x
			CMP #$F0
			BCC .Return

			LDA #$00
			STA $1892,y

.Return			RTS

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

UpdatePos:		LDA !RAM_ClusterYSpeed,y
			ASL
			ASL
			ASL
			ASL
			CLC
			ADC !RAM_ClusterYSpeedFrac,y
			STA !RAM_ClusterYSpeedFrac,y
			PHP
			LDA !RAM_ClusterYSpeed,y
			LSR
			LSR
			LSR
			LSR
			CMP #$08
			LDX #$00
			BCC .Label1
			ORA #$F0
			DEX

.Label1			PLP
			ADC !RAM_ClusterYPosLo,y
			STA !RAM_ClusterYPosLo,y
			TXA
			ADC !RAM_ClusterYPosHi,y
			STA !RAM_ClusterYPosHi,y

			LDA !RAM_ClusterXSpeed,y
			ASL
			ASL
			ASL
			ASL
			CLC
			ADC !RAM_ClusterXSpeedFrac,y
			STA !RAM_ClusterXSpeedFrac,y
			PHP
			LDA !RAM_ClusterXSpeed,y
			LSR
			LSR
			LSR
			LSR
			CMP #$08
			LDX #$00
			BCC .Label2
			ORA #$F0
			DEX

.Label2			PLP
			ADC !RAM_ClusterXPosLo,y
			STA !RAM_ClusterXPosLo,y
			TXA
			ADC !RAM_ClusterXPosHi,y
			STA !RAM_ClusterXPosHi,y

			RTS

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

MarioInteract:		LDA !RAM_ClusterXPosLo,y
			STA $02
			LDA !RAM_ClusterXPosHi,y
			STA $03

			LDA !RAM_ClusterYPosLo,y
			STA $04
			LDA !RAM_ClusterYPosHi,y
			STA $05

			REP #$20
			LDA !RAM_MarioXPos
			SEC
			SBC $02
			CLC
			ADC #$000C
			CMP #$0018
			BCS .Return

			LDA #$0010
			LDX !RAM_IsDucking
			BNE .Continue
			LDX !RAM_MarioPowerUp
			BEQ .Continue
			LDA #$0020

.Continue		STA $00
			LDA !RAM_MarioYPos
			SEC
			SBC $04
			CLC
			ADC #$0018
			CMP $00

.Return			SEP #$20
			RTS

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

AimAtMario:		JSR GetSpeeds
			LDA $00
			STA !RAM_ClusterYSpeed,y
			LDA $01
			STA !RAM_ClusterXSpeed,y
			RTS

GetSpeeds:		LDA #$20				;\ set speed
			STA $01					;/
			STY $00
			PHX
			PHY
			JSR SubVertPos				; $0E = vertical distance to Mario
			STY $02					; $02 = vertical direction to Mario
			LDA $0E					;\ $0C = vertical distance to Mario, positive
			BPL Code01BF7C				; |
			EOR #$FF				; |
			CLC					; |
			ADC #$01				; |
Code01BF7C:		STA $0C					;/
			JSR SubHorizPos				; $0F = horizontal distance to Mario
			STY $03					; $03 = horizontal direction to Mario
			LDA $0F					;\ $0D = horizontal distance to Mario, positive
			BPL Code01BF8C				; |
			EOR #$FF				; |
			CLC					; |
			ADC #$01				; |
Code01BF8C:		STA $0D					;/
			LDY #$00
			LDA $0D					;\ if vertical distance less than horizontal distance,
			CMP $0C					; |
			BCS Code01BF9F				;/ branch
			INY					; set y register
			PHA					;\ switch $0C and $0D
			LDA $0C					; |
			STA $0D					; |
			PLA					; |
			STA $0C					;/
Code01BF9F:		LDA #$00				;\ zero out $00 and $0B
			STA $0B					; | ...what's wrong with STZ?
			STA $00					;/
			LDX $01					;\ divide $0C by $0D?
Code01BFA7:		LDA $0B					; |\ if $0C + loop counter is less than $0D,
			CLC					; | |
			ADC $0C					; | |
			CMP $0D					; | |
			BCC Code01BFB4				; |/ branch
			SBC $0D					; | else, subtract $0D
			INC $00					; | and increase $00
Code01BFB4:		STA $0B					; |
			DEX					; |\ if still cycles left to run,
			BNE Code01BFA7				;/ / go to start of loop
			TYA					;\ if $0C and $0D was not switched,
			BEQ Code01BFC6				;/ branch
			LDA $00					;\ else, switch $00 and $01
			PHA					; |
			LDA $01					; |
			STA $00					; |
			PLA					; |
			STA $01					;/
Code01BFC6:		LDA $00					;\ if horizontal distance was inverted,
			LDY $02					; | invert $00
			BEQ Code01BFD3				; |
			EOR #$FF				; |
			CLC					; |
			ADC #$01				; |
			STA $00					;/
Code01BFD3:		LDA $01					;\ if vertical distance was inverted,
			LDY $03					; | invert $01
			BEQ Code01BFE0				; |
			EOR #$FF				; |
			CLC					; |
			ADC #$01				; |
			STA $01					;/
Code01BFE0:		PLY
			PLX
			RTS					; return

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

SubHorizPos:		LDY #$00
			LDX $00
			LDA !RAM_MarioXPos
			SEC
			SBC !RAM_ClusterXPosLo,x
			STA $0F
			LDA !RAM_MarioXPosHi
			SBC !RAM_ClusterXPosHi,x
			BPL .Return
			INY
.Return			RTS

SubVertPos:		REP #$20
			LDX $00
			LDA !RAM_MarioYPos
			CLC
			ADC.w #$0010
			STA $0C
			SEP #$20

			LDY #$00
			LDA $0C
			SEC
			SBC !RAM_ClusterYPosLo,x
			STA $0E
			LDA $0D
			SBC !RAM_ClusterYPosHi,x
			BPL .Return
			INY
.Return			RTS					; return

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

SubOffScreen:		LDA !RAM_ClusterYPosLo,y	; y pos (low)
			STA $00				; store to scratch
			LDA !RAM_ClusterYPosHi,y	; y pos (high)
			STA $01				; 
			LDA !RAM_ClusterXPosLo,y	; x pos (low)
			STA $02				;
			LDA !RAM_ClusterXPosHi,y	; x pos (high)
			STA $03

			REP #$20		; 16 bit A
			LDA $00			; sprite y
			SEC
			SBC $1C			; layer 1 y
			BMI .Offscreen		; kill self if offscreen
			CMP #$00F0
			BCS .Offscreen
			STA $00

			LDA $02			; sprite x
			SEC
			SBC $1A			; layer 1 x
			BMI .Offscreen		; kill self if offscreen
			CMP #$00F0
			BCS .Offscreen
			STA $01
	
			SEP #$20		; 8 bit A
			RTS

.Offscreen		SEP #$20		; 8 bit A
			LDA #$00		; kill sprite
			STA $1892,y
			RTS