[comp.sources.games] v10i084: 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 84
Archive-name: nethack3p9/Part39
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 39 (of 56)."
# Contents:  amiga/amidos.c auxil/MacHelp others/Makefile.os2
#   others/maintain.ovl
# Wrapped by billr@saab on Wed Jul 11 17:11:51 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'amiga/amidos.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'amiga/amidos.c'\"
else
echo shar: Extracting \"'amiga/amidos.c'\" \(16788 characters\)
sed "s/^X//" >'amiga/amidos.c' <<'END_OF_FILE'
X/*    SCCS Id: @(#)amidos.c msdos.c - Amiga version   3.0    89/05/01
X/* NetHack may be freely redistributed.  See license for details. */
X/* An assortment of imitations of cheap plastic MSDOS functions.
X */
X
X#define NEED_VARARGS
X#include "hack.h"
X
X#undef TRUE
X#undef FALSE
X#undef COUNT
X#undef NULL
X
X#include <libraries/dos.h>
X#ifdef LATTICE
X#include <proto/exec.h>
X#include <proto/dos.h>
X#endif
X
X/* Prototypes for functions defined in amidos.c */
Xvoid NDECL (flushout);
Xint NDECL (getpid);
Xint FDECL (abs, (int x));
Xint NDECL (tgetch);
Xint NDECL (dosh);
Xlong FDECL (freediskspace, (char *path));
Xlong FDECL (filesize, (char *file));
Xvoid FDECL (eraseall, (char *path,
X              char *files));
Xchar *FDECL (CopyFile, (char *from,
X               char *to));
Xvoid FDECL (copybones, (int mode));
Xvoid NDECL (playwoRAMdisk);
Xint FDECL (saveDiskPrompt, (int start));
Xvoid NDECL (gameDiskPrompt);
Xvoid NDECL (read_config_file);
Xvoid NDECL (set_lock_and_bones);
Xvoid FDECL (append_slash, (char *name));
Xvoid FDECL (getreturn, (char *str));
Xvoid VDECL (msmsg, (char *fmt, ...));
XFILE * FDECL (fopenp, (char *name,
X                      char *mode));
Xint FDECL (chdir, (char *dir));
Xvoid FDECL (msexit, (int code));
Xstatic boolean NDECL (record_exists);
Xstatic int FDECL (strcmpi, (register char *a, register char *b));
X
Xextern char Initialized;
X
X#ifdef AZTEC_C
Xstruct DateStamp *FDECL(DateStamp, (struct DateStamp *));
XBPTR FDECL(Lock, (char *, long));
XBPTR FDECL(CurrentDir, (BPTR));
XBPTR FDECL(Open, (char *, long));
Xlong FDECL(Read, (BPTR, char *, long));
Xlong FDECL(Write, (BPTR, char *, long));
Xlong NDECL(IoErr);
Xlong FDECL(AvailMem, (long));
Xvoid *FDECL(malloc, (unsigned int));
Xchar *FDECL(rindex, (char *, int));
Xchar *FDECL(index, (char *, int));
X#endif
X
Xint Enable_Abort = 0;	/* for stdio package */
X
X/* Initial path, so we can find NetHack.cnf */
X
Xchar PATH[PATHLEN] = "Ram:;df0:;NetHack:";
X
Xvoid
Xflushout()
X{
X    (void) fflush(stdout);
X}
X
X#ifndef getuid
Xgetuid()
X{
X    return 1;
X}
X#endif
X
X/*
X *  Actually make up a process id.
X *  Makes sure one can mess less with saved levels...
X */
X
Xint getpid()
X{
X    static short pid;
X
X    while (pid == 0) {
X	struct DateStamp dateStamp;
X	pid = rnd(30000);
X	pid += (short) DateStamp(&dateStamp);    /* More or less random */
X	pid ^= (short) (dateStamp.ds_Days >> 16) ^
X	       (short) (dateStamp.ds_Days)       ^
X	       (short) (dateStamp.ds_Minute)     +
X	       (short) (dateStamp.ds_Tick);
X	pid %= 30000;
X    }
X
X    return (int)pid;
X}
X
X#ifndef getlogin
Xchar *
Xgetlogin()
X{
X    return ((char *) NULL);
X}
X#endif
X
Xint
Xabs(x)
Xint x;
X{
X    return x < 0? -x: x;
X}
X
Xint
Xtgetch() {
X    char ch;
X
X    ch = WindowGetchar();
X    return ((ch == '\r') ? '\n' : ch);
X}
X
X#ifdef DGK
X# include <ctype.h>
X/* # include <fcntl.h> */
X
X# define Sprintf (void) sprintf
X
X# ifdef SHELL
Xint
Xdosh()
X{
X    pline("No mysterious force prevented you from using multitasking.");
X    return 0;
X}
X# endif /* SHELL */
X
X#define ID_DOS1_DISK	'DOS\1'
X#define EXTENSION	72
X
X/*
X *  This routine uses an approximation of the free bytes on a disk.
X *  How large a file you can actually write depends on the number of
X *  extension blocks you need for it.
X *  In each extenstion block there are maximum 72 pointers to blocks,
X *  so every 73 disk blocks have only 72 available for data.
X *  The (necessary) file header is also good for 72 data block pointers.
X */
Xlong
Xfreediskspace(path)
Xchar *path;
X{
X    register long freeBytes = 0;
X    register struct InfoData *infoData; /* Remember... longword aligned */
X    char fileName[32];
X
X    /*
X     *	Find a valid path on the device of which we want the free space.
X     *	If there is a colon in the name, it is an absolute path
X     *	and all up to the colon is everything we need.
X     *	Remember slashes in a volume name are allowed!
X     *	If there is no colon, it is relative to the current directory,
X     *	so must be on the current device, so "" is enough...
X     */
X    {
X	register char *colon;
X
X	strncpy(fileName, path, sizeof(fileName)-1);
X	fileName[31] = 0;
X	if (colon = index(fileName, ':'))
X	    colon[1] = '\0';
X	else
X	    fileName[0] = '\0';
X    }
X
X    if (infoData = malloc(sizeof(struct InfoData))) {
X	BPTR fileLock;
X	if (fileLock = Lock(fileName, SHARED_LOCK)) {
X	    if (Info(fileLock, infoData)) {
X		/* We got a kind of DOS volume, since we can Lock it. */
X		/* Calculate number of blocks available for new file */
X		/* Kludge for the ever-full VOID: (oops RAM:) device */
X		if (infoData->id_UnitNumber == -1 &&
X		    infoData->id_NumBlocks == infoData->id_NumBlocksUsed) {
X		    freeBytes = AvailMem(0L) - 64 * 1024L;
X		    /* Just a stupid guess at the */
X		    /* Ram-Handler overhead per block: */
X		    freeBytes -= freeBytes/16;
X		} else {
X		    /* Normal kind of DOS file system device/volume */
X		    freeBytes = infoData->id_NumBlocks -
X				infoData->id_NumBlocksUsed;
X		    freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1);
X		    freeBytes *= infoData->id_BytesPerBlock;
X		}
X		if (freeBytes < 0)
X		    freeBytes = 0;
X	    }
X	    UnLock(fileLock);
X	}
X	free(infoData);
X    }
X    return freeBytes;
X}
X
X
Xlong
Xfilesize(file)
Xchar *file;
X{
X    register BPTR fileLock;
X    register struct FileInfoBlock *fileInfoBlock;
X    register long size = 0;
X
X    if (fileInfoBlock = malloc(sizeof(struct FileInfoBlock))) {
X	if (fileLock = Lock(file, SHARED_LOCK)) {
X	    if (Examine(fileLock, fileInfoBlock)) {
X		size = fileInfoBlock->fib_Size;
X	    }
X	    UnLock(fileLock);
X	}
X	free(fileInfoBlock);
X    }
X    return size;
X}
X
X/*
X *  On the Amiga, looking if a specific file exists is much faster
X *  than sequentially reading a directory.
X */
X
Xvoid
Xeraseall(path, files)
Xchar *path, *files;
X{
X    char buf[FILENAME];
X    short i;
X    BPTR fileLock, dirLock;
X
X    if (dirLock = Lock(path ,SHARED_LOCK)) {
X	dirLock = CurrentDir(dirLock);
X
X	strcpy(buf, files);
X	for (i = 0; i <= MAXLEVEL; i++) {
X	    name_file(buf, i);
X	    if (fileLock = Lock(buf, SHARED_LOCK)) {
X		UnLock(fileLock);
X		DeleteFile(buf);
X	    } else if (IoErr() == ERROR_DEVICE_NOT_MOUNTED)
X		break;
X	    }
X
X	UnLock(CurrentDir(dirLock));
X    }
X}
X
X/* This size makes that most files can be copied with two Read()/Write()s */
X
X#define COPYSIZE    4096
X
Xchar *CopyFile(from, to)
Xchar *from, *to;
X{
X    register BPTR fromFile, toFile;
X    register char *buffer;
X    register long size;
X    char *error = NULL;
X
X    if (buffer = malloc(COPYSIZE)) {
X	if (fromFile = Open(from, MODE_OLDFILE)) {
X	    if (toFile = Open(to, MODE_NEWFILE)) {
X		while (size = Read(fromFile, buffer, (long)COPYSIZE)) {
X		    if (size != Write(toFile, buffer, size)) {
X			error = "Write error";
X			break;
X		    }
X		}
X		Close(toFile);
X	    } else /* Can't open destination file */
X		error = "Cannot open destination";
X	    Close(fromFile);
X	} else /* Cannot open source file. Should not happen. */
X	    error = "Huh?? Cannot open source??";
X	free(buffer);
X	return error;
X    } else /* Cannot obtain buffer for copying */
X	return "No Memory !";
X}
X
Xvoid
Xcopybones(mode)
Xint mode;
X{
X    BPTR fileLock;
X    char from[FILENAME], to[FILENAME];
X    char *frompath, *topath, *status;
X    short i;
X    extern int saveprompt;
X
X    if (!ramdisk)
X	return;
X
X    frompath = (mode != TOPERM) ? permbones : levels;
X    topath = (mode == TOPERM) ? permbones : levels;
X
X    /* Remove any bones files in `to' directory. */
X    eraseall(topath, allbones);
X
X    /* Copy `from' to `to' */
X    strcpy(from, frompath);
X    strcat(from, allbones);
X    strcpy(to, topath);
X    strcat(to, allbones);
X
X    for (i = 1; i < MAXLEVEL; i++) {
X	name_file(from, i);
X	name_file(to, i);
X	if (fileLock = Lock(from, SHARED_LOCK)) {
X	    UnLock(fileLock);
X	    if (status = CopyFile(from, to))
X		goto failed;
X	} else if (IoErr() == ERROR_DEVICE_NOT_MOUNTED) {
X	    status = "disk not present";
X	    goto failed;
X	}
X    }
X
X    /*
X     * The last file got there.  Remove the ramdisk bones files.
X     */
X    if (mode == TOPERM)
X	eraseall(frompath, allbones);
X    return;
X
X    /* Last file didn't get there. */
X
Xfailed:
X    msmsg("Cannot copy `%s' to `%s'\n(%s)\n", from, to, status);
X
X    if (mode == TOPERM) {
X	msmsg("Bones will be left in `%s'\n",
X	    *frompath ? frompath : hackdir);
X	return;
X    } else {
X	/* Remove all bones files on the RAMdisk */
X	eraseall(levels, allbones);
X	playwoRAMdisk();
X    }
X}
X
Xvoid
XplaywoRAMdisk()
X{
X    msmsg("Do you wish to play without a RAMdisk (y/n) ? ");
X
X    /* Set ramdisk false *before* exit'ing (because msexit calls
X     * copybones)
X     */
X    ramdisk = FALSE;
X    if (Getchar() != 'y') {
X	settty("Be seeing you ...\n");
X	exit(0);
X    }
X    set_lock_and_bones();
X    return;
X}
X
Xint
XsaveDiskPrompt(start)
X{
X    extern int saveprompt;
X    char buf[BUFSIZ], *bp;
X    BPTR fileLock;
X
X    if (saveprompt) {
X	/* Don't prompt if you can find the save file */
X	if (fileLock = Lock(SAVEF, SHARED_LOCK)) {
X	    UnLock(fileLock);
X	    return 1;
X	}
X	remember_topl();
X	home();
X	cl_end();
X	msmsg("If save file is on a SAVE disk, put that disk in 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{
X    FILE *file;
X
X    if (file = fopenp(RECORD, "r")) {
X	fclose(file);
X	return TRUE;
X    }
X    return FALSE;
X}
X
X/* Prompt for game disk, then check for record file.
X */
Xvoid
XgameDiskPrompt()
X{
X    extern int saveprompt;
X
X    if (record_exists())
X	return;
X
X    if (saveprompt) {
X	(void) putchar('\n');
X	getreturn("when the GAME disk has been put in");
X    }
X
X    if (!record_exists()) {
X	msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
X
X	msmsg("If the GAME disk is not in, put it in now.\n");
X	getreturn("to continue");
X    }
X}
X
X/* Read configuration */
Xvoid
Xread_config_file()
X{
X    char    tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
X    char    buf[BUFSZ], *bufp;
X    FILE    *fp;
X    extern  char plname[];
X    extern  int saveprompt;
X
X    tmp_ramdisk[0] = 0;
X    tmp_levels[0] = 0;
X    if ((fp = fopenp(configfile, "r")) == NULL) {
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 = index(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	} else if (!strncmp(buf, "RAMDISK", 3)) {
X	    strncpy(tmp_ramdisk, bufp, PATHLEN);
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, (boolean)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	    char *ptr;
X	    if (ptr = index(bufp, ';')) {
X		*ptr = '\0';
X		if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
X		    saveprompt = FALSE;
X	    }
X	    (void) strncpy(SAVEF, bufp, PATHLEN);
X	    append_slash(SAVEF);
X	} else if (!strncmp(buf, "GRAPHICS", 4)) {
X	    unsigned int translate[MAXPCHARS+1]; /* for safety */
X	    int  lth;
X
X	    if ((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])) < 0) {
X		    msmsg ("Syntax error in GRAPHICS\n");
X		    getreturn("to continue");
X	    } /* Yuck! Worked only with low-byte first!!! */
X	    assign_graphics(translate, lth);
X	} else if (!strncmp(buf, "PATH", 4)) {
X	    strncpy(PATH, bufp, PATHLEN);
X
X	} else {
X	    msmsg("Bad option line: '%s'\n", buf);
X	    getreturn("to continue");
X	}
X    }
X    fclose(fp);
X
X    strcpy(permbones, tmp_levels);
X    if (tmp_ramdisk[0]) {
X	strcpy(levels, tmp_ramdisk);
X	if (strcmpi(permbones, levels))        /* if not identical */
X	    ramdisk = TRUE;
X    } else
X	strcpy(levels, tmp_levels);
X    strcpy(bones, levels);
X}
X
X/* Set names for bones[] and lock[] */
X
Xvoid
Xset_lock_and_bones()
X{
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}
X
X/*
X * Add a slash 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 != ':') {
X	*++ptr = '/';
X	*++ptr = '\0';
X    }
X}
X
X
Xvoid
Xgetreturn(str)
Xchar *str;
X{
X    int ch;
X
X    msmsg("Hit <RETURN> %s.", str);
X    while ((ch = Getchar()) != '\n')
X	;
X}
X
Xvoid
Xmsmsg VA_DECL(char *, fmt)
X    VA_START(fmt);
X    VA_INIT(fmt, char *);
X#ifdef LATTICE
X	{
X	extern struct Screen *HackScreen;
X	char buf[100];
X	vsprintf(buf,fmt,VA_ARGS);
X	if(HackScreen){
X		WindowFPuts(buf);
X		WindowFlush();
X	} else {
X		fprintf(stdout,buf);
X		fflush(stdout);
X	}
X	}
X#else
X    vprintf(fmt, VA_ARGS);
X    (void) fflush(stdout);
X#endif
X    VA_END();
X}
X
X/* Follow the PATH, trying to fopen the file.
X */
X#define PATHSEP    ';'
X#undef fopen
X
XFILE *
Xfopenp(name, mode)
Xregister char *name, *mode;
X{
X    char buf[BUFSIZ], *bp, *pp, lastch;
X    FILE *fp;
X    register BPTR theLock;
X
X    /* Try the default directory first.  Then look along PATH.
X     */
X    strcpy(buf, name);
X    if (theLock = Lock(buf, SHARED_LOCK)) {
X	UnLock(theLock);
X	if (fp = fopen(buf, mode))
X	    return fp;
X    }
X    pp = PATH;
X    while (pp && *pp) {
X	bp = buf;
X	while (*pp && *pp != PATHSEP)
X	    lastch = *bp++ = *pp++;
X	if (lastch != ':' && lastch != '/' && bp != buf)
X	    *bp++ = '/';
X	strcpy(bp, name);
X	if (theLock = Lock(buf, SHARED_LOCK)) {
X	    UnLock(theLock);
X	    if (fp = fopen(buf, mode))
X		return fp;
X	}
X	if (*pp)
X	    pp++;
X    }
X    return NULL;
X}
X#endif /* DGK */
X
X#ifdef CHDIR
X
X/*
X *  A not general-purpose directory changing routine.
X *  Assumes you want to return to the original directory eventually,
X *  by chdir()ing to orgdir.
X *  Assumes -1 is not a valid lock, since 0 is valid.
X */
X
X#define NO_LOCK     ((BPTR) -1)
X
Xchar orgdir[1];
Xstatic BPTR OrgDirLock = NO_LOCK;
X
Xchdir(dir)
Xchar *dir;
X{
X    if (dir == orgdir) {
X	/* We want to go back to where we came from. */
X	if (OrgDirLock != NO_LOCK) {
X	    UnLock(CurrentDir(OrgDirLock));
X	    OrgDirLock = NO_LOCK;
X	}
X    } else {
X	/*
X	 * Go to some new place. If still at the original
X	 * directory, save the FileLock.
X	 */
X	BPTR newDir;
X
X	if (newDir = Lock(dir, SHARED_LOCK)) {
X	    if (OrgDirLock == NO_LOCK) {
X		OrgDirLock = CurrentDir(newDir);
X	    } else {
X		UnLock(CurrentDir(newDir));
X	    }
X	} else {
X	    return -1;	/* Failed */
X	}
X    }
X    /* CurrentDir always succeeds if you have a lock */
X    return 0;
X}
X
X#endif
X
X/* Chdir back to original directory
X */
X#undef exit
Xvoid
Xmsexit(code)
X{
X#ifdef CHDIR
X    extern char orgdir[];
X#endif
X
X#ifdef DGK
X    (void) fflush(stdout);
X    if (ramdisk)
X	copybones(TOPERM);
X#endif
X#ifdef CHDIR
X    chdir(orgdir);      /* chdir, not chdirx */
X#endif
X
X    CleanUp();
X    exit(code);
X}
X
X/*
X *  Strcmp while ignoring case. Not general-purpose, so static.
X */
X
Xstatic int strcmpi(a, b)
Xregister char *a, *b;
X{
X    while (tolower(*a) == tolower(*b)) {
X	if (!*a)        /* *a == *b, so at end of both strings */
X	    return 0;	/* equal. */
X	a++;
X	b++;
X    }
X    return 1;
X}
X
X/*
X *  memcmp - used to compare two struct symbols, in lev.c
X */
X
X#if defined(AZTEC_C) && !defined(memcmp)
Xmemcmp(a, b, size)
Xregister unsigned char *a, *b;
Xregister int size;
X{
X    while (size--) {
X	if (*a++ != *b++)
X	    return 1;	/* not equal */
X    }
X
X    return 0;		/* equal */
X}
X#endif
END_OF_FILE
if test 16788 -ne `wc -c <'amiga/amidos.c'`; then
    echo shar: \"'amiga/amidos.c'\" unpacked with wrong size!
