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

billr@saab.CNA.TEK.COM (Bill Randle) (07/25/89)

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 79
Archive-name: NetHack3/Part24



#! /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 24 (of 38)."
# Contents:  Install.dos src/dokick.c src/mondata.c src/pager.c
# Wrapped by billr@saab on Sun Jul 23 21:33:07 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Install.dos' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Install.dos'\"
else
echo shar: Extracting \"'Install.dos'\" \(6416 characters\)
sed "s/^X//" >'Install.dos' <<'END_OF_FILE'
XInstructions for installing NetHack 3.0 on an MS-DOS system
X===========================================================
X
X1.  Make sure all the NetHack files are in the appropriate directory structure.
X    You should have a main directory with subdirectories src, include, auxil,
X    amiga, and others.  If you do not follow this structure, the Makefile
X    will not function properly.  All the UNIX .c files and the source Makefile
X    belong in src; all the PC .c files and Makefiles belong in others; all the
X    .h files belong in include; other assorted files belong in auxil.  The
X    PC version does not use any files from the amiga directory.
X
X    If you downloaded or ftp'd the sources from a UNIX system, the lines will
X    probably end in UNIX-style newlines, instead of DOS-style carriage return
X    and line feed pairs.  Turbo C in particular does not like these; you will
X    have to run a program such as Rahul Dhesi's 'flip' to convert them.
X
X2.  Move everything from the others directory to your src directory; you'll
X    be needing it, especially pc*.c.  PC NetHack needs msdos.c, ST NetHack
X    needs tos.c.
X
X3.  You should have several Makefiles in your src directory now.  If you are
X    using Microsoft C, rename Makefile.pc to Makefile; if Turbo C, rename
X    Makefile.tcc to Makefile, and also rename Maketcc.ini to Make.ini.
X    NDMake can find Make.ini anywhere on your PATH, so you may relocate it
X    if you wish.  If you are using another compiler, you will have to adapt
X    one of the Makefiles and the Make.ini file to your needs.  Good luck.
X
X    As for the other Makefiles, I would delete them to make space, but you may
X    want to keep them around for comparison in case something goes wrong.  Two
X    other Makefiles we will not be using, Makefile.top and Makefile.auxil,
X    reside in the top and auxil directories.  We won't need those either.
X
X4.  Go to the include subdirectory and edit config.h according to the comments
X    to match your system and desired set of features.  Similarly edit
X    pcconf.h.
X
X    The base size of the executable, with no extra features, will be around
X    520K in size.  Anything over 540K is likely not to work.  With MicroSoft
X    C, here is an incomplete list of the costs of various additional features
X    in terms of executable size:
X
X    ALTARS		 4K
X    ARMY		 1K
X    COM_COMPL		 1K
X    COMPRESS		 2K
X    DGK			 7K
X    ENDGAME		 2K
X    EXPLORE_MODE	 1K
X    FOUNTAINS		 2K
X    GOLEMS		 2K
X    HARD - SEDUCE	 5K
X    MSDOSCOLOR		 1K
X    MUSIC		 6K
X    POLYSELF		31K
X    PROBING		 0K
X    REDO		 1K
X    REINCARNATION	 7K
X    SINKS		 5K
X    SOUNDS		 6K
X    SPELLS		10K
X    STRONGHOLD		13K
X    THEOLOGY		11K
X    THRONES		 3K
X    WALKIES		 4K
X    WALLIFIED_MAZE	 0K
X    WIZARD		 3K
X
X    I eked by with just DGK, MSDOSCOLOR, REDO, HARD, MEDUSA, EXPLORE_MODE,
X    and WIZARD, to give you an idea of just how little leeway you have for all
X    these nifty features.  Maybe those of you with overlay linkers can get by
X    with more.
X
X5.  If you want to, look through system.h.  This file attempts to match the
X    types for system calls and library routines with various flavors of
X    operating systems.  Leaving this file alone is unlikely to cause problems,
X    but if you're using a different compiler and get compile errors with
X    any functions in the standard library, it's worth checking the
X    declarations there.
X
X6.  If you want to change the high score list behavior, go to the src
X    subdirectory and look at the top of topten.c.  You may want to change the
X    definitions of PERSMAX, POINTSMIN, and ENTRYMAX.  I set POINTSMIN of
X    51 and ENTRYMAX of 50 to keep the size of the score list down.
X
X7.  Edit the top section of the Makefile.  (If you are doing a full
X    recompile, or if you got your files from someplace besides the official
X    distribution, type 'touch makedefs.c' to make sure certain files (onames.h,
X    pm.h) get remade instead of relying on the potentially troublesome
X    timestamps.)  Be sure the directory you want the game installed in
X    actually exists.  If you elected to use the high-quality BSD random
X    routines by defining RANDOM in pcconf.h, you will have to add random.c
X    to the dependency and link macros.  If you elected to use Fred Fish's
X    termcap library (bundled in as termcap.arc), you will have to generate
X    termcap.lib from those sources (follow the comments therein, if you can).
X
X    Now, type 'make all', and take a long siesta; your computer will be
X    occupied for a long time.  If all goes well, you will get an executable.
X    If you tried to compile in too many features, you probably will not get
X    a working one, and have to start over.
X
X8.  Edit NetHack.cnf to reflect your particular setup, following the comments.
X    Then move the file to your game directory, along with the termcap file.
X
X    If your game directory is not on your PATH, you will want to 'set HACKDIR
X    =\games\nethack' (or whatever directory you want to use) now, and add it
X    to your autoexec.bat if you'll be playing often.
X
X    Make sure the support files data, rumors, cmdhelp, opthelp, help, hh,
X    history, and license (and oracles, if you compiled in that feature) got
X    copied to the game directory.  If not, move them there from the auxil
X    directory yourself.  rumors can be created manually by typing 'makedefs
X    -r'; data by typing 'makedefs -d'.
X
X    If you compiled in the special levels, make sure castle, tower?, and
X    perhaps endgame are there, too.  lev_comp file.des will create these.
X
XNotes:
X
X1.  No, your old save files and bones files will not work with NetHack 3.0.
X    Don't bother trying to keep them.  The old score list will work fine,
X    but I recommend you delete it and create a new, empty one ('type record
X    >record' will do this nicely).  It is a good deal harder to achieve the
X    same scores in this version.
X
X2.  To install an update of this version of NetHack after changing something,
X    type 'make' from the src directory.  If you created the new version
X    yourself, it should be safe to use 'make update' as long as you did not
X    add, delete, or reorder monsters or objects and you did not change 
X    the format of saved level files.  If you did any of these things, you
X    should also delete any saved games and bones levels.  (Trying to use such
X    files often produces amusing but useless confusions on the game's part.)
END_OF_FILE
if test 6416 -ne `wc -c <'Install.dos'`; then
    echo shar: \"'Install.dos'\" unpacked with wrong size!
fi
# end of 'Install.dos'
fi
if test -f 'src/dokick.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/dokick.c'\"
else
echo shar: Extracting \"'src/dokick.c'\" \(15059 characters\)
sed "s/^X//" >'src/dokick.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)dokick.c	3.0	89/6/9
X/* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include	"hack.h"
X#include	"eshk.h"
X
X#define martial()	((pl_character[0] == 'S' || pl_character[0] == 'P'))
X
X#ifdef KICK
X
X# ifdef WORM
Xextern boolean notonhead;
X# endif
X
Xstatic void
Xkickdmg(mon, clumsy)
Xregister struct monst *mon;
Xregister boolean clumsy;
X{
X	register int mdx, mdy;
X	register int dmg = (((uarmg && 
X				uarmg->otyp == GAUNTLETS_OF_POWER) ? 
X				25 : ACURR(A_STR) > 18 ? 18 : ACURR(A_STR))+
X				ACURR(A_DEX)+ACURR(A_CON))/15;
X
X	/* excessive wt affects dex, so it affects dmg */
X	if(clumsy) dmg = dmg/2;
X
X	/* kicking a dragon or an elephant will not harm it */
X	if(thick_skinned(mon->data)) dmg = 0;
X	
X
X	/* squeeze some guilt feelings... */
X	if(mon->mtame) {
X# ifdef SOUNDS
X	    if (rn2(10)) yelp(mon);
X	    else growl(mon); /* give them a moment's worry */
X# endif
X	    mon->mtame--;
X	    mon->mflee = mon->mtame ? 1 : 0;
X# ifdef HISX
X	    mon->mfleetim = mon->mfleetim + (dmg ? rnd(dmg) : 1);
X# else
X	    mon->mfleetim += (dmg ? rnd(dmg) : 1);
X# endif
X	}
X	
X	mon->mhp -= (!martial() ? rnd(dmg) : rnd(dmg)+rnd(ACURR(A_DEX)/2));  
X	if(mon->mhp < 1) {
X		killed(mon);
X		return;
X	}
X	if(martial() && !bigmonst(mon->data) && !rn2(3) && !mon->mfroz) {
X	    	/* see if the monster has a place to move into */
X	    	mdx = mon->mx + u.dx;
X	    	mdy = mon->my + u.dy;
X	    	if(goodpos(mdx, mdy)) {
X			pline("%s reels from the blow.", Monnam(mon));
X			levl[mon->mx][mon->my].mmask = 0;
X			levl[mdx][mdy].mmask = 1;
X			mon->mx = mdx;
X			mon->my = mdy;
X			pmon(mon);
X			set_apparxy(mon);
X	    	}
X	}
X
X/*	it is unchivalrous to attack the defenseless or from behind */
X	if (pl_character[0] == 'K' && u.ualigntyp == U_LAWFUL && 
X		u.ualign > -10 && (mon->mfroz || mon->msleep || mon->mflee))
X	    	adjalign(-1);
X
X}
X
Xstatic void
Xkick_monster(x, y)
Xregister int x, y;
X{
X	register boolean clumsy = FALSE;
X	register struct monst *mon = m_at(x, y);
X	register int i, j;
X
X	/* no need to check POLYSELF since only ghosts, which you can't turn */
X	/* into, are noncorporeal */
X	if(noncorporeal(mon->data)) {
X		Your("kick passes through!");
X		return;
X	}
X
X	if(special_case(mon)) return;
X
X	setmangry(mon);
X
X	if(Levitation && !rn2(3) && verysmall(mon->data) && 
X			!is_floater(mon->data) && !is_flyer(mon->data)) {
X		You("are floating in the air, and miss wildly!");
X		return;
X	}
X
X	i = abs(inv_weight());
X	j = weight_cap();
X
X	if(i < (j*3)/10) {
X		if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) {
X			if(martial() && !rn2(2)) goto doit;
X			Your("clumsy kick does no damage.");
X			return;
X		}
X		if(i < j/10) clumsy = TRUE;
X		else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE;  
X	} 
X
X	if(Fumbling) clumsy = TRUE;
X
X	else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
X		clumsy = TRUE;
Xdoit:
X	kludge("You kick %s.", mon_nam(mon));
X	if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) && 
X	   mon->mcansee && !thick_skinned(mon->data) &&
X	   !mon->mfroz && !mon->mstun && !mon->mconf) {
X		mnexto(mon);
X		if(mon->mx != x || mon->my != y) {
X		    kludge("%s jumps, %s evading your %skick.", Monnam(mon),
X				clumsy ? "easily" : "nimbly",
X				clumsy ? "clumsy " : "");
X		    return;
X		} /* else fall to the next case */		
X	}
X	kickdmg(mon, clumsy);
X}
X#endif /* KICK */
X
X/* return TRUE if caught, FALSE otherwise */
Xboolean
Xghitm(mtmp, amount)
Xregister struct monst *mtmp;
Xregister long amount;
X{
X	if(!likes_gold(mtmp->data) && !mtmp->isshk 
X#if defined(ALTARS) && defined(THEOLOGY)
X		&& !mtmp->ispriest
X#endif
X		) 
X		wakeup(mtmp);
X	else {
X		mtmp->msleep = 0;
X		mtmp->meating = 0;
X		if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
X		
X		/* greedy monsters catch gold */
X		pline("%s catches the gold.", Monnam(mtmp));
X		mtmp->mgold += amount;
X		if (mtmp->isshk) {
X			long robbed = ESHK(mtmp)->robbed;
X
X			if (robbed) {
X				robbed -= amount;
X				if (robbed < 0) robbed = 0;
X				pline("The amount %scovers %s recent losses.",
X					!robbed ? "" : "partially ", 
X					ESHK(mtmp)->ismale ? "his" : "her");
X				ESHK(mtmp)->robbed = robbed;
X				if(!robbed)
X					make_happy_shk(mtmp);
X			} else {
X				if(mtmp->mpeaceful) {
X				    ESHK(mtmp)->credit += amount;
X				    You("have %ld zorkmids in credit.",
X						ESHK(mtmp)->credit);
X				} else verbalize("Thanks, scum!");
X			}
X		}
X#if defined(ALTARS) && defined(THEOLOGY)
X		else if(mtmp->ispriest) {
X			if(mtmp->mpeaceful)
X			    verbalize("Thank you for your contribution.");
X			else verbalize("Thanks, scum!");
X		}
X#endif
X		return(1);
X	}
X	return(0);
X
X}
X
Xboolean
Xbad_kick_throw_pos(x,y)
Xxchar x,y;
X{
X	register struct rm *lvl = &(levl[x][y]);
X
X	return(!ACCESSIBLE(lvl->typ) || lvl->typ == SDOOR ||
X	    (IS_DOOR(lvl->typ) && (lvl->doormask & (D_CLOSED | D_LOCKED))) );
X}
X
Xstruct monst *
Xghit(ddx, ddy, range)
Xregister int ddx, ddy, range; 
X{
X	register struct monst *mtmp = (struct monst *) 0;
X
X	bhitpos.x = u.ux;
X	bhitpos.y = u.uy;
X
X	tmp_at(-1, GOLD_SYM);	/* open call */
X	tmp_at(-3, (int)AT_GLD);
X	while(range-- > 0) {
X		bhitpos.x += ddx;
X		bhitpos.y += ddy;
X		if(levl[bhitpos.x][bhitpos.y].mmask) {
X			mtmp = m_at(bhitpos.x,bhitpos.y);
X			tmp_at(-1, -1); /* close call */
X			return(mtmp);
X		}
X		/* stop on a zorkmid */
X		if(levl[bhitpos.x][bhitpos.y].gmask ||
X		     	    levl[bhitpos.x][bhitpos.y].omask) {
X			tmp_at(-1, -1); /* close call */
X			return (struct monst *)0;
X		}
X		if(bad_kick_throw_pos(bhitpos.x,bhitpos.y)) {
X			bhitpos.x -= ddx;
X			bhitpos.y -= ddy;
X			break;
X		}
X		tmp_at(bhitpos.x, bhitpos.y);
X	}
X	tmp_at(-1, -1);
X	return(struct monst *)0;
X}
X
X#ifdef KICK
Xstatic int
Xkick_object(x, y)
Xregister int x, y;
X{
X	register int range, odx, ody, cnt = 0;
X	register struct monst *mon;
X	register struct gold *gold;
X	register struct obj *otmp, *obj;
X	register boolean costly = FALSE;
X
X	/* if a pile, the "top" object gets kicked */
X	for (otmp = fobj; otmp; otmp = otmp->nobj)
X		if(otmp->ox == x && otmp->oy == y)
X		    if(!otmp->cobj)
X			if (otmp != uchain) {
X			    cnt++;
X			    if(cnt == 1) obj = otmp;
X			}
X
X	/* range < 2 means the object will not move.	*/
X	/* maybe dexterity should also figure here.     */
X	if(cnt) range = (int)((ACURR(A_STR) > 18 ? 20 : 
X				ACURR(A_STR))/2 - obj->owt/4);
X	else range = rnd((int)ACURR(A_STR));
X
X	if(range < 1) range = 1; /* safety... */
X	if(martial()) range = range + rnd(3);
X
X	/* see if the object has a place to move into */
X	odx = x + u.dx;
X	ody = y + u.dy;
X	if(bad_kick_throw_pos(odx,ody))
X	    range = 1;
X
X	if(Fumbling && !rn2(3)) {
X		Your("clumsy kick missed.");
X		return(1);
X	}
X
X	if(!cnt && levl[x][y].gmask) {
X		long zm;
X		gold = g_at(x, y);
X		zm = gold->amount;
X		if(range < 2 || zm > 300L) /* arbitrary */
X		    return(0);
X		else {
X		    freegold(gold);
X		    if(!levl[x][y].mmask) newsym(x, y);
X		    if(mon = ghit(u.dx, u.dy, range)) {
X			setmangry(mon); /* not a means for payment to shk */
X			if(ghitm(mon, zm)) /* was it caught? */
X			    return(1);
X		    }
X		    mkgold(zm, bhitpos.x, bhitpos.y);
X		    if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y);
X		}
X		return(1);
X	}
X
X	if(obj->otyp == BOULDER || obj == uball)
X		return(0);
X
X	/* a box gets a chance of breaking open here */
X	if(Is_box(obj)) {
X		boolean otrp = obj->otrapped;
X
X		if (!obj->olocked && (!rn2(3) ||
X					(martial() && !rn2(2)))) {
X		    pline("The lid slams open, then falls shut.");
X		    if(otrp) goto gotcha;
X		    return(1);
X		} else if (obj->olocked && 
X				(!rn2(5) || (martial() && !rn2(2)))) {
X		    You("break open the lock!");
X		    obj->olocked = 0;
X	            if(otrp) {
Xgotcha:
X		        chest_trap(obj, LEG);
X		    }
X		    return(1);
X		}
X		/* let it fall through to the next cases... */
X	}
X
X	if(Levitation && !rn2(3)) {
X		You("miss."); /* do not identify the object */
X		return(1);
X	}
X
X	/* fragile objects should not be kicked */
X	if (breaks(obj, FALSE)) return(1);
X
X	costly = costly_spot(x, y);
X
X	/* potions get a chance of breaking here */
X	if(obj->olet == POTION_SYM) {
X		if(rn2(2)) {
X		    You("smash the %s!", xname(obj));
X		    if(costly) addtobill(obj, FALSE);
X		    potionbreathe(obj);
X		    delobj(obj);	/* takes care of omask */
X		    return(1);
X		}
X	}
X
X	/* too heavy to move. make sure not to call bhit  */
X	/* in this function when range < 2 (a display bug */
X	/* results otherwise).  			  */
X	if(range <= 2) {
X	    if(Is_box(obj)) pline("THUD!");
X	    else pline("Thump!");
X	    if(!rn2(3) || martial()) return(1);
X	    return(0);
X	}
X
X	if(cnt > 1) {
X		/* Needed to fool bhit's display-cleanup to show */
X		/* immediately the next object in the pile.  We  */
X		/* know here that the object will move, so there */
X		/* is no need to worry about omask.		 */
X		obj->ox = u.ux;
X		obj->oy = u.uy;
X	} else {
X		levl[x][y].omask = 0;
X		if(!levl[x][y].gmask) newsym(x, y);
X	}
X
X	mon = bhit(u.dx, u.dy, range, obj->olet,
X			(int (*)()) 0, (int (*)()) 0, obj);
X	if(mon) {
X# ifdef WORM
X		if (mon->mx != bhitpos.x || mon->my != bhitpos.y)
X			notonhead = TRUE;
X# endif
X		/* awake monster if sleeping */
X		wakeup(mon);
X		if(thitmonst(mon, obj)) return(1);
X	}
X	if(costly && !costly_spot(bhitpos.x,bhitpos.y)) addtobill(obj, FALSE);
X	obj->ox = bhitpos.x;
X	obj->oy = bhitpos.y;
X	levl[obj->ox][obj->oy].omask = 1;
X	stackobj(obj);
X	return(1);
X}
X#endif /* KICK */
X
X
Xint
Xdokick() {		/* try to kick the door down - noisy! */
X        register int x, y;
X	register struct rm *maploc;
X	register int avrg_attrib = (ACURR(A_STR)+ACURR(A_DEX)+ACURR(A_CON))/3;
X
X#ifdef POLYSELF
X	if(nolimbs(uasmon)) {
X		You("have no legs to kick with.");
X		return(0);
X	}
X	if(verysmall(uasmon)) {
X		You("are too small to do any kicking.");
X		return(0);
X	}
X#endif
X	if(Wounded_legs) {
X		Your("%s %s in no shape for kicking.",
X		      ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES)
X			? makeplural(body_part(LEG)) : body_part(LEG),
X		      ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES) ? "are" : "is");
X		return(0);
X	}
X
X	if(inv_weight() > 0) {
X		Your("load is too heavy to balance yourself for a kick.");
X		return(0);
X	}
X
X        if(u.utrap) {
X		switch (u.utraptype) {
X		    case TT_PIT:
X			pline("There's nothing to kick down here.");
X		    case TT_WEB:
X		    case TT_BEARTRAP:
X			You("can't move your %s!", body_part(LEG));
X		}
X		return(0);
X	}
X
X	if(!getdir(1)) return(0);
X	if(!u.dx && !u.dy) return(0);
X
X	x = u.ux + u.dx;
X	y = u.uy + u.dy;
X
X	if(u.uswallow) {
X		switch(rn2(3)) {
X		case 0:  You("can't move your %s!", body_part(LEG));
X			 break;
X		case 1:  pline("%s burps loudly.", Monnam(u.ustuck)); break;
X		default: Your("feeble kick has no effect."); break;
X		}
X		return(1);
X	}
X
X	wake_nearby();
X	u_wipe_engr(2);
X
X	maploc = &levl[x][y];
X
X#ifdef KICK
X	/* The next four main loops should stay in */
X	/* their present order: monsters, objects, */
X	/* non-doors, doors.			   */ 
X
X	if(maploc->mmask) {
X		kick_monster(x, y);
X		return(1);
X	}
X
X	if((maploc->omask || maploc->gmask) && !Levitation) {
X		if(kick_object(x, y)) return(1);
X		else goto ouch;
X	}
X
X	if(!IS_DOOR(maploc->typ)) {
X		if(maploc->typ == SDOOR) {
X		    if(rn2(30) < avrg_attrib) { 
X			pline("Crash!  You kick open a secret door!");
X			maploc->typ = DOOR;
X			atl(x, y, (char) DOOR_SYM);
X			if(maploc->doormask & D_TRAPPED) {
X			    b_trapped("door");
X			    maploc->doormask = D_NODOOR;
X			} else
X			    maploc->doormask = D_ISOPEN;
X			return(1);
X		    } else goto ouch;
X		}
X		if(maploc->typ == SCORR) {
X		    if(rn2(30) < avrg_attrib) { 
X			pline("Crash!  You kick open a secret passage!");
X			maploc->typ = CORR;
X			atl(x, y, (char) CORR_SYM);
X			return(1);
X		    } else goto ouch;
X		}
X# ifdef THRONES
X		if(IS_THRONE(maploc->typ)) {
X		    register int i;
X		    if((u.uluck < 0 || maploc->doormask) && !rn2(3)) {
X			pline("CRASH!  You destroy the throne.");
X			maploc->typ = ROOM;
X			maploc->doormask = 0; /* don't leave loose ends.. */
X			mkgold((long)rnd(200), x, y);
X			prl(x, y);
X			return(1);
X		    } else if(u.uluck && !rn2(3) && !maploc->doormask) {
X			You("kick loose some ornamental coins and gems!");
X			mkgold((300L+(long)rn2(201)), x, y);
X			i = u.uluck + 1;
X			if(i > 6) i = 6;
X			while(i--) (void) mkobj_at(GEM_SYM, x, y);
X			prl(x, y);
X			/* prevent endless milking */
X			maploc->doormask = T_LOOTED; 
X			return(1);
X		    } else if (!rn2(4)) {
X			register struct trap *ttmp = 
X					maketrap(u.ux,u.uy,TRAPDOOR);
X			dotrap(ttmp);
X			return(1);
X		    }
X		    goto ouch;
X		}
X# endif
X# ifdef ALTARS
X		if(IS_ALTAR(maploc->typ)) {
X		    You("kick the altar.");
X		    if(!rn2(3)) goto ouch; 
X#  ifdef THEOLOGY
X		    altar_wrath(x, y);
X#  endif
X		    return(1);
X		}
X# endif
X# ifdef SINKS
X		if(IS_SINK(maploc->typ)) {
X		    if(rn2(5)) {
X			if(flags.soundok)
X			    pline("Klunk!  The pipes vibrate noisily.");
X			else pline("Klunk!");
X		        return(1);
X		    } else if(!rn2(3) &&
X			      !(mons[PM_BLACK_PUDDING].geno & G_GENOD)) {
X			pline("A %s ooze gushes up from the drain!",
X			      Hallucination ? hcolor() : black);
X			pmon(makemon(&mons[PM_BLACK_PUDDING], x, y));
X			return(1);
X#  ifdef HARD
X		    } else if(!rn2(3) &&
X#   ifndef POLYSELF
X			      poly_gender() != 2 &&
X#   endif
X			      !(mons[poly_gender() == 1 ? PM_INCUBUS : PM_SUCCUBUS].geno & G_GENOD)) {
X			/* can't resist... */
X			pline("The dish washer returns!");
X			pmon(makemon(&mons[poly_gender() == 1 ? PM_INCUBUS : PM_SUCCUBUS], x, y));
X			return(1);
X#  endif
X		    } else if(!rn2(3)) {
X			pline("Flupp!  Muddy waste pops up from the drain.");
X			if(!maploc->doormask) { /* only once per sink */
X			    if(!Blind) 
X				You("see a ring shining in its midst.");
X			    (void) mkobj_at(RING_SYM, x, y);
X			    prl(x, y);
X			    maploc->doormask = T_LOOTED;
X			}
X			return(1);
X		    }
X		    goto ouch;
X		}
X# endif
X		if(maploc->typ == STAIRS 
X# ifdef STRONGHOLD
X					|| maploc->typ == LADDER
X# endif
X		  ) goto ouch;
X		if(IS_STWALL(maploc->typ)) {
Xouch:
X		    pline("Ouch!  That hurts!");
X		    if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
X		    losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), "dumb move");
X		    return(1);
X		}
X# ifdef STRONGHOLD
X		if (is_drawbridge_wall(x,y) >= 0) {
X		    pline("The drawbridge is unaffected.");
X		    return(1);
X		}
X# endif
X		goto dumb;
X	}
X#endif /* KICK */
X
X	if(maploc->doormask == D_ISOPEN ||
X	   maploc->doormask == D_BROKEN ||
X	   maploc->doormask == D_NODOOR) {
X#ifdef KICK
Xdumb:
X#endif
X		if (martial() || ACURR(A_DEX) >= 16) {
X			You("kick at empty space.");
X		} else {
X			pline("Dumb move!  You strain a muscle.");
X			set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
X		}
X		return(0);
X	}
X
X	/* door is known to be CLOSED or LOCKED */
X	if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
X		/* break the door */
X		if(maploc->doormask & D_TRAPPED) {
X		    pline("As you kick the door, it explodes!");
X		    b_trapped("door");
X		    maploc->doormask = D_NODOOR;
X		} else if(ACURR(A_STR) > 18 && !rn2(5) && !in_shop(x, y)) {
X		    pline("As you kick the door, it shatters to pieces!");
X		    maploc->doormask = D_NODOOR;
X		} else {
X		    pline("As you kick the door, it crashes open!");
X		    maploc->doormask = D_BROKEN;
X		    if(in_shop(x, y) && !in_shop(u.ux, u.uy))
X			pay_for_door(x, y, "break");
X		}
X	} else	pline("WHAMMM!!!");
X
X	return(1);
X}
END_OF_FILE
if test 15059 -ne `wc -c <'src/dokick.c'`; then
    echo shar: \"'src/dokick.c'\" unpacked with wrong size!
