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