org 39936
;SPRITE GRAPHICS, on word boundary.  PRESHIFTED, 8 frames per direction
moleratright
	DEFB 0, 0,0,36; 36, 0		;FRAME 0
	DEFB 60, 0,0,62; 62, 0
	DEFB 62, 0,0,60; 60, 0
	DEFB 36, 0, 0,0;0, 0
	;
	DEFB 0, 0,0,18; 18, 0		;FRAME 1
	DEFB 30, 0,0,31; 31, 0
	DEFB 31, 0, 0,30;30, 0
	DEFB 18, 0,0,0; 0, 0
	;
	DEFB 0, 0, 128,16;16, 128	;FRAME 2
	DEFB 15, 0,128,15; 15, 128
	DEFB 15, 128,0,15; 15, 0
	DEFB 6, 0, 0,0;0, 0
	;
	DEFB 0, 0,64,8; 8, 64		;FRAME 3
	DEFB 7, 128,192,7; 7, 192
	DEFB 7, 192,128,7; 7, 128
	DEFB 3, 0,0,0; 0, 0
	;
	DEFB 0, 0,64,2; 2, 64		;FRAME 4
	DEFB 3, 192,224,3; 3, 224
	DEFB 3, 224,192,3; 3, 192
	DEFB 2, 64,0,0; 0, 0
	;
	DEFB 0, 0,32,1; 1, 32		;FRAME 5
	DEFB 1, 224,240,1; 1, 240
	DEFB 1, 240,224,1; 1, 224
	DEFB 1, 32,0,0; 0, 0
	;
	DEFB 0, 0,96,0; 0, 96		;FRAME 6
	DEFB 0, 240,248,0; 0, 248
	DEFB 0, 248,240,0; 0, 240
	DEFB 1, 8, 0,0;0, 0
	;
	DEFB 0, 0,48,0; 0, 48		;FRAME 7
	DEFB 0, 120,124,0; 0, 124
	DEFB 0, 124,120,0; 0, 120
	DEFB 0, 132,0,0; 0, 0
	;
moleratleft
	DEFB 0, 0,0,12; 12, 0		;FRAME 0
	DEFB 30, 0,0,62; 62, 0
	DEFB 62, 0,0,30; 30, 0
	DEFB 33, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,6; 6, 0		;FRAME 1
	DEFB 15, 0,0,31; 31, 0
	DEFB 31, 0,0,15; 15, 0
	DEFB 16, 128,0,0; 0, 0
	;
	DEFB 0, 0,128,4; 4, 128		;FRAME 2
	DEFB 7, 128,128,15; 15, 128
	DEFB 15, 128,128,7; 7, 128
	DEFB 4, 128,0,0; 0, 0
	;
	DEFB 0, 0,64,2; 2, 64		;FRAME 3
	DEFB 3, 192,192,7; 7, 192
	DEFB 7, 192, 192,3;3, 192
	DEFB 2, 64, 0,0;0, 0
	;
	DEFB 0, 0, 16,2;2, 16		;FRAME 4
	DEFB 1, 224,224,3; 3, 224
	DEFB 3, 224,224,1; 1, 224
	DEFB 0, 192,0,0; 0, 0
	;
	DEFB 0, 0,8,1; 1, 8		;FRAME 5
	DEFB 0, 240,240,1; 1, 240
	DEFB 1, 240,240,0; 0, 240
	DEFB 0, 96, 0,0;0, 0
	;
	DEFB 0, 0, 72,0;0, 72		;FRAME 6
	DEFB 0, 120, 248,0;0, 248
	DEFB 0, 248,120,0; 0, 120
	DEFB 0, 72, 0,0;0, 0
	;
	DEFB 0, 0,36,0; 0, 36		;FRAME 7
	DEFB 0, 60,124,0; 0, 124
	DEFB 0, 124,60,0;0, 60
	DEFB 0, 36, 0,0;0, 0
	;
moleratup
	DEFB 0, 0,0,24; 24, 0		;FRAME 0
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 0, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,24; 24, 0		;FRAME 1
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 0, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,26; 26, 0		;FRAME 2
	DEFB 60, 0,0,124; 124, 0
	DEFB 124, 0,0,60; 60, 0
	DEFB 2, 0, 0,0;0, 0
	;
	DEFB 0, 0,0,26; 26, 0		;FRAME 3
	DEFB 60, 0,0,124; 124, 0
	DEFB 124, 0,0,60; 60, 0
	DEFB 2, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,24; 24, 0		;FRAME 4
	DEFB 126, 0, 0,60;60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 0, 0, 0,0;0, 0
	;
	DEFB 0, 0,0,24; 24, 0		;FRAME 5
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0, 0,126;126, 0
	DEFB 0, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,088; 88, 0		;FRAME 6
	DEFB 60, 0,0,62; 62, 0
	DEFB 62, 0,0,60; 60, 0
	DEFB 64, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,88; 88, 0		;FRAME 7
	DEFB 60, 0,0,62; 62, 0
	DEFB 62, 0,0,60; 60, 0
	DEFB 64, 0,0,0; 0, 0
	;
moleratdown
	DEFB 0, 0,0,0; 0, 0		;FRAME 0
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 24, 0,0,0; 0, 0
	;
	DEFB 0, 0, 0,0;0, 0		;FRAME 1
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 24, 0, 0,0;0, 0
	;
	DEFB 0, 0,0,2; 2, 0		;FRAME 2
	DEFB 60, 0,0,124; 124, 0
	DEFB 124, 0,0,60; 60, 0
	DEFB 26, 0,0,0; 0, 0
	;
	DEFB 0, 0, 0,2;2, 0		;FRAME 3
	DEFB 60, 0,0,124; 124, 0
	DEFB 124, 0,0,60; 60, 0
	DEFB 26, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,0; 0, 0		;FRAME 4
	DEFB 126, 0, 0,60;60, 0
	DEFB 60, 0, 0,126;126, 0
	DEFB 24, 0,0,0; 0, 0
	;
	DEFB 0, 0,0,0; 0, 0		;FRAME 5
	DEFB 126, 0,0,60; 60, 0
	DEFB 60, 0,0,126; 126, 0
	DEFB 24, 0,0,0; 0, 0
	;
	DEFB 0, 0, 0,64;64, 0		;FRAME 6
	DEFB 60, 0,0,62; 62, 0
	DEFB 62, 0,0,60; 60, 0
	DEFB 88, 0,0,0; 0, 0
	;
	DEFB 0, 0, 0,64;64, 0		;FRAME 7
	DEFB 60, 0,0,62; 62, 0
	DEFB 62, 0,0,60; 60, 0
	DEFB 88, 0,0,0; 0, 0
mothright
	DEFB 192, 0,0,112; 112, 0	;FRAME 0
	DEFB 61, 0,0,126; 126, 0
	DEFB 126, 0,0,61; 61, 0
	DEFB 112, 0,0,192; 192, 0
	;
	DEFB 96, 0,0,56; 56, 0		;FRAME 1
	DEFB 30, 128,0,63; 63, 0
	DEFB 63, 0,128,30; 30, 128
	DEFB 56, 0,0,96; 96, 0
	;
	DEFB 48, 0,0,28; 28, 0		;FRAME 2
	DEFB 15, 64,128,31; 31, 128
	DEFB 31, 128,64,15; 15, 64
	DEFB 28, 0,0,48; 48, 0
	;
	DEFB 24, 0,0,14; 14, 0		;FRAME 3
	DEFB 7, 160,192,15; 15, 192
	DEFB 15, 192, 160,7;7, 160
	DEFB 14, 0,0,24; 24, 0
	;
	DEFB 12, 0,0,7; 7, 0		;FRAME 4
	DEFB 3, 208,224,7; 7, 224
	DEFB 7, 224,208,3; 3, 208
	DEFB 7, 0,0,12; 12, 0
	;
	DEFB 6, 0,128,3; 3, 128		;FRAME 5
	DEFB 1, 232,240,3; 3, 240
	DEFB 3, 240,232,1; 1, 232
	DEFB 3, 128,0,6; 6, 0
	;
	DEFB 3, 0,192,1; 1, 192		;FRAME 6
	DEFB 0, 244,248,1; 1, 248
	DEFB 1, 248,244,0; 0, 244
	DEFB 1, 192,0,3; 3, 0
	;
	DEFB 1, 128,224,0; 0, 224	;FRAME 7
	DEFB 0, 122,252,0; 0, 252
	DEFB 0, 252,122,0; 0, 122
	DEFB 0, 224,128,1; 1, 128
mothleft
	DEFB 3, 0,0,14; 14, 0		;FRAME 0
	DEFB 188, 0,0,126; 126, 0
	DEFB 126, 0,0,188; 188, 0
	DEFB 14, 0,0,3; 3, 0
	;
	DEFB 1, 128,0,7; 7, 0		;FRAME 1
	DEFB 94, 0,0,63; 63, 0
	DEFB 63, 0,0,94; 94, 0
	DEFB 7, 0,128,1; 1, 128
	;
	DEFB 0, 192,128,3; 3, 128	;FRAME 2
	DEFB 47, 0,128,31; 31, 128
	DEFB 31, 128,0,47; 47, 0
	DEFB 3, 128,192,0; 0, 192
	;
	DEFB 0, 96,192,1; 1, 192	;FRAME 3
	DEFB 23, 128,192,15; 15, 192
	DEFB 15, 192,128,23; 23, 128
	DEFB 1, 192,96,0; 0, 96
	;
	DEFB 0, 48,224,0; 0, 224	;FRAME 4
	DEFB 11, 192,224,7; 7, 224
	DEFB 7, 224,192,11; 11, 192
	DEFB 0, 224,48,0; 0, 48
	;
	DEFB 0, 24, 112,0;0, 112	;FRAME 5
	DEFB 5, 224,240,3; 3, 240
	DEFB 3, 240,224,5; 5, 224
	DEFB 0, 112,24,0; 0, 24
	;
	DEFB 0, 12,56,0; 0, 56		;FRAME 6
	DEFB 2, 240,248,1; 1, 248
	DEFB 1, 248,240,1; 2, 240
	DEFB 0, 56,12,0; 0, 12
	;
	DEFB 0, 6,28,0; 0, 28		;FRAME 7
	DEFB 1, 120,252,0; 0, 252
	DEFB 0, 252,120,1; 1, 120
	DEFB 0, 28,6,0; 0, 6
	;
mothup
	DEFB 36, 0,0,24; 24, 0		;FRAME 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 1
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 2
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 3
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 4
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 5
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 6
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
	DEFB 36, 0,0,24; 24, 0		;FRAME 7
	DEFB 60, 0,0,60; 60, 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 219, 0,0,129; 129, 
	;
mothdown
	DEFB 129, 0,0,219; 219, 0	;FRAME 0
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 1
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 2
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 3
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 4
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 5
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 6
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	;
	DEFB 129, 0,0,219; 219, 0	;FRAME 7
	DEFB 126, 0,0,126; 126, 0
	DEFB 60, 0,0,60; 60, 0
	DEFB 24, 0,0,36; 36, 0
	; 
