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