;
;  gamePlayer.s
;  BuGS
;
;  Created by Jeremy Rand on 2020-10-28.
;Copyright © 2020 Jeremy Rand. All rights reserved.
;

		case on
        mcopy gamePlayer.macros
        keep gamePlayer

gamePlayer start
		using globalData
		using tileData
		using screenData
		
PLAYER_EXPLOSION_FRAME_COUNT	equ 3
PLAYER_RESTART_LEVEL_FRAME_COUNT	equ 20
		
		
initPlayer entry
		ldy #STARTING_NUM_LIVES
		sty numLives
		stz playerIgnoreFirstPoll
		stz playerNum
		ldx #P1_LIVES_OFFSET
initPlayer_loop1 anop
		lda #TILE_PLAYER
		sta tileType,x
		phy
		_dirtyNonGameTile
		ply
		dex
		dex
		dey
		bne initPlayer_loop1
		
		lda isSinglePlayer
		beq initPlayer_done
		ldy #STARTING_NUM_LIVES
		sty numLives+2
		ldx #P2_LIVES_OFFSET
initPlayer_loop2 anop
		lda #TILE_PLAYER
		sta tileType,x
		phy
		_dirtyNonGameTile
		ply
		dex
		dex
		dey
		bne initPlayer_loop2
		
initPlayer_done anop
		jmp scoreSwitchPlayer
		
		
playerLevelStart entry
		stz playerIgnoreFirstPoll
		lda #PLAYER_STATE_ONSCREEN
		sta playerState
		lda #STARTING_MOUSE_X
		sta mouseX
		lda #STARTING_MOUSE_Y
		sta mouseY
		asl a
		tay
		lda mouseX
		lsr a
		adc mouseYAddress,y
		sta mouseAddress
		lda #1
		sta mouseDown
		ldx playerNum
		dec numLives,x
		cpx #PLAYER_ONE
		beq playerLevelStart_playerOne
		lda #P2_LIVES_OFFSET
		bra playerLevelStart_cont
playerLevelStart_playerOne anop
		lda #P1_LIVES_OFFSET
playerLevelStart_cont anop
		sec
		sbc numLives,x
		sec
		sbc numLives,x
		tax
		lda #TILE_EMPTY
		sta tileType,x
		_dirtyNonGameTile
		rtl
		
		
playerAddLife entry
		ldx playerNum
		cpx #PLAYER_ONE
		beq playerAddLife_playerOne
		lda #P2_LIVES_OFFSET
		bra playerAddLife_cont
playerAddLife_playerOne anop
		lda #P1_LIVES_OFFSET
playerAddLife_cont anop
		sec
		sbc numLives,x
		sec
		sbc numLives,x
		inc numLives,x
		tax
		lda #TILE_PLAYER
		sta tileType,x
		_dirtyNonGameTile
		jmp playExtraLifeSound
		

updatePlayer entry
		lda gameState
		bne updatePlayer_gameRunning
		rtl
updatePlayer_gameRunning anop
		lda playerState
		cmp #PLAYER_STATE_NONE
		bne updatePlayer_notNone
		rtl
updatePlayer_notNone anop
		cmp #PLAYER_STATE_EXPLODING
		beq updatePlayer_exploding
		jmp updatePlayer_onScreen
updatePlayer_exploding anop
		lda playerFrameCount
		beq updatePlayer_nextExplosion
		dec a
		sta playerFrameCount
		bra updatePlayer_drawExplosion
updatePlayer_nextExplosion anop
		lda playerExplosionOffset
		beq updatePlayer_doneExplosion
		sec
		sbc #4
		sta playerExplosionOffset
		lda #PLAYER_EXPLOSION_FRAME_COUNT
		sta playerFrameCount
		bra updatePlayer_drawExplosion
updatePlayer_doneExplosion anop
		lda #PLAYER_STATE_NONE
		sta playerState
		rtl

updatePlayer_drawExplosion anop
		lda mouseAddress
		sec
		sbc #SCREEN_ADDRESS
		and #$fffc
		tax
		lda >screenToTileOffset,x
		tax
		lda #TILE_STATE_DIRTY
		sta tileDirty,x
		ldy tileBelow,x
		cpy #INVALID_TILE_NUM
		beq updatePlayer_drawExplosionSkipBelow1
		sta tileDirty,y
updatePlayer_drawExplosionSkipBelow1 anop
		ldy tileRight,x
		sta tileDirty,y
		ldx tileBelow,y
		cpx #INVALID_TILE_NUM
		beq updatePlayer_drawExplosionSkipBelow2
		sta tileDirty,x
updatePlayer_drawExplosionSkipBelow2 anop
		ldx tileRight,y
		cpx #RHS_FIRST_TILE_OFFSET
		bge updatePlayer_drawExplosionSkipBelow3
		sta tileDirty,x
		ldy tileBelow,x
		cpy #INVALID_TILE_NUM
		beq updatePlayer_drawExplosionSkipBelow3
		sta tileDirty,y
