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