LASER_MAX_SEGMENTS	EQU 24

macro LaserNextSegment
	ld A,(current_laser) ;get segment
	inc A
	cp LASER_MAX_SEGMENTS
	jr c,$+3
	xor A
	ld (current_laser),A
mend

;***************************
;*** CLEANUP LASER STATE ***
;***************************
.LASER_Init
	ld B,LASER_MAX_SEGMENTS
	ld HL,LaserBuffer
	ld C,5
.LASER_InitLoop
	ld (HL),0
	ld A,C
	add L
	ld L,A
	djnz LASER_InitLoop
	
	xor A
	ld (laserA),A
	ld (laserB),A
	ld (laserC),A
	ld (FIRE_A),A
	ld (FIRE_B),A
	ld (CIRC_State),A
	
	ret
	

;******************
;*** Fire laser ***
;******************
; HL = laser address
; BC = X & Y
; A = direction
.LASER_Fire
	ex AF,AF'
	ld A,(HL)
	or A
	jr nz,LASER_FireNot	
	ex AF,AF'
	
	ld (HL),5 ;max bounds
	inc HL
	ld (HL),C
	inc HL
	ld (HL),B
	inc HL
	ld (HL),A
	
	ld A,sfx_laserStart
	call SND_SfxPlay
	
.LASER_FireNot	
	ex AF,AF'
	ret

;************************
;*** Draw laser segments ***
;************************
.LAZER_Draw
	ld A,(BALLPOW)	;check if weapon type is 1 or 3 to update laser draw
	and 1
	ret z
	
;if power not low nor high - no laser !
	ld A,(BALL2)
	ld B,A
	ld A,(BALL3)
	or B
	ret z
	
;check max segments

	ld HL,LaserBuffer
LAZER_MaxSegments	EQU $+2
	ld BC,#1805		;max 24 segments , 5 bytes per segment
	
.LAZER_Draw_Loop
	ld A,(HL)
	and 15		;keep only 4 bits
	jr z,LAZER_DrawEmpty
		
	dec (HL)	;decrement sprite count
	
	bit 7,(HL)	;is fire ?
	jr nz,LAZER_Fire
	
	inc L
	ld E,(HL)	;cell address in DE
	inc L
	ld D,(HL)
	
	ld A,(DE)
	and %10000001
	jr nz,LAZER_DoDamage	;is empty ?
	
	ex DE,HL	;let's write sprite
	
	ld (HL),63 ;1 ;is a non solid compiled sprite
	inc H
	;ld (HL),#C0	;main bank
	inc H
	inc E
	ld A,(DE)	;get sprite low
	ld (HL),A
	inc H
	inc E
	ld A,(DE)	;high
	ld (HL),A
	inc H
	ld (HL),64	;neutral master
	
	ex DE,HL	
	inc L ;next sprite !
	djnz LAZER_Draw_Loop
	jr LAZER_DrawFinish
	
.LAZER_Fire

	inc L
	ld E,(HL)	;cell address in DE
	inc L
	ld D,(HL)
	
	ex AF,AF'	;keep A
	
	ld A,(DE)
	;bit 6,A
	;jr nz,LAZER_Fire_SkipEgg
	and %10000001
	jr nz,LAZER_DoDamage	;is empty ?
;.LAZER_Fire_SkipEgg	
	ex AF,AF'

;compute address to get sprite
	dec A	;0 to 9
	jr z,LAZER_Fire_phaseOK	;is last ?
	
	ld A,(FRAME)
	and 3	;cycle from 1 to 4
	inc A
	
.LAZER_Fire_phaseOK
	
	add A	;*2
	inc L
	add (HL)	;we are on sprite low
	inc L
	push HL
	ld H,(HL)	;so we got sprite address
	ld L,A
	
	;slighty modified laser drawing code
	ex DE,HL	;let's write sprite
	
	ld (HL),63 ;1 ;is a non solid compiled sprite
	inc H
	;ld (HL),#C0	;main bank
	inc H
	ld A,(DE)	;get sprite low
	ld (HL),A
	inc H
	inc E
	ld A,(DE)	;high
	ld (HL),A
	inc H
	ld (HL),64	;neutral master
	
	pop HL
	inc L ;next sprite !
	djnz LAZER_Draw_Loop
	jr LAZER_DrawFinish
	
.LAZER_DrawEmpty
	ld A,C
	add L
	ld L,A	
	djnz LAZER_Draw_Loop
.LAZER_DrawFinish	
	ret
	
