;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; test program for the 


	.model small
	.stack 1000h
	p386

	locals	

	.data

; palette is at +30h, and is in a byte per colour ordinate in groups of 3


;the_palette	equ	the_file+030h



hello_mess	db	"Type away ...... :-)",13,10,0
hex_digits	db	"0123456789ABCDEF"

;bar		dw	256 dup (?)

dta_file_size	equ	01ah
dta_file_name	equ	01eh

cds	struc
ob_flag		dw	?
ob_x		dw 	?
ob_y		dw 	?
ob_xv		dw	?
ob_yv		dw	?
ob_colour	dw	?
ob_old_x	dw	?
ob_old_y	dw	?
ob_len		dw	?
	ends

snow	struc
snow_flag		dw	?
snow_addr		dw 	?
snow_old_addr		dw	?
snow_count		dw 	?
snow_speed		db	?
snow_delay		db	?
snow_direction		db	?
snow_slide		db	?
snow_len		dw	?
	ends


dust	struc
dust_flag		dw	?
dust_x			dd	?
dust_y			dd	?
dust_xv			dd	?
dust_yv			dd	?
dust_old_addr		dw	?
dust_old_addr1		dw	?
dust_old_addr2		dw	?
dust_old_addr3		dw	?
dust_count		dw 	?
dust_len		dw	?
	ends


grav	struc
grav_flag		dw	?
grav_x			dd	?
grav_y			dd	?
grav_xv			dd	?
grav_yv			dd	?
grav_old_addr		dw	?
grav_old_addr1		dw	?
grav_old_addr2		dw	?
grav_old_addr3		dw	?
grav_count		dw 	?
grav_len		dw	?
	ends


grid	struc
grid_x		dd	?
grid_y		dd	?
grid_z		dd	?
grid_zv		dd	?
grid_len		dd	?
	ends

max_grav	equ	40


max_dust	equ	1600

grid_gap	dw	10		; gap is in pixels, minimum is 5
grid_speed	dw	4		; 1 to 20


half_gap	dw	0


grid_size	dw	0    	; max 50

grid_w		equ	50		; max size of grid 213/xxx+2

grid_corner_x	equ	0		;-15
grid_corner_y	equ	0

max_snow	equ	1000
snow_freeze	equ	20

slide_time	db	10

snow_melts	equ	0



palette		db	256*3 dup (0)

mouse_x		dw	0
mouse_y		dw	0
mouse_buttons	dw	0
old_mouse_x		dw	0
old_mouse_y		dw	0

		dw	0
mouse_xv	dw	0
		dw	0
mouse_yv	dw	0
		dw	0

seed		dw	0
seed1		dw	0


stack_pointer	dw	0

last_key	db	0

colour		dw	0

hlr_colour	db	0

direction	db	0		; direction to check first


friction	db	5

max_ob		equ	16
max_obs		equ	max_ob


max_x		equ	320
max_y		equ	200


screen_segment	dw	0
ob_table	dw	0
grid_table	dw	0


y_line_offset	dw	0

command_length	db	0

command_ptr	dw	0		; index into command line

command_line	db	80 dup (0)	; buffer for command line

horizon		dw	320 dup (?)

dos_data_seg	dw	0

dta_es_ptr	dw	0		; es pointer to buffer for file i/o
dta_pointer	dw	0		; pointer to buffer for file i/o.

file_handle	dw	0
file_length	dw	0

work_filename_1		db	"12345678.123",0
work_filename_2		db	"12345678.123",0

file_name		db	"--------.---",0


a_name		db	"melx.spr",0

source_segment		dw	0

destination_segment	dw	0

buffer_segment		dw	0


	udataseg
;ob_table	db	ob_len*max_ob dup (?)
;snow_table	db	snow_len*max_snow dup (?)
;grid_table	db	grid_w*grid_w*grid_len dup (?)


	.code


	
malloc	macro	par1,par2
	mov	ah,048h
	mov	bx,(par1)/16+1
	int	21h
	mov	[par2],ax
endm	malloc


dalloc	macro	par1
	push	es 	
	mov	ax,[par1]
	mov	es,ax
	mov	ah,049h
	int	21h
	pop	es
	endm



start:
	mov	ax,@data     	; get data segment
	mov	ds,ax

	mov	stack_pointer,sp


	mov	ah,04ah		; resize memory requirements
	mov	bx,1000h	; 16k for workspace
	int	21h
	jc	exit

; allocate memory requirements for this program

	malloc	65535,screen_segment
	jc	exit

	malloc	64000,ob_table
	jc	exit

	mov	ax,ob_table
	mov	buffer_segment,ax

	malloc	64000,grid_table	;grid_w*grid_w*grid_len,grid_table
	jc	exit


	mov	ax,0a000h
	mov	es,ax			; point es: to video ram




	mov	ah,0
;	mov	al,14	  		; mcga
	mov	al,19	  		; mcga
	int	10h

	call	init_mouse




;	mov	si,offset hello_mess
;	call	print_string

;	call	test_input
;	call	rnd_test
;	call	line_demo

;	call	test_load

;	call	grav_demo

	call	dust_demo
	call	snow_demo
	call	grid_demo

	call	setup_obs

;	call	rnd_test
	call	setup_palette


grid_demo:
	call	get_gap
	call	setup_palette
@@again:
	mov	[last_key],0
	call	setup_grid
@@re_edit:
	call	edit_grid
	mov	[last_key],0
@@loop:
	call	download_screen
	mov	ax,[screen_segment]
	mov	es,ax			; point es: to screen ram
	call	clear_screen
;	call	draw_grid
	call	draw_grid_hlr
	mov	friction,0
	call	move_grid

	call	read_mouse
	mov	ax,mouse_buttons
	test	ax,3
	jne	@@re_edit

	call	maybe_exit
	call	raster_wait
	mov	al,last_key
	cmp	al,020h
	je	@@again
	jmp	@@loop


;pluck	macro	x,y,h
;	mov	word ptr grid_table+2+grid_z+grid_len*(x+grid_w*y),-h
;	endm


	ideal
macro	clear	par1
	mov	par1,0
endm	clear


macro	ld	par1,par2
	mov	par1,par2
endm	ld

	include	"james.asm"
	masm
	locals




test_load:

	mov	dx,offset a_name
	call	load_a_file


	push	ds
	pusha
	mov	ax,0a000h
	mov	es,ax			; point es: to video ram
	mov	ax,[buffer_segment]
	mov	ds,ax			; point ds: to screen ram
	mov	edi,0
	mov	esi,0
	mov	ecx,64000/4
	cld
	rep	movsd
	popa
	pop	ds


@@loop:
	call	maybe_exit
	jmp	@@loop


	ret

edit_grid:
	pusha
	mov	ax,[screen_segment]
	mov	es,ax			; point es: to screen ram
	call	clear_screen
;	call	draw_grid_borderless
	call	draw_grid_hlr
	call	download_screen

	call	show_mouse
@@loop:
	call	maybe_exit
	mov	al,last_key
	cmp	al,020h
	je	@@done
	call	read_mouse
	mov	ax,mouse_buttons
	test	ax,3
	je	@@loop
	call	move_point
	jmp	@@loop

@@done:
	call	hide_mouse

	popa
	ret
	

move_point:
	call	hide_mouse
	call	find_point
@@loop:


	call	read_mouse
	call	maybe_exit
	call	adjust_point

	mov	ax,[screen_segment]
 	mov	es,ax			; point es: to screen ram
	call	clear_screen
	mov	ax,mouse_buttons
	test	ax,1
	je	@@no_movement
	mov	ax,7
;	add	ax,[grid_speed]
	mov	[friction],al
	call	move_grid_with_fix
@@no_movement:
	call	adjust_point
