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