updatePlayer_drawExplosionSkipBelow3 anop
		ldy mouseAddress
		ldx playerExplosionOffset
		lda shipExplosionJumpTable,x
		sta jumpInst+1
		lda shipExplosionJumpTable+2,x
		sta jumpInst+3
jumpInst anop
		jmp >shipExplosion1
		nop
		
updatePlayer_onScreen anop
		ldx #0
		ldy #0
; This code for reading the mouse data is based on some code which John Brooks helpfully provided, although I did things
; quite differently because I have different needs.  But this is about as low cost as can be made for reading the position
; of the mouse.
		short i,m
		phb
		lda #$e0
		pha
		plb
		lda MOUSE_STATUS
		bpl updatePlayer_noMousePoll
		and #2
		bne updatePlayer_mouseYOnly
		ldx MOUSE_DATA_REG
updatePlayer_mouseYOnly anop
		ldy MOUSE_DATA_REG
updatePlayer_doneMousePoll anop
		plb
		long i,m
		lda playerIgnoreFirstPoll
		bne updatePlayer_handleDeltas
		lda #1
		sta playerIgnoreFirstPoll
		jmp updatePlayer_skipDeltas

updatePlayer_noMousePoll anop
		plb
		long i,m
		jmp updatePlayer_skipDeltas
		
updatePlayer_handleDeltas anop
; The X and Y register also has a bit in each which indicates whether a
; mouse button is down or not.
		txa
		and #$0080
		beq updatePlayer_mouseDown
		tya
		and #$0080
		beq updatePlayer_mouseDown
		lda #1
		sta mouseDown
		bra updatePlayer_doY
updatePlayer_mouseDown anop
		stz mouseDown

updatePlayer_doY anop
; The Y register has the deltaY
		tya
		bit #$40
		bne updatePlayer_negY
		and #$3f
		inc a
		lsr a
		bne updatePlayer_hasPosY
		jmp updatePlayer_doX
updatePlayer_hasPosY anop
		cmp #9
		blt updatePlayer_posYNoClamp
		lda #8
updatePlayer_posYNoClamp anop
		clc
		adc mouseY
		cmp #MOUSE_MAX_Y
		blt updatePlayer_checkBelow
		lda #MOUSE_MAX_Y-1
updatePlayer_checkBelow anop
		sta mouseY
		asl a
		tay
		lda mouseYTileBelow,y
		sta mouseTemp
		lda mouseX
		asl a
		tay
		lda mouseXTileLeft,y
		clc
		adc mouseTemp
		phx
		tax
		lda tileType,x
		bne updatePlayer_blockedBelow
		lda mouseXTileRight,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		bne updatePlayer_blockedBelow
		plx
		bra updatePlayer_doX
updatePlayer_blockedBelow anop
		plx
		lda mouseY
		dec a
		and #$fff8
		sta mouseY
		bra updatePlayer_doX
		
updatePlayer_negY anop
		ora #$ffc0
		dec a
		lsr a
		ora #$8000
		cmp #$fff8
		bge updatePlayer_negYNoClamp
		lda #$fff8
updatePlayer_negYNoClamp anop
		clc
		adc mouseY
		bpl updatePlayer_checkAbove
		lda #0
updatePlayer_checkAbove anop
		sta mouseY
		asl a
		tay
		lda mouseYTileAbove,y
		sta mouseTemp
		lda mouseX
		asl a
		tay
		lda mouseXTileLeft,y
		clc
		adc mouseTemp
		phx
		tax
		lda tileType,x
		bne updatePlayer_blockedAbove
		lda mouseXTileRight,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		bne updatePlayer_blockedAbove
		plx
		bra updatePlayer_doX
updatePlayer_blockedAbove anop
		plx
		lda mouseY
		clc
		adc #TILE_PIXEL_HEIGHT
		and #$fff8
		sta mouseY

updatePlayer_doX anop
; The X register has the deltaX
		txa
		bit #$40
		bne updatePlayer_negX
		and #$3f
		inc a
		lsr a
		bne updatePlayer_hasPosX
		jmp updatePlayer_skipDeltas
updatePlayer_hasPosX anop
		cmp #9
		blt updatePlayer_posXNoClamp
		lda #8
updatePlayer_posXNoClamp anop
		clc
		adc mouseX
		cmp #MOUSE_MAX_X
		blt updatePlayer_checkRight
		lda #MOUSE_MAX_X-1
updatePlayer_checkRight anop
		sta mouseX
		asl a
		tay
		lda mouseXTileRight,y
		sta mouseTemp
		lda mouseY
		asl a
		tay
		lda mouseYTileAbove,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		bne updatePlayer_blockedRight
		lda mouseYTileBelow,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		beq updatePlayer_skipDeltas
updatePlayer_blockedRight anop
		lda mouseX
		dec a
		and #$fff8
		sta mouseX
		bra updatePlayer_skipDeltas
		