fi
# end of 'src/dokick.c'
fi
if test -f 'src/mondata.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/mondata.c'\"
else
echo shar: Extracting \"'src/mondata.c'\" \(14444 characters\)
sed "s/^X//" >'src/mondata.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)mondata.c	3.0	89/01/10
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include "hack.h"
X#include "eshk.h"
X#include "epri.h"
X
X/*	These routines provide basic data for any type of monster. */
X
Xboolean
Xattacktype(ptr, atyp)
X	register struct	permonst	*ptr;
X	register int atyp;
X{
X	int	i;
X
X	for(i = 0; i < NATTK; i++)
X	    if(ptr->mattk[i].aatyp == atyp) return(TRUE);
X
X	return(FALSE);
X}
X
Xboolean
Xresists_ston(ptr)	/* returns TRUE if monster is petrify resistant */
X	register struct permonst *ptr;
X{
X	return (ptr->mflags1 & M1_STON_RES || dmgtype(ptr, AD_STON) ||
X		dmgtype(ptr, AD_ACID));
X}
X
Xboolean
Xresists_drli(ptr)	/* returns TRUE if monster is drain-life resistant */
X
X	register struct permonst *ptr;
X{
X	return(is_undead(ptr) || is_demon(ptr) || is_were(ptr));
X}
X
Xboolean
Xranged_attk(ptr)	/* returns TRUE if monster can attack at range */
X	register struct permonst *ptr;
X{
X	return (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) ||
X		attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) ||
X		attacktype(ptr, AT_MAGC));
X}
X
Xboolean
Xcan_track(ptr)		/* returns TRUE if monster can track well */
X	register struct permonst *ptr;
X{
X#ifdef NAMED_ITEMS
X	if(uwep && !strcmp(ONAME(uwep), "Excalibur")) return TRUE;
X#endif
X	return(haseyes(ptr));
X}
X
X#ifdef POLYSELF
Xboolean
Xbreakarm(ptr)	/* creature will break out of armor */
X	register struct permonst *ptr;
X{
X	return(bigmonst(ptr) || (!verysmall(ptr) && !humanoid(ptr))
X#ifdef HARD
X	       || ptr == &mons[PM_MARILITH]
X#endif
X	       );
X	/* Marilith is about the only case of a monster which is otherwise
X	 * humanoid but cannot wear armor (too many arms).  Centaurs would
X	 * be another except that they are already accounted for by
X	 * bigmonst.
X	 */
X}
X
Xboolean
Xsliparm(ptr)	/* creature will slide out of armor */
X	register struct permonst *ptr;
X{
X	return(!bigmonst(ptr) && (verysmall(ptr) || ptr == &mons[PM_GHOST]));
X}
X#endif
X
Xboolean
Xsticks(ptr)	/* creature sticks other creatures it hits */
X	register struct permonst *ptr;
X{
X	return(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) ||
X		attacktype(ptr,AT_HUGS));
X}
X
X/* not one hundred percent correct: now a snake may hide under an
X *				    invisible object.
X */
Xboolean
Xcanseemon(mtmp)
X	register struct monst *mtmp;
X{
X	return((!mtmp->minvis || See_invisible)
X		&& (!mtmp->mhide ||
X		    (levl[mtmp->mx][mtmp->my].omask == 0 &&
X		     levl[mtmp->mx][mtmp->my].gmask == 0))
X		&& cansee(mtmp->mx, mtmp->my));
X}
X
Xboolean
Xdmgtype(ptr, dtyp)
X	register struct	permonst	*ptr;
X	register int dtyp;
X{
X	int	i;
X
X	for(i = 0; i < NATTK; i++)
X	    if(ptr->mattk[i].adtyp == dtyp) return TRUE;
X
X	return FALSE;
X}
X
Xint
Xmonsndx(ptr)		/* return an index into the mons array */
X	struct	permonst	*ptr;
X{
X	register int	i;
X	register struct permonst *mdat;
X
X	if(ptr == &playermon) return(-1);
X
X	for(i = 0, mdat = &mons[0]; mdat->mlet; i++)
X	     if(ptr == mdat++) return(i);
X
X	panic("monsndx - could not index monster (%x)", ptr);
X	return FALSE;			   /* will not get here */
X}
X
Xint
Xname_to_mon(str)
Xchar *str;
X{
X	/* Be careful.  We must check the entire string in case it was
X	 * something such as "ettin zombie corpse".  The calling routine
X	 * doesn't know about the "corpse" until the monster name has
X	 * already been taken off the front, so we have to be able to
X	 * read the name with extraneous stuff such as "corpse" stuck on
X	 * the end.
X	 * This causes a problem for names which prefix other names such
X	 * as "ettin" on "ettin zombie".  In this case we want the _longest_
X	 * name which exists.
X	 * This also permits plurals created by adding suffixes such as 's'
X	 * or 'es'.  Other plurals must still be handled explicitly.
X	 */
X	register int i;
X	register int mntmp = -1;
X	register char *s;
X	char buf[BUFSZ];
X	int len=0;
X
X	Strcpy(buf, str);
X	str = buf;
X	if (!strncmp(str, "a ", 2)) str += 2;
X	else if (!strncmp(str, "an ", 3)) str += 3;
X
X	/* Some irregular plurals */
X#ifdef HARD
X	if (!strncmp(str, "incubi", 6)) return PM_INCUBUS;
X	if (!strncmp(str, "succubi", 7)) return PM_SUCCUBUS;
X#endif
X	if (!strncmp(str, "violet fungi", 12)) return PM_VIOLET_FUNGUS;
X	if (!strncmp(str, "homunculi", 9)) return PM_HOMUNCULUS;
X	if (!strncmp(str, "baluchitheria", 13)) return PM_BALUCHITHERIUM;
X	if (!strncmp(str, "lurkers above", 13)) return PM_LURKER_ABOVE;
X	if (!strncmp(str, "cavemen", 7)) return PM_CAVEMAN;
X	if (!strncmp(str, "cavewomen", 9)) return PM_CAVEWOMAN;
X	if (!strncmp(str, "zruties", 7)) return PM_ZRUTY;
X	if (!strncmp(str, "djinn", 5)) return PM_DJINNI;
X		/* be careful with "ies"; "priest", "zombies" */
X	for(s=str; *s; s++) {
X		if (!strncmp(s, "vortices", 8)) {
X			Strcpy(s+4, "ex");
X			break;
X		}
X		if (!strncmp(s, "jellies", 7) || !strncmp(s, "mummies", 7)) {
X			Strcpy(s+4, "y");
X			break;
X		}
X		if (!strncmp(s, "ves", 3)) {
X		/* luckily no monster names end in fe or ve with ves plurals */
X			Strcpy(s, "f");
X			break;
X		}
X	}
X	
X	for(i = 0; mons[i].mlet; i++) {
X		if(!strncmp(mons[i].mname, str, strlen(mons[i].mname))) {
X			if (strlen(mons[i].mname) > len) {
X				mntmp = i;
X				len = strlen(mons[i].mname);
X			}
X		}
X	}
X	return mntmp;
X}
X
X#ifdef POLYSELF
Xboolean
Xwebmaker(ptr)   /* creature can spin a web */
X	register struct permonst *ptr;
X{
X	return (ptr->mlet == S_SPIDER && ptr != &mons[PM_SCORPION]);
X}
X#endif
X
Xboolean
Xis_female(mtmp)
X	register struct monst *mtmp;
X{
X	if (mtmp->isshk) return !ESHK(mtmp)->ismale;
X#if defined(ALTARS) && defined(THEOLOGY)
X	if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
X#endif
X	return !!(mtmp->data->mflags1 & M1_FEM);
X}
X
X/* Gender function.  Differs from is_female() in that 1) It allows the monster
X * type of a polymorphed shopkeeper to override ESHK(mtmp)->ismale, and 2)
X * it returns 3 values (0=male, 1=female, 2=none) instead of 2.
X */
Xint
Xgender(mtmp)
X	register struct monst *mtmp;
X{
X	if (!humanoid(mtmp->data)) return 2;
X	if (mtmp->data->mflags1 & M1_FEM) return 1;
X	if (mtmp->data == &mons[PM_CAVEMAN]
X		|| mtmp->data == &mons[PM_PRIEST]
X#ifdef HARD
X		|| mtmp->data == &mons[PM_INCUBUS]
X#endif
X						) return 0;
X#if defined(ALTARS) && defined(THEOLOGY)
X	if (mtmp->ispriest) return !EPRI(mtmp)->ismale;
X#endif
X	if (mtmp->isshk) return !ESHK(mtmp)->ismale;
X	return 0;
X}
X
Xboolean
Xlevl_follower(mtmp)
Xregister struct monst *mtmp;
X{
X	return (mtmp->mtame || (mtmp->data->mflags1 & M1_STALK) || is_fshk(mtmp)
X		|| (mtmp->iswiz && !mon_has_amulet(mtmp)));
X}
X
Xstruct permonst *
Xplayer_mon()
X{
X	switch (pl_character[0]) {
X		case 'A': return &mons[PM_ARCHEOLOGIST];
X		case 'B': return &mons[PM_BARBARIAN];
X		case 'C': if (flags.female) return &mons[PM_CAVEWOMAN];
X			else return &mons[PM_CAVEMAN];
X		case 'E': return &mons[PM_ELF];
X		case 'H': return &mons[PM_HEALER];
X		case 'K': return &mons[PM_KNIGHT];
X		case 'P': if (flags.female) return &mons[PM_PRIESTESS];
X			else return &mons[PM_PRIEST];
X		case 'R': return &mons[PM_ROGUE];
X		case 'S': return &mons[PM_SAMURAI];
X		case 'T': return &mons[PM_TOURIST];
X		case 'V': return &mons[PM_VALKYRIE];
X		case 'W': return &mons[PM_WIZARD];
X		default: impossible("what are you?");
X			return &mons[PM_HUMAN];
X	}
X}
X
Xconst int grownups[][2] = { {PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG},
X	{PM_HELL_HOUND_PUP, PM_HELL_HOUND}, {PM_KITTEN, PM_HOUSECAT},
X	{PM_HOUSECAT, PM_LARGE_CAT}, {PM_BABY_GREY_DRAGON, PM_GREY_DRAGON},
X	{PM_BABY_RED_DRAGON, PM_RED_DRAGON},
X	{PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON},
X	{PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON},
X	{PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON},
X	{PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON},
X	{PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON},
X	{PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON},
X	{PM_RED_NAGA_HATCHLING, PM_RED_NAGA},
X	{PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA},
X	{PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA},
X	{PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA},
X	{PM_BABY_PURPLE_WORM, PM_PURPLE_WORM},
X#ifdef WORM
X	{PM_BABY_LONG_WORM, PM_LONG_WORM},
X#endif
X#ifdef ARMY
X	{PM_SOLDIER, PM_SERGEANT},
X	{PM_SERGEANT, PM_LIEUTENANT},
X	{PM_LIEUTENANT, PM_CAPTAIN},
X#endif
X	{-1,-1}
X};
X
Xint little_to_big(montype)
Xint montype;
X{
X	register int *i;
X	
X	for(i=grownups[0]; *i >= 0; i++)
X		if(montype == *i) return *(i+1);
X	return montype;
X}
X
Xint big_to_little(montype)
Xint montype;
X{
X	register int *i;
X	
X	for(i=grownups[0]; *i >= 0; i++)
X		if(montype == *(i+1)) return *i;
X	return montype;
X}
X
X
X#ifdef STUPID_CPP	/* otherwise these functions are macros in mondata.h */
X
Xint
Xbigmonst(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_BIG) != 0L);
X}
X
Xint
Xverysmall(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_VSMALL) != 0L);
X}
X
Xint
Xis_flyer(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_FLY) != 0L);
X}
X
Xint
Xis_floater(ptr) struct permonst *ptr; {
X	return(ptr->mlet == S_EYE);
X}
X
Xint
Xis_swimmer(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_SWIM) != 0L);
X}
X
Xint
Xpasses_walls(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_WALLWALK) != 0L);
X}
X
Xint
Xnoncorporeal(ptr) struct permonst *ptr; {
X	return(ptr->mlet == S_GHOST);
X}
X
Xint
Xis_animal(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_ANIMAL) != 0L);
X}
X
Xint
Xhumanoid(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_HUMANOID) != 0L);
X}
X
Xint
Xis_undead(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_UNDEAD) != 0L);
X}
X
Xint
Xis_were(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_WERE) != 0L);
X}
X
Xint haseyes(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_NOEYES) == 0L);
X}
X
Xint
Xnohands(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_NOHANDS) != 0L);
X}
X
Xint
Xlays_eggs(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_EGGS) != 0L);
X}
X
Xint
Xpoisonous(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_POIS) != 0L);
X}
X
Xint
Xresists_poison(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & (M1_POIS | M1_POIS_RES)) != 0L);
X}
X
Xint
Xresists_fire(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_FIRE_RES) != 0L);
X}
X
Xint
Xresists_cold(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_COLD_RES) != 0L);
X}
X
Xint
Xresists_acid(ptr) struct permonst *ptr; {
X	return(dmgtype(ptr, AD_ACID));
X}
X
Xint
Xresists_elec(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_ELEC_RES) != 0L);
X}
X
Xint
Xresists_sleep(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & (M1_SLEE_RES | M1_UNDEAD)) != 0L);
X}
X
Xint
Xresists_disint(ptr) struct permonst *ptr; {
X	return(ptr == &mons[PM_BLACK_DRAGON] ||
X		ptr == &mons[PM_BABY_BLACK_DRAGON]);
X}
X
Xint
Xregenerates(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_REGEN) != 0L);
X}
X
Xint
Xperceives(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_SEE_INVIS) != 0L);
X}
X
Xint
Xcan_teleport(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_TPORT) != 0L);
X}
X
Xint
Xcontrol_teleport(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_TPORT_CONTROL) != 0L);
X}
X
Xint
Xis_armed(ptr) struct permonst *ptr; {
X	return(attacktype(ptr, AT_WEAP));
X}
X
Xint
Xlikes_gold(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_GREEDY) != 0L);
X}
X
Xint
Xlikes_gems(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_JEWELS) != 0L);
X}
X
Xint
Xlikes_objs(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_COLLECT) != 0L || is_armed(ptr));
X}
X
Xint
Xlikes_magic(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_MAGIC) != 0L);
X}
X
Xint
Xhides_under(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_CONCEAL) != 0L);
X}
X
Xint
Xis_hider(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_HIDE) != 0L);
X}
X
X# ifdef POLYSELF
Xint
Xpolyok(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_NOPOLY) == 0L);
X}
X# endif /* POLYSELF */
X
Xint
Xtunnels(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_TUNNEL) != 0L);
X}
X
Xint
Xneedspick(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_NEEDPICK) != 0L);
X}
X
Xint
Xis_elf(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_ELF) != 0L);
X}
X
Xint
Xis_dwarf(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_DWARF) != 0L);
X}
X
Xint
Xis_giant(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_GIANT) != 0L);
X}
X
X# ifdef GOLEMS
Xint
Xis_golem(ptr) struct permonst *ptr; {
X	return(ptr->mlet == S_GOLEM);
X}
X# endif /* GOLEMS */
X
Xint
Xis_orc(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_ORC) != 0L);
X}
X
Xint
Xis_human(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_HUMAN) != 0L);
X}
X
Xint
Xis_demon(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_DEMON) != 0L);
X}
X
Xint
Xis_mercenary(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_MERC) != 0L);
X}
X
Xint
Xthrows_rocks(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_ROCKTHROW) != 0L);
X}
X
Xint
Xis_wanderer(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_WANDER) != 0L);
X}
X
Xint
Xis_lord(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_LORD) != 0L);
X}
X
Xint
Xis_prince(ptr) struct permonst *ptr; {
X	return((ptr->mflags1 & M1_PRINCE) != 0L);
X}
X
X# ifdef HARD
Xint
Xis_ndemon(ptr) struct permonst *ptr; {
X	return(is_demon(ptr) &&
X		(ptr->mflags1 & (M1_LORD | M1_PRINCE)) == 0L);
X}
X# else /* HARD */
Xint
Xis_ndemon(ptr) struct permonst *ptr; {
X	return(ptr == &mons[PM_DEMON]);
X}
X# endif /* HARD */
X
Xint
Xis_dlord(ptr) struct permonst *ptr; {
X	return(is_demon(ptr) && is_lord(ptr));
X}
X
Xint
Xis_dprince(ptr) struct permonst *ptr; {
X	return(is_demon(ptr) && is_prince(ptr));
X}
X
Xint
Xtype_is_pname(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_PNAME) != 0L);
X}
X
Xint
Xalways_hostile(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_HOSTILE) != 0L);
X}
X
Xint
Xalways_peaceful(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_PEACEFUL) != 0L);
X}
X
Xint
Xstrongmonst(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_STRONG) != 0L);
X}
X
Xint
Xextra_nasty(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_NASTY) != 0L);
X}
X
X# ifdef POLYSELF
Xint
Xcan_breathe(ptr) struct permonst *ptr; {
X	return(attacktype(ptr, AT_BREA));
X}
X
Xint
Xcantwield(ptr) struct permonst *ptr; {
X	return(nohands(ptr) || verysmall(ptr));
X}
X
Xint
Xcantweararm(ptr) struct permonst *ptr; {
X	return(breakarm(ptr) || sliparm(ptr));
X}
X
Xint
Xnolimbs(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_NOLIMBS) != 0L);
X}
X# endif /* POLYSELF */
X
Xint
Xcarnivorous(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_CARNIVORE) != 0L);
X}
X
Xint
Xherbivorous(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_HERBIVORE) != 0L);
X}
X
Xint
Xthick_skinned(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_THICK_HIDE) != 0L);
X}
X
Xint
Xamorphous(ptr) struct permonst *ptr; {
X	return((ptr->mflags2 & M2_AMORPHOUS) != 0L);
X}
X
X#endif /* STUPID_CPP */
END_OF_FILE
if test 14444 -ne `wc -c <'src/mondata.c'`; then
    echo shar: \"'src/mondata.c'\" unpacked with wrong size!
