[comp.sources.games] v03i013: NetHack2.2 - display oriented dungeons and dragons, Part13/20

games-request@tekred.TEK.COM (12/02/87)

Submitted by: mike@genat.UUCP (Mike Stephenson)
Comp.sources.games: Volume 3, Issue 13
Archive-name: nethack2.2/Part13



#! /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 13 (of 20)."
# Contents:  Fixes.2.2 cmd.c date.h save.c spell.c unixunix.c
# Wrapped by billr@tekred on Tue Dec  1 16:25:06 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Fixes.2.2 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Fixes.2.2\"
else
echo shar: Extracting \"Fixes.2.2\" \(8320 characters\)
sed "s/^X//" >Fixes.2.2 <<'END_OF_Fixes.2.2'
X		NetHack Fixes List	Revision 2.2
X
XGuidebook.mn	New file "Guide to the Mazes of Menace". By Eric Raymond.
XGuidebook	A file for preparation using the "mn" macros supplied with
X		the 2.11 news release, as well as an ascii version of the
X		same. 
X
XNetHack.cnf	Sample configuration file for the PC. (creps@silver)
X
XMakefiles	Corrected problem in which the linking was done on build and
X(unix/xenix)	on install. (Contributed by Janet Walz - walz@mimsy)
X
XMakefile.att	Added a makefile for the AT&T Unix PC using shared libraries.
X		(Contributed by ahby@umn-cs)
X
XMakefile.pc	Streamlined compilation of main.o, tty.o, and unix.o
XMakefile.tcc	(Contributed by polder@cs.vu.nl).
X
Xdata.base	deletion of duplicate lines and spelling fixes. (sweet@scubed)
X
Xinvent.c	REDO problem with "What do you want to..." text fixed.
X		down stairway identification fixed.
X		Alloc "buf" to allow for variable length HI/HE. (tom@uw-warp)
X
Xengrave.c	Correction to "feel" code. (mike@genat)
X		Corrected switch for message determination. (patrickm@hpisof0)
X		BURN'ed engravings made un-erasable again. (kyrimis@princeton)
X
Xpri.c		Added colour highliting functions (sweet@scubed)
X
Xprisym.c	changed "symbol.room" to "ROOM_SYM" (one I missed)
X		(Ralf.Brown@b.gp.cs.cmu.edu)
X		Changed "dirlet()" to return an int. (maartenj@cs.vu.nl)
X
Xmsdos.c		Changed "symbol" to "showsyms" (Ralf.Brown@b.gp.cs.cmu.edu)
X		Fixed up REDO & IBMBIOS stuff. (Kevin Sweet - sweet@scubed)
X
Xdo.c		Dropping gold asked for only when gold posessed. (walz@mimsy)
X		Potential unsigned value problem fixed (u.ucreamed)
X		Added leash dropping code. (maartenj@cs.vu.nl)
X		Blind modifications for blindfolding.  (eric@snark)
X		Value wrap fixed for u.ucreamed
X
Xfight.c		Dog's name now used in hitting avoidence message. (walz@mimsy)
X		Variable initialization fixed w.r.t. #ifdef / #else.
X		(Reported by Erwin Unruh - unruh@infbs)
X		Added giant rats and kobolds back into code. (sweet@scubed)
X
Xspell.c		Potential unsigned value problem fixed (u.ulevel).
X		Typos corrected. (Tom May - tom@uw-warp)
X		Blind modifications for blindfolding.  (eric@snark)
X
Xshk.c		"inshop" crash bug corrected (many sources).
X		extern declaration of carrying() moved to avoid a Turbo-C
X		type mismatch msg. (Ralf.Brown@b.gp.cs.cmu.edu)
X		Added new "online()" which executes faster. (tom@uw-warp)
X		Blind modifications for blindfolding.  (eric@snark)
X		Added item pricing shopkeeper talk.
X		(Idea from a hacked up 1.0.1 source sent in by michael@stb)
X		Cleaned up Kops code. (sweet@scubed)
X
Xmhitu.c		Argument mismatches fixed. (walz@mimsy)
X		Scorpion/spider mixup fix. (William LeFebvre - phil@rice.edu)
X		Blind modifications for blindfolding.  (eric@snark)
X
Xpotion.c	Argument mismatch fixed. (walz@mimsy)
X		Blind modifications for blindfolding.  (eric@snark)
X		Poison handling made more dependant on poison resistance.
X		(From an idea by Steve Creps - creps@silver)
X
Xmklev.c		Fixed up installation of vamp traps. (sweet@scubed)
X
Xmakemon.c	Monster creation location bug fixed. (walz@mimsy)
X		Monster creation crash fixed. (many sources)
X		Monster posessions bug fixed. (S. Wrammerfors stewr@obelix)
X		Added giant rats and kobolds back into code. (sweet@scubed)
X
Xhack.c		"Elbereth" effectiveness increased under "HARD" option to
X		be reasonable. (walz@mimsy)
X		Declaration of "register struct monst *m_at()" fixed. (many)
X		Typo fixed. (tom@uw-warp)
X		Fixed scroll of scare monster pickup problems (and giveaway)
X		(polder@cs.vu.nl)
X		Documentation modifications for blindfolding.  (eric@snark)
X
Xioctl.c		ioctl call for SET changed to function properly under
X
Xunixtty.c	Sys V R3 mods.  (tom@uw-warp)
X
Xdecl.c		in_doagain initialized. (many sources)
X
Xwield.c		Ability to remove cursed weapons w. w- removed. (many sources)
X
Xoptions.c	Major rewrite of options help.  Now uses pager.  (mike@genat)
X		Rewrote GRAPHICS setup. (maartenj@cs.vu.nl)
X		Allowed reassignment of inventory order #ifdef DGK
X		(polder@cs.vu.nl)
X
Xpray.c		Fixed mk_obj of spellbook under all conditions to make book
X		if "SPELLS" defined, and scroll otherwise. (unruh@infbs)
X		Fixed typo in "gods angry" text. (tom@uw-warp)
X		Fixed blessing code. (Simon Brown - simon@its63b)
X		Blind modifications for blindfolding.  (eric@snark)
X
Xzap.c		Potion of invis. breakage message improved. (unruh@infbs)
X		Added WAN_PROBING to "zapyourself".
X		Changed "dirlet()" to return an int. (maartenj@cs.vu.nl)
X		Fixed cancellation code to work properly on wands (spe
X		set to -1 instead of 0) this means no infinite wands of
X		wishing. (Ron Wessels - ron@utcsri)
X		Fixed bug in "buzz()" causing crash when destroying a
X		trapper from inside with a wand/spell.  (mike@genat)
X		Added fcn to destroy wands with zero charges. (sweet@scubed)
X
Xpcmain.c	Added a routine to zero out the fileinfo array in order to
X		prevent crashes on level change. (ralf@b.gp.cs.cmu.edu)
X		Added chdir to HACKDIR before looking for .CNF file.
X		Added call "uptodate(savefile)". (polder@cs.vu.nl)
X
Xpager.c		changed "cornline()" to use xputs for HI/HE. (tom@uw-warp)
X		added choice for dowhatis() to allow letter or cursor object
X		selection. (polder@cs.vu.nl)
X
Xcmd.c		Added ^W (wish) and ^I (ident-all) commands for WIZARD-mode.
X		(Paul Polderman - polder@cs.vu.nl)
X		Added "Z" as alternate to "# cast" (Eric Raymond - eric@snark)
X
Xu_init.c	Expanded a tab which didn't show in raw mode.
X		Changed trobj.trotyp to "unsigned short" to avoid >255
X		problems. (Maarten Jan Huisjes - maartenj@cs.vu.nl)
X		Removed wand of wishing from WIZARD's inventory (due to
X		the above cmd additions). (polder@cs.vu.nl)
X		Fixed declaration of leash. (simon@its63b)
X		Beefed up Wizard class.
X		Added Wakizashi for Samurai.
X		Added holy water for Priest(ess)es.
X		Modifications to provide blindfolds.  (eric@snark)
X
Xend.c		changed inventory identification on death to list form.
X		(polder@cs.vu.nl)
X		added hallucination effects to done_in_by()
X		added posession of amulet flag for scoreboard (sweet@scubed)
X
Xwizard.c	corrected "nasties" decl. (maartenj@cs.vu.nl)
X		Blind modifications for blindfolding.  (eric@snark)
X
Xdo_wear.c	Prot. from shape changers logic fixed. (maartenj@cs.vu.nl)
X
Xlev.c		Prot. from shape changers logic fixed. (maartenj@cs.vu.nl)
X
Xmon.c		Inserted cast to fix compiler warning. (maartenj@cs.vu.nl)
X		Nymphs now leave potions of object detection when killed.
X		Kops now don't leave treasure behind. (sweet@scubed)
X
Xtopl.c		Changed size of "toplines" to avoid overflow in "parseoptions"
X		when help is asked for. (probably n/a) (maartenj@cs.vu.nl)
X
Xtopten.c	Added longer death descriptions, including name of
X		shopkeeper who killed character.  (many sources)
X
Xtermcap.c	Changed allocation of HI/HO for copying SI/SO to allow room
X		for null.  (maartenj@cs.vu.nl)
X		Added PCHack 3.61 termcap stuff.
X		Added colour highliting code. (sweet@scubed)
X
Xversion.c	Expanded a tab for rawmode io. (maartenj@cs.vu.nl)
X
Xobjnam.c	Allow the WIZARD to wish for really excessive objects.
X		(polder@cs.vu.nl)
X
Xmakedefs.c	Added "freopen" which works (MSC 4.0 drops first couple
X		of lines).  Solves missing #define AMULET... problem.
X		(Nathan Glasser - nathan@mit-eddie)
X
Xrnd.c		Changed around random number generation:
X		BSD uses "random()". (Paul Eggert - eggert@grand)
X		SYSV uses "lrand48()". (mike@genat from above)
X
Xeat.c		Changed "choke()" code to waste food rather than choke on
X		it #ifndef HARD. (Allan Pratt - apratt@atari)
X		Blind modifications for blindfolding.  (eric@snark)
X
Xobjects.h	added blindfold object (tool).  (eric@snark)
X
Xyou.h		changed Blind/BLIND to Blinded/Blinded
X		added Blindfolded/BLINDFOLDED
X		redefined Blind in terms of above parameters.  (eric@snark)
X
Xapply.c		added blindfold code.  (eric@snark)
X
Xtimeout.c	Blind modifications for blindfolding.  (eric@snark)
X
Xsit.c		Blind modifications for blindfolding.  (eric@snark)
X
Xtrap.c		Blind modifications for blindfolding.  (eric@snark)
X		Level teleportation to hell fixed so that it will not
X		do so unless character has Fire_resistance. (many sources)
X		Added polymorph trap. (many sources)
X
Xmonmove.c	added check on presence of "fobj" before atl() call
X		to avoid potential segmentation problem with ROCKMOLE.
X		(Reported by Doug Rudoff - doug@wiley)
X
Xvarious files	Fixed typos.  Also converted British English words to
X		American English for uniformity.  (Original list of typos
X		submitted by Steve Creps - creps@silver)
END_OF_Fixes.2.2
if test 8320 -ne `wc -c <Fixes.2.2`; then
    echo shar: \"Fixes.2.2\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f cmd.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cmd.c\"
