[comp.sources.games] v10i072: nethack3p9 - display oriented dungeons & dragons

billr@saab.CNA.TEK.COM (Bill Randle) (07/12/90)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 72
Archive-name: nethack3p9/Part27
Supersedes: 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 27 (of 56)."
# Contents:  others/msdos.c src/restore.c
# Wrapped by billr@saab on Wed Jul 11 17:11:32 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'others/msdos.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/msdos.c'\"
else
echo shar: Extracting \"'others/msdos.c'\" \(30281 characters\)
sed "s/^X//" >'others/msdos.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)msdos.c	3.0	89/12/26
X/* NetHack may be freely redistributed.  See license for details. */
X/* An assortment of MSDOS functions.
X */
X
X#define NEED_VARARGS
X#include "hack.h"
X
X#ifdef MSDOS
X
X# ifdef TOS
X#  include <osbind.h>
X#  ifndef WORD
X#    define WORD short		/* 16 bits -- redefine if necessary */
X#  endif
X# else
X#  ifdef __TURBOC__	/* avoid incompatible redeclaration */
X#   undef getdate
X#  endif
X#  include <dos.h>
X# endif
X# ifdef OS2
X#  include "def_os2.h"   /* OS2 definitions (Timo Hakulinen) */
X# endif
X
X#include <ctype.h>
X#include <fcntl.h>
X#include <process.h>
X
Xstatic char NDECL(DOSgetch);
X# ifdef DGK
Xstatic char NDECL(BIOSgetch);
X# endif
X# ifdef TOS
Xstatic void NDECL(init_aline);
Xchar *_a_line;			/* for Line A variables */
X# else
Xstatic unsigned int FDECL(ioctl, (int,int,unsigned));
Xstatic boolean NDECL(comspec_exists);
X# endif
X
Xstatic int FDECL(findfirst, (char *));
Xstatic int NDECL(findnext);
Xstatic boolean NDECL(record_exists);
X# if !defined(TOS) && !defined(__TURBOC__) && !defined(OS2)
Xstatic char NDECL(switchar);
X# endif
X# ifndef OS2
Xstatic char * NDECL(getdta);
X# endif
X
Xvoid
Xflushout()
X{
X	(void) fflush(stdout);
X	return;
X}
X
Xint
Xtgetch() {
X	char ch;
X
X# ifdef DGK
X	/* BIOSgetch can use the numeric key pad on IBM compatibles. */
X	if (flags.IBMBIOS)
X		ch = BIOSgetch();
X	else
X# endif
X		ch = DOSgetch();
X	return ((ch == '\r') ? '\n' : ch);
X}
X
X# if !defined(OS2) && !defined(TOS)
X/*
X * MS-DOS functions
X */
X#define DIRECT_INPUT	0x07	/* Unfiltered Character Input Without Echo */
X#define FATINFO 	0x1B	/* Get Default Drive Data */
X/* MS-DOS 2.0+: */
X#define GETDTA		0x2F	/* Get DTA Address */
X#define FREESPACE	0x36	/* Get Drive Allocation Info */
X#define GETSWITCHAR	0x3700	/* Get Switch Character */
X#define FINDFIRST	0x4E	/* Find First File */
X#define FINDNEXT	0x4F	/* Find Next File */
X#define SETFILETIME	0x5701	/* Set File Date & Time */
X/*
X * BIOS interrupts
X */
X#define KEYBRD_BIOS	0x16
X#define VIDEO_BIOS	0x10
X/*
X * Keyboard BIOS functions
X */
X#define READCHAR	0x00	/* Read Character from Keyboard */
X#define GETKEYFLAGS	0x02	/* Get Keyboard Flags */
X/*
X * Video BIOS functions
X */
X#define SETCURPOS	0x02	/* Set Cursor Position */
X#define GETMODE 	0x0f	/* Get Video Mode */
X#define FONTINFO	0x1130	/* Get Font Info */
X# endif
X
X
X/*
X *  Keyboard translation tables.
X */
X#  ifdef TOS
X#define KEYPADLO	0x61
X#define KEYPADHI	0x71
X#  else
X#define KEYPADLO	0x47
X#define KEYPADHI	0x53
X#  endif
X
X#define PADKEYS 	(KEYPADHI - KEYPADLO + 1)
X#define iskeypad(x)	(KEYPADLO <= (x) && (x) <= KEYPADHI)
X
X/*
X * Keypad keys are translated to the normal values below.
X * When IBM_BIOS is active, shifted keypad keys are translated to the
X *    shift values below.
X */
Xstatic const struct pad {
X	char normal, shift, cntrl;
X} keypad[PADKEYS] = {
X#  ifdef TOS
X			{C('['), 'Q', C('[')},		/* UNDO */
X			{'?', '/', '?'},		/* HELP */
X			{'(', 'a', '('},		/* ( */
X			{')', 'w', ')'},		/* ) */
X			{'/', '/', '/'},		/* / */
X			{C('p'), '$', C('p')},		/* * */
X#  endif
X			{'y', 'Y', C('y')},		/* 7 */
X			{'k', 'K', C('k')},		/* 8 */
X			{'u', 'U', C('u')},		/* 9 */
X#  ifndef TOS
X			{'m', C('p'), C('p')},		/* - */
X#  endif
X			{'h', 'H', C('h')},		/* 4 */
X#  ifdef TOS
X			{'.', '.', '.'},
X#  else
X			{'g', 'g', 'g'},		/* 5 */
X#  endif
X			{'l', 'L', C('l')},		/* 6 */
X#  ifndef TOS
X			{'p', 'P', C('p')},		/* + */
X#  endif
X			{'b', 'B', C('b')},		/* 1 */
X			{'j', 'J', C('j')},		/* 2 */
X			{'n', 'N', C('n')},		/* 3 */
X			{'i', 'I', C('i')},		/* Ins */
X			{'.', ':', ':'}			/* Del */
X}, numpad[PADKEYS] = {
X#  ifdef TOS
X			{C('['), 'Q', C('[')}	,	/* UNDO */
X			{'?', '/', '?'},		/* HELP */
X			{'(', 'a', '('},		/* ( */
X			{')', 'w', ')'},		/* ) */
X			{'/', '/', '/'},		/* / */
X			{C('p'), '$', C('p')},		/* * */
X#  endif
X			{'7', M('7'), '7'},		/* 7 */
X			{'8', M('8'), '8'},		/* 8 */
X			{'9', M('9'), '9'},		/* 9 */
X#  ifndef TOS
X			{'m', C('p'), C('p')},		/* - */
X#  endif
X			{'4', M('4'), '4'},		/* 4 */
X#  ifdef TOS
X			{'.', '.', '.'},		/* 5 */
X#  else
X			{'g', 'G', 'g'},		/* 5 */
X#  endif
X			{'6', M('6'), '6'},		/* 6 */
X#  ifndef TOS
X			{'p', 'P', C('p')},		/* + */
X#  endif
X			{'1', M('1'), '1'},		/* 1 */
X			{'2', M('2'), '2'},		/* 2 */
X			{'3', M('3'), '3'},		/* 3 */
X			{'i', 'I', C('i')},		/* Ins */
X			{'.', ':', ':'}			/* Del */
X};
X
X/*
X * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
X * meaning unless assigned one by a keyboard conversion table, so the
X * keyboard BIOS normally does not return a character code when Alt-letter
X * is pressed.	So, to interpret unassigned Alt-letters, we must use a
X * scan code table to translate the scan code into a letter, then set the
X * "meta" bit for it.  -3.
X */
X#define SCANLO		0x10
X#define SCANHI		0x32
X#define SCANKEYS	(SCANHI - SCANLO + 1)
X#define inmap(x)	(SCANLO <= (x) && (x) <= SCANHI)
X
Xstatic const char scanmap[SCANKEYS] = { 	/* ... */
X	'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
X	0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
X	0, '\\', 'z','x','c','v','b','N','m' 	/* ... */
X};
X
X# ifdef DGK
X/*
X * BIOSgetch gets keys directly with a BIOS call.
X */
X#define SHIFT		(0x1 | 0x2)
X#define CTRL		0x4
X#define ALT		0x8
X
Xstatic char
XBIOSgetch() {
X	unsigned char scan, shift, ch;
X	const struct pad *kpad;
X
X#  ifdef OS2
X	KBDKEYINFO CharData;
X	USHORT IOWait = 0;
X	HKBD KbdHandle = 0;
X
X	KbdCharIn(&CharData,IOWait,KbdHandle);
X	ch = CharData.chChar;
X	scan = CharData.chScan;
X	shift = CharData.fsState;
X#  else /* OS2 */
X#   ifdef TOS
X	long  x;
X#   else
X	union REGS regs;
X#   endif
X
X	/* Get scan code.
X	 */
X#   ifdef TOS
X	x = Crawcin();
X	ch = x & 0x0ff;
X	scan = (x & 0x00ff0000L) >> 16;
X#   else
X	regs.h.ah = READCHAR;
X	int86(KEYBRD_BIOS, &regs, &regs);
X	ch = regs.h.al;
X	scan = regs.h.ah;
X#   endif
X	/* Get shift status.
X	 */
X#   ifdef TOS
X	shift = Kbshift(-1);
X#   else
X	regs.h.ah = GETKEYFLAGS;
X	int86(KEYBRD_BIOS, &regs, &regs);
X	shift = regs.h.al;
X#   endif
X#  endif /* OS2 */
X
X	/* Translate keypad keys */
X	if (iskeypad(scan)) {
X		kpad = flags.num_pad ? numpad : keypad;
X		if (shift & SHIFT)
X			ch = kpad[scan - KEYPADLO].shift;
X		else if (shift & CTRL)
X			ch = kpad[scan - KEYPADLO].cntrl;
X		else
X			ch = kpad[scan - KEYPADLO].normal;
X	}
X	/* Translate unassigned Alt-letters */
X	if ((shift & ALT) && !ch) {
X		if (inmap(scan))
X			ch = scanmap[scan - SCANLO];
X		return (isprint(ch) ? M(ch) : ch);
X	}
X	return ch;
X}
X
Xstatic char
XDOSgetch() {
X# ifdef TOS
X	return (Crawcin() & 0x007f);
X# else
X#  ifdef OS2
X	KBDKEYINFO CharData;
X	USHORT IOWait = 0;
X	HKBD KbdHandle = 0;
X
X	KbdCharIn(&CharData,IOWait,KbdHandle);
X	if (CharData.chChar == 0) {	/* an extended code -- not yet supported */
X		KbdCharIn(&CharData,IOWait,KbdHandle);	   /* eat the next character */
X		CharData.chChar = 0;		/* and return a 0 */
X	}
X	return (CharData.chChar);
X#  else
X	union REGS regs;
X	char ch;
X	struct pad (*kpad)[PADKEYS];
X
X	regs.h.ah = DIRECT_INPUT;
X	intdos(&regs, &regs);
X	ch = regs.h.al;
X
X	/*
X	 * The extended codes for Alt-shifted letters, and unshifted keypad
X	 * and function keys, correspond to the scan codes.  So we can still
X	 * translate the unshifted cursor keys and Alt-letters.  -3.
X	 */
X	if (ch == 0) {		/* an extended key */
X		regs.h.ah = DIRECT_INPUT;
X		intdos(&regs, &regs);	/* get the extended key code */
X		ch = regs.h.al;
X
X		if (iskeypad(ch)) {	/* unshifted keypad keys */
X			kpad = (void *)(flags.num_pad ? numpad : keypad);
X			ch = (*kpad)[ch - KEYPADLO].normal;
X		} else if (inmap(ch)) { /* Alt-letters */
X			ch = scanmap[ch - SCANLO];
X			if (isprint(ch)) ch = M(ch);
X		} else ch = 0;		/* munch it */
X	}
X	return (ch);
X#  endif /* OS2 */
X# endif /* TOS */
X}
X
X
X#  ifndef TOS
X
X#   ifdef __TURBOC__
X#define switchar()	(char)getswitchar()
X#   else
X#    ifndef OS2
Xstatic char
Xswitchar()
X{
X	union REGS regs;
X
X	regs.x.ax = GETSWITCHAR;
X	intdos(&regs, &regs);
X	return regs.h.dl;
X}
X#    endif /* OS2 */
X#   endif /* __TURBOC__ */
X# endif  /* TOS */
X
Xstatic const char *COMSPEC = 
X# ifdef TOS
X"SHELL";
X# else
X"COMSPEC";
X# endif
X
X#define getcomspec() getenv(COMSPEC)
X
X# ifdef SHELL
Xint
Xdosh() {
X	extern char orgdir[];
X	char *comspec;
X
X	if (comspec = getcomspec()) {
X#  if defined(DGK) && !defined(TOS)	/* TOS has a variety of shells */
X		settty("To return to NetHack, enter \"exit\" at the DOS prompt.\n");
X#  else
X		settty((char *)0);
X#  endif /* DGK */
X		chdirx(orgdir, 0);
X		if (spawnl(P_WAIT, comspec, comspec, NULL) < 0) {
X			Printf("\nCan't spawn \"%s\"!\n", comspec);
X			flags.toplin = 0;
X			more();
X		}
X#ifdef TOS
X/* Some shells (e.g. Gulam) turn the cursor off when they exit */
X		if (flags.IBMBIOS) {
X			(void)Cursconf(1, -1);
X			get_scr_size(); /* maybe they changed the screen */
X		}
X#else
X		gettty(); /* ctrl-P might get turned back on (TH) */
X		get_scr_size(); /* maybe the screen mode changed (TH) */
X#endif
X		chdirx(hackdir, 0);
X		start_screen();
X		docrt();
X	} else
X#  ifdef OS2
X		pline("Can't execute CMD.EXE");
X#  else
X#   ifdef TOS
X		pline("Can't find SHELL.");
X#   else
X		pline("Can't find COMSPEC.");
X#   endif
X#  endif /* OS2 */
X	return 0;
X}
X# endif /* SHELL */
X
X#ifndef TOS
X
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X#   ifdef OS2
X	struct {
X		ULONG  idFileSystem;
X		ULONG  cSectorUnit;
X		ULONG  cUnit;
X		ULONG  cUnitAvail;
X		USHORT cbSector;
X	} FSInfoBuf;
X	USHORT DriveNumber, FSInfoLevel = 1, res;
X
X	if (path[0] && path[1] == ':')
X		DriveNumber = (toupper(path[0]) - 'A') + 1;
X	else
X		DriveNumber = 0;
X	res = DosQFSInfo(DriveNumber,FSInfoLevel,(PBYTE)&FSInfoBuf,sizeof(FSInfoBuf));
X	if (res)
X		return -1L;		/* error */
X	else
X		return ((long) FSInfoBuf.cSectorUnit * FSInfoBuf.cUnitAvail *
X			       FSInfoBuf.cbSector);
X#   else /* OS2 */
X	union REGS regs;
X
X	regs.h.ah = FREESPACE;
X	if (path[0] && path[1] == ':')
X		regs.h.dl = (toupper(path[0]) - 'A') + 1;
X	else
X		regs.h.dl = 0;
X	intdos(&regs, &regs);
X	if (regs.x.ax == 0xFFFF)
X		return -1L;		/* bad drive number */
X	else
X		return ((long) regs.x.bx * regs.x.cx * regs.x.ax);
X#   endif /* OS2 */
X}
X
X#   ifdef OS2
XFILEFINDBUF ResultBuf;
XHDIR DirHandle;
X#   endif
X
X/* Functions to get filenames using wildcards
X */
Xstatic int
Xfindfirst(path)
Xchar *path;
X{
X#   ifdef OS2
X	USHORT res, SearchCount = 1;
X
X	DirHandle = 1;
X	res = DosFindFirst((PSZ)path,&DirHandle,0,&ResultBuf,sizeof(FILEFINDBUF),&SearchCount,0L);
X	return(!res);
X#   else
X	union REGS regs;
X	struct SREGS sregs;
X
X	regs.h.ah = FINDFIRST;
X	regs.x.cx = 0;		/* attribute: normal files */
X	regs.x.dx = FP_OFF(path);
X	sregs.ds = FP_SEG(path);
X	intdosx(&regs, &regs, &sregs);
X	return !regs.x.cflag;
X#   endif /* OS2 */
X}
X
Xstatic int
Xfindnext() {
X#   ifdef OS2
X	USHORT res, SearchCount = 1;
X
X	res = DosFindNext(DirHandle,&ResultBuf,sizeof(FILEFINDBUF),&SearchCount);
X	return(!res);
X#   else
X	union REGS regs;
X
X	regs.h.ah = FINDNEXT;
X	intdos(&regs, &regs);
X	return !regs.x.cflag;
X#   endif /* OS2 */
X}
X
X#   ifndef OS2
X/* Get disk transfer area, Turbo C already has getdta */
Xstatic char *
Xgetdta() {
X	union REGS regs;
X	struct SREGS sregs;
X	char *ret;
X
X	regs.h.ah = GETDTA;
X	intdosx(&regs, &regs, &sregs);
X#    ifdef MK_FP
X	ret = MK_FP(sregs.es, regs.x.bx);
X#    else
X	FP_OFF(ret) = regs.x.bx;
X	FP_SEG(ret) = sregs.es;
X#    endif
X	return ret;
X}
X#   endif /* OS2 */
X
X#  else /* TOS */
X
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X	int drive = 0;
X	struct {
X		long freal; /*free allocation units*/
X		long total; /*total number of allocation units*/
X		long bps;   /*bytes per sector*/
X		long pspal; /*physical sectors per allocation unit*/
X	} freespace;
X	if (path[0] && path[1] == ':')
X		drive = (toupper(path[0]) - 'A') + 1;
X	if (Dfree(&freespace,drive)<0) return -1;
X	return freespace.freal*freespace.bps*freespace.pspal;
X}
X
Xstatic int
Xfindfirst(path)
Xchar *path;
X{
X	return (Fsfirst(path, 0) == 0);
X}
X
Xstatic int findnext() {
X	return (Fsnext() == 0);
X}
X
Xstatic char *
Xgetdta() {
X	return (char *) Fgetdta();
X}
X
X#  endif /* TOS */
X
Xlong
Xfilesize(file)
Xchar *file;
X{
X#  ifndef OS2
X	char *dta;
X#  endif
X
X	if (findfirst(file)) {
X#  ifdef OS2
X		return  (* (long *) (ResultBuf.cbFileAlloc));
X#  else
X		dta = getdta();
X		return  (* (long *) (dta + 26));
X#  endif
X	} else
X		return -1L;
X}
X
Xvoid
Xeraseall(path, files)
Xconst char *path, *files;
X{
X#  ifndef OS2
X	char *dta;
X#  endif
X	char buf[PATHLEN];
X
X#  ifndef OS2
X	dta = getdta();
X#  endif
X	Sprintf(buf, "%s%s", path, files);
X	if (findfirst(buf))
X		do {
X			Sprintf(buf, "%s%s", path,
X#  ifdef OS2
X				ResultBuf.achName
X#  else
X				dta + 30
X#  endif
X				);
X			(void) unlink(buf);
X		} while (findnext());
X	return;
X}
X
X/* Rewritten for version 3.3 to be faster
X */
Xvoid
Xcopybones(mode)
Xint mode;
X{
X	char from[PATHLEN], to[PATHLEN], last[13];
X	char *frompath, *topath;
X#  ifndef OS2
X	char *dta;
X#  endif
X#  ifndef TOS
X	int status;
X	char copy[8], *comspec;
X	extern saveprompt;
X#  endif
X
X	if (!ramdisk)
X		return;
X
X	/* Find the name of the last file to be transferred
X	 */
X	frompath = (mode != TOPERM) ? permbones : levels;
X#  ifndef OS2
X	dta = getdta();
X#  endif
X	last[0] = '\0';
X	Sprintf(from, "%s%s", frompath, allbones);
X	topath = (mode == TOPERM) ? permbones : levels;
X#  ifdef TOS
X	eraseall(topath, allbones);
X#  endif
X	if (findfirst(from))
X		do {
X#  ifdef TOS
X			Sprintf(from, "%s%s", frompath, dta+30); 
X			Sprintf(to, "%s%s", topath, dta+30);
X			if (_copyfile(from, to))
X				goto error_copying;
X#  endif
X			Strcpy(last,
X#  ifdef OS2
X				ResultBuf.achName
X#  else
X				dta + 30
X#  endif
X				);
X		} while (findnext());
X#  ifdef TOS
X	else
X		return;
X#  else
X	if (last[0]) {
X		Sprintf(copy, "%cC copy",
X#   ifdef OS2
X			'/'
X#   else
X			switchar()
X#   endif
X			);
X
X		/* Remove any bones files in `to' directory.
X		 */
X		eraseall(topath, allbones);
X
X		/* Copy `from' to `to' */
X		Sprintf(to, "%s%s", topath, allbones);
X		comspec = getcomspec();
X		status =spawnl(P_WAIT, comspec, comspec, copy, from,
X			to, "> nul", NULL);
X	} else
X		return;
X#  endif /* TOS */
X
X	/* See if the last file got there.  If so, remove the ramdisk bones
X	 * files.
X	 */
X	Sprintf(to, "%s%s", topath, last);
X	if (findfirst(to)) {
X		if (mode == TOPERM)
X			eraseall(frompath, allbones);
X		return;
X	}
X
X#  ifdef TOS
Xerror_copying:
X#  endif
X	/* Last file didn't get there.
X	 */
X	Sprintf(to, "%s%s", topath, allbones);
X	msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to);
X#  ifndef TOS
X	if (status < 0)
X	    msmsg("can't spawn \"%s\"!", comspec);
X	else
X#  endif
X	    msmsg((freediskspace(topath) < filesize(from)) ?
X			"insufficient disk space." : "bad path(s)?");
X	if (mode == TOPERM) {
X		msmsg("Bones will be left in \"%s\"\n",
X			*levels ? levels : hackdir);
X	} else {
X		/* Remove all bones files on the RAMdisk */
X		eraseall(levels, allbones);
X		playwoRAMdisk();
X	}
X	return;
X}
X
X#if 0 /* defined(MSDOS) && !defined(TOS) && !defined(OS2) */
Xboolean
Xremoveable_drive(drive)
Xchar drive;
X/* check whether current drive is a fixed disk,
X   so we don't ask the player to insert one */
X{
X	union REGS regs;
X	char *fat_id;
X
X	regs.h.ah = FATINFO;
X	intdos(&regs, &regs);
X	/* also returns size info, as
X	   AL (sectors/cluster) * CX (bytes/sector) * DX (clusters/disk) */
X#   ifdef MK_FP
X	fat_id = MK_FP(sregs.ds, regs.x.bx);
X#   else
X	FP_OFF(fat_id) = regs.x.bx;
X	FP_SEG(fat_id) = sregs.ds;
X#   endif
X	return (*fat_id != 0xF8);
X}
X#endif /* 0 */
X
Xvoid
XplaywoRAMdisk() {
X	msmsg("Do you wish to play without a RAMdisk? ");
X
X	/* Set ramdisk false *before* exit-ing (because msexit calls
X	 * copybones)
X	 */
X	ramdisk = FALSE;
X	if (yn() != 'y') {
X		settty("Be seeing you...\n");
X		exit(0);
X	}
X	set_lock_and_bones();
X	return;
X}
X
Xint
XsaveDiskPrompt(start)
Xint start;
X{
X	extern saveprompt;
X	char buf[BUFSIZ], *bp;
X	int fd;
X
X	if (saveprompt) {
X		/* Don't prompt if you can find the save file */
X		if ((fd = open(SAVEF, 0)) >= 0) {
X			(void) close(fd);
X			return 1;
X		}
X		remember_topl();
X		home();
X		cl_end();
X		msmsg("If save file is on a save disk, insert that disk now.\n");
X		cl_end();
X		msmsg("File name (default \"%s\"%s) ? ", SAVEF,
X			start ? "" : ", <Esc> cancels save");
X		getlin(buf);
X		home();
X		cl_end();
X		curs(1, 2);
X		cl_end();
X		if (!start && *buf == '\033')
X			return 0;
X
X		/* Strip any whitespace. Also, if nothing was entered except
X		 * whitespace, do not change the value of SAVEF.
X		 */
X		for (bp = buf; *bp; bp++)
X			if (!isspace(*bp)) {
X				strncpy(SAVEF, bp, PATHLEN);
X				break;
X			}
X	}
X	return 1;
X}
X
X/* Return 1 if the record file was found */
Xstatic boolean
Xrecord_exists() {
X	int fd;
X#  ifdef OS2_CODEVIEW
X	char tmp[PATHLEN];
X
X	Strcpy(tmp,hackdir);
X	append_slash(tmp);
X	Strcat(tmp,RECORD);
X	if ((fd = open(tmp, 0)) >= 0) {
X#  else
X	if ((fd = open(RECORD, 0)) >= 0) {
X#  endif
X		(void) close(fd);
X		return TRUE;
X	}
X	return FALSE;
X}
X
X#  ifdef TOS
X#define comspec_exists() 1
X#  else
X/* Return 1 if the comspec was found */
Xstatic boolean
Xcomspec_exists() {
X	int fd;
X	char *comspec;
X
X	if (comspec = getcomspec())
X		if ((fd = open(comspec, 0)) >= 0) {
X			(void) close(fd);
X			return TRUE;
X		}
X	return FALSE;
X}
X#  endif
X
X/* Prompt for game disk, then check for record file.
X */
Xvoid
XgameDiskPrompt() {
X	extern int saveprompt;
X
X	if (saveprompt) {
X		if (record_exists() && comspec_exists())
X			return;
X		(void) putchar('\n');
X		getreturn("when the game disk has been inserted");
X	}
X	if (comspec_exists() && record_exists())
X		return;
X
X	if (!comspec_exists())
X		msmsg("\n\nWARNING: can't find command processor \"%s\"!\n", getcomspec());
X        if (!record_exists())
X		msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD);
X	msmsg("If the game disk is not in, insert it now.\n");
X	getreturn("to continue");
X	return;
X}
X
X# endif /* DGK */
X
X/* Read configuration */
Xvoid
Xread_config_file() {
X# ifdef DGK
X	char	tmp_ramdisk[PATHLEN];
X	extern	int saveprompt;
X# else
X#define fopenp fopen
X# endif
X	char	tmp_levels[PATHLEN];
X	char	buf[BUFSZ], *bufp;
X	FILE	*fp;
X	extern	char plname[];
X
X# ifdef DGK
X	tmp_ramdisk[0] = 0;
X# endif
X	tmp_levels[0] = 0;
X	if ((fp = fopenp(configfile, "r")) == (FILE *)0) {
X		msmsg("Warning: no configuration file!\n");
X		getreturn("to continue");
X		return;
X	}
X	while (fgets(buf, BUFSZ, fp)) {
X		if (*buf == '#')
X			continue;
X
X		/* remove trailing whitespace
X		 */
X		bufp = index(buf, '\n');
X		while (bufp > buf && isspace(*bufp))
X			bufp--;
X		if (bufp == buf)
X			continue;		/* skip all-blank lines */
X		else
X			*(bufp + 1) = 0;	/* 0 terminate line */
X
X		/* find the '=' */
X		if (!(bufp = strchr(buf, '='))) {
X			msmsg("Bad option line: \"%s\"\n", buf);
X			getreturn("to continue");
X			continue;
X		}
X		
X		/* skip  whitespace between '=' and value */
X		while (isspace(*++bufp))
X			;
X
X		/* Go through possible variables */
X		if (!strncmp(buf, "HACKDIR", 4)) {
X			strncpy(hackdir, bufp, PATHLEN);
X		
X# ifdef DGK
X		} else if (!strncmp(buf, "RAMDISK", 3)) {
X			strncpy(tmp_ramdisk, bufp, PATHLEN);
X# endif
X
X		} else if (!strncmp(buf, "LEVELS", 4)) {
X			strncpy(tmp_levels, bufp, PATHLEN);
X
X		} else if (!strncmp(buf, "OPTIONS", 4)) {
X			parseoptions(bufp, TRUE);
X			if (plname[0])		/* If a name was given */
X				plnamesuffix();	/* set the character class */
X
X		} else if (!strncmp(buf, "SAVE", 4)) {
X# ifdef DGK
X			char *ptr;
X			if (ptr = index(bufp, ';')) {
X				*ptr = '\0';
X				if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
X					saveprompt = FALSE;
X			}
X# endif /* DGK */
X			(void) strncpy(SAVEF, bufp, PATHLEN);
X			(void) strncpy(SAVEP, bufp, PATHLEN);
X			append_slash(SAVEF);
X			append_slash(SAVEP);
X		} else if (!strncmp(buf, "GRAPHICS", 4)) {
X			unsigned int translate[MAXPCHARS+1];
X			int lth;
X#ifdef OVERLAY
X			/* THIS is what I call a stupid hack, but MSC cannot survive
X			   the overlays without it (TH) */
X			lth = sscanf(bufp,
X	"%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[0], &translate[1], &translate[2],
X				&translate[3], &translate[4], &translate[5],
X				&translate[6], &translate[7], &translate[8],
X				&translate[9], &translate[10], &translate[11]);
X			lth += sscanf(bufp,
X	"%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[12], &translate[13], &translate[14],
X				&translate[15], &translate[16], &translate[17],
X				&translate[18], &translate[19], &translate[20],
X				&translate[21], &translate[22], &translate[23]);
X			lth += sscanf(bufp,
X	"%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[24], &translate[25], &translate[26],
X				&translate[27], &translate[28], &translate[29],
X				&translate[30], &translate[31], &translate[32],
X				&translate[33], &translate[34]);
X#else
X		     lth = sscanf(bufp,
X	"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
X				&translate[0], &translate[1], &translate[2],
X				&translate[3], &translate[4], &translate[5],
X				&translate[6], &translate[7], &translate[8],
X				&translate[9], &translate[10], &translate[11],
X				&translate[12], &translate[13], &translate[14],
X				&translate[15], &translate[16], &translate[17],
X				&translate[18], &translate[19], &translate[20],
X				&translate[21], &translate[22], &translate[23],
X				&translate[24], &translate[25], &translate[26],
X				&translate[27], &translate[28], &translate[29],
X				&translate[30], &translate[31], &translate[32],
X				&translate[33], &translate[34]);
X#endif /* OVERLAY */
X			if (lth <= 0) {
X				msmsg ("Syntax error in GRAPHICS\n");
X				getreturn("to continue");
X			}
X			assign_graphics(translate, lth);
X		} else {
X			msmsg("Bad option line: \"%s\"\n", buf);
X			getreturn("to continue");
X		}
X	}
X	(void) fclose(fp);
X
X# ifdef DGK
X	Strcpy(permbones, tmp_levels);
X	if (tmp_ramdisk[0]) {
X		Strcpy(levels, tmp_ramdisk);
X		if (strcmp(permbones, levels))		/* if not identical */
X			ramdisk = TRUE;
X	} else
X# endif /* DGK */
X		Strcpy(levels, tmp_levels);
X	Strcpy(bones, levels);
X	return;
X}
X
X# ifdef DGK
X/* Set names for bones[] and lock[]
X */
Xvoid
Xset_lock_and_bones() {
X	if (!ramdisk) {
X		Strcpy(levels, permbones);
X		Strcpy(bones, permbones);
X	}
X	append_slash(permbones);
X	append_slash(levels);
X	append_slash(bones);
X	Strcat(bones, allbones);
X	Strcpy(lock, levels);
X	Strcat(lock, alllevels);
X	return;
X}
X# endif /* DGK */
X
X/* Add a backslash to any name not ending in /, \ or :   There must
X * be room for the \
X */
Xvoid
Xappend_slash(name)
Xchar *name;
X{
X	char *ptr;
X
X	if (!*name)
X		return;
X	ptr = name + (strlen(name) - 1);
X	if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
X		*++ptr = '\\';
X		*++ptr = '\0';
X	}
X	return;
X}
X
Xvoid
Xgetreturn(str)
Xconst char *str;
X{
X# ifdef TOS
X	msmsg("Hit <Return> %s.", str);
X# else
X	msmsg("Hit <Enter> %s.", str);
X# endif
X	while (Getchar() != '\n') ;
X	return;
X}
X
Xvoid
Xmsmsg VA_DECL(const char *, fmt)
X	VA_START(fmt);
X	VA_INIT(fmt, const char *);
X	Vprintf(fmt, VA_ARGS);
X	flushout();
X	VA_END();
X	return;
X}
X
X/* Chdrive() changes the default drive.
X */
X# ifndef __TURBOC__
X#  ifndef OS2
X#define SELECTDISK	0x0E
X#  endif
Xvoid
Xchdrive(str)
Xchar *str;
X{
X	char *ptr;
X#  ifndef TOS
X#   ifndef OS2
X	union REGS inregs;
X#   endif
X#  endif
X	char drive;
X
X	if ((ptr = index(str, ':')) != NULL) {
X		drive = toupper(*(ptr - 1));
X#  ifdef TOS
X		(void)Dsetdrv(drive - 'A');
X#  else
X#   ifdef OS2
X		DosSelectDisk((USHORT)(drive - 'A' + 1));
X#   else
X		inregs.h.ah = SELECTDISK;
X		inregs.h.dl = drive - 'A';
X		intdos(&inregs, &inregs);
X#   endif
X#  endif
X	}
X	return;
X}
X# else
Xextern int setdisk(int);
X
Xvoid
Xchdrive(str)
Xchar *str;
X{
X	if (str[1] == ':')
X		(void)setdisk((int)(toupper(str[0]) - 'A'));
X	return;
X}
X# endif
X
X# ifndef TOS
X/* Use the IOCTL DOS function call to change stdin and stdout to raw
X * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
X * freeing us of ^P toggling 'echo to printer'.
X * Thanks to Mark Zbikowski (markz@microsoft.UUCP).
X */
X
X#  ifndef OS2
X#define DEVICE		0x80
X#define RAW		0x20
X#define IOCTL		0x44
X#define STDIN		fileno(stdin)
X#define STDOUT		fileno(stdout)
X#define GETBITS		0
X#define SETBITS		1
X#  endif
X
Xstatic unsigned	int old_stdin, old_stdout;
X
Xvoid
Xdisable_ctrlP() {
X#  ifdef OS2
X	KBDINFO KbdInfo;
X	HKBD KbdHandle = 0;
X#  endif
X
X#  ifdef DGK
X	if (!flags.rawio) return;
X#  endif
X#  ifdef OS2
X	KbdInfo.cb = sizeof(KbdInfo);
X	KbdGetStatus(&KbdInfo,KbdHandle);
X	KbdInfo.fsMask &= 0xFFF7; /* ASCII off */
X	KbdInfo.fsMask |= 0x0004; /* BINARY on */
X	KbdSetStatus(&KbdInfo,KbdHandle);
X#  else
X	old_stdin = ioctl(STDIN, GETBITS, 0);
X	old_stdout = ioctl(STDOUT, GETBITS, 0);
X	if (old_stdin & DEVICE)
X		ioctl(STDIN, SETBITS, old_stdin | RAW);
X	if (old_stdout & DEVICE)
X		ioctl(STDOUT, SETBITS, old_stdout | RAW);
X#  endif /* OS2 */
X	return;
X}
X
Xvoid
Xenable_ctrlP() {
X#  ifdef OS2
X	KBDINFO KbdInfo;
X	HKBD KbdHandle = 0;
X#  endif
X
X#  ifdef DGK
X	if (!flags.rawio) return;
X#  endif
X#  ifdef OS2
X	KbdInfo.cb = sizeof(KbdInfo);
X	KbdGetStatus(&KbdInfo,KbdHandle);
X	KbdInfo.fsMask &= 0xFFFB; /* BINARY off */
X	KbdInfo.fsMask |= 0x0008; /* ASCII on */
X	KbdSetStatus(&KbdInfo,KbdHandle);
X#  else
X	if (old_stdin)
X		(void) ioctl(STDIN, SETBITS, old_stdin);
X	if (old_stdout)
X		(void) ioctl(STDOUT, SETBITS, old_stdout);
X#  endif
X	return;
X}
X
X#  ifndef OS2
Xstatic unsigned int
Xioctl(handle, mode, setvalue)
Xint handle, mode;
Xunsigned setvalue;
X{
X	union REGS regs;
X
X	regs.h.ah = IOCTL;
X	regs.h.al = mode;
X	regs.x.bx = handle;
X	regs.h.dl = setvalue;
X	regs.h.dh = 0;			/* Zero out dh */
X	intdos(&regs, &regs);
X	return (regs.x.dx);
X}
X#  endif /* OS2 */
X# endif /* TOS */
X
X# ifdef DGK
X/* Follow the PATH, trying to fopen the file.
X */
X#  ifdef TOS
X#define PATHSEP	','
X#  else
X#define PATHSEP	';'
X#  endif
X
XFILE *
Xfopenp(name, mode)
Xconst char *name, *mode;
X{
X	char buf[BUFSIZ], *bp, *pp, lastch = 0;
X	FILE *fp;
X
X	/* Try the default directory first.  Then look along PATH.
X	 */
X	Strcpy(buf, name);
X	if (fp = fopen(buf, mode))
X		return fp;
X	else {
X		pp = getenv("PATH");
X		while (pp && *pp) {
X			bp = buf;
X			while (*pp && *pp != PATHSEP)
X				lastch = *bp++ = *pp++;
X			if (lastch != '\\' && lastch != '/')
X				*bp++ = '\\';
X			Strcpy(bp, name);
X			if (fp = fopen(buf, mode))
X				return fp;
X			if (*pp)
X				pp++;
X		}
X	}
X#  ifdef OS2_CODEVIEW /* one more try for hackdir */
X	Strcpy(buf,hackdir);
X	append_slash(buf);
X	Strcat(buf,name);
X	if(fp = fopen(buf,mode))
X		return fp;
X#  endif
X	return (FILE *)0;
X}
X# endif /* DGK */
X
X/* Chdir back to original directory
X */
X#undef exit
X# ifdef TOS
Xextern boolean run_from_desktop;	/* set in pcmain.c */
X# endif
X
Xvoid exit(int);
Xvoid
Xmsexit(code)
Xint code;
X{
X# ifdef CHDIR
X	extern char orgdir[];
X# endif
X
X	flushout();
X# ifndef TOS
X	enable_ctrlP();		/* in case this wasn't done */
X# endif
X# ifdef DGK
X	if (ramdisk) copybones(TOPERM);
X# endif
X# ifdef CHDIR
X	chdir(orgdir);		/* chdir, not chdirx */
X	chdrive(orgdir);
X# endif
X# ifdef TOS
X	if (run_from_desktop)
X	    getreturn("to continue"); /* so the user can read the score list */
X#  ifdef TEXTCOLOR
X	if (flags.IBMBIOS && flags.use_color)
X		restore_colors();
X#  endif
X# endif
X	exit(code);
X	return;
X}
X
X#  ifdef DGK		/* for flags.IBMBIOS */
Xvoid
Xget_scr_size()
X{
X#   ifdef OS2
X	VIOMODEINFO ModeInfo;
X	HVIO VideoHandle = 0;
X
X	ModeInfo.cb = sizeof(ModeInfo);
X
X	(void) VioGetMode(&ModeInfo,VideoHandle);
X
X	CO = ModeInfo.col;
X	LI = ModeInfo.row;
X#   else
X#    ifndef TOS
X	union REGS regs;
X
X	if (!flags.IBMBIOS) {		/* assume standard screen size */
X		CO = 80;
X		LI = 24;
X		return;
X	}
X
X	regs.x.ax = FONTINFO;
X	regs.x.bx = 0;			/* current ROM BIOS font */
X	regs.h.dl = 24;			/* default row count */
X					/* in case no EGA/MCGA/VGA */
X	int86(VIDEO_BIOS, &regs, &regs); /* Get Font Information */
X
X	/* MDA/CGA/PCjr ignore INT 10h, Function 11h, but since we
X	 * cleverly loaded up DL with the default, everything's fine.
X	 *
X	 * Otherwise, DL now contains rows - 1.  Also, CX contains the
X	 * points (bytes per character) and ES:BP points to the font
X	 * table.  -3.
X	 */
X
X	regs.h.ah = GETMODE;
X	int86(VIDEO_BIOS, &regs, &regs); /* Get Video Mode */
X
X	/* This goes back all the way to the original PC.  Completely
X	 * safe.  AH contains # of columns, AL contains display mode,
X	 * and BH contains the active display page.
X	 */
X
X	LI = regs.h.dl + 1;
X	CO = regs.h.ah;
X#    else  /* TOS */
X	init_aline();
X	LI = (*((WORD  *)(_a_line + -42L))) + 1;
X	CO = (*((WORD  *)(_a_line + -44L))) + 1;
X#    endif /* TOS */
X#   endif /* OS2 */
X}
X
X#   ifndef TOS
Xvoid
Xgotoxy(x,y)
Xint x,y;
X{
X#    ifdef OS2
X	HVIO VideoHandle = 0;
X
X	x--; y--;			/* (0,0) is upper right corner */
X
X	(void) VioSetCurPos(x, y, VideoHandle);
X#    else
X	union REGS regs;
X
X	x--; y--;			/* (0,0) is upper right corner */
X
X	regs.h.ah = SETCURPOS;
X	regs.h.bh = 0;			/* display page */
X	regs.h.dh = y;			/* row */
X	regs.h.dl = x;			/* column */
X	int86(VIDEO_BIOS, &regs, &regs); /* Set Cursor Position */
X
X	/* This, too, goes back all the way to the original PC.  If
X	 * we ever get so fancy as to swap display pages (i doubt it),
X	 * then we'll need to set BH appropriately.  This function
X	 * returns nothing.  -3.
X	 */
X#    endif /* OS2 */
X}
X#   endif /* TOS */
X#  endif /* DGK */
X
X#endif /* MSDOS */
X
X
X#ifdef TOS
X# define BIGBUF  8192
X
Xint
X_copyfile(from, to)
Xchar *from, *to;
X{
X	int fromfd, tofd, r;
X	char *buf;
X
X	if ((fromfd = open(from, O_RDONLY|O_BINARY, 0)) < 0)
X		return -1;
X	if ((tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, FCMASK)) < 0)
X		return -1;
X	if (!(buf = (char *)malloc((size_t)BIGBUF)))
X		return -1;
X	while ( (r = read(fromfd, buf, BIGBUF)) > 0)
X		write(tofd, buf, r);
X	close(fromfd);
X	close(tofd);
X	free(buf);
X	return 0;	/* successful */
X}
X
Xint kbhit()
X{
X	return Cconis();
X}
X
Xstatic void
Xinit_aline()
X{
X# ifdef __GNUC__
X	asm(" .word 0xa000; movel d0, __a_line");
X# else
X	asm(" .dc.w 0xa000");	/* tweak as necessary for your compiler */
X	asm(" move.l d0, __a_line");
X# endif
X}
X
X# ifdef TEXTCOLOR
Xstatic unsigned orig_color[4] = {-1, -1, -1, -1};
Xstatic unsigned new_color[4] = { 0x0, 0x730, 0x047, 0x555 };
Xstatic int numcolors = 2;
X
Xvoid set_colors()
X{
X	int i;
X	char *s;
X	static char newhe[] = "\033q\033b\017\033c0";
X
X	if (!flags.IBMBIOS)
X		return;
X	init_aline();
X	numcolors = 1 << (((unsigned char *) _a_line)[1]);
X	if (numcolors == 2) {			/* mono */
X		flags.use_color = FALSE;
X		return;
X	}
X	else if (numcolors == 4) {
X		for (i = 0; i < 4; i++)
X			orig_color[i] = Setcolor(i, new_color[i]);
X	}
X	else {
X		orig_color[0] = Setcolor(0, new_color[0]);
X		orig_color[1] = Setcolor(15, 0x777);
X		hilites[0] = "";
X		for (i = 1; i < 16; i++) {
X			s = (char *) alloc(sizeof("\033b0"));
X			sprintf(s, "\033b%c", '0'+i);
X			hilites[i] = s;
X		}
X		HE = newhe;
X	}
X}
X
Xvoid restore_colors()
X{
X	int i;
X
X	if (numcolors == 2)
X		return;
X	else if (numcolors == 4)
X		for (i = 0; i < 4; i++)
X			(void) Setcolor(i, orig_color[i]);
X	else {
X		(void) Setcolor(0, orig_color[0]);
X		(void) Setcolor(15, orig_color[1]);
X	}
X}
X# endif /* TEXTCOLOR */
X#endif /* TOS */
END_OF_FILE
if test 30281 -ne `wc -c <'others/msdos.c'`; then
    echo shar: \"'others/msdos.c'\" unpacked with wrong size!