;	call	draw_grid_borderless
	call	draw_grid_hlr
	call	raster_wait
	call	download_screen

	mov	ax,mouse_buttons
	test	ax,3
	jne	@@loop

	call	show_mouse
	ret


find_point:
	mov	di,[grid_table]
	add	di,grid_len*(grid_w+1)
	mov	si,di
	mov	dx,10000
	
	mov	cx,[grid_size]
	sub	cx,2
@@next_row:
	push	cx
	mov	cx,[grid_size]
	sub	cx,2
	push	di
@@next_col:
	push	dx
	mov	ax,word ptr grid_x[di+2]
	sub	ax,mouse_x
	sar	ax,1
	mul	ax
	mov	bx,ax
	mov	ax,word ptr grid_y[di+2]
	add	ax,word ptr grid_z[di+2]
	sub	ax,mouse_y
	sar	ax,1
	mul	ax
	add	ax,bx
	pop	dx
	cmp	dx,ax
	jl	@@not_this
	mov	dx,ax
	mov	si,di
@@not_this:
	add	di,grid_len
	loop	@@next_col
	pop	di
	add	di,grid_len*grid_w
	pop	cx
	loop	@@next_row
	mov	di,si
	ret

adjust_point:
	mov	ax,mouse_y
	sub	ax,word ptr grid_y[di+2]
	mov	word ptr grid_z[di+2],ax
	mov	word ptr grid_zv[di+2],0
	ret
	

setup_grid:
	pusha


	mov	ax,[grid_gap]
	or	ax,ax
	jne	@@ok
  	mov	ax,8
  	mov	[grid_gap],ax
@@ok:
	sar	ax,1
	mov	[half_gap],ax
	mov	ax,213
	xor	dx,dx
	div	[grid_gap]

;	cmp	ax,40
;	jg	@@ok_size
;	mov	ax,40
;@@ok_size:

	mov	[grid_size],ax

	

;	mov	ax,grid_corner_x+(grid_w-2)*grid_gap/2
;	mov	bx,grid_corner_y+200-16-(grid_w-2)*grid_gap/2

	mov	ax,[grid_size]
	sub	ax,2
	mul	half_gap
	mov	bx,ax
	neg	bx
	add	bx,grid_corner_y+200-16
	add	ax,grid_corner_x

	
	

	mov	cx,[grid_size]
	mov	di,[grid_table]
@@next_row:
	push	cx
	push	ax
	push	di
	mov	cx,[grid_size]
@@next_col:
	mov	word ptr grid_x[di+2],ax
	mov	word ptr grid_y[di+2],bx
	mov	grid_z[di],0
	mov	grid_zv[di],0
	add	ax,grid_gap
	add	di,grid_len
	loop	@@next_col

	pop	di
	add	di,grid_len*grid_w

	pop	ax
	sub	ax,half_gap
	pop	cx
	add	bx,half_gap
	loop	@@next_row


;	pluck	3,6,80
;	pluck	2,3,10

	popa
	ret

move_grid:
	pusha
	mov	cx,grid_speed
@@loop:
	push	cx
	call	adjust_velocities
	call	move_grid_points
	pop	cx
	loop	@@loop
	popa
	ret


move_grid_with_fix:
	pusha
	mov	cx,grid_speed
@@loop:
	push	cx
	call	adjust_velocities
	call	move_grid_points
	call	adjust_point
	pop	cx
	loop	@@loop
	popa
	ret

adjust_velocities:
	pusha
	mov	di,[grid_table]
	add	di,grid_len*(grid_w+1)
	mov	cx,[grid_size]
	sub	cx,2
@@next_row:
	push	cx
	mov	cx,[grid_size]
	sub	cx,2
	push	di
@@next_col:
	push	cx

	mov	ebx,grid_z[di-grid_len]		; left
	add	ebx,grid_z[di+grid_len]	      	; right
	add	ebx,grid_z[di-grid_w*grid_len]	; above
	add	ebx,grid_z[di+grid_w*grid_len]	; below
	add	ebx,grid_z[di-grid_w*grid_len-grid_len]	; above left
	add	ebx,grid_z[di+grid_w*grid_len+grid_len]	; below
	mov	eax,grid_z[di]
	add	eax,eax
	mov	ecx,eax
	add	eax,eax
	add	eax,ecx		
	sub	eax,ebx		; eax = compound offset of the six points	
	sar	eax,5		; eax = acceleration from this position

	mov	cl,friction
	or	cl,cl
	je	@@no_frict
	mov	ebx,grid_zv[di]
	sar	ebx,cl		 ; friction
	add	eax,ebx
@@no_frict:

	sub	grid_zv[di],eax

	add	di,grid_len
	pop	cx
	loop	@@next_col

	pop	di
	add	di,grid_len*grid_w		; skip two cols
	pop	cx
	loop	@@next_row
	
	popa
	ret

move_grid_points:
	pusha
	mov	di,[grid_table]
	add	di,grid_len*(grid_w+1)
	mov	cx,[grid_size]
	sub	cx,2
@@next_row:
	push	cx
	mov	cx,[grid_size]
	sub	cx,2
	push	di
@@next_col:
	mov	ebx,grid_zv[di]
	add	grid_z[di],ebx
	add	di,grid_len
	loop	@@next_col
	pop	di
	add	di,grid_len*grid_w
	pop	cx
	loop	@@next_row
	popa


	ret
	

draw_grid:
	pusha
	mov	si,1	     		; grid colour

	mov	cx,grid_w-1
	mov	di,[grid_table]
@@next_row:
	push	cx
	mov	cx,grid_w-1
@@next_col:
	push	cx
	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len]
	call	draw_line
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w]
	call	draw_line
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w+grid_len]
	call	draw_line
	add	di,grid_len
	pop	cx

	inc	si

	loop	@@next_col
	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w]
	call	draw_line
	add	di,grid_len    		; skip last col
	pop	cx
	add	bx,grid_gap
	loop	@@next_row
	mov	cx,grid_w-1
@@next_bot_col:
	push	cx
	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len]
	call	draw_line
	add	di,grid_len
	pop	cx
	loop	@@next_bot_col


	popa
	ret
	

getcol:
	mov	si,0
	mov	ax,word ptr grid_z[di+2]
	sar	ax,1

	sub	ax,20		; move middle up a bit

	or	ax,ax
	jns	@@ok
	neg	ax
;	add	ax,64

;	mov	si,63
;	cmp	ax,63
;	jl	@@ok
	
	mov	si,ax
@@ok:
	ret


draw_grid_borderless:
	pusha
	mov	si,1	     		; grid colour

	mov	cx,[grid_size]
	sub	cx,3
	mov	di,[grid_table]
	add	di,grid_len*(grid_w+1)
@@next_row:
	push	cx
	mov	cx,[grid_size]
	sub	cx,3
	push	di
@@next_col:
	push	cx

	call	getcol


	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len]
	call	draw_line
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w]
	call	draw_line
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w+grid_len]
	call	draw_line
	add	di,grid_len
	pop	cx
	loop	@@next_col
	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len*grid_w]
	mov	dx,word ptr grid_y[di+2+grid_len*grid_w]
	add	dx,word ptr grid_z[di+2+grid_len*grid_w]
	call	draw_line

	pop	di
	add	di,grid_len*grid_w    	; skip last col
	pop	cx
	add	bx,grid_gap
	loop	@@next_row
	mov	cx,[grid_size]
	sub	cx,3
@@next_bot_col:
	push	cx

	call	getcol

	mov	ax,word ptr grid_x[di+2]
	mov	bx,word ptr grid_y[di+2]
	add	bx,word ptr grid_z[di+2]
	mov	cx,word ptr grid_x[di+2+grid_len]
	mov	dx,word ptr grid_y[di+2+grid_len]
	add	dx,word ptr grid_z[di+2+grid_len]
	call	draw_line
	add	di,grid_len
	pop	cx
	loop	@@next_bot_col


	popa
	ret



