	
	
	ORG &00F0
	DB 0,5			;type 5 = machine code application program
	DW FileEnd-FileStart	;16 bit length
	DB 0,0,0,0,0,0,0,0,0,0,0,0 ;not used bytes
;Program starts at ORG &0100

FileStart:			
	LD SP,&100				;Set up a base stack pointer
	call ScreenINIT
	
	ld de,ENT_Keboardname
	ld a,11					;Open the keyboard as stream 11
	rst 48					;EXOS
	db 1 					;Open stream	

	ld a,0					;Dummy Key value 
	JR StartDraw
infloop:
	call TestChar			;Read A key from keyboard
	cp 0
	jr z,infloop			;See if no keys are pressed
StartDraw:
	push af
		ld a,(PlayerX)		;Back up X
		ld b,a
		ld (PlayerX2),a

		ld a,(PlayerY)		;Back up Y
		ld c,a
		ld (PlayerY2),a

		push bc
			call BlankPlayer;Remove old player sprite
		pop bc
	pop af
	ld d,a
	cp &B0
	jr nz,JoyNotUp			;Jump if UP not presesd
	ld a,c
	sub 4
	ld c,a					;Move Y Up the screen
JoyNotUp:
	ld a,d
	cp &B4
	jr nz,JoyNotDown		;Jump if DOWN not presesd
	ld a,c
	add 4
	ld c,a					;Move Y Down the screen
JoyNotDown:
	ld a,d
	cp &B8
	jr nz,JoyNotLeft 		;Jump if LEFT not presesd
	dec b					;Move X Left 
JoyNotLeft:
	ld a,d
	cp &BC
	jr nz,JoyNotRight		;Jump if RIGHT not presesd
	inc b					;Move X Right
JoyNotRight: 
	ld a,b
	ld (PlayerX),a			;Update X
	ld a,c
	ld (PlayerY),a			;Update Y
	
;X Boundary Check - if we go <0 we will end up back at &FFFF
	ld a,b
	cp 80-2 				;320 / 256  =1 remainder 64
	jr c,PlayerPosXOk
	jr PlayerReset 			;Player out of bounds - Reset!
PlayerPosXOk:

;Y Boundary Check - only need to check 1 byte
	ld a,c
	cp 200-8
	jr c,PlayerPosYOk;Not Out of bounds
	
PlayerReset:
	ld a,(PlayerX2) 		;Reset Xpos	
	ld b,a
	ld (PlayerX),a	

	ld a,(PlayerY2)			;Reset Ypos
	ld c,a
	ld (PlayerY),a
	
PlayerPosYOk:
	call DrawPlayer			;Draw Player Sprite
	
	ld bc,5000
	call PauseBC			;Wait a bit!

	jp infloop

PauseBC:
	dec bc
	ld a,b
	or c
	jr nz,PauseBC
	ret
	
	
BlankPlayer:	
	push bc
		ld de,BlankSprite	;Sprite Source
		jr DrawBoth
Drawplayer:
	push bc
		ld de,TestSprite	;Sprite Source
DrawBoth:
	pop bc
	call GetScreenPos		;Calculate desitiation memory address	
	ld b,8					;Lines

SpriteNextLine:
	push hl
		ld a,(de)			;Source Byte
		ld (hl),a			;Screen Destination

		inc de				;INC Source (Sprite) Address
		inc hl				;INC Dest (Screen) Address

		ld a,(de)			;Source Byte
		ld (hl),a			;Screen Destination
	
		inc de				;INC Source (Sprite) Address
	pop hl
	call GetNextLine		;Scr Next Line (Alter HL to move down a line)

	djnz SpriteNextLine		;Repeat for next line
	
	ret
	
TestChar:
	push bc
		ld a,11 			;Keyboard is channel 11
		rst 48				;EXOS call
		db 9 				;Channel Read Status
		;Result in C (0=Byte waiting / 1=no byte / FF=StreamEnd)
			
		ld a,c				
		or a				;0=ready
		ld a,0				;return zero if z flag not set
		jr nz,TestChar_NoCharWaiting
		
		;Get the waiting character
		ld a,11 			;Keyboard is channel 11
		rst 48				;EXOS call
		db 5 				;Read from channel - result in b
		ld a,b
TestChar_NoCharWaiting:
	pop bc
	ret
	
ENT_Keboardname: db 9,'KEYBOARD:'

;Current player pos
PlayerX: db &10
PlayerY: db &10

;Last player pos (For clearing sprite)
PlayerX2: db &10
PlayerY2: db &10
	
	
TestSprite:
;Bitplane   00001111  00001111
		db %00110000,%11000000	
		db %01110000,%11100000	
		db %11110010,%11110100	
		db %11110000,%11110000	
		db %11110000,%11110000	
		db %11010010,%10110100	
		db %01100001,%01101000	
		db %00110000,%11000000

BlankSprite:
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		db %00000000,%00000000
		
GetScreenPos:	;return memory pos in HL of screen co-ord B,C (X,Y)
				;Input  BC= XY (x=bytes - so 80 across)
				;Output HL= screen mem pos
	push de