updatePlayer_negX anop
		ora #$ffc0
		dec a
		lsr a
		ora #$8000
		cmp #$fff8
		bge updatePlayer_negXNoClamp
		lda #$fff8
updatePlayer_negXNoClamp anop
		clc
		adc mouseX
		bpl updatePlayer_checkLeft
		lda #0
updatePlayer_checkLeft anop
		sta mouseX
		asl a
		tay
		lda mouseXTileLeft,y
		sta mouseTemp
		lda mouseY
		asl a
		tay
		lda mouseYTileAbove,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		bne updatePlayer_blockedLeft
		lda mouseYTileBelow,y
		clc
		adc mouseTemp
		tax
		lda tileType,x
		beq updatePlayer_skipDeltas
updatePlayer_blockedLeft anop
		lda mouseX
		clc
		adc #TILE_PIXEL_WIDTH
		and #$fff8
		sta mouseX

updatePlayer_skipDeltas anop
		lda mouseDown
		bne updatePlayer_notShooting
		jsl maybeShoot
updatePlayer_notShooting anop
		lda mouseY
		asl a
		tay
		lda mouseX
		lsr a
		bcs updatePlayer_shift
		adc mouseYAddress,y
		sta mouseAddress
		tay
		jsl drawShip
		bra updatePlayer_dirty
		
updatePlayer_shift anop
		adc mouseYAddress,y
		dec a
		sta mouseAddress
		tay
		jsl drawShipShift
		
updatePlayer_dirty anop
		bne updatePlayer_collision
		jmp updatePlayer_noCollision
updatePlayer_collision anop
		lda #PLAYER_STATE_EXPLODING
		sta playerState

; Figure out which kind of bug collided with the player and cause it to
; explode.
		txa
		sec
		sbc #SCREEN_ADDRESS
		and #$fffc
		tax
		lda >screenToTileOffset,x
		jsl isSpiderCollision
		bcc updatePlayer_notSpiderCollision
		jsl explodeSpider
		bra updatePlayer_explode
updatePlayer_notSpiderCollision anop
		jsl isFleaCollision
		bcc updatePlayer_notFleaCollision
		jsl explodeFlea
		bra updatePlayer_explode
		
updatePlayer_notFleaCollision anop
		jsl isSegmentCollision
		bcc updatePlayer_explode
		jsl explodeSegment
		
updatePlayer_explode anop
		lda mouseAddress
		sec
		sbc #TILE_BYTE_WIDTH/2
		sta mouseAddress
		sec
		sbc #SCREEN_ADDRESS
		and #$fffc
		tax
		lda >screenToTileOffset,x
		cmp #RHS_FIRST_TILE_OFFSET
		bge updatePlayer_explosionOffLeft
		tay
		ldx tileRight,y
		ldy tileRight,x
		cpy #RHS_FIRST_TILE_OFFSET
		blt updatePlayer_contCollision
		lda mouseAddress
		dec a
		and #$fffc
		sta mouseAddress
		bra updatePlayer_contCollision
		
updatePlayer_explosionOffLeft anop
		lda mouseAddress
		clc
		adc #TILE_BYTE_WIDTH
		and #$fffc
		sta mouseAddress
		
updatePlayer_contCollision anop
		lda #PLAYER_EXPLOSION_FRAME_COUNT
		sta playerFrameCount
		lda #SHIP_EXPLOSION_LAST_OFFSET
		sta playerExplosionOffset
		jsl playDeathSound
		jmp updatePlayer_exploding
		
updatePlayer_noCollision anop
		lda mouseAddress
		sec
		sbc #SCREEN_ADDRESS
		and #$fffc
		tax
		lda >screenToTileOffset,x
		tax
		lda #TILE_STATE_DIRTY
		cpx #RHS_FIRST_TILE_OFFSET
		bge updatePlayer_tileOffscreen1
		sta tileDirty,x
updatePlayer_tileOffscreen1 anop
		ldy tileRight,x
		cpy #RHS_FIRST_TILE_OFFSET
		bge updatePlayer_tileOffscreen2
		sta tileDirty,y
updatePlayer_tileOffscreen2 anop
		ldy tileBelow,x
		cpy #INVALID_TILE_NUM
		beq updatePlayer_done
		sta tileDirty,y
		ldx tileRight,y
		cpx #RHS_FIRST_TILE_OFFSET
		bge updatePlayer_done
		sta tileDirty,x
		
updatePlayer_done anop
		rtl


playerFrameCount 		dc i2'0'
playerExplosionOffset	dc i2'0'
playerIgnoreFirstPoll   dc i2'0'
mouseDown	dc i2'0'
mouseTemp 	dc i2'0'


SHIP_EXPLOSION_LAST_OFFSET	equ 7*4

shipExplosionJumpTable anop
		dc i4'shipExplosion8'
		dc i4'shipExplosion7'
		dc i4'shipExplosion6'
		dc i4'shipExplosion5'
		dc i4'shipExplosion4'
		dc i4'shipExplosion3'
		dc i4'shipExplosion2'
		dc i4'shipExplosion1'


        end