; draw the grid with hidden lines removed
; draw lines bottom to top
draw_grid_hlr:
	pusha

	call	init_horizon

	mov	si,1	     		; grid colour



	mov	di,[grid_table]		; start of map
	add	di,grid_len		; in a column
	
	mov	ax,grid_len
	mov	bx,grid_w		
	mul	bx  		; ax  = size of a line
	mov	bx,[grid_size]		
	sub	bx,2
	mul	bx			; ax = offset of second line from bot
	add	di,ax			; di = second line from bot

	mov	cx,[grid_size]
	sub	cx,3
@@next_row:
	push	cx
	push	di



; flat


	push	di
	add	di,grid_len
	mov	cx,[grid_size]
	sub	cx,3
@@next_col1:
	push	cx
	call	getcol

	mov	cx,word ptr grid_x[di+2]
	mov	dx,word ptr grid_y[di+2]
	add	dx,word ptr grid_z[di+2]
	mov	ax,word ptr grid_x[di+2-grid_len]
	mov	bx,word ptr grid_y[di+2-grid_len]
	add	bx,word ptr grid_z[di+2-grid_len]
	call	draw_line_hlr
	add	di,grid_len	 
	pop	cx
	loop	@@next_col1
	pop	di

; diagonal

	push	di
	add	di,grid_len
	mov	cx,[grid_size]
	sub	cx,3
@@next_col2:
	push	cx
	call	getcol

	mov	cx,word ptr grid_x[di+2]
	mov	dx,word ptr grid_y[di+2]
	add	dx,word ptr grid_z[di+2]
	mov	ax,word ptr grid_x[di+2-grid_len*grid_w-grid_len]
	mov	bx,word ptr grid_y[di+2-grid_len*grid_w-grid_len]
	add	bx,word ptr grid_z[di+2-grid_len*grid_w-grid_len]
	call	draw_line_hlr
	add	di,grid_len	 
	pop	cx
	loop	@@next_col2
	pop	di


; up (with initial left edge)


	call	getcol
	mov	cx,word ptr grid_x[di+2]
	mov	dx,word ptr grid_y[di+2]
	add	dx,word ptr grid_z[di+2]
	mov	ax,word ptr grid_x[di+2-grid_len*grid_w]
	mov	bx,word ptr grid_y[di+2-grid_len*grid_w]
	add	bx,word ptr grid_z[di+2-grid_len*grid_w]
	call	draw_line_hlr  	; left edge
	add	di,grid_len

	mov	cx,[grid_size]
	sub	cx,3
@@next_col:
	push	cx

	call	getcol

	mov	cx,word ptr grid_x[di+2]
	mov	dx,word ptr grid_y[di+2]
	add	dx,word ptr grid_z[di+2]
	mov	ax,word ptr grid_x[di+2-grid_len*grid_w]
	mov	bx,word ptr grid_y[di+2-grid_len*grid_w]
	add	bx,word ptr grid_z[di+2-grid_len*grid_w]
	call	draw_line_hlr
	add	di,grid_len	 
	pop	cx
	loop	@@next_col



	pop	di
	sub	di,grid_len*grid_w    	; nex line
	pop	cx
	add	bx,grid_gap
	dec	cx
	or	cx,cx
	jne	@@next_row

	mov	cx,[grid_size]
	sub	cx,3
@@next_bot_col:
	push	cx

	call	getcol

	mov	cx,word ptr grid_x[di+2]
	mov	dx,word ptr grid_y[di+2]
	add	dx,word ptr grid_z[di+2]
	mov	ax,word ptr grid_x[di+2+grid_len]
	mov	bx,word ptr grid_y[di+2+grid_len]
	add	bx,word ptr grid_z[di+2+grid_len]
	call	draw_line_hlr
	add	di,grid_len
	pop	cx
	loop	@@next_bot_col


	popa
	ret


; set all the horizon to the max (200)
init_horizon:
	pusha
	push	es
	mov	ax,@data
	mov	es,ax
	mov	ax,64000
	mov	di,offset horizon
	mov	cx,320
	cld
	rep	stosw
	pop	es
	popa
	ret
	


;****************************************************************
;****************************************************************
;****************************************************************


snow_demo:
	call	get_snow
@@again:
	call	clear_screen
	call	setup_snow_palette
	call	setup_snow
	call	bottom_line

	mov	[last_key],0
	call	draw_with_mouse

@@loop:
	call	move_snow
	call	draw_snow

	mov	[last_key],0
	call	maybe_exit

	call	raster_wait


	mov	al,last_key
	cmp	al,020h
	je	@@again

	jmp	@@loop


dust_demo:
@@again:
	call	clear_screen
	call	setup_dust_palette
	call	setup_dust

	mov	[last_key],0
;	call	draw_with_mouse

@@loop:
	call	read_mouse
	mov	ax,mouse_buttons
	test	ax,1
	jne	@@no
	call	rnd
	and	ax,01ffh
	mov	mouse_x,ax
	call	rnd
	and	ax,01ffh
	mov	mouse_y,ax
	mov	mouse_xv,0
	mov	mouse_yv,0
@@no:
	call	rnd
	and	ax,0ffh
	add	ax,10
	mov	cx,ax
	call	new_dust

	mov	cx,10
@@nothing:
	push	cx
	call	move_dust
	call	draw_dust
	call	raster_wait
	pop	cx
	loop	@@nothing

	mov	[last_key],0
	call	maybe_exit



	mov	al,last_key
	cmp	al,020h
	je	@@again

	jmp	@@loop




grav_demo:
@@again:
	call	clear_screen
	call	setup_dust_palette
	call	setup_grav

	mov	[last_key],0
;	call	draw_with_mouse

@@loop:
	call	read_mouse
	mov	ax,mouse_buttons
	test	ax,1
	jne	@@no
@@no:

;	mov	si,[ob_table]
;	mov	ax,mouse_x
;	mov	word ptr grav_x[si+2],ax
;	mov	ax,mouse_y
;	mov	word ptr grav_y[si+2],ax
;	mov	grav_xv[si],0
;	mov	grav_yv[si],0

@@um:
	call	move_grav
	call	draw_grav

	mov	[last_key],0
	call	maybe_exit

	call	raster_wait


	mov	al,last_key
	cmp	al,020h
	je	@@again

	jmp	@@loop

	


line_demo:
	call	setup_obs

@@loop:
	call	move_obs
;	call	funny_draw_obs
	call	line_draw_obs

	call	maybe_exit

	call	raster_wait

	jmp	@@loop



exit:

	mov	sp,stack_pointer

	mov	ah,0  			; back to 80x25 text mode
	mov	al,3
	int	10h

	dalloc	grid_table
	dalloc	ob_table
	dalloc	screen_segment

	mov	al,0			; exit code ok
	mov	ah,4ch	    		; exit 
	int	21h




init_mouse:
	mov	ax,00h
	int	33h
	ret


show_mouse:
	push	ax
	mov	ax,001h
	int	33h
	pop	ax
	ret

hide_mouse:
	push	ax
	mov	ax,002h
	int	33h
	pop	ax
	ret

get_mouse_pos:
	mov	ax,003h
	int	33h
	ret


read_mouse:
	pusha
	mov	ax,mouse_x
	mov	bx,mouse_y
	pusha
	call	get_mouse_pos
 	mov	[mouse_buttons],bx
	shr	cx,1
	mov	[mouse_x],cx
	mov	[mouse_y],dx
	popa
	sub	ax,mouse_x
	sub	bx,mouse_y
	neg	ax
	mov	mouse_xv,ax
	neg	bx
	mov	mouse_yv,bx
	popa
	ret


