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