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

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

Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 10, Issue 62
Archive-name: nethack3p9/Part17
Supersedes: NetHack3: Volume 7, Issue 56-93



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 17 (of 56)."
# Contents:  src/mhitm.c src/mon.c
# Wrapped by billr@saab on Wed Jul 11 17:11:14 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/mhitm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/mhitm.c'\"
else
echo shar: Extracting \"'src/mhitm.c'\" \(19029 characters\)
sed "s/^X//" >'src/mhitm.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)mhitm.c	3.0	89/11/27
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X#include	"hack.h"
X#ifdef NAMED_ITEMS
X#  include "artifact.h"
X#endif
X
X#ifdef OVLB
X
Xstatic boolean NEARDATA vis, NEARDATA far_noise;
Xstatic long NEARDATA noisetime;
Xstatic struct obj NEARDATA *otmp;
X
Xstatic void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
Xstatic int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
Xstatic int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
Xstatic void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
Xstatic void FDECL(noises,(struct monst *,struct attack *));
Xstatic void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
X
Xstatic void
Xnoises(magr, mattk)
X	register struct monst *magr;
X	register struct	attack *mattk;
X{
X	boolean farq = (dist(magr->mx, magr->my) > 15);
X
X	if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
X		far_noise = farq;
X		noisetime = moves;
X		You("hear %s%s.",
X			(mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
X			farq ? " in the distance" : "");
X	}
X}
X
Xstatic
Xvoid
Xmissmm(magr, mdef, mattk)
X	register struct monst *magr, *mdef;
X	struct attack *mattk;
X{
X	char buf[BUFSZ];
X
X	if(vis) {
X		if(mdef->mimic) seemimic(mdef);
X		if(magr->mimic) seemimic(magr);
X		if (could_seduce(magr,mdef,mattk) && !magr->mcan)
X			Sprintf(buf, "%s pretends to be friendly to",
X								Monnam(magr));
X		else
X			Sprintf(buf,"%s misses", Monnam(magr));
X		pline("%s %s.", buf, mon_nam(mdef));
X	} else  noises(magr, mattk);
X}
X
X/*
X * fightm returns 3 if no attack, otherwise the results of mattackm
X */
Xint
Xfightm(mtmp)		/* have monsters fight each other */
X	register struct monst *mtmp;
X{
Xregister struct monst *mon, *nmon;
X#ifdef LINT
X	nmon = 0;
X#endif
X	for(mon = fmon; mon; mon = nmon) {
X	    nmon = mon->nmon;
X	    if(nmon == mtmp) nmon = mtmp->nmon;
X	    if(mon != mtmp) {
X		if(dist2(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3)
X		/* note: grid bug check needed here as well as in mattackm */
X		    if(mtmp->data != &mons[PM_GRID_BUG] || mtmp->mx==mon->mx
X				|| mtmp->my==mon->my)
X			return(mattackm(mtmp,mon));
X	    }
X	}
X	return(3);
X}
X
X/*
X * mattackm returns -1 (magr died), 0 (miss), 1 (mdef hit), or 2 (mdef killed)
X *
X * Each successive attack has a lower probability of hitting.  Some
X * rely on the success of previous attacks.
X *
X * In the case of exploding monsters, the monster dies as well.
X */
Xint
Xmattackm(magr, mdef)
X	register struct monst *magr,*mdef;
X{
X	int	i, tmp, nsum, sum[NATTK];
X	struct	attack	*mattk;
X	struct	permonst *pa, *pd;
X	schar	strike;
X
X	if(!magr || !mdef) return(0);		/* mike@genat */
X	pa = magr->data; pd = mdef->data;
X	if(!magr->mcanmove) return(0);		/* riv05!a3 */
X	if(pa==&mons[PM_GRID_BUG] && magr->mx != mdef->mx
X						&& magr->my != mdef->my)
X		return(0);
X
X/*	Calculate the armour class differential.	*/
X
X	tmp = pd->ac + magr->m_lev;
X	if(mdef->mconf || !mdef->mcanmove || mdef->msleep){
X		tmp += 4;
X		if(mdef->msleep) mdef->msleep = 0;
X	}
X
X	if (is_elf(magr->data) && is_orc(mdef->data)) tmp++;
X
X/*	Set up visibility of action			*/
X	vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
X
X/*	Set flag indicating monster has moved this turn.  Necessary since a
X *	monster might get an attack out of sequence (i.e. before its move) in
X *	some cases, in which case this still counts as its move for the round
X *	and it shouldn't move again.
X */
X	magr->mlstmv = moves;
X
X/*	Now perform all attacks for the monster.	*/
X
X	for(i=0; i<NATTK; i++) sum[i] = 0;
X	for(i = nsum = 0; i < NATTK; nsum |= sum[i++]) {
X	    mattk = &(pa->mattk[i]);
X	    otmp = (struct obj *)0;
X	    switch(mattk->aatyp) {
X
X		case AT_WEAP:		/* "hand to hand" attacks */
X			otmp = select_hwep(magr);
X			if(otmp) {
X				if (vis) mswingsm(magr, mdef, otmp);
X				tmp += hitval(otmp, pd);
X			}
X		case AT_CLAW:
X		case AT_KICK:
X		case AT_BITE:
X		case AT_STNG:
X		case AT_TUCH:
X		case AT_BUTT:
X			if((strike = (tmp > rnd(20+i)))) {
X				sum[i] = hitmm(magr, mdef, mattk);
X				if(sum[i] == -1) return(-1);
X			} else	missmm(magr, mdef, mattk);
X			break;
X
X		case AT_HUGS:	/* automatic if prev two attacks succeed */
X			strike = 1;
X			if(sum[i-1] && sum[i-2]) {
X			    sum[i] = hitmm(magr, mdef, mattk);
X			    if(sum[i] == -1) return(-1);
X			}
X			break;
X
X		case AT_GAZE:	/* will not wake up a sleeper */
X			strike = 0;
X			sum[i] = gazemm(magr, mdef, mattk);
X			break;
X
X		case AT_EXPL:	/* automatic hit if next to */
X			strike = -1;
X			sum[i] = explmm(magr, mdef, mattk);
X			break;
X
X		case AT_ENGL:
X			if((strike = (tmp > rnd(20+i))))
X				sum[i]= gulpmm(magr, mdef, mattk);
X			else	missmm(magr, mdef, mattk);
X			break;
X
X		default:		/* no attack */
X			strike = 0;
X			break;
X	    }
X	    if(sum[i] == 2) return(2);  	/* defender dead */
X	    if(strike)	    mdef->msleep = 0;
X	    if(strike == -1)   return(-1);		/* attacker dead */
X	    nsum |= sum[i];
X	}
X	return(nsum);
X}
X
X/* hitmm returns 0 (miss), 1 (hit), 2 (kill), or -1 (magr died) */
Xstatic int
Xhitmm(magr, mdef, mattk)
X	register struct monst *magr,*mdef;
X	struct	attack *mattk;
X{
X	if(vis){
X		int compat;
X		char buf[BUFSZ];
X
X		if(mdef->mimic) seemimic(mdef);
X		if(magr->mimic) seemimic(magr);
X		if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
X			Sprintf(buf, "%s %s", Monnam(magr),
X				mdef->mcansee ? "smiles at" : "talks to");
X			pline("%s %s %s.", buf, mon_nam(mdef),
X				compat == 2 ?
X					"engagingly" : "seductively");
X		} else {
X		    switch (mattk->aatyp) {
X			case AT_BITE:
X				Sprintf(buf,"%s bites", Monnam(magr));
X				break;
X			case AT_STNG:
X				Sprintf(buf,"%s stings", Monnam(magr));
X				break;
X			case AT_BUTT:
X				Sprintf(buf,"%s butts", Monnam(magr));
X				break;
X			case AT_TUCH:
X				Sprintf(buf,"%s touches", Monnam(magr));
X				break;
X			case AT_HUGS:
X				if (magr != u.ustuck) {
X				    Sprintf(buf,"%s squeezes", Monnam(magr));
X				    break;
X				}
X			default:
X				Sprintf(buf,"%s hits", Monnam(magr));
X		    }
X		}
X		pline("%s %s.", buf, mon_nam(mdef));
X	} else  noises(magr, mattk);
X	return(mdamagem(magr, mdef, mattk));
X}
X
Xstatic int
Xgazemm(magr, mdef, mattk)
X	register struct monst *magr, *mdef;
X	struct attack *mattk;
X{
X	char buf[BUFSZ];
X
X	if(vis) {
X		Sprintf(buf,"%s gazes at", Monnam(magr));
X		pline("%s %s.", buf, mon_nam(mdef));
X	}
X
X	if (!mdef->mcansee || mdef->msleep) {
X
X	    if(vis) pline("but nothing happens.");
X	    return(0);
X	}
X
X	return(mdamagem(magr, mdef, mattk));
X}
X
Xstatic int
Xgulpmm(magr, mdef, mattk)
X	register struct monst *magr, *mdef;
X	register struct	attack *mattk;
X{
X	int	mx, my, tmp;
X	char buf[BUFSZ];
X
X	if(mdef->data->msize >= MZ_HUGE) return 0;
X
X	if(vis) {
X		Sprintf(buf,"%s swallows", Monnam(magr));
X		pline("%s %s.", buf, mon_nam(mdef));
X	}
X
X	mx = magr->mx;
X	my = magr->my;
X	 /* move over top of the defender */
X	if(cansee(mdef->mx, mdef->my))	unpmon(mdef);
X	if(cansee(magr->mx, magr->my))	unpmon(magr);
X	magr->mx = mdef->mx;
X	magr->my = mdef->my;
X	if(cansee(magr->mx, magr->my))	pmon(magr);
X	if((tmp = mdamagem(magr, mdef, mattk)) == 2) {
X		remove_monster(mx, my);
X		place_monster(magr, magr->mx, magr->my);
X		/* if mdamagem left a corpse it erased magr's symbol */
X		unpmon(magr);
X		pmon(magr);
X		return(2);	/* defender died */
X	} else {		/* defender survived */
X		if(cansee(mdef->mx, mdef->my))
X			pline("%s is regurgitated!", Monnam(mdef));
X		if(cansee(magr->mx, magr->my))	unpmon(magr);
X		magr->mx = mx;
X		magr->my = my;
X		/* move off of defender */
X		if(cansee(magr->mx, magr->my))	pmon(magr);
X		if(cansee(mdef->mx, mdef->my))	pmon(mdef);
X		nscr();
X		return(tmp);
X	}
X}
X
Xstatic int
Xexplmm(magr, mdef, mattk)
X	register struct monst *magr, *mdef;
X	register struct	attack *mattk;
X{
X
X	if(cansee(magr->mx, magr->my))
X		pline("%s explodes!", Monnam(magr));
X	else	noises(magr, mattk);
X
X	(void) mdamagem(magr, mdef, mattk);
X
X	if(magr->mtame)
X		You("have a sad feeling for a moment, then it passes.");
X	mondead(magr);
X	return(2);
X}
X
Xstatic const char psf[] =
X	"have a peculiarly sad feeling for a moment, then it passes.";
X
Xstatic int
Xmdamagem(magr, mdef, mattk)
X	register struct monst	*magr, *mdef;
X	register struct attack	*mattk;
X{
X	struct	permonst *ptr, *pd = mdef->data;
X	int	tmp = d((int)mattk->damn,(int)mattk->damd);
X	char buf[BUFSZ];
X
X	if(mdef->data == &mons[PM_COCKATRICE] && !resists_ston(magr->data) &&
X	   (mattk->aatyp != AT_WEAP || !otmp) &&
X	   (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) &&
X	   (!is_mercenary(magr->data) || !m_carrying(magr, LEATHER_GLOVES))) {
X	   /* Note: other monsters may carry gloves, only soldiers have them */
X	   /* as their "armor" and can be said to wear them */
X		if (vis) pline("%s turns to stone!", Monnam(magr));
X		else if (magr->mtame) You(psf);
X		monstone(magr);
X		return -1;
X	}
X
X	switch(mattk->adtyp) {
X	    case AD_DGST:
X		if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
X		tmp = mdef->mhp;
X		break;
X	    case AD_STUN:
X		if (magr->mcan) break;
X		if(vis) pline("%s staggers for a moment.", Monnam(mdef));
X		mdef->mstun = 1;
X		/* fall through */
X	    case AD_WERE:
X	    case AD_HEAL:
X	    case AD_LEGS:
X	    case AD_PHYS:
X		if (mattk->aatyp == AT_KICK && thick_skinned(mdef->data))
X			tmp = 0;
X		else if(mattk->aatyp == AT_WEAP) {
X		    if(otmp) {
X			tmp += dmgval(otmp, pd);
X#ifdef NAMED_ITEMS
X			if(spec_ability(otmp, SPFX_DRLI) &&
X			    !resists_drli(mdef->data)) {
X			    int dam = rnd(8);
X
X			    tmp += dam;
X			    if(vis)
X				pline("The %s blade drains the life from %s!",
X					Hallucination ? hcolor() : black,
X					mon_nam(mdef));
X			    mdef->mhpmax -= dam;
X			    if (mdef->m_lev == 0)
X				tmp = mdef->mhp;
X			    else mdef->m_lev--;
X			}
X#endif
X			mrustm(magr, mdef, otmp);
X		    }
X		}
X		break;
X	    case AD_FIRE:
X		if (magr->mcan) {
X		    tmp = 0;
X		    break;
X		}
X		if(vis) pline("%s is on fire!", Monnam(mdef));
X		tmp += destroy_mitem(mdef, SCROLL_SYM, AD_FIRE);
X#ifdef SPELLS
X		tmp += destroy_mitem(mdef, SPBOOK_SYM, AD_FIRE);
X#endif
X		if(resists_fire(pd)) {
X		    pline("The fire doesn't seem to burn %s!", mon_nam(mdef));
X		    shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X		    golemeffects(mdef, AD_FIRE, tmp);
X#endif /* GOLEMS */
X		    tmp = 0;
X		}
X		/* only potions damage resistant players in destroy_item */
X		tmp += destroy_mitem(mdef, POTION_SYM, AD_FIRE);
X		break;
X	    case AD_COLD:
X		if (magr->mcan) {
X		    tmp = 0;
X		    break;
X		}
X		if(vis) pline("%s is covered in frost!", Monnam(mdef));
X		if(resists_cold(pd)) {
X		    pline("The frost doesn't seem to chill %s!",
X			mon_nam(mdef));
X		    shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X		    golemeffects(mdef, AD_COLD, tmp);
X#endif /* GOLEMS */
X		    tmp = 0;
X		}
X		tmp += destroy_mitem(mdef, POTION_SYM, AD_COLD);
X		break;
X	    case AD_ELEC:
X		if (magr->mcan) {
X		    tmp = 0;
X		    break;
X		}
X		if(vis) pline("%s gets zapped!", Monnam(mdef));
X		tmp += destroy_mitem(mdef, WAND_SYM, AD_ELEC);
X		if(resists_elec(pd)) {
X		    pline("The zap doesn't shock %s!", mon_nam(mdef));
X		    shieldeff(mdef->mx, mdef->my);
X#ifdef GOLEMS
X		    golemeffects(mdef, AD_ELEC, tmp);
X#endif /* GOLEMS */
X		    tmp = 0;
X		}
X		/* only rings damage resistant players in destroy_item */
X		tmp += destroy_mitem(mdef, RING_SYM, AD_ELEC);
X		break;
X	    case AD_ACID:
X		if (magr->mcan) {
X		    tmp = 0;
X		    break;
X		}
X		if(resists_acid(pd)) {
X		    pline("%s is covered in acid, but it seems harmless.",
X			Monnam(mdef));
X		    tmp = 0;
X		} else {
X		    pline("%s is covered in acid!", Monnam(mdef));
X		    pline("It burns %s!", mon_nam(mdef));
X		}
X		break;
X	    case AD_RUST:
X#ifdef GOLEMS
X		if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) {
X			if (vis) pline("%s falls to pieces!", Monnam(mdef));
X			else if(mdef->mtame)
X			     pline("May %s rust in peace.", mon_nam(mdef));
X			mondied(mdef);
X			magr->mhpmax = magr->mhpmax +
X                                            (1 + rn2((int)mdef->m_lev+1));
X			ptr = grow_up(magr);
X			if(!ptr) return(-1);
X			return(2);
X		}
X#endif /* GOLEMS */
X		tmp = 0;
X		break;
X	    case AD_DCAY:
X#ifdef GOLEMS
X		if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] ||
X		    pd == &mons[PM_LEATHER_GOLEM])) {
X			if (vis) pline("%s falls to pieces!", Monnam(mdef));
X			else if(mdef->mtame)
X			     pline("May %s rot in peace.", mon_nam(mdef));
X			mondied(mdef);
X			magr->mhpmax = magr->mhpmax +
X			                       (1 + rn2((int)mdef->m_lev+1));
X			ptr = grow_up(magr);
X			if(!ptr) return(-1);
X			return(2);
X		}
X#endif /* GOLEMS */
X		tmp = 0;
X		break;
X	    case AD_STON:
X		if(!resists_ston(pd)) {
X			magr->mhpmax = magr->mhpmax +
X                                              (1 + rn2((int)mdef->m_lev+1));
X			if(vis) pline("%s turns to stone!", Monnam(mdef));
X			else if(mdef->mtame) You(psf);
X			monstone(mdef);
X			ptr = grow_up(magr);
X			if(!ptr) return(-1);
X			return(2);
X		}
X		tmp = 0;	/* no damage if this fails */
X		break;
X	    case AD_TLPT:
X		if(!magr->mcan && tmp < mdef->mhp) {
X		    rloc(mdef);
X		    if(vis && !cansee(mdef->mx, mdef->my))
X			pline("%s suddenly disappears!", Monnam(mdef));
X		}
X		break;
X	    case AD_SLEE:
X		if(!resists_sleep(pd) && !magr->mcan && !mdef->msleep
X							&& mdef->mcanmove) {
X		    if (vis) {
X			Strcpy(buf, Monnam(mdef));
X			pline("%s is put to sleep by %s.", buf, mon_nam(magr));
X		    }
X		    mdef->mcanmove = 0;
X		    mdef->mfrozen = rnd(10);
X		}
X		break;
X	    case AD_PLYS:
X		if(!magr->mcan && mdef->mcanmove) {
X		    if (vis) {
X			Strcpy(buf, Monnam(mdef));
X			pline("%s is frozen by %s.", buf, mon_nam(magr));
X		    }
X		    mdef->mcanmove = 0;
X		    mdef->mfrozen = rnd(10);
X		}
X		break;
X	    case AD_SLOW:
X		if(!magr->mcan && vis && mdef->mspeed != MSLOW) {
X		    if (vis) pline("%s slows down.", Monnam(mdef));
X		    if (mdef->mspeed == MFAST) mdef->mspeed = 0;
X		    else mdef->mspeed = MSLOW;
X		}
X		break;
X	    case AD_CONF:
X		/* Since confusing another monster doesn't have a real time
X		 * limit, setting spec_used would not really be right (though
X		 * we still should check for it).
X		 */
X		if(!magr->mcan && vis && !mdef->mconf && !magr->mspec_used) {
X		    pline("%s looks confused.", Monnam(mdef));
X		    mdef->mconf = 1;
X		}
X		break;
X	    case AD_BLND:
X		if(!magr->mcan && haseyes(pd)) {
X
X		    if(vis && mdef->mcansee)
X			pline("%s is blinded.", Monnam(mdef));
X		    {
X			register unsigned rnd_tmp;
X			rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
X			mdef->mcansee = 0;
X			if((mdef->mblinded + rnd_tmp) > 127)
X				mdef->mblinded = 127;
X			else mdef->mblinded += rnd_tmp;
X		    }
X		}
X		tmp = 0;
X		break;
X	    case AD_CURS:
X		if(!night() && (magr->data == &mons[PM_GREMLIN])) break;
X		if(!magr->mcan && !rn2(10)) {
X		    if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
X			were_change(mdef);
X#ifdef GOLEMS
X		    if (mdef->data == &mons[PM_CLAY_GOLEM]) {
X			    if (vis) {
X				pline("Some writing vanishes from %s's head!",
X				    mon_nam(mdef));
X				pline("%s dies!", Monnam(mdef));
X			    }
X			    else if (mdef->mtame)
X	You("have a strangely sad feeling for a moment, then it passes.");
X			    mondied(mdef);
X			    magr->mhpmax = magr->mhpmax +
X					          (1 + rn2((int)mdef->m_lev+1));
X			    ptr = grow_up(magr);
X			    if(!ptr) return(-1);
X			    return(2);
X		      }
X#endif /* GOLEMS */
X		    mdef->mcan = 1;
X		    if (flags.soundok) {
X			    if (!vis) You("hear laughter.");
X			    else pline("%s chuckles.", Monnam(magr));
X		    }
X		}
X		break;
X	    case AD_SGLD:
X		tmp = 0;
X		if (magr->mcan || !mdef->mgold) break;
X		/* technically incorrect; no check for stealing gold from
X		 * between mdef's feet...
X		 */
X		magr->mgold += mdef->mgold;
X		mdef->mgold = 0;
X		if (vis) {
X			Strcpy(buf, Monnam(magr));
X			pline("%s steals some gold from %s.", buf,
X								mon_nam(mdef));
X		}
X		break;
X	    case AD_DRLI:
X		if(rn2(2) && !resists_drli(mdef->data)) {
X			tmp = d(2,6);
X			if (vis)
X			    kludge("%s suddenly seems weaker!", Monnam(mdef));
X			mdef->mhpmax -= tmp;
X			if (mdef->m_lev == 0)
X				tmp = mdef->mhp;
X			else mdef->m_lev--;
X			/* Automatic kill if drained past level 0 */
X		}
X		break;
X#ifdef SEDUCE
X	    case AD_SSEX:
X#endif
X	    case AD_SITM:	/* for now these are the same */
X	    case AD_SEDU:
X		if (!magr->mcan && mdef->minvent) {
X		   	otmp = mdef->minvent;
X			mdef->minvent = otmp->nobj;
X			otmp->nobj = magr->minvent;
X			magr->minvent = otmp;
X			if (vis) {
X				Strcpy(buf, Monnam(magr));
X				pline("%s steals %s from %s!", buf,
X						doname(otmp), mon_nam(mdef));
X			}
X		}
X		tmp = 0;
X		break;
X	    case AD_DRST:
X	    case AD_DRDX:
X	    case AD_DRCO:
X		if (!magr->mcan && !rn2(8)) {
X		    if (vis)
X			pline("%s's %s was poisoned!", Monnam(magr),
X				mattk->aatyp==AT_BITE ? "bite" : "sting");
X		    if (resists_poison(mdef->data)) {
X			if (vis)
X			    pline("The poison doesn't seem to affect %s.",
X				mon_nam(mdef));
X		    } else {
X			if (rn2(10)) tmp += rn1(10,6);
X			else {
X			    if (vis) pline("The poison was deadly...");
X			    tmp = mdef->mhp;
X			}
X		    }
X		}
X		break;
X	    case AD_STCK:
X	    case AD_WRAP: /* monsters cannot grab one another, it's too hard */
X		break;
X	    default:	tmp = 0;
X			break;
X	}
X	if(!tmp) return(1);
X
X	if((mdef->mhp -= tmp) < 1) {
X	    magr->mhpmax = magr->mhpmax + (1 + rn2((int)mdef->m_lev+1));
X	    if(vis)
X		pline("%s is %s!", Monnam(mdef),
X			(is_demon(mdef->data) || is_undead(mdef->data)) ?
X			 "destroyed" : "killed");
X	    else if(mdef->mtame)
X		You("have a sad feeling for a moment, then it passes.");
X	    mondied(mdef);
X	    ptr = grow_up(magr);
X	    if(!ptr) return(-1);
X	    return(2);
X	}
X	return(1);
X}
X
X#endif /* OVLB */
X#ifdef OVL0
X
Xint
Xnoattacks(ptr)			/* returns 1 if monster doesn't attack */
X	struct	permonst *ptr;
X{
X	int i;
X
X	for(i = 0; i < NATTK; i++)
X		if(ptr->mattk[i].aatyp) return(0);
X
X	return(1);
X}
X
X#endif /* OVL0 */
X#ifdef OVLB
X
Xstatic void
Xmrustm(magr, mdef, obj)
Xregister struct monst *magr, *mdef;
Xregister struct obj *obj;
X{
X	if (!magr || !mdef || !obj) return; /* just in case */
X	if (mdef->data == &mons[PM_RUST_MONSTER] &&
X				objects[obj->otyp].oc_material == METAL &&
X				!obj->rustfree && obj->spe > -2) {
X		if(obj->blessed && rn2(3)) {
X		    if (cansee(mdef->mx, mdef->my))
X			pline("%s's weapon is not affected.", Monnam(magr));
X		} else {
X		    if (cansee(mdef->mx, mdef->my))
X			pline("%s's %s!", Monnam(magr),
X						aobjnam(obj, "corrode"));
X		    obj->spe--;
X		}
X	}
X}
X
Xstatic void
Xmswingsm(magr, mdef, otemp)
Xregister struct monst *magr, *mdef;
Xregister struct obj *otemp;
X{
X	char buf[BUFSZ];
X	Strcpy(buf, mon_nam(mdef));
X	if (!flags.verbose || Blind || otemp->olet != WEAPON_SYM) return;
X	pline("%s %s %s %s at %s.", Monnam(magr),
X	      ((otemp->otyp >= SPEAR &&
X	        otemp->otyp <= LANCE) ||
X	       (otemp->otyp >= PARTISAN &&
X	        otemp->otyp <= SPETUM) ||
X	       otemp->otyp == TRIDENT) ? "thrusts" : "swings",
X	      is_female(magr) ? "her" :
X	      is_human(magr->data) ? "his" : "its",
X	      xname(otemp), buf);
X}
X
X#endif /* OVLB */
END_OF_FILE
if test 19029 -ne `wc -c <'src/mhitm.c'`; then
    echo shar: \"'src/mhitm.c'\" unpacked with wrong size!