else
echo shar: Extracting \"cmd.c\" \(10896 characters\)
sed "s/^X//" >cmd.c <<'END_OF_cmd.c'
X/*	SCCS Id: @(#)cmd.c	2.0	87/09/15
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include	"hack.h"
X#include	"func_tab.h"
X
Xint doredraw(),doredotopl(),dodrop(),dodrink(),doread(),dosearch(),dopickup(),
Xdoversion(),doweararm(),dowearring(),doremarm(),doddoremarm(),doremring(),
Xdopay(),doapply(),dosave(),dowield(),ddoinv(),dozap(),ddocall(),dowhatis(),
Xdoengrave(),dotele(),dohelp(),doeat(),doddrop(),do_mname(),doidtrap(),
Xdoprwep(),doprarm(),doprring(),doprgold(),dodiscovered(),dotypeinv(),dolook(),
Xdoset(),doup(), dodown(), done1(), donull(), dothrow(), doextcmd(), dodip(),
Xdopray(), doextlist();
X#ifdef WIZARD
Xint wiz_wish(), wiz_identify();
X#endif
X#ifdef NEWCLASS
Xint dosit(), doturn();
X#endif
X#ifdef SPELLS
Xint docast(), dovspell(), doxcribe();
X#endif
X#ifdef SHELL
Xint dosh();
X#endif
X#ifdef SUSPEND
Xint dosuspend();
X#endif
X#ifdef KAA
Xint doremove(), dobreathe();
X# ifdef KOPS
Xint dowipe();
X# endif
X#endif
X
Xint rndobjsym(), rndmonsym();
Xchar *hcolor(), *rndmonnam(), *defmonnam();
X
Xextern char *occtxt;
Xextern int (*occupation)();
X
X#ifdef DGKMOD
Xint dotogglepickup(), doMSCversion();
X# ifdef DEBUG
Xint dodebug();
X# endif
X
Xstatic int (*timed_occ_fn)();
X
X/* Count down by decrementing multi */
Xtimed_occupation() {
X	(*timed_occ_fn)();
X	if (multi > 0)
X		multi--;
X	return (multi > 0);
X}
X
X/* If a time is given, use it to timeout this function, otherwise the
X * function times out by its own means.
X */
Xvoid
Xset_occupation(fn, txt, time)
Xint (*fn)();
Xchar *txt;
X{
X	if (time) {
X		occupation = timed_occupation;
X		timed_occ_fn = fn;
X	} else
X		occupation = fn;
X	occtxt = txt;
X	occtime = 0;
X}
X#endif /* DGKMOD */
X
X#ifdef REDO
X/* Provide a means to redo the last command.  The flag `in_doagain' is set
X * to true while redoing the command.  This flag is tested in commands that
X * require additional input (like `throw' which requires a thing and a
X * direction), and the input prompt is not shown.  Also, while in_doagain is
X * TRUE, no keystrokes can be saved into the saveq.
X */
X#define BSIZE 20
Xstatic char pushq[BSIZE], saveq[BSIZE];
Xstatic int phead, ptail, shead, stail;
Xextern int in_doagain;
X
Xchar
Xpopch() {
X	/* If occupied, return 0, letting tgetch know a character should
X	 * be read from the keyboard.  If the character read is not the
X	 * ABORT character (as checked in main.c), that character will be
X	 * pushed back on the pushq.
X	 */
X	if (occupation) return(0);
X	if (in_doagain) return ((shead != stail) ? saveq[stail++] : 0);
X	else		return ((phead != ptail) ? pushq[ptail++] : 0);
X}
X
X/* A ch == 0 resets the pushq */
Xvoid
Xpushch(ch)
Xchar ch;
X{
X	if (!ch)
X		phead = ptail = 0;
X	if (phead < BSIZE)
X		pushq[phead++] = ch;
X}
X
X/* A ch == 0 resets the saveq.  Only save keystrokes when not
X * replaying a previous command.
X */
Xvoid
Xsavech(ch)
Xchar ch;
X{
X	if (!in_doagain) {
X		if (!ch)
X			phead = ptail = shead = stail = 0;
X		else if (shead < BSIZE)
X			saveq[shead++] = ch;
X	}
X}
X#endif /* REDO */
X
Xstruct func_tab cmdlist[]={
X#ifdef WIZARD
X	{'\011', wiz_identify},
X#endif
X	{'\020', doredotopl},
X	{'\022', doredraw},
X	{'\024', dotele},
X#ifdef WIZARD
X	{'\027', wiz_wish},
X#endif
X#ifdef SUSPEND
X	{'\032', dosuspend},
X#endif
X	{'a', doapply},
X	{'A', doddoremarm},
X/*	'b', 'B' : go sw */
X	{'c', ddocall},
X	{'C', do_mname},
X	{'d', dodrop},
X	{'D', doddrop},
X	{'e', doeat},
X	{'E', doengrave},
X/* Soon to be
X	{'f', dofight, "fighting"},
X	{'F', doFight, "fighting"},
X */
X/*	'g', 'G' : multiple go */
X/*	'h', 'H' : go west */
X	{'I', dotypeinv},		/* Robert Viduya */
X	{'i', ddoinv},
X/*	'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
X/*	'o', doopen,	*/
X	{'O', doset},
X	{'p', dopay},
X	{'P', dowearring},
X	{'q', dodrink},
X	{'Q', done1},
X	{'r', doread},
X	{'R', doremring},
X	{'s', dosearch, "searching"},
X	{'S', dosave},
X	{'t', dothrow},
X	{'T', doremarm},
X/*	'u', 'U' : go ne */
X	{'v', doversion},
X	{'w', dowield},
X	{'W', doweararm},
X#ifdef SPELLS
X	{'x', dovspell},			/* Mike Stephenson */
X	{'X', doxcribe},			/* Mike Stephenson */ 
X#endif
X/*	'y', 'Y' : go nw */
X	{'z', dozap},
X#ifdef SPELLS
X	{'Z', docast},
X#endif
X	{'<', doup},
X	{'>', dodown},
X	{'/', dowhatis},
X	{'?', dohelp},
X#ifdef SHELL
X	{'!', dosh},
X#endif
X	{'.', donull, "waiting"},
X	{' ', donull, "waiting"},
X	{',', dopickup},
X	{':', dolook},
X	{'^', doidtrap},
X	{'\\', dodiscovered},		/* Robert Viduya */
X#ifdef DGKMOD
X	{'@', dotogglepickup},
X	{'V', doMSCversion},
X# ifdef DEBUG_DOESNT_WORK
X	{'\004', dodebug},	/* generic debug function */
X# endif
X#endif
X	{WEAPON_SYM,  doprwep},
X	{ARMOR_SYM,  doprarm},
X	{RING_SYM,  doprring},
X	{GOLD_SYM, doprgold},
X	{'#', doextcmd},
X	{0,0,0}
X};
X
Xstruct ext_func_tab extcmdlist[] = {
X#ifdef KAA
X	"breathe", "breathe like a dragon", dobreathe,
X#endif
X#ifdef SPELLS
X	"cast", "cast a spell", docast,
X#endif
X	"dip", "dip an object into something", dodip,
X	"pray", "pray to the gods for help", dopray,
X#ifdef KAA
X	"remove", "remove a cursed item", doremove,
X#endif
X#ifdef NEWCLASS
X	"sit", "sit down", dosit,
X	"turn", "turn undead", doturn,
X#endif
X#if defined(KOPS) && defined(KAA)
X	"wipe", "wipe your face off", dowipe,
X#endif
X	"?", "get this list of extended commands", doextlist,
X	(char *) 0, (char *) 0, donull
X};
X
Xextern char *parse(), lowc(), unctrl(), quitchars[];
X
Xrhack(cmd)
Xregister char *cmd;
X{
X	register struct func_tab *tlist = cmdlist;
X	boolean firsttime = FALSE;
X	register res;
X
X	if(!cmd) {
X		firsttime = TRUE;
X		flags.nopick = 0;
X		cmd = parse();
X	}
X#ifdef REDO
X	if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
X		in_doagain = TRUE;
X		stail = 0;
X		rhack((char *) 0);	/* read and execute command */
X		in_doagain = FALSE;
X		return;
X	}
X
X	/* Special case of *cmd == ' ' handled better below */
X	if(!*cmd || *cmd == (char)0377) {
X#else
X	if(!*cmd || *cmd == (char)0377 || (flags.no_rest_on_space && *cmd == ' ')){
X#endif
X		bell();
X		flags.move = 0;
X		return;		/* probably we just had an interrupt */
X	}
X	if(movecmd(*cmd)) {
X	walk:
X		if(multi) flags.mv = 1;
X		domove();
X		return;
X	}
X	if(movecmd(lowc(*cmd))) {
X		flags.run = 1;
X	rush:
X		if(firsttime){
X			if(!multi) multi = COLNO;
X			u.last_str_turn = 0;
X		}
X		flags.mv = 1;
X#ifdef QUEST
X		if(flags.run >= 4) finddir();
X		if(firsttime){
X			u.ux0 = u.ux + u.dx;
X			u.uy0 = u.uy + u.dy;
X		}
X#endif
X		domove();
X		return;
X	}
X	if((*cmd == 'g' && movecmd(cmd[1])) || movecmd(unctrl(*cmd))) {
X		flags.run = 2;
X		goto rush;
X	}
X	if(*cmd == 'G' && movecmd(lowc(cmd[1]))) {
X		flags.run = 3;
X		goto rush;
X	}
X	if(*cmd == 'm' && movecmd(cmd[1])) {
X		flags.run = 0;
X		flags.nopick = 1;
X		goto walk;
X	}
X	if(*cmd == 'M' && movecmd(lowc(cmd[1]))) {
X		flags.run = 1;
X		flags.nopick = 1;
X		goto rush;
X	}
X#ifdef QUEST
X	if(*cmd == cmd[1] && (*cmd == 'g' || *cmd == 'G')) {
X		flags.run = 4;
X		if(*cmd == 'G') flags.run += 2;
X		if(cmd[2] == '-') flags.run += 1;
X		goto rush;
X	}
X#endif
X	while(tlist->f_char) {
X		if(*cmd == tlist->f_char){
X#ifdef DGKMOD
X			/* Special case of *cmd == ' ' handled here */
X			if (*cmd == ' ' && flags.no_rest_on_space)
X				break;
X
X			/* Now control-A can stop lengthy commands */
X			if (tlist->f_text && !occupation && multi)
X				set_occupation(tlist->f_funct, tlist->f_text,
X					multi);
X#endif
X			res = (*(tlist->f_funct))();
X			if(!res) {
X				flags.move = 0;
X				multi = 0;
X			}
X			return;
X		}
X		tlist++;
X	}
X	{ char expcmd[10];
X	  register char *cp = expcmd;
X	  while(*cmd && cp-expcmd < sizeof(expcmd)-2) {
X		if(*cmd >= 040 && *cmd < 0177)
X			*cp++ = *cmd++;
X		else {
X			*cp++ = '^';
X			*cp++ = *cmd++ ^ 0100;
X		}
X	  }
X	  *cp++ = 0;
X	  pline("Unknown command '%s'.", expcmd);
X	}
X	multi = flags.move = 0;
X	return;
X}
X
Xdoextcmd()	/* here after # - now read a full-word command */
X{
X	char buf[BUFSZ];
X	register struct ext_func_tab *efp = extcmdlist;
X
X	pline("# ");
X#ifdef COM_COMPL
X	get_ext_cmd(buf);
X#else
X	getlin(buf);
X#endif
X	clrlin();
X	if(buf[0] == '\033')
X		return(0);
X	while(efp->ef_txt) {
X		if(!strcmp(efp->ef_txt, buf))
X			return((*(efp->ef_funct))());
X		efp++;
X	}
X	pline("%s: unknown command.", buf);
X	return(0);
X}
X
Xdoextlist()	/* here after #? - now list all full-word commands */
X{
X	register struct ext_func_tab *efp = extcmdlist;
X	char     buf[BUFSZ];
X
X	set_pager(0);
X	if(page_line("") ||
X	   page_line("        Extended Command Set:") ||
X	   page_line(""))					 goto quit;
X
X	while(efp->ef_txt) {
X
X		(void)sprintf(buf, "    %-8s  - %s.", efp->ef_txt, efp->ef_desc);
X		if(page_line(buf)) goto quit;
X		efp++;
X	}
X	set_pager(1);
X	return(0);
Xquit:
X	set_pager(2);
X	return(0);
X}
X
Xchar
Xlowc(sym)
Xchar sym;
X{
X    return( (sym >= 'A' && sym <= 'Z') ? sym+'a'-'A' : sym );
X}
X
Xchar
Xunctrl(sym)
Xchar sym;
X{
X    return( (sym >= ('A' & 037) && sym <= ('Z' & 037)) ? sym + 0140 : sym );
X}
X
X/* 'rogue'-like direction commands */
Xchar sdir[] = "hykulnjb><";
Xschar xdir[10] = { -1,-1, 0, 1, 1, 1, 0,-1, 0, 0 };
Xschar ydir[10] = {  0,-1,-1,-1, 0, 1, 1, 1, 0, 0 };
Xschar zdir[10] = {  0, 0, 0, 0, 0, 0, 0, 0, 1,-1 };
X
Xmovecmd(sym)	/* also sets u.dz, but returns false for <> */
Xchar sym;
X{
X	register char *dp;
X
X	u.dz = 0;
X	if(!(dp = index(sdir, sym))) return(0);
X	u.dx = xdir[dp-sdir];
X	u.dy = ydir[dp-sdir];
X	u.dz = zdir[dp-sdir];
X	return(!u.dz);
X}
X
Xgetdir(s)
Xboolean s;
X{
X	char dirsym;
X
X#ifdef REDO
X	if (!in_doagain)
X#endif
X	    if(s) pline("In what direction?");
X	dirsym = readchar();
X#ifdef REDO
X	savech(dirsym);
X#endif
X#ifdef KAA
X	if(dirsym == '.' || dirsym == 's')
X		u.dx = u.dy = u.dz = 0;
X	else
X#endif
X	if(!movecmd(dirsym) && !u.dz) {
X		if(!index(quitchars, dirsym))
X			pline("What a strange direction!");
X		return(0);
X	}
X	if(Confusion && !u.dz) confdir();
X	return(1);
X}
X
Xconfdir()
X{
X	register x = rn2(8);
X	u.dx = xdir[x];
X	u.dy = ydir[x];
X}
X
X#ifdef QUEST
Xfinddir(){
Xregister int i, ui = u.di;
X	for(i = 0; i <= 8; i++){
X		if(flags.run & 1) ui++; else ui += 7;
X		ui %= 8;
X		if(i == 8){
X			pline("Not near a wall.");
X			flags.move = multi = 0;
X			return(0);
X		}
X		if(!isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
X			break;
X	}
X	for(i = 0; i <= 8; i++){
X		if(flags.run & 1) ui += 7; else ui++;
X		ui %= 8;
X		if(i == 8){
X			pline("Not near a room.");
X			flags.move = multi = 0;
X			return(0);
X		}
X		if(isroom(u.ux+xdir[ui], u.uy+ydir[ui]))
X			break;
X	}
X	u.di = ui;
X	u.dx = xdir[ui];
X	u.dy = ydir[ui];
X}
X
Xisroom(x,y)  register x,y; {		/* what about POOL? */
X	return(isok(x,y) && (levl[x][y].typ == ROOM ||
X				(levl[x][y].typ >= LDOOR && flags.run >= 6)));
X}
X#endif /* QUEST /**/
X
Xisok(x,y) register x,y; {
X	/* x corresponds to curx, so x==1 is the first column. Ach. %% */
X	return(x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1);
X}
X
X#ifdef WIZARD
Xint wiz_wish()	/* Unlimited wishes for wizard mode by Paul Polderman */
X{
X	if (!wizard) {
X		pline("Alas! You are not allowed to make a wish.");
X		pline("Nice try though...");
X	} else
X		makewish();
X	return(0);
X}
X
Xint wiz_identify()
X{
X	struct obj *obj;
X
X	if (!wizard)
X		pline("You don't have the proper identity!");
X	else {
X		for (obj = invent; obj; obj = obj->nobj)
X			if (!objects[obj->otyp].oc_name_known || !obj->known)
X				identify(obj);
X	}
X	return(0);
X}
X#endif /* WIZARD */
END_OF_cmd.c
if test 10896 -ne `wc -c <cmd.c`; then
    echo shar: \"cmd.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f date.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"date.h\"
else
echo shar: Extracting \"date.h\" \(88 characters\)
sed "s/^X//" >date.h <<'END_OF_date.h'
X/*	SCCS Id: @(#)date.h	1.4	87/08/08 */
X
Xchar datestring[] = "Mon Nov 30 01:25:12 1987";
END_OF_date.h
if test 88 -ne `wc -c <date.h`; then
    echo shar: \"date.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f save.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"save.c\"
else
echo shar: Extracting \"save.c\" \(10663 characters\)
sed "s/^X//" >save.c <<'END_OF_save.c'
X/*	SCCS Id: @(#)save.c	2.1	87/10/07
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include <signal.h>
X#include <stdio.h>
X#include "hack.h"
Xextern char genocided[60];		/* defined in Decl.c */
Xextern char fut_geno[60];		/* idem */
Xextern struct permonst	pm_wizard;	/* since the wizard evolves */
X
Xextern char SAVEF[], nul[];
Xextern char pl_character[PL_CSIZ];
Xextern long lseek();
Xextern struct obj *restobjchn();
Xextern struct monst *restmonchn();
X
Xdosave(){
X	clear_screen();
X	fflush(stdout);
X	if(dosave0(0)) {
X		settty("Be seeing you ...\n");
X		exit(0);
X	}
X#ifdef LINT
X	return(0);
X#endif
X}
X
X#ifndef NOSAVEONHANGUP
Xhangup(){
X	(void) dosave0(1);
X	exit(1);
X}
X#endif
X
X/* returns 1 if save successful */
Xdosave0(hu) int hu; {
X	register fd, ofd;
X	int tmp;		/* not register ! */
X#ifdef DGK
X	long fds, needed;
X	extern long bytes_counted;
X	int mode;
X#endif
X#ifdef UNIX
X	(void) signal(SIGHUP, SIG_IGN);
X#endif
X#ifndef __TURBOC__
X	(void) signal(SIGINT, SIG_IGN);
X#endif
X#ifdef DGK
X	if (!saveDiskPrompt(0))
X		return 0;
X	fd = open(SAVEF, O_WRONLY | O_BINARY | O_CREAT, FMASK);
X#else
X	fd = creat(SAVEF, FMASK);
X#endif
X	if(fd < 0) {
X		if(!hu) pline("Cannot open save file. (Continue or Quit)");
X		(void) unlink(SAVEF);		/* ab@unido */
X		return(0);
X	}
X	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */
X		u.uluck--;			/* and unido!ab */
X#ifdef DGKMOD
X	home();
X	cl_end();
X#endif
X#ifdef DGK
X	msmsg("Saving: ");
X	mode = COUNT;
Xagain:
X	savelev(fd, dlevel, mode);
X	/* count_only will be set properly by savelev */
X#else
X	savelev(fd,dlevel);
X#endif
X	saveobjchn(fd, invent);
X	saveobjchn(fd, fcobj);
X	savemonchn(fd, fallen_down);
X	tmp = getuid();
X	bwrite(fd, (char *) &tmp, sizeof tmp);
X	bwrite(fd, (char *) &flags, sizeof(struct flag));
X	bwrite(fd, (char *) &dlevel, sizeof dlevel);
X	bwrite(fd, (char *) &maxdlevel, sizeof maxdlevel);
X	bwrite(fd, (char *) &moves, sizeof moves);
X	bwrite(fd, (char *) &u, sizeof(struct you));
X#ifdef SPELLS
X	bwrite(fd, (char *) spl_book, sizeof(struct spell) * (MAXSPELL + 1));
X#endif
X	if(u.ustuck)
X		bwrite(fd, (char *) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
X	bwrite(fd, (char *) pl_character, sizeof pl_character);
X	bwrite(fd, (char *) genocided, sizeof genocided);
X	bwrite(fd, (char *) fut_geno, sizeof fut_geno);
X#ifdef HARD
X	bwrite(fd, (char *) &pm_wizard, sizeof(struct permonst));
X#endif
X	savenames(fd);
X#ifdef DGK
X	if (mode == COUNT) {
X		/* make sure there is enough disk space */
X		needed = bytes_counted;
X		for (tmp = 1; tmp <= maxdlevel; tmp++)
X			if (tmp != dlevel && fileinfo[tmp].where)
X				needed += fileinfo[tmp].size + (sizeof tmp);
X		fds = freediskspace(SAVEF);
X		if (needed > fds) {
X			pline("There is insufficient space on SAVE disk.");
X			pline("Require %ld bytes but only have %ld.", needed,
X				fds);
X			flushout();
X			(void) close(fd);
X			(void) unlink(SAVEF);
X			return 0;
X		}
X		mode = WRITE;
X		goto again;
X	}
X#endif
X	for(tmp = 1; tmp <= maxdlevel; tmp++) {
X		extern int hackpid;
X#ifdef DGK
X		if (tmp == dlevel || !fileinfo[tmp].where) continue;
X		if (fileinfo[tmp].where != ACTIVE)
X			swapin_file(tmp);
X#else
X		extern boolean level_exists[];
X
X		if(tmp == dlevel || !level_exists[tmp]) continue;
X#endif
X		glo(tmp);
X#ifdef DGK
X		msmsg(".");
X#endif
X		if((ofd = open(lock, 0)) < 0) {
X		    if(!hu) pline("Error while saving: cannot read %s.", lock);
X		    (void) close(fd);
X		    (void) unlink(SAVEF);
X		    if(!hu) done("tricked");
X		    return(0);
X		}
X		getlev(ofd, hackpid, tmp);
X		(void) close(ofd);
X		bwrite(fd, (char *) &tmp, sizeof tmp);	/* level number */
X#ifdef DGK
X		savelev(fd,tmp,WRITE);			/* actual level */
X#else
X		savelev(fd,tmp);			/* actual level */
X#endif
X		(void) unlink(lock);
X	}
X	(void) close(fd);
X	glo(dlevel);
X	(void) unlink(lock);	/* get rid of current level --jgm */
X	glo(0);
X	(void) unlink(lock);
X	return(1);
X}
X
Xdorecover(fd)
Xregister fd;
X{
X	register nfd;
X	int tmp;		/* not a register ! */
X	unsigned mid;		/* idem */
X	struct obj *otmp;
X	extern boolean restoring;
X#ifdef DGK
X	struct flag oldflags;
X
X	oldflags = flags;	/* Save flags set in the config file */
X#endif
X	restoring = TRUE;
X	getlev(fd, 0, 0);
X	invent = restobjchn(fd);
X	for(otmp = invent; otmp; otmp = otmp->nobj)
X		if(otmp->owornmask)
X			setworn(otmp, otmp->owornmask);
X	fcobj = restobjchn(fd);
X	fallen_down = restmonchn(fd);
X	mread(fd, (char *) &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		puts("Saved game was not yours.");
X		restoring = FALSE;
X		return(0);
X	    }
X	mread(fd, (char *) &flags, sizeof(struct flag));
X#ifdef DGK
X	/* Some config file OPTIONS take precedence over those in save file.
X	 */
X	flags.rawio = oldflags.rawio;
X	flags.DECRainbow = oldflags.DECRainbow;
X	flags.IBMBIOS = oldflags.IBMBIOS;
X#endif
X	mread(fd, (char *) &dlevel, sizeof dlevel);
X	mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
X	mread(fd, (char *) &moves, sizeof moves);
X	mread(fd, (char *) &u, sizeof(struct you));
X#ifdef SPELLS
X	mread(fd, (char *) spl_book, sizeof(struct spell) * (MAXSPELL + 1));
X#endif
X	if(u.ustuck)
X		mread(fd, (char *) &mid, sizeof mid);
X	mread(fd, (char *) pl_character, sizeof pl_character);
X	mread(fd, (char *) genocided, sizeof genocided);
X	mread(fd, (char *) fut_geno, sizeof fut_geno);
X#ifdef HARD
X	mread(fd, (char *) &pm_wizard, sizeof(struct permonst));
X#endif
X	restnames(fd);
X#ifdef DGK
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	cl_end();
X	msmsg("Restoring: ");
X#endif
X	while(1) {
X		if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
X			break;
X		getlev(fd, 0, tmp);
X		glo(tmp);
X#ifdef DGK
X		msmsg(".");
X		nfd = open(lock, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FMASK);
X#else
X		nfd = creat(lock, FMASK);
X#endif
X		if (nfd < 0)	panic("Cannot open temp file %s!\n", lock);
X#ifdef DGK
X		if (!savelev(nfd, tmp, 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				(void) lseek(fd, 0L, 0); /* Rewind save file */
X				return dorecover(fd);	 /* and try again */
X			} else {
X				msmsg("Be seeing you ...\n");
X				exit(0);
X			}
X		}
X#else
X		savelev(nfd,tmp);
X#endif
X		(void) close(nfd);
X	}
X	(void) lseek(fd, 0L, 0);
X	getlev(fd, 0, 0);
X	(void) close(fd);
X	(void) unlink(SAVEF);
X	if(Punished) {
X		for(otmp = fobj; otmp; otmp = otmp->nobj)
X			if(otmp->olet == CHAIN_SYM) goto chainfnd;
X		panic("Cannot find the iron chain?");
X	chainfnd:
X		uchain = otmp;
X		if(!uball){
X			for(otmp = fobj; otmp; otmp = otmp->nobj)
X				if(otmp->olet == BALL_SYM && otmp->spe)
X					goto ballfnd;
X			panic("Cannot find the iron ball?");
X		ballfnd:
X			uball = otmp;
X		}
X	}
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#ifndef QUEST
X	setsee();  /* only to recompute seelx etc. - these weren't saved */
X#endif
X#ifdef DGK
X	gameDiskPrompt();
X#endif
X	docrt();
X	restoring = FALSE;
X	return(1);
X}
X
Xstruct obj *
Xrestobjchn(fd)
Xregister fd;
X{
X	register struct obj *otmp, *otmp2;
X	register struct obj *first = 0;
X	int xl;
X#ifdef LINT
X	/* suppress "used before set" warning from lint */
X	otmp2 = 0;
X#endif
X	while(1) {
X		mread(fd, (char *) &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, (char *) otmp, (unsigned) xl + sizeof(struct obj));
X		if(!otmp->o_id) otmp->o_id = flags.ident++;
X		otmp2 = otmp;
X	}
X	if(first && otmp2->nobj){
X		impossible("Restobjchn: error reading objchn.");
X		otmp2->nobj = 0;
X	}
X	return(first);
X}
X#ifdef MSDOS
Xstruct monst *
Xrestmonchn(fd)
Xregister fd;
X{
X	register struct monst *mtmp, *mtmp2;
X	register struct monst *first = 0;
X	int xl;
X	int monsindex, mi;
X	extern struct permonst li_dog, dog, la_dog;
X#ifdef KAA
X	extern struct permonst hell_hound;
X# ifdef HARD
X	extern struct permonst d_lord, d_prince;
X# endif
X# ifdef KJSMODS
X	extern struct permonst pm_guard, pm_ghost, pm_eel;
X# endif
X#endif
X
X#ifdef lint
X	/* suppress "used before set" warning from lint */
X	mtmp2 = 0;
X#endif /* lint /**/
X	while(1) {
X		mread(fd, (char *) &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, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
X		if(!mtmp->m_id)
X			mtmp->m_id = flags.ident++;
X		monsindex = *((int *)&mtmp->data);
X		if (monsindex == (mi = -1))	/* Special fake index */
X			mtmp->data = &li_dog;
X		else if (monsindex == --mi)	/* Special fake index */
X			mtmp->data = &dog;
X		else if (monsindex == --mi)	/* Special fake index */
X			mtmp->data = &la_dog;
X#ifdef KAA
X		else if (monsindex == --mi)
X			mtmp->data = &hell_hound;
X# ifdef HARD
X		else if (monsindex == --mi)
X			mtmp->data = &d_lord;
X
X		else if (monsindex == --mi)
X			mtmp->data = &d_prince;
X# endif
X# ifdef KJSMODS
X		else if (monsindex == --mi)
X			mtmp->data = &pm_guard;
X
X		else if (monsindex == --mi)
X			mtmp->data = &pm_ghost;
X
X		else if (monsindex == --mi)
X			mtmp->data = &pm_eel;
X# endif
X#endif
X		else
X			mtmp->data = &mons[monsindex];
X		if(mtmp->minvent)
X			mtmp->minvent = restobjchn(fd);
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#else
Xstruct monst *
Xrestmonchn(fd)
Xregister fd;
X{
X	register struct monst *mtmp, *mtmp2;
X	register struct monst *first = 0;
X	int xl;
X
X	struct permonst *monbegin;
X	long differ;
X
X	mread(fd, (char *)&monbegin, sizeof(monbegin));
X	differ = (char *)(&mons[0]) - (char *)(monbegin);
X
X#ifdef LINT
X	/* suppress "used before set" warning from lint */
X	mtmp2 = 0;
X#endif
X	while(1) {
X		mread(fd, (char *) &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, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
X		if(!mtmp->m_id)
X			mtmp->m_id = flags.ident++;
X		mtmp->data = (struct permonst *)
X			((char *) mtmp->data + differ);
X		if(mtmp->minvent)
X			mtmp->minvent = restobjchn(fd);
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#endif
END_OF_save.c
if test 10663 -ne `wc -c <save.c`; then
    echo shar: \"save.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f spell.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"spell.c\"
else
echo shar: Extracting \"spell.c\" \(10416 characters\)
sed "s/^X//" >spell.c <<'END_OF_spell.c'
X/*	SCCS Id: @(#)spell.c	2.1	87/10/07
X */
X
X#include "hack.h"
X#ifdef SPELLS
Xextern char *nomovemsg;
X
Xdoxcribe() {
X	register struct obj *book;
X	struct	 obj	*getobj();
X	register boolean confused = (Confusion != 0);
X	register boolean oops;
X	register schar	 delay;
X	register int   booktype;
X	register int	 i;
X
X	book = getobj("+", "transcribe");
X	if(!book) return(0);
X
X	if(Blind) {
X	    pline("Being blind, you cannot read the mystic runes.");
X	    useup(book);		/* well, if you are stupid... */
X	    return(0);
X	}
X
X	if(confused) {
X	    pline("Being confused, you cannot grasp the meaning of this tome.");
X	    useup(book);		/* and more stupidity... */
X	    return(0);
X	}
X	booktype = book->otyp;
X	oops = !rn2(u.ulevel - objects[booktype].spl_lev + 7);
X	switch(booktype)  {
X
X/* level 1 spells */
X	case SPE_HEALING:
X	case SPE_DETECT_MONSTERS:
X	case SPE_FORCE_BOLT:
X	case SPE_LIGHT:
X	case SPE_SLEEP:
X/* level 2 spells */
X	case SPE_MAGIC_MISSILE:
X	case SPE_CONFUSE_MONSTER:
X	case SPE_SLOW_MONSTER:
X	case SPE_CURE_BLINDNESS:
X	case SPE_CREATE_MONSTER:
X	case SPE_DETECT_FOOD:
X		delay = -objects[booktype].oc_delay;
X		break;
X/* level 3 spells */
X	case SPE_HASTE_SELF:
X	case SPE_CAUSE_FEAR:
X	case SPE_CURE_SICKNESS:
X	case SPE_DETECT_UNSEEN:
X	case SPE_EXTRA_HEALING:
X	case SPE_CHARM_MONSTER:
X/* level 4 spells */
X	case SPE_LEVITATION:
X	case SPE_RESTORE_STRENGTH:
X	case SPE_INVISIBILITY:
X	case SPE_FIREBALL:
X	case SPE_DETECT_TREASURE:
X		delay = -(objects[booktype].spl_lev - 1) * objects[booktype].oc_delay;
X		break;
X/* level 5 spells */
X	case SPE_REMOVE_CURSE:
X	case SPE_MAGIC_MAPPING:
X	case SPE_CONE_OF_COLD:
X	case SPE_IDENTIFY:
X	case SPE_DIG:
X/* level 6 spells */
X	case SPE_TURN_UNDEAD:
X	case SPE_POLYMORPH:
X	case SPE_CREATE_FAMILIAR:
X	case SPE_TELEPORT_AWAY:
X		delay = -objects[booktype].spl_lev * objects[booktype].oc_delay;
X		break;
X/* level 7 spells */
X	case SPE_CANCELLATION:
X	case SPE_FINGER_OF_DEATH:
X	case SPE_GENOCIDE:
X		delay = -8 * objects[booktype].oc_delay;
X		break;
X/* impossible */
X	default:
X		impossible("Unknown spell-book, %d;", booktype);
X		return(0);
X	}
X
X	pline("You begin to transcribe the spell.");
X	if(oops || book->cursed)  {
X		cursed_book(objects[booktype].spl_lev);
X		nomul(delay);			/* study time */
X	} else  {
X		nomul(delay);			/* study time */
X		for(i = 0; i < MAXSPELL; i++)  {
X		    if(spl_book[i].sp_id == booktype)  {
X#ifdef HARD
X			nomovemsg = "You make that spell more legible.";
X			spl_book[i].sp_uses += rn1(3,8-spl_book[i].sp_lev);
X#else			
X			nomovemsg = "Oh, you already know that one!";
X#endif
X			useup(book);
X			return(1);
X		    } else if (spl_book[i].sp_id == NO_SPELL)  {
X			spl_book[i].sp_id = booktype;
X			spl_book[i].sp_lev = objects[booktype].spl_lev;
X			spl_book[i].sp_flags = objects[booktype].bits;
X#ifdef HARD
X			/* spells have 2 .. 10-level uses. */
X			/* ie 2 or 3 uses w/ most potent */
X			spl_book[i].sp_uses = rn1(3,8-spl_book[i].sp_lev);
X#endif
X			nomovemsg = "You add the spell to your books.";
X			objects[booktype].oc_name_known = 1;
X			useup(book);
X			return(1);
X		    }
X		}
X		impossible("Too many spells in spellbook!");
X	}
X	useup(book);
X	return(1);
X}
X
Xcursed_book(level)
X	register int	level;
X{
X	switch(rn2(level)) {
X	case 0:
X		pline("You feel a wrenching sensation.");
X		tele();		/* teleport him */
X		break;
X	case 1:
X		pline("You feel threatened.");
X		aggravate();
X		break;
X	case 2:
X		if(!Blind)	pline("A cloud of darkness falls upon you.");
X		Blinded += rn1(100,250);
X		seeoff(0);
X		break;
X	case 3:
X		if (u.ugold <= 0)  {
X			pline("You feel a strange sensation.");
X		} else {
X			pline("You notice you have no gold!");
X			u.ugold = 0;
X			flags.botl = 1;
X		}
X		break;
X	case 4:
X		pline("These runes were just too much to comprehend.");
X		HConfusion += rn1(7,16);
X		break;
X	case 5:
X		pline("The book was coated with contact poison!");
X		if(Poison_resistance) {
X		    losestr(rn1(1,2));
X		    losehp(rnd(6), "contact poison");
X		} else {
X		    losestr(rn1(4,3));
X		    losehp(rnd(10), "contact poison");
X		}
X		break;
X	case 6:
X		pline("As you read the book, it explodes in your face!");
X		losehp (2*rnd(10)+5, "exploding rune");
X		break;
X	default:
X		rndcurse();
X		break;
X	}
X	return(0);
X}
X
Xdocast()
X{
X	register int	 spell, energy, damage;
X	register boolean confused = (Confusion != 0);
X	register struct  obj	*pseudo;
X	struct	 obj	 *mksobj();
X
X	spell = getspell();
X	if (!spell) return(0);
X	else  {
X#ifdef HARD
X		/* note that turning to the page decrements the # of uses,  */
X		/* even if the mage does not have enough food/energy to use */
X		/* the spell */
X		switch (spelluses(spell)) {
X		case 0:
X		    pline ("That page is too faint to read at the moment.");
X		    return(0);
X		case 1:
X		    pline ("You can barely make out the runes on this page.");
X		    break;
X		case 2:
X		    pline ("This spell is starting to look well used.");
X		    break;
X		default:
X		    break;
X		}
X		decrnuses(spell);
X#endif		
X		energy = spellev(spell);
X#ifdef BVH
X		if (has_amulet()) {
X
X		    pline("You feel the amulet draining your energy away.");
X		    energy *= rnd(6);
X		}
X#endif
X		if(energy > u.uen)  {
X			pline("You are too weak to cast that spell.");
X			return(0);
X		} else  if ((u.uhunger <= 100) || (u.ustr < 6))  {
X			pline("You miss the strength for that spell.");
X			return(0);
X		} else	{
X			morehungry(energy * 10);
X			u.uen -= energy;
X		}
X		flags.botl = 1;
X	}
X#ifdef HARD
X	if (confused ||
X	    (rn2(10) + (int)(u.ulevel + u.uluck) - 3*spellev(spell)) < 0) {
X
X		if (Hallucination)
X			pline("Far out... a light show!");
X		else	pline("The air around you crackles as you goof up.");
X		return(0);
X	}
X#endif
X
X/*	pseudo is a temporary "false" object containing the spell stats. */
X	pseudo = mksobj(spellid(spell));
X	pseudo->quan = 20;			/* do not let useup get it */
X	switch(pseudo->otyp)  {
X
X/* These spells are all duplicates of wand effects */
X	case SPE_FORCE_BOLT:
X	case SPE_SLEEP:
X	case SPE_MAGIC_MISSILE:
X	case SPE_SLOW_MONSTER:
X	case SPE_FIREBALL:
X	case SPE_CONE_OF_COLD:
X	case SPE_DIG:
X	case SPE_TURN_UNDEAD:
X	case SPE_POLYMORPH:
X	case SPE_TELEPORT_AWAY:
X	case SPE_CANCELLATION:
X	case SPE_FINGER_OF_DEATH:
X	case SPE_LIGHT:
X	case SPE_DETECT_UNSEEN:
X		if (!(objects[pseudo->otyp].bits & NODIR)) {
X			getdir(1);
X			if(!u.dx && !u.dy && !u.dz && (u.ulevel > 8)) {
X			    if((damage = zapyourself(pseudo)))
X				losehp(damage, "self-inflicted injury");
X			} else	weffects(pseudo);
X		} else weffects(pseudo);
X		break;
X/* These are all duplicates of scroll effects */
X	case SPE_CONFUSE_MONSTER:
X	case SPE_DETECT_FOOD:
X	case SPE_CAUSE_FEAR:
X	case SPE_CHARM_MONSTER:
X	case SPE_REMOVE_CURSE:
X	case SPE_MAGIC_MAPPING:
X	case SPE_CREATE_MONSTER:
X	case SPE_IDENTIFY:
X	case SPE_GENOCIDE:
X		seffects(pseudo);
X		break;
X	case SPE_HASTE_SELF:
X	case SPE_DETECT_TREASURE:
X	case SPE_DETECT_MONSTERS:
X	case SPE_LEVITATION:
X	case SPE_RESTORE_STRENGTH:
X	case SPE_INVISIBILITY:
X		peffects(pseudo);
X		break;
X	case SPE_HEALING:
X		pline("You feel a bit better.");
X		healup(rnd(8), 0, 0, 0);
X		break;
X	case SPE_CURE_BLINDNESS:
X		healup(0, 0, 0, 1);
X		break;
X	case SPE_CURE_SICKNESS:
X		pline("You are no longer ill.");
X		healup(0, 0, 1, 0);
X		break;
X	case SPE_EXTRA_HEALING:
X		pline("You feel a fair bit better.");
X		healup(d(2,8), 1, 0, 0);
X		break;
X	case SPE_CREATE_FAMILIAR:
X		{	register struct monst *mtmp;
X			struct   monst  *makedog();
X
X			mtmp = makedog();
X			if(mtmp) {
X				/* make it into something else */
X				(void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]);
X				if(confused)
X					mtmp->mtame = mtmp->mpeaceful = 0;
X			}
X		}
X		break;
X	default:
X		impossible("Unknown spell %d attempted.", spell);
X		obfree(pseudo, (struct obj *)0);
X		return(0);
X	}
X	obfree(pseudo, (struct obj *)0);	/* now, get rid of it */
X	return(1);
X}
X
Xgetspell()  {
X
X	register int	max, ilet, i;
X	char	 lets[BUFSZ], buf[BUFSZ];
X
X	if (spl_book[0].sp_id == NO_SPELL)  {
X
X		pline("You don't know any spells right now.");
X		return(0);
X	} else  {
X
X	    for(max = 1; (max < MAXSPELL) && (spl_book[max].sp_id != NO_SPELL); max++);
X	    if (max >= MAXSPELL)  {
X
X		impossible("Too many spells memorized.");
X		return(0);
X	    }
X
X	    for(i = 0; (i < max) && (i < 26); buf[++i] = 0)  buf[i] = 'a' + i;
X	    for(i = 26; (i < max) && (i < 52); buf[++i] = 0) buf[i] = 'A' + i - 26;
X
X	    if (max == 1)  strcpy(lets, "a");
X	    else if (max < 27)  sprintf(lets, "a-%c", 'a' + max - 1);
X	    else if (max == 27)  sprintf(lets, "a-z A");
X	    else sprintf(lets, "a-z A-%c", 'A' + max - 27);
X	    for(;;)  {
X
X		pline("Cast which spell [%s ?]: ", lets);
X		if ((ilet = readchar()) == '?')  {
X			dovspell();
X			continue;
X		} else if ((ilet == '\033')||(ilet == '\n')||(ilet == ' '))
X			return(0);
X		else for(i = 0; buf[i] != 0; i++)  if(ilet == buf[i])  return(++i);
X		pline("You don't know that spell.");
X	    }
X	}
X}
X
Xlosespells() {
X	register boolean confused = (Confusion != 0);
X	register int	 n, nzap, i;
X
X	for(n = 0;(spl_book[n].sp_id != NO_SPELL) && (n < MAXSPELL); n++);
X	if (!n) return;
X	if (n < MAXSPELL) {
X		nzap = rnd(n);
X		if (nzap < n) nzap += confused;
X		for (i = 0; i < nzap; i++) spl_book[n-i-1].sp_id = NO_SPELL;
X	} else impossible("Too many spells in spellbook!");
X	return;
X}
X
Xdovspell() {
X
X	register int max, i, side;
X	char     buf[BUFSZ],
X		 *spellname();
X
X	if (spl_book[0].sp_id == NO_SPELL)  {
X
X		pline("You don't know any spells right now.");
X		return(0);
X	} else  {
X
X	    for(max = 1; (max < MAXSPELL) && (spl_book[max].sp_id != NO_SPELL); max++);
X	    if (max >= MAXSPELL)  {
X
X		impossible("Too many spells memorized.");
X		return(0);
X	    }
X	}
X	set_pager(0);
X	side = (max + 1) / 2;
X	if(page_line("Currently known spells:") || page_line(""))  goto quit;
X
X	for(i = 1; i <= side; i++) {
X
X		if((i < side) || !(max % 2))  {
X
X		    (void) sprintf(buf, "%c - (%d) %22s          %c - (%d) %22s",
X				   spellet(i), spellev(i), spellname(i),
X				   spellet(i + side), spellev(i + side), spellname(i + side));
X		} else {
X
X		    (void) sprintf(buf, "%c - (%d) %22s", spellet(i), spellev(i), spellname(i));
X		}
X		if(page_line(buf)) goto quit;
X	}
X
X	set_pager(1);
X	return(0);
Xquit:
X	set_pager(2);
X	return(0);
X}
X
Xspellet(spl)  {
X
X	if (spl < 27)	return('a' + spl - 1);
X	else		return('A' + spl - 27);
X}
X
Xspellev(spl)  {
X
X	return(spl_book[spl-1].sp_lev);
X}
X
Xchar *
Xspellname(spl)  {
X
X	return(objects[spl_book[spl-1].sp_id].oc_name);
X}
X
Xspellid(spl)  {		return(spl_book[spl-1].sp_id);		}
X
X#ifdef HARD
Xspelluses(spell) {	return(spl_book[spell-1].sp_uses);	}
Xdecrnuses(spell) {	spl_book[spell-1].sp_uses--;		}
X#endif
X
X#endif /* SPELLS /**/
END_OF_spell.c
if test 10416 -ne `wc -c <spell.c`; then
    echo shar: \"spell.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f unixunix.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"unixunix.c\"
else
echo shar: Extracting \"unixunix.c\" \(10405 characters\)
sed "s/^X//" >unixunix.c <<'END_OF_unixunix.c'
X/*	SCCS Id: @(#)unixunix.c	1.4	87/08/08
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* hack.unix.c - version 1.0.3 */
X
X/* This file collects some Unix dependencies; pager.c contains some more */
X
X/*
X * The time is used for:
X *	- seed for rand()
X *	- year on tombstone and yymmdd in record file
X *	- phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
X *	- night and midnight (the undead are dangerous at midnight)
X *	- determination of what files are "very old"
X */
X
X#include <stdio.h>
X#include <errno.h>
X#include "hack.h"	/* mainly for index() which depends on BSD */
X
X#include	<sys/types.h>		/* for time_t and stat */
X#include	<sys/stat.h>
X#ifdef BSD
X#include	<sys/time.h>
X#else
X#include	<time.h>
X#endif
X
Xextern char *getenv();
Xextern time_t time();
X
Xsetrandom()
X{
X	(void) srand((int) time ((time_t *) 0));
X}
X
Xstruct tm *
Xgetlt()
X{
X	time_t date;
X	struct tm *localtime();
X
X	(void) time(&date);
X	return(localtime(&date));
X}
X
Xgetyear()
X{
X	return(1900 + getlt()->tm_year);
X}
X
Xchar *
Xgetdate()
X{
X	static char datestr[7];
X	register struct tm *lt = getlt();
X
X	(void) sprintf(datestr, "%2d%2d%2d",
X		lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
X	if(datestr[2] == ' ') datestr[2] = '0';
X	if(datestr[4] == ' ') datestr[4] = '0';
X	return(datestr);
X}
X
Xphase_of_the_moon()			/* 0-7, with 0: new, 4: full */
X{					/* moon period: 29.5306 days */
X					/* year: 365.2422 days */
X	register struct tm *lt = getlt();
X	register int epact, diy, golden;
X
X	diy = lt->tm_yday;
X	golden = (lt->tm_year % 19) + 1;
X	epact = (11 * golden + 18) % 30;
X	if ((epact == 25 && golden > 11) || epact == 24)
X		epact++;
X
X	return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
X}
X
Xnight()
X{
X	register int hour = getlt()->tm_hour;
X
X	return(hour < 6 || hour > 21);
X}
X
Xmidnight()
X{
X	return(getlt()->tm_hour == 0);
X}
X
Xstruct stat buf, hbuf;
X
Xgethdate(name) char *name; {
X/* old version - for people short of space */
X/*
X/* register char *np;
X/*	if(stat(name, &hbuf))
X/*		error("Cannot get status of %s.",
X/*			(np = rindex(name, '/')) ? np+1 : name);
X/*
X/* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
X
X
X/*
X * The problem with   #include	<sys/param.h>   is that this include file
X * does not exist on all systems, and moreover, that it sometimes includes
X * <sys/types.h> again, so that the compiler sees these typedefs twice.
X */
X#define		MAXPATHLEN	1024
X
Xregister char *np, *path;
Xchar filename[MAXPATHLEN+1];
X	if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL)
X		path = "";
X
X	for (;;) {
X		if ((np = index(path, ':')) == NULL)
X			np = path + strlen(path);	/* point to end str */
X		if (np - path <= 1)			/* %% */
X			(void) strcpy(filename, name);
X		else {
X			(void) strncpy(filename, path, np - path);
X			filename[np - path] = '/';
X			(void) strcpy(filename + (np - path) + 1, name);
X		}
X		if (stat(filename, &hbuf) == 0)
X			return;
X		if (*np == '\0')
X			break;
X		path = np + 1;
X	}
X	error("Cannot get status of %s.",
X		(np = rindex(name, '/')) ? np+1 : name);
X}
X
Xuptodate(fd) {
X	if(fstat(fd, &buf)) {
X		pline("Cannot get status of saved level? ");
X		return(0);
X	}
X	if(buf.st_mtime < hbuf.st_mtime) {
X		pline("Saved level is out of date. ");
X		return(0);
X	}
X	return(1);
X}
X
X/* see whether we should throw away this xlock file */
Xveryold(fd) {
X	register int i;
X	time_t date;
X
X	if(fstat(fd, &buf)) return(0);			/* cannot get status */
X	if(buf.st_size != sizeof(int)) return(0);	/* not an xlock file */
X	(void) time(&date);
X	if(date - buf.st_mtime < 3L*24L*60L*60L) {	/* recent */
X		extern int errno;
X		int lockedpid;	/* should be the same size as hackpid */
X
X		if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) !=
X			sizeof(lockedpid))
X			/* strange ... */
X			return(0);
X
X		/* From: Rick Adams <seismo!rick>
X		/* This will work on 4.1cbsd, 4.2bsd and system 3? & 5.
X		/* It will do nothing on V7 or 4.1bsd. */
X		if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
X			return(0);
X	}
X	(void) close(fd);
X	for(i = 1; i <= MAXLEVEL; i++) {		/* try to remove all */
X		glo(i);
X		(void) unlink(lock);
X	}
X	glo(0);
X	if(unlink(lock)) return(0);			/* cannot remove it */
X	return(1);					/* success! */
X}
X
Xgetlock()
X{
X	extern int errno, hackpid, locknum;
X	register int i = 0, fd;
X
X	(void) fflush(stdout);
X
X	/* we ignore QUIT and INT at this point */
X	if (link(HLOCK, LLOCK) == -1) {
X		register int errnosv = errno;
X
X		perror(HLOCK);
X		printf("Cannot link %s to %s\n", LLOCK, HLOCK);
X		switch(errnosv) {
X		case ENOENT:
X		    printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
X		    break;
X		case EACCES:
X		    printf("It seems you don't have write permission here.\n");
X		    break;
X		case EEXIST:
X		    printf("(Try again or rm %s.)\n", LLOCK);
X		    break;
X		default:
X		    printf("I don't know what is wrong.");
X		}
X		getret();
X		error("");
X		/*NOTREACHED*/
X	}
X
X	regularize(lock);
X	glo(0);
X	if(locknum > 25) locknum = 25;
X
X	do {
X		if(locknum) lock[0] = 'a' + i++;
X
X		if((fd = open(lock, 0)) == -1) {
X			if(errno == ENOENT) goto gotlock;    /* no such file */
X			perror(lock);
X			(void) unlink(LLOCK);
X			error("Cannot open %s", lock);
X		}
X
X		if(veryold(fd))	/* if true, this closes fd and unlinks lock */
X			goto gotlock;
X		(void) close(fd);
X	} while(i < locknum);
X
X	(void) unlink(LLOCK);
X	error(locknum ? "Too many hacks running now."
X		      : "There is a game in progress under your name.");
Xgotlock:
X	fd = creat(lock, FMASK);
X	if(unlink(LLOCK) == -1)
X		error("Cannot unlink %s.", LLOCK);
X	if(fd == -1) {
X		error("cannot creat lock file.");
X	} else {
X		if(write(fd, (char *) &hackpid, sizeof(hackpid))
X		    != sizeof(hackpid)){
X			error("cannot write lock");
X		}
X		if(close(fd) == -1) {
X			error("cannot close lock");
X		}
X	}
X}	
X
X#ifdef MAIL
X
X/*
X * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
X * I don't know the details of his implementation.]
X * { Later note: he disliked my calling a general mailreader and felt that
X *   hack should do the paging itself. But when I get mail, I want to put it
X *   in some folder, reply, etc. - it would be unreasonable to put all these
X *   functions in hack. }
X * The mail daemon '2' is at present not a real monster, but only a visual
X * effect. Thus, makemon() is superfluous. This might become otherwise,
X * however. The motion of '2' is less restrained than usual: diagonal moves
X * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
X * in a ROOM, even when you are Blind.
X * Its path should be longer when you are Telepat-hic and Blind.
X *
X * Interesting side effects:
X *	- You can get rich by sending yourself a lot of mail and selling
X *	  it to the shopkeeper. Unfortunately mail isn't very valuable.
X *	- You might die in case '2' comes along at a critical moment during
X *	  a fight and delivers a scroll the weight of which causes you to
X *	  collapse.
X *
X * Possible extensions:
X *	- Open the file MAIL and do fstat instead of stat for efficiency.
X *	  (But sh uses stat, so this cannot be too bad.)
X *	- Examine the mail and produce a scroll of mail called "From somebody".
X *	- Invoke MAILREADER in such a way that only this single letter is read.
X *
X *	- Make him lose his mail when a Nymph steals the letter.
X *	- Do something to the text when the scroll is enchanted or cancelled.
X */
X#include	"mkroom.h"
Xstatic struct stat omstat,nmstat;
Xstatic char *mailbox;
Xstatic long laststattime;
X
Xgetmailstatus() {
X	if(!(mailbox = getenv("MAIL")))
X		return;
X	if(stat(mailbox, &omstat)){
X#ifdef PERMANENT_MAILBOX
X		pline("Cannot get status of MAIL=%s .", mailbox);
X		mailbox = 0;
X#else
X		omstat.st_mtime = 0;
X#endif
X	}
X}
X
Xckmailstatus() {
X	if(!mailbox
X#ifdef MAILCKFREQ
X		    || moves < laststattime + MAILCKFREQ
X#endif
X							)
X		return;
X	laststattime = moves;
X	if(stat(mailbox, &nmstat)){
X#ifdef PERMANENT_MAILBOX
X		pline("Cannot get status of MAIL=%s anymore.", mailbox);
X		mailbox = 0;
X#else
X		nmstat.st_mtime = 0;
X#endif
X	} else if(nmstat.st_mtime > omstat.st_mtime) {
X		if(nmstat.st_size)
X			newmail();
X		getmailstatus();	/* might be too late ... */
X	}
X}
X
Xnewmail() {
X	/* produce a scroll of mail */
X	register struct obj *obj;
X	register struct monst *md;
X	extern char plname[];
X	extern struct obj *mksobj(), *addinv();
X	extern struct monst *makemon();
X	extern struct permonst pm_mail_daemon;
X
X	obj = mksobj(SCR_MAIL);
X	if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
X		mdrush(md,0);
X
X	pline("\"Hello, %s! I have some mail for you.\"", plname);
X	if(md) {
X		if(dist(md->mx,md->my) > 2)
X			pline("\"Catch!\"");
X		more();
X
X		/* let him disappear again */
X		mdrush(md,1);
X		mondead(md);
X	}
X
X	obj = addinv(obj);
X	(void) identify(obj);		/* set known and do prinv() */
X}
X
X/* make md run through the cave */
Xmdrush(md,away)
Xregister struct monst *md;
Xboolean away;
X{
X	register int uroom = inroom(u.ux, u.uy);
X	if(uroom >= 0) {
X		register int tmp = rooms[uroom].fdoor;
X		register int cnt = rooms[uroom].doorct;
X		register int fx = u.ux, fy = u.uy;
X		while(cnt--) {
X			if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){
X				fx = doors[tmp].x;
X				fy = doors[tmp].y;
X			}
X			tmp++;
X		}
X		tmp_at(-1, md->data->mlet);	/* open call */
X		if(away) {	/* interchange origin and destination */
X			unpmon(md);
X			tmp = fx; fx = md->mx; md->mx = tmp;
X			tmp = fy; fy = md->my; md->my = tmp;
X		}
X		while(fx != md->mx || fy != md->my) {
X			register int dx,dy,nfx = fx,nfy = fy,d1,d2;
X
X			tmp_at(fx,fy);
X			d1 = DIST(fx,fy,md->mx,md->my);
X			for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
X			    if(dx || dy) {
X				d2 = DIST(fx+dx,fy+dy,md->mx,md->my);
X				if(d2 < d1) {
X				    d1 = d2;
X				    nfx = fx+dx;
X				    nfy = fy+dy;
X				}
X			    }
X			if(nfx != fx || nfy != fy) {
X			    fx = nfx;
X			    fy = nfy;
X			} else {
X			    if(!away) {
X				md->mx = fx;
X				md->my = fy;
X			    }
X			    break;
X			} 
X		}
X		tmp_at(-1,-1);			/* close call */
X	}
X	if(!away)
X		pmon(md);
X}
X
Xreadmail() {
X#ifdef DEF_MAILREADER			/* This implies that UNIX is defined */
X	register char *mr = 0;
X	more();
X	if(!(mr = getenv("MAILREADER")))
X		mr = DEF_MAILREADER;
X	if(child(1)){
X		execl(mr, mr, (char *) 0);
X		exit(1);
X	}
X#else
X	(void) page_file(mailbox, FALSE);
X#endif
X	/* get new stat; not entirely correct: there is a small time
X	   window where we do not see new mail */
X	getmailstatus();
X}
X#endif /* MAIL /**/
X
Xregularize(s)	/* normalize file name - we don't like ..'s or /'s */
Xregister char *s;
X{
X	register char *lp;
X
X	while((lp = index(s, '.')) || (lp = index(s, '/')))
X		*lp = '_';
X}
END_OF_unixunix.c
if test 10405 -ne `wc -c <unixunix.c`; then
    echo shar: \"unixunix.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 13 \(of 20\).
cp /dev/null ark13isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 20 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