#include "ti83plus.inc"
vid = plotsscreen
.org	$9D93				;address to which TI-OS loads the program
.db	$BB,$6D				;identifies to TI-OS that this is an asm program
#define bullseyex savesscreen
#define bullseyey savesscreen+1
score .equ savesscreen+2
	
	xor a
	ld (score),a
show:
	call clear_vid
	call crosshair
	call generate
	call bullseyed
	ld de,(0*256)+0
	ld (CurRow),de		; x = 3, y = 2
	ld HL,(score)
	bcall(_DispHL)		; disp hl in big font
	bcall(_getkey)
InArrow:
	call crosshair
    LD     A, $FF          ; Reset key port
    OUT    (1), A
    LD     A, %11111110
    OUT    (1), A
    IN     A, (1)
	ld b,a
    BIT    0, B
    call    Z, moveDown
    BIT    1, B
    call    Z, moveLeft
    BIT    2, B
    call   Z, moveRight
    BIT    3, B
    call     Z, moveUp
	call crosshair	;draw crosshair
	ld	a,$FF
	out	(1),a			;reset keyport
	ld	a,$BF			;check group that contains second and delete
	out	(1),a
	in	a,(1)
	cp	%10111111
	call z,invert_vid
	cp	%01111111		;check for delete key	
	ret	z			;return control to the system
	cp	%11011111		;check for second key
	call	z,player_shot	;if second was pressed, create a player shot
	call fastcopy
    jp InArrow

MoveDown:
    LD     A, (playery)        ; Check if at bottom edge of screen
    CP     57
    RET    Z
    INC    A                ; Down one pixel
    LD     (playery), A
    RET

MoveUp:
    LD     A, (playery)        ; Check if at top edge of screen
    OR     A
    RET    Z
    DEC    A                ; Up one pixel
    LD     (playery), A
    RET

MoveLeft:
    LD     A, (playerx)        ; Check if at left edge of screen
    OR     A
    RET    Z
    DEC    A                ; Left one pixel
    LD     (playerx), A
    RET

MoveRight:
    LD     A, (playerx)        ; Check if at right edge of screen
    CP     89            ; 96 - number of pixels the string takes up
    RET    Z
    INC    A                ; Right one pixel
    LD     (playerx), A
    RET

player_shot:
	di
	ld a,$FF
	out (1),a
	ld a,$BF
	out (1),a
	in a,(1)
	bit 5,a
	jr z,player_shot		;wait until they let go
	ei

;detection
	ld a,(playerx)
	sub 4
	ld b,a
	ld a,(bullseyex)
	sub b
	call abs
 	ld e,a
	ld h,a
	call multiply_e_h
  	push hl
  	ld a,(playery)
	sub 4
	ld b,a
	ld a,(bullseyey)
	sub b
	call abs
 	ld e,a
	ld h,a
 	call multiply_e_h
  	pop de
 	add hl,de
	ex de,hl
	call Sqrt
	ld b,a
	ld a,7
	cp b
	jp c,missed
    pop bc
    ld hl,score
    ld a,8
    sub b
    add a,(hl)
    ld (hl),a
	jp show
 
multiply_e_h:
	ld l,0
	ld d,0
 
	sla	h		; optimised 1st iteration
	jr	nc,$+3
	ld	l,e
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
 
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	add	hl,hl		; unroll 7 times
	jr	nc,$+3		; ...
	add	hl,de		; ...
	ret
	
abs:
	or a
	ret p
	neg
	ret

Sqrt:
    ld hl,0
    ld c,l
    ld b,h
    ld a,8
Sqrtloop:
    sla e
    rl d
    adc hl,hl
    sla e
    rl d
    adc hl,hl
    scf               ;Can be optimised
    rl c              ;with SL1 instruction
    rl b
    sbc hl,bc
    jr nc,Sqrtaddbit
    add hl,bc
    dec c
Sqrtaddbit:
    inc c
    res 0,c
    dec a
    jr nz,Sqrtloop
    ld a,c
    rr b
    rra
    ret

missed:   
	ld	hl,playerx		;give hl address of player_x
	ld	a,(hl)			;load a player_x
	inc	hl			;increment hl to player_y
	ld	l,(hl)			;load l player_y
	ld	b,6
	ld	ix,bullethole
	jp draw_image

bullseyed:
	ld	hl,bullseyex		;give hl address of player_x
	ld	a,(hl)			;load a player_x
	inc	hl			;increment hl to player_y
	ld	l,(hl)			;load l player_y
	ld	b,15
	ld	c,2
	ld	ix,bullseye
	jp largeSprite

crosshair:
	ld	hl,playerx		;give hl address of player_x
	ld	a,(hl)			;load a player_x
	inc	hl			;increment hl to player_y
	ld	l,(hl)			;load l player_y
	ld	b,7
	ld	ix,crosshairsprite

