;** ùUùNùRùEùAùLù2ù  Copyright (C) 1993 The Future Crew
;**------------------------------------------------------
;**  Assembler utilities. Most of the useful stuff,
;**  called from the main routine. This file is included
;**  to U2.ASM

;ħħħħħħħħħħħħħħħħ Dos macros ħħħħħħħħħħħħħħħħ

DOS_OPEN equ	3dh
DOS_CLOSE equ	3eh
DOS_READ equ	3fh
DOS_ALLOC equ	48h
DOS_FREE equ	49h
DOS_REALLOC equ	4ah

dosint	MACRO	function
	mov	ah,function
	int	21h
	ENDM
	
fatalerror PROC NEAR
	mov	cs:errorcode,8
	mov	cs:notextmode,0
	mov	ax,3
	int	10h
	jmp	fatalexit00
	push	ax
	push	bx
	push	si
	push	di
	push	ds
	push	es
	mov	si,cx
	mov	ds,dx
	mov	bx,ax
	add	bl,'0'
	mov	ax,1
	int	10h
	mov	ax,0b800h
	mov	es,ax
	test	bx,100h
	jz	@@2
	mov	di,0
	mov	cx,80
	mov	ah,4fh
@@4:	mov	al,ds:[si]
	or	al,al
	jz	@@2
	inc	si
	mov	es:[di],ax
	add	di,2
	loop	@@4
@@2:	mov	di,160
	mov	cx,2000/8
	mov	ah,4eh
@@1:	mov	al,'E'
	mov	es:[di+0],ax
	mov	al,'R'
	mov	es:[di+2],ax
	mov	al,'R'
	mov	es:[di+4],ax
	mov	al,bl
	mov	es:[di+6],ax
	add	di,8
	loop	@@1
	mov	ah,0
	int	16h
	mov	ax,13h
	int	10h
	pop	es
	pop	ds
	pop	di
	pop	si
	pop	bx
	pop	ax
	ret
fatalerror ENDP
	
;ħħħħħħħħħħħħħħħħ Memory management ħħħħħħħħħħħħħħħħ

;°°°°°°°°°°°°°°°° getmem °°°°°°°°°°°°°°°°
;entry:	BX=paras
; exit: AX=segment
;saves: SEGS/SI/DI/BP
;descr: allocates memory
getmem	PROC NEAR
	dosint	DOS_ALLOC
	jc	@@err
	;ax=seg
	ret
@@err:	mov	ax,1
	call	fatalerror
	xor	ax,ax
	ret
getmem	ENDP

;°°°°°°°°°°°°°°°° getmemall °°°°°°°°°°°°°°°°
;entry:	-
; exit: AX=segment,BX=size
;saves: SEGS/SI/DI/BP
;descr: allocates biggest free block ofmemory
getmemall PROC NEAR
	mov	bx,0ffffh
	dosint	DOS_ALLOC
	push	bx
	dosint	DOS_ALLOC
	pop	bx
	jc	@@err
	;ax=seg
	ret
@@err:	mov	ax,2
	call	fatalerror
	xor	ax,ax
	ret
getmemall ENDP

;°°°°°°°°°°°°°°°° getmemup °°°°°°°°°°°°°°°°
;entry:	BX=paras
; exit: AX=segment
;saves: SEGS/SI/DI/BP
;descr: allocates memory from the top of the memory pool
getmemup PROC NEAR
	push	es
	mov	dx,bx
	mov	bx,0ffffh
	dosint	DOS_ALLOC
	sub	bx,dx
	dec	bx
	dosint	DOS_ALLOC
	mov	bx,dx
	mov	dx,ax
	dosint	DOS_ALLOC
	jc	@@err
	mov	es,dx
	mov	dx,ax
	dosint	DOS_FREE
	mov	ax,dx ;ax=seg
	pop	es
	ret
@@err:	pop	es
	mov	ax,3
	call	fatalerror
	xor	ax,ax
	ret
