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