xref: /netbsd-src/games/hack/hack.mon.c (revision d5b021c7edb8313eee3804ec3819b28abef1d1a0)
1*d5b021c7Sdholland /*	$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $	*/
23ea4a95cSchristos 
302ded532Smycroft /*
41c7f94e5Sjsm  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm  * Amsterdam
61c7f94e5Sjsm  * All rights reserved.
71c7f94e5Sjsm  *
81c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm  * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm  * met:
111c7f94e5Sjsm  *
121c7f94e5Sjsm  * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm  * this list of conditions and the following disclaimer.
141c7f94e5Sjsm  *
151c7f94e5Sjsm  * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm  * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm  * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm  *
191c7f94e5Sjsm  * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm  * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm  * promote products derived from this software without specific prior
221c7f94e5Sjsm  * written permission.
231c7f94e5Sjsm  *
241c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm  */
361c7f94e5Sjsm 
371c7f94e5Sjsm /*
381c7f94e5Sjsm  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm  * All rights reserved.
401c7f94e5Sjsm  *
411c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm  * modification, are permitted provided that the following conditions
431c7f94e5Sjsm  * are met:
441c7f94e5Sjsm  * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm  * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm  *    documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm  * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm  *    derived from this software without specific prior written permission.
511c7f94e5Sjsm  *
521c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
551c7f94e5Sjsm  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6202ded532Smycroft  */
6302ded532Smycroft 
643ea4a95cSchristos #include <sys/cdefs.h>
6502ded532Smycroft #ifndef lint
66*d5b021c7Sdholland __RCSID("$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $");
6702ded532Smycroft #endif				/* not lint */
6861f28255Scgd 
693ea4a95cSchristos #include <stdlib.h>
7061f28255Scgd #include "hack.h"
713ea4a95cSchristos #include "extern.h"
7261f28255Scgd #include "hack.mfndpos.h"
7361f28255Scgd 
749b92b189Sdholland static int warnlevel;	/* used by movemon and dochugw */
759b92b189Sdholland static long lastwarntime;
769b92b189Sdholland static int lastwarnlev;
779b92b189Sdholland 
789b92b189Sdholland static const char *const warnings[] = {
7961f28255Scgd 	"white", "pink", "red", "ruby", "purple", "black"
8061f28255Scgd };
8161f28255Scgd 
829b92b189Sdholland static int dochugw(struct monst *);
839b92b189Sdholland static void mpickgold(struct monst *);
849b92b189Sdholland static void mpickgems(struct monst *);
859b92b189Sdholland static void dmonsfree(void);
869b92b189Sdholland static int ishuman(struct monst *);
879b92b189Sdholland 
883ea4a95cSchristos void
movemon(void)891fa8a9a6Sdholland movemon(void)
9061f28255Scgd {
913ea4a95cSchristos 	struct monst   *mtmp;
923ea4a95cSchristos 	int             fr;
9361f28255Scgd 
9461f28255Scgd 	warnlevel = 0;
9561f28255Scgd 
9661f28255Scgd 	while (1) {
9761f28255Scgd 		/* find a monster that we haven't treated yet */
983ea4a95cSchristos 		/*
993ea4a95cSchristos 		 * note that mtmp or mtmp->nmon might get killed while mtmp
1003ea4a95cSchristos 		 * moves, so we cannot just walk down the chain (even new
1013ea4a95cSchristos 		 * monsters might get created!)
1023ea4a95cSchristos 		 */
10361f28255Scgd 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1043ea4a95cSchristos 			if (mtmp->mlstmv < moves)
1053ea4a95cSchristos 				goto next_mon;
10661f28255Scgd 		/* treated all monsters */
10761f28255Scgd 		break;
10861f28255Scgd 
10961f28255Scgd next_mon:
11061f28255Scgd 		mtmp->mlstmv = moves;
11161f28255Scgd 
11261f28255Scgd 		/* most monsters drown in pools */
1133ea4a95cSchristos 		{
1143ea4a95cSchristos 			boolean         inpool, iseel;
11561f28255Scgd 
11661f28255Scgd 			inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
11761f28255Scgd 			iseel = (mtmp->data->mlet == ';');
11861f28255Scgd 			if (inpool && !iseel) {
11961f28255Scgd 				if (cansee(mtmp->mx, mtmp->my))
12061f28255Scgd 					pline("%s drowns.", Monnam(mtmp));
12161f28255Scgd 				mondead(mtmp);
12261f28255Scgd 				continue;
12361f28255Scgd 			}
12461f28255Scgd 			/* but eels have a difficult time outside */
12561f28255Scgd 			if (iseel && !inpool) {
1263ea4a95cSchristos 				if (mtmp->mhp > 1)
1273ea4a95cSchristos 					mtmp->mhp--;
12861f28255Scgd 				mtmp->mflee = 1;
12961f28255Scgd 				mtmp->mfleetim += 2;
13061f28255Scgd 			}
13161f28255Scgd 		}
13261f28255Scgd 		if (mtmp->mblinded && !--mtmp->mblinded)
13361f28255Scgd 			mtmp->mcansee = 1;
13461f28255Scgd 		if (mtmp->mfleetim && !--mtmp->mfleetim)
13561f28255Scgd 			mtmp->mflee = 0;
1363ea4a95cSchristos 		if (mtmp->mimic)
1373ea4a95cSchristos 			continue;
13861f28255Scgd 		if (mtmp->mspeed != MSLOW || !(moves % 2)) {
13961f28255Scgd 			/* continue if the monster died fighting */
14061f28255Scgd 			fr = -1;
14161f28255Scgd 			if (Conflict && cansee(mtmp->mx, mtmp->my)
14261f28255Scgd 			    && (fr = fightm(mtmp)) == 2)
14361f28255Scgd 				continue;
14461f28255Scgd 			if (fr < 0 && dochugw(mtmp))
14561f28255Scgd 				continue;
14661f28255Scgd 		}
14761f28255Scgd 		if (mtmp->mspeed == MFAST && dochugw(mtmp))
14861f28255Scgd 			continue;
14961f28255Scgd 	}
15061f28255Scgd 
15161f28255Scgd 	warnlevel -= u.ulevel;
15261f28255Scgd 	if (warnlevel >= SIZE(warnings))
15361f28255Scgd 		warnlevel = SIZE(warnings) - 1;
15461f28255Scgd 	if (warnlevel >= 0)
15561f28255Scgd 		if (warnlevel > lastwarnlev || moves > lastwarntime + 5) {
156ab8b6343Sjsm 			const char           *rr;
15761f28255Scgd 			switch (Warning & (LEFT_RING | RIGHT_RING)) {
15861f28255Scgd 			case LEFT_RING:
15961f28255Scgd 				rr = "Your left ring glows";
16061f28255Scgd 				break;
16161f28255Scgd 			case RIGHT_RING:
16261f28255Scgd 				rr = "Your right ring glows";
16361f28255Scgd 				break;
16461f28255Scgd 			case LEFT_RING | RIGHT_RING:
16561f28255Scgd 				rr = "Both your rings glow";
16661f28255Scgd 				break;
16761f28255Scgd 			default:
16861f28255Scgd 				rr = "Your fingertips glow";
16961f28255Scgd 				break;
17061f28255Scgd 			}
17161f28255Scgd 			pline("%s %s!", rr, warnings[warnlevel]);
17261f28255Scgd 			lastwarntime = moves;
17361f28255Scgd 			lastwarnlev = warnlevel;
17461f28255Scgd 		}
17561f28255Scgd 	dmonsfree();		/* remove all dead monsters */
17661f28255Scgd }
17761f28255Scgd 
1783ea4a95cSchristos void
justswld(struct monst * mtmp,const char * name)1791fa8a9a6Sdholland justswld(struct monst *mtmp, const char *name)
18061f28255Scgd {
18161f28255Scgd 
18261f28255Scgd 	mtmp->mx = u.ux;
18361f28255Scgd 	mtmp->my = u.uy;
18461f28255Scgd 	u.ustuck = mtmp;
18561f28255Scgd 	pmon(mtmp);
18661f28255Scgd 	kludge("%s swallows you!", name);
18761f28255Scgd 	more();
18861f28255Scgd 	seeoff(1);
18961f28255Scgd 	u.uswallow = 1;
19061f28255Scgd 	u.uswldtim = 0;
19161f28255Scgd 	swallowed();
19261f28255Scgd }
19361f28255Scgd 
1943ea4a95cSchristos void
youswld(struct monst * mtmp,int dam,unsigned int die,const char * name)195ab7b7d01Sjoerg youswld(struct monst *mtmp, int dam, unsigned int die, const char *name)
19661f28255Scgd {
1973ea4a95cSchristos 	if (mtmp != u.ustuck)
1983ea4a95cSchristos 		return;
19961f28255Scgd 	kludge("%s digests you!", name);
20061f28255Scgd 	u.uhp -= dam;
20161f28255Scgd 	if (u.uswldtim++ >= die) {	/* a3 */
20261f28255Scgd 		pline("It totally digests you!");
20361f28255Scgd 		u.uhp = -1;
20461f28255Scgd 	}
2053ea4a95cSchristos 	if (u.uhp < 1)
2063ea4a95cSchristos 		done_in_by(mtmp);
2073ea4a95cSchristos #if 0
2083ea4a95cSchristos 	flags.botlx = 1;		/* should we show status line ? */
2093ea4a95cSchristos #endif
21061f28255Scgd }
21161f28255Scgd 
2129b92b189Sdholland static int
dochugw(struct monst * mtmp)2131fa8a9a6Sdholland dochugw(struct monst *mtmp)
2143ea4a95cSchristos {
2153ea4a95cSchristos 	int x = mtmp->mx;
2163ea4a95cSchristos 	int y = mtmp->my;
2173c439f43Sdholland 	int dead = dochug(mtmp);
2183ea4a95cSchristos 	int dd;
2193c439f43Sdholland 
2203c439f43Sdholland 	if (!dead)		/* monster still alive */
22161f28255Scgd 		if (Warning)
22261f28255Scgd 			if (!mtmp->mpeaceful)
22361f28255Scgd 				if (mtmp->data->mlevel > warnlevel)
22461f28255Scgd 					if ((dd = dist(mtmp->mx, mtmp->my)) < dist(x, y))
22561f28255Scgd 						if (dd < 100)
22661f28255Scgd 							if (!canseemon(mtmp))
22761f28255Scgd 								warnlevel = mtmp->data->mlevel;
2283c439f43Sdholland 	return (dead);
22961f28255Scgd }
23061f28255Scgd 
23161f28255Scgd /* returns 1 if monster died moving, 0 otherwise */
2323ea4a95cSchristos int
dochug(struct monst * mtmp)2331fa8a9a6Sdholland dochug(struct monst *mtmp)
23461f28255Scgd {
235ab8b6343Sjsm 	const struct permonst *mdat;
2363ea4a95cSchristos 	int tmp = 0, nearby, scared;
23761f28255Scgd 
23861f28255Scgd 	if (mtmp->cham && !rn2(6))
23961f28255Scgd 		(void) newcham(mtmp, &mons[dlevel + 14 + rn2(CMNUM - 14 - dlevel)]);
24061f28255Scgd 	mdat = mtmp->data;
24161f28255Scgd 	if (mdat->mlevel < 0)
24261f28255Scgd 		panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel);
24361f28255Scgd 
24461f28255Scgd 	/* regenerate monsters */
2453ea4a95cSchristos 	if ((!(moves % 20) || strchr(MREGEN, mdat->mlet)) &&
24661f28255Scgd 	    mtmp->mhp < mtmp->mhpmax)
24761f28255Scgd 		mtmp->mhp++;
24861f28255Scgd 
2493ea4a95cSchristos 	if (mtmp->mfroz)
2503ea4a95cSchristos 		return (0);	/* frozen monsters don't do anything */
25161f28255Scgd 
25261f28255Scgd 	if (mtmp->msleep) {
25361f28255Scgd 		/* wake up, or get out of here. */
25461f28255Scgd 		/* ettins are hard to surprise */
25561f28255Scgd 		/* Nymphs and Leprechauns do not easily wake up */
25661f28255Scgd 		if (cansee(mtmp->mx, mtmp->my) &&
25761f28255Scgd 		    (!Stealth || (mdat->mlet == 'e' && rn2(10))) &&
2583ea4a95cSchristos 		    (!strchr("NL", mdat->mlet) || !rn2(50)) &&
2593ea4a95cSchristos 		    (Aggravate_monster || strchr("d1", mdat->mlet)
26061f28255Scgd 		     || (!rn2(7) && !mtmp->mimic)))
26161f28255Scgd 			mtmp->msleep = 0;
2623ea4a95cSchristos 		else
2633ea4a95cSchristos 			return (0);
26461f28255Scgd 	}
26561f28255Scgd 	/* not frozen or sleeping: wipe out texts written in the dust */
26661f28255Scgd 	wipe_engr_at(mtmp->mx, mtmp->my, 1);
26761f28255Scgd 
26861f28255Scgd 	/* confused monsters get unconfused with small probability */
2693ea4a95cSchristos 	if (mtmp->mconf && !rn2(50))
2703ea4a95cSchristos 		mtmp->mconf = 0;
27161f28255Scgd 
27261f28255Scgd 	/* some monsters teleport */
2733ea4a95cSchristos 	if (mtmp->mflee && strchr("tNL", mdat->mlet) && !rn2(40)) {
27461f28255Scgd 		rloc(mtmp);
27561f28255Scgd 		return (0);
27661f28255Scgd 	}
2773ea4a95cSchristos 	if (mdat->mmove < rnd(6))
2783ea4a95cSchristos 		return (0);
27961f28255Scgd 
28061f28255Scgd 	/* fleeing monsters might regain courage */
28161f28255Scgd 	if (mtmp->mflee && !mtmp->mfleetim
28261f28255Scgd 	    && mtmp->mhp == mtmp->mhpmax && !rn2(25))
28361f28255Scgd 		mtmp->mflee = 0;
28461f28255Scgd 
28561f28255Scgd 	nearby = (dist(mtmp->mx, mtmp->my) < 3);
28661f28255Scgd 	scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) ||
28761f28255Scgd 			     sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)));
28861f28255Scgd 	if (scared && !mtmp->mflee) {
28961f28255Scgd 		mtmp->mflee = 1;
29061f28255Scgd 		mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
29161f28255Scgd 	}
29261f28255Scgd 	if (!nearby ||
29361f28255Scgd 	    mtmp->mflee ||
29461f28255Scgd 	    mtmp->mconf ||
29561f28255Scgd 	    (mtmp->minvis && !rn2(3)) ||
2963ea4a95cSchristos 	    (strchr("BIuy", mdat->mlet) && !rn2(4)) ||
29761f28255Scgd 	    (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
29861f28255Scgd 	    (!mtmp->mcansee && !rn2(4)) ||
29961f28255Scgd 	    mtmp->mpeaceful
30061f28255Scgd 		) {
30161f28255Scgd 		tmp = m_move(mtmp, 0);	/* 2: monster died moving */
30261f28255Scgd 		if (tmp == 2 || (tmp && mdat->mmove <= 12))
30361f28255Scgd 			return (tmp == 2);
30461f28255Scgd 	}
3053ea4a95cSchristos 	if (!strchr("Ea", mdat->mlet) && nearby &&
30661f28255Scgd 	    !mtmp->mpeaceful && u.uhp > 0 && !scared) {
30761f28255Scgd 		if (mhitu(mtmp))
30861f28255Scgd 			return (1);	/* monster died (e.g. 'y' or 'F') */
30961f28255Scgd 	}
31061f28255Scgd 	/* extra movement for fast monsters */
3113ea4a95cSchristos 	if (mdat->mmove - 12 > rnd(12))
3123ea4a95cSchristos 		tmp = m_move(mtmp, 1);
31361f28255Scgd 	return (tmp == 2);
31461f28255Scgd }
31561f28255Scgd 
3163ea4a95cSchristos int
m_move(struct monst * mtmp,int after)317ab8b6343Sjsm m_move(struct monst *mtmp, int after)
31861f28255Scgd {
3193ea4a95cSchristos 	struct monst   *mtmp2;
3203ea4a95cSchristos 	int		nx, ny, omx, omy, appr, nearer, cnt, i, j;
32161f28255Scgd 	xchar           gx, gy, nix, niy, chcnt;
32261f28255Scgd 	schar           chi;
3233ea4a95cSchristos 	boolean         likegold = 0, likegems = 0, likeobjs = 0;
32461f28255Scgd 	char            msym = mtmp->data->mlet;
3253ea4a95cSchristos 	schar           mmoved = 0;	/* not strictly nec.: chi >= 0 will
3263ea4a95cSchristos 					 * do */
32761f28255Scgd 	coord           poss[9];
32861f28255Scgd 	int             info[9];
32961f28255Scgd 
33061f28255Scgd 	if (mtmp->mfroz || mtmp->msleep)
33161f28255Scgd 		return (0);
33261f28255Scgd 	if (mtmp->mtrapped) {
33361f28255Scgd 		i = mintrap(mtmp);
3343ea4a95cSchristos 		if (i == 2)
3353ea4a95cSchristos 			return (2);	/* he died */
3363ea4a95cSchristos 		if (i == 1)
3373ea4a95cSchristos 			return (0);	/* still in trap, so didnt move */
33861f28255Scgd 	}
33961f28255Scgd 	if (mtmp->mhide && o_at(mtmp->mx, mtmp->my) && rn2(10))
34061f28255Scgd 		return (0);	/* do not leave hiding place */
34161f28255Scgd 
34261f28255Scgd #ifndef NOWORM
34361f28255Scgd 	if (mtmp->wormno)
34461f28255Scgd 		goto not_special;
3453ea4a95cSchristos #endif	/* NOWORM */
34661f28255Scgd 
34761f28255Scgd 	/* my dog gets a special treatment */
34861f28255Scgd 	if (mtmp->mtame) {
34961f28255Scgd 		return (dog_move(mtmp, after));
35061f28255Scgd 	}
35161f28255Scgd 	/* likewise for shopkeeper */
35261f28255Scgd 	if (mtmp->isshk) {
35361f28255Scgd 		mmoved = shk_move(mtmp);
35461f28255Scgd 		if (mmoved >= 0)
35561f28255Scgd 			goto postmov;
35661f28255Scgd 		mmoved = 0;	/* follow player outside shop */
35761f28255Scgd 	}
35861f28255Scgd 	/* and for the guard */
35961f28255Scgd 	if (mtmp->isgd) {
36061f28255Scgd 		mmoved = gd_move();
36161f28255Scgd 		goto postmov;
36261f28255Scgd 	}
3633ea4a95cSchristos 	/*
3643ea4a95cSchristos 	 * teleport if that lies in our nature ('t') or when badly wounded
3653ea4a95cSchristos 	 * ('1')
3663ea4a95cSchristos 	 */
36761f28255Scgd 	if ((msym == 't' && !rn2(5))
36861f28255Scgd 	    || (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5))
36961f28255Scgd 				|| levl[u.ux][u.uy].typ == STAIRS))) {
37061f28255Scgd 		if (mtmp->mhp < 7 || (msym == 't' && rn2(2)))
37161f28255Scgd 			rloc(mtmp);
37261f28255Scgd 		else
37361f28255Scgd 			mnexto(mtmp);
37461f28255Scgd 		mmoved = 1;
37561f28255Scgd 		goto postmov;
37661f28255Scgd 	}
37761f28255Scgd 	/* spit fire ('D') or use a wand ('1') when appropriate */
3783ea4a95cSchristos 	if (strchr("D1", msym))
37961f28255Scgd 		inrange(mtmp);
38061f28255Scgd 
38161f28255Scgd 	if (msym == 'U' && !mtmp->mcan && canseemon(mtmp) &&
38261f28255Scgd 	    mtmp->mcansee && rn2(5)) {
38361f28255Scgd 		if (!Confusion)
38461f28255Scgd 			pline("%s's gaze has confused you!", Monnam(mtmp));
38561f28255Scgd 		else
38661f28255Scgd 			pline("You are getting more and more confused.");
3873ea4a95cSchristos 		if (rn2(3))
3883ea4a95cSchristos 			mtmp->mcan = 1;
38961f28255Scgd 		Confusion += d(3, 4);	/* timeout */
39061f28255Scgd 	}
39161f28255Scgd not_special:
3923ea4a95cSchristos 	if (!mtmp->mflee && u.uswallow && u.ustuck != mtmp)
3933ea4a95cSchristos 		return (1);
39461f28255Scgd 	appr = 1;
3953ea4a95cSchristos 	if (mtmp->mflee)
3963ea4a95cSchristos 		appr = -1;
39761f28255Scgd 	if (mtmp->mconf || Invis || !mtmp->mcansee ||
3983ea4a95cSchristos 	    (strchr("BIy", msym) && !rn2(3)))
39961f28255Scgd 		appr = 0;
40061f28255Scgd 	omx = mtmp->mx;
40161f28255Scgd 	omy = mtmp->my;
40261f28255Scgd 	gx = u.ux;
40361f28255Scgd 	gy = u.uy;
40461f28255Scgd 	if (msym == 'L' && appr == 1 && mtmp->mgold > u.ugold)
40561f28255Scgd 		appr = -1;
40661f28255Scgd 
4073ea4a95cSchristos 	/*
4083ea4a95cSchristos 	 * random criterion for 'smell' or track finding ability should use
4093ea4a95cSchristos 	 * mtmp->msmell or sth
41061f28255Scgd 	 */
41161f28255Scgd 	if (msym == '@' ||
41261f28255Scgd 	    ('a' <= msym && msym <= 'z')) {
4133ea4a95cSchristos 		coord          *cp;
41461f28255Scgd 		schar           mroom;
41561f28255Scgd 		mroom = inroom(omx, omy);
41661f28255Scgd 		if (mroom < 0 || mroom != inroom(u.ux, u.uy)) {
41761f28255Scgd 			cp = gettrack(omx, omy);
41861f28255Scgd 			if (cp) {
41961f28255Scgd 				gx = cp->x;
42061f28255Scgd 				gy = cp->y;
42161f28255Scgd 			}
42261f28255Scgd 		}
42361f28255Scgd 	}
42461f28255Scgd 	/* look for gold or jewels nearby */
4253ea4a95cSchristos 	likegold = (strchr("LOD", msym) != NULL);
4263ea4a95cSchristos 	likegems = (strchr("ODu", msym) != NULL);
42761f28255Scgd 	likeobjs = mtmp->mhide;
42861f28255Scgd #define	SRCHRADIUS	25
4293ea4a95cSchristos 	{
4303ea4a95cSchristos 		xchar           mind = SRCHRADIUS;	/* not too far away */
4313ea4a95cSchristos 		int             dd;
43261f28255Scgd 		if (likegold) {
4333ea4a95cSchristos 			struct gold    *gold;
43461f28255Scgd 			for (gold = fgold; gold; gold = gold->ngold)
43561f28255Scgd 				if ((dd = DIST(omx, omy, gold->gx, gold->gy)) < mind) {
43661f28255Scgd 					mind = dd;
43761f28255Scgd 					gx = gold->gx;
43861f28255Scgd 					gy = gold->gy;
43961f28255Scgd 				}
44061f28255Scgd 		}
44161f28255Scgd 		if (likegems || likeobjs) {
4423ea4a95cSchristos 			struct obj     *otmp;
44361f28255Scgd 			for (otmp = fobj; otmp; otmp = otmp->nobj)
44461f28255Scgd 				if (likeobjs || otmp->olet == GEM_SYM)
44561f28255Scgd 					if (msym != 'u' ||
44661f28255Scgd 					    objects[otmp->otyp].g_val != 0)
44761f28255Scgd 						if ((dd = DIST(omx, omy, otmp->ox, otmp->oy)) < mind) {
44861f28255Scgd 							mind = dd;
44961f28255Scgd 							gx = otmp->ox;
45061f28255Scgd 							gy = otmp->oy;
45161f28255Scgd 						}
45261f28255Scgd 		}
45361f28255Scgd 		if (mind < SRCHRADIUS && appr == -1) {
45461f28255Scgd 			if (dist(omx, omy) < 10) {
45561f28255Scgd 				gx = u.ux;
45661f28255Scgd 				gy = u.uy;
45761f28255Scgd 			} else
45861f28255Scgd 				appr = 1;
45961f28255Scgd 		}
46061f28255Scgd 	}
46161f28255Scgd 	nix = omx;
46261f28255Scgd 	niy = omy;
46361f28255Scgd 	cnt = mfndpos(mtmp, poss, info,
46461f28255Scgd 		      msym == 'u' ? NOTONL :
46561f28255Scgd 		  (msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) :
4663ea4a95cSchristos 		      strchr(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS);
46761f28255Scgd 	/* ALLOW_ROCK for some monsters ? */
46861f28255Scgd 	chcnt = 0;
46961f28255Scgd 	chi = -1;
47061f28255Scgd 	for (i = 0; i < cnt; i++) {
47161f28255Scgd 		nx = poss[i].x;
47261f28255Scgd 		ny = poss[i].y;
47361f28255Scgd 		for (j = 0; j < MTSZ && j < cnt - 1; j++)
47461f28255Scgd 			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
4753ea4a95cSchristos 				if (rn2(4 * (cnt - j)))
4763ea4a95cSchristos 					goto nxti;
47761f28255Scgd #ifdef STUPID
47861f28255Scgd 		/* some stupid compilers think that this is too complicated */
4793ea4a95cSchristos 		{
4803ea4a95cSchristos 			int             d1 = DIST(nx, ny, gx, gy);
48161f28255Scgd 			int             d2 = DIST(nix, niy, gx, gy);
48261f28255Scgd 			nearer = (d1 < d2);
48361f28255Scgd 		}
48461f28255Scgd #else
48561f28255Scgd 		nearer = (DIST(nx, ny, gx, gy) < DIST(nix, niy, gx, gy));
4863ea4a95cSchristos #endif	/* STUPID */
48761f28255Scgd 		if ((appr == 1 && nearer) || (appr == -1 && !nearer) ||
48861f28255Scgd 		    !mmoved ||
48961f28255Scgd 		    (!appr && !rn2(++chcnt))) {
49061f28255Scgd 			nix = nx;
49161f28255Scgd 			niy = ny;
49261f28255Scgd 			chi = i;
49361f28255Scgd 			mmoved = 1;
49461f28255Scgd 		}
49561f28255Scgd nxti:		;
49661f28255Scgd 	}
49761f28255Scgd 	if (mmoved) {
49861f28255Scgd 		if (info[chi] & ALLOW_M) {
49961f28255Scgd 			mtmp2 = m_at(nix, niy);
500dce30741Sjnemeth 			if (mtmp2 == NULL)
501dce30741Sjnemeth 				panic("error in m_move");
50261f28255Scgd 			if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
5033ea4a95cSchristos 			    hitmm(mtmp2, mtmp) == 2)
5043ea4a95cSchristos 				return (2);
50561f28255Scgd 			return (0);
50661f28255Scgd 		}
50761f28255Scgd 		if (info[chi] & ALLOW_U) {
50861f28255Scgd 			(void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd) + 1);
50961f28255Scgd 			return (0);
51061f28255Scgd 		}
51161f28255Scgd 		mtmp->mx = nix;
51261f28255Scgd 		mtmp->my = niy;
5133ea4a95cSchristos 		for (j = MTSZ - 1; j > 0; j--)
5143ea4a95cSchristos 			mtmp->mtrack[j] = mtmp->mtrack[j - 1];
51561f28255Scgd 		mtmp->mtrack[0].x = omx;
51661f28255Scgd 		mtmp->mtrack[0].y = omy;
51761f28255Scgd #ifndef NOWORM
5183ea4a95cSchristos 		if (mtmp->wormno)
5193ea4a95cSchristos 			worm_move(mtmp);
5203ea4a95cSchristos #endif	/* NOWORM */
52161f28255Scgd 	} else {
52261f28255Scgd 		if (msym == 'u' && rn2(2)) {
52361f28255Scgd 			rloc(mtmp);
52461f28255Scgd 			return (0);
52561f28255Scgd 		}
52661f28255Scgd #ifndef NOWORM
5273ea4a95cSchristos 		if (mtmp->wormno)
5283ea4a95cSchristos 			worm_nomove(mtmp);
5293ea4a95cSchristos #endif	/* NOWORM */
53061f28255Scgd 	}
53161f28255Scgd postmov:
53261f28255Scgd 	if (mmoved == 1) {
53361f28255Scgd 		if (mintrap(mtmp) == 2)	/* he died */
53461f28255Scgd 			return (2);
5353ea4a95cSchristos 		if (likegold)
5363ea4a95cSchristos 			mpickgold(mtmp);
5373ea4a95cSchristos 		if (likegems)
5383ea4a95cSchristos 			mpickgems(mtmp);
5393ea4a95cSchristos 		if (mtmp->mhide)
5403ea4a95cSchristos 			mtmp->mundetected = 1;
54161f28255Scgd 	}
54261f28255Scgd 	pmon(mtmp);
54361f28255Scgd 	return (mmoved);
54461f28255Scgd }
54561f28255Scgd 
5469b92b189Sdholland static void
mpickgold(struct monst * mtmp)5471fa8a9a6Sdholland mpickgold(struct monst *mtmp)
5483ea4a95cSchristos {
5493ea4a95cSchristos 	struct gold    *gold;
5503ea4a95cSchristos 	while ((gold = g_at(mtmp->mx, mtmp->my)) != NULL) {
55161f28255Scgd 		mtmp->mgold += gold->amount;
55261f28255Scgd 		freegold(gold);
55361f28255Scgd 		if (levl[mtmp->mx][mtmp->my].scrsym == '$')
55461f28255Scgd 			newsym(mtmp->mx, mtmp->my);
55561f28255Scgd 	}
55661f28255Scgd }
55761f28255Scgd 
5589b92b189Sdholland static void
mpickgems(struct monst * mtmp)5591fa8a9a6Sdholland mpickgems(struct monst *mtmp)
5603ea4a95cSchristos {
5613ea4a95cSchristos 	struct obj     *otmp;
56261f28255Scgd 	for (otmp = fobj; otmp; otmp = otmp->nobj)
56361f28255Scgd 		if (otmp->olet == GEM_SYM)
56461f28255Scgd 			if (otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
56561f28255Scgd 				if (mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0) {
56661f28255Scgd 					freeobj(otmp);
56761f28255Scgd 					mpickobj(mtmp, otmp);
56861f28255Scgd 					if (levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
56961f28255Scgd 						newsym(mtmp->mx, mtmp->my);	/* %% */
57061f28255Scgd 					return;	/* pick only one object */
57161f28255Scgd 				}
57261f28255Scgd }
57361f28255Scgd 
57461f28255Scgd /* return number of acceptable neighbour positions */
5753ea4a95cSchristos int
mfndpos(struct monst * mon,coord poss[9],int info[9],int flag)5761fa8a9a6Sdholland mfndpos(struct monst *mon, coord poss[9], int info[9], int flag)
57761f28255Scgd {
5783ea4a95cSchristos 	int             x, y, nx, ny, cnt = 0, ntyp;
5793ea4a95cSchristos 	struct monst   *mtmp;
58061f28255Scgd 	int             nowtyp;
58161f28255Scgd 	boolean         pool;
58261f28255Scgd 
58361f28255Scgd 	x = mon->mx;
58461f28255Scgd 	y = mon->my;
58561f28255Scgd 	nowtyp = levl[x][y].typ;
58661f28255Scgd 
58761f28255Scgd 	pool = (mon->data->mlet == ';');
5883ea4a95cSchristos nexttry:			/* eels prefer the water, but if there is no
5893ea4a95cSchristos 				 * water nearby, they will crawl over land */
59061f28255Scgd 	if (mon->mconf) {
59161f28255Scgd 		flag |= ALLOW_ALL;
59261f28255Scgd 		flag &= ~NOTONL;
59361f28255Scgd 	}
5943ea4a95cSchristos 	for (nx = x - 1; nx <= x + 1; nx++)
5953ea4a95cSchristos 		for (ny = y - 1; ny <= y + 1; ny++)
5963ea4a95cSchristos 			if (nx != x || ny != y)
5973ea4a95cSchristos 				if (isok(nx, ny))
59861f28255Scgd 					if (!IS_ROCK(ntyp = levl[nx][ny].typ))
59961f28255Scgd 						if (!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR)))
60061f28255Scgd 							if ((ntyp == POOL) == pool) {
60161f28255Scgd 								info[cnt] = 0;
60261f28255Scgd 								if (nx == u.ux && ny == u.uy) {
6033ea4a95cSchristos 									if (!(flag & ALLOW_U))
6043ea4a95cSchristos 										continue;
60561f28255Scgd 									info[cnt] = ALLOW_U;
6063ea4a95cSchristos 								} else if ((mtmp = m_at(nx, ny)) != NULL) {
6073ea4a95cSchristos 									if (!(flag & ALLOW_M))
6083ea4a95cSchristos 										continue;
60961f28255Scgd 									info[cnt] = ALLOW_M;
61061f28255Scgd 									if (mtmp->mtame) {
6113ea4a95cSchristos 										if (!(flag & ALLOW_TM))
6123ea4a95cSchristos 											continue;
61361f28255Scgd 										info[cnt] |= ALLOW_TM;
61461f28255Scgd 									}
61561f28255Scgd 								}
61661f28255Scgd 								if (sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
6173ea4a95cSchristos 									if (flag & NOGARLIC)
6183ea4a95cSchristos 										continue;
61961f28255Scgd 									info[cnt] |= NOGARLIC;
62061f28255Scgd 								}
62161f28255Scgd 								if (sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
62261f28255Scgd 								    (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
6233ea4a95cSchristos 									if (!(flag & ALLOW_SSM))
6243ea4a95cSchristos 										continue;
62561f28255Scgd 									info[cnt] |= ALLOW_SSM;
62661f28255Scgd 								}
62761f28255Scgd 								if (sobj_at(ENORMOUS_ROCK, nx, ny)) {
6283ea4a95cSchristos 									if (!(flag & ALLOW_ROCK))
6293ea4a95cSchristos 										continue;
63061f28255Scgd 									info[cnt] |= ALLOW_ROCK;
63161f28255Scgd 								}
63261f28255Scgd 								if (!Invis && online(nx, ny)) {
6333ea4a95cSchristos 									if (flag & NOTONL)
6343ea4a95cSchristos 										continue;
63561f28255Scgd 									info[cnt] |= NOTONL;
63661f28255Scgd 								}
6373ea4a95cSchristos 								/*
6383ea4a95cSchristos 								 * we cannot
6393ea4a95cSchristos 								 * avoid
6403ea4a95cSchristos 								 * traps of
6413ea4a95cSchristos 								 * an unknown
6423ea4a95cSchristos 								 * kind
6433ea4a95cSchristos 								 */
6443ea4a95cSchristos 								{
6453ea4a95cSchristos 									struct trap    *ttmp = t_at(nx, ny);
6463ea4a95cSchristos 									int             tt;
64761f28255Scgd 									if (ttmp) {
64861f28255Scgd 										tt = 1 << ttmp->ttyp;
64961f28255Scgd 										if (mon->mtrapseen & tt) {
6503ea4a95cSchristos 											if (!(flag & tt))
6513ea4a95cSchristos 												continue;
65261f28255Scgd 											info[cnt] |= tt;
65361f28255Scgd 										}
65461f28255Scgd 									}
65561f28255Scgd 								}
65661f28255Scgd 								poss[cnt].x = nx;
65761f28255Scgd 								poss[cnt].y = ny;
65861f28255Scgd 								cnt++;
65961f28255Scgd 							}
66061f28255Scgd 	if (!cnt && pool && nowtyp != POOL) {
66161f28255Scgd 		pool = FALSE;
66261f28255Scgd 		goto nexttry;
66361f28255Scgd 	}
66461f28255Scgd 	return (cnt);
66561f28255Scgd }
66661f28255Scgd 
6673ea4a95cSchristos int
dist(int x,int y)6681fa8a9a6Sdholland dist(int x, int y)
6693ea4a95cSchristos {
67061f28255Scgd 	return ((x - u.ux) * (x - u.ux) + (y - u.uy) * (y - u.uy));
67161f28255Scgd }
67261f28255Scgd 
6733ea4a95cSchristos void
poisoned(const char * string,const char * pname)6741fa8a9a6Sdholland poisoned(const char *string, const char *pname)
67561f28255Scgd {
6763ea4a95cSchristos 	int             i;
67761f28255Scgd 
6783ea4a95cSchristos 	if (Blind)
6793ea4a95cSchristos 		pline("It was poisoned.");
6803ea4a95cSchristos 	else
6813ea4a95cSchristos 		pline("The %s was poisoned!", string);
68261f28255Scgd 	if (Poison_resistance) {
68361f28255Scgd 		pline("The poison doesn't seem to affect you.");
68461f28255Scgd 		return;
68561f28255Scgd 	}
68661f28255Scgd 	i = rn2(10);
68761f28255Scgd 	if (i == 0) {
68861f28255Scgd 		u.uhp = -1;
68961f28255Scgd 		pline("I am afraid the poison was deadly ...");
69061f28255Scgd 	} else if (i <= 5) {
69161f28255Scgd 		losestr(rn1(3, 3));
69261f28255Scgd 	} else {
69361f28255Scgd 		losehp(rn1(10, 6), pname);
69461f28255Scgd 	}
69561f28255Scgd 	if (u.uhp < 1) {
69661f28255Scgd 		killer = pname;
69761f28255Scgd 		done("died");
69861f28255Scgd 	}
69961f28255Scgd }
70061f28255Scgd 
7013ea4a95cSchristos void
mondead(struct monst * mtmp)7021fa8a9a6Sdholland mondead(struct monst *mtmp)
70361f28255Scgd {
70461f28255Scgd 	relobj(mtmp, 1);
70561f28255Scgd 	unpmon(mtmp);
70661f28255Scgd 	relmon(mtmp);
70761f28255Scgd 	unstuck(mtmp);
7083ea4a95cSchristos 	if (mtmp->isshk)
7093ea4a95cSchristos 		shkdead(mtmp);
7103ea4a95cSchristos 	if (mtmp->isgd)
7113ea4a95cSchristos 		gddead();
71261f28255Scgd #ifndef NOWORM
7133ea4a95cSchristos 	if (mtmp->wormno)
7143ea4a95cSchristos 		wormdead(mtmp);
7153ea4a95cSchristos #endif	/* NOWORM */
71661f28255Scgd 	monfree(mtmp);
71761f28255Scgd }
71861f28255Scgd 
71961f28255Scgd /* called when monster is moved to larger structure */
7203ea4a95cSchristos void
replmon(struct monst * mtmp,struct monst * mtmp2)7211fa8a9a6Sdholland replmon(struct monst *mtmp, struct monst *mtmp2)
72261f28255Scgd {
72361f28255Scgd 	relmon(mtmp);
72461f28255Scgd 	monfree(mtmp);
72561f28255Scgd 	mtmp2->nmon = fmon;
72661f28255Scgd 	fmon = mtmp2;
7273ea4a95cSchristos 	if (u.ustuck == mtmp)
7283ea4a95cSchristos 		u.ustuck = mtmp2;
7293ea4a95cSchristos 	if (mtmp2->isshk)
7303ea4a95cSchristos 		replshk(mtmp, mtmp2);
7313ea4a95cSchristos 	if (mtmp2->isgd)
7323ea4a95cSchristos 		replgd(mtmp, mtmp2);
73361f28255Scgd }
73461f28255Scgd 
7353ea4a95cSchristos void
relmon(struct monst * mon)7361fa8a9a6Sdholland relmon(struct monst *mon)
73761f28255Scgd {
7383ea4a95cSchristos 	struct monst   *mtmp;
73961f28255Scgd 
7403ea4a95cSchristos 	if (mon == fmon)
7413ea4a95cSchristos 		fmon = fmon->nmon;
74261f28255Scgd 	else {
74361f28255Scgd 		for (mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon);
74461f28255Scgd 		mtmp->nmon = mon->nmon;
74561f28255Scgd 	}
74661f28255Scgd }
74761f28255Scgd 
7483ea4a95cSchristos /*
7493ea4a95cSchristos  * we do not free monsters immediately, in order to have their name available
7503ea4a95cSchristos  * shortly after their demise
7513ea4a95cSchristos  */
7529b92b189Sdholland static struct monst *fdmon;	/* chain of dead monsters, need not to be
7533ea4a95cSchristos 				 * saved */
75461f28255Scgd 
7553ea4a95cSchristos void
monfree(struct monst * mtmp)7561fa8a9a6Sdholland monfree(struct monst *mtmp)
7573ea4a95cSchristos {
75861f28255Scgd 	mtmp->nmon = fdmon;
75961f28255Scgd 	fdmon = mtmp;
76061f28255Scgd }
76161f28255Scgd 
7629b92b189Sdholland static void
dmonsfree(void)7631fa8a9a6Sdholland dmonsfree(void)
7643ea4a95cSchristos {
7653ea4a95cSchristos 	struct monst   *mtmp;
7663ea4a95cSchristos 	while ((mtmp = fdmon) != NULL) {
76761f28255Scgd 		fdmon = mtmp->nmon;
7688e73b3adSdholland 		free(mtmp);
76961f28255Scgd 	}
77061f28255Scgd }
77161f28255Scgd 
7723ea4a95cSchristos void
unstuck(struct monst * mtmp)7731fa8a9a6Sdholland unstuck(struct monst *mtmp)
77461f28255Scgd {
77561f28255Scgd 	if (u.ustuck == mtmp) {
77661f28255Scgd 		if (u.uswallow) {
77761f28255Scgd 			u.ux = mtmp->mx;
77861f28255Scgd 			u.uy = mtmp->my;
77961f28255Scgd 			u.uswallow = 0;
78061f28255Scgd 			setsee();
78161f28255Scgd 			docrt();
78261f28255Scgd 		}
78361f28255Scgd 		u.ustuck = 0;
78461f28255Scgd 	}
78561f28255Scgd }
78661f28255Scgd 
7873ea4a95cSchristos void
killed(struct monst * mtmp)7881fa8a9a6Sdholland killed(struct monst *mtmp)
78961f28255Scgd {
79061f28255Scgd #ifdef lint
79161f28255Scgd #define	NEW_SCORING
7923ea4a95cSchristos #endif	/* lint */
7933ea4a95cSchristos 	int             tmp, nk, x, y;
794ab8b6343Sjsm 	const struct permonst *mdat;
79561f28255Scgd 
7963ea4a95cSchristos 	if (mtmp->cham)
7973ea4a95cSchristos 		mtmp->data = PM_CHAMELEON;
79861f28255Scgd 	mdat = mtmp->data;
7993ea4a95cSchristos 	if (Blind)
8003ea4a95cSchristos 		pline("You destroy it!");
80161f28255Scgd 	else {
80261f28255Scgd 		pline("You destroy %s!",
80361f28255Scgd 		      mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
80461f28255Scgd 	}
80561f28255Scgd 	if (u.umconf) {
8063ea4a95cSchristos 		if (!Blind)
8073ea4a95cSchristos 			pline("Your hands stop glowing blue.");
80861f28255Scgd 		u.umconf = 0;
80961f28255Scgd 	}
81061f28255Scgd 	/* count killed monsters */
81161f28255Scgd #define	MAXMONNO	100
81261f28255Scgd 	nk = 1;			/* in case we cannot find it in mons */
8133ea4a95cSchristos 	tmp = mdat - mons;	/* strchr in mons array (if not 'd', '@', ...) */
81461f28255Scgd 	if (tmp >= 0 && tmp < CMNUM + 2) {
81561f28255Scgd 		u.nr_killed[tmp]++;
81661f28255Scgd 		if ((nk = u.nr_killed[tmp]) > MAXMONNO &&
8173ea4a95cSchristos 		    !strchr(fut_geno, mdat->mlet))
81861f28255Scgd 			charcat(fut_geno, mdat->mlet);
81961f28255Scgd 	}
82061f28255Scgd 	/* punish bad behaviour */
8213ea4a95cSchristos 	if (mdat->mlet == '@')
8223ea4a95cSchristos 		Telepat = 0, u.uluck -= 2;
8233ea4a95cSchristos 	if (mtmp->mpeaceful || mtmp->mtame)
8243ea4a95cSchristos 		u.uluck--;
8253ea4a95cSchristos 	if (mdat->mlet == 'u')
8263ea4a95cSchristos 		u.uluck -= 5;
8273ea4a95cSchristos 	if ((int) u.uluck < LUCKMIN)
8283ea4a95cSchristos 		u.uluck = LUCKMIN;
82961f28255Scgd 
83061f28255Scgd 	/* give experience points */
83161f28255Scgd 	tmp = 1 + mdat->mlevel * mdat->mlevel;
8323ea4a95cSchristos 	if (mdat->ac < 3)
8333ea4a95cSchristos 		tmp += 2 * (7 - mdat->ac);
8343ea4a95cSchristos 	if (strchr("AcsSDXaeRTVWU&In:P", mdat->mlet))
83561f28255Scgd 		tmp += 2 * mdat->mlevel;
8363ea4a95cSchristos 	if (strchr("DeV&P", mdat->mlet))
8373ea4a95cSchristos 		tmp += (7 * mdat->mlevel);
8383ea4a95cSchristos 	if (mdat->mlevel > 6)
8393ea4a95cSchristos 		tmp += 50;
8403ea4a95cSchristos 	if (mdat->mlet == ';')
8413ea4a95cSchristos 		tmp += 1000;
84261f28255Scgd 
84361f28255Scgd #ifdef NEW_SCORING
8443ea4a95cSchristos 	/*
8453ea4a95cSchristos 	 * ------- recent addition: make nr of points decrease when this is
8463ea4a95cSchristos 	 * not the first of this kind
8473ea4a95cSchristos 	 */
8483ea4a95cSchristos 	{
8493ea4a95cSchristos 		int             ul = u.ulevel;
85061f28255Scgd 		int             ml = mdat->mlevel;
851*d5b021c7Sdholland 		int tmp2;
85261f28255Scgd 
8533ea4a95cSchristos 		if (ul < 14)	/* points are given based on present and
8543ea4a95cSchristos 				 * future level */
85561f28255Scgd 			for (tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
85661f28255Scgd 				if (u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4 << (tmp2 - 1))) / nk
85761f28255Scgd 				    >= 10 * pow((unsigned) (ul - 1)))
8583ea4a95cSchristos 					if (++ul == 14)
8593ea4a95cSchristos 						break;
86061f28255Scgd 
86161f28255Scgd 		tmp2 = ml - ul - 1;
86261f28255Scgd 		tmp = (tmp + ((tmp2 < 0) ? 0 : 4 << tmp2)) / nk;
8633ea4a95cSchristos 		if (!tmp)
8643ea4a95cSchristos 			tmp = 1;
86561f28255Scgd 	}
86661f28255Scgd 	/* note: ul is not necessarily the future value of u.ulevel */
86761f28255Scgd 	/* ------- end of recent valuation change ------- */
8683ea4a95cSchristos #endif	/* NEW_SCORING */
86961f28255Scgd 
87061f28255Scgd 	more_experienced(tmp, 0);
87161f28255Scgd 	flags.botl = 1;
87261f28255Scgd 	while (u.ulevel < 14 && u.uexp >= newuexp()) {
87361f28255Scgd 		pline("Welcome to experience level %u.", ++u.ulevel);
87461f28255Scgd 		tmp = rnd(10);
8753ea4a95cSchristos 		if (tmp < 3)
8763ea4a95cSchristos 			tmp = rnd(10);
87761f28255Scgd 		u.uhpmax += tmp;
87861f28255Scgd 		u.uhp += tmp;
87961f28255Scgd 		flags.botl = 1;
88061f28255Scgd 	}
88161f28255Scgd 
88261f28255Scgd 	/* dispose of monster and make cadaver */
8833ea4a95cSchristos 	x = mtmp->mx;
8843ea4a95cSchristos 	y = mtmp->my;
88561f28255Scgd 	mondead(mtmp);
88661f28255Scgd 	tmp = mdat->mlet;
8873ea4a95cSchristos 	if (tmp == 'm') {	/* he killed a minotaur, give him a wand of
8883ea4a95cSchristos 				 * digging */
88961f28255Scgd 		/* note: the dead minotaur will be on top of it! */
89061f28255Scgd 		mksobj_at(WAN_DIGGING, x, y);
89161f28255Scgd 		/* if(cansee(x,y)) atl(x,y,fobj->olet); */
89261f28255Scgd 		stackobj(fobj);
89361f28255Scgd 	} else
89461f28255Scgd #ifndef NOWORM
89561f28255Scgd 	if (tmp == 'w') {
89661f28255Scgd 		mksobj_at(WORM_TOOTH, x, y);
89761f28255Scgd 		stackobj(fobj);
89861f28255Scgd 	} else
8993ea4a95cSchristos #endif	/* NOWORM */
9003ea4a95cSchristos 	if (!letter(tmp) || (!strchr("mw", tmp) && !rn2(3)))
9013ea4a95cSchristos 		tmp = 0;
90261f28255Scgd 
90361f28255Scgd 	if (ACCESSIBLE(levl[x][y].typ))	/* might be mimic in wall or dead eel */
9043ea4a95cSchristos 		if (x != u.ux || y != u.uy)	/* might be here after
9053ea4a95cSchristos 						 * swallowed */
9063ea4a95cSchristos 			if (strchr("NTVm&", mdat->mlet) || rn2(5)) {
9073ea4a95cSchristos 				struct obj     *obj2 = mkobj_at(tmp, x, y);
90861f28255Scgd 				if (cansee(x, y))
90961f28255Scgd 					atl(x, y, obj2->olet);
91061f28255Scgd 				stackobj(obj2);
91161f28255Scgd 			}
91261f28255Scgd }
91361f28255Scgd 
9143ea4a95cSchristos void
kludge(const char * str,const char * arg)915ab8b6343Sjsm kludge(const char *str, const char *arg)
91661f28255Scgd {
91761f28255Scgd 	if (Blind) {
9183ea4a95cSchristos 		if (*str == '%')
9193ea4a95cSchristos 			pline(str, "It");
9203ea4a95cSchristos 		else
9213ea4a95cSchristos 			pline(str, "it");
9223ea4a95cSchristos 	} else
9233ea4a95cSchristos 		pline(str, arg);
92461f28255Scgd }
92561f28255Scgd 
9263ea4a95cSchristos void
rescham(void)9271fa8a9a6Sdholland rescham(void)
9283ea4a95cSchristos {				/* force all chameleons to become normal */
9293ea4a95cSchristos 	struct monst   *mtmp;
93061f28255Scgd 
93161f28255Scgd 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
93261f28255Scgd 		if (mtmp->cham) {
93361f28255Scgd 			mtmp->cham = 0;
93461f28255Scgd 			(void) newcham(mtmp, PM_CHAMELEON);
93561f28255Scgd 		}
93661f28255Scgd }
93761f28255Scgd 
9381fa8a9a6Sdholland /* make a chameleon look like a new monster */
93961f28255Scgd /* returns 1 if the monster actually changed */
9401fa8a9a6Sdholland int
newcham(struct monst * mtmp,const struct permonst * mdat)9411fa8a9a6Sdholland newcham(struct monst *mtmp, const struct permonst *mdat)
94261f28255Scgd {
9433ea4a95cSchristos 	int mhp, hpn, hpd;
94461f28255Scgd 
9453ea4a95cSchristos 	if (mdat == mtmp->data)
9463ea4a95cSchristos 		return (0);	/* still the same monster */
94761f28255Scgd #ifndef NOWORM
9483ea4a95cSchristos 	if (mtmp->wormno)
9493ea4a95cSchristos 		wormdead(mtmp);	/* throw tail away */
9503ea4a95cSchristos #endif	/* NOWORM */
95161f28255Scgd 	if (u.ustuck == mtmp) {
95261f28255Scgd 		if (u.uswallow) {
95361f28255Scgd 			u.uswallow = 0;
95461f28255Scgd 			u.uswldtim = 0;
95561f28255Scgd 			mnexto(mtmp);
95661f28255Scgd 			docrt();
95761f28255Scgd 			prme();
95861f28255Scgd 		}
95961f28255Scgd 		u.ustuck = 0;
96061f28255Scgd 	}
96161f28255Scgd 	hpn = mtmp->mhp;
96261f28255Scgd 	hpd = (mtmp->data->mlevel) * 8;
9633ea4a95cSchristos 	if (!hpd)
9643ea4a95cSchristos 		hpd = 4;
96561f28255Scgd 	mtmp->data = mdat;
96661f28255Scgd 	mhp = (mdat->mlevel) * 8;
96761f28255Scgd 	/* new hp: same fraction of max as before */
96861f28255Scgd 	mtmp->mhp = 2 + (hpn * mhp) / hpd;
96961f28255Scgd 	hpn = mtmp->mhpmax;
97061f28255Scgd 	mtmp->mhpmax = 2 + (hpn * mhp) / hpd;
97161f28255Scgd 	mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
97261f28255Scgd #ifndef NOWORM
9733ea4a95cSchristos 	if (mdat->mlet == 'w' && getwn(mtmp))
9743ea4a95cSchristos 		initworm(mtmp);
97561f28255Scgd 	/* perhaps we should clear mtmp->mtame here? */
9763ea4a95cSchristos #endif	/* NOWORM */
97761f28255Scgd 	unpmon(mtmp);		/* necessary for 'I' and to force pmon */
97861f28255Scgd 	pmon(mtmp);
97961f28255Scgd 	return (1);
98061f28255Scgd }
98161f28255Scgd 
9821fa8a9a6Sdholland /* Make monster mtmp next to you (if possible) */
9833ea4a95cSchristos void
mnexto(struct monst * mtmp)9841fa8a9a6Sdholland mnexto(struct monst *mtmp)
98561f28255Scgd {
98661f28255Scgd 	coord           mm;
98761f28255Scgd 	mm = enexto(u.ux, u.uy);
98861f28255Scgd 	mtmp->mx = mm.x;
98961f28255Scgd 	mtmp->my = mm.y;
99061f28255Scgd 	pmon(mtmp);
99161f28255Scgd }
99261f28255Scgd 
9939b92b189Sdholland static int
ishuman(struct monst * mtmp)9941fa8a9a6Sdholland ishuman(struct monst *mtmp)
9953ea4a95cSchristos {
99661f28255Scgd 	return (mtmp->data->mlet == '@');
99761f28255Scgd }
99861f28255Scgd 
9993ea4a95cSchristos void
setmangry(struct monst * mtmp)10001fa8a9a6Sdholland setmangry(struct monst *mtmp)
10013ea4a95cSchristos {
10023ea4a95cSchristos 	if (!mtmp->mpeaceful)
10033ea4a95cSchristos 		return;
10043ea4a95cSchristos 	if (mtmp->mtame)
10053ea4a95cSchristos 		return;
100661f28255Scgd 	mtmp->mpeaceful = 0;
10073ea4a95cSchristos 	if (ishuman(mtmp))
10083ea4a95cSchristos 		pline("%s gets angry!", Monnam(mtmp));
100961f28255Scgd }
101061f28255Scgd 
10113ea4a95cSchristos /*
10123ea4a95cSchristos  * not one hundred procent correct: now a snake may hide under an invisible
10133ea4a95cSchristos  * object
10143ea4a95cSchristos  */
10153ea4a95cSchristos int
canseemon(struct monst * mtmp)10161fa8a9a6Sdholland canseemon(struct monst *mtmp)
101761f28255Scgd {
101861f28255Scgd 	return ((!mtmp->minvis || See_invisible)
101961f28255Scgd 		&& (!mtmp->mhide || !o_at(mtmp->mx, mtmp->my))
102061f28255Scgd 		&& cansee(mtmp->mx, mtmp->my));
102161f28255Scgd }
1022