getmemup ENDP

;°°°°°°°°°°°°°°°° freemem °°°°°°°°°°°°°°°°
;entry:	AX=segment
; exit: -
;saves: SEGS/SI/DI/BP
;descr: frees memory
freemem	PROC NEAR
	mov	es,ax
	dosint	DOS_FREE
	jc	@@err
	;ax=seg
	ret
@@err:	mov	ax,4
	call	fatalerror
	xor	ax,ax
	ret
freemem	ENDP

;°°°°°°°°°°°°°°°° regetmem °°°°°°°°°°°°°°°°
;entry:	AX=segment,BX=paras
; exit: -
;saves: SEGS/SI/DI/BP
;descr: resets memory block size
regetmem PROC NEAR
	mov	es,ax
	dosint	DOS_REALLOC
	jc	@@err
	;ax=seg
	ret
@@err:	mov	ax,5
	call	fatalerror
	xor	ax,ax
	ret
regetmem ENDP

;ħħħħħħħħħħħħħħħħ DATAloader: file routines ħħħħħħħħħħħħħħħħ

;°°°°°°°°°°°°°°°° openfile °°°°°°°°°°°°°°°°
;entry:	DS:SI=file name
; exit: AX=file handle (-1=error)
;saves: SEGS/SI/DI/BP
;descr: opens the specified file, wherever it is. 
openfile PROC NEAR
	mov	dx,si
	mov	al,0 ;read
	dosint	DOS_OPEN
	jc	@@1
	ret
@@1:	;error
	mov	ax,-1
	ret
openfile ENDP

;°°°°°°°°°°°°°°°° closefile °°°°°°°°°°°°°°°°
;entry:	AX=file id
; exit: -
;saves: SEGS/SI/DI/BP
;descr: closes the selected file.
closefile PROC NEAR
	mov	bx,ax
	dosint	DOS_CLOSE
	ret
closefile ENDP

;°°°°°°°°°°°°°°°° readfile °°°°°°°°°°°°°°°°
;entry:	AX=file id, CX=count, ES:DI=destination
; exit: -
;saves: SEGS/SI/DI/BP
;descr: reads data.
readfile PROC NEAR
	push	si
	push	ds
	mov	bx,ax
	mov	ax,es
	mov	ds,ax
	mov	dx,di
	dosint	DOS_READ
	pop	ds
	pop	si
	ret
readfile ENDP

;ħħħħħħħħħħħħħħħħ EXEloader: loadexe/runexe ħħħħħħħħħħħħħħħħ

ALIGN 2
exeldr_pspseg	dw	0 ;loaded programs psp [USED BY DISINT.ASM FOR SETPID]
exeldr_ownpsp	dw	0 ;exeloaders psp      [USED BY DISINT.ASM FOR SETPID]
exeldr_oktorun	dw	0
exeldr_handle	dw	0
exeldr_pspsi	dw	0
exeldr_base	dw	0 ;codewise segment 0
exeldr_hdrseg	dw	0
exeldr_exelen	dw	0 ;in paras
exeldr_highflag	dw	0 ;1=load high as possible
exeldr_ownss	dw	0
exeldr_ownsp	dw	0
exeldr_cs	dw	0
exeldr_ip	dw	0
exeldr_ss	dw	0
exeldr_sp	dw	0
exeldr_goodexe	dw	0

;°°°°°°°°°°°°°°°° loadexe °°°°°°°°°°°°°°°°
;entry:	AX=file handle pointing to exefile
; exit: (exeldr_* variables)
;saves: none
;descr: loads the specified exe file to memory, does relocations
;       and creates psp. Also sets exeldr_* variables for 
;       subsequent call to runexe. NOTE, that at worst, all memory
;	will be reserved after this call for the just loaded exe.
;	NOTE: There are two entry points:
;	loadexe - loads exe normally
;	loadexehigh - loads exe as high in memory as minparasneeded
;                     allows (empty space left BEFORE exe)
loadexeboth PROC NEAR
loadexehigh: ;**ENTRY**
	mov	dx,1
	jmp	@@cont