;screen is 80 wide = 00000000 01010000
		ld h,C		;YYYYYYYY 00000000
		xor a
		
		srl h
		rra			;0YYYYYYY Y0000000
		srl h
		rra 		;00YYYYYY YY000000
		
		ld d,h
		ld e,a		;Store first part for later
		
		srl h
		rra			;000YYYYY YYY00000
		srl h
		rra			;0000YYYY YYYY0000
		
		
		add e		
		add B		;Add the X pos 
		ld l,a
		
		ld a,h
		adc d
		add &C0		;Add screen Base &C000
		ld h,a	
	pop de
	ret 			;return memory location in hl


	
GetNextLine:
	push af
		ld a,l		
		add &50		;each line is 80 bytes wide
		ld l,a
		jr nc,GetNextLineDone
		inc h		;Deal with overflow if needed
GetNextLineDone:
	pop af
	ret

	
	;The code below was based on an example from the Enterprise forever forum
ScreenINIT:
	di
	LD A,12		;disable memory wait states
	OUT (191),A	

	;setting the Border color to black

	LD BC,&100+27	;B=1 write
	;C=27 number of system variable (BORDER)	
	LD D,0			;new value
	rst 6*8
	db 16			;handling EXOS variable

	CALL BankSwitch_RequestVidBank	;get a free Video segment
	Jr NZ,VideoFail	;if not available then exit
	LD A,C		
	LD (VIDS),A		;store segment number page to the page 3.
	OUT (&B3),A		

	LD DE,0			;segment number low two bits
	RRA				;will be the top two bits of the video address
	RR D			
	RRA				
	RR D			
	LD (VIDADR1),DE ;this is the start of pixel data in the video memory

	LD HL,&3F00		;after the pixel bytes starting the Line Parameter Table (LPT)
	ADD HL,DE	
	LD (LPTADR),HL	
		
	LD HL,LPT		;Line Parameter Table copy to the end of video segment
	LD DE,&FF00	
	LD BC,LPTH	
	LDIR		
VidAgain:		
	LD HL,(LPTADR)	;LPT video address
	LD B,4			;4 bit rotate
LPTA: SRL H
	RR L
	DJNZ LPTA
	LD A,L			;low byte send to Nick
	OUT (&82),A	
	LD A,H			;high 4 bits enable Nick running
	OR &C0		
	
	;switch to the new LPT at the end of current frame send to Nick
	OUT (&83),A	
			
VideoFail:
	ret



BankSwitch_RequestVidBank:           
	LD HL,FileEnd		;buffer area
	LD (HL),0			;start of the list
GetSegment:	
	rst 6*8				;get a free segment
	db 24			
	RET NZ				;if error then return
	LD A,C				;segment number
	CP &FC				;<0FCh?, no video segment?
	JR NC,ENDGET		;exit cycle if video
	INC HL				;next buffer address
	LD (HL),C			;store segment number
	JR GetSegment		;get next segment
ENDGET: 
	PUSH BC				;store segment number
FREES:	LD C,(HL)		;deallocate onwanted

		rst 6 *8
		db 25			;free non video segments

		DEC HL			;previoud buffer address
		JR Z,FREES		;continue deallocating when call the EXOS 25 function with
		;c=0 which is stored at the start of list, then got a error, flag is NZ
		
	POP BC				;get back the video segment number
	XOR A				;Z = no error
	ret


;NICK Line Parameter Table (LPT)

LPT: DB 256-200		;Screen Size: 200 lines.... 
					;Two's complement of the number of scanlines in this mode line.
	   ;ICCRMMML
	db %00110010   		;I   VINT=0, no IRQ
						;CC  Colour Mode=01, 4 colours mode (2/4/16/256)
						;R   VRES=1, full vertical resolution (full/half)
						;MMM Video Mode=001, pixel graphics mode
						;L   Reload=0, LPT will continue
	
	DB 11   		;left margin=11
	DB 51  			;right margin=51
VIDADR1:  DW 0    	;primary video address, address of pixel data
	DW 0  			;secondary vide0 address, not used in pixel graphics mode
ENT_PALETTE:	
	; 	GRBGRBGR  	;g0 | r0 | b0 | g1 | r1 | b1 | g2 | r2 | - x0 = lsb 
	db %00000000	;Color 0: Black
	db %00100100	;Color 1: Blue
	db %11011011	;Color 2: Yellow
	db %01001001	;Color 3: Red
	db 0,0,0,0 		;Colors 4-7 (unused)

;Line definitions			
	DB -50,&12,63,0,0,0,0,0,0,0,0,0,0,0,0,0	;50 lines of border, this is the bottom margin,
	DB -3,16,63,0,0,0,0,0,0,0,0,0,0,0,0,0	;3 black lines, syncronization off
	DB -4,16,6,63,0,0,0,0,0,0,0,0,0,0,0,0	;4 lines, syncronization on
	DB -1,&90,63,32,0,0,0,0,0,0,0,0,0,0,0,0	;1 line, syncronization will switch off at half of line
												;the NICK chip generate video IRQ at this line
	DB 252,&12,6,63,0,0,0,0,0,0,0,0,0,0,0,0 ;4 black lines
	DB -50,&13,63,0,0,0,0,0,0,0,0,0,0,0,0,0 ;50 lines of border, this is the top margin,
LPTEnd:              
LPTH equ LPTEnd-LPT ;length of LPT
	
VIDS:		DB 0	;variables for storing allocated memory
LPTADR:     DW 0		
	
FileEnd:
	