fi
# end of 'amiga/amidos.c'
fi
if test -f 'auxil/MacHelp' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'auxil/MacHelp'\"
else
echo shar: Extracting \"'auxil/MacHelp'\" \(3856 characters\)
sed "s/^X//" >'auxil/MacHelp' <<'END_OF_FILE'
X                             Macintosh Nethack Primer
X
XMovement
X
X        y k u           7 8 9                 UP              the mouse
X         \|/             \|/                  |               cursor shows
X        h-.-l           4-.-6           LEFT<- ->RIGHT        which way
X         /|\             /|\                  |               you'll move
X        b j n           1 2 3                DOWN             when clicked.
X       keyboard       numberpad          cursor keys          mouse click
X
XMove commands and modifiers:
Xyuhjklbn: go one step in specified direction
XYUHJKLBN: go in specified direction until you
X          hit a wall or run into something.
X[CTRL]<dir>,
Xg<dir>:   run in direction <dir> until something
X          interesting is seen.
X[SHIFT]<dir>,
XG<dir>:   same, except a branching corridor isn't considered
X              interesting.
Xm<dir>:   move without picking up objects.
X
XFor all Macintosh keyboards the [command] key (apple or pretzel key)
Xfunctions as the [control] key and the [~] key functions as the [escape]
Xkey. The normal [control] and [escape] keys are also supported.
X
XThe Number Pad
XWhen the window title shows "[MOVE]", the number keys may also be used
Xto move your character, otherwise they act as a numeric keypad.
X
XThe '5' key on the numberpad invokes the "open door" command.
XThe '0' key on the numberpad invokes the "do inventory" command.
X
XThe 'g', 'G', '[SHIFT]', [CTRL] and 'm' modifiers may also be used with
Xthe numberpad and the cursor keys.
X
XPress the clear key (or Num Lock) on the number pad to enable or disable
Xusing the number pad for movement.
X
XThe Cursor
XAlthough NetHack was meant to be played from a keyboard, on the Macintosh
Xyou can essentially play NetHack using the mouse. The mouse cursor shows
Xwhich direction you will try to move if you press the mouse button when
Xthe mouse is in the Nethack window. Of course, if you're confused this may
Xbe different. You may use the 'g', 'G', '[SHIFT]' and 'm' modifiers with
Xthe mouse button, too. Note that [SHIFT]-clicking on the spot where you're
Xstanding will "look" at the objects piled there. Holding down the mouse
Xbutton will, after a delay, cause repeated moves in the indicated direction.
X
XThe cursor will at times also indicate your current state of well-being.
XThese auxiliary cursors may look better on a non-inverted screen (they
Xlook best against the standard white Macintosh background). The cursor
Xmadness can be controlled from the "Set Options" dialog (see below).
X
XAlerts
XOccasionally a mac alert will appear in response to some action of yours.
XThese mac alerts typically require a "yes" or "no" (or alternate) response.
XYou can accept the default response button (indicated by a surrounding
Xhilite) by clicking on that button, hitting return or typing the first
Xletter of that button (i.e. y for yes). The alternate response(s) can be
Xchosen by clicking on them or typing their first letter, appropriately.
X
XMacintosh-specific Options
XMultiFinder AutoZoom: when enabled shrinks the NetHack window to icon size
Xwhen the game is context-swapped out and restores the window upon return.
X
XAlternative Cursors: when enabled allows the standard NetHack arrow cursor
Xset to be replaced by "hands" while blind a/o "strange" cursors while
Xhallucinating, if not blind, and so on. This does not affect the randomly
Xoriented cursors that appear when you're confused or stunned. A fatal
Xskull-n-crossbones cursor set will appear if you become deathly sick.
X
XThe other NetHack options are described elsewhere under the "?" command.
XThe names may be slightly different on the options dialog.
X
XMiscellaneous
XThe option key is the meta-key. For option-n, press option-shift-n and
Xfor option-u, press option-shift-u.
X
XBug Reports
XComments, questions, problems, etc. should be directed to (InterNet):
Xnethack-bugs@linc.cis.upenn.edu
X
X
END_OF_FILE
if test 3856 -ne `wc -c <'auxil/MacHelp'`; then
    echo shar: \"'auxil/MacHelp'\" unpacked with wrong size!