loadexe: ;**ENTRY**
	xor	dx,dx
@@cont:	mov	cs:exeldr_highflag,dx
	mov	cs:exeldr_oktorun,0
	mov	cs:exeldr_handle,ax
	
	mov	ah,51h
	int	21h ;get current PSP
	mov	cs:exeldr_ownpsp,bx
	
	mov	bx,32/16
	call	getmem
	mov	es,ax
	xor	di,di
	mov	cx,32
	mov	ax,cs:exeldr_handle
	call	readfile
	mov	bx,es:[8h] ;size in paras
	call	getmemup
	mov	cs:exeldr_hdrseg,ax
	mov	cx,32
	mov	ax,es
	mov	ds,ax
	xor	si,si
	mov	es,cs:exeldr_hdrseg
	xor	di,di
	call	memcpy
	mov	ax,ds
	call	freemem
	;load rest of header
	mov	es,cs:exeldr_hdrseg
	mov	cx,es:[8h]
	shl	cx,4
	sub	cx,32
	cmp	cx,0
	jl	@@6
	mov	es,cs:exeldr_hdrseg
	mov	di,32
	mov	ax,cs:exeldr_handle
	call	readfile
@@6:	
	;header now in es:[], no other memory reserved
	mov	ax,es:[0]
	mov	cs:exeldr_goodexe,1
	cmp	ax,0faebh
	je	@@goodexe
	mov	cs:exeldr_goodexe,0
	cmp	ax,5a4dh
	jne	@@badexe
@@goodexe:
	mov	ax,es:[10h]
	mov	cs:exeldr_sp,ax
	mov	ax,es:[0eh]
	mov	cs:exeldr_ss,ax
	mov	ax,es:[14h]
	mov	cs:exeldr_ip,ax
	mov	ax,es:[16h]
	mov	cs:exeldr_cs,ax
	mov	ax,es:[04h]
	shl	ax,5
	mov	cs:exeldr_exelen,ax
	;allocate psp & segment for exe
	cmp	cs:exeldr_highflag,0
	je	@@norm
	mov	bx,es:[0ah] ;minimum paras needed
	add	bx,cs:exeldr_exelen
	add	bx,dx
	push	bx
	call	getmemup
	pop	bx
	jmp	@@con2
@@norm:	call	getmemall ;bx=size of seg allocated
@@con2:	mov	cs:exeldr_pspseg,ax
	add	ax,10h
	mov	cs:exeldr_base,ax
	;create new psp
	mov	dx,cs:exeldr_pspseg
	mov	si,es:[0ch] ;maximum paras needed
	add	si,cs:exeldr_exelen
	jc	@@1b
	cmp	si,bx
	jb	@@1
@@1b:	mov	si,bx
@@1:	mov	ax,es:[0ah] ;minimum paras needed
	add	ax,cs:exeldr_exelen
	cmp	si,ax
	jb	@@badexe2
	add	si,dx
	mov	cs:exeldr_pspsi,si
	
	;load exe data
	mov	si,cs:exeldr_exelen
	mov	bp,cs:exeldr_pspseg
	mov	di,100h
@@4:	mov	cx,si
	cmp	cx,1024
	jb	@@2
	mov	cx,1024
@@2:	push	cx
	shl	cx,4
	mov	ax,cs:exeldr_handle
	mov	es,bp
	call	readfile
	pop	cx
	add	bp,cx
	sub	si,cx
	jz	@@3
	jnc	@@4
@@3:
	;do relocations
	mov	dx,cs:exeldr_base
	mov	ds,cs:exeldr_hdrseg
	mov	si,ds:[18h] ;offset to first relocation item
	mov	cx,ds:[6h] ;number of reloc items
	jcxz	@@7
