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@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
movemon(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
justswld(struct monst * mtmp,const char * name)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
youswld(struct monst * mtmp,int dam,unsigned int die,const char * name)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
dochugw(struct monst * mtmp)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
dochug(struct monst * mtmp)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
m_move(struct monst * mtmp,int after)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
mpickgold(struct monst * mtmp)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
mpickgems(struct monst * mtmp)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
mfndpos(struct monst * mon,coord poss[9],int info[9],int flag)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
dist(int x,int y)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
poisoned(const char * string,const char * pname)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
mondead(struct monst * mtmp)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
replmon(struct monst * mtmp,struct monst * mtmp2)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
relmon(struct monst * mon)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
monfree(struct monst * mtmp)756 monfree(struct monst *mtmp)
757 {
758           mtmp->nmon = fdmon;
759           fdmon = mtmp;
760 }
761 
762 static void
dmonsfree(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
unstuck(struct monst * mtmp)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
killed(struct monst * mtmp)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
kludge(const char * str,const char * arg)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
rescham(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
newcham(struct monst * mtmp,const struct permonst * mdat)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
mnexto(struct monst * mtmp)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
ishuman(struct monst * mtmp)994 ishuman(struct monst *mtmp)
995 {
996           return (mtmp->data->mlet == '@');
997 }
998 
999 void
setmangry(struct monst * mtmp)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
canseemon(struct monst * mtmp)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