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