bigbang				;250 points graphic
	DEFB 0, 0,34,39; 39, 34		;FRAME 0
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 1
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 2
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 3
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0	;
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 4
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 5
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 6
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
	DEFB 0, 0,34,39; 39, 34		;FRAME 7
	DEFB 84, 82,82,22; 22, 82
	DEFB 33, 82, 80,65;65, 80
	DEFB 118, 34,0,0; 0, 0
	;
bang				;8 FRAME EXPLOSION GRAPHIC
	DEFB 0, 0, 0, 128	;used by both player sprite and baddy, on collision
	DEFB 3, 192, 1, 224
	DEFB 3, 192, 1, 192
	DEFB 2, 160, 0, 0
	;
	DEFB 2, 0, 0, 160		;FRAME 1
	DEFB 3, 208, 5, 224
	DEFB 3, 96, 5, 208
	DEFB 2, 160, 1, 64
	;
	DEFB 4, 136, 17, 32		;FRAME 2
	DEFB 2, 212, 5, 176
	DEFB 19, 100, 4, 144
	DEFB 2, 160, 9, 72
	;
	DEFB 8, 132, 37, 32		;FRAME 3
	DEFB 2, 154, 6, 192
	DEFB 1, 82, 46, 176
	DEFB 4, 8, 21, 36
	;
	DEFB 20, 72, 64, 2		;FRAME 4
	DEFB 2, 136, 84, 101
	DEFB 21, 4, 74, 82
	DEFB 16, 8, 37, 22
	;
	DEFB 40, 73, 129, 4		;FRAME 5
	DEFB 16, 0, 173, 101
	DEFB 45, 71, 146, 80
	DEFB 0, 40, 74, 19
	;
	DEFB 41, 74, 128, 1		;FRAME 6
	DEFB 16, 8, 173, 42
	DEFB 45, 78, 151, 123
	DEFB 0, 0, 170, 74
	;
	DEFB 85, 85, 0, 0		;FRAME 7
	DEFB 37, 42, 85, 74
	DEFB 85, 78, 34, 42
	DEFB 0, 0, 170, 170
	;
bullrt		;FIRED PROJECTILE GRAPHIC, 2 PIXELS/FRAME, FILLS ONE CHAR ONLY
	defb	000,000,000,192,192,192,000,000	;FRAME 0
	defb	000,000,000,048,048,048,000,000
	defb	000,000,000,012,012,012,000,000
	defb	000,000,000,003,003,003,000,000

bulllt	defb	000,000,000,003,003,003,000,000	;FRAME 1
	defb	000,000,000,192,192,192,000,000
	defb	000,000,000,048,048,048,000,000	
	defb	000,000,000,012,012,012,000,000	

bullup	defb	000,000,000,000,000,000,028,028	;FRAME 2
	defb	000,000,000,000,028,028,000,000
	defb	000,000,028,028,000,000,000,000
	defb	028,028,000,000,000,000,000,000

bulldn	defb	028,028,000,000,000,000,000,000	;FRAME 3
	defb	000,000,028,028,000,000,000,000
	defb	000,000,000,000,028,028,000,000
	defb	000,000,000,000,000,000,028,028
	;
;USR 41344 BELOW, START POINT OF GAME
ENTRY	ld a,(23672)		;get some pseudorandom numbers for seed setting
	ld h,a
	ld a,r
	ld d,a
	call any_key2		;hl inc and de dec during this
	xor a
	or h
	or l
	or d
	or e			;if all are zero the RNG won't work, 1 in 4294967296 chance!
	call z,monument_to_bizarre_events		;which should be appropriately marked
	ld (rnd+1),de
	ld (rnd+4),hl		;set seeds, only need to do once at the beginning
	call set_interrupt	;create vector address table and set im2
	call save_sprites	;ldirs sprite data to storage for later	
	call no_key
start	ld sp,0			;just in caaaase, must pay more heed to the stack in future	
	call introscreen
start3	call get_key_pressed	;preserve loading screen and random time event to seed random seed
	cp '1'
	push af
	call z,refine_keys
	pop af
	cp '2'
	jr nz,start3
	call ready_screen
	call set_game_up	;screen draw, variables, etc
start2	call main_game_loop
	ld a,(lives)
check	dec a			;we check this is still dec a, anti-hack (FEEBLE! ANDREW RYALS HACKED THE GAME IN 10 Mins!)
	cp 255			;4 lives, on spuds advice
	ld (lives),a
	push af
	call z,scrash
	pop af
	jp z,endscreen		;all lives gone? displays END OF GAME, then goes to anykey, then jumps to start
	call ready_screen
	call set_game_up2	;sets up variables but keep guardian on off switches
	jp start2		;lives left, continue playing
	;
set_interrupt
	ld hl,65021		;simple interrupt routine then vector table
	ld (hl),251		;defb = ei
	inc hl
	ld (hl),201		;defb = RET
	inc hl
	ld (hl),253
	ld d,h
	ld e,l
	inc de
	ld bc,258
	ldir			;257 bytes of defb 253, interrupt jumps to 65021	
	di
	ld a,254		;i register will jump to vector table at 65024, full of defb 253
	ld i,a			;which is the routine at 65021 EI, RET
	im 2
	ei
	ret
	;
save_sprites			;ldirs full sprite variables at the top end of memory after the buffers as they are altered in game
	ld hl,scadd
	ld de,spritestore
ss2	ld bc,number_of_sprites*length_of_sprite_table
	ldir
	ret
	;
ldir_sprite_data		;at the start of each  new game we reinstall ALL the untainted sprite data
	ld hl,spritestore
	ld de,scadd
	ld bc,number_of_sprites*length_of_sprite_table
	ldir
	ret				;reuse the code above
	;
get_guardian_status			;record which guardians are switched off and on, used in game on restart between lives
	ld ix,gstatus			;we restore
	ld hl,statusstore
	ld de,length_of_sprite_table
	ld b,number_of_sprites-1	;only doing guardians
ggslp	ld a,(ix+0)			;get status byte
	ld (hl),a			;store it
	inc hl				;next place to store
	add ix,de			;next guardian status byte
	djnz ggslp			;continue till all done
	ret
	;
poke_guardian_status			;used in game betwen lives, restores which sprites are active and not
	ld ix,statusstore
	ld hl,gstatus
	ld de,length_of_sprite_table
	ld b,number_of_sprites-1
pgslp	ld a,(ix+0)			;get status
	ld (hl),a			;poke it into sprite ix table
	inc ix				;next one in store
	add hl,de			;next one in table
	djnz pgslp
	ret
	;
introscreen				;blue screen, intro etc	
	ld hl,levelstrstore
	ld de,levelstr
	ld bc,3
	ldir
	call bluescreen			;a few routines to set up screen colours, border, cls
	ld ix,string1
	call print_string
	ld ix,string2
	call print_string
	ld ix,string15			;MOLE RAT ! String
	ld de,16384+96+4+32+3
	call bigfont			;converts normal font into 16x16 graphic
	ret
	;
ready_screen
	call bluescreen
	ld ix,string10			;Get ready player 1 string
	call print_string
	jp any_key
	;
endscreen
	call check_hi_score
	call bluescreen
	ld ix,string11			;END OF GAME MESSAGE
	call print_string	
	call delay
	call delay
	call delay
	jp start
	;
check_hi_score				;cp two sets of ASCII
	ld ix,score
	ld hl,hiscore
	ld b,5				;5 digits only, the 6th one is always 0
chilp	ld a,(ix+0)			;new score byte
	cp (hl)				;cp old score byte
	ret c				;if carry set old score is higher
	jr nz,newsc			;nc & nz means new score is higher
	inc ix	
	inc hl
	djnz chilp
	ret				;reaching here means hi & low score equal
newsc	ld hl,score			;ok new score is higher than old hi score
	ld de,hiscore			;new high score, so ldir it in place
	ld bc,6
	ldir
	ret
	;
success_screen				;ADD (x)000 points !!! etc
	call clear_screen
	ld a,9
	call colp2			;paper and ink the same as for attr effect
	call colour_border
	ld ix,string12
	ld a,(level)			;every 4 success screens we get an extra life!
	and 3				;as long as we don't already have the maximum of 3 grrr nasty
	cp 3
	call z,extra_life		;points to EXTRA LIFE string rather than BONUS POINTS message
	call print_string		;BONUS POINTS MESSAGE
	call flashattr			;prints big score but in flash attr
	call suctit			;print big score yellow paper blue ink
	call romnoise			;cycles rom, gives nice effect in the letters, waits for keypress
	call ready_screen
	call set_game_up2		;reset variables except level and lives
	call ldir_sprite_data		;but but in all new sprite data (slightly different to in game restart)
	ld a,(mothcountstore)
	ld (mothcount),a
	jp start2			;main game loop
	;
extra_life
	ld a,(lives)
	cp 3				;don't go beyond max three, that would be too easy eh ;-)
	ret nc
	inc a
	ld (lives),a
	ld ix,string13
	ret
	;
monument_to_bizarre_events		;this screen will never be called!
	call bluescreen			;Thanks to Einar Saukas and Gedlion for their help on this one
	ld ix,string14
	ld de,18432+8
	call print_string
	inc h				;ensure seed is not zero
	ld a,r
	ld d,a
	xor a
	in a,(254)
	jp any_key			;return and these values will be set
	;
flashattr				;start of 1000 points message uses flash attribute yellow/red effect
	ld a,86+128
	ld (bitset+1),a	;red paper yellow ink flash
	call suctit
	ld a,113
	ld (bitset+1),a	;yellow paper blue ink
	call delay
	call delay
	ret
	;
romnoise				;That cool scrambled effect on the success screen
	ld hl,0
rmlp	halt
	halt	
	ld de,16384
	ld bc,2048
	ldir
	ld a,h
	and 31
	ld h,a
	xor a
	in a,(254)
	and 31
	cp 31
	jr z,rmlp
	ret
	;
suctit	ld ix,bonus		;string of ascii numbers
	ld de,22528		;point hl at start of letters
sslp3	ld a,(ix+0)
	cp 255			;255 marks end of string
	ret z	
	push de
	call bigup		;print one big letter/number in attributes
	pop de
	ld a,e
	add a,8			;for next letter/number along
	ld e,a
	inc ix
	jr sslp3		;keep going until we hit defb 255
	;
bigup	call get_char		;point hl at the graphic for this number
	ex de,hl		;hl now pointing at attributes, de at graphic
	ld c,8			;8 lines of graphic
sslp2	ld b,8			;8 bits to rotate out
	ld a,(de)
sslp1	rla
	call c,bitset		;put a block of paper in then
	inc l			;next column along
	djnz sslp1
	push de
	ld de,24
	add hl,de
	pop de
	inc de				;next byte of graphic
	dec c
	jr nz,sslp2
	ret	
bitset	ld (hl),113			;yellow paper blue ink
	ret
	;
bonus	defb	'0000',255		;we poke the in
	;
set_game_up
	ld hl,scorestore		;new game so zeroify the score
	ld de,score
	ld bc,6
	ldir				;ldir 6 x defb 48 (ascii 0) in
	ld ix,game_map
	ld de,49152+32			;buffer at 49152, 128 high bytes above screen memory, +64 is the two rows down
	call print_blocks		;print the blocks in the buffer
	call white_frame		;bit of a patch this, puts the white frame in the buffer, didn't want each one to have a block type
	call ldir_buffer_to_screen
	ld hl,variablestore		;put untainted start variables back
	ld de,level			;start of variables
	ld bc,9
	ldir
	ld ix,string1			;info at top of the screen, 'CREDITS, SCORE etc'
	call print_string
	call print_lives		;print number of lives as ugs at top
	call ldir_attrs_to_buffer	;move screen attrs to buffer at 30720
	call ldir_sprite_data		;put untainted sprite data in position
	ret
	;