fi
# end of 'src/mondata.c'
fi
if test -f 'src/pager.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/pager.c'\"
else
echo shar: Extracting \"'src/pager.c'\" \(15100 characters\)
sed "s/^X//" >'src/pager.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)pager.c	3.0	88/10/25 */
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X/* This file contains the command routine dowhatis() and a pager. */
X/* Also readmail() and doshell(), and generally the things that
X   contact the outside world. */
X
X/* block some unused #defines to avoid overloading some cpp's */
X#define MONATTK_H
X#include	 "hack.h"
X
X#ifndef TOS
X#include <signal.h>
X#endif
X#if defined(BSD) || defined(ULTRIX)
X#include <sys/wait.h>
X#endif
X
Xstatic char hc = 0;
X
Xstatic void page_more();
X
Xint
Xdowhatis()
X{
X	FILE *fp;
X	char bufr[BUFSZ+6];
X	register char *buf = &bufr[6], *ep, q;
X	register struct monst *mtmp;
X
X	if(!(fp = fopen(DATAFILE, "r")))
X		pline("Cannot open data file!");
X	else {
X		coord	cc;
X		uchar	r;
X
X		pline ("Specify unknown object by cursor? ");
X		q = ynq();
X		cc.x = cc.y = -1;
X		if (q == 'q') {
X			(void) fclose(fp);
X			return 0;
X		} else if (q == 'n') {
X			pline("Specify what? ");
X			r = readchar();
X		} else {
X		    if(flags.verbose)
X			pline("Please move the cursor to the unknown object.");
X		    getpos(&cc, TRUE, "the unknown object");
X		    r = levl[cc.x][cc.y].scrsym;
X		}
X
X		if (r == showsyms.stone) q = defsyms.stone;
X		else if (r == showsyms.vwall) q = defsyms.vwall;
X		else if (r == showsyms.hwall) q = defsyms.hwall;
X		else if (r == showsyms.tlcorn) q = defsyms.tlcorn;
X		else if (r == showsyms.trcorn) q = defsyms.trcorn;
X		else if (r == showsyms.blcorn) q = defsyms.blcorn;
X		else if (r == showsyms.brcorn) q = defsyms.brcorn;
X		else if (r == showsyms.crwall) q = defsyms.crwall;
X		else if (r == showsyms.tuwall) q = defsyms.tuwall;
X		else if (r == showsyms.tdwall) q = defsyms.tdwall;
X		else if (r == showsyms.tlwall) q = defsyms.tlwall;
X		else if (r == showsyms.trwall) q = defsyms.trwall;
X		else if (r == showsyms.door) q = defsyms.door;
X		else if (r == showsyms.room) q = defsyms.room;
X		else if (r == showsyms.corr) q = defsyms.corr;
X		else if (r == showsyms.upstair) q = defsyms.upstair;
X		else if (r == showsyms.dnstair) q = defsyms.dnstair;
X		else if (r == showsyms.trap) q = defsyms.trap;
X#ifdef FOUNTAINS
X		else if (r == showsyms.pool) q = defsyms.pool;
X		else if (r == showsyms.fountain) q = defsyms.fountain;
X#endif
X#ifdef THRONES
X		else if (r == showsyms.throne) q = defsyms.throne;
X#endif
X		else if (r == showsyms.web) q = defsyms.web;
X#ifdef SINKS
X		else if (r == showsyms.sink) q = defsyms.sink;
X#endif
X#ifdef ALTARS
X		else if (r == showsyms.altar) q = defsyms.altar;
X#endif
X		else
X		    q = r;
X		if (index(quitchars, q)) {
X			(void) fclose(fp); /* sweet@scubed */
X			return 0;
X		}
X		if(q == '%') {
X			pline("%%       a piece of food");
X			(void) fclose(fp);
X			return 0;
X		}
X
X		if(q != '\t')
X		while(fgets(buf,BUFSZ,fp))
X		    if(*buf == q) {
X			ep = index(buf, '\n');
X			if(ep) *ep = 0;
X			/* else: bad data file */
X			/* Expand tab 'by hand' */
X			if(buf[1] == '\t'){
X				buf = bufr;
X				buf[0] = r;
X				(void) strncpy(buf+1, "       ", 7);
X			}
X			pline(buf);
X			if(cc.x != -1 && IS_ALTAR(levl[cc.x][cc.y].typ)) {
X			    int type = levl[u.ux][u.uy].altarmask & ~A_SHRINE;
X			    pline("(%s)", (type==0) ? "chaotic" :
X				(type==1) ? "neutral" : "lawful");
X			}
X			if (!Invisible && u.ux==cc.x && u.uy==cc.y) {
X			    pline("(%s named %s)",
X#ifdef POLYSELF
X				u.mtimedone ? mons[u.umonnum].mname :
X#endif
X				pl_character, plname);
X			} else if((q >= 'A' && q <= 'z') || index(";:& @`",q)) {
X			    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X				if(mtmp->mx == cc.x && mtmp->my == cc.y) {
X				    pline("(%s%s)",
X					mtmp->mtame ? "tame " :
X					  mtmp->mpeaceful ? "peaceful " : "",
X					strncmp(lmonnam(mtmp), "the ", 4)
X					  ? lmonnam(mtmp) : lmonnam(mtmp)+4);
X				    break;
X				}
X			}
X			if(ep[-1] == ';') {
X				pline("More info? ");
X				if(yn() == 'y') {
X					page_more(fp,1); /* does fclose() */
X					return 0;
X				}
X			}
X			(void) fclose(fp); 	/* kopper@psuvax1 */
X			return 0;
X		    }
X		pline("I've never heard of such things.");
X		(void) fclose(fp);
X	}
X	return 0;
X}
X
Xint
Xdowhatdoes()
X{
X	FILE *fp;
X	char bufr[BUFSZ+6];
X	register char *buf = &bufr[6], *ep, q, ctrl;
X
X	if(!(fp = fopen(CMDHELPFILE, "r"))) {
X		pline("Cannot open data file!");
X		return 0;
X	}
X	pline("What command? ");
X#ifdef UNIX
X	introff();
X#endif
X	q = readchar();
X#ifdef UNIX
X	intron();
X#endif
X	if (q == '\033') ctrl = '[';
X	else if (q != unctrl(q)) ctrl = q - 1 + 'A';
X	else ctrl = 0;
X	while(fgets(buf,BUFSZ,fp))
X	    if ((!ctrl && *buf==q) || (ctrl && *buf=='^' && *(buf+1)==ctrl)) {
X		ep = index(buf, '\n');
X		if(ep) *ep = 0;
X		if(!ctrl && buf[1] == '\t'){
X			buf = bufr;
X			buf[0] = q;
X			(void) strncpy(buf+1, "       ", 7);
X		} else if (ctrl && buf[2] == '\t'){
X			buf = bufr + 1;
X			buf[0] = '^';
X			buf[1] = ctrl;
X			(void) strncpy(buf+2, "      ", 6);
X		}
X		pline(buf);
X		(void) fclose(fp);
X		return 0;
X	    }
X	pline("I've never heard of such commands.");
X	(void) fclose(fp);
X	return 0;
X}
X
X/* make the paging of a file interruptible */
Xstatic int got_intrup;
X
X#if !defined(MSDOS) && !defined(TOS)
Xstatic int
Xintruph(){
X	(void) signal(SIGINT, (SIG_RET_TYPE) intruph);
X	got_intrup++;
X	return 0;
X}
X#endif
X
X/* simple pager, also used from dohelp() */
Xstatic void
Xpage_more(fp,strip)
XFILE *fp;
Xint strip;	/* nr of chars to be stripped from each line (0 or 1) */
X{
X	register char *bufr;
X#if !defined(MSDOS) && !defined(MINIMAL_TERM)
X	register char *ep;
X#endif
X#if !defined(MSDOS) && !defined(TOS)
X	int (*prevsig)() = (int (*)())signal(SIGINT, (SIG_RET_TYPE) intruph);
X#endif
X#if defined(MSDOS) || defined(MINIMAL_TERM)
X	/* There seems to be a bug in ANSI.SYS  The first tab character
X	 * after a clear screen sequence is not expanded correctly.  Thus
X	 * expand the tabs by hand -dgk
X	 */
X	int tabstop = 8, spaces;
X	char buf[BUFSIZ], *bufp, *bufrp;
X
X	set_pager(0);
X	bufr = (char *) alloc((unsigned) COLNO);
X	while (fgets(buf, BUFSIZ, fp) && (!strip || *buf == '\t')){
X		bufp = buf;
X		bufrp = bufr;
X		while (*bufp && *bufp != '\n') {
X			if (*bufp == '\t') {
X				spaces = tabstop - (bufrp - bufr) % tabstop;
X				while (spaces--)
X					*bufrp++ = ' ';
X				bufp++;
X			} else
X				*bufrp++ = *bufp++;
X		}
X		*bufrp = '\0';
X#else /* MSDOS /**/
X	set_pager(0);
X	bufr = (char *) alloc((unsigned) COLNO);
X	bufr[COLNO-1] = 0;
X	while(fgets(bufr,COLNO-1,fp) && (!strip || *bufr == '\t')){
X		ep = index(bufr, '\n');
X		if(ep)
X			*ep = 0;
X#endif /* MSDOS /**/
X		if(got_intrup || page_line(bufr+strip)) {
X			set_pager(2);
X			goto ret;
X		}
X	}
X	set_pager(1);
Xret:
X	free((genericptr_t) bufr);
X	(void) fclose(fp);
X#if !defined(MSDOS) && !defined(TOS)
X	(void) signal(SIGINT, (SIG_RET_TYPE) prevsig);
X	got_intrup = 0;
X#endif
X}
X
Xstatic boolean whole_screen = TRUE;
X#define	PAGMIN	12	/* minimum # of lines for page below level map */
X
Xvoid
Xset_whole_screen() {	/* called in termcap as soon as LI is known */
X	whole_screen = (LI-ROWNO-2 <= PAGMIN || !CD);
X}
X
X#ifdef NEWS
Xint
Xreadnews() {
X	register int ret;
X
X	whole_screen = TRUE;	/* force a docrt(), our first */
X	ret = page_file(NEWS, TRUE);
X	set_whole_screen();
X	return(ret);		/* report whether we did docrt() */
X}
X#endif
X
Xvoid
Xset_pager(mode)
Xregister int mode;	/* 0: open  1: wait+close  2: close */
X{
X#ifdef LINT	/* lint may handle static decl poorly -- static boolean so; */
X	boolean so;
X#else
X	static boolean so;
X#endif
X	if(mode == 0) {
X		if(!whole_screen) {
X			/* clear topline */
X			clrlin();
X			/* use part of screen below level map */
X			curs(1, ROWNO+4);
X		} else {
X			cls();
X		}
X		so = flags.standout;
X		flags.standout = 1;
X	} else {
X		if(mode == 1) {
X			curs(1, LI);
X			more();
X		}
X		flags.standout = so;
X		if(whole_screen)
X			docrt();
X		else {
X			curs(1, ROWNO+4);
X			cl_eos();
X		}
X	}
X}
X
Xint
Xpage_line(s)		/* returns 1 if we should quit */
Xregister char *s;
X{
X	if(cury == LI-1) {
X		if(!*s)
X			return(0);	/* suppress blank lines at top */
X		(void) putchar('\n');
X		cury++;
X		cmore("q\033");
X		if(morc) {
X			morc = 0;
X			return(1);
X		}
X		if(whole_screen)
X			cls();
X		else {
X			curs(1, ROWNO+4);
X			cl_eos();
X		}
X	}
X#ifdef TERMINFO
X	xputs(s); xputc('\n');
X#else
X	(void) puts(s);
X#endif
X	cury++;
X	return(0);
X}
X
X/*
X * Flexible pager: feed it with a number of lines and it will decide
X * whether these should be fed to the pager above, or displayed in a
X * corner.
X * Call:
X *	cornline(0, title or 0)	: initialize
X *	cornline(1, text)	: add text to the chain of texts
X *	cornline(2, morcs)	: output everything and cleanup
X *	cornline(3, 0)		: cleanup
X *	cornline(-1,"")		: special, for help menu mode only
X */
X
Xvoid
Xcornline(mode, text)
Xint mode;
Xchar *text;
X{
X	static struct line {
X		struct line *next_line;
X		char *line_text;
X	} *texthead, *texttail;
X	static int maxlen;
X	static int linect;
X	register struct line *tl;
X	register boolean hmenu = FALSE;
X
X	if(mode == -1) { /* help menu display only */
X		mode = 2;
X		hmenu = TRUE;
X	}
X	if(mode == 0) {
X		texthead = 0;
X		maxlen = 0;
X		linect = 0;
X		if(text) {
X			cornline(1, text);	/* title */
X			cornline(1, "");	/* blank line */
X		}
X		return;
X	}
X
X	if(mode == 1) {
X	    register int len;
X
X	    if(!text) return;	/* superfluous, just to be sure */
X	    linect++;
X	    len = strlen(text) + 1; /* allow for an extra leading space */
X	    if(len > maxlen)
X		maxlen = len;
X	    tl = (struct line *)
X		alloc((unsigned)(len + sizeof(struct line) + 1));
X	    tl->next_line = 0;
X	    tl->line_text = (char *)(tl + 1);
X	    tl->line_text[0] = ' ';
X	    tl->line_text[1] = '\0';
X	    Strcat(tl->line_text, text);
X	    if(!texthead)
X		texthead = tl;
X	    else
X		texttail->next_line = tl;
X	    texttail = tl;
X	    return;
X	}
X
X	/* --- now we really do it --- */
X	if(mode == 2 && linect == 1)			    /* topline only */
X		pline(texthead->line_text);
X	else
X	if(mode == 2) {
X	    register int curline, lth;
X
X	    if(flags.toplin == 1) more();	/* ab@unido */
X	    remember_topl();
X
X	    lth = CO - maxlen - 2;		   /* Use full screen width */
X	    if (linect < LI && lth >= 10) {		     /* in a corner */
X		home ();
X		cl_end ();
X		flags.toplin = 0;
X		curline = 1;
X		for (tl = texthead; tl; tl = tl->next_line) {
X#if defined(MSDOS) && !defined(AMIGA)
X		    cmov (lth, curline);
X#else
X		    curs (lth, curline);
X#endif
X		    if(curline > 1)
X			cl_end ();
X		    xputs(tl->line_text);
X		    curx = curx + strlen(tl->line_text);
X		    curline++;
X		}
X		if(hmenu) hc = lowc(readchar()); /* help menu display */
X#if defined(MSDOS) && !defined(AMIGA)
X		cmov (lth, curline);
X#else
X		curs (lth, curline);
X#endif
X		cl_end ();
X		if (!hmenu) cmore (text);
X		home ();
X		cl_end ();
X		docorner (lth, curline-1);
X	    } else {					/* feed to pager */
X		set_pager(0);
X		for (tl = texthead; tl; tl = tl->next_line) {
X		    if (page_line (tl->line_text)) {
X			set_pager(2);
X			goto cleanup;
X		    }
X		}
X		if(text) {
X			cgetret(text);
X			set_pager(2);
X		} else
X			set_pager(1);
X	    }
X	}
X
Xcleanup:
X	while(tl = texthead) {
X		texthead = tl->next_line;
X		free((genericptr_t) tl);
X	}
X}
X
X#ifdef WIZARD
Xstatic
Xvoid
Xwiz_help()
X{
X	cornline(0, "Wizard-Mode Quick Reference:");
X	cornline(1, "^E  ==  detect secret doors and traps.");
X	cornline(1, "^F  ==  do magic mapping.");
X	cornline(1, "^G  ==  create monster.");
X	cornline(1, "^I  ==  identify items in pack.");
X	cornline(1, "^O  ==  tell locations of special levels.");
X	cornline(1, "^T  ==  do intra-level teleport.");
X	cornline(1, "^V  ==  do trans-level teleport.");
X	cornline(1, "^W  ==  make wish.");
X	cornline(1, "^X  ==  show intrinsic attributes.");
X	cornline(1, "");
X	cornline(2, "");
X}
X#endif
X
Xstatic void
Xhelp_menu() {
X	cornline(0, "Information available:");
X	cornline(1, "a.  Long description of the game and commands.");
X	cornline(1, "b.  List of game commands.");
X	cornline(1, "c.  Concise history of NetHack.");
X	cornline(1, "d.  Info on a character in the game display.");
X	cornline(1, "e.  Info on what a given key does.");
X	cornline(1, "f.  List of game options.");
X	cornline(1, "g.  Longer explanation of game options.");
X	cornline(1, "h.  List of extended commands.");
X	cornline(1, "i.  The NetHack license.");
X#ifdef WIZARD
X	if (wizard)
X		cornline(1, "j.  List of wizard-mode commands.");
X#endif
X	cornline(1, "");
X#ifdef WIZARD
X	if (wizard)
X		cornline(1, "Select one of a,b,c,d,e,f,g,h,i,j or ESC: ");
X	else
X#endif
X		cornline(1, "Select one of a,b,c,d,e,f,g,h,i or ESC: ");
X	cornline(-1,"");
X}
X
Xint
Xdohelp()
X{
X	char c;
X
X	do {
X	    help_menu();
X	    c = hc;
X#ifdef WIZARD
X	} while ((c < 'a' || c > (wizard ? 'j' : 'i')) && !index(quitchars,c));
X#else
X	} while ((c < 'a' || c > 'i') && !index(quitchars,c));
X#endif
X	if (!index(quitchars, c)) {
X		switch(c) {
X			case 'a':  (void) page_file(HELP, FALSE);  break;
X			case 'b':  (void) page_file(SHELP, FALSE);  break;
X			case 'c':  (void) dohistory();  break;
X			case 'd':  (void) dowhatis();  break;
X			case 'e':  (void) dowhatdoes();  break;
X			case 'f':  option_help();  break;
X			case 'g':  (void) page_file(OPTIONFILE, FALSE);  break;
X			case 'h':  (void) doextlist();  break;
X			case 'i':  (void) page_file(LICENSE, FALSE);  break;
X#ifdef WIZARD
X			case 'j':  wiz_help();  break;
X#endif
X		}
X	}
X	return 0;
X}
X
Xint
Xdohistory()
X{
X	(void) page_file(HISTORY, FALSE);
X	return 0;
X}
X
Xint
Xpage_file(fnam, silent)	/* return: 0 - cannot open fnam; 1 - otherwise */
Xregister char *fnam;
Xboolean silent;
X{
X#ifdef DEF_PAGER			/* this implies that UNIX is defined */
X      {
X	/* use external pager; this may give security problems */
X
X	register int fd = open(fnam, 0);
X
X	if(fd < 0) {
X		if(!silent) pline("Cannot open %s.", fnam);
X		return(0);
X	}
X	if(child(1)){
X		/* Now that child() does a setuid(getuid()) and a chdir(),
X		   we may not be able to open file fnam anymore, so make
X		   it stdin. */
X		(void) close(0);
X		if(dup(fd)) {
X			if(!silent) Printf("Cannot open %s as stdin.\n", fnam);
X		} else {
X			(void) execl(catmore, "page", NULL);
X			if(!silent) Printf("Cannot exec %s.\n", catmore);
X		}
X		exit(1);
X	}
X	(void) close(fd);
X      }
X#else
X      {
X	FILE *f;			/* free after Robert Viduya */
X
X	if ((f = fopen (fnam, "r")) == (FILE *) 0) {
X		if(!silent) {
X			home(); perror (fnam); flags.toplin = 1;
X			pline ("Cannot open %s.", fnam);
X		}
X		return(0);
X	}
X	page_more(f, 0);
X      }
X#endif /* DEF_PAGER /**/
X
X	return(1);
X}
X
X#ifdef UNIX
X#ifdef SHELL
Xint
Xdosh(){
Xregister char *str;
X	if(child(0)) {
X		if(str = getenv("SHELL"))
X			(void) execl(str, str, NULL);
X		else
X			(void) execl("/bin/sh", "sh", NULL);
X		pline("sh: cannot execute.");
X		exit(1);
X	}
X	return 0;
X}
X#endif /* SHELL /**/
X
Xint
Xchild(wt)
Xint wt;
X{
Xregister int f = fork();
X	if(f == 0){		/* child */
X		settty(NULL);		/* also calls end_screen() */
X		(void) setgid(getgid());
X		(void) setuid(getuid());
X#ifdef CHDIR
X		(void) chdir(getenv("HOME"));
X#endif
X		return(1);
X	}
X	if(f == -1) {	/* cannot fork */
X		pline("Fork failed.  Try again.");
X		return(0);
X	}
X	/* fork succeeded; wait for child to exit */
X	(void) signal(SIGINT,SIG_IGN);
X	(void) signal(SIGQUIT,SIG_IGN);
X	(void) wait(
X#if defined(BSD) || defined(ULTRIX)
X		(union wait *)
X#else
X		(int *)
X#endif
X		0);
X	gettty();
X	setftty();
X	(void) signal(SIGINT, (SIG_RET_TYPE) done1);
X#ifdef WIZARD
X	if(wizard) (void) signal(SIGQUIT,SIG_DFL);
X#endif
X	if(wt) getret();
X	docrt();
X	return(0);
X}
X#endif /* UNIX /**/
END_OF_FILE
if test 15100 -ne `wc -c <'src/pager.c'`; then
    echo shar: \"'src/pager.c'\" unpacked with wrong size!
fi
# end of 'src/pager.c'
fi
echo shar: End of archive 24 \(of 38\).
cp /dev/null ark24isdone
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 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 38 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