@@5:	mov	di,ds:[si]
	mov	ax,ds:[si+2]
	add	ax,dx
	mov	es,ax
	add	es:[di],dx
	add	si,4
	loop	@@5
@@7:
	;free hdr data
	mov	ax,cs:exeldr_hdrseg
	call	freemem
	
	mov	cs:exeldr_oktorun,1
	ret
@@badexe:
	mov	ax,6
	call	fatalerror
	ret
@@badexe2:
	mov	ax,7
	call	fatalerror
	ret
loadexeboth ENDP

;°°°°°°°°°°°°°°°° runexe °°°°°°°°°°°°°°°°
;entry:	(exeldr_* variables)
; exit: -
;saves: none
;descr: runs the exe file loaded previously with loadexe. 
;       returns after exe executed, and frees the memory
;	it uses.
runexe	PROC NEAR
	cmp	cs:exeldr_oktorun,0
	jne	@@0
	ret
@@0:	
	mov	cs:exeldr_ownss,ss
	mov	cs:exeldr_ownsp,sp

	mov	si,cs:exeldr_pspsi
	mov	dx,cs:exeldr_pspseg
	mov	ah,55h
	int	21h ;create psp

	mov	ds,cs:exeldr_pspseg
	mov	bx,cs:exeldr_ownpsp
	mov	ds:[16h],bx ;parents address
	mov	word ptr ds:[0ah],OFFSET @@return
	mov	ds:[0ch],cs ;terminate address

	mov	ah,50h
	mov	bx,cs:exeldr_pspseg
	int	21h

	cli
	mov	ax,cs:exeldr_cs
	add	ax,cs:exeldr_base
	mov	word ptr cs:@@fjmp[3],ax
	mov	ax,cs:exeldr_ip
	mov	word ptr cs:@@fjmp[1],ax
	mov	ax,cs:exeldr_ss
	add	ax,cs:exeldr_base
	mov	ss,ax
	mov	sp,cs:exeldr_sp
	xor	ax,ax
	push	ax
	xor	bx,bx
	mov	cx,0ffh
	mov	dx,cs:exeldr_pspseg
	mov	ds,dx
	mov	es,dx
	mov	bp,0fcfch ;in dos, ?
	mov	si,0fcfch ;in dos, ?
	mov	di,010h
	sti
@@fjmp:	db	0eah,0,0,0,0 ;run exe (far jmp)
	
@@return: ;returns here after int 4c00h
	cli
	mov	ss,cs:exeldr_ownss
	mov	sp,cs:exeldr_ownsp
	sti
	mov	ah,50h
	mov	bx,cs:exeldr_ownpsp
	int	21h
	;free memory
	mov	ax,cs:exeldr_pspseg
	call	freemem
	ret
runexe	ENDP

flash	PROC NEAR
	push	ax
	push	dx
	mov	dx,3dah
	in	al,dx
	mov	dx,3c8h
	xor	al,al
	out	dx,al
	mov	al,ah
	out	dx,al
	xor	al,al
	out	dx,al
	out	dx,al
	pop	dx
	pop	ax
	ret
flash	ENDP

;°°°°°°°°°°°°°°°° execute °°°°°°°°°°°°°°°°
;entry:	DS:SI=offset to filename
; exit: -
;saves: none
;descr: executes the selected exe file. Returns after it has terminates.
execute PROC NEAR
	cld
	IF TESTF
	mov	ah,63
	call	flash
	ENDIF
	call	openfile
	cmp	ax,-1
	je	@@err
	push	ax
	call	loadexe
	pop	ax
	call	closefile
	IF TESTF
	mov	ah,0
	call	flash
	ENDIF
	call	runexe
	IF TESTF
	mov	ah,32
	call	flash
	ENDIF
@@err:	ret
execute	ENDP