set_game_up2				;for setting game up with same lives, guardians on screen etc, BETWEEN LIVES SET UP RATHER THAN NEW GAME
	ld ix,game_map
	ld de,49152+32			;buffer at 49152, 128 high bytes above screen memory, +64 is the two rows down
	call print_blocks		;print the blocks in the buffer
	call white_frame		;bit of a patch this, puts the white frame in the buffer, didn't want each one to have a block type
	call ldir_buffer_to_screen
	ld ix,string1			;info at top of the screen, 'CREDITS, SCORE etc'
	call print_string
	call print_lives		;print number of lives as ugs at top
	call ldir_attrs_to_buffer	;move screen attrs to buffer at 30720
	call get_guardian_status	;get which ones are switched on and off, then poke the values in after all other data restored
	call ldir_sprite_data		;put untainted sprite data in position
	call poke_guardian_status	;poke which sprites are on and off
	ld hl,variablestore2		;rest variables but not level & lives
	ld de,loop_counter
	ld bc,5				;don't overwrite number of moths!
	ldir
	xor a
	ld (specswitch),a		;turn off spectrum smuggler, he only appears in game
	ret
	;
;THE GAME LOOP, WHERE THE ACTION HAPPENS
main_game_loop
	ld b,61				;start with hack check each time, dec a in asm, for antihack
	ld hl,check-56
	call anti_hack			;mild anti hack
	call change_pattern		;set guardian behaviour
	call print_level
	call print_score
	xor a				;unset a few variables
	ld (specswitch),a
	ld (smugtimer),a
	;ACTUAL MAIN GAME LOOP HERE
mglp	halt				;start of loop, HALT is just EI RET
	call delete			;delete all sprites with buffer background (10 max, still a bit of flicker one last one)
	call drawsprite			;OR all sprites on
	call drawbullet	
	call check_keys			;Player keys
	call firekey			;fire key separate, so we can move and shoot at the same time
	call shooter			;controls bullet movement
	call bullet_check		;collision check for bullet/guardian
	call guardian_control		;'AI' , I am not very happy with this bit
	call set_directions_and_move	;move all sprites
	call bullet_check		;more than one bullet check per main loop needed (found bullets passing through on occasion).
	call death_check		;player death check, 2 needed per main loop
	call inertia			;player sprite only
	ld a,(direction)
	ld (olddir),a			;for inertia check next time round
	call coloursprite		;deletes old colour from buffer at 30720 (5 high bytes above attrs), then puts new at new position
	call buildingflash		;controls for when yellow moth appears
	call events			;when yellow moth is called, when guardians go more chasey, when speed goes up etc
	call sounds			;checks a couple of sound flags and makes a beeper noise if set
	ld hl,(loop_counter)		;our clock, a defw
	inc hl
	ld (loop_counter),hl
	ld a,(mothcount)		;have all (red) moths been shot?
	or a
	jp z,level_completed		;nope, some left keep playing
	ld a,(deadflag)			;are we dead?
	cp 255				;by checking if deadflag set
	jr nz,mglp			;keep looping mglp if not (main game loop without the print score bit)
deadscreen				;all 3 lives lost
	ld hl,bang
	ld (graphpoint),hl		;bang graphic
	xor a
	ld (frame),a
	ld a,50
	ld (clen+1),a			;length of duration of bang
	ld b,6
deadlp	push bc				;crash noises when dead
	ld ix,scadd
	call delspr
	call colspr
	ld b,1
	ld a,(frame)
	inc a
	ld (frame),a
	call drspr
	call crash
	ld a,(clen+1)			;bend length of crash so it sounds better (only slightly, still naff!)
	sub 8
	ld (clen+1),a
	pop bc
	djnz deadlp
	ld ix,scadd
	call delay		
	ret				;return to just after 'call main_game_loop'
	;
level_completed				;YAY!
	ld a,50				;this is a duration in a beep routine
	ld (clen+1),a
	ld b,6
lclp	push bc
	call crash			;loop is decreased each time so makes a bending sound
	ld a,(clen+1)
	sub 8
	ld (clen+1),a
	pop bc
	djnz lclp
	call scrash
	call oh_yeah			;SHIRU's excellent OH YEAH! noise
	call delay
	call add_1			;add 1 to level
	ld a,(level)			;next level, keep as a defb, doubt anyone will play beyond 256!  maybe a kill screen in order
	inc a
	ld (level),a
	cp 10
	call nc,keepnine		;this will mess up the ascii, 9000 points is the max you get matey
	ld b,a				;for add1000 score, 1000 to 9000
	add a,48
	ld (bonus),a			;changes 1-9000 for bonus score (ASCII)
	call add_1000			;add b thousands to score, (1-9,000)
	jp success_screen		;now big flashy score screen
	;
keepnine
	ld a,9
	ret
	;
delay	ld b,40				;called from various places, 80% of a second pause
delaylp	halt
	djnz delaylp
	ret
	;
anti_hack				;this proved feeble, Andrew Ryals got it in 10 mins
	ld de,56
	add hl,de			;point hl to the bit where we check it's still 'dec a' = defb 61
	cp b				;b is 61
	ret z
	ld (hl),b			;if different poke 61 in
	ret
	;
print_lives				;prints the correct number of molerat udgs for # of lives
	ld ix,string9			;delete old lives first
	ld de,16384
	call print_string
	ld a,(lives)
	or a
	ret z				;just in case this gets called with zero lives, b would overshoot, avoid
	ld b,a
	ld hl,mol			;molerat udg
	ld de,16384			;screen address
pllp	push de
	push hl
	call print_char
	pop hl
	pop de
	inc e
	djnz pllp
	ret
	;	
white_frame				;bit silly this I suppose, pokes the white frame into the buffer
	ld hl,49152+64			;I'm doing this so we have all block zero and 1 as blocks we can move through
	ld (hl),127			;at least people can POKE 42220,201 to stop white frame if they don't like it
	inc l
	ld b,29
wf1	ld (hl),255
	inc l
	djnz wf1
	ld (hl),254
	ex de,hl
	ld b,175
wf2	call nextlinedn
	ld a,1
	ld (de),a
	djnz wf2
	ex de,hl
	ld (hl),254
	dec l
	ld b,29
wf3	ld (hl),255
	dec l
	djnz wf3
	ld (hl),127
	ex de,hl
	ld b,174
wf4	call nextlineup
	ld a,128
	ld (de),a
	djnz wf4
	ret				;PHEW!  Lazy lazy coder.
	;
print_blocks				;block printing in buffer, slightly different to printstring
	ld a,(ix+0)			;get first byte
	cp 255				;255 marks the end of the string
	ret z
	call get_block			;points hl at start of correct graphic
	push af
	push de
	call print_char			;print at char cell that de is pointing at
	pop de
	pop af
	call colour_block
	inc e
	call z,newsegment
	inc ix
	jr print_blocks
	;
print_score				;in game ands faster than print_string, less checks and fancy bits
	ld ix,score			;score string as ASCII
	ld de,16384+32			;position of score on screen
pslp	ld a,(ix+0)
	cp 255				;end of string
	ret z
	call get_char
	push de
	call print_char
	pop de
	inc e
	inc ix
	jr pslp
	;
print_level				;overprints the current level suring the game
	ld ix,levelstr			;score string as ASCII
	ld de,16384+18			;position of score on screen
	jr pslp				;use print score routine above
	;
		defb	'000'		;you never know how far players might get :-)
levelstr	defb	'001',255,255	;level number as an ascii string
levelstrstore	defb	'001'
	;
bigfont	ld a,(ix+0)			;turns ascii string into 16x16 printout, call with ix at string, de at screen
	cp 255				;end of string
	ret z
	call get_char
	push de
	ex de,hl			;de now pointing at graphic, hl at screen
	call print_big_char
	pop de
	inc ix
	inc e
	inc e
	jr bigfont
	ret
	;
get_char				;takes ASCII in 'a' and points hl at corresponding graphic
	ld h,0
	ld l,a
	add hl,hl
	add hl,hl
	add hl,hl
	ld bc,(fontseed)
	add hl,bc
	ret
	;
print_big_char				;BIG 16x16 printing stuff
	ld b,8
pbclp	push bc
	call fatline
	call nexthldn
	pop bc
	djnz pbclp
	ret
	;
fatline	ld a,(de)	
	ld c,128			;when this is rr c out we have finished one byte
cont3	rra
	push af
	rr c
	pop af
	rr c
	jr nc,cont3
	;
bits2	ld b,128			;when this is rr c out we have finished one byte
cont2	rra
	push af
	rr b
	pop af
	rr b
	jr nc,cont2
	;
	ld (hl),b
	inc l
	ld (hl),c
	call nexthldn
	ld (hl),c
	dec l
	ld (hl),b
	inc de				;next byte of graphic
	ret
	;
nexthldn				;converts hl to next line down in DF, modifies from various
	ld a,h				;only used by bigprint, other nextlinedn is in DE
	inc h
	and 7
	cp 7
	ret nz
	ld a,l
	add a,32
	ld l,a
	ret c
	ld a,h
	sub 8
	ld h,a
	ret
	;
print_string				;print string with various in string control codes
	ld a,(ix+0)			;get first byte
	cp 255				;255 marks the end of the string
	ret z
	cp 254				;254 means continue but next row down
	jp z,newstringrow
	cp 253
	jp z,newstringadd		;253 means the next two bytes are a new screen address
	cp 252
	jp z,newfontcolour		;252 means the next byte is a new font colour
	cp 251
	call z,print_udg		;252 means the next byte is a udg, so change fontseed
	call get_char			;points hl at start of correct graphic
	push de
	call print_char			;print at char cell that de is pointing at
	pop de
	call colour_char
	inc e
	call z,newsegment
	inc ix
	ld hl,15616-256
	ld (fontseed),hl
	jr print_string
	;
newstringrow
	ld a,e
	and 224
	add a,32
	call z,newsegment	
	inc ix				;skip over byte 254 to displacement along next row
	or (ix+0)			;or new column number in
	ld e,a
	inc ix
	jp print_string
	;
newsegment				;for when we are about to spill into a new segment during a print rouinte
	push af
	ld a,d
	add a,8
	ld d,a
	pop af
	ret
	;
newstringadd
	inc ix				;skip over indicator byte (253)
	ld e,(ix+0)			;get new screen address
	ld d,(ix+1)
	inc ix
	inc ix				;skip over address
	jp print_string
	;
newfontcolour
	inc ix				;skip over new colour indicator byte (252)
	ld a,(ix+0)			;get new colour byte
	ld (fontcolour+1),a		;poke new value into colouring routine
	inc ix				;skip over colour byte
	jp print_string
	;
get_block				;for game maze printing
	ld h,0				;same as get_char but different graphics pointer, could easily have used get char & changed the seed tho
	ld l,a
	add hl,hl
	add hl,hl
	add hl,hl
	ld bc,blocks			;can be changed easily
	add hl,bc
	ret
	;
