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

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

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



#! /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 14 (of 38)."
# Contents:  include/coord.h src/monmove.c src/read.c
# Wrapped by billr@saab on Sun Jul 23 21:32:57 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'include/coord.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'include/coord.h'\"
else
echo shar: Extracting \"'include/coord.h'\" \(272 characters\)
sed "s/^X//" >'include/coord.h' <<'END_OF_FILE'
X/*	SCCS Id: @(#)coord.h	3.0	88/04/25
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#ifndef COORD_H
X#define COORD_H
X
Xtypedef struct {
X	xchar x,y;
X} coord;
X
X#endif /* COORD_H /* */
END_OF_FILE
if test 272 -ne `wc -c <'include/coord.h'`; then
    echo shar: \"'include/coord.h'\" unpacked with wrong size!
fi
# end of 'include/coord.h'
fi
if test -f 'src/monmove.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/monmove.c'\"
else
echo shar: Extracting \"'src/monmove.c'\" \(20241 characters\)
sed "s/^X//" >'src/monmove.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)monmove.c	3.0	88/11/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 "mfndpos.h"
X#ifdef NAMED_ITEMS
X#  include "artifact.h"
X#endif
X
Xstatic boolean /* TRUE : mtmp died */
Xmb_trapped(mtmp)
Xregister struct monst *mtmp;
X{
X	if (flags.verbose) {
X	    if (cansee(mtmp->mx, mtmp->my))
X	       pline("KABOOM!!  You see a door explode.");
X	    else if (flags.soundok)
X               You("hear a distant explosion.");
X	}
X	mtmp->mstun = 1;
X	mtmp->mhp -= rnd(15);
X	if(mtmp->mhp <= 0) {
X		mondied(mtmp);
X		return(TRUE);
X	}
X	return(FALSE);
X}
X
Xboolean  
Xmdig_tunnel(mtmp)  /* FALSE: monster died */
Xregister struct monst *mtmp;
X{
X	register struct rm *here;
X	register int pile = rnd(12);
X	boolean canseeit = cansee(mtmp->mx, mtmp->my);
X	here = &levl[mtmp->mx][mtmp->my];
X
X	if(IS_ROCK(here->typ)) {
X	    /* Just ate something. */
X	    if(here->typ == STONE) here->typ = CORR;
X	    else if(IS_WALL(here->typ) &&
X			!(here->diggable & W_NONDIGGABLE)) {
X		if(flags.soundok && flags.verbose && !rn2(5))
X		       You("hear the sound of crashing rock.");
X		here->typ = DOOR;
X		here->doormask = D_NODOOR;
X	    }
X	}
X	/* Eats away door if present & closed or locked */
X	else if(IS_DOOR(here->typ) &&
X		(here->doormask & (D_LOCKED | D_CLOSED))) {
X		if(here->doormask & D_TRAPPED) {
X		    here->doormask = D_NODOOR;
X		    if(mb_trapped(mtmp)) return(FALSE);
X		} else {
X		    if(!rn2(3) && flags.verbose) /* not too often.. */
X		        You("feel an unexpected draft of air.");
X		    here->doormask = D_BROKEN;
X		}
X	    }
X	else pile = 12; /* it doesn't leave rocks if it didn't dig */
X
X	/* Left behind a pile? */
X	if(pile < 5) {
X	    if(pile == 1)
X		(void) mksobj_at(BOULDER, mtmp->mx, mtmp->my);
X	    else
X		(void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X	}
X	if(canseeit) {
X	    here->seen = TRUE;
X	    newsym(mtmp->mx,mtmp->my);
X	} else
X	    mnewsym(mtmp->mx,mtmp->my);
X	return(TRUE);
X}
X
Xint
Xdochugw(mtmp)
X	register struct monst *mtmp;
X{
X	register int x = mtmp->mx;
X	register int y = mtmp->my;
X	register int rd = dochug(mtmp);
X	register int dd;
X
X	if(!rd && !mtmp->mpeaceful &&
X			(dd = dist(mtmp->mx,mtmp->my)) < dist(x,y) &&
X			dd < 100 && !canseemon(mtmp)) {
X#ifdef NAMED_ITEMS
X	    /* Note: this assumes we only want to warn against the monster which
X	     * the weapon does extra damage to, as there is no "monster which
X	     * the weapon warns against" field.
X	     */
X		if(spec_ability(uwep,SPFX_WARN) && spec_dbon(uwep,mtmp->data,1))
X			warnlevel = 100;
X		else
X#endif
X		if (Warning && mtmp->m_lev > warnlevel)
X			warnlevel = mtmp->m_lev;
X	}
X	return(rd);
X}
X
Xboolean
Xonscary(x, y, mtmp)
Xint x, y;
Xstruct monst *mtmp;
X{
X	if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee ||
X			mtmp->data->mlet == S_HUMAN || mtmp->mpeaceful)
X		return(FALSE);
X	return(
X#ifdef ELBERETH
X		   sengr_at("Elbereth", x, y) ||
X#endif
X		    sobj_at(SCR_SCARE_MONSTER, x, y) != (struct obj *)0);
X}
X
X/* returns 1 if monster died moving, 0 otherwise */
Xint
Xdochug(mtmp)
X	register struct monst *mtmp;
X{
X	register struct permonst *mdat = mtmp->data;
X	register int tmp=0, inrange, nearby, scared, seescaryx,
X		seescaryy;
X
X/*	Pre-movement adjustments	*/
X
X	if(mtmp->cham && !rn2(6))	/* polymorph chameleons */
X	    (void) newcham(mtmp, (struct permonst *)0);
X
X	/* regenerate monsters */
X	if((!(moves%20) || regenerates(mdat)) && mtmp->mhp < mtmp->mhpmax)
X		mtmp->mhp++;
X	if(mtmp->mspec_used) mtmp->mspec_used--;
X
X	/* polymorph lycanthropes */
X	were_change(mtmp);
X
X	if(mtmp->mfroz) {
X		if (Hallucination) pmon(mtmp);
X		return(0);	/* frozen monsters don't do anything */
X	}
X
X	if(mtmp->msleep)	/* there is a chance we will wake it */
X		if(!disturb(mtmp)) return(0);
X
X	/* not frozen or sleeping: wipe out texts written in the dust */
X	wipe_engr_at(mtmp->mx, mtmp->my, 1);
X
X	/* confused monsters get unconfused with small probability */
X	if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
X
X	/* stunned monsters get un-stunned with larger probability */
X	if(mtmp->mstun && !rn2(10)) mtmp->mstun = 0;
X
X	/* some monsters teleport */
X	if(mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz) {
X		rloc(mtmp);
X		return(0);
X	}
X	if(mdat->mmove < rnd(6)) return(0);
X
X	/* fleeing monsters might regain courage */
X	if(mtmp->mflee && !mtmp->mfleetim
X	   && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0;
X
X	set_apparxy(mtmp);
X	/* Must be done after you move and before the monster does.  The
X	 * set_apparxy() call in m_move() doesn't suffice since the variables
X	 * inrange, etc... all depend on stuff set by set_apparxy().
X	 */
X
X	/* The Wizard's prime directive */
X	/* may teleport, so do it before inrange is set */
X	if(mtmp->iswiz)
X		(void) wiz_get_amulet(mtmp);
X
X	inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
X							(BOLT_LIM * BOLT_LIM));
X	nearby = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) < 3);
X	/* Note: if your image is displaced, the monster sees the Elbereth
X	 * at your displaced position, thus never attacking your displaced
X	 * position, but possibly attacking you by accident.  If you are
X	 * invisible, it sees the Elbereth at your real position, thus never
X	 * running into you by accident but possibly attacking the spot
X	 * where it guesses you are.
X	 */
X	if (Invis && !perceives(mdat)) {
X		seescaryx = mtmp->mux;
X		seescaryy = mtmp->muy;
X	} else {
X		seescaryx = u.ux;
X		seescaryy = u.uy;
X	}
X	scared = (nearby && onscary(seescaryx, seescaryy, mtmp));
X
X	if(scared && !mtmp->mflee) {
X#ifdef POLYSELF
X		if (!sticks(uasmon))
X#endif
X			unstuck(mtmp);	/* monster lets go when fleeing */
X		mtmp->mflee = 1;
X		mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
X	}
X
X#ifdef HARD	/* Demonic Blackmail!!! */
X	if(nearby && is_demon(mdat) && mtmp->mpeaceful && !mtmp->mtame) {
X		if (mtmp->mux != u.ux || mtmp->muy != u.uy) {
X			pline("%s whispers something to thin air.",
X			    cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It");
X#ifdef POLYSELF
X			if (is_demon(uasmon)) rloc(mtmp);
X			  /* "Good hunting, brother" */
X			else
X#endif
X			if (is_lord(mdat) || is_prince(mdat)) {
X			  /* use is_lord instead of is_dlord */
X			    mtmp->minvis = 0;
X			    /* Why?  For the same reason in real demon talk */
X			    pline("%s gets angry.", Xmonnam(mtmp));
X			    mtmp->mpeaceful = 0;
X			    /* since no way is an image going to pay it off */
X			}
X		} else if(demon_talk(mtmp)) return(1);	/* you paid it off */
X	}
X#endif
X
X/*	Now the actual movement phase	*/
X
X	if(!nearby || mtmp->mflee || scared ||
X	   mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) ||
X	   (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) ||
X	   (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) ||
X	   (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) {
X
X		tmp = m_move(mtmp, 0);
X		nearby = (dist(mtmp->mx, mtmp->my) < 3);	/* recalc */
X		scared = (nearby && onscary(seescaryx, seescaryy, mtmp));
X		switch (tmp) {
X
X		    case 0:	/* no movement, but it can still attack you */
X		    case 3:	/* absolutely no movement */
X				/* for pets, case 0 and 3 are equivalent */
X 			/* During hallucination, monster appearance should
X 			 * still change - even if it doesn't move.
X  			 */
X 			if(Hallucination) pmon(mtmp);
X 			break;
X 		    case 1:	/* monster moved */
X 			if(!nearby && ranged_attk(mdat)) break;
X 			else if(mdat->mmove <= 12) return(0);
X 			break;
X 		    case 2:	/* monster died */
X 			return(1);
X 		}
X
X		inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
X							(BOLT_LIM * BOLT_LIM));
X		if(scared && !mtmp->mflee) {
X			mtmp->mflee = 1;
X			mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
X		}
X	}
X
X/*	Now, attack the player if possible - one attack set per monst	*/
X
X	if(inrange && !noattacks(mdat) &&
X	   !mtmp->mpeaceful && !mtmp->mtame && u.uhp > 0 && !scared && tmp != 3)
X	    if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */
X
X#ifdef WORM
X	if(mtmp->wormno && !mtmp->mtame) wormhit(mtmp);
X#endif
X
X	/* extra movement for fast monsters */
X	if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp, 1);
X	return(tmp == 2);
X}
X
Xstatic const char practical[] = { WEAPON_SYM, GEM_SYM, FOOD_SYM, 0 };
Xstatic const char magical[] = {
X	AMULET_SYM, POTION_SYM, SCROLL_SYM, WAND_SYM, RING_SYM,
X#ifdef SPELLS
X	SPBOOK_SYM,
X#endif
X	0 };
Xstatic const char indigestion[] = { BALL_SYM, ROCK_SYM, 0 };
X
X#ifdef POLYSELF
Xstatic boolean
Xitsstuck(mtmp)
Xregister struct monst *mtmp;
X{
X	if (sticks(uasmon) && mtmp==u.ustuck && !u.uswallow) {
X		kludge("%s cannot escape from you!", Monnam(mtmp));
X		return(TRUE);
X	}
X	return(FALSE);
X}
X#endif
X
Xint
Xm_move(mtmp, after)
Xregister struct monst *mtmp;
Xregister int after;
X{
X	register struct monst *mtmp2;
X	register int nx,ny,omx,omy,appr,nearer,cnt,i,j;
X	xchar gx,gy,nix,niy,chcnt;
X	schar chi;
X	boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0;
X	boolean likerock=0, can_tunnel=0;
X	struct permonst *ptr = mtmp->data;
X	schar mmoved = 0;	/* not strictly nec.: chi >= 0 will do */
X	coord poss[9];
X	long info[9];
X	long flag;
X
X	if(mtmp->mtrapped) {
X	    i = mintrap(mtmp);
X	    if(i == 2) return(2);	/* it died */
X	    if(i == 1) return(0);	/* still in trap, so didn't move */
X	}
X	if(mtmp->mhide &&
X	   (levl[mtmp->mx][mtmp->my].omask || levl[mtmp->mx][mtmp->my].gmask) &&
X	   rn2(10))
X	    return(0);		/* do not leave hiding place */
X	if(mtmp->meating) {
X	    mtmp->meating--;
X	    return(3);			/* still eating */
X	}
X
X	set_apparxy(mtmp);
X	/* where does mtmp think you are? */
X	/* Not necessary if m_move called from here, but necessary in
X	 * other calls of m_move (i.e. leprechauns dodging)
X	 */
X	can_tunnel = tunnels(ptr) &&
X#ifdef REINCARNATION
X		     dlevel != rogue_level &&
X#endif
X		     (!needspick(ptr) || m_carrying(mtmp, PICK_AXE));
X#ifdef WORM
X	if(mtmp->wormno) goto not_special;
X#endif
X	/* my dog gets a special treatment */
X	if(mtmp->mtame) return( dog_move(mtmp, after) );
X
X	/* likewise for shopkeeper */
X	if(mtmp->isshk) {
X	    mmoved = shk_move(mtmp);
X	    if(mmoved == -2) return(2);
X	    if(mmoved >= 0) goto postmov;
X	    mmoved = 0;		/* follow player outside shop */
X	}
X
X	/* and for the guard */
X	if(mtmp->isgd) {
X	    mmoved = gd_move();
X	    goto postmov;
X	}
X
X	/* and the wiz already got special treatment */
X	if(mtmp->iswiz) {
X	    mmoved = 0;
X	    goto postmov;
X	}
X#if defined(ALTARS) && defined(THEOLOGY)
X	/* and for the priest */
X	if(mtmp->ispriest) {
X	    mmoved = pri_move(mtmp);
X	    if(mmoved == -2) return(2);
X	    if(mmoved >= 0) goto postmov;
X	    mmoved = 0;
X	}
X#endif
X#ifdef MAIL
X	if(ptr == &mons[PM_MAIL_DAEMON]) {
X	    if(flags.soundok && canseemon(mtmp))
X		pline("\"I'm late!\"");
X	    mongone(mtmp);
X	    return(2);	    
X	}
X#endif
X
X	/* teleport if that lies in our nature */
X	if(ptr == &mons[PM_TENGU] && !rn2(5)) {
X	    if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
X		rloc(mtmp);
X	    else
X		mnexto(mtmp);
X	    mmoved = 1;
X	    goto postmov;
X	}
X#ifdef WORM
Xnot_special:
X#endif
X	if(!mtmp->mflee && u.uswallow && u.ustuck != mtmp) return(1);
X	appr = 1;
X	if(mtmp->mflee) appr = -1;
X	if(mtmp->mconf || (Invis && !perceives(ptr)) ||  !mtmp->mcansee ||
X	   (mtmp->mpeaceful && !mtmp->isshk) ||	/* allow shks to follow */
X	   ((ptr->mlet == S_STALKER || ptr->mlet == S_BAT ||
X	     ptr->mlet == S_YLIGHT) && !rn2(3)))
X	    appr = 0;
X	omx = mtmp->mx;
X	omy = mtmp->my;
X	gx = mtmp->mux;
X	gy = mtmp->muy;
X	if(ptr == &mons[PM_LEPRECHAUN] && appr == 1 && mtmp->mgold > u.ugold)
X	    appr = -1;
X
X	if(can_track(ptr)) {
X	    register coord *cp;
X	    schar mroom;
X
X	    mroom = inroom(omx,omy);
X	    if(mroom < 0 || mroom != inroom(u.ux,u.uy)){
X		cp = gettrack(omx,omy);
X		if(cp){
X		    gx = cp->x;
X		    gy = cp->y;
X		}
X	    }
X	}
X
X#ifdef REINCARNATION
X	if (dlevel != rogue_level)
X#endif
X	{
X		register int pctload = (curr_mon_load(mtmp) * 100) /
X			max_mon_load(mtmp);
X
X		/* look for gold or jewels nearby */
X		likegold = (likes_gold(ptr) && pctload < 95);
X		likegems = (likes_gems(ptr) && pctload < 85);
X		likeobjs = (likes_objs(ptr) && pctload < 75);
X		likemagic = (likes_magic(ptr) && pctload < 85);
X		likerock = (throws_rocks(ptr) && pctload < 50);
X		conceals = hides_under(ptr);
X	}
X
X#define	SRCHRADIUS	25
X
X      { xchar mind = SRCHRADIUS;		/* not too far away */
X	register int dd;
X
X	/* cut down the search radius if it thinks character is closer. */
X	if(dist2(mtmp->mux, mtmp->muy, omx, omy) < SRCHRADIUS &&
X	    !mtmp->mtame && !mtmp->mpeaceful)	 mind /= 2;
X
X	if(likegold){
X	    register struct gold *gold;
X
X	    for(gold = fgold; gold; gold = gold->ngold)
X		if((dd = dist2(omx,omy,gold->gx,gold->gy)) < mind){
X		    mind = dd;
X		    gx = gold->gx;
X		    gy = gold->gy;
X		}
X	}
X	if((likegems || likeobjs || likemagic || likerock || conceals)
X	      && (!in_shop(omx, omy) || (!rn2(25) && !mtmp->isshk))) {
X	    register struct obj *otmp;
X
X	    for(otmp = fobj; otmp; otmp = otmp->nobj)
X		if((likeobjs && index(practical, otmp->olet)) ||
X		   (likemagic && index(magical, otmp->olet)) ||
X		   (likerock && otmp->otyp == BOULDER) ||
X		   (likegems && otmp->olet == GEM_SYM &&
X			otmp->otyp < LAST_GEM + 5) ||
X		   (conceals && !cansee(otmp->ox,otmp->oy)) ||
X		   (ptr == &mons[PM_GELATINOUS_CUBE] &&
X					!index(indigestion, otmp->olet))
X		  ) {
X			if(can_carry(mtmp,otmp))
X			if(ptr->mlet != S_UNICORN ||
X					objects[otmp->otyp].g_val != 0)
X			    if((dd = dist2(omx,omy,otmp->ox,otmp->oy)) < mind){
X				mind = dd;
X				gx = otmp->ox;
X				gy = otmp->oy;
X			    }
X		}
X	}
X	if(mind < SRCHRADIUS && appr == -1) {
X	    if(dist2(omx,omy,mtmp->mux,mtmp->muy) < 10) {
X		gx = mtmp->mux;
X		gy = mtmp->muy;
X	    } else
X		appr = 1;
X	}
X      }
X	nix = omx;
X	niy = omy;
X	flag = ALLOW_TRAPS;
X	if (mtmp->mpeaceful) flag |= (ALLOW_SANCT | ALLOW_SSM);
X	else flag |= ALLOW_U;
X	if (ptr->mlet == S_UNICORN) flag |= NOTONL;
X	if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK);
X	if (can_tunnel) flag |= ALLOW_DIG;
X	if (is_human(ptr)) flag |= ALLOW_SSM;
X	if (is_undead(ptr)) flag |= NOGARLIC;
X	if (throws_rocks(ptr)) flag |= ALLOW_ROCK;
X	cnt = mfndpos(mtmp, poss, info, flag);
X	chcnt = 0;
X	chi = -1;
X
X	for(i=0; i < cnt; i++) {
X	    nx = poss[i].x;
X	    ny = poss[i].y;
X
X	    for(j=0; j < MTSZ && j < cnt-1; j++)
X		if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
X		    if(rn2(4*(cnt-j))) goto nxti;
X
X	    nearer = (dist2(nx,ny,gx,gy) < dist2(nix,niy,gx,gy));
X
X	    if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
X		   	!mmoved || (!appr && !rn2(++chcnt))) {
X		nix = nx;
X		niy = ny;
X		chi = i;
X		mmoved = 1;
X	    }
X	nxti:	;
X	}
X
X	if(mmoved) {
X#ifdef POLYSELF
X	    if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
X		return(3);
X#endif
X	    if((info[chi] & ALLOW_U) || (nix == u.ux && niy == u.uy)) {
X		mtmp->mux = u.ux;
X		mtmp->muy = u.uy;
X		return(0);
X	    }
X	    /* The monster may attack another based on 1 of 2 conditions:
X	     * 1 - He may be under the "conflict" influence.
X	     * 2 - He may mistake the monster for your (displaced) image.
X	     * Pets get taken care of above and shouldn't reach this code.
X	     */
X	    if((info[chi] & ALLOW_M) ||
X		   (nix == mtmp->mux && niy == mtmp->muy)) {
X		mtmp2 = 
X		    (levl[nix][niy].mmask ? m_at(nix,niy) : (struct monst *)0);
X		if(mattackm(mtmp, mtmp2) == 1 && rn2(4) &&
X			mtmp2->mlstmv != moves && mattackm(mtmp2, mtmp) == 2)
X		    return(2);
X		return(3);
X	    }
X#ifdef WORM
X	    /* The square now has a worm segment and must keep its mmask */
X	    if (!mtmp->wormno)
X#endif
X		    levl[omx][omy].mmask = 0;
X	    levl[nix][niy].mmask = 1;
X	    mtmp->mx = nix;
X	    mtmp->my = niy;
X	    for(j = MTSZ-1; j > 0; j--)
X		mtmp->mtrack[j] = mtmp->mtrack[j-1];
X	    mtmp->mtrack[0].x = omx;
X	    mtmp->mtrack[0].y = omy;
X#ifdef WORM
X	    if(mtmp->wormno) worm_move(mtmp);
X#endif
X	} else {
X	    if(ptr->mlet == S_UNICORN && rn2(2)) {
X		rloc(mtmp);
X		return(1);
X	    }
X#ifdef WORM
X	    if(mtmp->wormno) worm_nomove(mtmp);
X#endif
X	}
Xpostmov:
X	if(mmoved == 1) {
X	    boolean canseeit = cansee(mtmp->mx, mtmp->my);
X	    boolean abstain = (mtmp->mpeaceful && !mtmp->mtame);
X
X	    if(mintrap(mtmp) == 2) return(2);	/* he died */
X
X	    /* open a door, or crash through it, if you can */
X	    if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ)
X		    && !passes_walls(ptr) /* doesn't need to open doors */
X	            && !amorphous(ptr) /* ditto */
X		    && !can_tunnel /* taken care of below */
X		  ) {
X		struct rm *here = &levl[mtmp->mx][mtmp->my];
X		boolean btrapped = (here->doormask & D_TRAPPED);
X
X		if(here->doormask & D_LOCKED && mtmp->isshk) {
X			/* can't lock out shk */
X		    if(btrapped) {
X			here->doormask = D_NODOOR;
X			if(mb_trapped(mtmp)) return(2);
X		    } else {
X			if (flags.verbose) {
X			    if (canseeit)
X			       You("see a door being unlocked and opened.");
X			    else if (flags.soundok)
X			       You("hear a door being unlocked and opened.");
X		        }
X		        here->doormask = D_ISOPEN;
X		    }
X		} else if (here->doormask == D_CLOSED && 
X					!nohands(mtmp->data)) {
X		    if(btrapped) {
X			here->doormask = D_NODOOR;
X			if(mb_trapped(mtmp)) return(2);
X		    } else {
X		        if (flags.verbose) {
X			    if (canseeit)
X			         You("see a door being opened.");
X			    else if (flags.soundok)
X			         You("hear the sound of a door opening.");
X		        }
X		        here->doormask = D_ISOPEN;
X		    }
X		} else if(here->doormask & (D_LOCKED | D_CLOSED)) {
X			/* mfndpos guarantees monster is a giant */
X		    if(btrapped) {
X			here->doormask = D_NODOOR;
X			if(mb_trapped(mtmp)) return(2);
X		    } else {
X		        if (flags.verbose) {
X			    if (canseeit)
X			        You("see a door crash open.");
X			    else if (flags.soundok)
X			        You("hear the sound of a door crashing open.");
X		        }
X		        if (here->doormask & D_LOCKED && !rn2(2))
X			        here->doormask = D_NODOOR;
X		        else here->doormask = D_BROKEN;
X		    }
X		}
X	    }
X	    /* Maybe a rock mole just ate something? */
X	    if(can_tunnel) if(!mdig_tunnel(mtmp)) return(2); /* died? */
X
X	    if(levl[mtmp->mx][mtmp->my].gmask == 1) {
X		/* Maybe a rock mole just ate some gold */
X		if(ptr == &mons[PM_ROCK_MOLE]) meatgold(mtmp);
X		if(likegold && (!abstain || !rn2(10))) mpickgold(mtmp);
X	    }
X	    if(levl[mtmp->mx][mtmp->my].omask == 1) {
X		/* Maybe a rock mole just ate some metal object */
X		if(ptr == &mons[PM_ROCK_MOLE]) meatgold(mtmp);
X		/* Maybe a cube ate just about anything */
X		if(ptr == &mons[PM_GELATINOUS_CUBE]) meatobj(mtmp);
X
X		if ((!abstain || !rn2(10)) 
X			&& (!in_shop(mtmp->mx, mtmp->my) || !rn2(25))) {
X		    if(likeobjs) mpickstuff(mtmp, practical);
X		    if(likemagic) mpickstuff(mtmp, magical);
X		    if(likerock || likegems) mpickgems(mtmp);
X		}
X	    }
X	    if(mtmp->mhide) mtmp->mundetected = (levl[mtmp->mx][mtmp->my].omask
X					|| levl[mtmp->mx][mtmp->my].gmask);
X
X	    /* set also in domove(), hack.c */
X	    if(u.uswallow && mtmp == u.ustuck) {
X		u.ux = mtmp->mx;
X		u.uy = mtmp->my;
X	        if(mtmp->mx != mtmp->mdx || mtmp->my != mtmp->mdy) {
X		    swallowed(0);
X		    mtmp->mdx = mtmp->mx;
X		    mtmp->mdy = mtmp->my;
X		}
X	    }
X	}
X	pmon(mtmp);
X	return(mmoved);
X}
X
Xvoid
Xset_apparxy(mtmp)		/* where does mtmp think you are standing? */
X	register struct monst *mtmp;
X{
X#define notseen (Invis && !perceives(mtmp->data))
X/*	add cases as required.  eg. Displacement ... */
X	register int disp = (notseen ? 1 : Displaced ? 2 : 0);
X
X/* 	without something like the following, invis. and displ. are too */
X/*	powerful. */
X	register boolean gotu =
X		(notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE);
X
X/*	Monsters which know where you are don't suddenly forget, if you
X	didn't move away. */
X	if (mtmp->mux==u.ux && mtmp->muy==u.uy) gotu = 1;
X
X/* 	your dog follows your smell */
X	if(!disp || mtmp->mtame || gotu ||
X/*	If invisible but not displaced, staying around gets you 'discovered' */
X	    (!Displaced && u.dx == 0 && u.dy == 0)) {
X		mtmp->mux = u.ux;
X		mtmp->muy = u.uy;
X	}
X	else do {
X		mtmp->mux = u.ux - disp + rn2(2*disp+1);
X		mtmp->muy = u.uy - disp + rn2(2*disp+1);
X	} while((mtmp->mux != u.ux || mtmp->muy != u.uy) &&
X	       (  (!passes_walls(mtmp->data) &&
X		      (!ACCESSIBLE(levl[mtmp->mux][mtmp->muy].typ) ||
X		       (IS_DOOR(levl[mtmp->mux][mtmp->muy].typ) &&
X			(levl[mtmp->mux][mtmp->muy].doormask & (D_LOCKED | D_CLOSED)) &&
X			!amorphous(mtmp->data)
X		      ))
X		  ) ||
X		  (disp==1 && mtmp->mux == mtmp->mx && mtmp->muy == mtmp->my)
X	       )
X	);
X}
END_OF_FILE
if test 20241 -ne `wc -c <'src/monmove.c'`; then
    echo shar: \"'src/monmove.c'\" unpacked with wrong size!
