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