jiffy:			equ	0fc9eh		;vblank updated variable
gtstck:			equ	0d5h		;bios routine for joystick
gttrig:			equ	0d8h		;bios routine for fire button
hook:			equ	0fd9fh		;isr HTIMI hook address
snsmat:			equ	141h		;read specific keyboard row
hmmm:			equ	0d0h
hmmv:			equ	0c0h
sat5:			equ	7600h
sat8:			equ	0fa00h
sp_gen_table5_0:	equ	7800h
sp_gen_table5_1:	equ	0f800h
sp_gen_table8_0:	equ	0f000h

	org	0c000h - 7
	db	0feh
	dw	begin,done,begin

begin:	
	call	clear_page1
	call	rand8_init
	jr	get_current_level
level:
	db	4
screen:
	db	5
result:
	db	0
get_current_level:
	xor	a
	ld	(source_y_hb),a
	ld	a,(level)
	dec	a
	jp	z,grid4
	dec	a
	jp	z,grid5
	dec	a
	jp	z,grid6
	dec	a
	jp	z,grid7
grid4:
	ld	a,64
	ld	(x_axis_dots_lb),a
	ld	(pixel_h_offset),a
	ld	a,53
	ld	(y_axis_dots_lb),a
	ld	(pixel_v_offset),a
	xor	a
	ld	(pointer),a
	ld	(pointer2),a
	inc	a
	ld	(pointer+1),a
	ld	(pointer3+1),a
	ld	a,43
	ld	(pointer3),a
	ld	(pointer4),a
	ld	a,55
	ld	(pointer2+1),a
	ld	(pointer4+1),a
	ld	a,15
	ld	(max_grid_value),a
	ld	a,4
	ld	(grid_v_offset),a
	call	rand8
	ld	b,16
	ld	c,31
	call	prepare_grid
	jp	set_screen
grid5:
	ld	a,50
	ld	(x_axis_dots_lb),a
	ld	(pixel_h_offset),a
	ld	a,42
	ld	(y_axis_dots_lb),a
	ld	(pixel_v_offset),a
	ld	a,1
	ld	(pointer),a
	ld	(pointer2),a
	ld	(pointer+1),a
	ld	(pointer3+1),a
	ld	a,33
	ld	(pointer3),a
	ld	(pointer4),a
	ld	a,41
	ld	(pointer2+1),a
	ld	(pointer4+1),a
	ld	a,24
	ld	(max_grid_value),a
	ld	a,5
	ld	(grid_v_offset),a
	call	rand8
	ld	b,25
	ld	c,31
	call	prepare_grid
	jp	set_screen	
grid6:
	ld	a,42
	ld	(x_axis_dots_lb),a
	ld	(pixel_h_offset),a
	ld	a,35
	ld	(y_axis_dots_lb),a
	ld	(pixel_v_offset),a
	ld	a,1
	ld	(pointer),a
	ld	(pointer2),a
	ld	(pointer+1),a
	ld	(pointer3+1),a
	ld	a,26
	ld	(pointer3),a
	ld	(pointer4),a
	ld	a,33
	ld	(pointer2+1),a
	ld	(pointer4+1),a
	ld	a,35
	ld	(max_grid_value),a
	ld	a,6
	ld	(grid_v_offset),a
	call	rand8
	ld	b,36
	ld	c,63
	call	prepare_grid
	jp	set_screen
grid7:
	ld	a,36
	ld	(x_axis_dots_lb),a
	ld	(pixel_h_offset),a
	ld	a,30
	ld	(y_axis_dots_lb),a
	ld	(pixel_v_offset),a
	ld	a,1
	ld	(pointer),a
	ld	(pointer2),a
	ld	(pointer+1),a
	ld	(pointer3+1),a
	ld	a,21
	ld	(pointer3),a
	ld	(pointer4),a
	ld	a,27
	ld	(pointer2+1),a
	ld	(pointer4+1),a
	ld	a,48
	ld	(max_grid_value),a
	ld	a,7
	ld	(grid_v_offset),a
	call	rand8
	ld	b,49
	ld	c,63
	call	prepare_grid
set_screen:
	call	draw_shuffled
	call	define_sprites
	jp	on_screen
main_loop:
	ld	a,(timer)
	cp	7
	jp	z,ready_to_move
	ld	hl,jiffy
	ld	a,(hl)
wait_frm:
	cp	(hl)
	jp	z,wait_frm
	ld	a,(timer)
	inc	a
	ld	(timer),a
	cp	7
	jp	nz,main_loop
ready_to_move:
	xor	a
	call	gtstck
	cp	1
	jp	z,up
	cp	3
	jp	z,right
	cp	5
	jp	z,down
	cp	7
	jp	z,left
	jp	check_for_fire	