draw_with_mouse:
;	call	show_mouse
@@loop:
	call	maybe_exit
	call	read_mouse
	
	mov	ax,mouse_buttons
	or	ax,ax
	je	@@no_button

	and	ax,3

	test	ax,01h
	je	@@not_left
	mov	si,100
	jmp	@@doit
@@not_left:
	test	ax,02h
	je	@@no_button
	mov	si,0
@@doit:
	call	hide_mouse
	mov	ax,mouse_x
	mov	bx,mouse_y
	mov	cx,old_mouse_x	
	mov	dx,old_mouse_y
	call	draw_line
	jmp	@@done

@@no_button:
	call	show_mouse
@@done:


	mov	ax,mouse_x
	mov	old_mouse_x,ax
	mov	ax,mouse_y
	mov	old_mouse_y,ax

	cmp	[last_key],32
	jne	@@loop
	call	hide_mouse
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




setup_palette:
	


	mov	ax,1010h
	mov	dh,0h
	mov	cl,0h
	mov	ch,0h
	mov	di,offset palette
	mov	bx,1		; first register
@@next:
	mov	byte ptr[di],dh
	mov	byte ptr[di+1],cl	   	; black to blue
	mov	byte ptr[di+2],ch
	add	di,3
;	inc	dh
;	inc	cl
	inc	ch
	inc	bx
	cmp	bx,32
	jne	@@next

	mov	bx,1		; first register

@@next1:
	mov	byte ptr[di],dh	   		; blue to green
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
;	inc	dh
	inc	cl
	inc	cl
	dec	ch
	dec	ch
	inc	bx
	cmp	bx,16
	jne	@@next1


	mov	bx,1		; first register

@@next2:
	mov	byte ptr[di],dh	     		; green to white
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
	inc	dh
;	inc	cl
	inc	ch
	inc	bx
	cmp	bx,32
	jne	@@next2


	mov	bx,1		; first register
@@next3:
	mov	byte ptr[di],dh	     		; white to red
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
;	inc	dh
	dec	cl
	dec	ch
	inc	bx
	cmp	bx,32
	jne	@@next3


	push	es
	mov	ax,@data
	mov	es,ax
	mov	ax,1012h
	mov	bx,0
	mov	cx,256
	mov	dx,offset palette
	int	10h
	pop	es


	ret


setup_snow_palette:
	
	mov	ax,1010h
	mov	bx,1		; first register
	mov	dh,0ffh
	mov	cl,0ffh
	mov	ch,0ffh
	mov	di,offset palette
@@next:
;	rept	4
	mov	byte ptr[di],dh
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
	inc	bx
;	endm

	dec	dh
	dec	cl
	dec	ch
	cmp	bx,255
	jne	@@next

	push	es
	mov	ax,@data
	mov	es,ax
	mov	ax,1012h
	mov	bx,1
	mov	cx,50
	mov	dx,offset palette
	int	10h
	pop	es


	ret



setup_dust_palette:
	
	mov	ax,1010h
	mov	bx,1		; first register
	mov	di,offset palette
	mov	si,offset the_palette
@@next:
	mov	byte ptr[di],dh
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
	inc	bx
;	endm

	inc	dh
	inc	cl
	inc	ch
	cmp	bx,255
	jl	@@next

	push	es
	mov	ax,@data
	mov	es,ax
	mov	ax,1012h
	mov	bx,1
	mov	cx,50
	mov	dx,offset the_palette
	int	10h
	pop	es


	ret
	


xsetup_dust_palette:
	
	mov	ax,1010h
	mov	bx,1		; first register
	mov	dh,0h
	mov	cl,0h
	mov	ch,0h
	mov	di,offset palette
@@next:
;	rept	2
	mov	byte ptr[di],dh
	mov	byte ptr[di+1],cl
	mov	byte ptr[di+2],ch
	add	di,3
	inc	bx
;	endm

	inc	dh
	inc	cl
	inc	ch
	cmp	bx,255
	jl	@@next

	push	es
	mov	ax,@data
	mov	es,ax
	mov	ax,1012h
	mov	bx,1
	mov	cx,50
	mov	dx,offset palette
	int	10h
	pop	es


	ret


old:
	mov	ax,1010h
	mov	bx,1		; first register
	mov	dh,0ffh
	mov	cl,0ffh
	mov	ch,0ffh
@@next:
	int	10h
	dec	dh
	dec	cl
	dec	ch
	inc	bx
	cmp	bx,255
	jne	@@next
	ret




setup_dust:
	pusha

	mov	cx,max_dust
	mov	si,[ob_table]
	mov	bx,1
@@loop:
	mov	dust_flag[si],0
	add	si,dust_len
	loop	@@loop


	popa	
	ret



move_dust:
	mov	cx,max_dust
	mov	si,[ob_table]
@@next_dust:
	mov	ax,dust_flag[si]
	or	ax,ax
	je	@@nope

	mov	eax,dust_xv[si]
	mov	ebx,eax
	sar	ebx,4  			; friction
	sub	eax,ebx
	mov	dust_xv[si],eax
	add	dust_x[si],eax

	mov	eax,dust_yv[si]
	mov	ebx,eax
	sar	ebx,4	 		; friction
	sub	eax,ebx
	add	eax,00000a00h		; gravity
	mov	dust_yv[si],eax
	add	dust_y[si],eax
	

@@nope:
	add	si,dust_len
	loop	@@next_dust

	ret



draw_dust:
	mov	cx,max_dust
	mov	si,[ob_table]
@@next_dust:
	mov	ax,dust_flag[si]
	or	ax,ax
	je	@@nope
	dec	ax
	mov	dust_flag[si],ax

	mov	di,dust_old_addr[si]
	mov	bl,0
	mov	[es:di],bl		; clear old one

;	mov	di,dust_old_addr1[si]
;	mov	[es:di],bl		; clear old one
;	mov	di,dust_old_addr2[si]
;	mov	[es:di],bl		; clear old one
;	mov	di,dust_old_addr3[si]
;	mov	[es:di],bl		; clear old one
	or	ax,ax
	je	@@nope

	push	cx
	mov	cx,word ptr dust_x[si+2]
	mov	dx,word ptr dust_y[si+2]
	cmp	dx,0
	jl	@@n
	cmp	dx,200
	jg	@@n
	mov	ax,dust_flag[si]

;	pusha	
	call	qplot
	mov	dust_old_addr[si],di
;	popa


	if	0
	pusha
	mov	bx,320
	sub	bx,cx
	mov	cx,bx
	call	qplot
	mov	dust_old_addr1[si],di
	popa
	pusha
	mov	bx,200
	sub	bx,dx
	mov	dx,bx
	call	qplot
	mov	dust_old_addr2[si],di
	popa
	pusha
	mov	bx,200
	sub	bx,dx
	mov	dx,bx
	mov	bx,320
	sub	bx,cx
	mov	cx,bx
	call	qplot
	mov	dust_old_addr3[si],di
	popa
	endif
@@n:
	pop	cx

@@nope:
	add	si,dust_len
	dec	cx
	or	cx,cx
	jne	@@next_dust
	ret
	


; input cx = number of particles
;

max_velocity	equ	450

new_dust:
	pushad
	mov	si,[ob_table]


	call	rnd
	mov	bx,max_velocity
	mul	bx
	mov	ax,dx			; ax = a random velicity
	cwde
	mov	edi,eax


@@next_dust:

	push	cx

	mov	cx,max_dust
@@find_dust:
	mov	ax,dust_flag[si]
	or	ax,ax
	je	@@got_one
	add	si,dust_len
	loop	@@find_dust
	pop	cx
	jmp	@@done
