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