get_spc	ld hl,spc			;used in refine key routine
	ret				;alternative udgs for non standard keys, Spc, CC, SS, Enter
get_ent	ld hl,ent
	ret
get_caps
	ld hl,csf
	ret
get_s_shft
	ld hl,ssf
	ret
	;
print_char			;arrive with de pointing at screen, hl at graphic
	ld a,(hl)		;take byte
	ld (de),a		;and put it on the screen
	inc d			;next line of char down
	inc hl			;next byte of graphic
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	inc d
	inc hl
	ld a,(hl)
	ld (de),a
	ret
	;
or_char			;arrive with de pointing at screen, hl at graphic, USED for printing bullet during game
	ld a,(de)	;take byte
	or (hl)
	ld (de),a	;and put it on the screen
	inc d		;next line of char down
	inc hl		;next byte of graphic
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	inc d
	inc hl
	ld a,(de)
	or (hl)
	ld (de),a
	ret
	;
delchar	ld de,(oldbullsc)	;delete old first	;DELETES A CHAR FROM BUFFER TO SCREEN
	ld h,d
	ld l,e			;point hl at buffer
	set 7,h			;which is 128 high bytes above display file
	ld a,(hl)
	ld (de),a
	inc d			;we are always within a char, so inc h/d ok
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	inc d
	inc h
	ld a,(hl)
	ld (de),a
	ret
	;
colour_char
	push de
	pop hl
	call screen2att
fontcolour
	ld (hl),15		;font colour, poke value in if non default wanted
	ret
	;
colour_block			;arrive with a pointing at ascii
	ld bc,colours
	ld h,0
	ld l,a
	add hl,bc
	ld a,(hl)
	push af
	push de			;de holds screen address
	pop hl			;which we need in hl..
	call screen2att		;...for this subroutine to calculate attrs
	pop af
	ld (hl),a		;hl pointing at attribute cell
	ret
	;
print_udg
	ld hl,udgs
	ld (fontseed),hl
	inc ix
	ld a,(ix+0)
	ret
	;
;SPRITE DISPLAY/DELETE AND SCREEN/ATTR related stuff
delete	ld ix,sprite_table		;moves unaltered background buffer at 49152 to screen at sprite old position (hl at buffer, de at screen)
	ld b,number_of_sprites
	;
delp	call delspr
	;
	ld de,length_of_sprite_table
	add ix,de
	djnz delp
	ret
	;
delspr	ld a,(ix+31)			;is it switched on?)
	or a
	ret z
delp2	ld d,(ix+3)			;get old screen address to delete
	ld e,(ix+2)			;point de at old screen address, moving from equivalent place in buffer to here	
del2	ld c,255			;using ldi, so ensure we don't set z flag while doing so
	ld h,d				;line1
	ld l,e
	set 7,h				;buffer is at 49152, 128 high bytes above screen address, point hl there
	ldi				;>> draw two bytes to the right
	ld a,(hl)
	ld (de),a
	call nextlinedn			;next line down on screen
	ld h,d				;line2
	ld l,e
	set 7,h
	ldd				;<< draw two bytes to the left
	ld a,(hl)
	ld (de),a
	call nextlinedn
	ld h,d				;line3
	ld l,e
	set 7,h				;buffer is at 49152, 128 high bytes above screen address
	ldi				;>> draw two bytes to the right
	ld a,(hl)
	ld (de),a
	call nextlinedn			;next line down on screen
	ld h,d				;line4
	ld l,e
	set 7,h
	ldd				;<< draw two bytes to the left
	ld a,(hl)
	ld (de),a
	call nextlinedn
	ld h,d				;line5
	ld l,e
	set 7,h				;buffer is at 49152, 128 high bytes above screen address
	ldi				;>> draw two bytes to the right
	ld a,(hl)
	ld (de),a
	call nextlinedn			;next line down on screen
	ld h,d				;line6
	ld l,e
	set 7,h
	ldd				;<< draw two bytes to the left
	ld a,(hl)
	ld (de),a
	call nextlinedn
	ld h,d				;line7
	ld l,e
	set 7,h				;buffer is at 49152, 128 high bytes above screen address
	ldi				;>> draw two bytes to the right
	ld a,(hl)
	ld (de),a
	call nextlinedn			;next line down on screen
	ld h,d				;line8
	ld l,e
	set 7,h
	ldd				;<< draw two bytes to the left
	ld a,(hl)
	ld (de),a
	ret
	;
drawbullet				;when bullet in play, deletes & draws appropriate frame 
	ld a,(shootflag)
	or a				;<>0 means there's a bullet to print
	ret z
	call delchar
	call delcol
	ld bc,(bullgraphpoint)
	ld a,(bullframe)
	ld h,0
	ld l,a
	add hl,hl
	add hl,hl
	add hl,hl
	add hl,bc
	ld de,(bullscadd)
	ld (oldbullsc),de		;for deleting next time
	call or_char
	ld hl,(bull_map_pos)		;now colour in new position
	res 7,h
	ld (hl),79			;white ink bullet
	ret
	;
drawsprite				;ORs sprite onto screen, ahead of raster after halt.  ~11 sprites (just) possible this way
	ld ix,sprite_table
	ld b,number_of_sprites
	;
drspr	ld a,(ix+31)			;is sprite switched on?
	or a
	jr z,drmiss	
	ld d,(ix+1)
	ld e,(ix+0)			;point de at screen address
	ld (ix+3),d
	ld (ix+2),e			;put into old screen address to delete here next time round
	ld a,(ix+16)			;frame 0-3 as we're moving right
	add a,a				;x2
	add a,a				;x4
	add a,a				;x8
	add a,a				;x16
	ld h,(ix+7)
	ld l,(ix+6)			;point hl at (graphpoint), differs according to which direction we're facing
	add a,l
	ld l,a				;hl now pointing at graphic
	ld a,(de)			;get byte of screen
	or (hl)				;OR graphic into it
	ld (de),a			;put it on the screen, line 1 drawing>>
	inc l				;next byte for the..
	inc e				;next column along
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 2 drawing<<
	or (hl)
	ld (de),a
	inc l
	dec e
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 3 drawing >>
	or (hl)
	ld (de),a
	inc l
	inc e
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 4 drawing<<
	or (hl)
	ld (de),a
	inc l
	dec e
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 5 drawing >>
	or (hl)
	ld (de),a
	inc l
	inc e
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 6 drawing<<
	or (hl)
	ld (de),a
	inc l
	dec e
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 7 drawing >>
	or (hl)
	ld (de),a
	inc l
	inc de
	ld a,(de)
	or (hl)
	ld (de),a
	inc l
	call nextlinedn
	ld a,(de)			;line 8 drawing<<
	or (hl)
	ld (de),a
	inc l
	dec e
	ld a,(de)
	or (hl)
	ld (de),a
	;
drmiss	ld de,length_of_sprite_table
	add ix,de
	dec b
	jp nz,drspr
	ret
	;
coloursprite
	ld ix,sprite_table
	ld b,number_of_sprites
colp	push bc	
	call colspr
	pop bc
	ld de,length_of_sprite_table
	add ix,de
	djnz colp
	ret
	;
;PART OF COLOURSPRITE routine
colspr	ld a,(ix+31)		;is sprite switched on?
	or a
	ret z	
	call delatt		;delete old attr by moving attribute buffer to screen
	ld h,(ix+1)		;now colour new squares
	ld l,(ix+0)		;point hl to new screen address
	call screen2att		;hl to corresponding attr
	ld a,(ix+18)		;is direction 0?
	cp 128
	jr z,onecell		;if not moving the sprite is only in the first cell, only colour one
	cp 2			;if moving up or down we colour differently
	jr nc,colvert
collat	ld a,(ix+17)		;get colour
	ld (hl),a
	inc l
	bit 6,(hl)		;this is superfluous, actually a ghost from a previous game where the blocks were non bright
	ret z
	ld (hl),a
	ret
colvert	ld bc,32
	ld a,(ix+17)
	ld (hl),a
	add hl,bc
	bit 6,(hl)		;this is superfluous, actually a ghost from a previous game where the blocks were non bright
	ret z
	ld (hl),a
	ret
onecell	ld a,(ix+17)
	ld (hl),a
	ret
	;
delatt	ld h,(ix+3)		;delete old attr
	ld l,(ix+2)		;point hl at old screen address
	call screen2att		;point hl at equivalent attr
	ld d,h
	ld e,l
	set 5,h			;attribute buffer 5 high bytes above attrs
	ld bc,32
	ldi
	ldi
	ld bc,30		;NEEDED? check
	add hl,bc
	res 5,h
	ld d,h
	ld e,l
	set 5,h
	ldi
	ldi
	ret
	;
buildingflash
	ld a,(smugtimer)
	or a
	ret z
	ld hl,(buildingseed)	;make building flash while waiting
	set 7,(hl)
	inc l
	set 7,(hl)
	ld de,32
	add hl,de
	set 7,(hl)
	dec l
	set 7,(hl)
	dec a			;dec timer
	ld (smugtimer),a
	ret nz
	;
	ld a,8
	ld (specswitch),a	;turn on spectrum smuggler
	;
	ld hl,0
	ld (loop_counter),hl	;reset clock to avoid too much calling
	;
	ld hl,(buildingseed)	;unset building flash
	res 7,(hl)
	inc l
	res 7,(hl)
	add hl,de		;de should hold 32!
	res 7,(hl)
	dec l
	res 7,(hl)	
	ret	
buildingseed	defw	22528+96+1
	;
nextlineup			;following couple modified from 'ADVANCED MACHINE CODE' book
	ld a,d
	dec d
	and 7
	ret nz
	ld a,e
	sub 32
	ld e,a
	ret c
	ld a,d
	add a,8
	ld d,a
	ret
	;
nextlinedn			;converts de to next line down in DF, modifies from various
	ld a,d
	inc d
	and 7
	cp 7
	ret nz
	ld a,e
	add a,32
	ld e,a
	ret c
	ld a,d
	sub 8
	ld d,a
	ret
	;
	;
screen2att	;from 'ADVANCED SPECTRUM MACHINE LANGUAGE'
	ld a,h	;arrive with hl pointing at display file address
	rrca	;exits with hl pointing at corresponding attribute cell
	rrca
	rrca
	and 3
	or 88
	ld h,a
	ret
	;
map2screen	;modified, takes map byte at 49152+6144 and converts to screen address
	ld a,h	;from ADVANCED SPECTRUM MACHINE LANGUAGE
	and 3	;arrive with hl pointing at attribute (or map following buffer)
	rlca	;returns with hl pointing at screen
	rlca
	rlca
	or 64
	ld h,a
	ret
	;
;;PATRICK RAK's XOR SHIFT RANDOM NUMBER GENERATOR, set hl and de as seed then just call when you want, returns rnd in a
rnd     ld  hl,0xA280   ; xz -> yw		;SEEDS SET ON ENTRY
        ld  de,0xC0DE   ; yw -> zt
        ld  (rnd+1),de  ; x = y, z = w
        ld  a,e         ; w = w ^ ( w << 3 )
        add a,a
        add a,a
        add a,a
        xor e
        ld  e,a
        ld  a,h         ; t = x ^ (x << 1)
        add a,a
        xor h
        ld  d,a
        rra             ; t = t ^ (t >> 1) ^ w
        xor d
        xor e
        ld  h,l         ; y = z
        ld  l,a         ; w = t
        ld  (rnd+4),hl
        ret
	;
	;