@@got_one:

	call	rnd
	cwde   	
	mov	ecx,edi
	mul	ecx
	sar	eax,4
	mov	dust_xv[si],eax

	call	rnd
	cwde   	
	mov	ecx,edi
	mul	ecx
	sar	eax,4
	mov	dust_yv[si],eax

	mov	ax,mouse_x
	mov	word ptr dust_x[si+2],ax
	mov	ax,mouse_y
	mov	word ptr dust_y[si+2],ax
	mov	dust_flag[si],64

	pop	cx
	loop	@@next_dust
@@done:
	popad

	ret
	









setup_grav:
	pusha

	mov	cx,max_grav
	mov	si,[ob_table]
	mov	bx,1
@@loop:
	mov	grav_flag[si],1

	call	rnd	
	and	ax,1ffh
	mov	word ptr grav_x[si+2],160     ;	ax
	call	rnd	
	and	ax,1ffh
	mov	word ptr grav_y[si+2],100     ;	ax
	call	rnd	
	and	eax,0ffffh
	sal	eax,2
	mov	grav_xv[si],0
	call	rnd	
	and	eax,0ffffh
	sal	eax,2
	mov	grav_yv[si],0


	mov	grav_flag[si],100
	add	si,grav_len
	loop	@@loop


	popa	
	ret



move_grav:
	mov	cx,max_grav
	mov	si,[ob_table]
@@next_grav:
	mov	ax,grav_flag[si]
	or	ax,ax
	je	@@nope


;	pusha
;
;	mov	cx,max_grav
;	mov	di,[ob_table]
;@@next_other:
;	mov	ax,grav_flag[di]
;	or	ax,ax
;	je	@@nope_other
;
;	mov	eax,grav_x[di]
;	sub	eax,grav_x[si]
;	sar	eax,10
;	add	grav_xv[si],eax
;@@nope_x:
;	
;
;
;	mov	eax,grav_y[di]
;	sub	eax,grav_y[si]
;	sar	eax,10
;	add	grav_yv[si],eax
;@@nope_y:
;
;@@nope_other:
;	add	di,grav_len
;;	loop	@@next_other
;	
;	popa




	call	rnd	
	and	eax,0ffffh
	sar	eax,1
	add	grav_xv[si],eax
	call	rnd	
	and	eax,0ffffh
	sar	eax,1
	add	grav_yv[si],eax

	call	rnd	
	and	eax,0ffffh
	sar	eax,1
	sub	grav_xv[si],eax
	call	rnd	
	and	eax,0ffffh
	sar	eax,1
	sub	grav_yv[si],eax



	mov	eax,grav_xv[si]
	mov	ebx,eax
	sar	ebx,5  			; friction
	sub	eax,ebx
	mov	grav_xv[si],eax
	add	grav_x[si],eax

	cmp	grav_x[si],0*65536
	jg	@@not_left
	mov	grav_x[si],0
	neg	grav_xv[si]
@@not_left:

	cmp	grav_x[si],320*65536
	jl	@@not_right
	mov	grav_x[si],319*65536
	neg	grav_xv[si]
@@not_right:


	mov	eax,grav_yv[si]
	mov	ebx,eax
	sar	ebx,5	 		; friction
	sub	eax,ebx
	mov	grav_yv[si],eax
	add	grav_y[si],eax
	

	cmp	grav_y[si],0*65536
	jg	@@not_top
	mov	grav_y[si],0
	neg	grav_yv[si]
@@not_top:

	cmp	grav_y[si],200*65536
	jl	@@not_bot
	mov	grav_y[si],199*65536
	neg	grav_yv[si]
@@not_bot:


@@nope:
	add	si,grav_len
	dec	cx
	jne	@@next_grav
;	loop	@@next_grav

	ret



draw_grav:
	mov	cx,max_grav
	mov	si,[ob_table]
@@next_grav:
	mov	ax,grav_flag[si]
	or	ax,ax
	je	@@nope
	dec	ax
;	mov	grav_flag[si],ax

	mov	di,grav_old_addr[si]
	mov	bl,0
	mov	[es:di],bl		; clear old one
	or	ax,ax
	je	@@nope

	push	cx
	mov	cx,word ptr grav_x[si+2]
	mov	dx,word ptr grav_y[si+2]
	cmp	dx,0
	jl	@@nah
	cmp	dx,200
	jg	@@nah
	mov	ax,grav_flag[si]

	call	qplot
	mov	grav_old_addr[si],di
@@nah:
	pop	cx

@@nope:
	add	si,grav_len
	dec	cx
	or	cx,cx
	jne	@@next_grav
	ret
	


new_grav:
	mov	cx,max_grav
	mov	si,[ob_table]
@@next_grav:
	mov	ax,grav_flag[si]
	or	ax,ax
	jne	@@nope

	call	rnd
	cwde   	
	sal	eax,2

	mov	ebx,dword ptr [mouse_xv-2]
	sar	ebx,2

	add	eax,ebx
	mov	grav_xv[si],eax

	call	rnd
	cwde   	
	sal	eax,2

	mov	ebx,dword ptr [mouse_yv-2]
	sar	ebx,2

	add	eax,ebx
	mov	grav_yv[si],eax

;	call	read_mouse
	mov	ax,mouse_x
	mov	word ptr grav_x[si+2],ax
	mov	ax,mouse_y
	mov	word ptr grav_y[si+2],ax
	mov	grav_flag[si],64
	jmp	@@done
@@nope:
	add	si,grav_len
	loop	@@next_grav
@@done:
	ret




setup_snow:
	pusha

	mov	cx,max_snow
	mov	si,[ob_table]
	mov	bx,1
@@loop:
	call	rnd
	and	ax,03ffh
	mov	snow_addr[si],ax
	mov	snow_flag[si],bx
	add	bx,2
	mov	snow_old_addr[si],ax
	mov	snow_count[si],snow_freeze
	call	rnd
	mov	dx,7
	mul	dx
	mov	ax,dx
	add	ax,1
	mov	snow_speed[si],al
	mov	snow_delay[si],al
	call	rnd	
	and	ax,1
	je	@@not_ff
	mov	al,0ffh
@@not_ff:
	mov	ah,slide_time
	mov	snow_slide[si],ah
	mov	snow_direction[si],al
	add	si,snow_len
	loop	@@loop


	popa	
	ret

bottom_line:
	pusha
	mov	ax,0
	mov	bx,199
	mov	cx,319
	mov	dx,199
	mov	si,100
	call	draw_line
	popa
	ret



move_snow:
	pusha

	mov	cx,max_snow
	mov	si,[ob_table]
@@loop:
	mov	ax,snow_flag[si]
	or	ax,ax
	je	@@on
	dec	ax
	mov	snow_flag[si],ax
	jmp	@@done
@@on:
	dec	snow_delay[si]
	jne	@@done
	mov	al,snow_speed[si]
	mov	snow_delay[si],al

	mov	di,snow_addr[si]
	mov	snow_old_addr[si],di
	add	di,320			; nex line down
	mov	al,[es:di]
	or	al,al
	je	@@this	

	mov	al,snow_direction[si]
	or	al,al
	je	@@right_first


	sub	di,1+320		; pixel to left
	mov	bx,di
	mov	ah,[es:di]
	or	ah,ah			; ah = pixel to left
	jne	@@not_left

	add	di,320			; down and to left
	mov	al,[es:di]
	or	al,al
	je	@@this
	sub	di,320	
@@not_left:
	add	di,2	    		; pixel to right
	mov	al,[es:di]
	or	al,al
	jne	@@not_right
	add	di,320			; down and to left
	mov	al,[es:di]
	or	al,al
	je	@@this
@@not_right:
	jmp	@@neither