fi
# end of 'auxil/MacHelp'
fi
if test -f 'others/Makefile.os2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/Makefile.os2'\"
else
echo shar: Extracting \"'others/Makefile.os2'\" \(17844 characters\)
sed "s/^X//" >'others/Makefile.os2' <<'END_OF_FILE'
X#	SCCS Id: @(#)Makefile.os2	3.0	90/02/22
X#	OS/2 NetHack 3.0 Makefile for Microsoft(tm) C 5.1 -- Timo Hakulinen
X#
X#	NDMAKE ver 4.5 or MS-NMAKE is required, MS-MAKE will not work.
X#	To enable either make utility, uncomment the respective
X#	make-specific macros. If you plan to cross-compile in DOS, your
X#	best bet is NDMAKE, since it requires less memory than NMAKE.
X#	To compile in OS/2 use NMAKE or compatible.  Remember to set
X#	$(RLIBS) to real mode libraries if compiling in DOS, and to
X#	protected mode libraries for compilation in OS/2.
X#
X#	Copy pctty.c, pcunix.c, pcmain.c, msdos.c and this file
X#	(+ termcap library if used) into $(SRC) directory, rename
X#	this file to "makefile" (important, some targets rely on it),
X#	compile and link inside $(SRC).  Termcap library can be built
X#	from termcap sources using makefile.lib in "others" directory.
X#
X#	When using CodeView versions earlier than ver. 2.3, define
X#	OS2_CODEVIEW in pcconf.h and set HACKDIR (+ TERM and TERMCAP
X#	if used) in OS/2 config.sys. Otherwise path searches may fail.
X#
X#	Note that $(GAMEDIR) must exist prior to compilation.
X#
XCC	= cl
XLINK	= link
XLIB	= lib
X
X# Enable the upper three lines for NDMAKE and lower three for MS-NMAKE.
X# ($(MAKE) macro is often predefined, so we use $(MAKEBIN) instead).
XMAKEBIN = make
XAB	= $*.c
XCB	= $*.c
X#MAKEBIN = nmake
X#AB	= $(@B).c
X#CB	= $$(@B).c
X
X# For those of us who have these on PC.
X#YACC	= yacc
X#LEX	= lex
XYACC	= bison -y
XLEX	= flex
X# Standard file names may vary in PC installations.
XYTABC	= y_tab.c
XYTABH	= y_tab.h
XLEXYYC	= lexyy.c
X
X# Directories (makedefs hardcodes these, don't change them).
XINCL	= ..\include
XAUX	= ..\auxil
XSRC	= ..\src
XOBJ	= $(SRC)\o2
X
X# The game name and description.
XGAME	= nethack
XGAMEDES = NetHack 3.0
X
X# The game directory.
XGAMEDIR = \games\$(GAME)
X
X# Memory model, compile only, disable optimization, remove stack probes,
X# 80286 instruction set, dedicated datasegment for items >= 5 bytes,
X# pack structures on 1 byte boundaries, generate code for 8087
X# coprocessor, compiler warning level, include file path.
XCFLAGS	= /AL /c /Od /Gs /G2 /Gt5 /Zp1 /FPi87 /W1 /I$(INCL) $(CDFLAGS)
X
X# + prepare for CodeView symbolic debugger.
XCDFLAGS =
X#CDFLAGS = /Zi
X
X# Don't ignore case in symbols, no default lib search, stack 4096 bytes.
X# (actually a bit of overkill), allow max 1024 segments in program.
XLFLAGS	= /noig /nod /stack:4096 /seg:1024 $(LDFLAGS)
X
X# + prepare for CodeView symbolic debugger.
XLDFLAGS =
X#LDFLAGS = /CO
X
X# Protected mode C libraries for 8087 (change if necessary),
X# OS/2 API entry points.
XPLIBS	= llibc7p doscalls
X
X# C libraries used by makedefs and lev_comp (change if necessary).
X# If compilation is done in DOS, enable the upper line, if in OS/2,
X# the lower (protected mode libraries).
XRLIBS	= llibc7r
X#RLIBS	= $(PLIBS)
X
X# Module definition file for OS/2.
XOS2DEFS	= $(GAME).def
X
X# The default make target (so just typing 'make' is useful).
Xdefault: $(GAME)
X
X# If you have yacc and lex programs and make any changes, comment out the
X# upper two lines and uncomment the lower two.
Xdo_yacc: yacc_msg
Xdo_lex:  lex_msg
X#do_yacc: yacc_act
X#do_lex:  lex_act
X
X# Optional high-quality BSD random number generation routines (see pcconf.h).
X# Set to nothing if not used.
XRANDOM	= $(OBJ)\random.o
X#RANDOM	=
X
X# If TERMLIB defined in pcconf.h, comment out the upper line and
X# uncomment the lower.  If the termcap-library doesn't exist, use
X# others\makefile.lib to build it.
XTERMLIB =
X#TERMLIB = termlib.lib
X
X######################################################################
X#
X# Nothing below this line should have to be changed.
X#
X# Other things that have to be reconfigured are in
X# config.h, pcconf.h and possibly system.h.
X#
X
X# The game filename.
XGAMEFILE = $(GAMEDIR)\$(GAME).exe
X
X# Object files for makedefs.
XMAKEOBJS = $(OBJ)\makedefs.o $(OBJ)\monst.o $(OBJ)\objects.o
X
X# Object files for special levels compiler.
XSOBJ01 = $(OBJ)\lev_comp.o $(OBJ)\lev_lex.o $(OBJ)\lev_main.o $(OBJ)\alloc.o
XSOBJ02 = $(OBJ)\monst.o $(OBJ)\objects.o $(OBJ)\panic.o
X
XSPLEVOBJS = $(SOBJ01) $(SOBJ02)
X
XVOBJ01 = $(OBJ)\allmain.o  $(OBJ)\alloc.o    $(OBJ)\apply.o    $(OBJ)\artifact.o
XVOBJ02 = $(OBJ)\attrib.o   $(OBJ)\bones.o    $(OBJ)\cmd.o      $(OBJ)\dbridge.o
XVOBJ03 = $(OBJ)\decl.o     $(OBJ)\demon.o    $(OBJ)\do.o       $(OBJ)\do_name.o
XVOBJ04 = $(OBJ)\do_wear.o  $(OBJ)\dog.o      $(OBJ)\dogmove.o  $(OBJ)\dokick.o
XVOBJ05 = $(OBJ)\dothrow.o  $(OBJ)\eat.o      $(OBJ)\end.o
XVOBJ06 = $(OBJ)\engrave.o  $(OBJ)\exper.o    $(OBJ)\extralev.o $(OBJ)\fountain.o
XVOBJ07 = $(OBJ)\getline.o  $(OBJ)\hack.o     $(OBJ)\invent.o   $(OBJ)\lock.o
XVOBJ08 = $(OBJ)\mail.o     $(OBJ)\main.o     $(OBJ)\makemon.o  $(OBJ)\mcastu.o
XVOBJ09 = $(OBJ)\mhitm.o    $(OBJ)\mhitu.o    $(OBJ)\mklev.o    $(OBJ)\mkmaze.o
XVOBJ10 = $(OBJ)\mkobj.o    $(OBJ)\mkroom.o   $(OBJ)\mon.o      $(OBJ)\mondata.o
XVOBJ11 = $(OBJ)\msdos.o    $(OBJ)\monmove.o  $(OBJ)\monst.o    $(OBJ)\mthrowu.o
XVOBJ12 = $(OBJ)\music.o    $(OBJ)\o_init.o   $(OBJ)\objects.o
XVOBJ13 = $(OBJ)\objnam.o   $(OBJ)\options.o  $(OBJ)\pager.o    $(OBJ)\pickup.o
XVOBJ14 = $(OBJ)\polyself.o $(OBJ)\potion.o   $(OBJ)\pray.o     $(OBJ)\pri.o
XVOBJ15 = $(OBJ)\priest.o   $(OBJ)\prisym.o   $(RANDOM)         $(OBJ)\read.o
XVOBJ16 = $(OBJ)\restore.o  $(OBJ)\rip.o      $(OBJ)\rnd.o      $(OBJ)\rumors.o
XVOBJ17 = $(OBJ)\save.o     $(OBJ)\search.o   $(OBJ)\shk.o      $(OBJ)\shknam.o
XVOBJ18 = $(OBJ)\sit.o      $(OBJ)\sounds.o   $(OBJ)\sp_lev.o   $(OBJ)\spell.o
XVOBJ20 = $(OBJ)\steal.o    $(OBJ)\termcap.o  $(OBJ)\timeout.o  $(OBJ)\topl.o
XVOBJ21 = $(OBJ)\topten.o   $(OBJ)\track.o    $(OBJ)\trap.o     $(OBJ)\tty.o
XVOBJ22 = $(OBJ)\u_init.o   $(OBJ)\uhitm.o    $(OBJ)\unix.o     $(OBJ)\vault.o
XVOBJ23 = $(OBJ)\weapon.o   $(OBJ)\were.o     $(OBJ)\wield.o
XVOBJ24 = $(OBJ)\wizard.o   $(OBJ)\worm.o     $(OBJ)\worn.o     $(OBJ)\write.o
XVOBJ25 = $(OBJ)\zap.o
XHHOBJ  = $(OBJ)\version.o
X
XVOBJ =	$(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) $(VOBJ06) $(VOBJ07) \
X	$(VOBJ08) $(VOBJ09) $(VOBJ10) $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) \
X	$(VOBJ15) $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ20) $(VOBJ21) $(VOBJ22) \
X	$(VOBJ23) $(VOBJ24) $(VOBJ25)
XHOBJ =	$(VOBJ) $(HHOBJ)
X
XPCCONF_H   = $(INCL)\pcconf.h $(INCL)\msdos.h $(INCL)\system.h \
X	     $(INCL)\extern.h $(INCL)\def_os2.h
XGLOBAL_H   = $(INCL)\global.h $(INCL)\coord.h $(PCCONF_H)
XCONFIG_H   = $(INCL)\config.h $(INCL)\tradstdc.h $(GLOBAL_H)
XTRAP_H	   = $(INCL)\trap.h
XPERMONST_H = $(INCL)\permonst.h $(INCL)\monattk.h $(INCL)\monflag.h
XYOU_H	   = $(INCL)\you.h $(INCL)\attrib.h $(PERMONST_H) $(INCL)\mondata.h \
X	     $(INCL)\monst.h $(INCL)\youprop.h $(INCL)\prop.h $(INCL)\pm.h
XDECL_H	   = $(INCL)\decl.h $(INCL)\spell.h $(INCL)\obj.h $(YOU_H) \
X	     $(INCL)\onames.h $(INCL)\color.h
XHACK_H	   = $(CONFIG_H) $(DECL_H) $(INCL)\monsym.h $(INCL)\mkroom.h \
X	     $(INCL)\objclass.h $(INCL)\gold.h $(TRAP_H) $(INCL)\flag.h \
X	     $(INCL)\rm.h $(INCL)\hack.h
X
X# The default target
X
Xall:	makedefs lev_comp $(GAME) auxil
X	@echo Done.
X
X# The main target
X
X$(GAME): $(OBJ) $(GAMEDIR)\$(GAME).exe
X$(GAME).exe: $(GAMEDIR)\$(GAME).exe
X$(GAMEDIR)\$(GAME).exe: $(GAME).res
X	$(LINK) @$(GAME).res
X
X$(GAME).res: $(HOBJ) $(OS2DEFS)
X	@echo $(VOBJ01) +> $@
X	@echo $(VOBJ02) +>> $@
X	@echo $(VOBJ03) +>> $@
X	@echo $(VOBJ04) +>> $@
X	@echo $(VOBJ05) +>> $@
X	@echo $(VOBJ06) +>> $@
X	@echo $(VOBJ07) +>> $@
X	@echo $(VOBJ08) +>> $@
X	@echo $(VOBJ09) +>> $@
X	@echo $(VOBJ10) +>> $@
X	@echo $(VOBJ11) +>> $@
X	@echo $(VOBJ12) +>> $@
X	@echo $(VOBJ13) +>> $@
X	@echo $(VOBJ14) +>> $@
X	@echo $(VOBJ15) +>> $@
X	@echo $(VOBJ16) +>> $@
X	@echo $(VOBJ17) +>> $@
X	@echo $(VOBJ18) +>> $@
X	@echo $(VOBJ20) +>> $@
X	@echo $(VOBJ21) +>> $@
X	@echo $(VOBJ22) +>> $@
X	@echo $(VOBJ23) +>> $@
X	@echo $(VOBJ24) +>> $@
X	@echo $(VOBJ25) +>> $@
X	@echo $(HHOBJ)>> $@
X	@echo $(GAMEDIR)\$(GAME)>> $@
X	@echo $(GAME)>> $@
X	@echo $(PLIBS) $(TERMLIB)>> $@
X	@echo $(OS2DEFS) $(LFLAGS);>> $@
X
X$(OBJ):
X	-mkdir $(OBJ)
X
X# Targets for makedefs.
X
Xmakedefs: $(OBJ) makedefs.exe
Xmakedefs.exe: makedefs.res
X	$(LINK) @makedefs.res
X
Xmakedefs.res: $(MAKEOBJS)
X	@echo $(MAKEOBJS)> $@
X	@echo makedefs>> $@
X	@echo nul>> $@
X	@echo $(RLIBS)>> $@
X	@echo $(LFLAGS);>> $@
X
X$(OBJ)\makedefs.o : $(CB) $(INCL)\config.h $(INCL)\permonst.h $(INCL)\objclass.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X
X# Targets for the special levels compiler.
X
Xlev_comp: $(OBJ) lev_comp.exe
Xlev_comp.exe: lev_comp.res
X	$(LINK) @lev_comp.res
X
Xlev_comp.res: $(SPLEVOBJS)
X	@echo $(SOBJ01) +> $@
X	@echo $(SOBJ02)>> $@
X	@echo lev_comp>> $@
X	@echo nul>> $@
X	@echo $(RLIBS)>> $@
X	@echo $(LFLAGS);>> $@
X
X$(OBJ)\lev_comp.o : $(CB) $(HACK_H) $(INCL)\sp_lev.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\lev_lex.o  : $(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev_comp.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\lev_main.o : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X
Xlev_comp.c : lev_comp.y
X	$(MAKEBIN) do_yacc
X
Xlev_lex.c  : lev_comp.l
X	$(MAKEBIN) do_lex
X
Xyacc_msg:
X	@echo lev_comp.y has changed. To update lev_comp.c and lev_comp.h run YACC.
X
Xyacc_act:
X	$(YACC) -d lev_comp.y
X	copy $(YTABC) lev_comp.c
X	copy $(YTABH) $(INCL)\lev_comp.h
X	del $(YTABC)
X	del $(YTABH)
X
Xlex_msg:
X	@echo lev_comp.l has changed. To update lev_lex.c run LEX.
X
Xlex_act:
X	$(LEX) lev_comp.l
X	copy $(LEXYYC) lev_lex.c
X	del $(LEXYYC)
X
X#
X#	The following include files depend on makedefs to be created.
X#
X#	date.h should be remade any time any of the source or include code
X#	is modified.
X#
X$(INCL)\date.h: $(VOBJ) makedefs.exe
X	makedefs -v
X
X$(INCL)\trap.h:	makedefs.exe
X	makedefs -t
X
X$(INCL)\onames.h: makedefs.exe
X	makedefs -o
X
X$(INCL)\pm.h: makedefs.exe
X	makedefs -p
X
Xdata:	$(AUX)\data.bas makedefs.exe
X	makedefs -d
X
Xrumors: $(AUX)\rumors.tru $(AUX)\rumors.fal makedefs.exe
X	makedefs -r
X
X#
X#	The following programs vary depending on what OS you are using.
X#
X$(OBJ)\main.o: pc$(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ pc$(AB)
X
X$(OBJ)\tty.o:  pc$(CB) $(HACK_H) $(INCL)\func_tab.h
X	$(CC) $(CFLAGS) /Fo$@ pc$(AB)
X
X$(OBJ)\unix.o: pc$(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ pc$(AB)
X
X#
X# Secondary targets
X#
X
Xauxil:	spec_lev data rumors
X	xcopy $(AUX)\cmdhelp $(GAMEDIR)
X	xcopy $(AUX)\help    $(GAMEDIR)
X	xcopy $(AUX)\hh      $(GAMEDIR)
X	xcopy $(AUX)\history $(GAMEDIR)
X	xcopy $(AUX)\license $(GAMEDIR)
X	xcopy $(AUX)\opthelp $(GAMEDIR)
X	xcopy $(AUX)\oracles $(GAMEDIR)
X	xcopy $(AUX)\data    $(GAMEDIR)
X	xcopy $(AUX)\rumors  $(GAMEDIR)
X
Xspec_lev: $(AUX)\castle.des $(AUX)\endgame.des $(AUX)\tower.des
X	lev_comp $(AUX)\castle.des
X	lev_comp $(AUX)\endgame.des
X	lev_comp $(AUX)\tower.des
X	xcopy castle  $(GAMEDIR)
X	xcopy endgame $(GAMEDIR)
X	xcopy tower?  $(GAMEDIR)
X	del castle
X	del endgame
X	del tower?
X
X$(OS2DEFS):
X	@echo NAME $(GAME) WINDOWCOMPAT> $(OS2DEFS)
X	@echo DESCRIPTION '$(GAMEDES)'>> $(OS2DEFS)
X	@echo PROTMODE>> $(OS2DEFS)
X	@echo EXETYPE OS2>> $(OS2DEFS)
X
Xclean:
X	-del $(OBJ)\*.o
X	-rmdir $(OBJ)
X
Xspotless: clean
X	-del $(INCL)\date.h
X	-del $(INCL)\onames.h
X	-del $(INCL)\pm.h
X	-del makedefs.exe
X	-del lev_comp.exe
X	-del *.res
X	-del *.def
X	-del *.map
X	-del $(AUX)\data
X	-del $(AUX)\rumors
X	-del castle
X	-del endgame
X	-del tower?
X
X#
X# Other dependencies.
X#
X# MS-NMAKE doesn't give a damn about default rules here, so until
X# that is fixed, we do this the hard way.
X#
X
X$(OBJ)\allmain.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\alloc.o    : $(CB) $(CONFIG_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\apply.o    : $(CB) $(HACK_H) $(INCL)\edog.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\artifact.o : $(CB) $(HACK_H) $(INCL)\artifact.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\attrib.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\bones.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\cmd.o      : $(CB) $(HACK_H) $(INCL)\func_tab.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\dbridge.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\decl.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\demon.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\do.o       : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\do_name.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\do_wear.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\dog.o      : $(CB) $(HACK_H) $(INCL)\edog.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\dogmove.o  : $(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\dokick.o   : $(CB) $(HACK_H) $(INCL)\eshk.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\dothrow.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\eat.o      : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\end.o      : $(CB) $(HACK_H) $(INCL)\eshk.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\engrave.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\exper.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\extralev.o : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\fountain.o : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\getline.o  : $(CB) $(HACK_H) $(INCL)\func_tab.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\hack.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\invent.o   : $(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\ioctl.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\lock.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\makemon.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mail.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mcastu.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mhitm.o    : $(CB) $(HACK_H) $(INCL)\artifact.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mhitu.o    : $(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mklev.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mkmaze.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mkobj.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mkroom.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mon.o      : $(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mondata.o  : $(CB) $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\monmove.o  : $(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\monst.o    : $(CB) $(CONFIG_H) $(PERMONST_H) $(INCL)\monsym.h $(INCL)\eshk.h \
X		    $(INCL)\vault.h $(INCL)\epri.h $(INCL)\color.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\msdos.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\mthrowu.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\music.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\o_init.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\objects.o  : $(CB) $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\prop.h \
X		    $(INCL)\color.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\objnam.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\options.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\pager.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\panic.o    : $(CB) $(CONFIG_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\pickup.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\polyself.o : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\potion.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\pray.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\pri.o      : $(CB) $(HACK_H) $(INCL)\epri.h $(INCL)\termcap.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\priest.o   : $(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h $(INCL)\epri.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\prisym.o   : $(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\random.o   : $(CB)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\read.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\restore.o  : $(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\rip.o      : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\rnd.o      : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\rumors.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\save.o     : $(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\search.o   : $(CB) $(HACK_H) $(INCL)\artifact.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\shk.o      : $(CB) $(HACK_H) $(INCL)\eshk.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\shknam.o   : $(CB) $(HACK_H) $(INCL)\eshk.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\sit.o      : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\sounds.o   : $(CB) $(HACK_H) $(INCL)\edog.h $(INCL)\eshk.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\sp_lev.o   : $(CB) $(HACK_H) $(INCL)\sp_lev.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\spell.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\steal.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\termcap.o  : $(CB) $(HACK_H) $(INCL)\termcap.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\timeout.o  : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\topl.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\topten.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\track.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\trap.o     : $(CB) $(HACK_H) $(INCL)\edog.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\u_init.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\uhitm.o    : $(CB) $(HACK_H) $(INCL)\artifact.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\vault.o    : $(CB) $(HACK_H) $(INCL)\vault.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\version.o  : $(CB) $(HACK_H) $(INCL)\date.h $(INCL)\patchlev.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\weapon.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\were.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\wield.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\wizard.o   : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\worm.o     : $(CB) $(HACK_H) $(INCL)\wseg.h
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\worn.o     : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\write.o    : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
X$(OBJ)\zap.o      : $(CB) $(HACK_H)
X	$(CC) $(CFLAGS) /Fo$@ $(AB)
END_OF_FILE
if test 17844 -ne `wc -c <'others/Makefile.os2'`; then
    echo shar: \"'others/Makefile.os2'\" unpacked with wrong size!
fi
# end of 'others/Makefile.os2'
fi
if test -f 'others/maintain.ovl' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'others/maintain.ovl'\"
else
echo shar: Extracting \"'others/maintain.ovl'\" \(17778 characters\)
sed "s/^X//" >'others/maintain.ovl' <<'END_OF_FILE'
X			Maintaining PC NetHack
X		       ========================
X		       Last revision: 1990may27
X
XThe installation of the system of overlay management that currently
Xbrings full-featured NetHack to the IBM PC and compatibles has
Xintroduced a number of arcanities into the source code of the
Xprogramme, and unfortunately running afoul of these intricacies can
Xresult (as we ourselves have discovered) in the most bizarre and
Xstrangely inexplicable dysfunctional manifestations, aka sick bugs.
X
XThis document is required reading for anyone making substantive
Xchanges to NetHack for the PC or embarking upon a revision of its
Xoverlay structure.
X
X
X1. The overlay manager
X----------------------
XNetHack is by now a fairly large programme (in excess of 800
Xkilobytes), and in order to compile it for the PC (which typically
Xhas little more than 500k of available memory) it was necessary to
Xrely on the technique of _overlaying_, whereby not all the
Xprogramme is resident in memory at the same time, segments of the
Xprogramme being loaded and discarded as they are needed. Unlike
Xtraditional candidates for the overlaying strategy, however, NetHack
Xdoes not exhibit strongly phased behaviour; although much of the code
Xis not being used at any one moment, there is comparatively little
Xcode that can be confidently said not to be related to or potentially
Xnecessary for the immediate progress of the game.
X	Furthermore we wished to develop an overlaying strategy that
Xdid _not_ involve intimate knowledge of the operation of the
Xprogramme (since NetHack is an international team effort, and few
Xpeople have a good feeling for the totality of the code structure),
Xand which would not require substantive changes to the source code,
Ximpacting on its maintainability and portability.
X	It turned out to be impossible to satisfy these goals with
Xtools that are widely available at the time of writing, and so we
Xundertook to write our own overlay manager (compatible with
XMicrosoft's, but more in concert with NetHack's particular needs).
XThe result is called ovlmgr.asm and is documented in the file
Xovlmgr.doc. You would probably be well advised to read at least the
Xless technical parts of that file now.
X
X
X2. The trampoli mechanism
X-------------------------
XOne of the difficulties with using overlays for C (particularly
XMicrosoft C) is that while common C programming practise places heavy
Xreliance on function pointers, Microsoft's overlay linker is unable
Xto resolve calls through pointers to functions that are in remote
Xoverlays. Nor, unfortunately, does it choose to report such failures;
Xrather, it generates calls into (what often turns out to be in the
Xcase of our nonstandard overlay manager) the deepest of space. This
Xcan result in truly strange behaviour on the part of your programme -
Xincluding bugs that come and go in as close to a random pattern as
Xyou are ever likely to see.
X	Other than the creative use of pattern-matching utilities
Xsuch as grep to locate the offending calls, there is unfortunately no
Xadvice we can offer in tracking down these bugs. Once they have been
Xisolated, however, they can be remedied straightforwardly.
X
XIn order for the linker not to screw up on a pointered function call
Xit is (to simplify an actually rather complicated situation)
Xnecessary that the function called be located in the ROOT "overlay",
Xand thus not be subject to swapping. Rather than linking the full
Xtext of every pointered function into the root, however, it suffices
Xto place a "trampoline" function there which performs a direct call
Xto the "real" function that does the work, in whatever overlay it
Xmight naturally reside in. Due to a not-quite-accident of the
Xbehaviour of the C preprocessor (it was originally intended to make
Xpossible functions whose address can be taken but which expand inline
Xas macros where possible, a not unrelated function), it turns out to
Xbe possible to arrange for this without major change to the C source
Xcode - and without serious impact on the performance of "regular"
Xcalls to the same functions.
X
XThe C preprocessor's expansion of a macro with parameters is triggered
Xby an encounter with the macro name immediately followed by an open
Xparenthesis. If the name is found, but it is not followed by a
Xparenthesis, the macro is not matched and no expansion takes place.
XAt the same time it may be noted that (unless someone has been oddly
Xstrange and enclosed a function name in quite unneeded parentheses!),
Xa function name is typically followed by an open parenthesis if, and
Xonly if, it is being declared, defined or invoked; if its address is
Xbeing taken it will necessarily be followed by some other token.
XFurthermore (except in the unfortunate case of the ill-conceived
Xnew-style ANSI declaration of a function that takes no parameters) it
Xwill be observed that the number of parameters to a call of the
Xfunction (assuming that this number is fixed; if not, I grant, we
Xhave a problem) is the same in all these contexts. This implies that
Xif all the modules of a programme are uniformly processed in the
Xcontext of a macro definition such as
X
X	#define zook(a,b) plenk(a,b)
X
Xand assuming that all functions named zook() take exactly two
Xarguments, then the resulting programme will be completely identical
Xto the original (without this definition) except that the link
Xmap will report the existence of the function plenk() in place of
Xzook() -- UNLESS there was a place in the programme where the address
Xof zook was taken. In that case, the linker would report an
Xunresolved external reference for that symbol.
X	That unresolved reference is, of course, precisely what we
Xneed; if in another source file (one that did not see the macro
Xdefinition) we placed the function declaration
X
X	some_t zook(this_t a, that_t b)
X	  { extern some_t plenk(this_t, that_t);
X	    return plenk(a, b);
X	  }
X
Xthis would both satisfy the unresolved reference and restore the
Xoriginal semantics of the programme (even including pointer
Xcomparison!) -- while providing us with precisely the kind of
X"trampoline" module that we need to circumvent the problem with the
Xlinker.
X	This is the basis of the approach we have taken in PC
XNetHack; rather than using the somewhat idiosyncratic identifier
X"plenk", however, we have systematically employed (in the files
Xtrampoli.h and trampoli.c) identifiers generated by appending
Xunderscores to the ends of the names of the functions we have needed
Xto so indirect(1).
X
XThere are a few small complications. The first is ensuring that both
Xthe versions of the trampoli'd function (foo() and foo_()) are
Xsimilarly typed by the appropriate extern declarations (which
Xthemselves must be written); this can be accomplished by placing all
Xof these declarations in a header file that is processed _twice_,
Xonce before and once after the inclusion of the file containing the
Xtrampoli macro definitions, thereby ensuring that both variants of
Xthe name have been seen in connection with the appropriate types. The
Xsecond is that some care must be exercised not to employ other macros
Xthat interfere with the normal recognition of function syntax: it is
Xthe presence of the open parenthesis after the name of the function
Xthat triggers name substitution, and not the fact that the function
Xis called; and so (particularly in the case of declarations) it is
Xnecessary that if a macro is used to supply the _arguments_ of a
Xtrampoli'd function, it must also supply the name (this necessity in
Xfact triggered a change in the style of the macros that provide
Xdialect-independent function declaration in NetHack; the new style
Xwould have you write FDECL(functionName, (argTypes...)).
X	Finally, there is the case of functions declared to take no
Xarguments whatsoever; in Standard C this is notated:
X
X	some_t aFunction(void);
X
Xfor no theoretically well-motivated reason I can discern. Such a
Xdeclaration will _not_ match a macro definition such as
X
X	#define aFunction() aFunction_()
X
X-- in fact the compiler will detect an error when processing that
Xdeclaration in the scope of this macro. The only solution is to
Xeschew the use of this strange syntax and unfrabjously forgo the
Xconcomitant security of well- and thoroughly- checked typage. To
Xwhich end we have provided an ecchy macro, NDECL(functionName), which
Xuses the new syntax _unless_ the compiler is not Standard or OVERLAY
Xis enabled.
X
XThere is one further consideration: that this technique only applies,
Xof course, to functions that are published to the linker. For this
Xreason, wherever such trampoli'd functions were originally declared
Xstatic, that declaration has been changed to "STATIC_PTR", a macro
Xthat expands to "static" unless the OVERLAY flag has been selected in
Xthe configuration file, enabling the trampoli mechanism. Thus such
Xfunctions lose their privacy in this one case.
X
X
X3. OVLx
X-------
XThe strategies described above work fine, but they only stretch so
Xfar. In particular, they do not admit of an overlay structure in
Xwhich functions are linked into different overlays even though they
Xoriginate in the same source file.
X	Classically, this is not considered a real limitation,
Xbecause one has the freedom to regroup the functions into different
Xsource files as needed; however, in the case of NetHack this was not
Xa realistic option, since what structure this unwieldy programme has
Xis precisely in the current grouping of functions together.
XNonetheless, the ability to perform some functional grouping is an
Xabsolute requirement for acceptable performance, since many NetHack
Xsource modules (were.c, for example) contain one or two tiny
Xfunctions that are called with great frequency (several millions of
Xtimes per game is not unheard of) and whose return value determines
Xwhether the remaining large, slow functions of the file will be
Xrequired at all in the near future. Obviously these small checking
Xfunctions should be linked into the same overlays with their callers,
Xwhile the remainder of the source module should not.
X
XIn order to make this possible we ran a dynamic profile on the game
Xto determine exactly which functions in which modules required such
Xdistinguished treatment, and we have flagged each function for
Xconditional compilation (with #if ... #endif) in groups according
Xapproximately to their frequency of invocation and functionality.
XThese groups have been arbitrarily named in each source file (in
Xdecreasing order of frequency), OVL0, OVL1, OVL2, OVL3 and OVLB (B
Xfor "base functions", those that deserve no special treatment at
Xall). It is thus possible to compile only a small number of the
Xfunctions in a file by defining but one or two of these symbols on
Xthe compiler's command line (with the switch /DOVL2, for example);
Xthe compiler will ignore the remainder as if they did not exist.
X(There is an "escape clause" in hack.h that ensures that if none of
Xthese flags is defined on the command line, then all of them will be
Xduring compilation; this makes the non-use of this mechanism
Xstraightforward!)
X	By repeated invocation of the compiler on the _same_ source
Xfile it is possible to accumulate disjoint object modules that
Xbetween them contain the images of all the functions in the original
Xsource, but partitioned as is most convenient. Care must, of course,
Xbe taken over conflicts of name in both the object file put out (all
Xslices will by default be called SRCFILE.OBJ, and this default must
Xbe overridden with distinct file names for each output slice) and in
Xthe names of the text segments the compiler is to generate; you can
Xsee this at work in Makefile.ovl. (You may wonder, as we did at
Xfirst, why the text segment name would have to be made distinct in
Xeach object file slice (the default segment name is a function of the
Xsource file name and the compilation model only). The reason for this
Xis, quite daftly to my mind, that the linker considers the identity
Xof segment names and combine classes better reason to combine
Xsegments than the programmer's explicit instructions in the requested
Xoverlay pattern are reason to keep them apart. Programmer, ask not
Xwhy...).
X
XOnce again, that works fine except for the small matter of
Xdeclarations (where have we heard this before?). For objects that
Xonce were static must now be made visible to the linker that they may
Xbe resolved across the reaches of inter-overlay space. To this end we
Xhave provided three macros, all of which expand simply to "static" if
Xno OVLx flags are defined on the compilation command line. They are:
X
XSTATIC_DCL	which introduces a declaration (as distinct from a
X		definition) of an object that would be static were it
X		not for the requirements of the OVLx mechanism. Its
X		expansion is "static", normally, but it becomes
X		"extern" in the event that this source file has been
X		split into slices with the OVLx mechanism.
X
XSTATIC_OVL	is used when _defining_ a function (giving its text,
X		that is) that is logically static but may be called
X		across slices; it expands to "static" unless OVLx is
X		active; in the latter case it expands to null,
X		leaving the function with "previous linkage" as the
X		standard says. Note that this behaviour is quite
X		similar to, but very different from, that of
X		STATIC_PTR (described above), which has the same two
X		expansions but which is triggered not by OVLx but by
X		the OVERLAY flag which enables the trampoli mechanism.
X			STATIC_OVL also differs from the STATIC_DCL
X		and STATIC_VAR in that it is employed _within_ OVLx
X		slices, while the others are used to generate
X		declarations and are deployed in areas common to all
X		slices.
X
XSTATIC_VAR	is used to introduce uninitialised would-be-static
X		variables. Its expansion is complex, since it must
X		read as "static" in the usual case, but as "extern"
X		if OVLx is in use -- in all overlays but one, where
X		it must expand to the null sequence -- giving it
X		"previous linkage" and "tentative definition" (to
X		ensure that the variable gets defined at all).
X			This one took a while to get right, and
X		believe me, using the macro is a lot easier than
X		trying to keep the #ifdefs straight yourself!
X
XAn initialised variable that is file-level static unless OVLx is in
Xuse must now be written with a STATIC_DCL declaration, and a
Xdefinition (and static initialiser) enclosed within the bracketing
Xtag of one of the OVLx slices (any will do; we use OVLB).
X	Type definitions, macro definitions and extern declarations
Xshould, of course remain outside any OVLx slice.
X
XFinally, of course, objects whose visibility need not be extended may
Xsafely continue to be declared static. And in this case, at least,
Xthe compiler will provide diagnostics that inform you when an object
Xhas slipped through the cracks and requires the application of Magic
XMacro Salve.
X
XIt is perhaps less than obvious that when a function is _both_ called
Xacross an OVLx split and referenced through a pointer, it should be
Xtreated as a pointered function (that is, it should get trampoli
Xentries and should be defined STATIC_PTR). The reason for this is that
Xthe STATIC_xxx macros associated with OVLx _only_ change the
Xdeclaration patterns of the objects, while trampoli results in the
Xgeneration of necessary code.
X	It is correct to do this, because the declarations produced by
XSTATIC_PTR are triggered by OVERLAY's being defined, and the selection
Xof OVERLAY is an absolute precondition for the activation of OVLx.
X
X
X4. Hacking
X----------
XBefore undertaking any serious modifications to the overlay structure
Xor support mechanisms, you should know that a _lot_ of work has gone
Xinto the current scheme. If performance seems poor, remember: the
Xoverlay manager itself can be invoked up to ten thousand times in a
Xsecond, and although the space available for loading overlays (once
Xthe data and stack spaces have been accounted for) is less than half
Xthe total size of the overlays that are swapped through it, a disk
Xaccess occurs well under 0.1% of the time(2). Furthermore, this
Xperformance (such as it is) has been achieved without substantive
Xchange or restructuring of the NetHack source code, which must remain
Xportable to many platforms other than the PC.
X
XIf these observations do not daunt you, you are a true Bit Warrior
Xindeed (or aspiration anyway), and we await your comments with bait.
X
X------------------------------------------------------------------------
X
XNOTES:
X------
X
X(1) In fact, we have applied this technique throughout NetHack, even
X    in cases where it is not strictly necessary (since the pointered
X    calls are not across overlay splits, for example - though note
X    that there are more splits than might be initially apparent, due
X    to the effects of the OVLx hackage as described in section 3).
X    There is, however, one exception; and beware: it is an exception
X    with fangs. The file termcap.c contains a few pointered functions
X    that we decided _not_ to trampoli for performance reasons (screen
X    output is one of the problem areas on the PC port at the moment,
X    in terms of performance). It is therefore vital to the health of
X    PC NetHack as it currently stands that the OVLx slice termcap.0 be
X    linked into the ROOT "overlay".
X
X(2) These figures are for a 4.77 MHz PC-XT running in low memory with
X    an older version of both the overlay manager and the NetHack
X    overlay arrangement. On a more capable computer and with the
X    current software, the figures are probably more like a 100kHz peak
X    service rate and a hit rate (since we fixed the bug in the LRU
X    clock logic!) in excess of 99.99% -- hopefully not both at the
X    same time.
X
X------------------------------------------------------------------------
XStephen P Spackman                             stephen@tira.uchicago.edu
X------------------------------------------------------------------------
X			     * Hack On! *
END_OF_FILE
if test 17778 -ne `wc -c <'others/maintain.ovl'`; then
    echo shar: \"'others/maintain.ovl'\" unpacked with wrong size!
fi
# end of 'others/maintain.ovl'
fi
echo shar: End of archive 39 \(of 56\).
cp /dev/null ark39isdone
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