;°°°°°°°°°°°°°°°° executehigh °°°°°°°°°°°°°°°°
;entry:	DS:SI=offset to filename
; exit: -
;saves: none
;descr: executes the selected exe file. Returns after it has terminates.
;	The difference to normal execute is, that the exe is loaded to
;	as high in memory as minparasneeded allows. Used for loading
;	music loaders and stuff.
executehigh PROC NEAR
	cld
	call	openfile
	push	ax
	call	loadexehigh
	pop	ax
	call	closefile
	call	runexe
	ret
executehigh ENDP

;°°°°°°°°°°°°°°°° flushkbd °°°°°°°°°°°°°°°°
flushkbd PROC NEAR
	mov	cx,256
@@2:	mov	ah,1
	int	16h
	jz	@@1
	mov	ah,0
	int	16h
	loop	@@2
@@1:	ret
flushkbd ENDP

;ħħħħħħħħħħħħħħħħħħħħ Misc utils ħħħħħħħħħħħħħħħħħħ
;all misc utils preserve all regs except ones in which values are returned
;these routines are not optimized for optimum performance, but are easy to use

;entry:	DS:SI=string
; exit:	AX=length
strlen	PROC NEAR
	xor	ax,ax
	push	si
@@2:	cmp	byte ptr ds:[si],0
	je	@@1
	inc	ax
	inc	si
	jmp	@@2
@@1:	pop	si
	ret
strlen	ENDP

;entry:	DS:SI=source, ES:DI=destination, CX=bytes to copy
; exit:	-
memcpy	PROC NEAR
	push	si
	push	di
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb
	pop	di
	pop	si
	ret
memcpy	ENDP

