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