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