fi
# end of 'src/monmove.c'
fi
if test -f 'src/read.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/read.c'\"
else
echo shar: Extracting \"'src/read.c'\" \(30625 characters\)
sed "s/^X//" >'src/read.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)read.c	3.0	88/04/13
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include "hack.h"
X
Xboolean	known;
X
Xstatic const char readable[] = { '#', SCROLL_SYM,
X#ifdef SPELLS
X	SPBOOK_SYM,
X#endif
X	0 };
X
Xstatic void explode P((struct obj *));
Xstatic void do_class_genocide();
X
Xint
Xdoread() {
X	register struct obj *scroll;
X	register boolean confused = (Confusion != 0);
X
X	known = FALSE;
X	scroll = getobj(readable, "read");	/* "#-" added by GAN 10/22/86 */
X	if(!scroll) return(0);
X
X	/* below added to allow reading of fortune cookies */
X	if(scroll->otyp == FORTUNE_COOKIE) {
X	    if(flags.verbose)
X		You("break up the cookie and throw away the pieces.");
X	    outrumor(bcsign(scroll), TRUE);
X	    useup(scroll);
X	    return(1);
X	} else
X		if(scroll->olet != SCROLL_SYM
X#ifdef SPELLS
X		   && scroll->olet != SPBOOK_SYM
X#endif
X		  ) {
X			pline("That is a silly thing to read.");
X			return(0);
X		}
X
X	if(Blind)
X#ifdef SPELLS
X	    if (scroll->olet == SPBOOK_SYM) {
X		pline("Being blind, you cannot read the mystic runes.");
X		return(0);
X	    } else
X#endif
X	    if (!scroll->dknown) {
X		pline("Being blind, you cannot read the formula on the scroll.");
X		return(0);
X	    }
X#ifdef SPELLS
X	if(scroll->olet == SPBOOK_SYM) {
X	    if(confused) {
X		You("cannot grasp the meaning of this tome.");
X		useup(scroll);
X		return(0);
X	    } else
X		return(study_book(scroll));
X	}
X#endif
X	if(scroll->otyp != SCR_BLANK_PAPER) {
X	  if(Blind)
X	    pline("As you pronounce the formula on it, the scroll disappears.");
X	  else
X	    pline("As you read the scroll, it disappears.");
X	  if(confused) {
X	    if (Hallucination)
X		pline("Being so trippy, you screw up...");
X	    else
X		pline("Being confused, you mispronounce the magic words...");
X	  }
X	}
X	if(!seffects(scroll))  {
X		if(!objects[scroll->otyp].oc_name_known) {
X		    if(known && !confused) {
X			makeknown(scroll->otyp);
X			more_experienced(0,10);
X		    } else if(!objects[scroll->otyp].oc_uname)
X			docall(scroll);
X		}
X		if(!(scroll->otyp == SCR_BLANK_PAPER) || confused)
X			useup(scroll);
X	}
X	return(1);
X}
X
Xstatic void
Xstripspe(obj)
Xregister struct obj *obj;
X{
X	if (obj->blessed) pline(nothing_happens);
X	else {
X		if (obj->spe > 0) {
X		    obj->spe = 0;
X		    Your("%s vibrates briefly.",xname(obj));
X		} else pline(nothing_happens);
X	}
X}
X
Xstatic void
Xp_glow1(otmp)
Xregister struct obj	*otmp;
X{
X	Your("%s %s briefly.", xname(otmp),
X		Blind ? "vibrates" : "glows");
X}
X
Xstatic void
Xp_glow2(otmp,color)
Xregister struct obj	*otmp;
Xregister char *color;
X{
X	Your("%s %s%s for a moment.",
X		xname(otmp),
X		Blind ? "vibrates" : "glows ",
X		Blind ? "" : Hallucination ? hcolor() : color);
X}
X
Xint
Xseffects(sobj)
Xregister struct obj	*sobj;
X{
X	register int cval = 0;
X	register boolean confused = (Confusion != 0);
X
X	switch(sobj->otyp) {
X#ifdef MAIL
X	case SCR_MAIL:
X		known = TRUE;
X		if (sobj->spe)
X		    pline("This seems to be junk mail addressed to the finder of the Eye of Larn.");
X		/* note to the puzzled: the game Larn actually sends you junk
X		 * mail if you win!
X		 */
X		else readmail(/* scroll */);
X		break;
X#endif
X	case SCR_ENCHANT_ARMOR:
X	    {
X		register struct obj *otmp = some_armor();
X		register schar s = 0;
X		if(!otmp) {
X			strange_feeling(sobj,
X					!Blind ? "Your skin glows then fades." :
X					"Your skin feels warm for a moment.");
X			return(1);
X		}
X		if(confused) {
X			if(Blind)
X			    Your("%s feels warm for a moment.",
X				xname(otmp));
X			else
X			    Your("%s is covered by a %s %s %s!",
X				xname(otmp),
X				sobj->cursed ? "mottled" : "shimmering",
X				Hallucination ? hcolor() :
X				  sobj->cursed ? black : "gold",
X				sobj->cursed ? "glow" :
X				  (is_shield(otmp) ? "layer" : "shield"));
X			if(!(otmp->rustfree))
X				otmp->rustfree = !(sobj->cursed);
X			break;
X		}
X#ifdef TOLKIEN
X		if((otmp->spe > ((otmp->otyp == ELVEN_MITHRIL_COAT) ? 5 : 3))
X#else
X		if((otmp->spe > 3)
X#endif
X				&& rn2(otmp->spe) && !sobj->cursed) {
X		Your("%s violently %s%s for a while, then evaporates.",
X			    xname(otmp),
X			    Blind ? "vibrates" : "glows ",
X			    Blind ? "" : Hallucination ? hcolor() : silver);
X			if(is_cloak(otmp)) (void) Cloak_off();
X			if(is_boots(otmp)) (void) Boots_off();
X			if(is_helmet(otmp)) (void) Helmet_off();
X			if(is_gloves(otmp)) (void) Gloves_off();
X			if(is_shield(otmp)) (void) Shield_off();
X			if(otmp == uarm) (void) Armor_gone();
X			useup(otmp);
X			break;
X		}
X		s = sobj->blessed ? rnd(3) : sobj->cursed ? -1 : 1;
X		Your("%s %s%s for a %s.",
X			xname(otmp),
X			Blind ? "vibrates" : "glows ",
X			Blind ? "" : Hallucination ? hcolor() :
X			  sobj->cursed ? black : silver,
X			  (s*s>1) ? "while" : "moment");
X		otmp->cursed = sobj->cursed;
X		otmp->blessed = sobj->blessed;
X		otmp->spe += s;
X		adj_abon(otmp, s);
X		break;
X	    }
X	case SCR_DESTROY_ARMOR:
X	    {   register struct obj *otmp = some_armor();
X
X		if(confused) {
X			if(!otmp) {
X				strange_feeling(sobj,"Your bones itch.");
X				return(1);
X			}
X			p_glow2(otmp,purple);
X			otmp->rustfree = sobj->cursed;
X			break;
X		}
X		if(!sobj->cursed || (sobj->cursed && (!otmp || !otmp->cursed))) {
X		    if(!destroy_arm(otmp)) {
X			strange_feeling(sobj,"Your skin itches.");
X			return(1);
X		    }
X		} else {	/* armor and scroll both cursed */
X		    Your("%s vibrates", xname(otmp));
X		    otmp->spe--;
X		    make_stunned(HStun + rn1(10, 10), TRUE);
X		}
X	    }
X	    break;
X	case SCR_CONFUSE_MONSTER:
X#ifdef SPELLS
X	case SPE_CONFUSE_MONSTER:
X#endif
X		if(u.usym != S_HUMAN || sobj->cursed) {
X			if(!HConfusion) You("feel confused.");
X			make_confused(HConfusion + rnd(100),FALSE);
X		} else  if(confused) {
X		    if(!sobj->blessed) {
X			Your("%s begin to %s%s.",
X			    makeplural(body_part(HAND)),
X			    Blind ? "tingle" : "glow ",
X			    Blind ? "" : Hallucination ? hcolor() : purple);
X			make_confused(HConfusion + rnd(100),FALSE);
X		    } else {
X			pline("A %s%s surrounds your %s.",
X			    Blind ? "" : Hallucination ? hcolor() : red,
X			    Blind ? "faint buzz" : " glow",
X			    body_part(HEAD));
X			make_confused(0L,TRUE);
X		    }
X		} else {
X			Your("%s%s %s.",
X			makeplural(body_part(HAND)),
X			Blind ? "" : " begin to glow",
X			Blind ? "tingle" : Hallucination ? hcolor() : red);
X			u.umconf = 1;
X		}
X		break;
X	case SCR_SCARE_MONSTER:
X#ifdef SPELLS
X	case SPE_CAUSE_FEAR:
X#endif
X	    {	register int ct = 0;
X		register struct monst *mtmp;
X
X		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X		    if(cansee(mtmp->mx,mtmp->my)) {
X			if(confused || sobj->cursed)
X			    mtmp->mflee = mtmp->mfroz = mtmp->msleep = 0;
X			else
X			    if (! resist(mtmp, sobj->olet, 0, NOTELL))
X				mtmp->mflee = 1;
X			if(!mtmp->mtame) ct++;	/* pets don't laugh at you */
X		    }
X		if(!ct)
X		      You("hear %s in the distance.",
X			       (confused || sobj->cursed) ? "sad wailing" :
X							"maniacal laughter");
X		else
X#ifdef SPELLS
X		     if(sobj->otyp == SCR_SCARE_MONSTER)
X#endif
X			    You("hear %s close by.",
X				  (confused || sobj->cursed) ? "sad wailing" :
X						 "maniacal laughter");
X		break;
X	    }
X	case SCR_BLANK_PAPER:
X		if(confused)
X		    You("try to read the strange patterns on this scroll, but it disappears.");
X		else  {
X		    pline("This scroll seems to be blank.");
X		    known = TRUE;
X		}
X		break;
X	case SCR_REMOVE_CURSE:
X#ifdef SPELLS
X	case SPE_REMOVE_CURSE:
X#endif
X	    {	register struct obj *obj;
X		if(confused)
X		    if (Hallucination)
X			You("feel the power of the Force against you!");
X		    else
X			You("feel like you need some help.");
X		else
X		    if (Hallucination)
X			You("feel in touch with the Universal Oneness.");
X		    else
X			You("feel like someone is helping you.");
X
X		if(sobj->cursed) pline("The scroll disintegrates.");
X		else {
X		    for(obj = invent; obj ; obj = obj->nobj)
X			if(sobj->blessed || obj->owornmask ||
X			   (obj->otyp == LOADSTONE)) {
X			    if(confused) blessorcurse(obj, 2);
X			    else obj->cursed = 0;
X			}
X		}
X		if(Punished && !confused) unpunish();
X		break;
X	    }
X	case SCR_CREATE_MONSTER:
X#if defined(WIZARD) || defined(EXPLORE_MODE)
X	    if (wizard || discover)
X		known = TRUE;
X#endif /* WIZARD || EXPLORE_MODE */
X#ifdef SPELLS
X	case SPE_CREATE_MONSTER:
X#endif
X	    {	register int cnt = 1;
X
X		if(!rn2(73)) cnt += rnd(4);
X		if(confused || sobj->cursed) cnt += 12;
X		while(cnt--) {
X#if defined(WIZARD) || defined(EXPLORE_MODE)
X		    if(wizard || discover)
X			if (!create_particular())
X#endif /* WIZARD || EXPLORE_MODE */
X		    (void) makemon (confused ? &mons[PM_ACID_BLOB] :
X					(struct permonst *) 0, u.ux, u.uy);
X		}
X		break;
X	    }
X/*	    break;	/*NOTREACHED*/
X	case SCR_ENCHANT_WEAPON:
X		if(uwep && (uwep->olet == WEAPON_SYM || uwep->olet == PICK_AXE)
X							&& confused) {
X		/* olet check added 10/25/86 GAN */
X			if(Blind)
X			    Your("weapon feels warm for a moment.");
X			else
X			    Your("%s covered by a %s %s %s!",
X				aobjnam(uwep, "are"),
X				sobj->cursed ? "mottled" : "shimmering",
X				Hallucination ? hcolor() :
X				  sobj->cursed ? purple : "gold",
X				sobj->cursed ? "glow" : "shield");
X			uwep->rustfree = !(sobj->cursed);
X		} else return !chwepon(sobj, bcsign(sobj)*2+1);
X		break;
X	case SCR_TAMING:
X#ifdef SPELLS
X	case SPE_CHARM_MONSTER:
X#endif
X	    {	register int i,j;
X		register int bd = confused ? 5 : 1;
X		register struct monst *mtmp;
X
X		for(i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++)
X		if(levl[u.ux+i][u.uy+j].mmask && (mtmp = m_at(u.ux+i, u.uy+j))) {
X		    if(sobj->cursed) {
X			if(!mtmp->mtame) mtmp->mpeaceful = 0;
X		    } else {
X			if (mtmp->isshk) {
X			    if (!mtmp->mpeaceful) {
X				kludge("%s calms down.", Monnam(mtmp));
X				mtmp->mpeaceful = 1;
X			    }
X			} else if(!resist(mtmp, sobj->olet, 0, NOTELL))
X			    (void) tamedog(mtmp, (struct obj *) 0);
X		    }
X		}
X		break;
X	    }
X	case SCR_GENOCIDE:
X		You("have found a scroll of genocide!");
X#ifdef SPELLS
X	case SPE_GENOCIDE:
X#endif
X		known = TRUE;
X		if (sobj->blessed) do_class_genocide();
X		else do_genocide(!sobj->cursed | (2 * !!Confusion));
X		break;
X	case SCR_LIGHT:
X		if(!Blind) known = TRUE;
X		litroom(!confused && !sobj->cursed);
X		break;
X	case SCR_TELEPORTATION:
X		if(confused || sobj->cursed) level_tele();
X		else {
X			register int uroom = inroom(u.ux, u.uy);
X
X			if (sobj->blessed && !Teleport_control) {
X				known = TRUE;
X				pline("Do you wish to teleport? ");
X				if (yn()=='n') break;
X			}
X			tele();
X			if(uroom != inroom(u.ux, u.uy)) known = TRUE;
X			if(Teleport_control) known = TRUE;
X		}
X		break;
X	case SCR_GOLD_DETECTION:
X		if (confused || sobj->cursed) return(trap_detect(sobj));
X		else return(gold_detect(sobj));
X	case SCR_FOOD_DETECTION:
X#ifdef SPELLS
X	case SPE_DETECT_FOOD:
X#endif
X		if (food_detect(sobj))
X			return(1);	/* nothing detected */
X		break;
X	case SCR_IDENTIFY:
X		/* known = TRUE; */
X		if(confused)
X			You("identify this as an identify scroll.");
X		else
X			pline("This is an identify scroll.");
X		if (sobj->blessed || (!sobj->cursed && !rn2(5)))
X			cval = rn2(5);
X			/* Note: if rn2(5)==0, identify all items */
X		else	cval = 1;
X		useup(sobj);
X		makeknown(SCR_IDENTIFY);
X#ifdef SPELLS
X	case SPE_IDENTIFY:
X#endif
X		if(!confused)
X		    while(invent && !ggetobj("identify", identify, cval));
X		return(1);
X	case SCR_CHARGING:
X	    {	register struct obj *obj;
X		register int n;
X		if (confused) {
X		    You("feel charged up!");
X		    break;
X		}
X		known = TRUE;
X		pline("This is a charging scroll.");
X		obj = getobj("0#", "charge");
X		if (!obj) break;
X		if (obj->olet != WAND_SYM) {
X		    switch(obj->otyp) {
X		    case MAGIC_MARKER:
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    n = obj->spe;
X			    if (n < 50) obj->spe = 50;
X			    if (n >= 50 && n < 75) obj->spe = 75;
X			    if (n >= 75) obj->spe += 10;
X			    p_glow2(obj,blue);
X			} else {
X			    if (obj->spe < 50) obj->spe = 50;
X			    else obj->spe++;
X			    p_glow2(obj,white);
X			}
X			break;
X		    case LAMP:
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    n = rn2(11);
X			    if (obj->spe < n) obj->spe = n;
X			    else obj->spe += rnd(3);
X			    p_glow2(obj,blue);
X			} else {
X			    obj->spe++;
X			    p_glow1(obj);
X			}
X			break;
X		    case MAGIC_LAMP:
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    if (obj->spe == 1) pline(nothing_happens);
X			    else {
X				obj->spe = 1;
X				p_glow1(obj);
X			    }
X			} else {
X			    if (obj->spe == 1) pline(nothing_happens);
X			    else {
X				n = rn2(2);
X				if (!n) {
X				    obj->spe = 1;
X				    p_glow1(obj);
X				} else pline(nothing_happens);
X			    }
X			}
X			break;
X		    case CRYSTAL_BALL:
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    obj->spe = 6;
X			    p_glow2(obj,blue);
X			} else {
X			    if (obj->spe < 5) {
X				obj->spe++;
X				p_glow1(obj);
X			    } else pline(nothing_happens);
X			}
X			break;
X		    case BAG_OF_TRICKS:
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    if (obj->spe <= 10)
X				obj->spe += (5 + rnd(10));
X			    else obj->spe += (5 + rnd(5));
X			    p_glow2(obj,blue);
X			} else {
X			    obj->spe += rnd(5);
X			    p_glow1(obj);
X			}
X			break;
X		    default:
X			pline("The scroll %s%s, and disintegrates.",
X				Blind ? "vibrates violently" : "glows ",
X				Blind ? "" : Hallucination ? hcolor() : "dark red");
X		    } /* switch */
X		    break;
X		}
X		else {
X		    if (obj->otyp == WAN_WISHING) {
X			if (obj->recharged) { /* recharged once already? */
X			    explode(obj);
X			    break;
X			}
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    if (obj->spe != 3) {
X				obj->spe = 3;
X				p_glow2(obj,blue);
X			    } else {
X				explode(obj);
X				break;
X			    }
X			} else {
X			    if (obj->spe < 3) {
X				obj->spe++;
X				p_glow2(obj,blue);
X			    } else pline(nothing_happens);
X			}
X			obj->recharged = 1; /* another recharging disallowed */
X		    }
X		    else {
X			if (sobj->cursed) stripspe(obj);
X			else if (sobj->blessed) {
X			    if (objects[obj->otyp].bits & NODIR) {
X				n = rn1(5,11);
X				if (obj->spe < n) obj->spe = n;
X				else obj->spe++;
X			    }
X			    else {
X				n = rn1(5,4);
X				if (obj->spe < n) obj->spe = n;
X				else obj->spe++;
X			    }
X			    p_glow2(obj,blue);
X			} else {
X			    obj->spe++;
X			    p_glow1(obj);
X			}
X			break;
X		    }
X		}
X	    }
X		break;
X	case SCR_MAGIC_MAPPING:
X		known = TRUE;
X		pline("On this scroll %s a map.", confused ? "was" : "is");
X#ifdef SPELLS
X	case SPE_MAGIC_MAPPING:
X#endif
X		cval = (sobj->cursed && !confused);
X		if(cval) HConfusion = 1;	/* to screw up map */
X		do_mapping();
X		if(cval) {
X		    HConfusion = 0;		/* restore */
X		    pline("Unfortunately, it is of a very poor quality.");
X		}
X		break;
X	case SCR_AMNESIA:
X	    {	register int zx, zy;
X
X		known = TRUE;
X		for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++)
X		    if(!confused || sobj->cursed || rn2(7))
X			if(!cansee(zx,zy))
X			    levl[zx][zy].seen = levl[zx][zy].new =
X				levl[zx][zy].scrsym = 0;
X		docrt();
X		if (Hallucination) /* Ommmmmm! */
X			Your("mind releases itself from mundane concerns.");
X		else if (!strncmp(plname, "Maud", 4))
X			pline("As your mind turns inward on itself, you forget everything else.");
X		else if (flags.female)
X			pline("Who was that Maud person anyway?");
X		else
X			pline("Thinking of Maud you forget everything else.");
X#ifdef SPELLS
X		if(!sobj->blessed) losespells();
X#endif
X		break;
X	    }
X	case SCR_FIRE:
X	    {	register int num;
X		register struct monst *mtmp;
X/*
X * Note: Modifications have been made as of 3.0 to allow for some damage
X *	 under all potential cases.
X */
X		cval = bcsign(sobj);
X		useup(sobj);
X		makeknown(SCR_FIRE);
X		if(confused) {
X		    if(Fire_resistance) {
X  			shieldeff(u.ux, u.uy);
X			if(!Blind)
X			    pline("Oh, look, what a pretty fire in your %s.",
X				makeplural(body_part(HAND)));
X			else You("feal a pleasant warmth in your %s.",
X				makeplural(body_part(HAND)));
X		    } else {
X			pline("The scroll catches fire and you burn your %s.",
X				makeplural(body_part(HAND)));
X			losehp(1, "scroll of fire");
X		    }
X		    return(1);
X		}
X		pline("The scroll erupts in a tower of flame!");
X		num = rnd(6) - 3 * cval;
X		if(num <= 0 || Fire_resistance) {
X			shieldeff(u.ux, u.uy);
X			You("are uninjured.");
X		} else {
X			u.uhpmax -= num;
X			losehp(num, "scroll of fire");
X		}
X		destroy_item(SCROLL_SYM, AD_FIRE);
X#ifdef SPELLS
X		destroy_item(SPBOOK_SYM, AD_FIRE);
X#endif
X		destroy_item(POTION_SYM, AD_FIRE);
X
X		num = (2*(rn1(3, 3) + 2 * cval) + 1)/3;
X		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X		    if(dist(mtmp->mx,mtmp->my) < 3) {
X			if (resists_fire(mtmp->data)) continue;
X			if (u.uswallow) {
X			    if (mtmp != u.ustuck) continue;
X			    pline("%s gets heartburn.", Monnam(u.ustuck));
X			    num *= 2;
X			}
X			mtmp->mhp -= num;		/* No saving throw! */
X			if(resists_cold(mtmp->data))
X			    mtmp->mhp -= 3*num;
X			if(mtmp->mhp < 1) {
X			    killed(mtmp);
X			    break;		/* primitive */
X			}
X		    }
X		}
X		return(1);
X	    }
X	case SCR_PUNISHMENT:
X		known = TRUE;
X		if(confused || sobj->blessed) {
X			You("feel guilty.");
X			break;
X		}
X		punish(sobj);
X		break;
X	default:
X		impossible("What weird effect is this? (%u)", sobj->otyp);
X	}
X	return(0);
X}
X
Xstatic void
Xexplode(obj)
Xregister struct obj *obj;
X{
X    Your("%s vibrates violently, and explodes!",xname(obj));
X    bell();
X    losehp(rn2(2*(u.uhpmax+1)/3),"exploding wand");
X    useup(obj);
X}
X
Xint
Xidentify(otmp)		/* also called by newmail() */
X	register struct obj *otmp;
X{
X	makeknown(otmp->otyp);
X	otmp->known = otmp->dknown = otmp->bknown = 1;
X	prinv(otmp);
X	return(1);
X}
X
Xvoid
Xlitroom(on)
Xregister boolean on;
X{
X	register int zx,zy;
X
X	/* first produce the text (provided he is not blind) */
X	if(Blind) goto do_it;
X	if(!on) {
X		if(u.uswallow || is_maze_lev || levl[u.ux][u.uy].typ == CORR ||
X		    !levl[u.ux][u.uy].lit) {
X			pline("It seems even darker in here than before.");
X			return;
X		} else
X			pline("It suddenly becomes dark in here.");
X	} else {
X		if(u.uswallow){
X			pline("%s's stomach is lit.", Monnam(u.ustuck));
X			return;
X		}
X		if(is_maze_lev){
X			pline(nothing_happens);
X			return;
X		}
X		if(levl[u.ux][u.uy].typ == CORR) {
X		    pline("The corridor lights up around you, then fades.");
X		    return;
X		} else if(levl[u.ux][u.uy].lit) {
X		    pline("The light here seems better now.");
X		    return;
X		} else
X		    pline("The room is lit.");
X	}
X
Xdo_it:
X	if(levl[u.ux][u.uy].lit == on)
X		return;
X	if (inroom(u.ux,u.uy) < 0)
X		return;
X	getcorners(&seelx,&seehx,&seely,&seehy,&seelx2,&seehx2,&seely2,&seehy2);
X
X	for(zy = seely; zy <= seehy; zy++)
X		for(zx = seelx; zx <= seehx; zx++) {
X			levl[zx][zy].lit = on;
X			if(!Blind && dist(zx,zy) > 2)
X				if(on) prl(zx,zy); else nosee(zx,zy);
X		}
X	for(zy = seely2; zy <= seehy2; zy++)
X		for(zx = seelx2; zx <= seehx2; zx++) {
X			levl[zx][zy].lit = on;
X			if(!Blind && dist(zx,zy) > 2)
X				if(on) prl(zx,zy); else nosee(zx,zy);
X		}
X	if(!on) seehx = 0;
X}
X
Xstatic void
Xdo_class_genocide()
X{
X	register int i, j, immunecnt, gonecnt, goodcnt;
X	char buf[BUFSZ];
X
X	for(j=0; ; j++) {
X		if (j >= 5) {
X			pline(thats_enough_tries);
X			return;
X		}
X    pline("What class of monsters do you wish to genocide? [type a letter] ");
X		do {
X			getlin(buf);
X		} while (buf[0]=='\033' || strlen(buf) != 1);
X		immunecnt = gonecnt = goodcnt = 0;
X		for(i=0; mons[i].mlet; i++) {
X			if(mons[i].mlet == buf[0]) {
X				if (!(mons[i].geno & G_GENO)) immunecnt++;
X				else if(mons[i].geno & G_GENOD) gonecnt++;
X				else goodcnt++;
X			}
X		}
X		if (!goodcnt && buf[0] != S_HUMAN) {
X			if (gonecnt)
X	pline("All such monsters are already nonexistent.");
X			else if (immunecnt)
X	You("aren't permitted to genocide such monsters.");
X			else
X	pline("That symbol does not represent any monster.");
X			continue;
X		}
X		for(i=0; mons[i].mlet; i++) {
X		    if(mons[i].mlet == buf[0]) {
X			register struct monst *mtmp, *mtmp2;
X			char *n = makeplural(mons[i].mname);
X
X			if (&mons[i]==player_mon() || ((mons[i].geno & G_GENO)
X				&& !(mons[i].geno & G_GENOD))) {
X			/* This check must be first since player monsters might
X			 * have G_GENOD or !G_GENO.
X			 */
X			    pline("Wiped out all %s.", n);
X			    if (&mons[i] == player_mon()) {
X				u.uhp = -1;
X				killer = "scroll of genocide";
X#ifdef POLYSELF
X				if (u.umonnum >= 0)
X				    You("feel dead inside.");
X				else
X#endif
X				    done("died");
X			    }
X			    /* for simplicity (and fairness) let's avoid
X			     * alignment changes here...
X			     */
X#ifdef POLYSELF
X			    if (i==u.umonnum) rehumanize();
X#endif
X			    mons[i].geno |= G_GENOD;
X			    for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X				mtmp2 = mtmp->nmon;
X				if(mtmp->data == &mons[i])
X				    mondead(mtmp);
X			    }
X			} else if (mons[i].geno & G_GENOD)
X			    pline("All %s are already nonexistent.", n);
X			else
X			    You("aren't permitted to genocide %s%s.",
X				i == PM_WIZARD_OF_YENDOR ? "the " : "",
X				type_is_pname(&mons[i]) ? mons[i].mname : n);
X			}
X		}
X		return;
X	}
X}
X		
X#define REALLY 1
X#define PLAYER 2
Xvoid
Xdo_genocide(how)
Xint how;
X/* 0 = no genocide; create monsters (cursed scroll) */
X/* 1 = normal genocide */
X/* 3 = forced genocide of player */
X{
X	char buf[BUFSZ];
X	register int	i, j, killplayer = 0;
X	register struct permonst *ptr;
X	register struct monst *mtmp, *mtmp2;
X
X	if (how & PLAYER) {
X		ptr = player_mon();
X		Strcpy(buf, ptr->mname);
X		killplayer++;
X	} else {
X	    for(j = 0; ; j++) {
X		if(j >= 5) {
X		    pline(thats_enough_tries);
X		    return;
X		}
X		pline("What monster do you want to genocide? [type the name] ");
X		getlin(buf);
X
X		if(strlen(buf) && (!strncmp(buf, pl_character, PL_CSIZ))) {
X	/* Note: pl_character starts with capitals and player_mon does not */
X		    ptr = player_mon();
X		    killplayer++;
X		    goto deadmeat;
X		} else {
X		    i = name_to_mon(buf);
X		    if(i == -1 || (mons[i].geno & G_GENOD)) {
X			pline("Such creatures do not exist in this world.");
X			continue;
X		    }
X		    ptr = &mons[i];
X		    if (ptr == player_mon()) {
X			killplayer++;
X			goto deadmeat;
X		    }
X		    if (is_human(ptr)) adjalign(-sgn(u.ualigntyp));
X		    if (is_demon(ptr)) adjalign(sgn(u.ualigntyp));
X
X		    if(!(ptr->geno & G_GENO))  {
X			if(flags.soundok) {
X			    if(flags.verbose)
X			pline("A thunderous voice booms though the caverns:");
X			    pline("\"No, mortal!  That will not be done.\"");
X			}
X			continue;
X		    }
X		    break;
X		}
X	    }
X	}
Xdeadmeat:
X	if (Hallucination) {
X#ifdef POLYSELF
X	    if (u.umonnum != -1)
X		Strcpy(buf,uasmon->mname);
X	    else
X#endif
X	    {
X		Strcpy(buf, pl_character);
X		buf[0] += 'a' - 'A';
X	    }
X	} else Strcpy(buf,ptr->mname); /* make sure we have standard singular */
X	if (how & REALLY) {
X	    pline("Wiped out all %s.", makeplural(buf));
X	    if(killplayer) {
X		u.uhp = -1;
X		killer = "genocide spell";
X#ifdef POLYSELF
X	/* A polymorphed character will die as soon as he is rehumanized. */
X		if(u.umonnum >= 0)	You("feel dead inside.");
X		else
X#endif
X			done("died");
X		return;
X	    }
X#ifdef POLYSELF
X	    else if ((how & REALLY) && ptr == &mons[u.umonnum]) rehumanize();
X#endif
X	    ptr->geno |= G_GENOD;
X	    for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X		mtmp2 = mtmp->nmon;
X		if(mtmp->data == ptr)
X		    mondead(mtmp);
X	    }
X	} else {
X	    pline("Sent in some %s.", makeplural(buf));
X	    j = rnd(3) + 3;
X	    for(i=1; i<=j; i++)
X		(void) makemon(ptr, u.ux, u.uy);
X	}
X}
X
Xstatic void
Xshow_map_spot(x, y)
Xregister int x, y;
X{
X	register struct rm *lev;
X	register int num;
X
X	if((Confusion != 0) && rn2(7)) return;
X	lev = &(levl[x][y]);
X	if((num = lev->typ) == 0) return;
X
X	if(num == SCORR) {
X		lev->typ = CORR;
X		lev->scrsym = CORR_SYM;
X	/*
X	 * magic mapping shouldn't find secret doors,
X	 * especially on the stronghold level
X	 */
X	} else if(lev->seen) return;
X	if(num != ROOM)
X	{
X		lev->seen = lev->new = 1;
X		if(lev->scrsym == STONE_SYM || !lev->scrsym)
X			newsym(x, y);
X		else	on_scr(x, y);
X	}
X}
X
Xvoid
Xdo_mapping() {
X	register int zx, zy;
X
X	for(zy = 0; zy < ROWNO; zy++)
X	    for(zx = 0; zx < COLNO; zx++)
X		show_map_spot(zx, zy);
X}
X
Xvoid
Xdo_vicinity_map() {
X	register int zx, zy;
X	
X	for(zy = (u.uy-5 < 0 ? 0 : u.uy-5); 
X			zy < (u.uy+6 > ROWNO ? ROWNO : u.uy+6); zy++)
X	    for(zx = (u.ux-9 < 0 ? 0 : u.ux-9); 
X			zx < (u.ux+10 > COLNO ? COLNO : u.ux+10); zx++)
X		show_map_spot(zx, zy);
X}
X
Xint
Xdestroy_arm(atmp)
Xregister struct obj *atmp;
X{
X	register struct obj *otmp;
X
X	if((otmp = uarmc) && (!atmp || atmp == uarmc)) {
X		Your("cloak crumbles and turns to dust!");
X		(void) Cloak_off();
X		useup(otmp);
X	} else if((otmp = uarm) && (!atmp || atmp == uarm)) {
X		Your("armor turns to dust and falls to the floor!");
X		(void) Armor_gone();
X		useup(otmp);
X#ifdef SHIRT
X	} else if((otmp = uarmu) && (!atmp || atmp == uarmu)) {
X		Your("shirt crumbles into tiny threads and falls apart!");
X		useup(otmp);
X#endif
X	} else if((otmp = uarmh) && (!atmp || atmp == uarmh)) {
X		Your("helmet turns to dust and is blown away!");
X		(void) Helmet_off();
X		useup(otmp);
X	} else if((otmp = uarmg) && (!atmp || atmp == uarmg)) {
X		Your("gloves vanish!");
X		(void) Gloves_off();
X		useup(otmp);
X		selftouch("You");
X	} else if((otmp = uarmf) && (!atmp || atmp == uarmf)) {
X		Your("boots disintegrate!");
X		(void) Boots_off();
X		useup(otmp);
X	} else if((otmp =uarms) && (!atmp || atmp == uarms)) {
X		Your("shield crumbles away!");
X		(void) Shield_off();
X		useup(otmp);
X	} else 	return(0);		/* could not destroy anything */
X
X	return(1);
X}
X
X/* the detections are pulled out so they can	*/
X/* also be used in the crystal ball routine	*/
X/* returns 1 if nothing was detected		*/
X/* returns 0 if something was detected		*/
Xint
Xtrap_detect(sobj)
Xregister struct obj	*sobj;
X/* sobj is null if crystal ball, *scroll if gold detection scroll */
X{
X	register struct trap *ttmp;
X	register struct obj *obj;
X	register int door;
X	boolean found = FALSE;
X	coord cc;
X
X	for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
X		if(ttmp->tx != u.ux || ttmp->ty != u.uy)
X			goto outtrapmap;
X		else found = TRUE;
X	}
X	for(obj = fobj; obj; obj = obj->nobj) {
X		if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped)
X			if (obj->ox != u.ux || obj->oy != u.uy)
X				goto outtrapmap;
X			else found = TRUE;
X	}
X	for(door=0; door<=doorindex; door++) {
X		cc = doors[door];
X		if (levl[cc.x][cc.y].doormask & D_TRAPPED)
X			if (cc.x != u.ux || cc.x != u.uy)
X				goto outtrapmap;
X			else found = TRUE;
X	}
X	if(!found) {
X		char buf[42];
X		Sprintf(buf, "Your %s stop itching.",
X			makeplural(body_part(TOE)));
X		strange_feeling(sobj,buf);
X		return(1);
X	}
X	/* traps exist, but only under me - no separate display required */
X	Your("%s itch.", makeplural(body_part(TOE)));
X	return(0);
Xouttrapmap:
X	cls();
X#define SYMBOL (uchar)(Hallucination ? rndobjsym() : \
X		(sobj && sobj->cursed) ? GOLD_SYM : TRAP_SYM)
X#define AT Hallucination || (sobj && sobj->cursed) ? AT_OBJ : AT_MAP
X	for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
X		at(ttmp->tx, ttmp->ty, SYMBOL, AT);
X	for(obj = fobj; obj; obj = obj->nobj) {
X		if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped)
X			at(obj->ox, obj->oy, SYMBOL, AT);
X	}
X	for(door=0; door<=doorindex; door++) {
X		cc = doors[door];
X		if (levl[cc.x][cc.y].doormask & D_TRAPPED)
X			at(cc.x, cc.y, SYMBOL, AT);
X	}
X#undef SYMBOL
X#undef AT
X	prme();
X	if (sobj && sobj->cursed)
X		You("feel very greedy.");
X	else
X		You("feel entrapped.");
X	more();
X	docrt();
X	return(0);
X}
X
Xint
Xgold_detect(sobj)
Xregister struct obj	*sobj;
X{
X	register struct gold *gtmp;
X
X	if(!fgold) {
X		if(sobj)
X		    strange_feeling(sobj, "You feel materially poor.");
X		return(1);
X	} else {
X		known = TRUE;
X		for(gtmp = fgold; gtmp; gtmp = gtmp->ngold)
X			if(gtmp->gx != u.ux || gtmp->gy != u.uy)
X				goto outgoldmap;
X		/* only under me - no separate display required */
X		You("notice some gold between your %s.",
X			makeplural(body_part(FOOT)));
X		return(0);
X	outgoldmap:
X		cls();
X		for(gtmp = fgold; gtmp; gtmp = gtmp->ngold)
X		    at( gtmp->gx, gtmp->gy,
X			(uchar)(Hallucination ? rndobjsym() : GOLD_SYM),
X			AT_OBJ);
X		prme();
X		You("feel very greedy, and sense gold!");
X		more();
X		docrt();
X	}
X	return(0);
X}
X
X/* food_detection is pulled out so that it 	*/
X/* can also be used in the crystal ball routine	*/
X/* returns 1 if nothing was detected		*/
X/* returns 0 if something was detected		*/
Xint
Xfood_detect(sobj)
Xregister struct obj	*sobj;
X{
X	register boolean confused = (Confusion || (sobj && sobj->cursed));
X	register int ct = 0, ctu = 0;
X	register struct obj *obj;
X	register char foodsym = confused ? POTION_SYM : FOOD_SYM;
X
X	for(obj = fobj; obj; obj = obj->nobj)
X		if(obj->olet == foodsym) {
X			if(obj->ox == u.ux && obj->oy == u.uy) ctu++;
X			else ct++;
X		}
X	if(!ct && !ctu) {
X		if (sobj) strange_feeling(sobj,"Your nose twitches.");
X		return(1);
X	} else if(!ct) {
X		known = TRUE;
X		You("%s %s close nearby.", sobj ? "smell" : "sense",
X			confused ? "something" : "food");
X	} else {
X		known = TRUE;
X		cls();
X		for(obj = fobj; obj; obj = obj->nobj)
X		    if(obj->olet == foodsym)
X			at(obj->ox, obj->oy,
X			   (uchar)(Hallucination ? rndobjsym() : FOOD_SYM),
X			   AT_OBJ);
X		prme();
X		if (sobj) Your("nose tingles and you smell %s.",
X				confused ? "something" : "food");
X		else You("sense %s.", confused ? "something" : "food");
X		more();
X		docrt();
X	}
X	return(0);
X}
X
Xvoid
Xpunish(sobj)
Xregister struct obj	*sobj;
X{
X	You("are being punished for your misbehavior!");
X	if(Punished){
X		Your("iron ball gets heavier.");
X		uball->owt += 15 * (1 + sobj->cursed);
X		return;
X	}
X	setworn(mkobj_at(CHAIN_SYM, u.ux, u.uy), W_CHAIN);
X	setworn(mkobj_at(BALL_SYM, u.ux, u.uy), W_BALL);
X	uball->spe = 1;		/* special ball (see save) */
X}
X
Xvoid
Xunpunish()
X{	    /* remove the ball and chain */
X	freeobj(uchain);
X	unpobj(uchain);
X	free((genericptr_t) uchain);
X	setworn((struct obj *)0, W_CHAIN);
X	uball->spe = 0;
X	setworn((struct obj *)0, W_BALL);
X}
X
X/* some creatures have special data structures that only make sense in their
X * normal locations -- if the player tries to create one elsewhere, or to revive
X * one, the disoriented creature becomes a zombie
X */
Xboolean
Xcant_create(mtype)
Xint *mtype;
X{
X
X	if (*mtype==PM_GUARD || *mtype==PM_SHOPKEEPER
X#if defined(ALTARS) && defined(THEOLOGY)
X	     || *mtype==PM_TEMPLE_PRIEST || *mtype==PM_TEMPLE_PRIESTESS
X#endif
X								) {
X		*mtype = PM_HUMAN_ZOMBIE;
X		return TRUE;
X	} else
X		return FALSE;
X}
X
X#if defined(WIZARD) || defined(EXPLORE_MODE)
Xboolean
Xcreate_particular()
X{
X	char buf[BUFSZ];
X	int which;
X
X	do {
X	    pline("Create what kind of monster? [type the name] ");
X	    getlin(buf);
X	} while(strlen(buf) < 1);
X	which = name_to_mon(buf);
X	if (which != -1) {
X	    if (!(mons[which].geno & G_GENOD) && cant_create(&which) &&
X								!Blind) {
X		if (mons[which].geno & G_GENOD)
Xpline("An image of the creature forms, wavers momentarily, then fades.");
X		else
Xpline("The disoriented creature's eyes slowly glaze over.");
X	    }
X	    (void) makemon(&mons[which], u.ux, u.uy);
X	    return TRUE;
X	}
X	return FALSE;
X}
X#endif /* WIZARD || EXPLORE_MODE */
END_OF_FILE
if test 30625 -ne `wc -c <'src/read.c'`; then
    echo shar: \"'src/read.c'\" unpacked with wrong size!
fi
# end of 'src/read.c'
fi
echo shar: End of archive 14 \(of 38\).
cp /dev/null ark14isdone
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