File: | src/games/hack/hack.mon.c |
Warning: | line 503, column 6 Branch condition evaluates to a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
69 | int warnlevel; /* used by movemon and dochugw */ | |||
70 | long lastwarntime; | |||
71 | int lastwarnlev; | |||
72 | char *warnings[] = { | |||
73 | "white", "pink", "red", "ruby", "purple", "black" | |||
74 | }; | |||
75 | ||||
76 | static int dochugw(struct monst *); | |||
77 | static void mpickgold(struct monst *); | |||
78 | static void mpickgems(struct monst *); | |||
79 | static void dmonsfree(void); | |||
80 | static int ishuman(struct monst *); | |||
81 | ||||
82 | void | |||
83 | movemon(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 | ||||
167 | void | |||
168 | justswld(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 | ||||
182 | void | |||
183 | youswld(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 | ||||
196 | static int | |||
197 | dochugw(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 */ | |||
216 | int | |||
217 | dochug(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 | ||||
298 | int | |||
299 | m_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 | } | |||
370 | not_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 | } | |||
499 | postmov: | |||
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 | ||||
511 | static void | |||
512 | mpickgold(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 | ||||
524 | static void | |||
525 | mpickgems(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 */ | |||
542 | int | |||
543 | mfndpos(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 == ';'); | |||
555 | nexttry: /* 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 | ||||
618 | int | |||
619 | dist(int x, int y) | |||
620 | { | |||
621 | return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy)); | |||
622 | } | |||
623 | ||||
624 | void | |||
625 | poisoned(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 | ||||
650 | void | |||
651 | mondead(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 */ | |||
666 | void | |||
667 | replmon(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 | ||||
678 | void | |||
679 | relmon(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 */ | |||
692 | struct monst *fdmon; /* chain of dead monsters, need not to be saved */ | |||
693 | ||||
694 | void | |||
695 | monfree(struct monst *mtmp) | |||
696 | { | |||
697 | mtmp->nmon = fdmon; | |||
698 | fdmon = mtmp; | |||
699 | } | |||
700 | ||||
701 | static void | |||
702 | dmonsfree(void) | |||
703 | { | |||
704 | struct monst *mtmp; | |||
705 | ||||
706 | while ((mtmp = fdmon)) { | |||
707 | fdmon = mtmp->nmon; | |||
708 | free(mtmp); | |||
709 | } | |||
710 | } | |||
711 | ||||
712 | void | |||
713 | unstuck(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 | ||||
727 | void | |||
728 | killed(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 && | |||
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 | ||||
832 | void | |||
833 | kludge(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 | ||||
841 | void | |||
842 | rescham(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 */ | |||
855 | int | |||
856 | newcham(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) */ | |||
894 | void | |||
895 | mnexto(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 | ||||
904 | static int | |||
905 | ishuman(struct monst *mtmp) | |||
906 | { | |||
907 | return(mtmp->data->mlet == '@'); | |||
908 | } | |||
909 | ||||
910 | void | |||
911 | setmangry(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 */ | |||
921 | int | |||
922 | canseemon(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 | } |