draw_image:
	ld	e,l
	ld	h,$00
	ld	d,h
	add	hl,de
	add	hl,de
	add	hl,hl
	add	hl,hl
	ld	e,a
	and	$07
	ld	c,a
	srl	e
	srl	e
	srl	e
	add	hl,de
	ld	de,vid
	add	hl,de
putSpriteLoop1:
	ld	d,(ix)
	ld	e,$00
	ld	a,c
	or	a
	jr	z,putSpriteSkip1
putSpriteLoop2:
	srl	d
	rr	e
	dec	a
	jr	nz,putSpriteLoop2
putSpriteSkip1:
	ld	a,(hl)
	xor	d
	ld	(hl),a
	inc	hl
	ld	a,(hl)
	xor	e
	ld	(hl),a
	ld	de,$0B
	add	hl,de
	inc	ix
	djnz	putSpriteLoop1
	ret

;-----> Draw a picture
;Input:	ix->sprite
;	a=x
;	l=y
;	b=height	(in pixels)
;	c=width		(in bytes, e.g. 2 would be 16)
;Output: nothing
; All registers are destroyed except bc', de', hl'
largeSprite:
	di
	ex	af,af'
	ld	a,c
	push	af
	ex	af,af'
	ld	e,l
	ld	h,$00
	ld	d,h
	add	hl,de
	add	hl,de
	add	hl,hl
	add	hl,hl
	ld	e,a
	and	$07
	ld	c,a
	srl	e
	srl	e
	srl	e
	add	hl,de
	ld	de,vid
	add	hl,de
largeSpriteLoop1:
	push	hl
largeSpriteLoop2:
	ld	d,(ix)
	ld	e,$00
	ld	a,c
	or	a
	jr	z,largeSpriteSkip1
largeSpriteLoop3:
	srl	d
	rr	e
	dec	a
	jr	nz,largeSpriteLoop3
largeSpriteSkip1:
	ld	a,(hl)
	xor	d
	ld	(hl),a
	inc	hl
	ld	a,(hl)
	xor	e
	ld	(hl),a
	inc	ix
	ex	af,af'
	dec	a
	push	af
	ex	af,af'
	pop	af
	jr	nz,largeSpriteLoop2
	pop	hl
	pop	af
	push	af
	ex	af,af'
	ld	de,$0C
	add	hl,de
	djnz	largeSpriteLoop1
	pop	af
	ret

fastCopy:
 di
 ld a,$80
 out ($10),a
 ld hl,vid-12-(-(12*64)+1)
 ld a,$20
 ld c,a
 inc hl
 dec hl
fastCopyAgain:
 ld b,64
 inc c
 ld de,-(12*64)+1
 out ($10),a
 add hl,de
 ld de,10
fastCopyLoop:
 add hl,de
 inc hl
 inc hl
 inc de
 ld a,(hl)
 out ($11),a
 dec de
 djnz fastCopyLoop
 ld a,c
 cp $2B+1
 jr nz,fastCopyAgain
 ei
 ret
 
clear_vid:
	ld	bc,767			;there are 768 bytes of video memory, we're doing one less
	ld	hl,vid
	ld	de,vid+1		;the cause for the one less
	ld	(hl),0			;put a 0, the clear it
	ldir				;loads (hl) into (de) then decrements bc until it equals zero
	ret

invert_vid:
	ld bc,768
	ld hl,vid
loop:
	ld a,(hl)
	cpl	;
	ld (hl),a
	inc hl
	dec bc
	ld a,b
	or c
	jr nz, loop
	ret

generate:
	ld b,80
	call random
	ld (bullseyex),a
	ld b,48
	call random
	ld (bullseyey),a
	ret
	
;-----> Generate a random number
; input b=upper bound
; ouput a=answer 0<=a<b
; all registers are preserved except: af and bc
random:
	push	hl
	push	de
	ld	hl,(randData)
	ld	a,r
	ld	d,a
	ld	e,(hl)
	add	hl,de
	add	a,l
	xor	h
	ld	(randData),hl
	sbc	hl,hl
	ld	e,a
	ld	d,h
randomLoop:
	add	hl,de
	djnz	randomLoop
	ld	a,h
	pop	de
	pop	hl
	ret

crosshairsprite:
	.db %00010000
	.db %00010000
	.db %00101000
	.db %11000110
	.db %00101000
	.db %00010000
	.db %00010000

bullethole:
	.db %00000000
	.db %00101000
	.db %01010100
	.db %00111000
	.db %01010100
	.db %00101000

bullseye:
	.db $03,$80,$0C,$60,$10,$10,$23,$88,$44,$44,$48,$24,$91,$12,$92,$92
	.db $91,$12,$48,$24,$44,$44,$23,$88,$10,$10,$0C,$60,$03,$80,$00,$00

playerx:
	.db 0
playery:
	.db 0