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