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