Bug Summary

File:src/games/hack/hack.mon.c
Warning:line 752, column 10
Although the value stored to 'nk' is used in the enclosing expression, the value is never actually read from 'nk'

Annotated Source Code

Press '?' to see keyboard shortcuts

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