timer_reset:
	xor	a
	ld	(timer),a
check_for_fire:	
	xor	a
	call	gttrig
	and	a
	jp	z,check_for_key
check_empty_near:
	ld	a,(grid_pos)
	ld	hl,grid
	ld	d,0
	ld	e,a
	add	hl,de
	ld	a,(hl)
	ld	b,a
	ld	a,(max_grid_value)
	inc	a
	cp	b
	jp	z,check_for_key
check_empty_up:
	xor	a
	ld	a,(grid_v_offset)
	ld	b,a
	ld	a,(grid_pos)
	sub	b
	jp	c,check_empty_down
	ld	hl,grid
	ld	e,a
	add	hl,de
	ld	a,(hl)
	ld	b,a
	ld	a,(max_grid_value)
	inc	a
	cp	b
	jp	z,move_up
check_empty_down:
	xor	a
	ld	a,(grid_v_offset)
	ld	b,a
	ld	a,(grid_pos)
	add	a,b
	ld	b,a
	ld	a,(max_grid_value)
	cp	b
	jp	c,check_empty_left
	ld	hl,grid
	ld	e,b
	add	hl,de
	ld	a,(hl)
	ld	b,a
	ld	a,(max_grid_value)
	inc	a
	cp	b
	jp	z,move_down
check_empty_left:
	ld	hl,pointer+1
	ld	a,(pixel_h_offset)
	ld	b,a
	ld	a,(hl)
	sub	b
	jp	c,check_empty_right
	ld	a,(grid_pos)
	dec	a
	ld	hl,grid
	ld	e,a
	add	hl,de
	ld	a,(hl)
	ld	b,a
	ld	a,(max_grid_value)
	inc	a
	cp	b
	jp	z,move_left
check_empty_right:
	ld	hl,pointer+1
	ld	a,(pixel_h_offset)
	ld	b,a
	ld	a,(hl)
	add	a,b
	jp	c,check_for_key
	ld	a,(grid_pos)
	inc	a
	ld	e,a
	ld	hl,grid
	add	hl,de
	ld	a,(hl)
	ld	b,a
	ld	a,(max_grid_value)
	inc	a
	cp	b
	jp	z,move_right
check_for_key:
	ld	a,3				;check if H key is pressed
	call	snsmat
	cp	11011111b
	jp	nz,page1_on			;if not keep showing page1
	call	switch_to_page0			;else show page0
	jp	check_for_esc
page1_on:
	call	switch_to_page1
check_for_esc:
	ld	a,7
	call	snsmat
	cp	11111011b
	jp	z,escape
on_screen:
	ld	bc,1198h
	ld	a,(screen)
	cp	5
	jp	nz,sc8_sat
sc5_sat:
	ld	hl,sat5
	xor	a
	call	SetVdp_Write
	jp	update_sat
sc8_sat:
	ld	hl,sat8
	xor	a
	call	SetVdp_Write
update_sat:
	ld	hl,pointer
	otir
	jp	main_loop
up:
	ld	hl,pointer
	ld	a,(pixel_v_offset)
	ld	b,a
	ld	a,(hl)
	sub	b
	jp	c,check_for_fire
	ld	(hl),a
	ld	(pointer2),a
	ld	a,(pointer3)
	sub	b
	ld	(pointer3),a
	ld	(pointer4),a


	ld	hl,grid_pos
	ld	a,(grid_v_offset)
	ld	b,a
	ld	a,(hl)
	sub	b
	ld	(hl),a
	jp	timer_reset
right:
	ld	hl,pointer+1
	ld	a,(pixel_h_offset)
	ld	b,a
	ld	a,(hl)
	add	a,b
	jp	c,check_for_fire
	cp	250
	jp	nc,check_for_fire
	ld	(hl),a
	ld	(pointer3+1),a
	ld	a,(pointer2+1)
	add	a,b
	ld	(pointer2+1),a
	ld	(pointer4+1),a
	ld	hl,grid_pos
	ld	a,(hl)
	inc	a
	ld	(hl),a
	jp	timer_reset
down:
	ld	hl,pointer
	ld	a,(pixel_v_offset)
	ld	b,a
	ld	a,(hl)
	add	a,b
	cp	210
	jp	nc,check_for_fire
	ld	(hl),a
	ld	(pointer2),a
	ld	a,(pointer3)
	add	a,b
	ld	(pointer3),a
	ld	(pointer4),a

	ld	hl,grid_pos
	ld	a,(grid_v_offset)
	ld	b,a
	ld	a,(hl)
	add	a,b
	ld	(hl),a
	jp	timer_reset