ldir_buffer_to_screen
	ld hl,49152		;now move buffer contents to screen
	ld de,16384
	ld bc,6144
	ldir
	ret
	;
ldir_attrs_to_buffer
	ld hl,22528
	ld de,30720
	ld bc,768
	ldir
	ret
	;
bluescreen			;a few subroutines used together a few times for blue screen clear
	call clear_screen	;cls
	call colour_paper	;fills screen with attribute in (paper) variable
	call colour_border	;outs border with (border) variable
	ret
	;
clear_screen
	ld hl,16384
	ld e,1
	ld d,h
	ld (hl),0
	ld bc,6143
	ldir
	ret
	;
colour_paper
	ld a,(paper)
colp2	ld hl,22528
	ld d,h
	ld e,1
	ld (hl),a
	ld bc,767
	ldir
	ret
	;
colour_border
	ld a,(border)
	out (254),a
	ret
	;
no_key	xor a			;wait for no key press
	in a,(254)
	and 31
	xor 31
	jr nz,no_key
	ret
	;
any_key	call no_key		;want to have no key pressed first eh?	
anykk	xor a			;wait for any key press, a pointing at all ports
	in a,(254)
	and 31
	xor 31
	jr z,anykk
	ret
	;
any_key2
	call no_key		;want to have no key pressed though first eh?	
anyk	inc hl
	dec de			;for random seed setting	
	xor a			;wait for any key press, a pointing at all ports
	in a,(254)
	and 31
	xor 31
	jr z,anyk
	ret
	;
;;;DEFINE KEY ROUTINE;;;
refine_keys
	call no_key		;easy tiger
	ld ix,string3		;'UP'
	ld de,18432+11		;overwrite REFINE KEYS
	call print_string
	ld ix,bc1		;where key data is logged in memory
	ld hl,and1
	call do_key
	;
	ld ix,string4		;'DOWN
	ld de,18432+11
	call print_string
	ld ix,bc2
	ld hl,and2
	call do_key
	;
	ld ix,string5		;'LEFT'
	ld de,18432+11
	call print_string
	ld ix,bc3
	ld hl,and3
	call do_key
	;
	ld ix,string6		;'RIGHT'
	ld de,18432+11
	call print_string
	ld ix,bc4
	ld hl,and4
	call do_key
	;
	ld ix,string7		;'FIRE'
	ld de,18432+11
	call print_string
	ld ix,bc5
	ld hl,and5
	call do_key
	;
	ld ix,string8		;'PAUSE'
	ld de,18432+11
	call print_string
	ld ix,bc6
	ld hl,and6
	call do_key		

	jp introscreen		;print new introscreen & exit
	;
do_key	call refkey		;wait for key press and log its port and bit at ix and (hl)
	push de
	call last_key_pressed
	pop de
	dec e
	dec e
	ld a,(ASCII_CODE)
	call get_char
	cp ' '			;if space pressed we have a special graphic
	call z,get_spc
	cp 1
	call z,get_caps		;ditto caps shift
	cp 2
	call z,get_ent		;ditto enter key
	cp 3
	call z,get_s_shft	;ditto symbol shift
	call print_char
	call longzap
	ld b,20
dklp	halt
	djnz dklp
	call no_key
	ret
	
	

refkey	ld bc,65278		;the highest port, 254 in both b and c
rdlp1	in a,(c)		;read that key row, check for keypress
	and 31
	xor 31			;if no key pressed, xor 31 gives zero
	jr nz,get_key		;aha! a key pressed, record it
cont	rlc b			;no key pressed, scroll through all the ports to check for more
	jr rdlp1		;continue checking until we have all 5 keys
	;
get_key
	ld (hl),a		;hl is pointing at the bit where you AND, eg 1 for bit 0, 2 for bit 1 etc
	ld (ix+0),c
	ld (ix+1),b		;get bc port which key press relates to
	ret
	;
get_key_pressed
	xor a
	ld (ASCII_CODE),a
gkplp	call last_key_pressed
	ld a,(ASCII_CODE)
	cp '1'			;refinekeys
	ret z
	cp '2'
	ret z
	jr gkplp
	;
;REPLACES (23560) ROM ROUTINE
last_key_pressed		;read all keys and puts corresponding ascii to key in (ASCII_CODE)
	ld bc,65278		;port 254 in b (ZXCVetc) and 254 in c (ie key row 0)
	ld hl,letters		;start of ASCII table (in same order as keys)
keyread	in a,(c)		;get INs on current row bc is pointing at
	ld d,5			;5 keys/bits to check in a
krlp	rra			;outermost key on row, bit 0
	call nc,log_key
	inc hl			;move pointer through ascii/key table
	dec d			;ext key/bit until all 5 done
	jr nz,krlp
	rlc b			;scroll through all key rows 0-7
	jr c,keyread		;when no carry, we have gone through all 8 ports
	ret
log_key				;we arrive here with hl pointing at correct part of table for key press
	push af
	ld a,(hl)		;get asciicode
	ld (ASCII_CODE),a	;and store it
	pop af
	ret
	;
	;;ASCII stuff, each set the keys as read in order from port 254,254.  1=CapsShift,2=Enter,3=Symbshift;;	
letters		defb	1,'ZXCVASDFGQWERT1234509876POIUY',2,'LKJH ',3,'MNB'	;
ASCII_CODE	defb	0,0	;where we store the ASCII of the last key pressed, first byte is actual ascii, second is 1,2or 3, caps,enter,symsh
	;
check_keys
	ld bc,(bc4)
	ld hl,and4
	in a,(c)
	and (hl)
	jr z,setrt
	ld bc,(bc3)
	ld hl,and3
	in a,(c)
	and (hl)
	jr z,setlt
	ld bc,(bc1)
	ld hl,and1
	in a,(c)
	and (hl)
	jr z,setup
	ld bc,(bc2)
	ld hl,and2
	in a,(c)
	and (hl)
	jr z,setdn
	;ld bc,(bc5)
	;ld hl,and5
	;in a,(c)
	;and (hl)
	;jp z,fire
	ld bc,(bc6)
	ld hl,and6
	in a,(c)
	and (hl)
	jp z,any_key	;pause
	ret
	;
firekey	ld bc,(bc5)
	ld hl,and5
	in a,(c)
	and (hl)
	jp z,fire
	ret
	;
setrt	ld a,1			;puts directional code into new direction byte (player only)
	ld (newdir),a
	ret
setlt	xor a
	ld (newdir),a
	ret
setup	ld a,2
	ld (newdir),a
	ret
setdn	ld a,3	
	ld (newdir),a
	ret
	;
and1	defb	1			;these addresses loaded with bc and AND data for keyread in main loop
and2	defb	1
and3	defb	2
and4	defb	1
and5	defb	1
and6	defb	16
bc1	defw	64510
bc2	defw	65022			;default set for the holy four
bc3	defw	57342
bc4	defw	57342
bc5	defw	32766			;space row
bc6	defw	49150
	defb	0,0,0,0,0,0,0,0		;surely not necessary but I don't want to risk overwrite bugs
	;
;control aspects, player and guardian
set_directions_and_move			;player control first
	ld ix,sprite_table
	ld a,(loop_counter)		;slows sprite down if <> 0
	and (ix+29)
	cp (ix+29)
	jr nz,miss4
	ld a,(charflg)
	or a
	jr nz,miss3
	call check_available_directions
	call check_new_direction
	call check_and_set_direction
