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