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