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