;entry:	DS:SI=source, ES:DI=destination (byte copied=length of source (strlen)
; exit:	-
strcpy	PROC NEAR
	push	si
	push	di
	push	ax
	call	strlen
	mov	cx,ax
	shr	cx,1
	rep	movsw
	adc	cx,cx
	rep	movsb
	pop	ax
	pop	di
	pop	si
	ret
strcpy	ENDP

;ħħħħħħħħħħħħħħħħħħħħ File system ħħħħħħħħħħħħħħħħħħ

ALIGN 16
file_oldint dd	0
keyb_oldint dd	0
keyb9_oldint dd	0

file_setint PROC NEAR
	xor	ax,ax
	mov	ds,ax
	mov	ax,word ptr ds:[021h*4+0]
	mov	bx,word ptr ds:[021h*4+2]
	mov	word ptr cs:file_oldint[0],ax
	mov	word ptr cs:file_oldint[2],bx
	mov	word ptr ds:[021h*4+0],OFFSET file_int
	mov	word ptr ds:[021h*4+2],cs
	mov	ax,word ptr ds:[016h*4+0]
	mov	bx,word ptr ds:[016h*4+2]
	mov	word ptr cs:keyb_oldint[0],ax
	mov	word ptr cs:keyb_oldint[2],bx
	mov	word ptr ds:[016h*4+0],OFFSET keyb_int
	mov	word ptr ds:[016h*4+2],cs
	mov	word ptr ds:[03h*4+0],OFFSET just_iret
	mov	word ptr ds:[03h*4+2],cs
        IF FINAL AND NOT KEYBON
	mov	ax,word ptr ds:[09h*4+0]
	mov	bx,word ptr ds:[09h*4+2]
	mov	word ptr cs:keyb9_oldint[0],ax
	mov	word ptr cs:keyb9_oldint[2],bx
	mov	word ptr ds:[09h*4+0],OFFSET keyb9_int
	mov	word ptr ds:[09h*4+2],cs
	mov	word ptr ds:[417h],0
        ENDIF
	ret
file_setint ENDP

file_resetint PROC NEAR
	xor	ax,ax
	mov	ds,ax
	mov	ax,word ptr cs:file_oldint[0]
	mov	bx,word ptr cs:file_oldint[2]
	mov	word ptr ds:[021h*4+0],ax
	mov	word ptr ds:[021h*4+2],bx
	mov	ax,word ptr cs:keyb_oldint[0]
	mov	bx,word ptr cs:keyb_oldint[2]
	mov	word ptr ds:[016h*4+0],ax
	mov	word ptr ds:[016h*4+2],bx
	IF FINAL
	mov	ax,word ptr cs:keyb9_oldint[0]
	mov	bx,word ptr cs:keyb9_oldint[2]
	mov	word ptr ds:[09h*4+0],ax
	mov	word ptr ds:[09h*4+2],bx
	ENDIF
	ret
file_resetint ENDP

chk1	db	'SECOND.EXE',0
chk2	db	'REALITY.FC',0
dummy	db	16 dup(0fch)

file_checkfiles PROC NEAR
	xor	ax,ax
	mov	ds,ax
	mov	cx,ds:[46ch]
	and	cx,15
	inc	cx
@@aga:	push	cx
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET chk1
	mov	ax,3d00h
	int	21h
	jc	@@err
	mov	bx,ax
	mov	ax,3e00h
	int	21h
	mov	dx,OFFSET chk2
	mov	ax,3d00h
	int	21h
	jc	@@err
	mov	bx,ax
	mov	ax,3f00h
	mov	cx,16
	mov	dx,OFFSET dummy
	int	21h
	mov	ax,3e00h
	int	21h
	pop	cx
	loop	@@aga
	ret
@@err:	pop	cx
	mov	cs:errorcode,7
	ret
file_checkfiles ENDP

exe_path db	'SECOND.EXE',0
	db	64 dup(0)
secondpath db	'SECOND.EXE',0
exe_base dd	0
exe_signature dw 0
seek_base dd	0
seek_end dd	0
seek_special dw	0

file_path dw	OFFSET file_name-5
	db	100 dup(0)
	db	'DATA\'
file_name db	32 dup(0),0
file_acc dw	0

keyb_int PROC FAR ;interrupt 016h server
	call	forcebreakcheck
	jmp	cs:keyb_oldint
keyb_int ENDP

keyb9_int PROC FAR ;interrupt 09h server
	cmp	cs:normalkbd,0
	jne	@@1
	push	ax
	in	al,60h
	cmp	al,1
	jne	@@2
	mov	cs:ctrlwasdown,1
@@2:
        in      al,61h
        mov     ah,al
        or      al,80h
        out     61h,al
        xchg    ah,al
        out     61h,al

	mov	al,20h
	out	20h,al
	pop	ax
just_iret:
	iret
@@1:	jmp	cs:keyb9_oldint
keyb9_int ENDP

	db	'INTT'
ALIGN 16
inttable LABEL BYTE
	db	256 dup(0)
	
ALIGN 2
read_poslow dw	0
read_adr dw	0
read_cnt dw	0
read_buf dw	0,0

file_int PROC FAR ;interrupt 021h server
	sti
	
	IF DEBUG
	push	bx
	mov	bl,ah
	xor	bh,bh
	or	cs:inttable[bx],1
	pop	bx
	ENDIF

	cmp	ah,42h ;seek file
	je	@@s
	cmp	ah,3dh ;open file
	je	@@1
	cmp	ah,3fh ;read file
	je	@@rr
	cmp	ah,30h ;version
	je	@@xit
IF DEBUG
	cmp	ah,48h ;alloc
	je	@@mem
ENDIF
@@nn:	jmp	cs:file_oldint
@@xit:	mov	al,5
	mov	ah,0
	iret

IF DEBUG	
@@mem:	cmp	bx,0ffffh
	je	@@nn
	pushf
	call	cs:file_oldint
	call	recheckmem
	ret	2
ENDIF

@@rr:	cmp	cs:seek_special,0
	je	@@nn
	push	ax
	push	cx
	push	dx
	mov	ax,4201h
	mov	cx,0
	mov	dx,0
	pushf	
	call	cs:file_oldint
	mov	cs:read_poslow,ax
	pop	dx
	pop	cx
	pop	ax
	mov	cs:read_buf[0],dx
	mov	cs:read_buf[2],ds
	mov	cs:read_cnt,cx
	pushf
	call	cs:file_oldint
	pusha
	push	ds
	mov	ax,cs:read_poslow
	mov	bx,cs:read_adr
	mul	bx
	lds	si,dword ptr cs:read_buf
	mov	cx,cs:read_cnt
	mov	dl,0ffh
@@rr1:	cmp	ax,0f000h
	jae	@@rr2
	xor	ds:[si],dl
@@rr2:	inc	si
	add	ax,bx
	dec	cx
	jnz	@@rr1
	pop	ds
	popa
	clc ;no errors, sure :-)
	ret 	2