.LAZER_DoDamage
	;get master first
	inc D	;bank
	inc D	;low addr
	inc D	;high
	inc D	;master
	ld A,(DE)
	or A
	jr z,LAZER_NoDamage ;master = 0 , no damage
	cp 32
	jr nc,LAZER_NoDamage ;not an enemy ,ignore !
	
	;get enemy slot first
 	DEC A
 	LD E,A
	ADD A
 	ADD A
 	ADD A
 	ADD E
 	LD D,SEQBUFF_high
	LD E,A
	
	;check life
	ld A,(DE)
	and 63
	or A
	jr z,LAZER_NoDamage
	
	dec A
	ld (DE),A
	ld A,8
	add E
	ld E,A
	ex DE,HL
	set 7,(HL)	;mark as hit
	ex DE,HL

.LAZER_NoDamage
	inc L
	inc L
	inc L
	;djnz LAZER_Draw_Loop
	dec B
	jp nz,LAZER_Draw_Loop
	jr LAZER_DrawFinish

	

;**********************
;*** Laser management ***
;**********************
;upadate lazer
;HL = laser address
.LAZER_Update
	push HL
	call LASER_Update_ReEnter
	pop HL


.LASER_Update_ReEnter	

	ld A,(HL)	;get state
	or A
	ret z
	
	;save lazer in IY for bounding count
	push HL
	pop IY
	
	;break
	
	push HL
	
	inc HL	
	ld B,(HL)	;x
	inc HL
	ld C,(HL)	;y
	inc HL
	ld A,(HL)	;direction
	
	ld E,A
	ex AF,AF'	;save direction
	ld A,E
	
	;get direction table in IX
	push HL	
	add A,A
	add	LaserMoveTable_Low
	ld	L,A
	ld H,LaserMoveTable_High
	
	ld A,(HL)
	ld IXL,A
	inc HL
	ld A,(HL)
	ld IXH,A
	pop HL
	
	;let's do the move !
	call LAZER_UpdateDoMove
	
	pop HL
	
	ld A,B
	cp	32
	jr nc,LAZER_Kill
	ld A,C
	cp 20
	jr nc,LAZER_Kill
	
	inc HL
	ld (HL),B	;x
	inc HL
	ld (HL),C	;y
	inc HL
	ex AF,AF'	;get direction
	ld (HL),A
	
	;compute new direction table to get sprite
	add A,A
	add	LaserMoveTable_Low
	ld	L,A
	ld H,LaserMoveTable_High
	
	ld C,(HL)
	inc L
	ld B,(HL)
	
	inc BC
	inc BC	;BC point on sprite , DE on cell address
	

	;write out in laser table
	;ld A,(current_laser) ;get segment
	;inc A
	;and 31
	;ld (current_laser),A
.debug_test
	LaserNextSegment
	
	ld L,A
	add A	;2
	add A	;4
	add L	;5
	ld L,A
	ld H,LaserBuffer_High ;current laser in HL

laser_life	EQU $+1	
	ld (HL),10	;life
	inc L
	ld (HL),E	;cell address low
	inc L
	ld (HL),D	;high
	inc L
	ld A,(BC)	;sprite low
	ld (HL),A
	inc L
	inc BC
	ld A,(BC)	;high
	ld (HL),A
	
	;temp stuff
	;ex DE,HL
	;ld (HL),1 ;not solid
	;inc H
	;ld (HL),#C0
	;inc H
	;ld A,(BC)
	;inc BC
	;ld (HL),A
	;inc H
	;ld A,(BC)
	;ld (HL),A
	;inc H
	;ld (HL),64	;neutral
	
	ret
	
.LAZER_Kill
	ld (HL),0
	ret
	
;compute next move 
;A' = direction
; B = X , C = Y
; IX = move table
;return new position in BC
;return new address in DE
;new direction in A'
.LAZER_UpdateDoMove	
	ld (LAZER_SaveCurrentPos),BC	;save pos
	ld A,(IX+0)	;x move
	add B
	cp 32
	jr nc,LAZER_KillOnMove
	ld B,A	
	ld A,(IX+1)	;y move
	add C
	cp 20
	jr nc,LAZER_KillOnMove ;kill if out of screen
	ld C,A	
	;check if we encounter something solid (solid flag+master 0)
	call LAZER_ComputePos
	ld A,(HL)
	;bit 6,A		;is destructible ?
	;jr nz,LAZER_BoundingEventOnEgg
	and %10000001
	jr z,LAZER_ValidateMove	;not solid ? validate
	ld (LAZER_SaveCurrentPos+2),HL ;save cell address
	ld D,H	;save H
	;else check master
	inc H	;bank
	inc H	;low addr
	inc H	;high addr
	inc H	;master
	ld A,(HL)	
	or A
	jr z,LAZER_BoundingEvent	;if bounding surface (master=0) , continue else return
	cp 32	;is egg ?
	jr z,LAZER_BoundingEvent
	ld H,D
.LAZER_ValidateMove
	ex DE,HL	;new address in DE
	;ex AF,AF'
	ret
