[comp.sources.games] v08i055: NetHack3 - display oriented dungeons & dragons

billr@saab.CNA.TEK.COM (Bill Randle) (11/23/89)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 8, Issue 55
Archive-name: NetHack3/Patch6b
Patch-To: NetHack3: Volume 7, Issue 56-93



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 15)."
# Contents:  patches06d
# Wrapped by billr@saab on Wed Nov 22 10:50:06 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'patches06d' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patches06d'\"
else
echo shar: Extracting \"'patches06d'\" \(58568 characters\)
sed "s/^X//" >'patches06d' <<'END_OF_FILE'
X*** /dev/null	Sun Nov 19 14:15:21 1989
X--- others/ovlmgr.asm	Sat Nov 18 17:17:30 1989
X***************
X*** 0 ****
X--- 1,1179 ----
X+ ;	SCCS Id: @(#)ovlmgr.asm 	3.0	89/11/16
X+ ;  Copyright (c) Pierre Martineau and Stephen Spackman, 1989.
X+ ;  This product may be freely redistributed.  See NetHack license for details.
X+ 
X+ 		PAGE	60,132
X+ 		TITLE	'Overlay manager for use with Microsoft overlay linker'
X+ 		SUBTTL	'Brought to you by Pierre Martineau and Stephen Spackman'
X+ 
X+ ; acknowledgements:   - No thanks to Microsoft
X+ ;		      - alltrsidsctysti!!!
X+ ;		      - izchak and friends for impetus
X+ ;		      - us for brilliance
X+ ;		      - coffee for speed
X+ ;		      - others as necessary
X+ 
X+ ; assumptions:	      - all registers are preserved including flags
X+ ;		      - the stack is preserved
X+ ;		      - re-entrancy is not required
X+ 
X+ DOSALLOC	equ	48h			; memory allocation
X+ DOSFREE 	equ	49h			; free allocated memory
X+ DOSREALLOC	equ	4ah			; modify memory block
X+ DOSREAD 	equ	3fh			; read bytes from handle
X+ DOSSEEK 	equ	42h			; logical handle seek
X+ DOSOPEN 	equ	3dh			; open handle
X+ DOSCLOSE	equ	3eh			; close handle
X+ DOSGETVEC	equ	35h			; get interrupt vector
X+ DOSSETVEC	equ	25h			; set interrupt vector
X+ DOSEXEC 	equ	4bh			; exec child process
X+ DOS		equ	21h			; Dos interrupt #
X+ PRINT		equ	09h			; print string
X+ TERMINATE	equ	4ch			; terminate process
X+ CR		equ	0dh
X+ LF		equ	0ah
X+ BELL		equ	07h
X+ FAERIE		equ	0h			; Used for dummy segment allocation
X+ PARSIZ		equ	10h			; this is the size of a paragraph - this better not change!
X+ 
X+ ; The following extrns are supplied by the linker
X+ 
X+ extrn		$$OVLBASE:byte			; segment of OVERLAY_AREA
X+ extrn		$$MPGSNOVL:byte 		; ^ to module table
X+ extrn		$$MPGSNBASE:word		; ^ to module segment fixups
X+ extrn		$$INTNO:byte			; interrupt number to be used
X+ extrn		$$COVL:word			; number of physical overlays
X+ extrn		$$CGSN:word			; number of modules
X+ extrn		$$MAIN:far			; ^ to function main()
X+ 
X+ public		$$OVLINIT			; Our entry point
X+ 						; called by the c startup code
X+ 
X+ ovlflgrec	record	running:1=0,locked:1=0,loaded:1=0 ; overlay flags
X+ 
X+ ; This is a dirty hack. What we need is a virtual segment that will be built
X+ ; by the (our) loader in multiple copies, one per overlay. Unfortunately, this
X+ ; doesn't seem to be a sensible idea in the minds of the folks at Microsoft.
X+ ; Declaring this segment AT will ensure that it never appears in the exefile,
X+ ; and ASSUME is dumb enough to be fooled.
X+ ;
X+ ; The reason we want to do this is also not-to-be-tried-at-home: it turns out
X+ ; that we can code a faster interrupt handler if we map overlay numbers to
X+ ; segment values. Normally I would consider this unacceptable programming
X+ ; practise because it is 86-mode specific, but the *need* for this entire
X+ ; programme is 86-mode specific, anyway.
X+ 
X+ pspseg		segment para at FAERIE		; dummy segment for psp
X+ 		org	2ch			; ^ to segment of environmemt in psp
X+ pspenv		LABEL	WORD
X+ pspseg		ends
X+ 
X+ ovltbl		segment para at FAERIE		; Dummy segment definition for overlay table
X+ 
X+ ; NOTE: This segment definition MUST be exactly 16 bytes long
X+ 
X+ ovlflg		ovlflgrec	<0,0,0> 	; overlay flags
X+ ovltblpad1	db	?			; go ahead, delete me!
X+ ovlmemblk	dw	?			; ^ to allocated memory block
X+ ovlseg		dw	0			; ovl segment physical add.
X+ ovlfiloff	dw	?			; ovl file offset in pages (512 bytes)
X+ ovlsiz		dw	?			; ovl size in paragraphs
X+ ovllrudat	dd	0			; misc lru data (pseudo time stamp)
X+ ovltblpad2	dw	?			; go ahead, delete me!
X+ 
X+ if1
X+ if		$ gt PARSIZ
X+ 		.err
X+ 		%out This segment MUST be no more than 16 bytes, REALLY!!!
X+ endif
X+ endif
X+ 
X+ ovlsegsiz	equ	PARSIZ			; this had better be true!!! (16 bytes)
X+ 
X+ ovltbl		ends
X+ 
X+ EXEHDR		struc				; structure of an EXE header
X+ exesign 	dw	5a4dh			; signature
X+ exelstpgesiz	dw	?			; last page size (512 byte pages)
X+ exesiz		dw	?			; total pages (including partial last page)
X+ relocitems	dw	?			; number of relocation entries
X+ hdrparas	dw	?			; number of paragraphs in the header
X+ minalloc	dw	?			; minimum paragraph allocation
X+ maxalloc	dw	?			; maximum patagraph allocation
X+ exess		dw	?			; initial stack segment
X+ exesp		dw	?			; initial stack pointer
X+ exechksum	dw	?			; checksum
X+ exeip		dw	?			; initial instruction pointer
X+ execs		dw	?			; initial code segment
X+ reloctbloff	dw	?			; offset from beginning of header to relocation table
X+ exeovlnum	dw	?			; overlay number
X+ EXEHDR		ends
X+ 
X+ MASK_used	equ	1			; memory block flag
X+ 
X+ memctlblk	struc				; memory block structure
X+ memblkflg	db	0			; flags
X+ memblkpad1	db	0			; go ahead, delete me!
X+ memblknxt	dw	0			; ^ to next block
X+ memblkprv	dw	0			; ^ to previous block
X+ memblkovl	dw	0			; ^ to overlay occupying this block
X+ memblksiz	dw	0			; size in paragraphs
X+ memblkpad	db	PARSIZ - ($ - memblkflg) mod parsiz dup (?) ; pad to 16 bytes
X+ memctlblk	ends
X+ 
X+ memctlblksiz	equ	memblkpad + SIZE memblkpad ; should equal 1 paragraph (16 bytes)
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ code		segment public
X+ 
X+ ovlexefilhdl	dw	-1			; always-open file handle of our .EXE
X+ ovltim		dd	0			; pseudo-lru time variable
X+ curovl		dw	offset framestk 	; ^ into stack frame
X+ ovlcnt		dw	0			; # overlays
X+ modcnt		dw	0			; # of modules
X+ ovltblbse	dw	-1			; segment of first overlay descriptor
X+ ovlrootcode	dw	0			; logical segment of OVERLAY_AREA
X+ ovldata 	dw	0			; logical segment of OVERLAY_END
X+ memblk1st	dw	0			; first memory block
X+ pspadd		dw	0			; our psp address + 10h (for relocations)
X+ oldvec		dd	-1			; saved interrupt vector
X+ oldint21	dd	-1			; saved int 21 vector
X+ memstat 	db	0ffh			; must we re-allocate some memory
X+ bxreg		dw	0			; temp save area
X+ esreg		dw	0			; temp save area
X+ farcall 	dd	0			; internal trampoline.
X+ hdr		EXEHDR	<>			; EXE header work area
X+ hdrsize 	equ	$ - hdr
X+ 
X+ framestk	dw	100h dup (0)		; internal stack
X+ 
X+ moduletbl	dw	256*2 dup (0)		; module lookup table
X+ 
X+ noroom		db	CR,LF,'Not enough memory to run this program.  Time to go to the store.',CR,LF,BELL,'$'
X+ nocore		db	CR,LF,'Your dog eats all your remaining memory!  You die.',CR,LF,BELL,'$'
X+ nofile		db	CR,LF,'The Nymph stole your .EXE file!  You die.',CR,LF,BELL,'$'
X+ exitmsg 	db	CR,LF,'$'
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ $$OVLINIT	proc	far			; Init entry point
X+ 
X+ 		assume	cs:code,ds:pspseg,es:nothing
X+ 
X+ 		push	ax
X+ 		push	bx
X+ 		push	cx
X+ 		push	dx
X+ 		push	si
X+ 		push	di
X+ 		push	bp
X+ 		push	ds
X+ 		push	es			; save the world
X+ 		mov	ax,ds			; get our psp
X+ 		add	ax,10h
X+ 		mov	pspadd,ax		; save it
X+ 		mov	ds,pspenv		; get environment segment
X+ 		mov	si,-1
X+ envloop:					; search for end of environment
X+ 		inc	si
X+ 		cmp	word ptr [si],0
X+ 		jnz	envloop
X+ 		add	si,4			; point to EXE filename
X+ 		mov	al,0			; access code
X+ 		mov	ah,DOSOPEN
X+ 		mov	dx,si
X+ 		int	DOS			; open EXE
X+ 		jnc	dontdie
X+ 		mov	al,5
X+ 		mov	dx,offset nofile
X+ 		jmp	putserr 		; cry to the world!
X+ dontdie:
X+ 		mov	ovlexefilhdl,ax 	; save handle
X+ 		mov	ax,SEG $$OVLBASE	; OVERLAY_AREA segment
X+ 		mov	ovlrootcode,ax
X+ 
X+ ; Now allocate memory
X+ 		mov	bx,0900h		; allocate memory for malloc()
X+ 		mov	ah,DOSALLOC
X+ 		int	DOS
X+ 		jnc	getmore
X+ 		jmp	buyram
X+ getmore:
X+ 		mov	es,ax			; find largest free memory
X+ 		mov	ah,DOSALLOC
X+ 		mov	bx,0ffffh		; Everything
X+ 		int	DOS
X+ 		mov	ah,DOSALLOC		; allocate our own memory
X+ 		int	DOS
X+ 		jnc	gotitall
X+ 		jmp	buyram
X+ gotitall:
X+ 		mov	memstat,0		; indicate that we have memory
X+ 		mov	ovltblbse,ax		; overlay descriptor table begins at start of memory block
X+ 		mov	ax,SEG $$COVL		; segment of DGROUP
X+ 		mov	ds,ax
X+ 		mov	cx,$$CGSN		; number of modules
X+ 		mov	modcnt,cx		; save for later use
X+ 		mov	cx,$$COVL		; number of physical overlays
X+ 		mov	ovlcnt,cx		; save for later use
X+ 		sub	bx,cx			; enough mem for ovl tbl?
X+ 		jnc	memloop
X+ 		jmp	buyram
X+ memloop:
X+ 		push	bx
X+ 		mov	ah,DOSFREE		; free first block for malloc()
X+ 		int	DOS
X+ 		jnc	cockadoodledoo
X+ 		jmp	buyram
X+ cockadoodledoo:
X+ 
X+ 		assume	es:ovltbl
X+ 
X+ 		xor	bp,bp
X+ 		xor	di,di
X+ 		xor	si,si
X+ filsegtbllpp:					; initialise ovl table
X+ 		call	gethdr			; get an EXE header
X+ 		mov	ax,ovltblbse
X+ 		add	ax,hdr.exeovlnum
X+ 		mov	es,ax			; ^ to ovl table entry
X+ 		xor	ax,ax
X+ 		mov	word ptr ovllrudat,ax	; initialise ovl lru
X+ 		mov	word ptr ovllrudat+2,ax
X+ 		mov	ovlseg,ax		; initialise ovl segment
X+ 		mov	ovlflg,al		; initialise ovl flags
X+ 		mov	ax,hdr.exesiz
X+ 		shl	ax,1
X+ 		shl	ax,1
X+ 		shl	ax,1
X+ 		shl	ax,1
X+ 		shl	ax,1			; * 32
X+ 		mov	dx,hdr.exelstpgesiz
X+ 		or	dx,dx
X+ 		jz	emptypage
X+ 		shr	dx,1
X+ 		shr	dx,1
X+ 		shr	dx,1
X+ 		shr	dx,1			; / 16
X+ 		inc	dx
X+ 		sub	ax,20h
X+ 		add	ax,dx
X+ emptypage:
X+ 		mov	ovlsiz,ax		; overlay size in paragraphs
X+ 		sub	ax,hdr.hdrparas 	; actual size of code and relocation table
X+ 		cmp	hdr.exeovlnum,0 	; skip if ovl 0 (root code)
X+ 		jz	notlargest
X+ 		cmp	ax,di			; find largest ovl
X+ 		jc	notlargest
X+ 		mov	di,ax
X+ 		mov	si,ovlsiz
X+ notlargest:
X+ 		mov	ovlfiloff,bp		; initialise ovl file offset
X+ 		add	bp,hdr.exesiz		; ^ to next overlay
X+ 		mov	dx,bp
X+ 		mov	cl,dh
X+ 		mov	dh,dl
X+ 		xor	ch,ch
X+ 		xor	dl,dl
X+ 		shl	dx,1
X+ 		rcl	cx,1			; cx:dx = bp * 512
X+ 		mov	al,0
X+ 		mov	ah,DOSSEEK		; seek to next ovl
X+ 		int	DOS
X+ 		mov	ax,ovlcnt
X+ 		dec	ax
X+ 		cmp	ax,hdr.exeovlnum	; all overlays done?
X+ 		jz	makmemblk
X+ 		jmp	filsegtbllpp		; Nope, go for more.
X+ makmemblk:
X+ 		push	si			; contains largest ovl size in paragraphs
X+ 
X+ 		assume	es:nothing		; prepare first two memory blocks
X+ 						; OVERLAY_AREA and allocated memory block
X+ 		mov	ax,ovlrootcode		; OVERLAY_AREA segment
X+ 		mov	es,ax
X+ 		mov	si,ovltblbse
X+ 		add	si,ovlcnt		; end of ovl table
X+ 		mov	es:memblkflg,0		; clear mem flags
X+ 		mov	es:memblknxt,si 	; point to next
X+ 		mov	es:memblkprv,0		; set previous to nothing
X+ 		mov	es:memblksiz,di 	; di contains OVERLAY_AREA size in paragraphs
X+ 		add	di,ax
X+ 		mov	ovldata,di		; end of OVERLAY_END
X+ 		mov	es,si			; end of ovl tbl (first memory block in allocated memory)
X+ 		mov	es:memblkflg,0		; clear mem flags
X+ 		mov	es:memblknxt,0		; set next to nothing
X+ 		mov	es:memblkprv,ax 	; point to previous
X+ 		pop	si
X+ 		pop	bx
X+ 		mov	es:memblksiz,bx 	; allocated memory block size less ovl table
X+ 		mov	memblk1st,ax		; save pointer to first mem block
X+ 		mov	word ptr ovltim,0	; initialise global lru time stamp
X+ 		mov	word ptr ovltim+2,0
X+ 		mov	ax,offset framestk
X+ 		mov	curovl,ax		; initialise stack frame pointer
X+ 		mov	di,ax
X+ 		mov	word ptr cs:[di],-1	; initialise stack frame
X+ 		add	di,6
X+ 		mov	ax,ovltblbse
X+ 		mov	cs:[di],ax
X+ 		mov	curovl,di
X+ 		mov	es,ax
X+ 		mov	es:ovlflg,MASK running OR MASK locked OR MASK loaded ; set flags on ovl 0
X+ 		inc	si			; largest ovl size + 1 paragraph
X+ 		cmp	bx,si			; enough memory to alloc largest?
X+ 		jnc	chgintvec
X+ buyram:
X+ 		mov	al,5
X+ 		mov	dx,OFFSET noroom	; free up some TSRs or something
X+ 		jmp	putserr
X+ chgintvec:
X+ 		mov	ax,SEG $$INTNO
X+ 		mov	ds,ax
X+ 		mov	ah,DOSGETVEC
X+ 		mov	al,$$INTNO		; get int number to use
X+ 		int	DOS			; get original vector
X+ 		mov	word ptr oldvec,bx	; save original vector
X+ 		mov	word ptr oldvec+2,es
X+ 
X+ 		mov	ah,DOSGETVEC
X+ 		mov	al,21h
X+ 		int	DOS			; get original vector
X+ 		mov	word ptr oldint21,bx	; save original vector
X+ 		mov	word ptr oldint21+2,es
X+ 
X+ 		mov	ax,SEG $$INTNO
X+ 		mov	ds,ax
X+ 		mov	ah,DOSSETVEC
X+ 		mov	al,$$INTNO
X+ 		mov	bx,cs
X+ 		mov	ds,bx
X+ 		mov	dx,OFFSET ovlmgr	; point to ovlmgr
X+ 		int	DOS			; set vector
X+ 
X+ 		mov	ah,DOSSETVEC
X+ 		mov	al,21h
X+ 		mov	bx,cs
X+ 		mov	ds,bx
X+ 		mov	dx,OFFSET int21 	; point to int21
X+ 		int	DOS			; set vector
X+ 
X+ 		mov	cx,modcnt		; module count
X+ 		mov	ax,SEG $$MPGSNBASE
X+ 		mov	es,ax
X+ 		mov	ax,cs
X+ 		mov	ds,ax
X+ 
X+ 		assume	ds:code
X+ 
X+ 		mov	bx,offset $$MPGSNBASE	; ^ to linker provided overlay segment fixups
X+ 		mov	si,offset $$MPGSNOVL	; ^ to linker provided module table
X+ 		mov	di,offset moduletbl	; ^ to our module table
X+ modloop:
X+ 		mov	al,es:[si]		; real physical ovl number
X+ 		xor	ah,ah
X+ 		add	ax,ovltblbse		; ovlctlseg address
X+ 		mov	[di],ax 		; save in module table
X+ 		mov	ax,es:[bx]		; get seg fixup
X+ 		sub	ax,ovlrootcode		; adjust for relative reference
X+ 		mov	[di+2],ax		; save in module table
X+ 		add	di,4
X+ 		add	bx,2
X+ 		inc	si
X+ 		loop	modloop
X+ 
X+ 		pop	es
X+ 		pop	ds
X+ 		pop	bp
X+ 		pop	di
X+ 		pop	si
X+ 		pop	dx
X+ 		pop	cx
X+ 		pop	bx
X+ 		pop	ax			; restore the world
X+ 		jmp	$$MAIN			; And away we go!
X+ 
X+ $$OVLINIT	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ ovlmgr		proc	far			; This the it!
X+ 
X+ 		assume cs:code,ds:nothing,es:nothing
X+ 
X+ 		mov	bxreg,bx		; preserve bx
X+ 		mov	esreg,es		; and es
X+ 		pop	bx			; retrieve caller ip
X+ 		pop	es			;     "      "    cs
X+ 		push	ax
X+ 		push	si
X+ 		mov	ax,es:[bx+1]		; offset in ovl to call
X+ 		mov	word ptr farcall,ax	; into trampoline
X+ 		xor	ah,ah
X+ 		mov	al,es:[bx]		; module # to call
X+ 		add	bx,3			; fix return address
X+ 		mov	si,curovl		; get stack frame pointer
X+ 		mov	cs:[si+2],es		; save return seg
X+ 		mov	cs:[si+4],bx		; and return offset
X+ 
X+ 		mov	bx,ax
X+ 		shl	bx,1
X+ 		shl	bx,1			; * 4 (2 words/entry in module tbl)
X+ 		add	bx,offset moduletbl
X+ 		mov	es,cs:[bx]		; ovl tbl entry
X+ 		mov	ax,cs:[bx+2]		; segment fixup
X+ 		mov	cs:[si+6],es		; ovl entry into stack frame
X+ 		add	curovl,6		; update stack
X+ 
X+ 		assume	es:ovltbl
X+ 
X+ 		mov	si,WORD PTR ovltim	; lru time stamp
X+ 		inc	si			; time passes!
X+ 		mov	WORD PTR ovltim,si	; update global clock
X+ 		mov	WORD PTR ovllrudat,si	; as well as ovl clock
X+ 		jz	ininc			; dword increment
X+ cryupcdon:	test	ovlflg,mask loaded	; ovl loaded?
X+ 		jz	inload			; load it then.
X+ ovlloadedupc:
X+ 		add	ax,ovlseg		; add fixup and segment address
X+ 		mov	word ptr farcall+2,ax	; into trampoline
X+ 		mov	bx,bxreg		; retore all registers
X+ 		mov	es,esreg
X+ 		pop	si
X+ 		pop	ax
X+ 		popf				; don't forget these!
X+ 		call	DWORD PTR farcall	; and GO
X+ 		pushf				; preserve registers again!
X+ 		mov	esreg,es
X+ 		mov	bxreg,bx
X+ 		mov	bx,curovl		; stack frame pointer
X+ 		mov	es,cs:[bx-6]		; retrieve ovl tbl entry
X+ 		push	cs:[bx-4]		; set return address
X+ 		push	cs:[bx-2]
X+ 		push	cx
X+ 		mov	cx,WORD PTR ovltim	; do the lru thing again
X+ 		inc	cx
X+ 		mov	WORD PTR ovltim,cx
X+ 		mov	WORD PTR ovllrudat,cx
X+ 		jz	outinc
X+ crydncdon:	test	ovlflg,mask loaded	; ovl loaded?
X+ 		jz	outload 		; better get it before someone notices
X+ jmpback:
X+ 		sub	curovl,6		; adjust stack
X+ 		mov	bx,bxreg		; get registers back
X+ 		mov	es,esreg
X+ 		pop	cx
X+ 		iret				; and GO back
X+ 
X+ ininc:
X+ 		mov	si,WORD PTR ovltim+2	; high word of lru
X+ 		inc	si
X+ 		mov	WORD PTR ovltim+2,si	; update global and
X+ 		mov	WORD PTR ovllrudat+2,si ; ovl clocks
X+ 		jmp	cryupcdon
X+ 
X+ inload:
X+ 		call	loadoverlay		; self explanatory
X+ 		jmp	ovlloadedupc
X+ 
X+ outinc:
X+ 		mov	cx,WORD PTR ovltim+2
X+ 		inc	cx
X+ 		mov	WORD PTR ovltim+2,cx
X+ 		mov	WORD PTR ovllrudat+2,cx
X+ 		jmp	crydncdon
X+ 
X+ outload:
X+ 		call	loadoverlay
X+ 		jmp	jmpback
X+ 
X+ ovlmgr		endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ loadoverlay	proc	near			; load overlay pointed to by es
X+ 
X+ 		assume	cs:code,ds:nothing,es:ovltbl
X+ 
X+ 		push	ax
X+ 		push	bx
X+ 		push	cx
X+ 		push	dx
X+ 		push	si
X+ 		push	di
X+ 		push	bp
X+ 		push	ds
X+ 		push	es			; just in case
X+ 		cmp	memstat,0
X+ 		jz	dontrealloc
X+ 		call	reallocmem
X+ dontrealloc:
X+ 		call	setrunning		; set the running flags
X+ 		test	ovlflg,MASK running	; was it already running?
X+ 		jnz	fxdadr			; Yup, it's a toughie
X+ 		mov	ax,ovlsiz		; How much?
X+ 		call	getpages		; never fail mem alloc, you bet.
X+ 		jmp	gleaner
X+ fxdadr:
X+ 		call	releasepages		; free memory where this ovl should be loaded
X+ gleaner:
X+ 		mov	ovlmemblk,ax		; memory block to use
X+ 		add	ax,memctlblksiz / PARSIZ; skip mem ctl blk
X+ 		mov	ds,ax
X+ 		mov	dx,ovlfiloff		; where in the file is it?
X+ 		mov	cl,dh
X+ 		mov	dh,dl
X+ 		xor	ch,ch
X+ 		xor	dl,dl
X+ 		shl	dx,1
X+ 		rcl	cx,1			; cx:dx = dx * 512
X+ 		mov	ah,DOSSEEK		; lseek to position
X+ 		mov	al,0
X+ 		mov	bx,ovlexefilhdl 	; never closing handle
X+ 		int	DOS
X+ 		jc	burnhead		; oops!
X+ 		xor	dx,dx
X+ 		mov	cx,ovlsiz		; number of paragraphs to load
X+ 		shl	cx,1
X+ 		shl	cx,1
X+ 		shl	cx,1
X+ 		shl	cx,1			; * 16 = number of bytes
X+ 		mov	ah,DOSREAD		; prevent random DOS behaviour
X+ 		int	DOS
X+ 		jc	burnhead		; double oops!
X+ 		call	ovlrlc			; perform relocation normally done by DOS EXE loader
X+ 		pop	es			; retrieve ovl tbl entry
X+ 		or	ovlflg,MASK loaded	; because it is now
X+ 		pop	ds
X+ 		pop	bp
X+ 		pop	di
X+ 		pop	si
X+ 		pop	dx
X+ 		pop	cx
X+ 		pop	bx
X+ 		pop	ax
X+ 		ret
X+ 
X+ burnhead:
X+ 		mov	al,5
X+ 		mov	dx,offset nofile
X+ 		jmp	putserr
X+ 
X+ loadoverlay	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ ovlrlc		proc	near			; ds:0 -> the overlay to relocate
X+ 
X+ 		assume	cs:code,ds:nothing,es:ovltbl
X+ 
X+ 		mov	cx,ds:relocitems	; roto-count
X+ 		mov	ax,ds
X+ 		add	ax,ds:hdrparas		; skip header
X+ 		mov	ovlseg,ax		; actual code starts here
X+ 		mov	di,ax
X+ 		sub	di,ovlrootcode		; segment fixup value
X+ 		mov	si,ds:reloctbloff	; ^ relocation tbl in header
X+ 		jcxz	relocdone		; not such a good idea, after all
X+ dorelocs:					; labels don't GET comments
X+ 		lodsw				; offset into load module
X+ 		mov	bx,ax
X+ 		lodsw				; segment in load module (zero reference)
X+ 		add	ax,pspadd		; now it is psp relative
X+ 		add	ax,di			; and now it is relative to the actual load address
X+ 		mov	es,ax
X+ 		mov	ax,es:[bx]		; pickup item to relocate
X+ 		add	ax,pspadd		; make it psp relative
X+ 		cmp	ax,ovlrootcode		; is it below the OVERLAY_AREA?
X+ 		jc	reloccomputed		; yup. it's relocated
X+ 		cmp	ax,ovldata		; is it above OVERLAY_AREA
X+ 		jnc	reloccomputed		; yup. it's relocated
X+ 		add	ax,di			; it's in OVERLAY_AREA, this one's ours.
X+ reloccomputed:
X+ 		mov	es:[bx],ax		; RAM it home!?!
X+ 		loop	dorelocs		; what goes around, comes around.
X+ relocdone:	ret
X+ 
X+ ovlrlc		endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ getvictim	proc	near			; select a victim to discard (and free up some memory)
X+ 
X+ 		assume	cs:code,ds:ovltbl,es:nothing
X+ 
X+ 		push	bx
X+ 		push	cx
X+ 		push	dx
X+ 		push	si
X+ 		push	di
X+ 		push	bp
X+ 		push	ds
X+ 		mov	ds,ovltblbse		; ^ ovl tbl
X+ 		xor	ax,ax			; will contain the low word of lru
X+ 		mov	dx,ax			; will contain the high word of lru
X+ 		mov	bp,ax			; will contain ovl tbl entry
X+ 		mov	bx,ax			; ovl tbl ptr
X+ ;		 mov	 cx,ovlcnt		 ; number of ovl's to scan
X+ ;foon:		 test	 ovlflg[bx],MASK loaded  ; is this one loaded?
X+ ;		 jz	 skip			 ; nope, try next one
X+ ;		 test	 ovlflg[bx],MASK locked  ; is this one loacked?
X+ ;		 jnz	 skip			 ; yup, try next one
X+ ;		 test	 ovlflg[bx],MASK running ; is this one running?
X+ ;		 jnz	 skip			 ; yup, try next one
X+ ;		 mov	 si,WORD PTR ovltim	 ; get global lru
X+ ;		 mov	 di,WORD PTR ovltim+2
X+ ;		 sub	 si,WORD PTR ovllrudat[bx] ; subtract from ovl lru
X+ ;		 sbb	 di,WORD PTR ovllrudat[bx+2]
X+ ;		 cmp	 dx,di			 ; is this one older?
X+ ;		 jc	 better 		 ; it sure is
X+ ;		 jnz	 skip			 ; it definitely isn't
X+ ;		 cmp	 ax,si
X+ ;		 jnc	 skip			 ; it really isn't
X+ ;better:	 mov	 ax,si			 ; save the lru stuff and ovl ptr
X+ ;		 mov	 dx,di
X+ ;		 mov	 bp,bx
X+ ;skip:		 add	 bx,ovlsegsiz		 ; do next ovl
X+ ;		 loop	 foon
X+ ;		 or	 bp,bp			 ; did we find anyone to kill?
X+ ;		 jnz	 gotvictim		 ; yes we did, partner.
X+ ;		 xor	 bx,bx			 ; Oh well, do it again disregarding the running flag
X+ 		mov	cx,ovlcnt
X+ foon1:		test	ovlflg[bx],MASK loaded
X+ 		jz	skip1
X+ 		test	ovlflg[bx],MASK locked
X+ 		jnz	skip1
X+ 		mov	si,WORD PTR ovltim
X+ 		mov	di,WORD PTR ovltim+2
X+ 		sub	si,WORD PTR ovllrudat[bx]
X+ 		sbb	di,WORD PTR ovllrudat[bx+2]
X+ 		cmp	dx,di
X+ 		jc	better1
X+ 		jnz	skip1
X+ 		cmp	ax,si
X+ 		jnc	skip1
X+ better1:	mov	ax,si
X+ 		mov	dx,di
X+ 		mov	bp,bx
X+ skip1:		add	bx,ovlsegsiz
X+ 		loop	foon1
X+ 		or	bp,bp			; were we more successful this time?
X+ 		jnz	gotvictim		; now we got one.
X+ nomoremem:
X+ 		mov	al,5			; were really %$# now!
X+ 		mov	dx,offset nocore
X+ 		jmp	putserr
X+ gotvictim:
X+ 		shr	bp,1			; convert offset to segment
X+ 		shr	bp,1
X+ 		shr	bp,1
X+ 		shr	bp,1
X+ 		mov	ax,ds
X+ 		add	ax,bp
X+ 		pop	ds
X+ 		pop	bp
X+ 		pop	di
X+ 		pop	si
X+ 		pop	dx
X+ 		pop	cx
X+ 		pop	bx
X+ 		ret
X+ getvictim	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ setrunning	proc	near			; set running flag on overlays still running
X+ 
X+ 		assume cs:code,ds:nothing,es:ovltbl
X+ 
X+ 		push	es
X+ 		mov	es,ovltblbse
X+ 		mov	cx,ovlcnt
X+ 		xor	bx,bx
X+ jim:		and	ovlflg[bx],NOT MASK running ; start by clearing them all
X+ 		add	bx,ovlsegsiz
X+ 		loop	jim
X+ 
X+ 		; Now chain down the stack links, setting running flags
X+ 
X+ 		mov	bx,curovl
X+ 		sub	bx,6
X+ 		jmp	jam
X+ jamloop:
X+ 		mov	ds,cs:[bx]
X+ 		assume	ds:ovltbl
X+ 		or	ovlflg,MASK running
X+ 		sub	bx,6
X+ jam:
X+ 		cmp	word ptr cs:[bx],-1	; end of stack ?
X+ 		jnz	jamloop
X+ 		pop	es
X+ 		ret
X+ 
X+ setrunning	    endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ int21		proc	near
X+ 
X+ ; free almost all overlay memory if app. tries to call the DOS exec function.
X+ 
X+ 		cmp	ah,DOSEXEC
X+ 		jz	freeall
X+ 		cmp	ah,TERMINATE
X+ 		jz	saybyebye
X+ 		jmp	cs:oldint21
X+ saybyebye:
X+ 		pop	ax			; clean up stack
X+ 		pop	ax
X+ 		pop	ax
X+ 		mov	al,0			; return code 0
X+ 		mov	dx,offset exitmsg
X+ 		jmp	putserr
X+ freeall:
X+ 		push	ax
X+ 		push	bx
X+ 		push	cx
X+ 		push	dx
X+ 		push	si
X+ 		push	di
X+ 		push	bp
X+ 		push	es
X+ 		push	ds			; preserve calling env.
X+ 
X+ 		assume cs:code,ds:nothing,es:ovltbl
X+ 
X+ 		mov	ax,cs:memblk1st 	; start de-allocating from first blk
X+ 		jmp	short lastblk
X+ unloadlp:
X+ 		mov	ds,ax
X+ 		cmp	ax,cs:ovltblbse 	; in alloced area ?
X+ 		jc	nextmemblk
X+ 		test	ds:memblkflg,MASK_used	; mem blk used ?
X+ 		jz	nextmemblk
X+ 		mov	es,ds:memblkovl
X+ 		and	ovlflg,NOT MASK loaded	; flag overlay as unloaded
X+ nextmemblk:
X+ 		mov	ax,ds:memblknxt
X+ lastblk:
X+ 		or	ax,ax			; keep going till no more
X+ 		jnz	unloadlp
X+ 
X+ 		mov	ax,cs:ovltblbse
X+ 		add	ax,cs:ovlcnt
X+ 		mov	es,ax			; ^ to first mem blk in alloced mem
X+ 		mov	es:memblksiz,2		; adjust size
X+ 		mov	es:memblknxt,0		; no other blocks after this one
X+ 		mov	es:memblkflg,0		; not used
X+ 		mov	cs:memstat,0ffh 	; memory needs to be re-alloced some day
X+ 
X+ 		mov	dx,word ptr cs:oldint21
X+ 		mov	ds,word ptr cs:oldint21+2
X+ 		mov	ah,DOSSETVEC		; put back DOS vector to avoid calling ourselves again!
X+ 		mov	al,21h
X+ 		int	DOS
X+ 
X+ 		mov	es,cs:ovltblbse
X+ 		mov	bx,cs:ovlcnt
X+ 		add	bx,2			; re-adjust alloced size
X+ 		mov	ah,DOSREALLOC
X+ 		int	DOS
X+ 		pop	ds
X+ 		pop	es
X+ 		pop	bp
X+ 		pop	di
X+ 		pop	si
X+ 		pop	dx
X+ 		pop	cx
X+ 		pop	bx
X+ 		pop	ax
X+ 		jmp	cs:oldint21		; allow DOS to continue!
X+ 
X+ int21		endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ reallocmem	proc	near
X+ 
X+ ; re-allocate our memory after a DOS exec function
X+ 
X+ 		push	es
X+ 		mov	ah,DOSREALLOC
X+ 		mov	es,cs:ovltblbse 	; mem blk handle
X+ 		mov	bx,0ffffh		; find out how much there is
X+ 		int	DOS
X+ 		mov	ah,DOSREALLOC		; re-allocate our own memory
X+ 		mov	es,cs:ovltblbse
X+ 		push	bx			; contains largest available blk
X+ 		int	DOS
X+ 		mov	cs:memstat,0		; flag it re-alloced
X+ 		mov	ax,cs:ovltblbse
X+ 		add	ax,cs:ovlcnt
X+ 		mov	es,ax			; ^ to first mem blk in alloced mem
X+ 		pop	ax
X+ 		sub	ax,cs:ovlcnt		; remove ovl rbl size
X+ 		mov	es:memblksiz,ax 	; fix mem blk size
X+ 
X+ 		mov	ah,DOSGETVEC
X+ 		mov	al,21h
X+ 		int	DOS			; get original vector
X+ 		mov	word ptr cs:oldint21,bx ; save original vector
X+ 		mov	word ptr cs:oldint21+2,es
X+ 
X+ 		mov	ah,DOSSETVEC
X+ 		mov	al,21h
X+ 		mov	bx,cs
X+ 		mov	ds,bx
X+ 		mov	dx,OFFSET int21 	; point to int21
X+ 		int	DOS			; set vector
X+ 
X+ 		pop	es
X+ 		ret
X+ 
X+ reallocmem	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ releasepages	proc	near			; Arg in es, result in ax
X+ 
X+ ; release any memory (and overlays) where this overlay should reside
X+ 
X+ 		assume	es:ovltbl
X+ 
X+ 		mov	bx,es:ovlmemblk 	; start of memory to release
X+ doitagain:
X+ 		mov	ax,memblk1st		; first memory blk
X+ 		jmp	dvart
X+ dvartloop:
X+ 		mov	ds,ax			; memory blk to check
X+ 		cmp	bx,ax			; does it start below the memory to release?
X+ 		jnc	dvartsmaller		; yup
X+ 		mov	dx,bx
X+ 		add	dx,es:ovlsiz
X+ 		add	dx,memctlblksiz / PARSIZ; end of memory to release
X+ 		cmp	ax,dx			; does it start above?
X+ 		jnc	dvartsilly		; yup
X+ 		call	killmem 		; it's in the way. Zap it.
X+ 		jmp	chkmemblk
X+ dvartsmaller:
X+ 		add	ax,ds:memblksiz 	; end of this memory blk
X+ 		cmp	bx,ax			; does it end below the memory to release?
X+ 		jnc	dvartsilly		; yup
X+ 		call	killmem 		; Oh well, zap it too.
X+ chkmemblk:					; was that enough?
X+ 		mov	ax,ds			; recently freed memory blk
X+ 		cmp	bx,ax			; does it start in the memory to be released?
X+ 		jc	dvartsilly		; yup, wasn't enough
X+ 		mov	dx,bx
X+ 		add	dx,es:ovlsiz
X+ 		add	dx,memctlblksiz / PARSIZ; end of memory to be released
X+ 		add	ax,ds:memblksiz 	; end of freed memory
X+ 		cmp	ax,dx			; does it end in the memory to be released?
X+ 		jc	dvartsilly		; yup, release more
X+ dvartgotblk:
X+ 		mov	ax,ds			; this is it!
X+ 		mov	cx,bx
X+ 		sub	cx,ax			; # of paragraphs between start of memory to release and mem blk
X+ 		jz	nosplit
X+ 		call	splitblkhigh		; split the block
X+ nosplit:
X+ 		mov	cx,es:ovlsiz
X+ 		add	cx,memctlblksiz / PARSIZ; paragraphs needed to load ovl
X+ 		jmp	splitblklow		; split remaining block
X+ dvartsilly:
X+ 		mov	ax,ds:memblknxt
X+ dvart:
X+ 		or	ax,ax			; enf of mem list?
X+ 		jz	dvartnocore
X+ 		jmp	dvartloop		; play it again Sam.
X+ dvartnocore:
X+ 		mov	al,5			; super OOPS!
X+ 		mov	dx,offset nocore
X+ 		jmp	putserr
X+ 
X+ releasepages	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ getpages	proc	near			; get enough memory to load ovl
X+ 
X+ 		mov	cx,ax
X+ 		add	cx,memctlblksiz / PARSIZ; total paragraphs needed
X+ 		call	largestmem		; find largest free blk
X+ 		cmp	dx,cx			; large enough?
X+ 		jnc	gotdork 		; yup.
X+ dorkkill:
X+ 		call	getvictim		; select a victim to release
X+ 		call	killovl 		; kill the selected victim
X+ 		cmp	ds:memblksiz,cx 	; was it enough?
X+ 		jc	dorkkill		; nope, select another one
X+ gotdork:
X+ 		jmp	splitblklow		; split the free blk
X+ 
X+ getpages	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ splitblklow	proc	near
X+ 
X+ ; split a block of memory returning the lower one to be used.
X+ 
X+ 		push	es
X+ 		or	ds:memblkflg,MASK_used	; set low block used
X+ 		mov	ax,ds
X+ 		add	ax,cx
X+ 		mov	es,ax			; ^ to upper blk to be created
X+ 		mov	ax,ds:memblksiz
X+ 		sub	ax,cx
X+ 		cmp	ax,1			; must be at least 1 para remaining to split
X+ 		jc	noodorksplit		; don't split
X+ 		mov	ds:memblksiz,cx 	; fix blk sizes
X+ 		mov	es:memblksiz,ax
X+ 		mov	ax,ds:memblknxt 	; fix pointers
X+ 		mov	es:memblknxt,ax
X+ 		mov	ds:memblknxt,es
X+ 		mov	es:memblkprv,ds
X+ 		mov	es:memblkflg,0		; set upper to not used
X+ 		push	ds
X+ 		mov	ax,es:memblknxt
X+ 		or	ax,ax
X+ 		jz	domergelow
X+ 		mov	ds,ax			; fix blk after upper to point to upper
X+ 		mov	ds:memblkprv,es
X+ domergelow:
X+ 		mov	ax,es
X+ 		mov	ds,ax
X+ 		call	mergemem		; merge remaining free memory
X+ 		pop	ds
X+ noodorksplit:
X+ 		pop	es
X+ 		mov	ds:memblkovl,es 	; fix ptr to ovl
X+ 		mov	ax,ds			; return lower blk segment
X+ 		ret
X+ 
X+ splitblklow	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ splitblkhigh	proc	near
X+ 
X+ ; split a block of memory returning the upper one to be used.
X+ 
X+ 		push	es
X+ 		mov	ax,ds
X+ 		add	ax,cx
X+ 		mov	es,ax			; ^ to upper blk to be created
X+ 		mov	ax,ds:memblksiz
X+ 		sub	ax,cx			; # of para remaining in upper blk
X+ 		mov	ds:memblksiz,cx 	; fix blk sizes
X+ 		mov	es:memblksiz,ax
X+ 		mov	ax,ds:memblknxt 	; fix blk pointers
X+ 		mov	es:memblknxt,ax
X+ 		mov	ds:memblknxt,es
X+ 		mov	es:memblkprv,ds
X+ 		mov	ds:memblkflg,0		; set lower to not used
X+ 		or	es:memblkflg,MASK_used	; set upper to used
X+ 		mov	ax,es:memblknxt
X+ 		or	ax,ax
X+ 		jz	domergehigh
X+ 		push	ds			; fix blk after upper to point to upper
X+ 		mov	ds,ax
X+ 		mov	ds:memblkprv,es
X+ 		pop	ds
X+ domergehigh:
X+ 		call	mergemem		; merge remaining free memory
X+ nodorksplit:
X+ 		mov	ax,es
X+ 		mov	ds,ax
X+ 		pop	es
X+ 		mov	ds:memblkovl,es 	; fix ovl ptr
X+ 		mov	ax,ds			; return upper blk segment
X+ 		ret
X+ 
X+ splitblkhigh	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ largestmem	proc	near	; returns seg in ax, size in dx; clobbers bx,ds,es
X+ 				; retruns first block that's large enough if possible
X+ 
X+ 		mov	ax,memblk1st		; first mem blk
X+ 		xor	dx,dx			; largest size found
X+ 		jmp	gook
X+ gookloop:	mov	ds,ax
X+ 		test	ds:memblkflg,MASK_used	; is this blk used?
X+ 		jnz	gookme			; yup
X+ 		cmp	ds:memblksiz,cx 	; is it large enough?
X+ 		jc	gookme			; nope
X+ 		mov	dx,ds:memblksiz 	; got one!
X+ 		ret
X+ gookme:
X+ 		mov	ax,ds:memblknxt
X+ gook:		or	ax,ax			; end of list?
X+ 		jnz	gookloop		; around and around
X+ 		ret
X+ 
X+ largestmem	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ killmem 	proc	near
X+ 
X+ 		test	ds:memblkflg,MASK_used	; is it used?
X+ 		jz	memnotused		; don't kill ovl
X+ 		push	es
X+ 		mov	es,ds:memblkovl
X+ 		and	es:ovlflg,NOT MASK loaded ; zap ovl associated with this blk
X+ 		pop	es
X+ memnotused:
X+ 		jmp	mergemem		; merge free memory
X+ 
X+ killmem 	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ killovl 	proc	near		; preserves bx
X+ 
X+ 		mov	ds,ax
X+ 		assume	ds:ovltbl
X+ 		and	ovlflg,NOT MASK loaded	; ovl no longer loaded
X+ 		mov	ax,ovlmemblk		; get mem blk
X+ 		mov	ds,ax
X+ 		jmp	mergemem		; merge free memory
X+ 
X+ killovl 	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ mergemem	proc	near
X+ 
X+ ; merge physically adjacent free memory blocks. Preserves es. ds -> a free block.
X+ 
X+ 		push	es
X+ 		and	ds:memblkflg,NOT MASK_used ; set current free
X+ 		mov	ax,ds:memblkprv 	; get previous blk
X+ 		or	ax,ax			; was there a previous blk?
X+ 		jz	gibber			; nope
X+ 		mov	es,ax
X+ 		test	es:memblkflg,MASK_used	; is the previous blk used?
X+ 		jnz	gibber			; yup
X+ 		add	ax,es:memblksiz 	; end of previous blk
X+ 		mov	dx,ds
X+ 		cmp	dx,ax			; physically adjacent?
X+ 		jnz	gibber			; nope
X+ 		mov	ax,ds:memblksiz
X+ 		add	es:memblksiz,ax 	; adjust size of new larger blk
X+ 		mov	ax,ds:memblknxt 	; fix pointers
X+ 		mov	es:memblknxt,ax
X+ 		or	ax,ax
X+ 		jz	almostgibber
X+ 		mov	ds,ax			; fix pointer of next blk
X+ 		mov	ds:memblkprv,es
X+ almostgibber:
X+ 		mov	ax,es
X+ 		mov	ds,ax			; new blk segment
X+ gibber:
X+ 		mov	ax,ds:memblknxt 	; get next blk
X+ 		or	ax,ax			; was there a next blk?
X+ 		jz	killdone		; nope
X+ 		mov	es,ax
X+ 		test	es:memblkflg,MASK_used	; is the nxt blk used?
X+ 		jnz	killdone		; yup
X+ 		mov	ax,ds
X+ 		add	ax,ds:memblksiz 	; end of this blk
X+ 		mov	dx,es
X+ 		cmp	ax,dx			; physically adjacent?
X+ 		jnz	killdone		; nope
X+ 		mov	ax,es:memblksiz
X+ 		add	ds:memblksiz,ax 	; adjust size of new larger blk
X+ 		mov	ax,es:memblknxt 	; fix pointers
X+ 		mov	ds:memblknxt,ax
X+ 		or	ax,ax
X+ 		jz	killdone
X+ 		mov	es,ax			; fix pointer of blk after nxt
X+ 		mov	es:memblkprv,ds
X+ killdone:
X+ 		and	ds:memblkflg,NOT MASK_used ; make sure it's free
X+ 		pop	es
X+ 		ret
X+ 
X+ mergemem	endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ gethdr		proc	near			; read EXE header from handle
X+ 
X+ 		push	cx
X+ 		mov	ax,cs
X+ 		mov	ds,ax
X+ 		mov	dx,offset hdr		; a place to put it
X+ 		mov	bx,ovlexefilhdl 	; the file handle
X+ 		mov	cx,hdrsize		; header size in bytes
X+ 		mov	ah,DOSREAD
X+ 		int	DOS			; read from file
X+ 		jc	exegone 		; oops
X+ 		cmp	ax,cx			; got correct number of bytes?
X+ 		jnz	exegone 		; nope
X+ 		pop	cx
X+ 		ret				; Wow, it worked!
X+ exegone:
X+ 		mov	al,5			; You lose!
X+ 		mov	dx,offset nofile
X+ 		jmp	putserr
X+ 
X+ gethdr		endp
X+ 
X+ ;-------------------------------------------------------------------------------
X+ 
X+ putserr 	proc	near
X+ 
X+ ; display error msg, close file, restore int vectors, free mem and return to DOS.
X+ 
X+ 		push	ax			; keep return code for later
X+ 		mov	ax,cs
X+ 		mov	ds,ax
X+ 		mov	ah,PRINT
X+ 		int	DOS			; display error msg
X+ 		mov	dx,word ptr oldvec	; get old vector
X+ 		cmp	dx,-1			; was it ever replaced?
X+ 		jz	free21			; nope
X+ 		push	ds
X+ 		mov	ds,word ptr oldvec+2
X+ 		mov	ah,DOSSETVEC		; put it back then.
X+ 		mov	al,$$INTNO
X+ 		int	DOS
X+ 		pop	ds
X+ free21:
X+ 		mov	dx,word ptr oldint21
X+ 		cmp	dx,-1
X+ 		jz	freemem
X+ 		push	ds
X+ 		mov	ds,word ptr oldint21+2
X+ 		mov	ah,DOSSETVEC		; put it back then.
X+ 		mov	al,21h
X+ 		int	DOS
X+ 		pop	ds
X+ freemem:
X+ 		mov	ax,ovltblbse		; get memory blk segment
X+ 		cmp	ax,-1			; was one ever allocated?
X+ 		jz	closefile		; nope
X+ 		mov	es,ax
X+ 		mov	ah,DOSFREE		; must free it.
X+ 		int	DOS
X+ closefile:
X+ 		mov	bx,ovlexefilhdl 	; get file handle
X+ 		cmp	bx,-1			; was the file ever opened?
X+ 		jz	byebye			; nope
X+ 		mov	ah,DOSCLOSE		; close it
X+ 		int	DOS
X+ byebye:
X+ 		pop	ax			; return code in al
X+ 		mov	ah,TERMINATE
X+ 		int	DOS			; terminate this process
X+ 
X+ putserr 	endp
X+ 
X+ code		ends
X+ 
X+ 		end
X*** /dev/null	Sun Nov 19 14:15:44 1989
X--- others/ovlmgr.doc	Tue Nov 14 21:11:07 1989
X***************
X*** 0 ****
X--- 1,200 ----
X+ 		     Brief notes about ovlmgr.asm
X+ 		     ----------------------------
X+ 			 (revised 1989nov12)
X+ 
X+ OVLMGR.ASM is a preliminary version of a multiple-residency overlay
X+ manager for use with the Microsoft Overlay Linker. It is functionally
X+ compatible with the one in the MSC library _except_:
X+ 
X+ - it doesn't support setjmp()/longjmp().
X+ - it leaves only a SMALL, fixed space for your heap (1).
X+ - it usually accesses the disk less often and is a lot faster in some
X+   applications.
X+ - it has different tuning characteristics.
X+ - you must (of course) link OVLMGR.OBJ into the root overlay (that is,
X+   outside any parentheses in the link command).
X+ 
X+   See also the bugs list below.
X+ 
X+ As with other Microsoft-compatible overlay handlers you must be *very*
X+ careful never to call a function in an overlay through a pointer,
X+ unless the initiator of the call resides in the *same* physical
X+ overlay as the target (2).
X+ 
X+ Although using the overlay manager is in essence much like using
X+ Microsoft's, they operate on a slightly different principle, and tuning
X+ for them is rather different. Technical part begins.
X+ 
X+ When overlay linking is requested (see you linker manual), the MS
X+ overlay linker changes all far calls into overlays from the (normal,
X+ 8086) format:
X+ 
X+ 	offset	contents
X+ 	------	--------
X+ 	:0000	CALL
X+ 	:0001	target-offset
X+ 	:0003	target-segment
X+ 
X+ to this:
X+ 	:0000	INT
X+ 	:0001	int#	target-mod#
X+ 	:0003	target-offset
X+ 
X+ (note that here we are looking at the actual layout of the machine
X+ code, not at the assembly code as such) and relocates the code parts
X+ of all the different overlays into the *same* physical area. The
X+ overlaid code is all actually placed at the end of the .EXE file,
X+ after the 'normal' executable image, along with all its administrative
X+ data (fixups etc.).
X+ 	When this altered 'call' is executed, of course, the interrupt
X+ handler int# is invoked. Its job is to ensure that the target overlay
X+ module is in memory (reading it from the tail of the .EXE file if it
X+ isn't already loaded) and then transfer to the given offset within it,
X+ 'faking up' the effect of the 'real' far call that would normally have
X+ occurred.  Something similar must be done when the call returns, to
X+ ensure that the thing being returned *into* is still (or is once more)
X+ loaded.
X+ 	The Microsoft linker, as we have said, relocates all the
X+ overlays to the same load address; and, in fact, it allocates am empty
X+ block of memory there that is at least as large as the largest
X+ overlay. Into this area all the overlays are loaded without further
X+ change; thus, there can only ever be one overlay in memory at one
X+ time. Transferring from one overlay to another causes one overlay to
X+ replace the other in the allocated overlay swap area.
X+ 	Our overlay manager does not use the space allocated by the
X+ linker in the same way. Rather, it allocates almost all of the memory
X+ available from MS-DOS (including the original overlay area). As
X+ overlays are needed, they are loaded wherever they will fit, and
X+ dynamically relocated to that address.	Thus, many more than one
X+ overlay may be loaded at any given time, greatly increasing potential
X+ performance. Managament of space is more or less according to an LRU
X+ policy - once all of memory is full, the least recently used overlay
X+ is selected as the most likely candidate for replacement.
X+ 
X+ The implications of this difference are as follows: while with the
X+ conventional (default) overlay manager, the best strategy is to group
X+ object modules together in an overlay whenever they are known to be
X+ used in rapid succession, to make each overlay as big as possible (all
X+ things being equal) in order to take advantage of all available
X+ memory, and to make as few overlays as possible (to reduce the amount
X+ of disk access), the best strategy with our overaly manager is almost
X+ the reverse. Having a lot of small overlays will increase the amount
X+ of useful stuff that can be resident in memory at the same time; all
X+ of memory will automatically be employed; and there is no advantage at
X+ all to uniformity of size (except perhaps in the unlikely case of
X+ *exact* uniformity!).
X+ 	One thing that is no longer a problem with this version
X+ (though it was with all earlier versions of this overlay manager) is
X+ that the DOS exec() call works normally. The memory that is allocated
X+ for administering the overlay system is freed before the exec call is
X+ made and reallocated afterwards (we trap the DOS function request
X+ vector to do this, which isn't very nice as a programming practise but
X+ makes the existence of the overlay manager far more transparent).
X+ There is, however, one circumstance under which this can be
X+ problematic: if you use the exec() call to load a TSR application,
X+ thereby causing memory that the overlay manager was using to become
X+ unavailable, you may make it impossible for the overlaid application
X+ to proceed. This is because code that is nominally 'running' (i.e. is
X+ currently on the stack) cannot be relocated and must be reloaded
X+ at the *same address* that previously held it. If another process now
X+ owns that area of memory, there is nothing we can do.
X+ 	We believe that this should not be a serious concern in normal
X+ use.
X+ 
X+ NOTA BENE: This is a preliminary version of the overlay manager, but
X+ by now it should be fairly well debugged. If you are considering
X+ upgrading it please be aware that the following improvements are
X+ planned for the next version (though who knows when delivery will
X+ occur):
X+ 	Twice the speed
X+ 	EMS support
X+ 	compatible versions of setjmp() and longjmp()
X+ 	Integration with malloc() so the heap can grow
X+ 	Major code revamping
X+ 
X+ Enjoy!
X+ ------------------------------------------------------------------------
X+ MESSAGES
X+ 
X+ Not enough memory to run this program. Time to go to the store.
X+ 	Although DOS successfully loaded the programme, it proved
X+ 	impossible to allocate enough additional contiguous memory to
X+ 	load one or more of the overlays. Either reduce the
X+ 	RAM-loading of the application by reducing the size of either
X+ 	the root or the largest overlays, or increase the amount of
X+ 	memory available by unloading TSRs and/or simplifying your
X+ 	CONFIG.SYS.
X+ 
X+ Your dog eats all your remaining memory! You die.
X+ 	Either an internal error has occurred in ovlmgr or the
X+ 	application programme, or some event has caused memory that
X+ 	ovlmgr believed it could count on becoming unavailable. A
X+ 	typical example of the latter would be the result of
X+ 	attempting to load a TSR while an overlaid application is
X+ 	running.
X+ 
X+ The Nymph stole your .EXE file! You die.
X+ 	For some reason ovlmgr could not locate or read the original
X+ 	.EXE file in which the overlays reside. This could be due to
X+ 	your attempting to use a very old version of DOS,
X+ 	an abject shortage of file handles, some strange event causng
X+ 	the file to be deleted, a disk error, or the diskette that
X+ 	contained the executable has been removed.
X+ ------------------------------------------------------------------------
X+ KNOWN BUGS
X+ 
X+ The present version cannot always be used as a direct replacement for
X+ Microsoft's overlay manager (even granted the documented differences)
X+ because the minimum size required for an overlaid programme to run is
X+ at least the size of the root plus TWICE the size of the largest
X+ overlay. If a programme has previously had its overlay structure tuned
X+ to take best advantage of Microsoft overlays, this may well cause a
X+ problem. The overlays themselves will need to be split up.
X+ 
X+ The error messages are whimsical and NetHack-culture-specific.
X+ Somewhat more informative versions appeared in one version of the
X+ programme but they seem to have been lost.
X+ 
X+ Transfers between overlays are very slow in machine terms, even if
X+ both overlays happen to reside in memory at the time.
X+ 
X+ Locking overlays into memory is not really implemeted even though
X+ reading the source code might make you think it was.
X+ ------------------------------------------------------------------------
X+ BUG ALERT
X+ 
X+ To repeat a point made above, if you ever try to call a function in an
X+ overlay through a pointer, you *may* die with the Microsoft overlay
X+ manager. If you ever try to call a function in an overlay through a
X+ pointer, you *will* die with ours. Nothing in an overlay ever ends up
X+ in the same segment as the linker anticipated.	You have been warned!
X+ ------------------------------------------------------------------------
X+ FOOTNOTES
X+ 
X+ (1) If you hunt through the code you will find a magic constant you
X+ can play with to vary this allotment, if you're brave enough. It's
X+ currently tuned for NetHack 3.0. If you should get a message to the
X+ effect that NetHack can't allocate 28000 and some bytes when entering
X+ a maze level, that isn't our problem! In all probability you forgot to
X+ rebuild your special level files when you changed the compiler flags.
X+ We got that one, too, at one point.
X+ 
X+ (2) This problem can be circumvented through the use of surrogate
X+ 'trampoline' functions: functions that reside in the root overlay and
X+ simply pass right through to the 'real', overlaid, implementations.
X+ This can even be made transparent to the source code through the use
X+ of the C macro preprocessor, with a locution of the form
X+ 	#define foo(x) foo_(x)
X+ visible everywhere except at the actual definition point of the
X+ trampoline. This has been implemented in Nethack 3.0h.
X+ ----------------------------------------------------------------------
X+ NOTICE
X+ 
X+ OVLMGR.ASM is brought to you by Pierre Martineau and Stephen Spackman.
X+ It, and this document, are copyright. They are, however, provided as
X+ part of NetHack and may be freely distributed as described in the
X+ NetHack license.
X+ ----------------------------------------------------------------------
X+ Stephen P Spackman		       stephen@concour.cs.concordia.ca
X+ ----------------------------------------------------------------------
X+      Copyright (C) 1989 Pierre G Martineau and Stephen P Spackman
X*** others/Old/pcmain.c	Sun Nov 19 14:16:14 1989
X--- others/pcmain.c	Tue Nov 14 20:32:13 1989
X***************
X*** 1,4 ****
X! /*	SCCS Id: @(#)pcmain.c	3.0	88/11/23
X  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X  /* NetHack may be freely redistributed.  See license for details. */
X  /* main.c - PC, ST, and Amiga NetHack */
X--- 1,4 ----
X! /*	SCCS Id: @(#)pcmain.c	3.0	89/10/25
X  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X  /* NetHack may be freely redistributed.  See license for details. */
X  /* main.c - PC, ST, and Amiga NetHack */
X***************
X*** 8,13 ****
X--- 8,14 ----
X  #ifndef NO_SIGNAL
X  #include <signal.h>
X  #endif
X+ #include <ctype.h>
X  #ifdef MACOS
X  extern WindowPtr	HackWindow;
X  extern short *switches;
X***************
X*** 21,27 ****
X  char SAVEF[FILENAME];
X  
X  char *hname = "NetHack";	/* used for syntax messages */
X! #ifndef AMIGA
X  char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
X  #endif
X  int hackpid;		/* not used anymore, but kept in for save files */
X--- 22,28 ----
X  char SAVEF[FILENAME];
X  
X  char *hname = "NetHack";	/* used for syntax messages */
X! #if !defined(AMIGA) && !defined(MACOS)
X  char obuf[BUFSIZ];	/* BUFSIZ is defined in stdio.h */
X  #endif
X  int hackpid;		/* not used anymore, but kept in for save files */
X***************
X*** 57,62 ****
X--- 58,65 ----
X  # endif
X  #endif
X  
X+ static const char *classes = "ABCEHKPRSTVW";
X+ 
X  int
X  main(argc,argv)
X  int argc;
X***************
X*** 160,166 ****
X  # endif /* DGK && !OLD_TOS */
X  
X  	initoptions();
X! # ifdef TOS
X  	if (flags.IBMBIOS && flags.use_color)
X  		set_colors();
X  # endif
X--- 163,169 ----
X  # endif /* DGK && !OLD_TOS */
X  
X  	initoptions();
X! # if defined(TOS) && defined(TEXTCOLOR)
X  	if (flags.IBMBIOS && flags.use_color)
X  		set_colors();
X  # endif
X***************
X*** 236,242 ****
X  		case 'D':
X  # ifdef WIZARD
X  			/* Must have "name" set correctly by NETHACK.CNF,
X! 			 * NETHACKOPTIONS, or -U
X  			 * before this flag to enter wizard mode. */
X  			if(!strcmp(plname, WIZARD)) {
X  				wizard = TRUE;
X--- 239,245 ----
X  		case 'D':
X  # ifdef WIZARD
X  			/* Must have "name" set correctly by NETHACK.CNF,
X! 			 * NETHACKOPTIONS, or -u
X  			 * before this flag to enter wizard mode. */
X  			if(!strcmp(plname, WIZARD)) {
X  				wizard = TRUE;
X***************
X*** 263,269 ****
X  			  argv++;
X  			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
X  			} else
X! 				Printf("Player name expected after -U\n");
X  			break;
X  #ifdef DGK
X  		/* Player doesn't want to use a RAM disk
X--- 266,272 ----
X  			  argv++;
X  			  (void) strncpy(plname, argv[0], sizeof(plname)-1);
X  			} else
X! 				Printf("Player name expected after -u\n");
X  			break;
X  #ifdef DGK
X  		/* Player doesn't want to use a RAM disk
X***************
X*** 273,281 ****
X  			break;
X  #endif
X  		default:
X! 			/* allow -T for Tourist, etc. */
X! 			(void) strncpy(pl_character, argv[0]+1,
X! 				sizeof(pl_character)-1);
X  		}
X  	}
X  
X--- 276,302 ----
X  			break;
X  #endif
X  		default:
X! 			if (index(classes, toupper(argv[0][1]))) {
X! 				/* allow -T for Tourist, etc. */
X! 				(void) strncpy(pl_character, argv[0]+1,
X! 					       sizeof(pl_character)-1);
X! 				break;
X! 			} else Printf("\nUnknown switch: %s\n", argv[0]);
X! 		case '?':
X! Printf("\nUsage: %s [-d dir] -s [-[%s]] [maxrank] [name]...", hname, classes);
X! Printf("\n       or");
X! Printf("\n       %s [-d dir] [-u name] [-[%s]]", hname, classes);
X! #if defined(WIZARD) || defined(EXPLORE_MODE)
X! 			Printf(" [-[DX]]");
X! #endif
X! #ifdef NEWS
X! 			Printf(" [-n]");
X! #endif
X! #ifdef DGK
X! 			Printf(" [-r]");
X! #endif
X! 			putchar('\n');
X! 			return 0;
X  		}
X  	}
X  
X***************
X*** 288,300 ****
X  		Strcpy(plname, "wizard");
X  	else
X  #endif
X- #if defined(KR1ED) && defined(WIZARD) && defined(MACOS)
X- 	if (!strcmp(plname,WIZARD))
X- 		Strcpy(plname, "wizard");
X- 	else
X- #endif
X  	if (!*plname)
X  		askname();
X  	plnamesuffix();		/* strip suffix from name; calls askname() */
X  				/* again if suffix was whole name */
X  				/* accepts any suffix */
X--- 309,326 ----
X  		Strcpy(plname, "wizard");
X  	else
X  #endif
X  	if (!*plname)
X  		askname();
X+ #if defined(WIZARD) && defined(MACOS)
X+ # ifdef KR1ED
X+ 	if (!strcmp(plname,WIZARD_NAME)) {
X+ # else
X+ 	if (!strcmp(plname,WIZARD)) {
X+ # endif
X+ 		Strcpy(plname, "wizard");
X+ 		wizard = true;
X+ 	}
X+ #endif
X  	plnamesuffix();		/* strip suffix from name; calls askname() */
X  				/* again if suffix was whole name */
X  				/* accepts any suffix */
X***************
X*** 431,437 ****
X  }
X  
X  /*
X!  * plname is filled either by an option (-U Player  or  -UPlayer) or
X   * explicitly (by being the wizard) or by askname.
X   * It may still contain a suffix denoting pl_character.
X   */
X--- 457,463 ----
X  }
X  
X  /*
X!  * plname is filled either by an option (-u Player  or  -uPlayer) or
X   * explicitly (by being the wizard) or by askname.
X   * It may still contain a suffix denoting pl_character.
X   */
X*** /dev/null	Sun Nov 19 14:17:50 1989
X--- others/trampoli.c	Fri Nov 17 20:45:08 1989
X***************
X*** 0 ****
X--- 1,420 ----
X+ /*	SCCS Id: @(#)trampoli.c 	3.0	89/11/15	  */
X+ /* Copyright (c) 1989, by Norm Meluch and Stephen Spackman	  */
X+ /* NetHack may be freely redistributed.  See license for details. */
X+ 
X+ #include "hack.h"
X+ 
X+ /****************************************************************************/
X+ /*									    */
X+ /*	This file contains a series of declarations of "one liner"	    */
X+ /*	functions.  These functions are to avoid calls to functions via     */
X+ /*	pointers.  This is necessary when the function called is in an      */
X+ /*	overlay segment.						    */
X+ /*	The original function (eg foo) has been defined to be foo_ and	    */
X+ /*	now the declaration of foo is placed in this file calling foo	    */
X+ /*	directly.  This module is _never_ placed in an overlay so	    */
X+ /*	calls via pointers to these functions will not cause difficulties.  */
X+ /*									    */
X+ /****************************************************************************/
X+ 
X+ #ifdef OVERLAY
X+ 
X+ /* ### apply.c ### */
X+ #undef dig
X+ #undef doapply
X+ #undef dojump
X+ #undef dorub
X+ 
X+ int dig()     { return dig_();     }
X+ int doapply() { return doapply_(); }
X+ int dojump()  { return dojump_();  }
X+ int dorub()   { return dorub_();   }
X+ 
X+ 
X+ /* ### cmd.c ### */
X+ #undef doextcmd
X+ #undef doextlist
X+ 
X+ #ifdef POLYSELF
X+ #undef domonability
X+ #endif /* POLYSELF */
X+ 
X+ #undef timed_occupation
X+ 
X+ #if defined(WIZARD) || defined(EXPLORE_MODE)
X+ #undef wiz_attributes
X+ #endif
X+ 
X+ #ifdef WIZARD
X+ #undef wiz_detect
X+ #undef wiz_genesis
X+ #undef wiz_identify
X+ #undef wiz_level_tele
X+ #undef wiz_map
X+ #undef wiz_where
X+ #undef wiz_wish
X+ #endif
X+ 
X+ int doextcmd()         { return doextcmd_();         }
X+ int doextlist()        { return doextlist_();        }
X+ 
X+ #ifdef POLYSELF
X+ int domonability()     { return domonability_();     }
X+ #endif /* POLYSELF */
X+ 
X+ int timed_occupation() { return timed_occupation_(); }
X+ 
X+ #if defined(WIZARD) || defined(EXPLORE_MODE)
X+ int wiz_attributes()   { return wiz_attributes_();   }
X+ #endif
X+ 
X+ #ifdef WIZARD
X+ int wiz_detect()       { return wiz_detect_();       }
X+ int wiz_genesis()      { return wiz_genesis_();      }
X+ int wiz_identify()     { return wiz_identify_();     }
X+ int wiz_level_tele()   { return wiz_level_tele_();   }
X+ int wiz_map()          { return wiz_map_();          }
X+ int wiz_where()        { return wiz_where_();        }
X+ int wiz_wish()         { return wiz_wish_();         }
X+ #endif
X+ 
X+ 
X+ /* ### do.c ### */
X+ #undef doddrop
X+ #undef dodown
X+ #undef dodrop
X+ #undef donull
X+ #undef doup
X+ #undef dowipe
X+ #undef drop
X+ #undef wipeoff
X+ 
X+ int doddrop()             { return doddrop_(); }
X+ int dodown()              { return dodown_();  }
X+ int dodrop()              { return dodrop_();  }
X+ int donull()              { return donull_();  }
X+ int doup()                { return doup_();    }
X+ int dowipe()              { return dowipe_();  }
X+ int drop(obj)
X+ register struct obj *obj; { return drop_(obj); }
X+ int wipeoff()             { return wipeoff_(); }
X+ 
X+ 
X+ /* ### do_name.c ### */
X+ #undef ddocall
X+ #undef do_mname
X+ 
X+ int ddocall()  { return ddocall_();  }
X+ int do_mname() { return do_mname_(); } 
X+ 
X+ 
X+ /* ### do_wear.c ### */
X+ 
X+ /* ### do_wear.c ### */
X+ #undef Armor_off
X+ #undef Boots_off
X+ #undef Gloves_off
X+ #undef Helmet_off
X+ #undef Armor_on
X+ #undef Boots_on
X+ #undef Gloves_on
X+ #undef Helmet_on
X+ #undef doddoremarm
X+ #undef doputon
X+ #undef doremring
X+ #undef dotakeoff
X+ #undef dowear
X+ #undef select_off
X+ #undef take_off
X+ 
X+ int Armor_off()   { return Armor_off_();   }
X+ int Boots_off()   { return Boots_off_();   }
X+ int Gloves_off()  { return Gloves_off_();  }
X+ int Helmet_off()  { return Helmet_off_();  }
X+ /* int Armor_on()    { return Armor_on_();    } */
X+ int Boots_on()    { return Boots_on_();    }
X+ int Gloves_on()   { return Gloves_on_();   }
X+ int Helmet_on()   { return Helmet_on_();   }
X+ int doddoremarm() { return doddoremarm_(); }
X+ int doputon()     { return doputon_();     }
X+ int doremring()   { return doremring_();   }
X+ int dotakeoff()   { return dotakeoff_();   }
X+ int dowear()      { return dowear_();      }
X+ int select_off(otmp) struct obj *otmp; { return select_off_(otmp); }
X+ int take_off()    { return take_off_();    }
X+ 
X+ 
X+ /* ### dokick.c ### */
X+ #undef dokick
X+ 
X+ int dokick() { return dokick_(); }
X+ 
X+ 
X+ /* ### dothrow.c ### */
X+ #undef dothrow
X+ 
X+ int dothrow() { return dothrow_(); }
X+ 
X+ 
X+ /* ### eat.c ### */
X+ #undef Hear_again
X+ #undef Meatdone
X+ #undef doeat
X+ #undef eatfood
X+ #undef opentin
X+ #undef unfaint
X+ 
X+ int Hear_again()  { return Hear_again_(); }
X+ int Meatdone()    { return Meatdone_();   }
X+ int doeat()       { return doeat_();      }
X+ int eatfood()     { return eatfood_();    }
X+ int opentin()     { return opentin_();    }
X+ int unfaint()     { return unfaint_();    }
X+ 
X+ 
X+ /* ### end.c ### */
X+ #undef done2
X+ 
X+ int done2() { return done2_(); }
X+ 
X+ 
X+ /* ### engrave.c ### */
X+ #undef doengrave
X+ 
X+ int doengrave() { return doengrave_(); }
X+ 
X+ 
X+ /* ### hack.c ### */
X+ #undef dopickup
X+ #undef identify
X+ 
X+ int dopickup() { return dopickup_(); }
X+ int identify(otmp) struct obj *otmp; { return identify_(otmp); }
X+ 
X+ 
X+ /* ### invent.c ### */
X+ #undef ckunpaid
X+ #undef ddoinv
X+ #undef dolook
X+ #undef dopramulet
X+ #undef doprarm
X+ #undef doprgold
X+ #undef doprring
X+ #undef doprtool
X+ #undef doprwep
X+ #undef dotypeinv
X+ 
X+ int ckunpaid(obj) struct obj *obj; { return ckunpaid_(obj); }
X+ int ddoinv()     { return ddoinv_();     }
X+ int dolook()     { return dolook_();     }
X+ int dopramulet() { return dopramulet_(); }
X+ int doprarm()    { return doprarm_();    }
X+ int doprgold()   { return doprgold_();   }
X+ int doprring()   { return doprring_();   }
X+ int doprtool()   { return doprtool_();   }
X+ int doprwep()    { return doprwep_();    }
X+ int dotypeinv()  { return dotypeinv_();  }
X+ 
X+ 
X+ /* ### ioctl.c ### */
X+ /*
X+ #ifdef UNIX
X+ #ifdef SUSPEND
X+ #undef dosuspend
X+ 
X+ int dosuspend() { return dosuspend_(); }
X+ #endif
X+ #endif
X+ */
X+ 
X+ 
X+ /* ### lock.c ### */
X+ #undef doclose
X+ #undef doforce
X+ #undef doopen
X+ #undef forcelock
X+ #undef picklock
X+ 
X+ int doclose()   { return doclose_();   }
X+ int doforce()   { return doforce_();   }
X+ int doopen()    { return doopen_();    }
X+ int forcelock() { return forcelock_(); }
X+ int picklock()  { return picklock_();  }
X+ 
X+ 
X+ /* ### o_init.c ### */
X+ #undef dodiscovered
X+ 
X+ int dodiscovered() { return dodiscovered_(); }
X+ 
X+ 
X+ /* ### objnam.c ### */
X+ #undef doname
X+ #undef xname
X+ 
X+ char *doname(obj) struct obj *obj; { return doname_(obj); }
X+ char *xname(obj)  struct obj *obj; { return xname_(obj); }
X+ 
X+ 
X+ /* ### options.c ### */
X+ #undef doset
X+ #undef dotogglepickup
X+ 
X+ int doset()          { return doset_();         }
X+ int dotogglepickup() { return dotogglepickup_(); }
X+ 
X+ 
X+ /* ### pager.c ### */
X+ #undef dohelp
X+ #undef dohistory
X+ #undef dowhatdoes
X+ #undef dowhatis
X+ #ifdef UNIX
X+ #ifdef SHELL
X+ #undef dosh
X+ 
X+ int dosh()       { return dosh_();       }
X+ #endif
X+ #endif
X+ 
X+ int dohelp()     { return dohelp_();     }
X+ int dohistory()  { return dohistory_();  }
X+ int dowhatdoes() { return dowhatdoes_(); }
X+ int dowhatis()   { return dowhatis_();   }
X+ 
X+ 
X+ /* ### pickup.c ### */
X+ #undef ck_bag
X+ #undef ck_container
X+ #undef doloot
X+ #undef in_container
X+ #undef out_container
X+ 
X+ int ck_bag()  { return ck_bag_();  }
X+ int ck_container(obj)  struct obj *obj; { return ck_container_(obj); }
X+ int doloot() { return doloot_(); }
X+ int in_container(obj)  struct obj *obj; { return in_container_(obj); }
X+ int out_container(obj) struct obj *obj; { return out_container_(obj); }
X+ 
X+ 
X+ /* ### potion.c ### */
X+ #undef dodrink
X+ #undef dodip
X+ 
X+ int dodrink() { return dodrink_(); }
X+ int dodip()   { return dodip_();   }
X+ 
X+ 
X+ /* ### pray.c ### */
X+ #undef doturn
X+ #ifdef THEOLOGY
X+ #undef dopray
X+ #undef dosacrifice
X+ 
X+ int dopray()      { return dopray_();      }
X+ int dosacrifice() { return dosacrifice_(); }
X+ #endif /* THEOLOGY */
X+ 
X+ int doturn()      { return doturn_();      }
X+ 
X+ 
X+ /* ### pri.c ### */
X+ #undef doredraw
X+ 
X+ int doredraw()    { return doredraw_(); }
X+ 
X+ 
X+ /* ### read.c ### */
X+ #undef doread
X+ 
X+ int doread() { return doread_(); }
X+ 
X+ 
X+ /* ### save.c ### */
X+ #undef dosave
X+ 
X+ int dosave() { return dosave_(); }
X+ 
X+ 
X+ /* ### search.c ### */
X+ #undef doidtrap
X+ #undef dosearch
X+ 
X+ int doidtrap() { return doidtrap_(); }
X+ int dosearch() { return dosearch_(); }
X+ 
X+ 
X+ /* ### shk.c ### */
X+ #undef dopay
X+ 
X+ int dopay() { return dopay_(); }
X+ 
X+ 
X+ /* ### sit.c ### */
X+ #undef dosit
X+ 
X+ int dosit() { return dosit_(); }
X+ 
X+ 
X+ /* ### sounds.c ### */
X+ #undef dotalk
X+ 
X+ int dotalk() { return dotalk_(); }
X+ 
X+ 
X+ /* ### spell.c ### */
X+ #ifdef SPELLS
X+ #undef learn
X+ #undef docast
X+ #undef dovspell
X+ 
X+ int learn() { return learn_(); }
X+ int docast()   { return docast_();   }
X+ int dovspell() { return dovspell_(); }
X+ #endif
X+ 
X+ 
X+ /* ### steal.c ### */
X+ #undef stealarm
X+ 
X+ int stealarm() { return stealarm_(); }
X+ 
X+ 
X+ /* ### topl.c ### */
X+ #undef doredotopl
X+ 
X+ int doredotopl() { return doredotopl_(); }
X+ 
X+ 
X+ /* ### trap.c ### */
X+ #undef dotele
X+ #undef dountrap
X+ #undef float_down
X+ 
X+ int dotele()     { return dotele_();     }
X+ int dountrap()   { return dountrap_();   }
X+ int float_down() { return float_down_(); }
X+ 
X+ 
X+ /* ### version.c ### */
X+ #undef doversion
X+ 
X+ int doversion() { return doversion_(); }
X+ 
X+ 
X+ /* ### wield.c ### */
X+ #undef dowield
X+ 
X+ int dowield() { return dowield_(); }
X+ 
X+ 
X+ /* ### zap.c ### */
X+ #undef bhitm
X+ #undef bhito
X+ #undef dozap
X+ 
X+ int bhitm(mtmp, otmp) struct monst *mtmp; struct obj *otmp;
X+ 	{ return bhitm_(mtmp, otmp); }
X+ int bhito(obj, otmp) struct obj *obj, *otmp; { return bhito_(obj,  otmp); }
X+ int dozap() { return dozap_(); }
X+ #endif /* OVERLAY */
END_OF_FILE
if test 58568 -ne `wc -c <'patches06d'`; then
    echo shar: \"'patches06d'\" unpacked with wrong size!
fi
# end of 'patches06d'
fi
echo shar: End of archive 2 \(of 15\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 15 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0