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