@@right_first:
	sub	di,320-1		; pixel to right
	mov	bx,di
	mov	ah,[es:di]
	or	ah,ah
	jne	@@not_right1

	add	di,320			; down and to left
	mov	al,[es:di]
	or	al,al
	je	@@this
	sub	di,320	
@@not_right1:
	sub	di,2	    		; pixel to right
	mov	al,[es:di]
	or	al,al
	jne	@@not_left1
	add	di,320			; down and to left
	mov	al,[es:di]
	or	al,al
	je	@@this
@@not_left1:


@@neither:


; if we get to here then the way down is blocked
; first check if we can move to the left or right
; ah will be the pixel there, bx will be the offset
	mov	al,snow_slide[si]
	or	al,al
	je	@@no_sliding
	dec	snow_slide[si]
	
	or	ah,ah
	jne	@@cant_slide
	mov	snow_count[si],snow_freeze     	; dont freeze yet
	mov	snow_addr[si],bx
	jmp	@@done	

@@cant_slide:
	not	snow_direction[si]
	jmp	@@done


@@no_sliding:
	mov	ax,snow_count[si]
	dec	ax
	mov	snow_count[si],ax
	or	ax,ax
	jne	@@done	
	pusha
	call	rnd
	and	ax,01ffh
	mov	snow_addr[si],ax
	if	not snow_melts
	mov	snow_old_addr[si],ax
	endif
	mov	snow_count[si],snow_freeze
	popa
	jmp	@@done
	
@@this:
	mov	ah,slide_time
	mov	snow_slide[si],ah
	not	snow_direction[si]
	mov	snow_count[si],snow_freeze
	mov	snow_addr[si],di
@@done:
	add	si,snow_len
	dec	cx
	jne	@@loop


	popa	
	ret

draw_snow:
	pusha
	mov	cx,max_snow
	mov	si,[ob_table]
@@loop:
	mov	ax,snow_flag[si]
	or	ax,ax
	jne	@@no
	mov	di,snow_old_addr[si]
	mov	byte ptr[es:di],0
	mov	di,snow_addr[si]
	mov	ax,snow_count[si]
	mov	byte ptr[es:di],al
@@no:
	add	si,snow_len
	loop	@@loop


	popa	
	ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
setup_obs:
	pusha

	mov	ax,0
	mov	bx,0
	mov	dx,-1

	mov	cx,max_ob
	mov	di,[ob_table]
@@loop:
	mov	ob_flag[di],1
	call	rnd
	and	ax,0ffh
	mov	ob_x[di],ax
	mov	ob_old_x[di],ax

	call	rnd
	and	ax,07fh
	mov	ob_y[di],ax
	mov	ob_old_y[di],ax


@@nzx:
	call	rnd
	and	ax,7
	sub	ax,3
	je	@@nzx
	mov	ob_xv[di],ax

@@nzy:
	call	rnd
	and	ax,7
	sub	ax,3
	je	@@nzy
	mov	ob_yv[di],ax

	call	rnd
	and	ax,0ffh
	mov	ob_colour[di],ax

	inc	ax
	inc	bx

	add	di,ob_len

	loop	@@loop

	popa
	ret


;rnd_test:
;@@again:
;	mov	cx,3000
;@@loop:
;	mov	di,offset bar
;	call	rnd
;	and	ax,0ffh
;	add	ax,ax
;	mov	si,di
;	add	si,ax
;	add	word ptr[si],1
;	loop	@@loop
;
;	mov	cx,255
;	mov	si,offset bar
;@@print:
;	push	cx
;	mov	dx,[si]
;	shr	dx,8
;	add	si,2
;	mov	al,100 
;	call	plot
;	pop	cx
;	loop	@@print
;	call	maybe_exit
;	jmp	@@again	
		
	



xrnd_test:

	mov	cx,0
	mov	dx,0
	mov	al,100
	call	plot

@@x:
	call	rnd
	and	ax,0ffh
	mov	cx,ax

	call	rnd
	and	ax,07fh
	mov	dx,ax

	call	rnd
	mov	al,100

	call	plot

	call	maybe_exit

	jmp	@@x
	



move_obs:
	pusha


	mov	cx,max_ob
	mov	di,[ob_table]
@@loop:
	push	cx

	mov	ax,ob_x[di]
	mov	ob_old_x[di],ax
	add	ax,ob_xv[di]
	cmp	ax,0
	jg	@@not_off_left
	mov	ax,0
	neg	ob_xv[di]
	jmp	@@not_off_right
@@not_off_left:
	cmp	ax,max_x
	jl	@@not_off_right
	mov	ax,max_x-1
	neg	ob_xv[di]
@@not_off_right:
	mov	ob_x[di],ax


	mov	ax,ob_y[di]
	mov	ob_old_y[di],ax
	add	ax,ob_yv[di]
	cmp	ax,0
	jg	@@not_off_top
	mov	ax,0
	neg	ob_yv[di]
	jmp	@@not_off_bot
@@not_off_top:
	cmp	ax,max_y
	jl	@@not_off_bot
	mov	ax,max_y-1
	neg	ob_yv[di]
@@not_off_bot:
	mov	ob_y[di],ax


	add	ob_colour[di],1

	add	di,ob_len
	pop	cx
	loop	@@loop


	popa
	ret



draw_obs:
	pusha


	mov	cx,max_ob
	mov	di,[ob_table]
@@loop:
	push	cx


	mov	cx,ob_old_x[di]
	mov	dx,ob_old_y[di]
	mov	al,0		; erase old one
	call	plot	

	mov	cx,ob_x[di]
	mov	dx,ob_y[di]
	mov	ob_old_x[di],cx
	mov	ob_old_y[di],dx
	mov	ax,ob_colour[di]		; draw new one
	call	plot	


	add	di,ob_len
	pop	cx
	loop	@@loop


	popa
	ret


line_draw_obs:
	pusha


	mov	cx,max_ob-1
	mov	di,[ob_table]
@@loop:
	push	cx
	
	mov	si,di
	add	si,ob_len	

	mov	ax,ob_old_x[si]
	mov	bx,ob_old_y[si]
	mov	cx,ob_old_x[di]
	mov	dx,ob_old_y[di]
	mov	si,0		; erase old one
	call	draw_line

	mov	si,di
	add	si,ob_len	

	mov	ax,ob_x[si]
	mov	bx,ob_y[si]
	mov	cx,ob_x[di]
	mov	dx,ob_y[di]
	mov	si,ob_colour[di]		; draw new
	call	draw_line


	add	di,ob_len
	pop	cx
	loop	@@loop

	mov	si,[ob_table]

	mov	ax,ob_old_x[si]
	mov	bx,ob_old_y[si]
	mov	cx,ob_old_x[di]
	mov	dx,ob_old_y[di]
	mov	si,0		; erase old one
	call	draw_line

	mov	si,[ob_table]

	mov	ax,ob_x[si]
	mov	bx,ob_y[si]
	mov	cx,ob_x[di]
	mov	dx,ob_y[di]
	mov	si,100		; draw new
	call	draw_line




	popa
	ret



funny_draw_obs:
	pusha

	
	mov	di,[ob_table]
	mov	si,100		; draw

	mov	colour,si
	mov	cx,max_ob
@@loop:
	push	cx
	mov	cx,max_ob
	mov	si,[ob_table]
@@all:
	push	cx

	mov	ax,ob_old_x[si]
	mov	bx,ob_old_y[si]
	mov	cx,ob_old_x[di]
	mov	dx,ob_old_y[di]
	push	si
	mov	si,0
	call	draw_line
	pop	si

	mov	ax,ob_x[si]
	mov	bx,ob_y[si]
	mov	cx,ob_x[di]
	mov	dx,ob_y[di]
	push	si
	mov	si,colour
	call	draw_line
	pop	si


	add	si,ob_len
	pop	cx
	loop	@@all

	add	di,ob_len
	pop	cx
	loop	@@loop


	popa
	ret



