Home | History | Annotate | Line # | Download | only in hack
      1 /*	$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
      5  * Amsterdam
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions are
     10  * met:
     11  *
     12  * - Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * - Redistributions in binary form must reproduce the above copyright
     16  * notice, this list of conditions and the following disclaimer in the
     17  * documentation and/or other materials provided with the distribution.
     18  *
     19  * - Neither the name of the Stichting Centrum voor Wiskunde en
     20  * Informatica, nor the names of its contributors may be used to endorse or
     21  * promote products derived from this software without specific prior
     22  * written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  */
     36 
     37 /*
     38  * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org>
     39  * All rights reserved.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. The name of the author may not be used to endorse or promote products
     50  *    derived from this software without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
     55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 __RCSID("$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $");
     67 #endif				/* not lint */
     68 
     69 #include <stdlib.h>
     70 #include "hack.h"
     71 #include "extern.h"
     72 #include "hack.mfndpos.h"
     73 
     74 static int warnlevel;	/* used by movemon and dochugw */
     75 static long lastwarntime;
     76 static int lastwarnlev;
     77 
     78 static const char *const warnings[] = {
     79 	"white", "pink", "red", "ruby", "purple", "black"
     80 };
     81 
     82 static int dochugw(struct monst *);
     83 static void mpickgold(struct monst *);
     84 static void mpickgems(struct monst *);
     85 static void dmonsfree(void);
     86 static int ishuman(struct monst *);
     87 
     88 void
     89 movemon(void)
     90 {
     91 	struct monst   *mtmp;
     92 	int             fr;
     93 
     94 	warnlevel = 0;
     95 
     96 	while (1) {
     97 		/* find a monster that we haven't treated yet */
     98 		/*
     99 		 * note that mtmp or mtmp->nmon might get killed while mtmp
    100 		 * moves, so we cannot just walk down the chain (even new
    101 		 * monsters might get created!)
    102 		 */
    103 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
    104 			if (mtmp->mlstmv < moves)
    105 				goto next_mon;
    106 		/* treated all monsters */
    107 		break;
    108 
    109 next_mon:
    110 		mtmp->mlstmv = moves;
    111 
    112 		/* most monsters drown in pools */
    113 		{
    114 			boolean         inpool, iseel;
    115 
    116 			inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
    117 			iseel = (mtmp->data->mlet == ';');
    118 			if (inpool && !iseel) {
    119 				if (cansee(mtmp->mx, mtmp->my))
    120 					pline("%s drowns.", Monnam(mtmp));
    121 				mondead(mtmp);
    122 				continue;
    123 			}
    124 			/* but eels have a difficult time outside */
    125 			if (iseel && !inpool) {
    126 				if (mtmp->mhp > 1)
    127 					mtmp->mhp--;
    128 				mtmp->mflee = 1;
    129 				mtmp->mfleetim += 2;
    130 			}
    131 		}
    132 		if (mtmp->mblinded && !--mtmp->mblinded)
    133 			mtmp->mcansee = 1;
    134 		if (mtmp->mfleetim && !--mtmp->mfleetim)
    135 			mtmp->mflee = 0;
    136 		if (mtmp->mimic)
    137 			continue;
    138 		if (mtmp->mspeed != MSLOW || !(moves % 2)) {
    139 			/* continue if the monster died fighting */
    140 			fr = -1;
    141 			if (Conflict && cansee(mtmp->mx, mtmp->my)
    142 			    && (fr = fightm(mtmp)) == 2)
    143 				continue;
    144 			if (fr < 0 && dochugw(mtmp))
    145 				continue;
    146 		}
    147 		if (mtmp->mspeed == MFAST && dochugw(mtmp))
    148 			continue;
    149 	}
    150 
    151 	warnlevel -= u.ulevel;
    152 	if (warnlevel >= SIZE(warnings))
    153 		warnlevel = SIZE(warnings) - 1;
    154 	if (warnlevel >= 0)
    155 		if (warnlevel > lastwarnlev || moves > lastwarntime + 5) {
    156 			const char           *rr;
    157 			switch (Warning & (LEFT_RING | RIGHT_RING)) {
    158 			case LEFT_RING:
    159 				rr = "Your left ring glows";
    160 				break;
    161 			case RIGHT_RING:
    162 				rr = "Your right ring glows";
    163 				break;
    164 			case LEFT_RING | RIGHT_RING:
    165 				rr = "Both your rings glow";
    166 				break;
    167 			default:
    168 				rr = "Your fingertips glow";
    169 				break;
    170 			}
    171 			pline("%s %s!", rr, warnings[warnlevel]);
    172 			lastwarntime = moves;
    173 			lastwarnlev = warnlevel;
    174 		}
    175 	dmonsfree();		/* remove all dead monsters */
    176 }
    177 
    178 void
    179 justswld(struct monst *mtmp, const char *name)
    180 {
    181 
    182 	mtmp->mx = u.ux;
    183 	mtmp->my = u.uy;
    184 	u.ustuck = mtmp;
    185 	pmon(mtmp);
    186 	kludge("%s swallows you!", name);
    187 	more();
    188 	seeoff(1);
    189 	u.uswallow = 1;
    190 	u.uswldtim = 0;
    191 	swallowed();
    192 }
    193 
    194 void
    195 youswld(struct monst *mtmp, int dam, unsigned int die, const char *name)
    196 {
    197 	if (mtmp != u.ustuck)
    198 		return;
    199 	kludge("%s digests you!", name);
    200 	u.uhp -= dam;
    201 	if (u.uswldtim++ >= die) {	/* a3 */
    202 		pline("It totally digests you!");
    203 		u.uhp = -1;
    204 	}
    205 	if (u.uhp < 1)
    206 		done_in_by(mtmp);
    207 #if 0
    208 	flags.botlx = 1;		/* should we show status line ? */
    209 #endif
    210 }
    211 
    212 static int
    213 dochugw(struct monst *mtmp)
    214 {
    215 	int x = mtmp->mx;
    216 	int y = mtmp->my;
    217 	int dead = dochug(mtmp);
    218 	int dd;
    219 
    220 	if (!dead)		/* monster still alive */
    221 		if (Warning)
    222 			if (!mtmp->mpeaceful)
    223 				if (mtmp->data->mlevel > warnlevel)
    224 					if ((dd = dist(mtmp->mx, mtmp->my)) < dist(x, y))
    225 						if (dd < 100)
    226 							if (!canseemon(mtmp))
    227 								warnlevel = mtmp->data->mlevel;
    228 	return (dead);
    229 }
    230 
    231 /* returns 1 if monster died moving, 0 otherwise */
    232 int
    233 dochug(struct monst *mtmp)
    234 {
    235 	const struct permonst *mdat;
    236 	int tmp = 0, nearby, scared;
    237 
    238 	if (mtmp->cham && !rn2(6))
    239 		(void) newcham(mtmp, &mons[dlevel + 14 + rn2(CMNUM - 14 - dlevel)]);
    240 	mdat = mtmp->data;
    241 	if (mdat->mlevel < 0)
    242 		panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel);
    243 
    244 	/* regenerate monsters */
    245 	if ((!(moves % 20) || strchr(MREGEN, mdat->mlet)) &&
    246 	    mtmp->mhp < mtmp->mhpmax)
    247 		mtmp->mhp++;
    248 
    249 	if (mtmp->mfroz)
    250 		return (0);	/* frozen monsters don't do anything */
    251 
    252 	if (mtmp->msleep) {
    253 		/* wake up, or get out of here. */
    254 		/* ettins are hard to surprise */
    255 		/* Nymphs and Leprechauns do not easily wake up */
    256 		if (cansee(mtmp->mx, mtmp->my) &&
    257 		    (!Stealth || (mdat->mlet == 'e' && rn2(10))) &&
    258 		    (!strchr("NL", mdat->mlet) || !rn2(50)) &&
    259 		    (Aggravate_monster || strchr("d1", mdat->mlet)
    260 		     || (!rn2(7) && !mtmp->mimic)))
    261 			mtmp->msleep = 0;
    262 		else
    263 			return (0);
    264 	}
    265 	/* not frozen or sleeping: wipe out texts written in the dust */
    266 	wipe_engr_at(mtmp->mx, mtmp->my, 1);
    267 
    268 	/* confused monsters get unconfused with small probability */
    269 	if (mtmp->mconf && !rn2(50))
    270 		mtmp->mconf = 0;
    271 
    272 	/* some monsters teleport */
    273 	if (mtmp->mflee && strchr("tNL", mdat->mlet) && !rn2(40)) {
    274 		rloc(mtmp);
    275 		return (0);
    276 	}
    277 	if (mdat->mmove < rnd(6))
    278 		return (0);
    279 
    280 	/* fleeing monsters might regain courage */
    281 	if (mtmp->mflee && !mtmp->mfleetim
    282 	    && mtmp->mhp == mtmp->mhpmax && !rn2(25))
    283 		mtmp->mflee = 0;
    284 
    285 	nearby = (dist(mtmp->mx, mtmp->my) < 3);
    286 	scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) ||
    287 			     sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)));
    288 	if (scared && !mtmp->mflee) {
    289 		mtmp->mflee = 1;
    290 		mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
    291 	}
    292 	if (!nearby ||
    293 	    mtmp->mflee ||
    294 	    mtmp->mconf ||
    295 	    (mtmp->minvis && !rn2(3)) ||
    296 	    (strchr("BIuy", mdat->mlet) && !rn2(4)) ||
    297 	    (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
    298 	    (!mtmp->mcansee && !rn2(4)) ||
    299 	    mtmp->mpeaceful
    300 		) {
    301 		tmp = m_move(mtmp, 0);	/* 2: monster died moving */
    302 		if (tmp == 2 || (tmp && mdat->mmove <= 12))
    303 			return (tmp == 2);
    304 	}
    305 	if (!strchr("Ea", mdat->mlet) && nearby &&
    306 	    !mtmp->mpeaceful && u.uhp > 0 && !scared) {
    307 		if (mhitu(mtmp))
    308 			return (1);	/* monster died (e.g. 'y' or 'F') */
    309 	}
    310 	/* extra movement for fast monsters */
    311 	if (mdat->mmove - 12 > rnd(12))
    312 		tmp = m_move(mtmp, 1);
    313 	return (tmp == 2);
    314 }
    315 
    316 int
    317 m_move(struct monst *mtmp, int after)
    318 {
    319 	struct monst   *mtmp2;
    320 	int		nx, ny, omx, omy, appr, nearer, cnt, i, j;
    321 	xchar           gx, gy, nix, niy, chcnt;
    322 	schar           chi;
    323 	boolean         likegold = 0, likegems = 0, likeobjs = 0;
    324 	char            msym = mtmp->data->mlet;
    325 	schar           mmoved = 0;	/* not strictly nec.: chi >= 0 will
    326 					 * do */
    327 	coord           poss[9];
    328 	int             info[9];
    329 
    330 	if (mtmp->mfroz || mtmp->msleep)
    331 		return (0);
    332 	if (mtmp->mtrapped) {
    333 		i = mintrap(mtmp);
    334 		if (i == 2)
    335 			return (2);	/* he died */
    336 		if (i == 1)
    337 			return (0);	/* still in trap, so didnt move */
    338 	}
    339 	if (mtmp->mhide && o_at(mtmp->mx, mtmp->my) && rn2(10))
    340 		return (0);	/* do not leave hiding place */
    341 
    342 #ifndef NOWORM
    343 	if (mtmp->wormno)
    344 		goto not_special;
    345 #endif	/* NOWORM */
    346 
    347 	/* my dog gets a special treatment */
    348 	if (mtmp->mtame) {
    349 		return (dog_move(mtmp, after));
    350 	}
    351 	/* likewise for shopkeeper */
    352 	if (mtmp->isshk) {
    353 		mmoved = shk_move(mtmp);
    354 		if (mmoved >= 0)
    355 			goto postmov;
    356 		mmoved = 0;	/* follow player outside shop */
    357 	}
    358 	/* and for the guard */
    359 	if (mtmp->isgd) {
    360 		mmoved = gd_move();
    361 		goto postmov;
    362 	}
    363 	/*
    364 	 * teleport if that lies in our nature ('t') or when badly wounded
    365 	 * ('1')
    366 	 */
    367 	if ((msym == 't' && !rn2(5))
    368 	    || (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5))
    369 				|| levl[u.ux][u.uy].typ == STAIRS))) {
    370 		if (mtmp->mhp < 7 || (msym == 't' && rn2(2)))
    371 			rloc(mtmp);
    372 		else
    373 			mnexto(mtmp);
    374 		mmoved = 1;
    375 		goto postmov;
    376 	}
    377 	/* spit fire ('D') or use a wand ('1') when appropriate */
    378 	if (strchr("D1", msym))
    379 		inrange(mtmp);
    380 
    381 	if (msym == 'U' && !mtmp->mcan && canseemon(mtmp) &&
    382 	    mtmp->mcansee && rn2(5)) {
    383 		if (!Confusion)
    384 			pline("%s's gaze has confused you!", Monnam(mtmp));
    385 		else
    386 			pline("You are getting more and more confused.");
    387 		if (rn2(3))
    388 			mtmp->mcan = 1;
    389 		Confusion += d(3, 4);	/* timeout */
    390 	}
    391 not_special:
    392 	if (!mtmp->mflee && u.uswallow && u.ustuck != mtmp)
    393 		return (1);
    394 	appr = 1;
    395 	if (mtmp->mflee)
    396 		appr = -1;
    397 	if (mtmp->mconf || Invis || !mtmp->mcansee ||
    398 	    (strchr("BIy", msym) && !rn2(3)))
    399 		appr = 0;
    400 	omx = mtmp->mx;
    401 	omy = mtmp->my;
    402 	gx = u.ux;
    403 	gy = u.uy;
    404 	if (msym == 'L' && appr == 1 && mtmp->mgold > u.ugold)
    405 		appr = -1;
    406 
    407 	/*
    408 	 * random criterion for 'smell' or track finding ability should use
    409 	 * mtmp->msmell or sth
    410 	 */
    411 	if (msym == '@' ||
    412 	    ('a' <= msym && msym <= 'z')) {
    413 		coord          *cp;
    414 		schar           mroom;
    415 		mroom = inroom(omx, omy);
    416 		if (mroom < 0 || mroom != inroom(u.ux, u.uy)) {
    417 			cp = gettrack(omx, omy);
    418 			if (cp) {
    419 				gx = cp->x;
    420 				gy = cp->y;
    421 			}
    422 		}
    423 	}
    424 	/* look for gold or jewels nearby */
    425 	likegold = (strchr("LOD", msym) != NULL);
    426 	likegems = (strchr("ODu", msym) != NULL);
    427 	likeobjs = mtmp->mhide;
    428 #define	SRCHRADIUS	25
    429 	{
    430 		xchar           mind = SRCHRADIUS;	/* not too far away */
    431 		int             dd;
    432 		if (likegold) {
    433 			struct gold    *gold;
    434 			for (gold = fgold; gold; gold = gold->ngold)
    435 				if ((dd = DIST(omx, omy, gold->gx, gold->gy)) < mind) {
    436 					mind = dd;
    437 					gx = gold->gx;
    438 					gy = gold->gy;
    439 				}
    440 		}
    441 		if (likegems || likeobjs) {
    442 			struct obj     *otmp;
    443 			for (otmp = fobj; otmp; otmp = otmp->nobj)
    444 				if (likeobjs || otmp->olet == GEM_SYM)
    445 					if (msym != 'u' ||
    446 					    objects[otmp->otyp].g_val != 0)
    447 						if ((dd = DIST(omx, omy, otmp->ox, otmp->oy)) < mind) {
    448 							mind = dd;
    449 							gx = otmp->ox;
    450 							gy = otmp->oy;
    451 						}
    452 		}
    453 		if (mind < SRCHRADIUS && appr == -1) {
    454 			if (dist(omx, omy) < 10) {
    455 				gx = u.ux;
    456 				gy = u.uy;
    457 			} else
    458 				appr = 1;
    459 		}
    460 	}
    461 	nix = omx;
    462 	niy = omy;
    463 	cnt = mfndpos(mtmp, poss, info,
    464 		      msym == 'u' ? NOTONL :
    465 		  (msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) :
    466 		      strchr(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS);
    467 	/* ALLOW_ROCK for some monsters ? */
    468 	chcnt = 0;
    469 	chi = -1;
    470 	for (i = 0; i < cnt; i++) {
    471 		nx = poss[i].x;
    472 		ny = poss[i].y;
    473 		for (j = 0; j < MTSZ && j < cnt - 1; j++)
    474 			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
    475 				if (rn2(4 * (cnt - j)))
    476 					goto nxti;
    477 #ifdef STUPID
    478 		/* some stupid compilers think that this is too complicated */
    479 		{
    480 			int             d1 = DIST(nx, ny, gx, gy);
    481 			int             d2 = DIST(nix, niy, gx, gy);
    482 			nearer = (d1 < d2);
    483 		}
    484 #else
    485 		nearer = (DIST(nx, ny, gx, gy) < DIST(nix, niy, gx, gy));
    486 #endif	/* STUPID */
    487 		if ((appr == 1 && nearer) || (appr == -1 && !nearer) ||
    488 		    !mmoved ||
    489 		    (!appr && !rn2(++chcnt))) {
    490 			nix = nx;
    491 			niy = ny;
    492 			chi = i;
    493 			mmoved = 1;
    494 		}
    495 nxti:		;
    496 	}
    497 	if (mmoved) {
    498 		if (info[chi] & ALLOW_M) {
    499 			mtmp2 = m_at(nix, niy);
    500 			if (mtmp2 == NULL)
    501 				panic("error in m_move");
    502 			if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
    503 			    hitmm(mtmp2, mtmp) == 2)
    504 				return (2);
    505 			return (0);
    506 		}
    507 		if (info[chi] & ALLOW_U) {
    508 			(void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd) + 1);
    509 			return (0);
    510 		}
    511 		mtmp->mx = nix;
    512 		mtmp->my = niy;
    513 		for (j = MTSZ - 1; j > 0; j--)
    514 			mtmp->mtrack[j] = mtmp->mtrack[j - 1];
    515 		mtmp->mtrack[0].x = omx;
    516 		mtmp->mtrack[0].y = omy;
    517 #ifndef NOWORM
    518 		if (mtmp->wormno)
    519 			worm_move(mtmp);
    520 #endif	/* NOWORM */
    521 	} else {
    522 		if (msym == 'u' && rn2(2)) {
    523 			rloc(mtmp);
    524 			return (0);
    525 		}
    526 #ifndef NOWORM
    527 		if (mtmp->wormno)
    528 			worm_nomove(mtmp);
    529 #endif	/* NOWORM */
    530 	}
    531 postmov:
    532 	if (mmoved == 1) {
    533 		if (mintrap(mtmp) == 2)	/* he died */
    534 			return (2);
    535 		if (likegold)
    536 			mpickgold(mtmp);
    537 		if (likegems)
    538 			mpickgems(mtmp);
    539 		if (mtmp->mhide)
    540 			mtmp->mundetected = 1;
    541 	}
    542 	pmon(mtmp);
    543 	return (mmoved);
    544 }
    545 
    546 static void
    547 mpickgold(struct monst *mtmp)
    548 {
    549 	struct gold    *gold;
    550 	while ((gold = g_at(mtmp->mx, mtmp->my)) != NULL) {
    551 		mtmp->mgold += gold->amount;
    552 		freegold(gold);
    553 		if (levl[mtmp->mx][mtmp->my].scrsym == '$')
    554 			newsym(mtmp->mx, mtmp->my);
    555 	}
    556 }
    557 
    558 static void
    559 mpickgems(struct monst *mtmp)
    560 {
    561 	struct obj     *otmp;
    562 	for (otmp = fobj; otmp; otmp = otmp->nobj)
    563 		if (otmp->olet == GEM_SYM)
    564 			if (otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
    565 				if (mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0) {
    566 					freeobj(otmp);
    567 					mpickobj(mtmp, otmp);
    568 					if (levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM)
    569 						newsym(mtmp->mx, mtmp->my);	/* %% */
    570 					return;	/* pick only one object */
    571 				}
    572 }
    573 
    574 /* return number of acceptable neighbour positions */
    575 int
    576 mfndpos(struct monst *mon, coord poss[9], int info[9], int flag)
    577 {
    578 	int             x, y, nx, ny, cnt = 0, ntyp;
    579 	struct monst   *mtmp;
    580 	int             nowtyp;
    581 	boolean         pool;
    582 
    583 	x = mon->mx;
    584 	y = mon->my;
    585 	nowtyp = levl[x][y].typ;
    586 
    587 	pool = (mon->data->mlet == ';');
    588 nexttry:			/* eels prefer the water, but if there is no
    589 				 * water nearby, they will crawl over land */
    590 	if (mon->mconf) {
    591 		flag |= ALLOW_ALL;
    592 		flag &= ~NOTONL;
    593 	}
    594 	for (nx = x - 1; nx <= x + 1; nx++)
    595 		for (ny = y - 1; ny <= y + 1; ny++)
    596 			if (nx != x || ny != y)
    597 				if (isok(nx, ny))
    598 					if (!IS_ROCK(ntyp = levl[nx][ny].typ))
    599 						if (!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR)))
    600 							if ((ntyp == POOL) == pool) {
    601 								info[cnt] = 0;
    602 								if (nx == u.ux && ny == u.uy) {
    603 									if (!(flag & ALLOW_U))
    604 										continue;
    605 									info[cnt] = ALLOW_U;
    606 								} else if ((mtmp = m_at(nx, ny)) != NULL) {
    607 									if (!(flag & ALLOW_M))
    608 										continue;
    609 									info[cnt] = ALLOW_M;
    610 									if (mtmp->mtame) {
    611 										if (!(flag & ALLOW_TM))
    612 											continue;
    613 										info[cnt] |= ALLOW_TM;
    614 									}
    615 								}
    616 								if (sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
    617 									if (flag & NOGARLIC)
    618 										continue;
    619 									info[cnt] |= NOGARLIC;
    620 								}
    621 								if (sobj_at(SCR_SCARE_MONSTER, nx, ny) ||
    622 								    (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) {
    623 									if (!(flag & ALLOW_SSM))
    624 										continue;
    625 									info[cnt] |= ALLOW_SSM;
    626 								}
    627 								if (sobj_at(ENORMOUS_ROCK, nx, ny)) {
    628 									if (!(flag & ALLOW_ROCK))
    629 										continue;
    630 									info[cnt] |= ALLOW_ROCK;
    631 								}
    632 								if (!Invis && online(nx, ny)) {
    633 									if (flag & NOTONL)
    634 										continue;
    635 									info[cnt] |= NOTONL;
    636 								}
    637 								/*
    638 								 * we cannot
    639 								 * avoid
    640 								 * traps of
    641 								 * an unknown
    642 								 * kind
    643 								 */
    644 								{
    645 									struct trap    *ttmp = t_at(nx, ny);
    646 									int             tt;
    647 									if (ttmp) {
    648 										tt = 1 << ttmp->ttyp;
    649 										if (mon->mtrapseen & tt) {
    650 											if (!(flag & tt))
    651 												continue;
    652 											info[cnt] |= tt;
    653 										}
    654 									}
    655 								}
    656 								poss[cnt].x = nx;
    657 								poss[cnt].y = ny;
    658 								cnt++;
    659 							}
    660 	if (!cnt && pool && nowtyp != POOL) {
    661 		pool = FALSE;
    662 		goto nexttry;
    663 	}
    664 	return (cnt);
    665 }
    666 
    667 int
    668 dist(int x, int y)
    669 {
    670 	return ((x - u.ux) * (x - u.ux) + (y - u.uy) * (y - u.uy));
    671 }
    672 
    673 void
    674 poisoned(const char *string, const char *pname)
    675 {
    676 	int             i;
    677 
    678 	if (Blind)
    679 		pline("It was poisoned.");
    680 	else
    681 		pline("The %s was poisoned!", string);
    682 	if (Poison_resistance) {
    683 		pline("The poison doesn't seem to affect you.");
    684 		return;
    685 	}
    686 	i = rn2(10);
    687 	if (i == 0) {
    688 		u.uhp = -1;
    689 		pline("I am afraid the poison was deadly ...");
    690 	} else if (i <= 5) {
    691 		losestr(rn1(3, 3));
    692 	} else {
    693 		losehp(rn1(10, 6), pname);
    694 	}
    695 	if (u.uhp < 1) {
    696 		killer = pname;
    697 		done("died");
    698 	}
    699 }
    700 
    701 void
    702 mondead(struct monst *mtmp)
    703 {
    704 	relobj(mtmp, 1);
    705 	unpmon(mtmp);
    706 	relmon(mtmp);
    707 	unstuck(mtmp);
    708 	if (mtmp->isshk)
    709 		shkdead(mtmp);
    710 	if (mtmp->isgd)
    711 		gddead();
    712 #ifndef NOWORM
    713 	if (mtmp->wormno)
    714 		wormdead(mtmp);
    715 #endif	/* NOWORM */
    716 	monfree(mtmp);
    717 }
    718 
    719 /* called when monster is moved to larger structure */
    720 void
    721 replmon(struct monst *mtmp, struct monst *mtmp2)
    722 {
    723 	relmon(mtmp);
    724 	monfree(mtmp);
    725 	mtmp2->nmon = fmon;
    726 	fmon = mtmp2;
    727 	if (u.ustuck == mtmp)
    728 		u.ustuck = mtmp2;
    729 	if (mtmp2->isshk)
    730 		replshk(mtmp, mtmp2);
    731 	if (mtmp2->isgd)
    732 		replgd(mtmp, mtmp2);
    733 }
    734 
    735 void
    736 relmon(struct monst *mon)
    737 {
    738 	struct monst   *mtmp;
    739 
    740 	if (mon == fmon)
    741 		fmon = fmon->nmon;
    742 	else {
    743 		for (mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon);
    744 		mtmp->nmon = mon->nmon;
    745 	}
    746 }
    747 
    748 /*
    749  * we do not free monsters immediately, in order to have their name available
    750  * shortly after their demise
    751  */
    752 static struct monst *fdmon;	/* chain of dead monsters, need not to be
    753 				 * saved */
    754 
    755 void
    756 monfree(struct monst *mtmp)
    757 {
    758 	mtmp->nmon = fdmon;
    759 	fdmon = mtmp;
    760 }
    761 
    762 static void
    763 dmonsfree(void)
    764 {
    765 	struct monst   *mtmp;
    766 	while ((mtmp = fdmon) != NULL) {
    767 		fdmon = mtmp->nmon;
    768 		free(mtmp);
    769 	}
    770 }
    771 
    772 void
    773 unstuck(struct monst *mtmp)
    774 {
    775 	if (u.ustuck == mtmp) {
    776 		if (u.uswallow) {
    777 			u.ux = mtmp->mx;
    778 			u.uy = mtmp->my;
    779 			u.uswallow = 0;
    780 			setsee();
    781 			docrt();
    782 		}
    783 		u.ustuck = 0;
    784 	}
    785 }
    786 
    787 void
    788 killed(struct monst *mtmp)
    789 {
    790 #ifdef lint
    791 #define	NEW_SCORING
    792 #endif	/* lint */
    793 	int             tmp, nk, x, y;
    794 	const struct permonst *mdat;
    795 
    796 	if (mtmp->cham)
    797 		mtmp->data = PM_CHAMELEON;
    798 	mdat = mtmp->data;
    799 	if (Blind)
    800 		pline("You destroy it!");
    801 	else {
    802 		pline("You destroy %s!",
    803 		      mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp));
    804 	}
    805 	if (u.umconf) {
    806 		if (!Blind)
    807 			pline("Your hands stop glowing blue.");
    808 		u.umconf = 0;
    809 	}
    810 	/* count killed monsters */
    811 #define	MAXMONNO	100
    812 	nk = 1;			/* in case we cannot find it in mons */
    813 	tmp = mdat - mons;	/* strchr in mons array (if not 'd', '@', ...) */
    814 	if (tmp >= 0 && tmp < CMNUM + 2) {
    815 		u.nr_killed[tmp]++;
    816 		if ((nk = u.nr_killed[tmp]) > MAXMONNO &&
    817 		    !strchr(fut_geno, mdat->mlet))
    818 			charcat(fut_geno, mdat->mlet);
    819 	}
    820 	/* punish bad behaviour */
    821 	if (mdat->mlet == '@')
    822 		Telepat = 0, u.uluck -= 2;
    823 	if (mtmp->mpeaceful || mtmp->mtame)
    824 		u.uluck--;
    825 	if (mdat->mlet == 'u')
    826 		u.uluck -= 5;
    827 	if ((int) u.uluck < LUCKMIN)
    828 		u.uluck = LUCKMIN;
    829 
    830 	/* give experience points */
    831 	tmp = 1 + mdat->mlevel * mdat->mlevel;
    832 	if (mdat->ac < 3)
    833 		tmp += 2 * (7 - mdat->ac);
    834 	if (strchr("AcsSDXaeRTVWU&In:P", mdat->mlet))
    835 		tmp += 2 * mdat->mlevel;
    836 	if (strchr("DeV&P", mdat->mlet))
    837 		tmp += (7 * mdat->mlevel);
    838 	if (mdat->mlevel > 6)
    839 		tmp += 50;
    840 	if (mdat->mlet == ';')
    841 		tmp += 1000;
    842 
    843 #ifdef NEW_SCORING
    844 	/*
    845 	 * ------- recent addition: make nr of points decrease when this is
    846 	 * not the first of this kind
    847 	 */
    848 	{
    849 		int             ul = u.ulevel;
    850 		int             ml = mdat->mlevel;
    851 		int tmp2;
    852 
    853 		if (ul < 14)	/* points are given based on present and
    854 				 * future level */
    855 			for (tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
    856 				if (u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4 << (tmp2 - 1))) / nk
    857 				    >= 10 * pow((unsigned) (ul - 1)))
    858 					if (++ul == 14)
    859 						break;
    860 
    861 		tmp2 = ml - ul - 1;
    862 		tmp = (tmp + ((tmp2 < 0) ? 0 : 4 << tmp2)) / nk;
    863 		if (!tmp)
    864 			tmp = 1;
    865 	}
    866 	/* note: ul is not necessarily the future value of u.ulevel */
    867 	/* ------- end of recent valuation change ------- */
    868 #endif	/* NEW_SCORING */
    869 
    870 	more_experienced(tmp, 0);
    871 	flags.botl = 1;
    872 	while (u.ulevel < 14 && u.uexp >= newuexp()) {
    873 		pline("Welcome to experience level %u.", ++u.ulevel);
    874 		tmp = rnd(10);
    875 		if (tmp < 3)
    876 			tmp = rnd(10);
    877 		u.uhpmax += tmp;
    878 		u.uhp += tmp;
    879 		flags.botl = 1;
    880 	}
    881 
    882 	/* dispose of monster and make cadaver */
    883 	x = mtmp->mx;
    884 	y = mtmp->my;
    885 	mondead(mtmp);
    886 	tmp = mdat->mlet;
    887 	if (tmp == 'm') {	/* he killed a minotaur, give him a wand of
    888 				 * digging */
    889 		/* note: the dead minotaur will be on top of it! */
    890 		mksobj_at(WAN_DIGGING, x, y);
    891 		/* if(cansee(x,y)) atl(x,y,fobj->olet); */
    892 		stackobj(fobj);
    893 	} else
    894 #ifndef NOWORM
    895 	if (tmp == 'w') {
    896 		mksobj_at(WORM_TOOTH, x, y);
    897 		stackobj(fobj);
    898 	} else
    899 #endif	/* NOWORM */
    900 	if (!letter(tmp) || (!strchr("mw", tmp) && !rn2(3)))
    901 		tmp = 0;
    902 
    903 	if (ACCESSIBLE(levl[x][y].typ))	/* might be mimic in wall or dead eel */
    904 		if (x != u.ux || y != u.uy)	/* might be here after
    905 						 * swallowed */
    906 			if (strchr("NTVm&", mdat->mlet) || rn2(5)) {
    907 				struct obj     *obj2 = mkobj_at(tmp, x, y);
    908 				if (cansee(x, y))
    909 					atl(x, y, obj2->olet);
    910 				stackobj(obj2);
    911 			}
    912 }
    913 
    914 void
    915 kludge(const char *str, const char *arg)
    916 {
    917 	if (Blind) {
    918 		if (*str == '%')
    919 			pline(str, "It");
    920 		else
    921 			pline(str, "it");
    922 	} else
    923 		pline(str, arg);
    924 }
    925 
    926 void
    927 rescham(void)
    928 {				/* force all chameleons to become normal */
    929 	struct monst   *mtmp;
    930 
    931 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
    932 		if (mtmp->cham) {
    933 			mtmp->cham = 0;
    934 			(void) newcham(mtmp, PM_CHAMELEON);
    935 		}
    936 }
    937 
    938 /* make a chameleon look like a new monster */
    939 /* returns 1 if the monster actually changed */
    940 int
    941 newcham(struct monst *mtmp, const struct permonst *mdat)
    942 {
    943 	int mhp, hpn, hpd;
    944 
    945 	if (mdat == mtmp->data)
    946 		return (0);	/* still the same monster */
    947 #ifndef NOWORM
    948 	if (mtmp->wormno)
    949 		wormdead(mtmp);	/* throw tail away */
    950 #endif	/* NOWORM */
    951 	if (u.ustuck == mtmp) {
    952 		if (u.uswallow) {
    953 			u.uswallow = 0;
    954 			u.uswldtim = 0;
    955 			mnexto(mtmp);
    956 			docrt();
    957 			prme();
    958 		}
    959 		u.ustuck = 0;
    960 	}
    961 	hpn = mtmp->mhp;
    962 	hpd = (mtmp->data->mlevel) * 8;
    963 	if (!hpd)
    964 		hpd = 4;
    965 	mtmp->data = mdat;
    966 	mhp = (mdat->mlevel) * 8;
    967 	/* new hp: same fraction of max as before */
    968 	mtmp->mhp = 2 + (hpn * mhp) / hpd;
    969 	hpn = mtmp->mhpmax;
    970 	mtmp->mhpmax = 2 + (hpn * mhp) / hpd;
    971 	mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0;
    972 #ifndef NOWORM
    973 	if (mdat->mlet == 'w' && getwn(mtmp))
    974 		initworm(mtmp);
    975 	/* perhaps we should clear mtmp->mtame here? */
    976 #endif	/* NOWORM */
    977 	unpmon(mtmp);		/* necessary for 'I' and to force pmon */
    978 	pmon(mtmp);
    979 	return (1);
    980 }
    981 
    982 /* Make monster mtmp next to you (if possible) */
    983 void
    984 mnexto(struct monst *mtmp)
    985 {
    986 	coord           mm;
    987 	mm = enexto(u.ux, u.uy);
    988 	mtmp->mx = mm.x;
    989 	mtmp->my = mm.y;
    990 	pmon(mtmp);
    991 }
    992 
    993 static int
    994 ishuman(struct monst *mtmp)
    995 {
    996 	return (mtmp->data->mlet == '@');
    997 }
    998 
    999 void
   1000 setmangry(struct monst *mtmp)
   1001 {
   1002 	if (!mtmp->mpeaceful)
   1003 		return;
   1004 	if (mtmp->mtame)
   1005 		return;
   1006 	mtmp->mpeaceful = 0;
   1007 	if (ishuman(mtmp))
   1008 		pline("%s gets angry!", Monnam(mtmp));
   1009 }
   1010 
   1011 /*
   1012  * not one hundred procent correct: now a snake may hide under an invisible
   1013  * object
   1014  */
   1015 int
   1016 canseemon(struct monst *mtmp)
   1017 {
   1018 	return ((!mtmp->minvis || See_invisible)
   1019 		&& (!mtmp->mhide || !o_at(mtmp->mx, mtmp->my))
   1020 		&& cansee(mtmp->mx, mtmp->my));
   1021 }
   1022