fi
# end of 'src/mhitm.c'
fi
if test -f 'src/mon.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/mon.c'\"
else
echo shar: Extracting \"'src/mon.c'\" \(36529 characters\)
sed "s/^X//" >'src/mon.c' <<'END_OF_FILE'
X/*	SCCS Id: @(#)mon.c	3.0	89/11/22
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed.  See license for details. */
X
X/* Aztec C on amiga doesn't recognize defined() at this point!
X   Neither does the Mac Lightspeed C v.3  compiler. If you're using
X   precompiled headers, you don't want this either */
X#ifndef AZTEC_C
X#ifndef THINK_C
X#if defined(MICROPORT_BUG) || (!defined(LINT) && !defined(__STDC__))
X#define MKROOM_H
X#endif /* Avoid the microport bug */
X#endif
X#endif
X
X#include "hack.h"
X#include "mfndpos.h"
X
X#ifdef WORM
X#  include "wseg.h"
X#endif
X
X#ifdef HARD
XSTATIC_DCL boolean FDECL(restrap,(struct monst *));
X#endif
X#ifdef INFERNO
X#  include <ctype.h>
X#endif
X
XSTATIC_DCL void NDECL(dmonsfree);
X
X#ifdef OVL1
Xlong lastwarntime;
Xint lastwarnlev;
Xconst char *warnings[] = {
X	"white", "pink", "red", "ruby", "purple", "black" };
X
X#endif /* OVL1 */
X
X#ifdef OVLB
Xstatic struct obj *FDECL(make_corpse,(struct monst *));
Xstatic void FDECL(m_detach,(struct monst *));
X
Xstruct monst *fdmon;  /* chain of dead monsters, need not be saved */
X		      /* otherwise used only in priest.c */
X
X/* Creates a monster corpse, a "special" corpse, or nothing if it doesn't
X * leave corpses.  Monsters which leave "special" corpses should have
X * G_NOCORPSE set in order to prevent wishing for one, finding tins of one,
X * etc....
X */
Xstatic struct obj *
Xmake_corpse(mtmp)
Xregister struct monst *mtmp;
X{
X	register struct permonst *mdat = mtmp->data;
X#ifdef GOLEMS
X	int pieces;
X#endif
X	struct obj *obj = 0;
X	int x = mtmp->mx, y = mtmp->my;
X
X	switch(monsndx(mdat)) {
X	    case PM_WHITE_UNICORN:
X	    case PM_GRAY_UNICORN:
X	    case PM_BLACK_UNICORN:
X		(void) mksobj_at(UNICORN_HORN, x, y);
X		goto default_1;
X#ifdef WORM
X	    case PM_LONG_WORM:
X		(void) mksobj_at(WORM_TOOTH, x, y);
X		goto default_1;
X#endif
X	    case PM_KOBOLD_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_KOBOLD_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_KOBOLD;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_GNOME_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_GNOME_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_GNOME;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_ORC_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_ORC_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_ORC;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_ELF_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_ELF_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_ELF;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_HUMAN_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_HUMAN_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_HUMAN;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_GIANT_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_GIANT_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_GIANT;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X	    case PM_ETTIN_MUMMY:
X		obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X	    case PM_ETTIN_ZOMBIE:
X		obj = mksobj_at(CORPSE, x, y);
X		obj->corpsenm = PM_ETTIN;
X		obj->age -= 50;			/* this is an *OLD* corpse */
X		break;
X#ifdef GOLEMS
X	    case PM_IRON_GOLEM:
X		pieces = d(2,6);
X		while (pieces--)
X			obj = mksobj_at(IRON_CHAIN, x, y);
X		break;
X	    case PM_CLAY_GOLEM:
X		obj = mksobj_at(ROCK, x, y);
X		obj->quan = rn2(20) + 100;
X		obj->owt = weight(obj);
X		break;
X	    case PM_STONE_GOLEM:
X		obj = mkcorpstat(STATUE, mdat, x, y);
X		break;
X	    case PM_WOOD_GOLEM:
X		pieces = d(2,4);
X		while(pieces--)
X			obj = mksobj_at(QUARTERSTAFF, x, y);
X		break;
X	    case PM_LEATHER_GOLEM:
X		pieces = d(2,4);
X		while(pieces--)
X			obj = mksobj_at(LEATHER_ARMOR, x, y);
X		break;
X#endif
X	    default_1:
X	    default:
X		if (mdat->geno & G_NOCORPSE)
X			return (struct obj *)0;
X		else obj = mkcorpstat(CORPSE, mdat, x, y);
X		break;
X	}
X	/* All special cases should precede the G_NOCORPSE check */
X
X	/* Note: oname() cannot be used generically for non-inventory objects
X	 * unless you fix the link from the previous object in the chains.
X	 * (Here we know it's the first one, so there was no link.)
X	 */
X	if (mtmp->mnamelth) {
X		obj = oname(obj, NAME(mtmp), 0);
X		fobj = obj;
X		level.objects[x][y] = obj;
X	}
X	stackobj(fobj);
X	newsym(x, y);
X	return obj;
X}
X
X#endif /* OVLB */
X#ifdef OVL2
X
XSTATIC_OVL void
Xdmonsfree(){
Xregister struct monst *mtmp;
X	while(mtmp = fdmon){
X		fdmon = mtmp->nmon;
X		free((genericptr_t) mtmp);
X	}
X}
X
X#endif /* OVL2 */
X#ifdef OVL1
X
Xvoid
Xmovemon()
X{
X	register struct monst *mtmp;
X
X	warnlevel = 0;
X
X	while(1) {
X		/*  Find a monster that we have not treated yet.
X		 *  Note that mtmp or mtmp->nmon might get killed
X		 *  while mtmp moves, so we cannot just walk down the
X		 *  chain (even new monsters might get created!)
X		 */
X		/* Do tame monsters first.  Necessary so that when the tame
X		 * monster attacks something, the something gets a chance to
X		 * attack the tame monster back (which it's permitted to do
X		 * only if it hasn't made its move yet).
X		 */
X		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X			if(mtmp->mlstmv < moves && mtmp->mtame) goto next_mon;
X		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X			if(mtmp->mlstmv < moves && !mtmp->mtame) goto next_mon;
X		/* treated all monsters */
X		break;
X
X	next_mon:
X		mtmp->mlstmv = moves;
X
X		/* most monsters drown in pools */
X		{ boolean inpool,iseel,isgremlin;
X#ifdef FOUNTAINS
X		  boolean infountain;
X#endif
X
X		  inpool = is_pool(mtmp->mx,mtmp->my);
X		  iseel = mtmp->data->mlet == S_EEL;
X		  isgremlin = mtmp->data->mlet == S_GREMLIN;
X#ifdef FOUNTAINS
X		  infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ);
X#endif
X		/* Gremlin multiplying won't go on forever since the hit points
X		 * keep going down, and when it gets to 1 hit point the clone
X		 * function will fail.
X		 */
X		  if((inpool
X#ifdef FOUNTAINS
X			     || infountain
X#endif
X					  ) && isgremlin && rn2(3)) {
X			struct monst *mtmp2 = clone_mon(mtmp);
X
X			if (mtmp2) {
X			    mtmp2->mhpmax = (mtmp->mhpmax /= 2);
X			    if(cansee(mtmp->mx,mtmp->my))
X				pline("%s multiplies.", Monnam(mtmp));
X			}
X#ifdef FOUNTAINS
X			if (infountain) dryup();
X#endif
X		  } else
X		  if(inpool && !is_flyer(mtmp->data) && !is_swimmer(mtmp->data)) {
X			if(cansee(mtmp->mx,mtmp->my))
X			    pline("%s drowns.", Monnam(mtmp));
X			mondead(mtmp);
X			continue;
X		  } else
X		/* but eels have a difficult time outside */
X		  if(iseel && !inpool) {
X			if(mtmp->mhp > 1) mtmp->mhp--;
X			mtmp->mflee = 1;
X			mtmp->mfleetim += 2;
X		  }
X		}
X		if(mtmp->mblinded && !--mtmp->mblinded)
X			mtmp->mcansee = 1;
X		if(mtmp->mfrozen && !--mtmp->mfrozen)
X			mtmp->mcanmove = 1;
X		if(mtmp->mfleetim && !--mtmp->mfleetim)
X			mtmp->mflee = 0;
X#ifdef HARD
X		/* unwatched mimics and piercers may hide again  [MRS] */
X		if(is_hider(mtmp->data) && restrap(mtmp))   continue;
X#endif
X		if(mtmp->mimic) continue;
X		if(mtmp->mspeed != MSLOW || !(moves%2)){
X		/* continue if the monster died fighting */
X		  if (Conflict && !mtmp->iswiz && mtmp->mcansee) {
X/* Note: A couple of notes on conflict here.
X	 1. Conflict does not take effect in the first round.  Therefore, 
X	    A monster in a stepping into the area will get to swing at you.
X	 2. Conflict still works when you are invisible.  (?)
X	 3. Certain areas (namely castle) you can be in 3 "rooms" at once!
X	    Polyself into Xorn wearing ring of conflict and it can be done.
X	    This code only allows for two.  This needs to be changed if more
X	    areas (with diggable walls and > 2 rooms) are put into the game.
X*/
X		    xchar clx = 0, chx = 0, cly = 0, chy = 0,
X			  clx2 = 0, chx2 = 0, cly2 = 0, chy2 = 0;
X		    /* seelx etc. are not set if blind or blindfolded! */
X		    getcorners(&clx, &chx, &cly, &chy,
X			       &clx2, &chx2, &cly2, &chy2);
X		    if ((dist(mtmp->mx,mtmp->my) < 3) || 
X		    /* if the monster is next to you OR */
X		 	(levl[u.ux][u.uy].lit &&
X			 levl[mtmp->mx][mtmp->my].lit &&
X		    /* both you and it are lit AND */
X			 ((clx <= mtmp->mx && mtmp->mx <= chx &&
X			   cly <= mtmp->my && mtmp->my <= chy) ||
X			  (clx2 <= mtmp->mx && mtmp->mx <= chx2 &&
X			   cly2 <= mtmp->my && mtmp->my <= chy2))))
X		    /* you *could* see it (ie it can see you) */
X		      if (fightm(mtmp) != 3)
X		      /* have it fight if it choses to */
X			continue;
X		  }
X		  if(dochugw(mtmp))
X		  /* otherwise just move the monster */
X		    continue;
X		}
X		if(mtmp->mspeed == MFAST && dochugw(mtmp))
X			continue;
X	}
X#ifdef NAMED_ITEMS
X	if (warnlevel == 100) {
X		Your("%s %s!", aobjnam(uwep, "glow"),
X			Hallucination ? hcolor() : light_blue);
X		warnlevel = 0;
X	}
X#endif
X	warnlevel -= u.ulevel;
X	if(warnlevel >= SIZE(warnings))
X		warnlevel = SIZE(warnings)-1;
X	if(!Blind && warnlevel >= 0)
X	if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
X	    register const char *rr;
X	
X	    switch((int) (Warning & (LEFT_RING | RIGHT_RING))){
X	    case LEFT_RING:
X		rr = "Your left ring glows";
X		break;
X	    case RIGHT_RING:
X		rr = "Your right ring glows";
X		break;
X	    case LEFT_RING | RIGHT_RING:
X		rr = "Both your rings glow";
X		break;
X	    default:
X		{ char buf[33];
X		Sprintf(buf, "Your %s glow", makeplural(body_part(FINGERTIP)));
X		rr = buf;
X		}
X		break;
X	    }
X	    pline("%s %s!", rr, Hallucination ? hcolor() : warnings[warnlevel]);
X	    lastwarntime = moves;
X	    lastwarnlev = warnlevel;
X	}
X
X	dmonsfree();	/* remove all dead monsters */
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xvoid
Xmeatgold(mtmp)
X	register struct monst *mtmp;
X{
X	register struct gold *gold;
X	register struct obj *otmp;
X
X	/* Eats gold if it is there */
X	if(gold = g_at(mtmp->mx, mtmp->my)){
X		if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X			pline("%s eats some gold!", Monnam(mtmp));
X		mtmp->meating = (int)((gold->amount + 500L)/1000L);
X		freegold(gold);
X		/* Left behind a pile? */
X		if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X		newsym(mtmp->mx, mtmp->my);
X	}
X	/* Eats topmost metal object if it is there */
X	for (otmp = level.objects[mtmp->mx][mtmp->my];
X						    otmp; otmp = otmp->nexthere)
X	    if (objects[otmp->otyp].oc_material > WOOD &&
X		objects[otmp->otyp].oc_material < MINERAL) {
X		    if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X			pline("%s eats %s!", Monnam(mtmp),
X				distant_name(otmp,doname));
X		    else if (flags.soundok && flags.verbose)
X			You("hear a crunching sound.");
X		    mtmp->meating = otmp->owt/2 - 1;
X		    /* Heal up to the object's weight in hp */
X		    if (mtmp->mhp < mtmp->mhpmax) {
X			mtmp->mhp += objects[otmp->otyp].oc_weight;
X			if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X		    }
X		    if(otmp == uball) {
X			unpunish();
X			freeobj(otmp);
X		    } else if(otmp == uchain)
X			unpunish();	/* frees uchain */
X		    else
X			freeobj(otmp);
X		    /* Left behind a pile? */
X		    if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X		    newsym(mtmp->mx, mtmp->my);
X		    break;
X	    }
X}
X
Xvoid
Xmeatobj(mtmp)		/* for gelatinous cubes */
X	register struct monst *mtmp;
X{
X	register struct obj *otmp, *otmp2;
X
X	/* Eats organic, glass, or wood objects if there */
X	/* Engulfs others, except huge rocks and metal attached to player */
X	for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
X	    otmp2 = otmp->nexthere;
X	    if(objects[otmp->otyp].oc_material <= WOOD) {
X		if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X		    pline("%s eats %s!", Monnam(mtmp),
X			    distant_name(otmp, doname));
X		else if (flags.soundok && flags.verbose)
X		    You("hear a slurping sound.");
X		/* Heal up to the object's weight in hp */
X		if (mtmp->mhp < mtmp->mhpmax) {
X		    mtmp->mhp += objects[otmp->otyp].oc_weight;
X		    if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X		}
X		delobj(otmp);		/* munch */
X	    } else if (otmp->olet != ROCK_SYM &&
X				    otmp != uball && otmp != uchain) {
X		if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X		    pline("%s engulfs %s.", Monnam(mtmp),
X			    distant_name(otmp,doname));
X		freeobj(otmp);
X		mpickobj(mtmp, otmp);	/* slurp */
X	    }
X	    /* Engulf & devour is instant, so don't set meating */
X	    newsym(mtmp->mx, mtmp->my);
X	}
X}
X
Xvoid
Xmpickgold(mtmp)
X	register struct monst *mtmp;
X{
X	register struct gold *gold;
X
X	if(gold = g_at(mtmp->mx, mtmp->my)){
X		mtmp->mgold += gold->amount;
X		if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X			pline("%s picks up some gold.", Monnam(mtmp));
X		freegold(gold);
X		if(levl[mtmp->mx][mtmp->my].scrsym == GOLD_SYM)
X			newsym(mtmp->mx, mtmp->my);
X	}
X}
X
X/* Now includes giants which pick up enormous rocks.  KAA */
Xvoid
Xmpickgems(mtmp)
X	register struct monst *mtmp;
X{
X	register struct obj *otmp;
X
X	for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp=otmp->nexthere)
X	    if(throws_rocks(mtmp->data) ? otmp->otyp == BOULDER :
X			(otmp->olet == GEM_SYM && otmp->otyp < LAST_GEM+6))
X		if(mtmp->data->mlet != S_UNICORN
X			|| objects[otmp->otyp].g_val != 0){
X		    if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X			pline("%s picks up %s.", Monnam(mtmp),
X				distant_name(otmp, doname));
X		    freeobj(otmp);
X		    mpickobj(mtmp, otmp);
X		    newsym(mtmp->mx, mtmp->my);
X		    return;	/* pick only one object */
X		}
X}
X
X#endif /* OVLB */
X#ifdef OVL0
X
Xint
Xcurr_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X	register int curload = 0;
X	register struct obj *obj;
X
X	for(obj = mtmp->minvent; obj; obj = obj->nobj) {
X		if(obj->otyp != BOULDER || !throws_rocks(mtmp->data))
X			curload += weight(obj);
X	}
X
X	return curload;
X}
X
Xint
Xmax_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X	register int maxload;
X
X	/* Base monster carrying capacity is equal to human maximum
X	 * carrying capacity, or half human maximum if not strong.
X	 * (for a polymorphed player, the value used would be the
X	 * non-polymorphed carrying capacity instead of max/half max).
X	 * This is then modified by the ratio between the monster weights
X	 * and human weights (weight of a human=45).  Limits for corpseless
X	 * monsters are arbitrary.
X	 */
X	if (!mtmp->data->cwt)
X		maxload = MAX_CARR_CAP * (mtmp->data->mlevel * 6) / 45;
X	else if (!strongmonst(mtmp->data)
X		|| (strongmonst(mtmp->data) && (mtmp->data->cwt > 45)))
X		maxload = MAX_CARR_CAP * mtmp->data->cwt / 45;
X	else	maxload = MAX_CARR_CAP;	/* strong monsters w/ cwt <= 45 */
X
X	if (!strongmonst(mtmp->data)) maxload /= 2;
X
X	return maxload;
X}
X
X/* for restricting monsters' object-pickup */
Xboolean
Xcan_carry(mtmp,otmp)
Xstruct monst *mtmp;
Xstruct obj *otmp;
X{
X	register int newload = weight(otmp);
X
X	if (otmp->otyp == CORPSE && otmp->corpsenm == PM_COCKATRICE
X						&& !resists_ston(mtmp->data))
X		return(FALSE);
X	if (mtmp->isshk) return(TRUE); /* no limit */
X	if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE);
X	/* otherwise players might find themselves obligated to violate
X	 * their alignment if the monster takes something they need
X	 */
X	
X	/* special--boulder throwers carry unlimited amounts of boulders */
X	if (throws_rocks(mtmp->data) && otmp->otyp == BOULDER)
X		return(TRUE);
X	
X	/* nymphs deal in stolen merchandise, but not boulders or statues */
X	if (mtmp->data->mlet == S_NYMPH)
X		return !(otmp->olet == ROCK_SYM);
X
X	if(curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return(FALSE);
X
X	return(TRUE);
X}
X
X#endif /* OVL0 */
X#ifdef OVL2
X
Xvoid
Xmpickstuff(mtmp, str)
X	register struct monst *mtmp;
X	register const char *str;
X{
X	register struct obj *otmp;
X
X/*	prevent shopkeepers from leaving the door of their shop */
X	if(mtmp->isshk && inhishop(mtmp)) return;
X
X	for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp=otmp->nexthere)
X	    if(index(str, otmp->olet)) {
X		if(!can_carry(mtmp,otmp)) return;
X		if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X			pline("%s picks up %s.", Monnam(mtmp), doname(otmp));
X		freeobj(otmp);
X		mpickobj(mtmp, otmp);
X		if(index(str, (char) levl[mtmp->mx][mtmp->my].scrsym))
X			newsym(mtmp->mx, mtmp->my);
X		return;			/* pick only one object */
X	    }
X}
X
X#endif /* OVL2 */
X#ifdef OVL0
X
X/* return number of acceptable neighbour positions */
Xint
Xmfndpos(mon, poss, info, flag)
X	register struct monst *mon;
X	coord *poss;	/* coord poss[9] */
X	long *info;	/* long info[9] */
X	long flag;
X{
X	register int x,y,nx,ny,cnt = 0;
X	register uchar ntyp;
X	uchar nowtyp;
X	boolean wantpool,poolok,nodiag;
X
X	x = mon->mx;
X	y = mon->my;
X	nowtyp = levl[x][y].typ;
X
X	nodiag = (mon->data == &mons[PM_GRID_BUG]);
X	wantpool = mon->data->mlet == S_EEL;
X	poolok = is_flyer(mon->data) || (is_swimmer(mon->data) && !wantpool);
Xnexttry:	/* eels prefer the water, but if there is no water nearby,
X		   they will crawl over land */
X	if(mon->mconf) {
X		flag |= ALLOW_ALL;
X		flag &= ~NOTONL;
X	}
X	if(!mon->mcansee)
X		flag |= ALLOW_SSM;
X	for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
X	    if((nx == x && ny == y) || !isok(nx,ny)) continue;
X	    if(nx != x && ny != y && nodiag) continue;
X	    if(IS_ROCK(ntyp = levl[nx][ny].typ) && !(flag & ALLOW_WALL) &&
X		!((flag & ALLOW_DIG) && may_dig(nx,ny))) continue;
X	    if(IS_DOOR(ntyp) && !amorphous(mon->data) &&
X	       ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
X		(levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))
X	       ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue;
X	    if(nx != x && ny != y &&
X#ifdef REINCARNATION
X	       ((IS_DOOR(nowtyp) &&
X	         ((levl[x][y].doormask & ~D_BROKEN) || dlevel == rogue_level)) ||
X		(IS_DOOR(ntyp) &&
X		 ((levl[nx][ny].doormask & ~D_BROKEN) || dlevel == rogue_level))
X#else
X	       ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
X		(IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN))
X#endif
X	       ))
X		continue;
X	    if(is_pool(nx,ny) == wantpool || poolok) {
X		/* Displacement also displaces the Elbereth/scare monster,
X		 * as long as you are visible.
X		 */
X		int dispx = (Displaced && (!Invis || perceives(mon->data)) &&
X			(mon->mux==nx)) ? u.ux : nx;
X		int dispy = (Displaced && (!Invis || perceives(mon->data)) &&
X			(mon->muy==ny)) ? u.uy : ny;
X
X		info[cnt] = 0;
X		if(sobj_at(SCR_SCARE_MONSTER, dispx, dispy)
X#ifdef ELBERETH
X		   || sengr_at("Elbereth", dispx, dispy)
X#endif
X		  ) {
X			if(!(flag & ALLOW_SSM)) continue;
X			info[cnt] |= ALLOW_SSM;
X		}
X		if((nx == u.ux && ny == u.uy) ||
X		   (nx == mon->mux && ny == mon->muy)) {
X			if(!(flag & ALLOW_U)) continue;
X			info[cnt] |= ALLOW_U;
X		} else {
X			if(MON_AT(nx, ny)) {
X				if(!(flag & ALLOW_M)) continue;
X				info[cnt] |= ALLOW_M;
X				if((m_at(nx,ny))->mtame) {
X					if(!(flag & ALLOW_TM)) continue;
X					info[cnt] |= ALLOW_TM;
X				}
X			}
X#if defined(ALTARS) && defined(THEOLOGY)
X			/* Note: ALLOW_SANCT only prevents movement, not */
X			/* attack, into a temple. */
X			if(!in_temple(x, y) && in_temple(nx, ny) &&
X					u_in_sanctuary(in_temple(nx, ny))) {
X				if(!(flag & ALLOW_SANCT)) continue;
X				info[cnt] |= ALLOW_SANCT;
X			}
X#endif
X		}
X		if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
X			if(flag & NOGARLIC) continue;
X			info[cnt] |= NOGARLIC;
X		}
X		if(sobj_at(BOULDER, nx, ny)) {
X			if(!(flag & ALLOW_ROCK)) continue;
X			info[cnt] |= ALLOW_ROCK;
X		}
X		if((!Invis || perceives(mon->data)) && online(nx,ny)){
X			if(flag & NOTONL) continue;
X			info[cnt] |= NOTONL;
X		}
X		/* we cannot avoid traps of an unknown kind */
X		{ register struct trap *ttmp = t_at(nx, ny);
X		  register long tt;
X			if(ttmp) {
X/*				tt = 1L << ttmp->ttyp;*/
X/* why don't we just have code look like what it's supposed to do? then it
X/* might start working for every case. try this instead: -sac */
X				tt = (ttmp->ttyp < TRAPNUM && ttmp->ttyp);
X				/* below if added by GAN 02/06/87 to avoid
X				 * traps out of range
X				 */
X				if(!(tt & ALLOW_TRAPS))  {
Ximpossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp);
X					continue;
X				}
X				if(mon->mtrapseen & tt) {
X
X					if(!(flag & tt)) continue;
X					info[cnt] |= tt;
X				}
X			}
X		}
X		poss[cnt].x = nx;
X		poss[cnt].y = ny;
X		cnt++;
X	    }
X	}
X	if(!cnt && wantpool && !is_pool(x,y)) {
X		wantpool = FALSE;
X		goto nexttry;
X	}
X	return(cnt);
X}
X
X#endif /* OVL0 */
X#ifdef OVL1
X
Xint
Xdist(x, y)
Xregister int x,y;
X{
X	register int dx = x - u.ux, dy = y - u.uy;
X	return dx*dx + dy*dy;
X}
X
Xboolean
Xmonnear(mon, x, y)
Xregister struct monst *mon;
Xregister int x,y;
X/* Is the square close enough for the monster to move or attack into? */
X{
X	register int distance = dist2(mon->mx, mon->my, x, y);
X	if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0;
X	return (distance < 3);
X}
X
X#endif /* OVL1 */
X#ifdef OVLB
X
Xstatic const char *poiseff[] = {
X
X	" feel very weak", "r brain is on fire",
X	" can't think straight", "r muscles won't obey you",
X	" feel very sick", " break out in hives"
X};
X
Xvoid
Xpoisontell(typ)
X
X	int	typ;
X{
X	pline("You%s.", poiseff[typ]);
X}
X
Xvoid
Xpoisoned(string, typ, pname, fatal)
Xregister const char *string, *pname;
Xregister int  typ, fatal;
X{
X	register int i, plural;
X	boolean thrown_weapon = !strncmp(string, "poison", 6);
X		/* admittedly a kludge... */
X
X	if(strcmp(string, "blast") && !thrown_weapon) {
X	    /* 'blast' has already given a 'poison gas' message */
X	    /* so have "poison arrow", "poison dart", etc... */
X	    plural = (string[strlen(string) - 1] == 's')? 1 : 0;
X	    if(Blind)
X		pline("%s poisoned.", plural ? "They were" : "It was");
X#ifdef INFERNO
X	    /* avoid "The" Orcus's sting was poisoned... */
X	    else if(isupper(*string))
X		pline("%s %s poisoned!", string, plural ? "were" : "was");
X#endif
X	    else
X		pline("The %s %s poisoned!", string, plural ? "were" : "was");
X	}
X
X	if(Poison_resistance) {
X		if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy);
X		pline("The poison doesn't seem to affect you.");
X		return;
X	}
X	i = rn2(fatal + 20*thrown_weapon);
X	if(i == 0 && typ != A_CHA) {
X		u.uhp = -1;
X		pline("The poison was deadly...");
X	} else if(i <= 5) {
X		You("%s!", poiseff[typ]);
X		adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), TRUE);
X	} else {
X		losehp(thrown_weapon ? rnd(6) : rn1(10,6), pname, KILLED_BY_AN);
X	}
X	if(u.uhp < 1) {
X		killer_format = KILLED_BY_AN;
X		killer = pname;
X		done(POISONING);
X	}
X}
X
Xstatic void
Xm_detach(mtmp)
Xregister struct monst *mtmp;
X{
X#ifdef WALKIES
X	if(mtmp->mleashed) m_unleash(mtmp);
X#endif
X	relobj(mtmp,1);
X	unpmon(mtmp);
X	relmon(mtmp);
X	unstuck(mtmp);
X}
X
Xvoid
Xmondead(mtmp)
Xregister struct monst *mtmp;
X{
X	m_detach(mtmp);	
X#ifdef KOPS
X	if(mtmp->data->mlet == S_KOP && allow_kops) {
X	    /* Dead Kops may come back. */
X	    switch(rnd(5)) {
X		case 1:	     /* returns near the stairs */
X			(void) makemon(mtmp->data,xdnstair,ydnstair);
X			break;
X		case 2:	     /* randomly */
X			(void) makemon(mtmp->data,0,0);
X			break;
X		default:
X			break;
X	    }
X	}
X#endif
X	if(mtmp->isshk) shkdead(mtmp);
X	if(mtmp->isgd) {
X		if(!grddead(mtmp)) return;
X	}
X#ifdef WORM
X	if(mtmp->wormno) wormdead(mtmp);
X#endif
X#ifdef HARD
X	if(mtmp->iswiz) wizdead(mtmp);
X#endif
X#ifdef MEDUSA
X	if(mtmp->data == &mons[PM_MEDUSA]) u.ukilled_medusa = TRUE;
X#endif
X	monfree(mtmp);
X}
X
X/* called when monster is moved to larger structure */
Xvoid
Xreplmon(mtmp, mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X	relmon(mtmp);
X	monfree(mtmp);
X	place_monster(mtmp2, mtmp2->mx, mtmp2->my);
X	mtmp2->nmon = fmon;
X	fmon = mtmp2;
X	if(u.ustuck == mtmp) u.ustuck = mtmp2;
X	if(mtmp2->isshk) replshk(mtmp,mtmp2);
X#ifdef WORM
X	if(mtmp2->wormno) {
X		/* Each square the worm is on has a pointer; fix them all */
X		register struct wseg *wtmp;
X
X		for(wtmp=wsegs[mtmp2->wormno]; wtmp; wtmp=wtmp->nseg)
X			place_worm_seg(mtmp2, wtmp->wx, wtmp->wy);
X	}
X#endif
X}
X
Xvoid
Xrelmon(mon)
Xregister struct monst *mon;
X{
X	register struct monst *mtmp;
X
X	if (fmon == 0)  panic ("relmon: no fmon available.");
X
X	remove_monster(mon->mx, mon->my);
X
X	if(mon == fmon) fmon = fmon->nmon;
X	else {
X		for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ;
X		if(mtmp)    mtmp->nmon = mon->nmon;
X		else	    panic("relmon: mon not in list.");
X	}
X}
X
X/* we do not free monsters immediately, in order to have their name
X   available shortly after their demise */
Xvoid
Xmonfree(mtmp) register struct monst *mtmp; {
X	mtmp->nmon = fdmon;
X	fdmon = mtmp;
X	remove_monster(mtmp->mx, mtmp->my);
X}
X
Xvoid
Xunstuck(mtmp)
Xregister struct monst *mtmp;
X{
X	if(u.ustuck == mtmp) {
X		if(u.uswallow){
X			u.ux = mtmp->mx;
X			u.uy = mtmp->my;
X			u.uswallow = 0;
X			u.uswldtim = 0;
X			setsee();
X			docrt();
X		}
X		u.ustuck = 0;
X	}
X}
X
Xvoid
Xkilled(mtmp)
Xregister struct monst *mtmp;
X{
X	xkilled(mtmp, 1);
X}
X
Xvoid
Xxkilled(mtmp, dest)
X	register struct monst *mtmp;
X/*
X * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
X * either; dest=3, message but no corpse
X */
X	int	dest;
X{
X	register int tmp, nk, x, y;
X	register struct permonst *mdat = mtmp->data;
X	register struct obj *otmp;
X	boolean chance;
X
X	if (dest & 1) {
X	    if(!cansee(mtmp->mx,mtmp->my)) You("destroy it!");
X	    else {
X		You("destroy %s!",
X			mtmp->mtame ? a2_monnam(mtmp, "poor") : mon_nam(mtmp));
X	    }
X	}
X
X	/* restore chameleon, lycanthropes to true form at death */
X	/* cannot do this in make_corpse() since genociding monsters after
X	 * MAXMONNO were killed does the wrong type
X	 */
X	if(mtmp->cham) mtmp->data = mdat = &mons[PM_CHAMELEON];
X	if(mdat == &mons[PM_JACKALWERE])
X		mtmp->data = mdat = &mons[PM_WEREJACKAL];
X	if(mdat == &mons[PM_WOLFWERE])
X		mtmp->data = mdat = &mons[PM_WEREWOLF];
X	if(mdat == &mons[PM_RATWERE])
X		mtmp->data = mdat = &mons[PM_WERERAT];
X
X	/* if we have killed MAXMONNO monsters of a given type, and it
X	 * can be done, genocide that monster.
X	 */
X	tmp = monsndx(mdat);
X	u.nr_killed[tmp]++;
X	nk = u.nr_killed[tmp];
X#ifdef TOLKIEN
X	if(nk > (tmp==PM_NAZGUL ? 9 : MAXMONNO) &&
X				!(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#else
X	if(nk > MAXMONNO && !(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#endif
X#ifdef DEBUG
X		pline("Automatically genocided %s.", makeplural(mons[tmp].mname));
X#endif
X		if (tmp != PM_WIZARD_OF_YENDOR)
X			mons[tmp].geno |= G_GENOD;
X	}
X#ifdef MAIL
X	/* If you kill the mail daemon, no more mail delivery.  -3. */
X	else if(tmp==PM_MAIL_DAEMON) mons[tmp].geno |= G_GENOD;
X#endif	
X
X	/* punish bad behaviour */
X	if(is_human(mdat) && !always_hostile(mdat) &&
X	   (monsndx(mdat) < PM_ARCHEOLOGIST || monsndx(mdat) > PM_WIZARD) &&
X	   u.ualigntyp != U_CHAOTIC) {
X		HTelepat &= ~INTRINSIC;
X		change_luck(-2);
X	}
X	if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame)	change_luck(-1);
X	if ((mdat==&mons[PM_BLACK_UNICORN] && u.ualigntyp == U_CHAOTIC) ||
X	    (mdat==&mons[PM_GRAY_UNICORN] && u.ualigntyp == U_NEUTRAL) ||
X	    (mdat==&mons[PM_WHITE_UNICORN] && u.ualigntyp == U_LAWFUL))
X		change_luck(-5);
X
X	/* give experience points */
X	tmp = experience(mtmp, nk);
X	more_experienced(tmp, 0);
X	newexplevel();		/* will decide if you go up */
X
X	/* adjust alignment points */
X	if(mtmp->mtame)
X		adjalign(-15);	/* bad!! */
X#if defined(ALTARS) && defined(THEOLOGY)
X	else if (mtmp->ispriest && !p_coaligned(mtmp))
X		adjalign(2);
X#endif
X	else if (mtmp->mpeaceful)
X		adjalign(-5);
X	/* malign was already adjusted for ualigntyp and randomization */
X	adjalign(mtmp->malign);
X
X	/* dispose of monster and make cadaver */
X	if(stoned) {
X		monstone(mtmp);
X		return;
X	}
X
X	x = mtmp->mx;   y = mtmp->my;
X
X	mondead(mtmp);
X
X	if((dest & 2)
X#ifdef REINCARNATION
X		 || dlevel == rogue_level
X#endif
X					) return;
X
X#ifdef MAIL
X	if(mdat == &mons[PM_MAIL_DAEMON]) {
X		(void) mksobj_at(SCR_MAIL, x, y);
X		stackobj(fobj);
X		newsym(x,y);
X	}
X#endif
X	if(!accessible(x, y)) {
X	    /* might be mimic in wall or dead eel*/
X 	    newsym(x,y);
X	} else if(x != u.ux || y != u.uy) {
X		/* might be here after swallowed */
X		if (!rn2(6) && !(mdat->geno & G_NOCORPSE)
X#ifdef KOPS
X					&& mdat->mlet != S_KOP
X#endif
X							) {
X			int typ;
X
X			otmp = mkobj_at(RANDOM_SYM, x, y, TRUE);
X			/* Don't create large objects from small monsters */
X			typ = otmp->otyp;
X			if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION
X#ifdef WALKIES
X			    && typ != LEASH
X#endif
X			    && typ != FIGURINE
X			    && (otmp->owt > 3 ||
X				(typ >= SPEAR && typ <= LANCE) ||
X				(typ >= SCIMITAR && typ <= KATANA) ||
X				(typ == MORNING_STAR || typ == QUARTERSTAFF) ||
X				(typ >= BARDICHE && typ <= VOULGE) ||
X				(typ>=PLATE_MAIL && typ<=DRAGON_SCALE_MAIL) ||
X				(typ == LARGE_SHIELD))) {
X			    delobj(otmp);
X			} else newsym(x,y);
X		}
X		/* Whether or not it always makes a corpse is, in theory,
X		 * different from whether or not the corpse is "special";
X		 * if we want both, we have to specify it explicitly.
X		 */
X		if (bigmonst(mdat) || mdat == &mons[PM_LIZARD]
X#ifdef GOLEMS
X				   || is_golem(mdat)
X#endif
X		   ) chance = 1;
X		else chance = !rn2((int)
X			(2 + ((mdat->geno & G_FREQ)<2) + verysmall(mdat)));
X		if (chance)
X			(void) make_corpse(mtmp);
X	}
X}
X
Xvoid
Xrescham() {	/* force all chameleons to become normal */
X
X	register struct monst *mtmp;
X
X	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X		if(mtmp->cham) {
X			mtmp->cham = 0;
X			(void) newcham(mtmp, &mons[PM_CHAMELEON]);
X		}
X		if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
X			(void) new_were(mtmp);
X		if(mtmp->mimic && cansee(mtmp->mx, mtmp->my)) {
X			seemimic(mtmp);
X			/* we pretend that the mimic doesn't */
X			/* know that it has been unmasked.   */
X			mtmp->msleep = 1;
X		}
X	}
X}
X
X/* Let the chameleons change again -dgk */
Xvoid
Xrestartcham() {
X
X	register struct monst *mtmp;
X
X	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X		if (mtmp->data == &mons[PM_CHAMELEON])
X			mtmp->cham = 1;
X		if(mtmp->data->mlet == S_MIMIC && mtmp->msleep &&
X				cansee(mtmp->mx, mtmp->my)) {
X			set_mimic_sym(mtmp);
X			unpmon(mtmp);
X			pmon(mtmp);
X		}
X	}
X}
X
Xint
Xnewcham(mtmp, mdat)	/* make a chameleon look like a new monster */
X			/* returns 1 if the monster actually changed */
X	register struct monst *mtmp;
X	register struct permonst *mdat;
X{
X	register int mhp, hpn, hpd;
X	int tryct;
X       struct permonst *olddata = mtmp->data;
X
X	/* mdat = 0 -> caller wants a random monster shape */
X	tryct = 0;
X	if(mdat == 0) {
X		while (++tryct < 100) {
X			static int NEARDATA num;
X			mdat = &mons[num=rn2(NUMMONS)];
X			if ((!is_human(mdat) || num == PM_NURSE)
X				&& !type_is_pname(mdat)
X				&& !is_were(mdat)
X#ifdef MEDUSA
X				&& num != PM_MEDUSA
X#endif
X#ifdef MAIL
X				&& num != PM_MAIL_DAEMON
X#endif
X				)
X				break;
X		}
X		if (tryct >= 100) return(0); /* Should never happen */
X	}
X  	if(mdat == mtmp->data) return(0);	/* still the same monster */
X
X#ifdef WORM
X	if(mtmp->wormno) wormdead(mtmp);	/* throw tail away */
X#endif
X	hpn = mtmp->mhp;
X 	hpd = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X 	if(!hpd) hpd = 4;
X
X	mtmp->m_lev = adj_lev(mdat);		/* new monster level */
X
X 	mhp = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X 	if(!mhp) mhp = 4;
X
X	/* new hp: same fraction of max as before */
X#ifndef LINT
X 	mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X 	if(mtmp->mhp < 0) mtmp->mhp = hpn;	/* overflow */
X/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
X   0HD creature will require this statement */
X 	if (!mtmp->mhp) mtmp->mhp = 1;
X
X/* and the same for maximum hit points */
X	hpn = mtmp->mhpmax;
X#ifndef LINT
X 	mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X 	if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn;	/* overflow */
X 	if (!mtmp->mhpmax) mtmp->mhpmax = 1;
X
X 	mtmp->data = mdat;
X	mtmp->minvis = !!(mdat->mlet == S_STALKER);
X	mtmp->mhide = !!hides_under(mdat);
X	if (!mtmp->mhide) mtmp->mundetected = 0;
X	if (u.ustuck == mtmp) {
X		if(u.uswallow) {
X			if(!attacktype(mdat,AT_ENGL)) {
X				/* Does mdat care? */
X				if (!noncorporeal(mdat) && !amorphous(mdat) && 
X				    !is_whirly(mdat) && 
X				    (mdat != &mons[PM_YELLOW_LIGHT])) {
X					You("break out of %s%s!", mon_nam(mtmp),
X					    (is_animal(mdat)? 
X					    "'s stomach" : ""));
X					mtmp->mhp = 1;  /* almost dead */
X				}
X				expels(mtmp, olddata, FALSE);
X			}
X		} else {
X			if(!sticks(mdat)
X#ifdef POLYSELF
X				&& !sticks(uasmon)
X#endif
X				)
X				unstuck(mtmp);
X		}
X	}
X
X#ifdef WORM
X	if(mdat == &mons[PM_LONG_WORM] && getwn(mtmp)) initworm(mtmp);
X#endif
X	unpmon(mtmp);	/* necessary for 'I' and to force pmon */
X	pmon(mtmp);
X	return(1);
X}
X
Xvoid
Xmnexto(mtmp)	/* Make monster mtmp next to you (if possible) */
X	struct monst *mtmp;
X{
X	coord mm;
X	if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return;
X	remove_monster(mtmp->mx, mtmp->my);
X	place_monster(mtmp, mm.x, mm.y);
X	pmon(mtmp);
X	set_apparxy(mtmp);
X}
X
Xvoid
Xmnearto(mtmp,x,y,gz)	/* Make monster near (or at) location if possible */
X	register struct monst *mtmp;
X	xchar x, y;
X	boolean gz;     
X{
X	coord mm;
X	if(!gz || !goodpos(x,y,mtmp->data)) {
X		if(!enexto(&mm, x, y, mtmp->data)) return;
X		x = mm.x; y = mm.y;
X	}
X	if(x == mtmp->mx && y == mtmp->my) /* that was easy */
X		return;
X	remove_monster(mtmp->mx, mtmp->my);
X	place_monster(mtmp, x, y);
X	pmon(mtmp);
X	set_apparxy(mtmp);
X}
X
X#endif /* OVLB */
X#ifdef OVL2
X
Xvoid
Xsetmangry(mtmp)
X	register struct monst *mtmp;
X{
X	if(!mtmp->mpeaceful) return;
X	if(mtmp->mtame) return;
X	mtmp->mpeaceful = 0;
X#if defined(ALTARS) && defined(THEOLOGY)
X	if(mtmp->ispriest) {
X		if(p_coaligned(mtmp)) adjalign(-5); /* very bad */
X		else adjalign(2);
X	} else
X#endif
X	adjalign(-1);		/* attacking peaceful monsters is bad */
X	if(humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
X		pline("%s gets angry!", Monnam(mtmp));
X#ifdef SOUNDS
X	else if (flags.verbose && flags.soundok) growl(mtmp);
X#endif
X}
X
Xint
Xdisturb(mtmp)		/* awaken monsters while in the same room.
X			 * return a 1 if they have been woken.
X			 */
X	register struct monst *mtmp;
X{
X	/* wake up, or get out of here. */
X	/* ettins are hard to surprise */
X	/* Nymphs and Leprechauns do not easily wake up */
X	if(cansee(mtmp->mx,mtmp->my) &&
X		(!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
X		(!(mtmp->data->mlet == S_NYMPH
X			|| mtmp->data == &mons[PM_JABBERWOCK]
X			|| mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
X		(Aggravate_monster ||
X		 (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN) ||
X		(!rn2(7) && !mtmp->mimic))) {
X		mtmp->msleep = 0;
X		return(1);
X	}
X	if(Hallucination) pmon(mtmp);
X	return(0);
X}
X
X#ifdef HARD
XSTATIC_OVL boolean
Xrestrap(mtmp)
X/* unwatched hiders may hide again,
X * if so, a 1 is returned.
X */
Xregister struct monst *mtmp;
X{
X	if(mtmp->cham || mtmp->mcan || mtmp->mimic ||
X	   cansee(mtmp->mx, mtmp->my) || rn2(3))
X		return(FALSE);
X
X	if(mtmp->data->mlet == S_MIMIC) {
X		set_mimic_sym(mtmp);
X		return(TRUE);
X	} else
X	    if(levl[mtmp->mx][mtmp->my].typ == ROOM)  {
X		(void) maketrap(mtmp->mx, mtmp->my, MONST_TRAP);
X		/* override type selection */
X		ftrap->pm = monsndx(mtmp->data);
X		mondead(mtmp);
X		return(TRUE);
X	    }
X
X	return(FALSE);
X}
X#endif
X
X#endif /* OVL2 */
X#ifdef OVLB
X
X/* drop (perhaps) a cadaver and remove monster */
Xvoid
Xmondied(mdef)
Xregister struct monst *mdef;
X{
X	mondead(mdef);
X	if(rn2(3)
X#ifdef REINCARNATION
X	   && dlevel != rogue_level
X#endif
X					)
X		(void) make_corpse(mdef);
X}
X
X/* monster disappears, not dies */
Xvoid
Xmongone(mdef)
Xregister struct monst *mdef;
X{
X	register struct obj *otmp, *otmp2;
X
X	/* release monster's inventory */
X	for (otmp = mdef->minvent; otmp; otmp = otmp2) {
X		otmp2 = otmp->nobj;
X		obfree(otmp, (struct obj *)0);
X	}
X	mdef->minvent = 0;
X	mdef->mgold = 0;
X	m_detach(mdef);
X	monfree(mdef);
X}
X
X/* drop a statue or rock and remove monster */
Xvoid
Xmonstone(mdef)
Xregister struct monst *mdef;
X{
X	struct obj *otmp;
X
X	if((int)mdef->data->msize > MZ_TINY ||
X	   !rn2(2 + ((mdef->data->geno & G_FREQ) > 2))) {
X		otmp = mk_named_object(STATUE, mdef->data, mdef->mx, mdef->my,
X			NAME(mdef), (int)mdef->mnamelth);
X		otmp->spe = 0; /* no book inside */
X	} else
X		(void) mksobj_at(ROCK, mdef->mx, mdef->my);
X
X	stackobj(fobj);
X
X	if(cansee(mdef->mx, mdef->my)){
X		unpmon(mdef);
X		atl(mdef->mx,mdef->my,Hallucination ? rndobjsym() : fobj->olet);
X	}
X	mondead(mdef);
X}
X
X#ifdef GOLEMS
Xvoid
Xgolemeffects(mon, damtype, dam)
Xregister struct monst *mon;
Xint damtype, dam;
X{
X	int heal=0, slow=0;
X
X	if (mon->data != &mons[PM_FLESH_GOLEM]
X					&& mon->data != &mons[PM_IRON_GOLEM])
X		return;
X
X	if (mon->data == &mons[PM_FLESH_GOLEM]) {
X		if (damtype == AD_ELEC) heal = dam / 6;
X		else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1;
X	} else {
X		if (damtype == AD_ELEC) slow = 1;
X		else if (damtype == AD_FIRE) heal = dam;
X	}
X	if (slow) {
X		if (mon->mspeed != MSLOW) {
X			if (mon->mspeed == MFAST) mon->mspeed = 0;
X			else mon->mspeed = MSLOW;
X			if (cansee(mon->mx, mon->my))
X				pline("%s seems to be moving slower.",
X					Monnam(mon));
X		}
X	}
X	if (heal) {
X		if (mon->mhp < mon->mhpmax) {
X			mon->mhp += dam;
X			if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
X			if (cansee(mon->mx, mon->my))
X				pline("%s seems healthier.", Monnam(mon));
X		}
X	}
X}
X#endif /* GOLEMS */
X
X#endif /* OVLB */
END_OF_FILE
if test 36529 -ne `wc -c <'src/mon.c'`; then
    echo shar: \"'src/mon.c'\" unpacked with wrong size!
fi
# end of 'src/mon.c'
fi
echo shar: End of archive 17 \(of 56\).
cp /dev/null ark17isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 56 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0