@@s:	cmp	cs:seek_special,0
	je	@@nn
	push	cx
	cmp	al,1 ;current
	je	@@sgo
	cmp	al,0
	jne	@@sm1
	add	dx,word ptr cs:seek_base[0]
	adc	cx,word ptr cs:seek_base[2]
@@sm1:	cmp	al,2
	jne	@@sm2
	add	dx,word ptr cs:seek_end[0]
	adc	cx,word ptr cs:seek_end[2]
@@sm2:	mov	ax,4200h
@@sgo:	pushf
	call	cs:file_oldint
	sub	ax,word ptr cs:seek_base[0]
	sbb	dx,word ptr cs:seek_base[2]
	pop	cx
	ret	2
	
@@1:	;special open?
	push	bx
	mov	bx,dx
	cmp	byte ptr ds:[bx],'*'
	jne	@@nosp
	;remove '*', use normal dos open
	inc	dx
	pop	bx
	jmp	cs:file_oldint
@@nosp: pop	bx
	;
	cmp	al,1
	je	@@nn ;writemode normally
	push	bx
	push	dx
	push	ds
	mov	cs:seek_base,0
	mov	cs:file_acc,ax
	cmp	cs:exe_signature,0fc0h
	je	@@p
@@try:	mov	cs:seek_special,0
	mov	bx,dx
	pushf
	call	cs:file_oldint
	jnc	@@3
	zzz=0
	REPT	32/2
	mov	ax,ds:[bx+zzz]
	mov	word ptr cs:file_name[zzz],ax
	zzz=zzz+2
	ENDM
	mov	ax,cs
	mov	ds,ax
	mov	dx,cs:file_path
	mov	ax,cs:file_acc
	pushf
	call	cs:file_oldint
	jnc	@@3
	pop	ds
	pop	dx
	pop	bx
	
	push	cx
	push	dx
	mov	cx,cs:file_path
	mov	dx,cs
	mov	ax,9+100h
	call	fatalerror
	pop	dx
	pop	cx
	
	mov	ax,2
	stc
	ret	2

@@3:	pop	ds
	pop	dx
	pop	bx
	ret	2
	
@@p:	mov	cs:seek_special,1
	;packed file, process
	;calculate checksums
	push	si
	push	di
	mov	si,dx
	xor	ah,ah
	mov	cx,1111h
	mov	dx,1111h
@@p2:	mov	al,ds:[si]
	or	al,al
	jz	@@p1
	and	al,not 20h
	xor	cx,ax
	rol	cx,1
	add	dx,ax
	inc	si
	jmp	@@p2
@@p1:	mov	si,cx
	mov	di,dx
	;seek list
	mov	bx,OFFSET filedir
	mov	cx,cs:[bx]
	jcxz	@@p4
	add	bx,2
@@p5:	cmp	cs:[bx+2],si
	jne	@@p6
	cmp	cs:[bx+6],di
	je	@@p3
@@p6:	add	bx,12
	loop	@@p5
@@p4:	pop	di
	pop	si
	pop	ds
	pop	dx
	pop	bx
	mov	ax,cs:file_acc
	push	bx
	push	dx
	push	ds
	jmp	@@try