left:
	ld	hl,pointer+1
	ld	a,(pixel_h_offset)
	ld	b,a
	ld	a,(hl)
	sub	b
	jp	c,check_for_fire
	ld	(hl),a
	ld	(pointer3+1),a
	ld	a,(pointer2+1)
	sub	b
	ld	(pointer2+1),a
	ld	(pointer4+1),a

	ld	hl,grid_pos
	ld	a,(hl)
	dec	a
	ld	(hl),a
	jp	timer_reset
escape:
	call	clear_grid
	xor	a
	ld	(timer),a
	dec	a
	ld	(result),a
	ld	a,216
	ld	(pointer+4),a
	ld	(pointer),a
	ret
move_up:
	ld	a,(grid_v_offset)
	ld	b,a
	call	save_grid_value_and_set_last_tile

	ld	hl,grid
	ld	a,(grid_pos)
	sub	b
	ld	e,a
	add	hl,de
	ld	(hl),c		;values swap complete
	add	a,a		;double it to align to the right byte on our coordinates LUT
	ld	b,a		;store it in B
	jp	copy_tile
move_down:
	ld	a,(grid_v_offset)
	ld	b,a
	call	save_grid_value_and_set_last_tile

	ld	hl,grid
	ld	a,(grid_pos)
	add	a,b
	ld	e,a
	add	hl,de
	ld	(hl),c		;values swap complete
	add	a,a		;double it to align to the right byte on our coordinates LUT
	ld	b,a		;store it in B
	jp	copy_tile
move_left:
	call	save_grid_value_and_set_last_tile
	ld	hl,grid
	ld	a,(grid_pos)
	dec	a
	ld	e,a
	add	hl,de
	ld	(hl),c
	add	a,a
	ld	b,a
	jp	copy_tile
move_right:
	call	save_grid_value_and_set_last_tile
	ld	hl,grid
	ld	a,(grid_pos)
	inc	a
	ld	e,a
	add	hl,de
	ld	(hl),c
	add	a,a
	ld	b,a
copy_tile:
	ld	a,1
	ld	(source_y_hb),a
	ld	a,(level)
	dec	a
	jp	z,move_grid4
	dec	a
	jp	z,move_grid5
	dec	a
	jp	z,move_grid6
move_grid7:
	ld	hl,grid7_xy
	jr	set_move_coord
move_grid6:
	ld	hl,grid6_xy
	jr	set_move_coord
move_grid5:
	ld	hl,grid5_xy
	jr	set_move_coord
move_grid4:
	ld	hl,grid4_xy
set_move_coord:
	push	hl
	ld	e,b
	ld	d,0
	add	hl,de
	ld	a,(hl)
	ld	(dest_x_lb),a
	inc	hl
	ld	a,(hl)
	ld	(dest_y_lb),a	
	pop	hl
	ld	a,(grid_pos)
	add	a,a
	ld	e,a
	add	hl,de
	push	hl
	ld	a,(hl)
	ld	(source_x_lb),a
	inc	hl
	ld	a,(hl)
	ld	(source_y_lb),a	
	ld	a,hmmm
	ld	(cmd),a
	xor	a
	ld	(reg44),a
	call	DoCopy
	pop	hl
	ld	a,(hl)
	ld	(dest_x_lb),a
	inc	hl
	ld	a,(hl)
	ld	(dest_y_lb),a
	ld	a,hmmv
	ld	(cmd),a
	ld	a,11001100b
	ld	(reg44),a
	call	DoCopy
	ld	a,hmmm
	ld	(cmd),a
	xor	a
	ld	(reg44),a
completion_check:
	ld	hl,grid
	ld	a,(max_grid_value)
	inc	a
	ld	b,a
	ld	e,1
check_loop:
	ld	a,(hl)	
	cp	e
	jp	nz,check_for_key
	inc	e
	inc	hl
	djnz	check_loop
	call	switch_to_page0

	ld	b,100
wait_a_moment:
	ld	hl,jiffy
	ld	a,(hl)
wait_one_frame:
	cp	(hl)
	jp	z,wait_one_frame	
	djnz	wait_a_moment
	call	clear_grid
	xor	a
	ld	(timer),a
	inc	a
	ld	(result),a
	ld	a,216
	ld	(pointer),a
	ret

save_grid_value_and_set_last_tile:
	ld	a,(grid_pos)
	ld	e,a
	ld	d,0
	ld	hl,grid
	add	hl,de
	ld	c,(hl)		;save our grid content on reg C for later
	ld	a,(max_grid_value)
	inc	a
	ld	(hl),a
	ret