fi
# end of 'others/msdos.c'
fi
if test -f 'src/restore.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/restore.c'\"
else
echo shar: Extracting \"'src/restore.c'\" \(25217 characters\)
sed "s/^X//" >'src/restore.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)restore.c	3.0	88/10/25
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include "hack.h"
X#include "lev.h"
X
X#ifdef WORM
X#include "wseg.h"
X#endif
X
Xstatic void FDECL(stuff_objs, (struct obj *));
Xstatic void NDECL(find_lev_obj);
X#ifndef NO_SIGNAL
Xstatic void NDECL(inven_inuse);
X#endif
Xstatic struct obj * FDECL(restobjchn, (int,BOOLEAN_P));
Xstatic struct monst * FDECL(restmonchn, (int,BOOLEAN_P));
Xstatic void FDECL(restgenoinfo, (int));
X
Xboolean restoring = FALSE;
X#ifdef TUTTI_FRUTTI
Xstatic struct fruit NEARDATA *oldfruit;
X#endif
Xstatic long NEARDATA omoves;
X
X/*
X * "stuff" objects back into containers (relink the fcobj list).
X */
Xstatic void
Xstuff_objs(cobj)
Xregister struct obj *cobj;
X{
X	register struct obj *otmp, *otmp2;
X
X	for(; cobj; cobj = cobj->nobj)
X	    if(Is_container(cobj))
X
X		for(otmp = cobj->nobj;
X		    otmp && otmp->cobj == (struct obj *) -1; otmp = otmp2) {
X
X		    otmp2 = otmp->nobj;
X
X		    otmp->cobj = cobj;
X		    cobj->nobj = otmp2;
X		    otmp->nobj = fcobj;
X		    fcobj = otmp;
X		}
X}
X
X/* Recalculate level.objects[x][y], since this info was not saved. */
Xstatic void
Xfind_lev_obj()
X{
X	register struct obj *fobjtmp = (struct obj *)0;
X	register struct obj *otmp;
X	int x,y;
X
X	for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
X		level.objects[x][y] = (struct obj *)0;
X
X	/* Reverse the entire fobj chain, which is necessary so that we can
X	 * place the objects in the proper order.
X	 */
X	while(otmp = fobj) {
X		fobj = otmp->nobj;
X		otmp->nobj = fobjtmp;
X		fobjtmp = otmp;
X	}
X	/* Set level.objects (as well as reversing the chain back again) */
X	while(otmp = fobjtmp) {
X		place_object(otmp, otmp->ox, otmp->oy);
X		fobjtmp = otmp->nobj;
X		otmp->nobj = fobj;
X		fobj = otmp;
X	}
X}
X
X#ifndef NO_SIGNAL
Xstatic void
Xinven_inuse()
X/* Things that were marked "in_use" when the game was saved (ex. via the
X * infamous "HUP" cheat) get used up here.
X */
X{
X	register struct obj *otmp, *otmp2;
X
X	for(otmp = invent; otmp; otmp = otmp2) {
X		otmp2 = otmp->nobj;
X		if(otmp->olet != ARMOR_SYM && otmp->olet != WEAPON_SYM
X			&& otmp->otyp != PICK_AXE && otmp->otyp != UNICORN_HORN
X			&& otmp->in_use) {
X			pline("Finishing off %s...", xname(otmp));
X			useup(otmp);
X		}
X	}
X}
X#endif
X
Xstatic struct obj *
Xrestobjchn(fd, ghostly)
Xregister int fd;
Xboolean ghostly;
X{
X	register struct obj *otmp, *otmp2;
X	register struct obj *first = 0;
X#ifdef TUTTI_FRUTTI
X	register struct fruit *oldf;
X#endif
X	int xl;
X#if defined(LINT) || defined(__GNULINT__)
X	/* suppress "used before set" warning from lint */
X	otmp2 = 0;
X#endif
X	while(1) {
X		mread(fd, (genericptr_t) &xl, sizeof(xl));
X		if(xl == -1) break;
X		otmp = newobj(xl);
X		if(!first) first = otmp;
X		else otmp2->nobj = otmp;
X		mread(fd, (genericptr_t) otmp, (unsigned) xl + sizeof(struct obj));
X		if(!otmp->o_id) otmp->o_id = flags.ident++;
X#ifdef TUTTI_FRUTTI
X		if(ghostly && otmp->otyp == SLIME_MOLD) {
X			for(oldf=oldfruit; oldf; oldf=oldf->nextf)
X				if (oldf->fid == otmp->spe) break;
X			if(!oldf) impossible("no old fruit?");
X			else otmp->spe = fruitadd(oldf->fname);
X		}
X#endif
X	/* Ghost levels get object age shifted from old player's clock to
X	 * new player's clock.  Assumption: new player arrived immediately
X	 * after old player died.
X	 */
X		if (ghostly) otmp->age = monstermoves-omoves+otmp->age;
X		otmp2 = otmp;
X	}
X	if(first && otmp2->nobj){
X		impossible("Restobjchn: error reading objchn.");
X		otmp2->nobj = 0;
X	}
X
X	stuff_objs(first);
X	return(first);
X}
X
Xstatic struct monst *
Xrestmonchn(fd, ghostly)
Xregister int fd;
Xboolean ghostly;
X{
X	register struct monst *mtmp, *mtmp2;
X	register struct monst *first = 0;
X	int xl;
X
X	struct permonst *monbegin;
X	off_t differ;
X
X	mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
X#if !defined(MSDOS) && !defined(M_XENIX) && !defined(THINKC4) && !defined(HPUX) && !defined(VAXC)
X	differ = (genericptr_t)(&mons[0]) - (genericptr_t)(monbegin);
X#else
X	differ = (long)(&mons[0]) - (long)(monbegin);
X#endif
X
X#if defined(LINT) || defined(__GNULINT__)
X	/* suppress "used before set" warning from lint */
X	mtmp2 = 0;
X#endif
X	while(1) {
X		mread(fd, (genericptr_t) &xl, sizeof(xl));
X		if(xl == -1) break;
X		mtmp = newmonst(xl);
X		if(!first) first = mtmp;
X		else mtmp2->nmon = mtmp;
X		mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
X		if(!mtmp->m_id)
X			mtmp->m_id = flags.ident++;
X#if !defined(MSDOS) && !defined(M_XENIX) && !defined(THINKC4) && !defined(HPUX) && !defined(VAXC)
X		/* ANSI type for differ is ptrdiff_t --
X		 * long may be wrong for segmented architecture --
X		 * may be better to cast pointers to (struct permonst *)
X		 * rather than (genericptr_t)
X		 * this code handles save file -- so any bug should glow
X		 * probably best not to keep lint from complaining
X		 */
X/*#ifdef LINT	/* possible compiler/hardware dependency - */
X/*		if (differ) mtmp->data = NULL;*/
X/*#else*/
X		mtmp->data = (struct permonst *)
X			((genericptr_t)mtmp->data + differ);
X/*#endif	/*LINT*/
X#else
X		mtmp->data = (struct permonst *)
X			((long) mtmp->data + differ);
X#endif
X		if(mtmp->minvent)
X			mtmp->minvent = restobjchn(fd, ghostly);
X		mtmp2 = mtmp;
X	}
X	if(first && mtmp2->nmon){
X		impossible("Restmonchn: error reading monchn.");
X		mtmp2->nmon = 0;
X	}
X	return(first);
X}
X
Xstatic void
Xrestgenoinfo(fd)
Xregister int fd;
X{
X	register int i;
X
X	for (i = 0; i < NUMMONS; i++)
X		mread(fd, (genericptr_t) &(mons[i].geno), sizeof(unsigned));
X}
X
Xint
Xdorecover(fd)
Xregister int fd;
X{
X	register int nfd;
X	int tmp;		/* not a register ! */
X	xchar ltmp;
X	unsigned int mid;		/* idem */
X	struct obj *otmp;
X#ifdef TUTTI_FRUTTI
X	struct fruit *fruit;
X#endif
X	struct flag oldflags;
X
X	oldflags = flags;
X
X#ifdef ZEROCOMP
X	minit();
X#endif
X	restoring = TRUE;
X	getlev(fd, 0, (xchar)0, FALSE);
X	invent = restobjchn(fd, FALSE);
X	for(otmp = invent; otmp; otmp = otmp->nobj)
X		if(otmp->owornmask)
X			setworn(otmp, otmp->owornmask);
X	fallen_down = restmonchn(fd, FALSE);
X	restgenoinfo(fd);
X	mread(fd, (genericptr_t) &tmp, sizeof tmp);
X#ifdef WIZARD
X	if(!wizard)
X#endif
X	    if(tmp != getuid()) {		/* strange ... */
X		(void) close(fd);
X		(void) unlink(SAVEF);
X#ifdef AMIGA_WBENCH
X		ami_wbench_unlink(SAVEF);
X#endif
X		(void) puts("Saved game was not yours.");
X		restoring = FALSE;
X		return(0);
X	    }
X	mread(fd, (genericptr_t) &flags, sizeof(struct flag));
X	/* Some config file and command line OPTIONS take precedence over
X	 * those in save file.
X	 */
X	flags.DECgraphics = oldflags.DECgraphics;
X	flags.IBMgraphics = oldflags.IBMgraphics;
X#if defined(MSDOS) && defined(DGK)
X	flags.rawio = oldflags.rawio;
X	flags.IBMBIOS = oldflags.IBMBIOS;
X#endif
X#ifdef TEXTCOLOR
X	flags.use_color = oldflags.use_color;
X#endif
X	/* these come from the current environment; ignore saved values */
X	flags.echo = oldflags.echo;
X	flags.cbreak = oldflags.cbreak;
X
X	mread(fd, (genericptr_t) &dlevel, sizeof dlevel);
X	mread(fd, (genericptr_t) &maxdlevel, sizeof maxdlevel);
X	mread(fd, (genericptr_t) &moves, sizeof moves);
X	mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
X	mread(fd, (genericptr_t) &wiz_level, sizeof wiz_level);
X	mread(fd, (genericptr_t) &medusa_level, sizeof medusa_level);
X	mread(fd, (genericptr_t) &bigroom_level, sizeof bigroom_level);
X#ifdef ORACLE
X	mread(fd, (genericptr_t) &oracle_level, sizeof oracle_level);
X#endif
X#ifdef REINCARNATION
X	mread(fd, (genericptr_t) &rogue_level, sizeof rogue_level);
X	if (dlevel==rogue_level)
X		(void) memcpy((genericptr_t)savesyms,
X			      (genericptr_t)showsyms, sizeof savesyms);
X#endif
X#ifdef STRONGHOLD
X	mread(fd, (genericptr_t) &stronghold_level, sizeof stronghold_level);
X	mread(fd, (genericptr_t) &tower_level, sizeof tower_level);
X	mread(fd, (genericptr_t) tune, sizeof tune);
X#  ifdef MUSIC
X	mread(fd, (genericptr_t) &music_heard, sizeof music_heard);
X#  endif
X#endif
X	mread(fd, (genericptr_t) &is_maze_lev, sizeof is_maze_lev);
X	mread(fd, (genericptr_t) &u, sizeof(struct you));
X	if(u.uhp <= 0) {
X	    (void) close(fd);
X	    (void) unlink(SAVEF);
X#ifdef AMIGA_WBENCH
X	    ami_wbench_unlink(SAVEF);
X#endif
X	    (void) puts("You were not healthy enough to survive restoration.");
X	    restoring = FALSE;
X	    return(0);
X	}
X#ifdef SPELLS
X	mread(fd, (genericptr_t) spl_book, 
X				sizeof(struct spell) * (MAXSPELL + 1));
X#endif
X#ifdef NAMED_ITEMS
X	mread(fd, (genericptr_t) artiexist, 
X			(unsigned int)(sizeof(boolean) * artifact_num));
X#endif
X	if(u.ustuck)
X		mread(fd, (genericptr_t) &mid, sizeof mid);
X	mread(fd, (genericptr_t) pl_character, sizeof pl_character);
X#ifdef TUTTI_FRUTTI
X	mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
X	mread(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
X	ffruit = 0;
X	while (fruit = newfruit(),
X	       mread(fd, (genericptr_t)fruit, sizeof(struct fruit)),
X	       fruit->fid) {
X		fruit->nextf = ffruit;
X		ffruit = fruit;
X	}
X	free((genericptr_t) fruit);
X#endif
X
X	restnames(fd);
X#if defined(DGK) || defined(MACOS)
X# ifdef MACOS
X#define msmsg printf
X# endif
X	msmsg("\n");
X	cl_end();
X	msmsg("You got as far as level %d%s.\n", maxdlevel,
X		flags.debug ? " in WIZARD mode" :
X		flags.explore ? " in discovery mode" : "");
X	cl_end();
X	msmsg("Restoring: ");
X#endif
X	while(1) {
X#ifdef ZEROCOMP
X		if(mread(fd, (genericptr_t) &ltmp, sizeof ltmp) < 0)
X#else
X		if(read(fd, (genericptr_t) &ltmp, sizeof ltmp) != sizeof ltmp)
X#endif
X			break;
X		getlev(fd, 0, ltmp, FALSE);
X		glo(ltmp);
X#if defined(DGK) || defined(MACOS)
X		msmsg(".");
X#endif
X#if defined(MSDOS) && !defined(TOS)
X		nfd = open(lock, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
X#else
X# ifdef MACOS
X		{
X			Str255	fileName;
X			OSErr	er;
X			struct term_info	*t;
X			short	oldVolume;
X			extern WindowPtr	HackWindow;
X			
X			t = (term_info *)GetWRefCon(HackWindow);
X			(void)GetVol(&fileName, &oldVolume);
X			(void)SetVol(0L, t->system.sysVRefNum);
X			fileName[0] = (uchar)strlen(lock);
X			Strcpy((char *)&fileName[1], lock);
X			
X			if (er = Create(&fileName, 0, CREATOR, LEVEL_TYPE))
X				SysBeep(1);
X			msmsg(".");
X			nfd = open(lock, O_WRONLY | O_BINARY);
X			(void)SetVol(0L, oldVolume);
X		}
X# else
X		nfd = creat(lock, FCMASK);
X# endif /* MACOS */
X#endif
X		if (nfd < 0)	panic("Cannot open temp file %s!\n", lock);
X#if defined(DGK)
X		if (!savelev(nfd, ltmp, COUNT | WRITE)) {
X
X			/* The savelev can't proceed because the size required
X			 * is greater than the available disk space.
X			 */
X			msmsg("\nNot enough space on `%s' to restore your game.\n",
X				levels);
X
X			/* Remove levels and bones that may have been created.
X			 */
X			(void) close(nfd);
X			eraseall(levels, alllevels);
X			eraseall(levels, allbones);
X
X			/* Perhaps the person would like to play without a
X			 * RAMdisk.
X			 */
X			if (ramdisk) {
X				/* PlaywoRAMdisk may not return, but if it does
X				 * it is certain that ramdisk will be 0.
X				 */
X				playwoRAMdisk();
X				/* Rewind save file and try again */
X				(void) lseek(fd, (off_t)0, 0);
X				return dorecover(fd);
X			} else {
X				msmsg("Be seeing you...\n");
X				exit(0);
X			}
X		}
X#else
X		savelev(nfd, ltmp);
X#endif
X#ifdef ZEROCOMP
X		bflush(nfd);
X#endif
X		(void) close(nfd);
X	}
X#ifdef BSD
X	(void) lseek(fd, 0L, 0);
X#else
X	(void) lseek(fd, (off_t)0, 0);
X#endif
X#ifdef ZEROCOMP
X	minit();
X#endif
X	getlev(fd, 0, (xchar)0, FALSE);
X	(void) close(fd);
X#if defined(WIZARD) || defined(EXPLORE_MODE)
X	if(
X# ifdef WIZARD
X	   !wizard
X#  ifdef EXPLORE_MODE
X		   &&
X#  endif
X# endif
X# ifdef EXPLORE_MODE
X		      !discover
X# endif
X				)
X#endif
X		(void) unlink(SAVEF);
X#ifdef AMIGA_WBENCH
X		ami_wbench_unlink(SAVEF);
X#endif
X#ifdef REINCARNATION
X	/* this can't be done earlier because we need to check the initial
X	 * showsyms against the one saved in each of the non-rogue levels */
X	if (dlevel==rogue_level) {
X		(void) memcpy((genericptr_t)showsyms,
X			      (genericptr_t)defsyms, sizeof showsyms);
X		showsyms[S_ndoor] = showsyms[S_vodoor] =
X		    showsyms[S_hodoor] = '+';
X	}
X#endif
X	if(u.ustuck) {
X		register struct monst *mtmp;
X
X		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X			if(mtmp->m_id == mid) goto monfnd;
X		panic("Cannot find the monster ustuck.");
X	monfnd:
X		u.ustuck = mtmp;
X	}
X	setsee();  /* only to recompute seelx etc. - these weren't saved */
X#ifdef DGK
X	gameDiskPrompt();
X#endif
X	max_rank_sz(); /* to recompute mrank_sz (pri.c) */
X#ifdef POLYSELF
X	set_uasmon();
X#endif
X	/* take care of iron ball & chain */
X	for(otmp = fobj; otmp; otmp = otmp->nobj)
X		if(otmp->owornmask)
X			setworn(otmp, otmp->owornmask);
X#ifndef NO_SIGNAL
X	/* in_use processing must be after:
X	 *  inven has been read so fcobj has been built and freeinv() works
X	 *  current level has been restored so billing information is available
X	 */
X	inven_inuse();
X#endif
X	docrt();
X	restoring = FALSE;
X	return(1);
X}
X
Xvoid
Xgetlev(fd, pid, lev, ghostly)
Xint fd, pid;
Xxchar lev;
Xboolean ghostly;
X{
X	register struct gold *gold;
X	register struct trap *trap;
X	register struct monst *mtmp;
X#ifdef WORM
X	register struct wseg *wtmp;
X	register int tmp;
X#endif
X	long nhp;
X	int hpid;
X	xchar dlvl;
X	symbol_array osymbol;
X	int x, y;
X	uchar osym, nsym;
X#ifdef TOS
X	short tlev;
X#endif
X
X#if defined(MSDOS) && !defined(TOS) && !defined(LATTICE) && !defined(AZTEC_C)
X	setmode(fd, O_BINARY);	    /* is this required for TOS??? NO --ERS */
X#endif
X#ifdef TUTTI_FRUTTI
X	/* Load the old fruit info.  We have to do it first, so the infor-
X	 * mation is available when restoring the objects.  
X	 */
X	if (ghostly) {
X		struct fruit *fruit;
X
X		oldfruit = 0;
X		while (fruit = newfruit(),
X		       mread(fd, (genericptr_t)fruit, sizeof(struct fruit)),
X		       fruit->fid) {
X			fruit->nextf = oldfruit;
X			oldfruit = fruit;
X		}
X		free((genericptr_t) fruit);
X	}
X#endif
X
X	/* First some sanity checks */
X	mread(fd, (genericptr_t) &hpid, sizeof(hpid));
X#ifdef TOS
X	mread(fd, (genericptr_t) &tlev, sizeof(tlev));
X	dlvl=tlev&0x00ff;
X#else
X	mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
X#endif
X	if((pid && pid != hpid) || (lev && dlvl != lev)) {
X#ifdef WIZARD
X		if (wizard) {
X			if (pid && pid != hpid)
X				pline("PID (%d) doesn't match saved PID (%d)!", hpid, pid);
X			else if (lev && dlvl != lev)
X				pline("This is level %d, not %d!", dlvl, lev);
X		}
X#endif
X		pline("Strange, this map is not as I remember it.");
X		pline("Somebody is trying some trickery here...");
X		pline("This game is void.");
X		done(TRICKED);
X	}
X
X#if defined(SMALLDATA) && defined(MACOS)
X	{
X	/* this assumes that the size of a row of struct rm's is <128 */
X		short	i, length, j;
X		char	*ptr, *src, *p, *d;
X		
X		d = calloc(ROWNO*COLNO, sizeof(struct rm));
X		p = d;
X		mread(fd, (genericptr_t)&j, sizeof(short));
X		mread(fd, (genericptr_t)d, j);
X		for (i = 0; i < COLNO; i++) {
X			length = (short)(*p++);
X			ptr = p;
X			src = (char *)&levl[i][0];
X			UnpackBits(&ptr, &src, ROWNO * sizeof(struct rm));
X			if ((ptr - p) != length) 
X			    panic("restore - corrupted file on unpacking\n");
X			p = ptr;
X		}
X		free(d);
X	}
X#else
X	mread(fd, (genericptr_t) levl, sizeof(levl));
X#endif
X	mread(fd, (genericptr_t) osymbol, sizeof(osymbol));
X#ifdef REINCARNATION
X	if (memcmp((genericptr_t) osymbol, ((dlevel==rogue_level)
X			? (genericptr_t)savesyms : (genericptr_t)showsyms),
X			sizeof (osymbol))
X		&& dlvl != rogue_level) {
X		/* rogue level always uses default syms.  Although showsyms
X		 * will be properly initialized from environment when restoring
X		 * a game, this routine is called upon saving as well as
X		 * restoring; when saving on the Rogue level, showsyms will
X		 * be wrong, so use savesyms (which is always right, both on
X		 * saving and restoring).
X		 */
X#else
X	if (memcmp((genericptr_t) osymbol,
X		   (genericptr_t) showsyms, sizeof (showsyms))) {
X#endif
X		for (x = 0; x < COLNO; x++)
X			for (y = 0; y < ROWNO; y++) {
X				osym = levl[x][y].scrsym;
X				nsym = 0;
X				switch (levl[x][y].typ) {
X				case STONE:
X				case SCORR:
X					if (osym == osymbol[S_stone])
X						nsym = showsyms[S_stone];
X					break;
X				case ROOM:
X#ifdef STRONGHOLD
X				case DRAWBRIDGE_DOWN:
X#endif /* STRONGHOLD /**/
X					if (osym == osymbol[S_room])
X						nsym = showsyms[S_room];
X					break;
X				case DOOR:
X					if (osym == osymbol[S_ndoor])
X						nsym = showsyms[S_ndoor];
X					else if (osym == osymbol[S_vodoor])
X						nsym = showsyms[S_vodoor];
X					else if (osym == osymbol[S_hodoor])
X						nsym = showsyms[S_hodoor];
X					else if (osym == osymbol[S_cdoor])
X						nsym = showsyms[S_cdoor];
X					break;
X				case CORR:
X					if (osym == osymbol[S_corr])
X						nsym = showsyms[S_corr];
X					break;
X				case VWALL:
X					if (osym == osymbol[S_vwall])
X						nsym = showsyms[S_vwall];
X#ifdef STRONGHOLD
X					else if (osym == osymbol[S_dbvwall])
X						nsym = showsyms[S_dbvwall];
X#endif
X					break;
X				case HWALL:
X					if (osym == osymbol[S_hwall])
X						nsym = showsyms[S_hwall];
X#ifdef STRONGHOLD
X					else if (osym == osymbol[S_dbhwall])
X						nsym = showsyms[S_dbhwall];
X#endif
X					break;
X				case TLCORNER:
X					if (osym == osymbol[S_tlcorn])
X						nsym = showsyms[S_tlcorn];
X					break;
X				case TRCORNER:
X					if (osym == osymbol[S_trcorn])
X						nsym = showsyms[S_trcorn];
X					break;
X				case BLCORNER:
X					if (osym == osymbol[S_blcorn])
X						nsym = showsyms[S_blcorn];
X					break;
X				case BRCORNER:
X					if (osym == osymbol[S_brcorn])
X						nsym = showsyms[S_brcorn];
X					break;
X				case SDOOR:
X					if (osym == osymbol[S_vwall])
X						nsym = showsyms[S_vwall];
X					else if (osym == osymbol[S_hwall])
X						nsym = showsyms[S_hwall];
X					break;
X				case CROSSWALL:
X					if (osym == osymbol[S_crwall])
X						nsym = showsyms[S_crwall];
X					break;
X				case TUWALL:
X					if (osym == osymbol[S_tuwall])
X						nsym = showsyms[S_tuwall];
X					break;
X				case TDWALL:
X					if (osym == osymbol[S_tdwall])
X						nsym = showsyms[S_tdwall];
X					break;
X				case TLWALL:
X					if (osym == osymbol[S_tlwall])
X						nsym = showsyms[S_tlwall];
X					break;
X				case TRWALL:
X					if (osym == osymbol[S_trwall])
X						nsym = showsyms[S_trwall];
X					break;
X				case STAIRS:
X					if (osym == osymbol[S_upstair])
X						nsym = showsyms[S_upstair];
X					else if (osym == osymbol[S_dnstair])
X						nsym = showsyms[S_dnstair];
X					break;
X#ifdef STRONGHOLD
X				case LADDER:
X					if (osym == osymbol[S_upladder])
X						nsym = showsyms[S_upladder];
X					else if (osym == osymbol[S_dnladder])
X						nsym = showsyms[S_dnladder];
X					break;
X#endif /* STRONGHOLD /**/
X				case POOL:
X				case MOAT:
X#ifdef STRONGHOLD
X				case DRAWBRIDGE_UP:
X#endif /* STRONGHOLD /**/
X					if (osym == osymbol[S_pool])
X						nsym = showsyms[S_pool];
X					break;
X#ifdef FOUNTAINS
X				case FOUNTAIN:
X					if (osym == osymbol[S_fountain])
X						nsym = showsyms[S_fountain];
X					break;
X#endif /* FOUNTAINS /**/
X#ifdef THRONES
X				case THRONE:
X					if (osym == osymbol[S_throne])
X						nsym = showsyms[S_throne];
X					break;
X#endif /* THRONES /**/
X#ifdef SINKS
X				case SINK:
X					if (osym == osymbol[S_sink])
X						nsym = showsyms[S_sink];
X					break;
X#endif /* SINKS /**/
X#ifdef ALTARS
X				case ALTAR:
X					if (osym == osymbol[S_altar])
X						nsym = showsyms[S_altar];
X					break;
X#endif /* ALTARS /**/
X				default:
X					break;
X				}
X				if (nsym)
X					levl[x][y].scrsym = nsym;
X			}
X	}
X
X	mread(fd, (genericptr_t)&omoves, sizeof(omoves));
X	mread(fd, (genericptr_t)&xupstair, sizeof(xupstair));
X	mread(fd, (genericptr_t)&yupstair, sizeof(yupstair));
X	mread(fd, (genericptr_t)&xdnstair, sizeof(xdnstair));
X	mread(fd, (genericptr_t)&ydnstair, sizeof(ydnstair));
X#ifdef STRONGHOLD
X	mread(fd, (genericptr_t)&xupladder, sizeof(xupladder));
X	mread(fd, (genericptr_t)&yupladder, sizeof(yupladder));
X	mread(fd, (genericptr_t)&xdnladder, sizeof(xdnladder));
X	mread(fd, (genericptr_t)&ydnladder, sizeof(ydnladder));
X#endif
X	mread(fd, (genericptr_t)&fountsound, sizeof(fountsound));
X	mread(fd, (genericptr_t)&sinksound, sizeof(sinksound));
X	fmon = restmonchn(fd, ghostly);
X
X	/* regenerate animals while on another level */
X	{ long tmoves = (monstermoves > omoves) ? monstermoves-omoves : 0;
X	  register struct monst *mtmp2;
X
X	  for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X
X		mtmp2 = mtmp->nmon;
X		if((mtmp->data->geno&G_GENOD) && !(mtmp->data->geno&G_UNIQ)) {
X			/* mondead() would try to link the monster's objects
X			 * into fobj and the appropriate nexthere chain.
X			 * unfortunately, such things will not have sane
X			 * values until after find_lev_obj() well below
X			 * here, so we'd go chasing random pointers if we
X			 * tried that.  we could save the monster's objects
X			 * in another chain and insert them in the level
X			 * later, but that's a lot of work for very little
X			 * gain.  hence, just throw the objects away via
X			 * mongone() and pretend the monster wandered off
X			 * somewhere private before the genocide.
X			 */
X			mongone(mtmp);
X			continue;
X		}
X
X		if (ghostly) {
X			/* reset peaceful/malign relative to new character */
X			if(!mtmp->isshk)
X				/* shopkeepers will reset based on name */
X				mtmp->mpeaceful = peace_minded(mtmp->data);
X			set_malign(mtmp);
X		} else if (mtmp->mtame && tmoves > 250)
X		  	mtmp->mtame = mtmp->mpeaceful = 0;
X
X		/* restore shape changers - Maarten Jan Huisjes */
X		if (mtmp->data == &mons[PM_CHAMELEON]
X		    && !Protection_from_shape_changers
X		    && !mtmp->cham)
X			mtmp->cham = 1;
X		else if(Protection_from_shape_changers) {
X			if (mtmp->cham) {
X				mtmp->cham = 0;
X				(void) newcham(mtmp, &mons[PM_CHAMELEON]);
X			} else if(is_were(mtmp->data) && !is_human(mtmp->data))
X				(void) new_were(mtmp);
X		}
X
X		if (!ghostly) {
X			nhp = mtmp->mhp +
X				(regenerates(mtmp->data) ? tmoves : tmoves/20);
X			if(!mtmp->mcansee && mtmp->mblinded) {
X				if (mtmp->mblinded < tmoves) mtmp->mblinded = 0;
X				else mtmp->mblinded -= tmoves;
X			}
X			if(!mtmp->mcanmove && mtmp->mfrozen) {
X				if (mtmp->mfrozen < tmoves) mtmp->mfrozen = 0;
X				else mtmp->mfrozen -= tmoves;
X			}
X			if(nhp > mtmp->mhpmax)
X				mtmp->mhp = mtmp->mhpmax;
X			else
X#ifdef LINT	/* (long)newhp -> (schar = short int) mhp; ok in context of text above */
X				mtmp->mhp = 0;
X#else
X				mtmp->mhp = nhp;
X#endif
X		}
X	  }
X	}
X
X	fgold = 0;
X	while(gold = newgold(),
X	      mread(fd, (genericptr_t)gold, sizeof(struct gold)),
X	      gold->gx) {
X		gold->ngold = fgold;
X		fgold = gold;
X	}
X	free((genericptr_t) gold);
X	ftrap = 0;
X	while (trap = newtrap(),
X	       mread(fd, (genericptr_t)trap, sizeof(struct trap)),
X	       trap->tx) {
X		trap->ntrap = ftrap;
X		ftrap = trap;
X	}
X	free((genericptr_t) trap);
X	fobj = restobjchn(fd, ghostly);
X	find_lev_obj();
X	billobjs = restobjchn(fd, ghostly);
X	rest_engravings(fd);
X	mread(fd, (genericptr_t)rooms, sizeof(rooms));
X	mread(fd, (genericptr_t)doors, sizeof(doors));
X#ifdef WORM
X	mread(fd, (genericptr_t)wsegs, sizeof(wsegs));
X	for(tmp = 1; tmp < 32; tmp++) if(wsegs[tmp]){
X		wheads[tmp] = wsegs[tmp] = wtmp = newseg();
X		while(1) {
X			mread(fd, (genericptr_t)wtmp, sizeof(struct wseg));
X			if(!wtmp->nseg) break;
X			wheads[tmp]->nseg = wtmp = newseg();
X			wheads[tmp] = wtmp;
X		}
X	}
X	mread(fd, (genericptr_t)wgrowtime, sizeof(wgrowtime));
X#endif
X
X	/* reset level.monsters for new level */
X	for (x = 0; x < COLNO; x++)
X	    for (y = 0; y < ROWNO; y++)
X		level.monsters[x][y] = (struct monst *) 0;
X	for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon)
X	    place_monster(mtmp, mtmp->mx, mtmp->my);
X
X#ifdef TUTTI_FRUTTI
X	/* Now get rid of all the temp fruits... */
X	if (ghostly) {
X		struct fruit *fruit;
X
X		while(oldfruit) {
X			fruit = oldfruit->nextf;
X			free((genericptr_t) oldfruit);
X			oldfruit = fruit;
X		}
X	}
X#endif
X	if(ghostly && lev > medusa_level && lev < stronghold_level &&
X						xdnstair == 0) {
X		coord cc;
X
X		mazexy(&cc);
X		xdnstair = cc.x;
X		ydnstair = cc.y;
X		levl[cc.x][cc.y].typ = STAIRS;
X	}
X}
X
X#ifdef ZEROCOMP
X#define RLESC '\0' 	/* Leading character for run of RLESC's */
X
Xstatic unsigned char NEARDATA inbuf[BUFSZ];
Xstatic unsigned short NEARDATA inbufp = 0;
Xstatic unsigned short NEARDATA inbufsz = 0;
Xstatic short NEARDATA inrunlength = -1;
Xstatic int NEARDATA mreadfd;
Xstatic int NDECL(mgetc);
X
Xstatic int
Xmgetc()
X{
X    if (inbufp >= inbufsz) {
X      inbufsz = read(mreadfd, (genericptr_t)inbuf, (int)sizeof inbuf);
X      if (!inbufsz) {
X	  if (inbufp > sizeof inbuf)
X	      error("EOF on file #%d.\n", mreadfd);
X	  inbufp = 1 + sizeof inbuf;  /* exactly one warning :-) */
X	  return -1;
X      }
X      inbufp = 0;
X    }
X    return inbuf[inbufp++];
X}
X
Xvoid
Xminit()
X{
X    inbufsz = 0;
X    inbufp = 0;
X    inrunlength = -1;
X}
X
Xint
Xmread(fd, buf, len)
Xint fd;
Xgenericptr_t buf;
Xregister unsigned len;
X{
X    /*register int readlen = 0;*/
X    mreadfd = fd;
X    while (len--) {
X      if (inrunlength > 0) {
X	  inrunlength--;
X	  *(*((char **)&buf))++ = '\0';
X      } else {
X	  register short ch = mgetc();
X	  if (ch < 0) return -1; /*readlen;*/
X	  if ((*(*(char **)&buf)++ = ch) == RLESC) {
X	      inrunlength = mgetc();
X	  }
X      }
X      /*readlen++;*/
X    }
X    return 0; /*readlen;*/
X}
X
X#else /* ZEROCOMP */
X
Xvoid
Xmread(fd, buf, len)
Xregister int fd;
Xregister genericptr_t buf;
Xregister unsigned int len;
X{
X	register int rlen;
X
X#if defined(BSD) || defined(ULTRIX)
X	rlen = read(fd, buf, (int) len);
X	if(rlen != len){
X#else /* e.g. SYSV, __TURBOC__ */
X	rlen = read(fd, buf, (unsigned) len);
X	if((unsigned)rlen != len){
X#endif
X		pline("Read %d instead of %u bytes.\n", rlen, len);
X		if(restoring) {
X			(void) unlink(SAVEF);
X#ifdef AMIGA_WBENCH
X			ami_wbench_unlink(SAVEF);
X#endif
X			error("Error restoring old game.");
X		}
X		panic("Error reading level file.");
X	}
X}
X#endif /* ZEROCOMP */
END_OF_FILE
if test 25217 -ne `wc -c <'src/restore.c'`; then
    echo shar: \"'src/restore.c'\" unpacked with wrong size!
fi
# end of 'src/restore.c'
fi
echo shar: End of archive 27 \(of 56\).
cp /dev/null ark27isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 56 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