@@p3:	;found!
	mov	dx,cs:[bx+2]
	add	dx,cs:[bx+6]
	mov	cs:read_adr,dx
	mov	dx,cs:[bx+0]
	mov	cx,cs:[bx+4]
	add	dx,word ptr cs:exe_base[0]
	adc	cx,word ptr cs:exe_base[2]
	mov	word ptr cs:seek_base[0],dx
	mov	word ptr cs:seek_base[2],cx
	push	cx
	push	dx
	add	dx,cs:[bx+8]
	adc	cx,cs:[bx+10]
	mov	word ptr cs:seek_end[0],dx
	mov	word ptr cs:seek_end[2],cx
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET exe_path
	mov	ax,3d00h
	pushf
	call	cs:file_oldint
	pop	dx
	pop	cx
	push	ax
	mov	bx,ax
	mov	ax,4200h
	pushf
	call	cs:file_oldint
	pop	ax
	pop	di
	pop	si
	pop	ds
	pop	dx
	pop	bx
	ret	2
file_int ENDP

;entry: DS=PSP
file_getexepath PROC NEAR
	ret
	mov	ax,ds:[2ch]
	mov	ds,ax ;ds=enviroment
	xor	si,si
	xor	ax,ax
	mov	cx,4096
@@1:	cmp	ds:[si],ax
	je	@@2
	inc	si
	loop	@@1
	ret
@@2:	add	si,4
	mov	ax,cs
	mov	es,ax
	call	strlen
	mov	di,OFFSET exe_path
	mov	cx,64
	call	memcpy
	push	si
	add	si,ax
	inc	ax
@@3:	dec	si
	dec	ax
	cmp	byte ptr ds:[si],'\'
	jne	@@3
	pop	si
	mov	di,OFFSET file_name-5 ;leave DATA\
	sub	di,ax
	mov	cs:file_path,di
	mov	cx,ax
	call	memcpy
	ret
file_getexepath ENDP

file_initpacking PROC NEAR
	mov	ax,cs
	mov	ds,ax
	mov	dx,OFFSET exe_path
	mov	ax,3d00h
	int	21h
	mov	bx,ax
	jc	@@err
	mov	ax,4202h
	mov	cx,-1
	mov	dx,-4
	int	21h
	jc	@@err
	mov	ah,3fh
	mov	cx,4
	mov	dx,OFFSET exe_base
	int	21h
	jc	@@err
	xor	dword ptr ds:exe_base,012345678h
	mov	ax,4200h
	mov	cx,word ptr ds:exe_base[2]
	mov	dx,word ptr ds:exe_base[0]
	int	21h
	jc	@@err
	mov	ah,3fh
	mov	cx,2
	mov	dx,OFFSET exe_signature
	int	21h
	jc	@@err
	mov	ax,ds:exe_signature
	add	dword ptr ds:exe_base,2
	ret
@@err:	mov	ax,8
	call	fatalerror
	ret
file_initpacking ENDP

;ħħħħħħħħħħħħħħħħ ħħħħħħħħħħħħħħħħ

inittwk PROC FAR
	push	bp
	mov	bp,sp
	push	si
	push	di
	push	ds
	;clear palette
;	mov	dx,3c8h
;	xor	al,al
;	out	dx,al
;	inc	dx
;	mov	cx,768
;@@1:	out	dx,al
;	loop	@@1
	;400 rows
	mov	dx,3d4h
	mov	ax,00009h
	out	dx,ax
	;tweak
	mov	dx,3d4h
	mov	ax,00014h
	out	dx,ax
	mov	ax,0e317h
	out	dx,ax
	mov	dx,3c4h
	mov	ax,0604h
	out	dx,ax
	;
	mov	dx,3c4h
	mov	ax,0f02h
	out	dx,ax
	mov	ax,0a000h
	mov	es,ax
	xor	di,di
	mov	cx,32768
	xor	ax,ax
	rep	stosw
	;
	pop	ds
	pop	di
	pop	si
	pop	bp
	ret
inittwk ENDP

;ħħħħħħħħħħħħħħħħ ħħħħħħħħħħħħħħħħ