; if esc is pressed then exit to dos
maybe_exit:
	pusha
	mov	ah,01h	 		; key pressed ?
	int	16h
	je	@@ok

	mov	ah,00h
	int	16h
	mov	[last_key],al
	cmp	al,27	     		; was it esc ?
	je	exit

@@ok:
	popa
	ret
	

test_line:
	
	mov	cx,100
	mov	dx,100
	mov	al,0ffh
@@next:
	call	plot
	dec	al
	dec	dx
	dec	cx
	jne	@@next


	ret





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; clear screen
;
	
clear_screen:
	pusha
	mov	edi,0
	mov	ecx,64000/4
	xor	eax,eax
	cld
	rep	stosd

	popa
	ret

download_screen:
	push	ds
	pusha
	mov	ax,0a000h
	mov	es,ax			; point es: to video ram
	mov	ax,[screen_segment]
	mov	ds,ax			; point ds: to screen ram
	mov	edi,0
	mov	esi,0
	mov	ecx,64000/4
	cld
	rep	movsd
	popa
	pop	ds
	ret	



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Random number routine
; returns ax as a 16 bit random number
; needs the word variables SEED and SEED1
; is very random and does not repeat for ages
; 
; a=seed b=seed1

;	b''=b+a
;	a'=a^b''^$1234
;	a''=a'^(a'&$8080>>7))

rnd:
	push	bx
	mov	ax,seed		; get old seed

	mov	bx,seed1	; get old seed1
	add	bx,ax	  	; adjust it
	mov	seed1,bx 	; and store it
	xor	ax,bx  		; xor seed with

	xor	ax,01234h
	mov	bx,ax
	and	bx,08080h
	ror	ax,7
	xor	ax,bx
	mov	seed,ax
	pop	bx
	ret
	

	
;-------------------------------------

Raster_Wait:
	pusha
	mov	dx,03dah
@@x:	in	al,dx
	test	al,08h
   	je	@@x

	popa		
   	ret

raster_gone:
	mov	dx,03dah
@@x:	in	al,dx
   	test	al,08h
   	jne	@@x
	ret

;-------------------------------------



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Plot a pixel in MCGA
; input cx,dx,al
; assumes ES is pointing to video ram
plot:
	pusha
	mov	bx,ax
	mov	ax,dx
	mov	dx,320
	mul	dx
	mov	di,ax
	add	di,cx	    		; point es:di - to video ram address
	mov	[es:di],bl
	popa

	ret
	
qplot:
	mov	bx,ax
	mov	ax,dx
	mov	dx,320
	mul	dx
	mov	di,ax
	add	di,cx	    		; point es:di - to video ram address
	mov	[es:di],bl
	ret


gd	dw	0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Draw a line in MCGA
; draw ax,bx to cx,dx in colour si
draw_line:
	pusha
	cmp	ax,cx
	jne	@@ok
	cmp	bx,dx
	jne	@@ok
	mov	ax,si
	call	plot	      	; plot if point coincide
	popa
	ret
@@ok:
	push	si		; save colour

	cmp	ax,cx
	jl	@@left_right
	xchg	ax,cx
	xchg	bx,dx
@@left_right:
	sub	cx,ax		; cx = XD
	sub	dx,bx		; dx = YD
	
; now find position on screen corresponding to x,y (ax,bx)
	mov	di,ax	 	; store x
	mov	ax,bx
	mov	bx,320
	mov	si,dx		; store dx for a tick
	mul	bx
	mov	dx,si	  	; restore dx
	add	di,ax	    	; point es:di - to video ram address

	mov	si,320		; si = line offset
	or	dx,dx
	jns	@@y_down	; if 
	neg	si		; going up
	neg	dx		; make YD positive
@@y_down:

	pop	bx	       	; get colour in bx

	cmp	cx,dx	 	; check if steep (xd<yd)
	jl	@@steep	

; shallow lines
; cx = ld, dx = gd		(always step in x)

	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@shallow_loop:
	mov	byte ptr[es:di],bl	; plot the pixel
	add	di,1		; next pixel in x
	sub	ax,dx		; sub LD from error term
	jnc	@@no_y_step	; if no carry then no extra step	
	add	di,si		; else step in the y	
	add	ax,gd		; add back the gd
@@no_y_step:
	loop	@@shallow_loop
	jmp	@@done

; steep lines
; cx = gd, dx = ld		(always step in y)

@@steep:
	xchg	cx,dx
	
	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@steep_loop:
	mov	byte ptr[es:di],bl	; plot the pixel
	add	di,si		; step in the y	
	sub	ax,dx		; sub LD from error term
	jnc	@@no_x_step	; if no carry then no extra step	
	add	di,1		; next pixel in x
	add	ax,gd		; add back the gd
@@no_x_step:
	loop	@@steep_loop
@@done:
	popa
	ret


; here si is the horizon table
; di is the screen address
; bp is free
maybe_plot_hlr	macro
	local	@@no
	mov	bp,[si]	
	cmp	bp,di
	jc	@@no
	mov	[si],di
	mov	byte ptr[es:di],bl	; plot the pixel
@@no:
	endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Draw a line in MCGA with hidden line removal
; draw ax,bx to cx,dx in colour si
; needs a table of word HORIZON that correspond to the current horizon addr
; for each column of the screen - initially they will be 64000 (bot of screen)
; now does up always
draw_line_hlr:
	pusha
	cmp	ax,cx
	jne	@@ok
	cmp	bx,dx
	jne	@@ok
;	mov	ax,si
;	call	plot	      	; plot if point coincide
	popa
	ret
@@ok:

	cmp	bx,dx
	jg	@@going_down
	xchg	ax,cx
	xchg	bx,dx
@@going_down:

	cmp	bx,199
	jg	@@done
	cmp	dx,200
	jl	@@no_bot_clip
	mov	dx,199
@@no_bot_clip:

	push	si		; save colour

	sub	cx,ax		; cx = XD
	sub	dx,bx		; dx = YD
	neg	dx		; make yd posotive
	
; now find position on screen corresponding to x,y (ax,bx)
	mov	di,ax	 	; store x
	mov	ax,bx
	mov	bx,320
	mov	si,dx		; store dx for a tick
	mul	bx
	mov	dx,si	  	; restore dx
	mov	si,offset horizon
	add	si,di
	add	si,di		; si is now the position in the horizon
	add	di,ax	    	; point es:di - to video ram address

	mov	bx,1		; line offset
	or	cx,cx
	jns	@@x_down	; if 
	neg	bx		; going up
	neg	cx		; make XD positive
@@x_down:
	mov	[y_line_offset],bx


	pop	bx	       	; get colour in bx

	cmp	cx,dx	 	; check if steep (xd<yd)
	jl	@@steep	

; shallow lines
; cx = ld, dx = gd		(always step in x)

	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@shallow_loop:
	maybe_plot_hlr
	add	di,[y_line_offset]   	
	add	si,[y_line_offset]   	
	add	si,[y_line_offset]   	
	sub	ax,dx		; sub LD from error term
	jnc	@@no_y_step	; if no carry then no extra step	
	sub	di,320		; else step in the y	
;	jc	@@done
	add	ax,gd		; add back the gd
@@no_y_step:
	loop	@@shallow_loop
	jmp	@@done

; steep lines
; cx = gd, dx = ld		(always step in y)

@@steep:
	xchg	cx,dx
	
	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@steep_loop:
;	mov	byte ptr[es:di],bl	; plot the pixel
	maybe_plot_hlr
	sub	di,320		; step in the y	