rand8_init:
	push	hl
	ld	hl,(jiffy)
	set	0,l
	ld	(randSeed),hl
	pop	hl
	ret
; choose a random number in the set [0,127] with uniform distribution
; return: A = random value
; this routine is from Artrag (posted at MRC)
rand8:
	push	hl
	ld      hl,(randSeed)
	add     hl,hl
	sbc     a,a
	and     083h 	;original value
	xor     l
	ld      l,a
	ld      (randSeed),hl
	pop	hl
	ret

prepare_grid:
	xor	a
	ld	(grid_pos),a
	ld	hl,grid
	ld	d,b
	inc	d
	ld	ixl,c
grid_setting_loop:
	ld	c,ixl
	call	rand8
	and	c				
	and	a
	jp	z,grid_setting_loop
	cp	d
	jp	nc,grid_setting_loop
	ld	e,a
	ld	c,d
	push	hl
	ld	hl,grid
check_grid:
	ld	a,(hl)
	cp	e
	jp	z,already_exist
	and	a
	jp	z,set_value
	inc	hl
	dec	c
	jp	nz,check_grid
already_exist:
	pop	hl
	jp	grid_setting_loop	
set_value:
	pop	hl
	ld	(hl),e
	inc	hl
	djnz	grid_setting_loop
	ret

draw_shuffled:
	ld	a,1
	ld	(dest_y_hb),a	
	ld	de,grid
	ld	a,(level)
	dec	a
	jp	z,draw_grid4
	dec	a
	jp	z,draw_grid5
	dec	a
	jp	z,draw_grid6
draw_grid7:
	ld	ix,grid7_xy
	ld	hl,grid7_xy
	ld	b,49
	jp	to_page1
draw_grid6:
	ld	hl,grid6_xy
	ld	ix,grid6_xy
	ld	b,36
	jp	to_page1
draw_grid5:
	ld	hl,grid5_xy
	ld	ix,grid5_xy
	ld	b,25
	jp	to_page1
draw_grid4:
	ld	hl,grid4_xy
	ld	ix,grid4_xy
	ld	b,16
to_page1:
	ld	c,b
to_page1_loop:
	ld	a,(de)
	cp	c
	jp	nz,not_last_tile
	push	ix
	ld	a,(hl)
	ld	(dest_x_lb),a
	inc	hl
	ld	a,(hl)
	ld	(dest_y_lb),a
	inc	hl
	ld	a,hmmv
	ld	(cmd),a
	ld	a,11001100b
	ld	(reg44),a
	call	DoCopy
	ld	a,hmmm
	ld	(cmd),a
	xor	a
	ld	(reg44),a
	inc	de	
	jr	after_copy
not_last_tile:
	dec	a		;we have values starting from 1 but need to start from 0 to get data from address 
set_grid_pos:
	push	ix
	and	a
	jp	z,get_value
adjust_ix:
	inc	ix
	inc	ix
	dec	a
	jp	nz,adjust_ix

get_value:
	ld	a,(ix+0)
	ld	(source_x_lb),a
	ld	a,(ix+1)
	ld	(source_y_lb),a
	ld	a,(hl)
	ld	(dest_x_lb),a
	inc	hl
	ld	a,(hl)
	ld	(dest_y_lb),a
	inc	hl
	inc	de
	call	DoCopy	
after_copy:
	pop	ix
	djnz	to_page1_loop
switch_to_page1:
	ld	a,63
	jr	switch
switch_to_page0:
	ld	a,31
switch:
	di
	out	(99h),a
	ld	a,2+128
	ei
	out	(99h),a
	ret
clear_grid:
	ld	hl,grid
	ld	de,grid+1
	ld	(hl),0
	ld	bc,48
	ldir
	ret
define_sprites:
	ld	bc,2098h
	ld	a,(screen)
	cp	5
	jp	nz,sp_def8
sp_def5:
	xor	a
	ld	hl,sp_gen_table5_0
	call	SetVdp_Write
	ld	hl,sprite_def
	otir
	ld	hl,7400h
	jp	set_col_address
sp_def8:
	xor	a
	ld	hl,sp_gen_table8_0
	call	SetVdp_Write
	ld	hl,sprite_def
	otir
	ld	hl,0f800h
set_col_address:
	call	SetVdp_Write
	ld	b,0
col_loop:
	ld	a,15
	out	(98h),a
	dec	a
	out	(98h),a
	djnz	col_loop
	ret	
;
; Fast DoCopy, by Grauw
; In:  HL = pointer to 15-byte VDP command data
; Out: HL = updated
; modifying the 15 bytes to send we can perform other commands and everywhere on the screen
; so I set a unique label to each one