miss3	ld b,(ix+30)		;1 here is normal speed, 2 is turbo (it's the # of times move is called	
mslp2	call move_sprite
	djnz mslp2
	;
	call death_check	;
	;
miss4	ld ix,gscadd		;now guardians
	ld b,number_of_sprites-1
sdmlp	push bc
	;
	call chall
	;
	pop bc
	ld de,length_of_sprite_table
	add ix,de
	djnz sdmlp
	ret
	;
chall	ld a,(ix+31)		;is sprite switched on?
	cp 8
	ret nz	
	ld a,(loop_counter)
	and (ix+29)		;slows down sprite if <>0
	cp (ix+29)
	ret nz	
	ld a,(ix+24)		;charlfg
	or a			;if between char cells we don't change anything yet
	jr nz,miss
	call check_available_directions
	call check_new_direction
	call check_and_set_direction
miss	ld b,(ix+30)		;1 here is normal speed, 2 is turbo (it's the # of times move is called	
mslp	call move_sprite
	djnz mslp
	ret
	;
check_available_directions
	ld a,(loop_counter)
	ld h,(ix+5)
	ld l,(ix+4)		;point hl at (map_position)
	push hl
	call check_right	;checks block/space etc and puts value in ix table, doesn't alter map position
	ld (ix+20),a
	pop hl
	push hl
	call check_left
	ld (ix+21),a
	pop hl
	push hl
	call check_up
	ld (ix+22),a
	pop hl
	call check_down
	ld (ix+23),a
	ret
	;
check_right			;these check routines: hl is pointing at the block map and returns with the block type
	inc hl
	ld a,(hl)
	ret
	;
check_left
	dec hl
	ld a,(hl)
	ret
	;
check_up
	ld de,65504
	add hl,de
	ld a,(hl)
	ret
	;
check_down
	ld de,32
	add hl,de
	ld a,(hl)
	ret
	;
check_new_direction		;check if desired direction is possible, and set if so
	ld a,(ix+19)		;desired direction
	or a			;cp 0
	jr z,chnewl
	dec a			;cp 1
	jr z,chnewr
	dec a			;cp 2
	jr z,chnewu
	dec a			;cp 3
	jr z,chnewd
	ret
	;
chnewr
	ld a,(ix+20)
	cp 2			;collectables are, blocks 2+
	ret nc			;>2? block in the way
	ld (ix+18),1		;(direction)
	ret
chnewl
	ld a,(ix+21)
	cp 2			;collectables are 0-1, blocks 2+
	ret nc
	ld (ix+18),0		;(direction)
	ret
	;
chnewu
	ld a,(ix+22)
	cp (ix+28)		;collectables are 0-1, blocks 2+NB using ix+28 here, as specchaser cannot go up to the top due to raster problems
	ret nc
	ld (ix+18),2		;(direction)
	ret
	;
chnewd
	ld a,(ix+23)
	cp 2			;collectables are 0-1, blocks 2+
	ret nc
	ld (ix+18),3		;(direction)
	ret
	;
check_and_set_direction
	ld h,(ix+5)
	ld l,(ix+4)		;(map position)
	ld a,(ix+18)		;(direction)so this is either the newly selected or old direction, check if possible and set new map position
	or a			;cp 0
	jr z,try_left
	dec a			;cp 1
	jr z,try_right
	dec a			;cp 2
	jr z,try_up
	dec a			;cp 3
	jr z,try_down
	ret
try_down
	call check_down
	cp 2			;collectables are 0-7, blocks <8
	jr nc,stop_sprite1
	ld (ix+5),h
	ld (ix+4),l		;put new (map position) in
	ld h,(ix+15)
	ld l,(ix+14)		;down facing graphic
	ld (ix+7),h
	ld (ix+6),l		;and put into graphic pointer
	ret
try_right
	call check_right
	cp 2			;collectables are 0-7, blocks <8
	jr nc,stop_sprite2
	ld (ix+5),h
	ld (ix+4),l		;put new (map position) in
	ld h,(ix+9)
	ld l,(ix+8)		;right facing graphic
	ld (ix+7),h
	ld (ix+6),l		;and put into graphic pointer
	ret
try_left
	call check_left
	cp 2			;collectables are 0-7, blocks <8
	jr nc,stop_sprite3
	ld (ix+5),h
	ld (ix+4),l		;put new (map position) in
	ld h,(ix+11)
	ld l,(ix+10)		;left facing graphic
	ld (ix+7),h
	ld (ix+6),l		;and put into graphic pointer
	ret
try_up
	call check_up
	cp (ix+28)		; < NB using ix+28 here, as specchaser cannot go up to the top due to raster problems
	jr nc,stop_sprite4
	ld (ix+5),h
	ld (ix+4),l		;put new (map position) in
	ld h,(ix+13)
	ld l,(ix+12)		;up facing graphic
	ld (ix+7),h
	ld (ix+6),l		;and put into graphic pointer
	ret
stop_sprite1			;ok sprite is in a unmovable position, keep trying till we find one
	ld a,1
	ld (ix+18),a
	ld (ix+19),a
	jp check_and_set_direction
stop_sprite2
	ld a,2
	ld (ix+18),a
	ld (ix+19),a
	jp check_and_set_direction
stop_sprite3
	ld a,3
	ld (ix+18),a
	ld (ix+19),a
	jp check_and_set_direction
stop_sprite4
	xor a
	ld (ix+18),a
	ld (ix+19),a
	jp check_and_set_direction
	;
death_check			;check for collision of map position between player and all active baddies
	ld ix,gscadd
	ld b,number_of_sprites-1
dclp2	ld a,(ix+31)		;is sprite switched on?
	cp 8
	jr nz,dmiss	
	ld hl,(map_position)	
	ld d,(ix+5)		;guardian map position
	ld e,(ix+4)
	ld a,h			;check if same as player (map_position)
	xor d
	ld d,a
	ld a,l
	xor e
	or d
	jr nz,dmiss
	ld a,255		;set deadflag if so
	ld (deadflag),a
dmiss	ld de,length_of_sprite_table
	add ix,de
	djnz dclp2
	ret
	;
bullet_check			;checks if bullet collides with guardian
	ld a,(shootflag)	;is there a bullet in play?
	or a
	ret z
	ld ix,gscadd
	ld b,number_of_sprites-1
bclp2	ld a,(ix+31)		;is sprite switched on
	cp 8
	jr nz,bcmiss	
	ld hl,(bull_map_pos)	
	ld d,(ix+5)		;guardian map position
	ld e,(ix+4)
	ld a,h			;check if same as bullet (map_position)
	xor d
	ld d,a
	ld a,l
	xor e
	or d
	jr nz,bcmiss		;no collision, miss switch off
	ld a,(mothcount)	;one less foe
	dec a
	ld (mothcount),a
	xor a
	ld (ix+24),a		;zero charflag to enable gcont
	ld (ix+16),a		;ditto frame so we see the full explode animation
	dec (ix+31)		;turn sprite into explde mode, from 8 into 7, whence it starts the explode via gcont
	ld hl,bang		;explode graphic
	ld (ix+7),h
	ld (ix+6),l		;inro graphpoint
	call delp2		;delete ghost graphic
	ld h,(ix+1)
	ld l,(ix+0)		;hl at gscadd
	call dc2		;delete ghost attribute
	call add_10		;add ten to the score
	ld a,(ix+32)		;have we hit a normal sprite (+10) or a spectrum smuggler (+250 points)?
	or a
	call nz,add_240		;if so +10 +240 = +250 points
	push ix
	call print_score
	pop ix
	jp unset_bullet		;and turn bullet off
bcmiss	ld de,length_of_sprite_table
	add ix,de
	djnz bclp2
	ret
	;
guardian_control
	ld ix,gscadd
	ld b,number_of_sprites-1	;minus the player
gclp	push bc
	call gcont
	pop bc
	ld de,length_of_sprite_table
	add ix,de
	djnz gclp
	ret
	;
gcont	ld a,(ix+31)		;is sprite switched on?
	or a			;rem 8 is on, 0 off totally, 1-7 exploding but not controlled
	ret z		
	cp 8
	jp c,exploding		;0 is off, 1-7 exploding, 8 on
	ld a,(ix+24)		;charflg
	or a			;we don't decide anything if we're moving between char cells
	ret nz
	ld a,(loop_counter)	;avoids change of direction too often
	cp (ix+27)		;probability of direction change
	ret nc
miss2	call rnd
	cp (ix+26)		;this is the chase probability byte
	jr c,gchase
gmove	ld a,(ix+25)		;1 means our last move was a lateral one, so toggle
	rra
	jr nc,vertmove
latmove
	ld a,(ix+18)		;direction byte
	cp 2
	jr c,vertmove
	inc (ix+25)
	call rnd
	rra
	jr c,gsetrt
	jr gsetlt
vertmove
	ld a,(ix+18)		;direction byte
	cp 2
	jr nc,latmove
	inc (ix+25)
	call rnd
	rra
	jr c,gsetup
	jr gsetdn
gchase	ld a,(ix+18)		;have we hit a block?
	rla
	jr c,gmove		;yep, this avoids sticking and gives an unpredictable nature to the chase
latchase	
	ld a,(ix+18)		;get current direction of movement
	cp 2			;if currently moving laterally (0+1) then we want a vertical move next
	jr c,vertchase
lhere	ld a,(scadd)		;player screen address low byte
	and 31			;get columns only
	ld c,a
	ld a,(ix+0)		;guardian screen address low byte	
	and 31
	cp c
	jr c,gsetrt
	jr gsetlt
	;
vertchase			;dictates vertical move
	ld a,(ix+18)
	cp 2
	jr nc,latchase
	ld a,(map_position+1)	;chasing by segments, lazy? high byte is either 64, 72, or 80
	cp (ix+5)
	jr z,segchase		;same segment, so choose closer chase
	jr c,gsetup
	jr gsetdn
	;
gsetlt	ld (ix+19),0		;put indicator byte into (gnewdir)
	ret
gsetrt	ld (ix+19),1
	ret
gsetup	ld (ix+19),2
	ret
gsetdn	ld (ix+19),3
	ret	
	;
segchase			;player and guardian in same segment, so refine chase
	ld a,(map_position)	;same relationship and attributes
	and 224
	ld b,a
	ld a,(ix+4)
	and 224
	cp b
	jr z,lhere
	jr c,gsetdn
	jr gsetup
	;
exploding
	ld a,(loop_counter)	;slow down the explosion so it looks better eh
	rra
	ret c
	ld a,(ix+31)
	ld (bangflag+1),a
	dec (ix+31)		;dec counter, stops cycling at zero
	push af
	call z,delatt		;if full cycle then we delete old colour
	pop af
	call z,delp2		;and delete ghost sprite
	inc (ix+16)		;scroll up through frame
	ret
	;
move_sprite
	ld a,(ix+18)		;(direction)
	cp 128			;128 means sprite not able to move
	ret z
	or a			;cp 0
	jr z,left
	dec a			;cp 1
	jr z,right
	dec a			;cp 2
	jr z,up
	dec a			;cp 3
	jr z,down
	ret
	;
up	ld d,(ix+1)
	ld e,(ix+0)		;point de at (scadd)
	call nextlineup
	ld (ix+1),d
	ld (ix+0),e
	ld a,(ix+16)		;frame
	inc a
	and 7
	ld (ix+16),a
	ld a,d
	and 7
	ld (ix+24),a		;charflag
	ret
	;
down	ld d,(ix+1)
	ld e,(ix+0)		;point de at (scadd)
	call nextlinedn
	ld (ix+1),d
	ld (ix+0),e
	ld a,(ix+16)		;frame
	inc a
	and 7
	ld (ix+16),a
	ld a,d
	and 7
	ld (ix+24),a		;charflag
	ret	
	;
right	ld a,(ix+16)		;(frame)
	inc a
	and 7
	ld (ix+16),a		;new frame
	ld (ix+24),a
	ret nz
	inc (ix+0)		;full sprite cycle complete, next column right
	ret
	;
left	ld a,(ix+16)
	dec a
	and 7
	ld (ix+16),a		;frame
	ld (ix+24),a
	cp 7
	ret nz
	dec (ix+0)		;full sprite cycle complete, next column left
	ret
	;
fire	ld a,(shootflag)		;already shooting?
	or a
	ret nz				;yes return until it's done
	ld a,(direction)
	cp 128				;we don't shoot when stationary, and that's only at the very beginning
	ret z
	ld a,255			;ok new bullet wanted on the screen, set up some variables and set the flag
	ld (shootflag),a
	ld a,10
	ld (shootnoiseflag),a		;nice noise with fire
	ld hl,(map_position)
	ld (bull_map_pos),hl		;as will the map position
	call map2screen
	ld (bullscadd),hl
	ld a,(direction)		;and current player direction
	ld (bulldirection),a
	ret
	;
shooter	ld a,(shootflag)		;controls bullet when in play
	or a
	ret z
	ld a,(bulldirection)
csh	or a		;cp 0
	jr z,bullet_left
	dec a		;cp 1
	jr z,bullet_right
	dec a		;cp 2
	jr z,bullet_up
	dec a		;cp 3
	jr z,bullet_down
	ret
bullet_left			;ok bullet going left
	ld hl,bulllt
	ld (bullgraphpoint),hl
	ld a,(bullframe)
	dec a
	and 3
	ld (bullframe),a
	ret nz			;when 0-1 frame overclocks we decrease column
	ld hl,(bull_map_pos)
	call check_left
	cp 2			;is there a block in the way?
	jr nc,unset_bullet
	ld (bull_map_pos),hl
	call map2screen
	ld (bullscadd),hl
	ret
	;
bullet_right
	ld hl,bullrt
	ld (bullgraphpoint),hl
	ld a,(bullframe)
	inc a
	and 3
	ld (bullframe),a
	ret nz			;when 0-1 frame overclocks we decrease column
	ld hl,(bull_map_pos)
	call check_right
	cp 2			;is there a block in the way?
	jr nc,unset_bullet
	ld (bull_map_pos),hl
	call map2screen
	ld (bullscadd),hl
	ret
bullet_up
	ld hl,bullup
	ld (bullgraphpoint),hl
	ld a,(bullframe)
	inc a
	and 3
	ld (bullframe),a
	ret nz			;when 0-1 frame overclocks we decrease column
	ld hl,(bull_map_pos)
	call check_up
	cp 2			;is there a block in the way?
	jr nc,unset_bullet
	ld (bull_map_pos),hl
	call map2screen
	ld (bullscadd),hl
	ret
bullet_down
	ld hl,bulldn
	ld (bullgraphpoint),hl
	ld a,(bullframe)
	inc a
	and 3
	ld (bullframe),a
	ret nz			;when 0-1 frame overclocks we decrease column
	ld hl,(bull_map_pos)
	call check_down
	cp 2			;is there a block in the way?
	jr nc,unset_bullet
	ld (bull_map_pos),hl
	call map2screen
	ld (bullscadd),hl
	ret
	;
unset_bullet
	call delcol		;delete ghost attr
	xor a
	ld (shootflag),a
	ld (bullframe),a
	ld de,(oldbullsc)
	jp delchar
	;
delcol	ld hl,(oldbullsc)
dc2	call screen2att
	set 5,h
	ld a,(hl)
	res 5,h
	ld (hl),a		;remove old colour using buffer
	ret
	;
bullscadd	defw	0
oldbullsc	defw	0
bull_map_pos	defw	0
bullgraphpoint	defw	0
bulldirection	defb	0
bullframe	defb	0
	;
inertia	ld a,(direction)	;are desired and actual direction the same
	ld b,a
	ld a,(olddir)		;previous direction
	cp b
	jr nz,cdr		;no, direction changed, slow and reset inertia if direction has upended
incont	ld hl,(intabseed)
	inc hl
	ld a,(hl)
	cp 128			;128 means at full speed already
	ret z
	ld (intabseed),hl
	ld (slow),a
	ret
	;
cdr	or a			;cp 0
	jr z,wasleft
	dec a			;cp 1
	jr z,wasright
	dec a			;cp 2
	jr z,wasup		
	dec a			;cp 3
	jr z,wasdown
cdr2	ld hl,intab		;direction has changed, need to reset inertia to start
	ld (intabseed),hl
	ld a,7
	ld (slow),a
	ret
	;
wasleft	ld a,b			;messy bit of code, decides if change of direction
	cp 1			;is an upend, ie right change to left or up to down
	jr z,cdr2		;if moving from lateral to verical inertia not reset
	jr incont
wasright
	ld a,b
	or a			;ok was right, are we trying left now?
	jr z,cdr2		;yep, so reset inertia
	jr incont		;nope, keep on with speed
wasup	ld a,b
	cp 3			;was up, is it now down?
	jr z,cdr2
	jr incont
wasdown	ld a,b
	cp 2			;was down, is it now up?
	jr z,cdr2
	jr incont
	;
events	ld a,(slow)
	cp 3
	call z,gcdr		;guardian change direction
	ld a,(shootflag)
	or a
	call nz,gcdr2		;also if player fires we change
	ld a,(mothcount)
	cp 4
	call c,erratic_guardians
	ld a,(loop_counter+1)
	cp 15			;plenty of time to complete the game
	call nc,turbo_up_guardians
	ld a,(level)
	cp 2			;levels 1&2
	jr c,easy
	cp 4			;levels 3&4
	jr c,medium		
hard	ld a,(loop_counter+1)
	and 1
	ret z			;call every other pass
	;
setsmuggler
	ld a,(smugtimer)
	or a
	ret nz
	ld a,(specswitch)	;spec smuggler needs to be off
	or a
	ret nz
	ld hl,spritestore+(number_of_sprites-1*length_of_sprite_table)
	ld de,specsmtab
	ld bc,length_of_sprite_table
	ldir			;ldier fresh variables variables in place
	ld a,255
	ld (smugtimer),a	;timer until spectrum smuggler arrives
	call getspecadd		;specsmug can appear in 3 different places, pick one
	ld de,specsmtab
	ld bc,6
	ldir			;put choice address variables in
	ld de,buildingseed
	ld c,255
	ldi
	ldi			;put corresponding building to flash in position
	ret
	;
getspecadd			;yellow moth
	call rnd
	ld hl,spectab1
	and 3
	cp 3
	ret z
	ld hl,spectab2
	cp 2
	ret z
	ld hl,spectab3
	ret
	
	;
easy	ld a,(loop_counter+1)	;how often yellow moth is called
	and 7	
	cp 7			;12.5% of the time
	jr z,setsmuggler
	ret
	;
medium	ld a,(loop_counter+1)	;how often yellow moth is called
	and 7	;01234567
	cp 5	;if >01234, 38% of the time
	jr nc,setsmuggler
	ret
smugtimer	defb	0		;how long you wait from flashing building to yellow moth appearance
	;
spectab1	defw	16384+64+64	;3 different positions where spec smuggler can appear
		defw	0
		defw	gsp+64
		defw	22528+96+1	;building address we flash
spectab2	defw	16384+64+64+64+24
		defw	0
		defw	gsp+64+64+24
		defw	22528+96+64+32+25
spectab3	defw	20480+64+15
		defw	0
		defw	bsp+15
		defw	22528+512+64+16
	;
sounds	ld a,(charflg)		;we don't want to slow down the busiest halt frame
	or a
	ret z
	ld a,(bangflag+1)
	or a
	call nz,scrash
	ld a,(shootnoiseflag)
	or a
	call nz,zap
	ret
	;
turbo_up_guardians		;when the player takes too long, speed guardians up, trouble is it's virtually unplayable
	ld ix,gscadd		;so hopefully doesn't happen
	ld de,length_of_sprite_table
	ld b,number_of_sprites-1
tulp	ld a,(ix+24)
	or a
	jr nz,tumiss	
	ld (ix+30),2		;number of times move is called during a main loop pass, 1 normal ,2 turbo (~unplayable)
tumiss	add ix,de	
	djnz tulp
	ret
	;
gcdr2	ld a,(shootnoiseflag)	;we occasionally want to change direction when player shoots
	cp 10			;origin of fire is 10 here
	ret nz
	call rnd
	cp 90			;we don't want to do it every time either
	ret nc
	jr gcdr3
gcdr	ld a,(loop_counter)	;this will get called too many times otherwise
	and 7
	cp 7
	ret nz	
	call rnd
	rra
	ret c
gcdr3	ld ix,gscadd
	ld b,number_of_sprites-1
gcdlp	ld a,(ix+24)		;only make decisions when not straddling char cell
	or a
	ret nz
	call rnd
	rra
	jr c,gcmiss
	ld a,(ix+19)
	cp (ix+18)		;new dir same as old?
	jr nz,gcmiss
	call rnd		;same, so change
	and 3
	ld (ix+19),a
gcmiss	ld de,length_of_sprite_table	
	add ix,de
	djnz gcdlp
	ret
	;
erratic_guardians
	ld ix,gscadd
	ld b,number_of_sprites-1
tlp	call rnd
	or 128	
	ld (ix+26),a
	call rnd
	or 32
	ld (ix+27),a
tmiss	ld de,length_of_sprite_table	
	add ix,de	
	djnz tlp
	ret
	;
intabseed	defw	intab	;inertia string and pointer 7 is slowest 0 is normal speed
intab	defb	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
inend	defb	128	;high numbers slow player, 0 full speed, 128 end marker for full speed
	;
variables		equ	border
border			defb	1	;border colour
paper			defb	12	;attribute value of paper colour blue paper & ink, for success screen mainly
fontseed		defw	15616-256
level			defb	0
lives			defb	3
olddir			defb	0	;old direction
loop_counter		defw	0
shootnoiseflag		defb	0
deadflag		defb	0
shootflag		defb	0	;0=no bullet in play, 255 bullet in action
mothcount		defb	10	;number of moths on level star, when zero level finished, doesn't count spectrum smugglers
sprite_table		equ	scadd
number_of_sprites	equ	12
length_of_sprite_table	equ	33
	;
variablestore;level,lives, olddir,defw loopcounter,shootnoise,deadflag,shootflagmothcount variables get ldired back at start of game
		defb	0,3,0		;reset all at start of game variables
variablestore2	defb	0,0,0,0,0
mothcountstore	defb	10	;during game variables
	;
;TEXT STRINGS
string1		defb	253
		defw	16384+12
		defb	252,15,'LEVEL ',252,10,'000',254,0
		defb	'000000',252,15,'  HIGH SCR ',252,10
hiscore		defb	'000000  000000',255			;can poke 'score' in here when it;s high enough
string2		defb	253
		defw	18432+9
		defb	252,10,'1',252,15,'-REFINE KEYS',254,9
		defb	252,10,'2',252,15,'-BEGIN  GAME'
		defb	253
		defw	18560+10+32
		defb	252,10,251,0,'  10',252,15,' POINTS',254,10
		defb	252,14,251,0,' 250',252,15,' POINTS'
		defb	253
		defw	20480+160-96-32+6
		defb	'YOU ARE MOLE RAT ',252,11,251,1,254,0,252,15
		defb	'SHOOT  ALL  THE MOTHS THAT  HAVE'
		defb	' INVADED YOUR WARREN FOR POINTS.',254,0
		defb	'BASED ON  SOME FAVOURITE  ARCADE'
		defb	'      GAMES FROM THE ',252,10,'1980',39,'s',255
string3		defb	252,15
		defb	'    UP      ',255	;redefine key strings
string4		defb	'   DOWN     ',255
string5		defb	'   LEFT     ',255
string6		defb	'   RIGHT    ',255
string7		defb	'   FIRE     ',255
string8		defb	'  PAUSE     ',255
string9		defb	252,15,'    ',255	;spaces for deleting lives at top of screen
string10	defb	253	
		defw	18432+64+11
		defb	252,15,'GET READY',254,11,'PLAYER  ',252,10,'1',255
string11	defb	253
		defw	18432+64+11	
		defb	252,15,'GAME OVER',255
string12	defb	253
		defw	18432+64+10
		defb	252,15,'BONUS POINTS!'
		defb	253
		defw	18432+192+12
		defb	252,10,'SPLENDID!',255
string13	defb	253
		defw	18432+64+10
		defb	252,15,'BONUS POINTS!'
		defb	253
		defw	18432+192+10
		defb	252,79+128,'EXTRA LIFE!!',255
string14	defb	252,15+128,'CONGRATULATIONS!'
		defb	253
		defw	18432+64+4
		defb	252,15,'YOU ARE THE VICTIM OF A',254,5
		defb	'1 in 4294967296 EVENT',254,3
		defb	'THAT WILL CAUSE THIS GAMES',254,3
		defb	'RANDOM NUMBER GENERATOR TO',254,2
		defb	'GENERATE A NON RANDOM VALUE',254,0,254,3
		defb	'PRESS ANY KEY TO CONTINUE',255
string15	defb	'MOLE RAT!',255
	;	
udgs	defb	036,024,060,060,126,126,219,129		;MOTH FIGHTER UDG
mol	defb	000,090,060,060,060,060,066,000		;MOLERAT UDG
spc	defb	000,048,070,037,022,100,004,000		;SPc udg for refine keys
csf	defb	000,102,136,132,130,108,000,000		;CapsShift udg
ent	defb	002,002,018,050,126,048,016,000		;Enter key udg
ssf	defb	000,102,136,068,034,204,000,000		;Symb Shft udg	
	;
colours	defb	074,079,077,077,077,077,009,000		;game block colours
	;
blocks	defb	000,000,000,000,000,000,000,000		;empty block we move through				0
	defb	000,000,000,000,000,000,000,000		;empty block we move through, white ink for edges	1
	defb	000,000,063,063,063,063,063,063		;yellow block top left					2
	defb	000,000,252,252,252,252,252,252		;yellow block top right					3
	defb	063,063,063,063,063,063,000,000		;yellow block bottom right				4
	defb	252,252,252,252,252,252,000,000		;yellow block bottom left				5
	defb	000,000,000,000,000,000,000,000		;empty dull blue block at far right			6
	;
	;SOUNDS, need to be in uncontended of course
	;all modified from DKTronics Sound FX generator
scrash	push hl			;From DKTronics Sound FX generator
	push de
	push bc
	push af	
	ld hl,1000		;SHORTER CRASH;;;modified from DKTRONICS SOUND FX noise
	ld d,100		;white noise with a digital grate
	ld e,50
bangflag
	ld b,0			;duration here
sc1	push bc
	xor a
	srl a
	srl a
	srl a
	or 16
	or 1			;blue border
	out (254),a
	ld b,(hl)
	nop
	nop
sc2	djnz sc2
	ld b,d
sc3	djnz sc3
	res 4,a
	or 1			;blue border
	out (254),a
	ld b, (hl)
sc4	djnz sc4
	inc hl
	ld b,e
	nop
	nop
sc5	djnz sc5
	nop
	nop
	inc e
	pop bc
	djnz sc1
	xor a
	ld (bangflag+1),a
	pop af
	pop bc
	pop de
	pop hl
	ret
	;
crash	LD HL, 1000		;bigger bang when player dies, ;From DKTronics Sound FX generator
	LD D, 61
	LD E, 240
clen	LD B, 100		;duration altered by poking values inhere in deadlp
c1	PUSH BC
	LD A, (23624)
	SRL A
	SRL A
	SRL A
	SET 4, A
	and 248
	or 1
	OUT (254), A
	LD B, (HL)
	NOP
	NOP
c2	DJNZ c2
	LD B, D
c3	DJNZ c3
	RES 4, A
	OUT (254), A
	and 248
	or 1
	LD B, (HL)
c4	DJNZ c4
	INC HL
	LD B, E
	NOP
	NOP
c5	DJNZ c5
	INC D
	NOP
	POP BC
	DJNZ c1
	ret
	;
zap	dec a				;From DKTronics Sound FX generator
	ld (shootnoiseflag),a
	LD D,5
	LD E,5
	LD B,5
zap3	PUSH BC
	xor a
	SRL A
	SRL A
	SRL A
	SET 4, A
	and 248
	or 1
	OUT (254), A
	LD B, D
zap1	NOP
	NOP
	NOP
	DJNZ zap1
	RES 4, A
	and 248
	or 1
	OUT (254), A
	LD B, E
zap2	NOP
	NOP
	NOP
	DJNZ zap2
	DEC D
	DEC D
	NOP
	INC D
	POP BC
	DJNZ zap3
	ret
	;
longzap	LD D,100		;;From DKTronics Sound FX generator
	LD E,100
	LD B,50
zap4	PUSH BC
	xor a
	SRL A
	SRL A
	SRL A
	SET 4, A
	and 248
	or 1
	OUT (254), A
	LD B, D
zap5	NOP
	NOP
	NOP
	DJNZ zap5
	RES 4, A
	and 248
	or 1
	OUT (254), A
	LD B, E
zap6	NOP
	NOP
	NOP
	DJNZ zap6
	DEC D
	DEC D
	NOP
	INC D
	POP BC
	DJNZ zap4
	ret
	;
	;JONATHAN CAULDWELLS HI-SCORE ROUTINE
uscor  ld a,(hl)           ; current value of digit.
       add a,b             ; add points to this digit.
       ld (hl),a           ; place new digit back in string.
       cp 58               ; more than ASCII value '9'?
       ret c               ; no - relax.
       sub 10              ; subtract 10.
       ld (hl),a           ; put new character back in string.
uscor0 dec hl              ; previous character in string.
       inc (hl)            ; up this by one.
       ld a,(hl)           ; what's the new value?
       cp 58               ; gone past ASCII nine?
       ret c               ; no, scoring done.
       sub 10              ; down by ten.
       ld (hl),a           ; put it back
       jp uscor0           ; go round again.
	;
	defb	0,0
score	defb '000000'
	defb	255,255,255	;endstring marker
	;
scorestore	defb '000000'
	;
add_240	ld a,(mothcount)	;if we arrive here it's because we hit a spectrum smuggler
	inc a			;which shouldn't dec the (mothcount), this is a lazy patch
	ld (mothcount),a	
	ld hl,bigbang		;explode graphic for spectrum smuggler
	ld (ix+7),h
	ld (ix+6),l		;inro graphpoint
	ld hl,score+3     	; point to hundreds column.
	ld b,2              	; 2 hundreds = 200.
	call uscor          	; increment the score.
	ld hl,score+4       	; point to tens column.
	ld b,4              	; 4 tens = 40.
	jp uscor          	; up the score.
	;
add_10	ld hl,score+4	 	; point to tens column.
	ld b,1           	;2 hundreds = 200.
	jp uscor       	   	; increment the score.
	;
add_1000	;arrive with b containing thousand didgit 1-9 and it will be added
	ld hl,score+2       ; point to thousands column.
	jp uscor          ; increment the score.
	;
add_1
	ld hl,levelstr+2	;level is 000, point to ones column
	ld b,1			;level is only ever inc by 1
	jp uscor		;use score routine
	;
		;
change_pattern
	call cp2			;points hl at selected behaviour pattern
	ld ix,gcbyte
	ld b,number_of_sprites-2	;not including spectrum smuggler or player (ie 10)
	ld de,length_of_sprite_table
cplp2	ld a,(hl)
	ld (ix+0),a			;poke the values in
	inc hl
	ld a,(hl)
	ld (ix+1),a
	add hl,de
	djnz cplp2
	ret
	;
cp2	call rnd
	cp 125
	jr c,rpatt		;random pattern wanted?
nrpatt	ld hl,pattern1		;nope, go with a pre made one
	and 3
	ret z
	ld b,a
cplp	ld de,20		;choose random pattern
	add hl,de
	djnz cplp
	ret
rpatt	ld ix,pattern5
	ld b,20			;20 random bytes to make
rplp	call rnd
	or 16			;too near 0 we get funny behaviour
	ld (ix+0),a
	inc ix
	djnz rplp
	ld hl,pattern5
	ret
		;some preset patterns below, dictates overall behaviour of the moth field
pattern1	defb	100,050,110,060,050,030,020,040,010,045,010,050,000,080,000,098,000,100,000,090	
pattern2	defb	200,100,220,110,100,050,040,095,020,090,015,092,005,080,012,098,000,093,000,091
pattern3	defb	255,100,230,150,190,100,100,100,100,100,050,050,050,050,025,100,025,050,025,050
pattern4	defb	220,100,220,110,100,050,040,095,020,090,015,092,005,080,012,120,000,093,000,091
pattern5	defb	000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000	;random vales poked in here
		defb	0,0,0,0
	;
oh_yeah		;SHIRU OH YEAH! SOUND THANKYOU VERY MUCH :-)
	di
	ld hl,sample
	ld de,sample_end-sample
.l0
	ld b,8
	ld c,(hl)
.l1
	ld a,12
	dec a
	jr nz,$-1
	rl c
	sbc a,a
	and $10
	or 1
	out ($fe),a
	djnz .l1
	inc hl
	dec de
	ld a,d
	or e
	jr nz,.l0
	ei
	ret
sample	incbin "sample.bin"
sample_end
	;
;;SPRITE TABLE DATA
scadd		defw	20480+128+27;20733		;screen address	;PLAYER SPRITE
oldscadd	defw	0		;old screen address for deleting ghost graphics
map_position	defw	psp+27		;position in maze, for block checks etc
graphpoint	defw	moleratright	;point at left facing, right facing up or down graphics
rgraph		defw	moleratright	;next 4 address hold directional graphics depending which way facing
lgraph		defw	moleratleft
upgraph		defw	moleratup
downgraph	defw	moleratdown
frame		defb	0		;(ix+16) 0-3 for lefts and rights, always 0 for vertical movements (LH char filled only)
colour		defb	75		;(ix+17) green ink, blue paper bright COLOUR (ix+17)
direction	defb	128		;(ix+18)actual direction
newdir		defb	2		;(ix+19)desired direction when possible
		defb	0,0,0,0		;(ix+20,21,22,23) newly available directions
charflg		defb	0		;(ix+24)flag to indicate (frame) is zero
		defb	0,0,0
blocked		defb	2		;below this block number we can move (most are 2, specchaser is 1, patch)
slow		defb	7		;0 fastest, 1,2,3 >>>slower
turbo		defb	1		;1 is normal, 2 is turbo
		defb	8		;0 on, <>o dead
		defb	0		;sprite type for scoring <>0 equal spectrum smuggler +250 points
		;
gscadd		defw	16384+64+3	;moth 1
		defw	0
		defw	gsp+3
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0;128
		defb	74
		defb	0
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0		;gpattern
gcbyte		defb	200		;chase probability
		defb	100;90		;direction change prob higher means more capricious, 0 just back and forth
		defb	2
gslow		defb	0
gturbo		defb	1
gstatus		defb	8;on off byte
		defb	0
		;
		defw	16384+64+6	;moth 2
		defw	0
		defw	gsp+6
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	220
		defb	110;90
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+9	;moth 3
		defw	0
		defw	gsp+9
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	100
		defb	50
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+12	;moth 4
		defw	0
		defw	gsp+12
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	40
		defb	95
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+15	;moth 5
		defw	0
		defw	gsp+15
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	20
		defb	90
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+18	;moth 6
		defw	0
		defw	gsp+18
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	15
		defb	92
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+21	;moth 7
		defw	0
		defw	gsp+21
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	5
		defb	80
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+24	;moth 8
		defw	0
		defw	gsp+24
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	12
		defb	98
		defb	2
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+27+32	;moth 9
		defw	0
		defw	gsp+27+32
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	0
		defb	93
		defb	1		;this spritr flickers a bit at the, restrict it from this bit of the screen
		defb	0
		defb	1
		defb	8
		defb	0
		;
		defw	16384+64+29+32	;moth 10
		defw	0
		defw	gsp+29+32
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	74
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	0
		defb	91
		defb	1		;this sprite flickers a bit at the, restrict it from this bit of the screen
		defb	0
		defb	1
		defb	8
		defb	0		
		;
specsmtab	defw	16384+64+64	;Spectrum Smuggler, off at beginning, emerges from block during game
		defw	0
		defw	gsp+64
		defw	mothdown
		defw	mothright
		defw	mothleft
		defw	mothup
		defw	mothdown
		defb	0
		defb	78
		defb	0;128
		defb	0
		defb	0,0,0,0		;available directions	(ix+20,21,22,23)
		defb	0
		defb	0
		defb	250
		defb	190
		defb	2		;top edge block for cp, 1 restricted, 2 not
		defb	0
		defb	1
specswitch	defb	0;8
		defb	255		;sprite type 2= spectrum smuggler
		;
statusstore	defb	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0	;for storing guardian on off data between lives
		;
;BLOCK MAP FOR GAME
org 49152+6144+32
game_map
	defb	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
gsp	defb	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
bsp	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
psp	defb	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,6
	defb	1,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,0,2,3,1,6;
	defb	1,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,0,4,5,1,6
	defb	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,255	;255 marks end of 'string'
	defb	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
	;
spritestore	;sprite data held here
