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