.LAZER_KillOnMove
	pop HL
	pop HL
	ld (HL),0
	ret
.LAZER_BoundingEventOnEgg
	ld (HL),4
	inc H
	inc H
	inc H
	inc H
	ld (HL),64	;neutral master !
.LAZER_BoundingEvent

	ld A,sfx_laserBounce
	call SND_SfxPlay

	;break
	ld A,(IY)
	dec A
	ld (IY),A
	or A
	jr z,LAZER_KillOnMove	;if null , kill laser !
;compute first event
	ld BC,(LAZER_SaveCurrentPos)
	ld A,(IX+4)	;x move
	add B
	cp 32
	jr nc,LAZER_KillOnMove ;kill if out of screen
	ld B,A	
	ld A,(IX+5)	;y move
	add C
	cp 20
	jr nc,LAZER_KillOnMove ;kill if out of screen
	ld C,A	
	ld (LAZER_Result0+1),BC
	call LAZER_IsSolid	
	ld (LAZER_Result0),A
	ld (LAZER_Result0+3),HL
	
;compute second event
	ld BC,(LAZER_SaveCurrentPos)
	ld A,(IX+6)	;x move
	add B
	ld B,A	
	ld A,(IX+7)	;y move
	add C
	ld C,A	
	call LAZER_IsSolid
	
	ld E,A
	ld A,(LAZER_Result0)
	
	cp E
	jr c,LAZER_SolutionB		;A<B
	jr z,LAZER_SolutionEqual	;A=B

	;break
	
	ex DE,HL	;get cell address in DE
	ld A,(IX+10)
	ex AF,AF'
	ret
	
.LAZER_SolutionB
	ld BC,(LAZER_Result0+1)
	ld DE,(LAZER_Result0+3)
	ld A,(IX+9)
	ex AF,AF'
	ret

.LAZER_SolutionEqual
;break
	ld BC,(LAZER_SaveCurrentPos)
	ld DE,(LAZER_SaveCurrentPos+2)
	ld A,(IX+8)
	ex AF,AF'
	ret



;in B=x , C=y
;out A = options (0=empty , 1=not empty) 
; HL =cell address
.LAZER_IsSolid	
	call LAZER_ComputePos
	
	push HL
	ld A,(HL)
	and %10000001
	jr z,LAZER_IsSolidNotSolid
	inc H
	inc H
	inc H
	inc H
	ld A,(HL)
	or A
	jr nz,LAZER_IsSolidNotSolid
	pop HL
	ld A,1
	ret	
.LAZER_IsSolidNotSolid
	pop HL
	xor A
	ret
	
;in B=x,C=y
;out HL = cell address
.LAZER_ComputePos
	ld A,C
	add A	;*2
	add	ATTR_Addr_low
	ld L,A
	ld H,ATTR_Addr_high	
	ld A,(HL)
	add B	; add X
	
	inc L
	ld H,(HL)
	ld L,A
	ret
	
	
	
.LAZER_SaveCurrentPos
	dw 0	;position
	dw 0	;cell address
.LAZER_Result0
	db 0 ;result
	dw 0 ;new x,y
	dw 0 ;new cell address

;laser structure
.laserA
db	0	;state
db	0,0	;pos x,y
db	0	;current move
dw	0	;current cell address
dw	0	;laser buffer

;laser structure
.laserB
db	0	;state
db	0,0	;pos x,y
db	0	;current move
dw	0	;current cell address
dw	0	;laser buffer

;laser structure
.laserC
db	0	;state
db	0,0	;pos x,y
db	0	;current move
dw	0	;current cell address
dw	0	;laser buffer

;laser options
.laser_move0	;up
db	0,-1		;move				IX+0,IX+1
dw	52			;sprite			IX+2,IX+3
db	0,0			;check 1			IX+4,IX+5
db	0,0			;check2			IX+6,IX+7
db	4			;IF check1=check2	IX+8
db	4			;IF check1<check2	IX+9
db	4			;IF check1>check2	IX+10

.laser_move1	;right/up
db	1,-1
dw	53
db	1,0
db	0,-1
db	5,3,7

.laser_move2	;right
db	1,0
dw	54
db	0,0
db	0,0
db	6,6,6

.laser_move3	;right/down
db	1,1
dw	52
db	1,0
db	0,1
db	7,1,5

.laser_move4	;down
db	0,1
dw	52
db	0,0
db	0,0
db	0,0,0

.laser_move5	;left/down
db	-1,1
dw	54
db	-1,0
db	0,1
db	1,7,3

.laser_move6	;left
db	-1,0
dw	54
db	0,0
db	0,0
db	2,2,2

.laser_move7	;left/up
db	-1,-1
dw	52
db	0,-1
db	-1,0
db	3,1,5