DoCopy:
	push	hl
	push	bc

	ld hl,copyblock
	ld a,32		;select reg32 (first used from hmmm command) use +128 to disable auto increment
	di
	out (99h),a
	ld a,17+128	;write reg 32 in reg17 as start indirect register access (auto increment set)
	out (99h),a
	ld c,9Bh	;commands port select
VDPready:
	ld a,2
	di
	out (99h),a	; select s#2 status register 2 (we need to check bit0, CE)
	ld a,15+128
	out (99h),a
	in a,(99h)	;get status register 2 value
	rra		;rotate right, if value=1 then it will set the carry flag
	ld a,0		;back to s#0, enable ints (isr needs status register 0) don't use "xor a" because it reset the carry
	out (99h),a
	ld a,15 + 128
	ei
	out (99h),a
	jp c,VDPready	;loop if vdp not ready (CE)
	outi		;15x OUTI
	outi		;(faster than OTIR)
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi
	outi

	pop	bc
	pop	hl
	ret

clear_page1:
	ld	a,(screen)
	cp	5
	jp	z,screen5
screen8:
	ld	a,4
	ld	hl,0
	call	SetVdp_Write2
	ld	bc,0d400h
	jr	vram_erase
screen5:
	ld	a,2
	ld	hl,0
	call	SetVdp_Write2
	ld	bc,6a00h
vram_erase:
	ld	a,1
	out	(98h),a
	dec	bc
	ld	a,b
	or	c
	jp	nz,vram_erase	
	ret
SetVdp_Write:
	rlc h
	rla
	rlc h
	rla
	srl h
	srl h
SetVdp_Write2:
	di
	out (99h),a
	ld a,14 + 128
	out (99h),a
	ld a,l
	out (99h),a
	ld a,h
	or 64
	ei
	out (99h),a
	ret
copyblock:
source_x_lb:
	db	0
source_x_hb
	db	0
source_y_lb:
	db	0
source_y_hb:
	db	0
dest_x_lb:
	db	0
dest_x_hb
	db	0
dest_y_lb:
	db	0
dest_y_hb:
	db	0
x_axis_dots_lb:
	db	0
x_axis_dots_hb:
	db	0
y_axis_dots_lb:
	db	0	
y_axis_dots_hb:
	db	0
reg44:
	db	0
reg45:
	db	0	;set to 0 simply to set vram for both source and destination
cmd:
	db	0d0h
randSeed:
	dw	0
grid:
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
	db	0,0,0,0,0,0,0
grid4_xy:
	db	0,0,64,0,128,0,192,0
	db	0,53,64,53,128,53,192,53
	db	0,106,64,106,128,106,192,106
	db	0,159,64,159,128,159,192,159

grid5_xy:
	db	0,1,50,1,100,1,150,1,200,1
	db	0,43,50,43,100,43,150,43,200,43
	db	0,85,50,85,100,85,150,85,200,85
	db	0,127,50,127,100,127,150,127,200,127
	db	0,169,50,169,100,169,150,169,200,169

grid6_xy:
	db	0,1,42,1,84,1,126,1,168,1,210,1
	db	0,36,42,36,84,36,126,36,168,36,210,36
	db	0,71,42,71,84,71,126,71,168,71,210,71
	db	0,106,42,106,84,106,126,106,168,106,210,106
	db	0,141,42,141,84,141,126,141,168,141,210,141
	db	0,176,42,176,84,176,126,176,168,176,210,176
	
grid7_xy:
	db	0,1,36,1,72,1,108,1,144,1,180,1,216,1
	db	0,31,36,31,72,31,108,31,144,31,180,31,216,31
	db	0,61,36,61,72,61,108,61,144,61,180,61,216,61
	db	0,91,36,91,72,91,108,91,144,91,180,91,216,91
	db	0,121,36,121,72,121,108,121,144,121,180,121,216,121
	db	0,151,36,151,72,151,108,151,144,151,180,151,216,151
	db	0,181,36,181,72,181,108,181,144,181,180,181,216,181
	
timer:
	db	0
grid_pos:
	db	0
grid_v_offset:
	db	4
pixel_v_offset:
	db	0
pixel_h_offset:
	db	0
max_grid_value:
	db	15
pointer:
	db	216,0,0,0
pointer2:
	db	216,0,1,0
pointer3:
	db	216,0,2,0
pointer4:
	db	216,0,3,0
	db	216
sprite_def:
	db	255,255,192,192,192,192,192,192
	db	255,255,3,3,3,3,3,3
	db	192,192,192,192,192,192,255,255
	db	3,3,3,3,3,3,255,255
done:
	end