;	jc	@@done
	sub	ax,dx		; sub LD from error term
	jnc	@@no_x_step	; if no carry then no extra step	
	add	di,[y_line_offset]   	
	add	si,[y_line_offset]   	
	add	si,[y_line_offset]   	
	add	ax,gd		; add back the gd
@@no_x_step:
	loop	@@steep_loop
@@done:
	popa
	ret




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Draw a line in MCGA with hidden line removal
; draw ax,bx to cx,dx in colour si
; needs a table of word HORIZON that correspond to the current horizon addr
; for each column of the screen - initially they will be 64000 (bot of screen)
xdraw_line_hlr:
	pusha
;	cmp	ax,cx
;	jne	@@ok
;	cmp	bx,dx
;	jne	@@ok
;	mov	ax,si
;	call	plot	      	; plot if point coincide
;	popa
;	ret
@@ok:
	push	si		; save colour

	cmp	ax,cx
	jl	@@left_right
	xchg	ax,cx
	xchg	bx,dx
@@left_right:
	sub	cx,ax		; cx = XD
	sub	dx,bx		; dx = YD
	
; now find position on screen corresponding to x,y (ax,bx)
	mov	di,ax	 	; store x
	mov	ax,bx
	mov	bx,320
	mov	si,dx		; store dx for a tick
	mul	bx
	mov	dx,si	  	; restore dx
	mov	si,offset horizon
	add	si,di
	add	si,di		; si is now the position in the horizon
	add	di,ax	    	; point es:di - to video ram address

	mov	bx,320		; line offset
	or	dx,dx
	jns	@@y_down	; if 
	neg	bx		; going up
	neg	dx		; make YD positive
@@y_down:
	mov	[y_line_offset],bx

	pop	bx	       	; get colour in bx

	cmp	cx,dx	 	; check if steep (xd<yd)
	jl	@@steep	

; shallow lines
; cx = ld, dx = gd		(always step in x)

	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@shallow_loop:
;	mov	byte ptr[es:di],bl	; plot the pixel
	maybe_plot_hlr
	inc	di		; next pixel in x
	inc	si
	inc	si
	sub	ax,dx		; sub LD from error term
	jnc	@@no_y_step	; if no carry then no extra step	
	add	di,[y_line_offset]		; else step in the y	
;	jc	@@done
	add	ax,gd		; add back the gd
@@no_y_step:
	loop	@@shallow_loop
	jmp	@@done

; steep lines
; cx = gd, dx = ld		(always step in y)

@@steep:
	xchg	cx,dx
	
	mov	gd,cx		; GD, dx = ld
	mov	ax,cx	    	
	sar	ax,1		; ax = error tern (GD/2)
	inc	cx		; loop is gd+1
@@steep_loop:
;	mov	byte ptr[es:di],bl	; plot the pixel
	maybe_plot_hlr
	add	di,[y_line_offset]		; step in the y	
;	jc	@@done
	sub	ax,dx		; sub LD from error term
	jnc	@@no_x_step	; if no carry then no extra step	
	inc	di		; next pixel in x
	inc	si
	inc	si
	add	ax,gd		; add back the gd
@@no_x_step:
	loop	@@steep_loop
@@done:
	popa
	ret




hex_word:
	ror	ax,8
	call	hex_byte
	ror	ax,8

hex_byte:
	ror	al,4
	call	hex_digit
	ror	al,4

; given al = a hex byte then print the hex digit corresponding to lower nibble
hex_digit:
	push	ax
	push	bx
	push	dx
	mov	bx,offset hex_digits
	and	al,0fh
	xlatb
	mov	dl,al
	mov	ah,2
	int	21h
	pop	dx	
	pop	bx
	pop	ax
	ret
	

space	macro
	push	ax
	push	dx
	mov	ah,02h
	mov	dl,20h
	int	21h
	pop	dx
	pop	ax
	endm

pchr	macro	char
	push	ax
	push	dx
	mov	ah,02h
	mov	dl,char
	int	21h
	pop	dx
	pop	ax
	endm
	


test_input:
@@wait:
	call	maybe_exit
	mov	ah,01h
	int	16h
	je	@@wait
	mov	ah,00h
	int	16h
	cmp	al,13
	je	@@done
	mov	dl,al

	mov	ah,2
	int	21h	
	pchr	"-"
	call	hex_word
	space

	jmp	@@wait
@@done:
	ret	



; call with si pointing to a string to print
; all regs preserved
print_string:
	push	dx
	push	si
	push	ax
@@loop:
	mov	dl,[si]
	inc	si
	mov	al,dl
	or	al,al
	je	@@exit
	mov	ah,2
	int	21h
	jmp	@@loop
@@exit:
	pop	ax
	pop	si
	pop	dx

	ret


;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; dos control stuff
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


get_psp:
	push	es
	mov	ah,062h
	int	021h
	mov	[dos_data_seg],bx

	mov	es,bx
	mov	bx,080h			; offset into psp

	mov	cl,[es:bx]		; length of command line +1
	cmp	cl,0
	je	@@no_parameters

	dec	cl
	mov	[command_length],cl
	inc	bx
	inc	bx			; move to start of data	

	mov	di,offset command_line
@@loop:
	mov	al,[es:bx]
	mov	[ds:di],al
	inc	di			; advance destination
	inc	bx			; advance source
	dec	cl
	jne	@@loop

; checks parameter field for blank chars only

	mov	cl,[command_length]
	mov	di,offset command_line
@@loop2:
	mov	al,[ds:di]
	cmp	al,32
	jne	@@not_blank
	dec	cl
	jne	@@loop2
	jmp	@@no_parameters
@@not_blank:
	xor	ax,ax
	pop	es
	ret


@@no_parameters:
	mov	ax,-1
	pop	es
	ret



get_snow:

	call	get_psp
	or	al,al
	jne	@@done


	mov	di,offset command_line

	call	get_number
	cmp	ax,-1
	je	@@done

	mov	[slide_time],0
	cmp	ax,0
	jl	@@done1
	mov	[slide_time],255
	cmp  	ax,255
	jg	@@done1
	mov	[slide_time],al

@@done1:

	call	get_number
	cmp	ax,-1
	je	@@done
	mov	[grid_speed],1
	cmp	ax,1
	jl	@@done
	mov	[grid_speed],20
	cmp  	ax,20
	jg	@@done
	mov	[grid_speed],ax


@@done:
	ret




get_gap:

	call	get_psp
	or	al,al
	jne	@@done


	mov	di,offset command_line

	call	get_number
	cmp	ax,-1
	je	@@done

	mov	[grid_gap],5
	cmp	ax,5
	jl	@@done1
	mov	[grid_gap],50
	cmp  	ax,50
	jg	@@done1
	mov	[grid_gap],ax

@@done1:

	call	get_number
	cmp	ax,-1
	je	@@done
	mov	[grid_speed],1
	cmp	ax,1
	jl	@@done
	mov	[grid_speed],20
	cmp  	ax,20
	jg	@@done
	mov	[grid_speed],ax


@@done:
	ret


get_number:
	mov	ax,-1
@@first_digit:
	mov	dl,[di]
	or	dl,dl
	je	@@got
	inc	di
	cmp	dl,"0"
	jl	@@first_digit
	cmp	dl,"9"
	jg	@@first_digit
	dec	di
	mov	ax,0
@@next_digit:
	mov	dl,[di]
	or	dl,dl
	je	@@got
	inc	di
	cmp	dl,"0"
	jl	@@got
	cmp	dl,"9"
	jg	@@got
	sub	dl,"0"
	mov	dh,0
	mov	si,10
	push	dx
	mul	si
	pop	dx
	add	ax,dx
	jmp	@@next_digit
@@got:
	ret






