(linenum→info "unix/slp.c:2238")

bsd-games/2.17/hack/hack.mon.c

    1: /*      $NetBSD: hack.mon.c,v 1.6 2003/04/02 18:36:38 jsm 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 <sys/cdefs.h>
   65: #ifndef lint
   66: __RCSID("$NetBSD: hack.mon.c,v 1.6 2003/04/02 18:36:38 jsm Exp $");
   67: #endif                          /* not lint */
   68: 
   69: #include <stdlib.h>
   70: #include "hack.h"
   71: #include "extern.h"
   72: #include "hack.mfndpos.h"
   73: 
   74: #ifndef NULL
   75: #define NULL    (char *) 0
   76: #endif
   77: 
   78: int             warnlevel;      /* used by movemon and dochugw */
   79: long            lastwarntime;
   80: int             lastwarnlev;
   81: const char           *const warnings[] = {
   82:         "white", "pink", "red", "ruby", "purple", "black"
   83: };
   84: 
   85: void
   86: movemon()
   87: {
   88:         struct monst   *mtmp;
   89:         int             fr;
   90: 
   91:         warnlevel = 0;
   92: 
   93:         while (1) {
   94:                 /* find a monster that we haven't treated yet */
   95:                 /*
   96:                  * note that mtmp or mtmp->nmon might get killed while mtmp
   97:                  * moves, so we cannot just walk down the chain (even new
   98:                  * monsters might get created!)
   99:                  */
  100:                 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  101:                         if (mtmp->mlstmv < moves)
  102:                                 goto next_mon;
  103:                 /* treated all monsters */
  104:                 break;
  105: 
  106: next_mon:
  107:                 mtmp->mlstmv = moves;
  108: 
  109:                 /* most monsters drown in pools */
  110:                 {
  111:                         boolean         inpool, iseel;
  112: 
  113:                         inpool = (levl[mtmp->mx][mtmp->my].typ == POOL);
  114:                         iseel = (mtmp->data->mlet == ';');
  115:                         if (inpool && !iseel) {
  116:                                 if (cansee(mtmp->mx, mtmp->my))
  117:                                         pline("%s drowns.", Monnam(mtmp));
  118:                                 mondead(mtmp);
  119:                                 continue;
  120:                         }
  121:                         /* but eels have a difficult time outside */
  122:                         if (iseel && !inpool) {
  123:                                 if (mtmp->mhp > 1)
  124:                                         mtmp->mhp--;
  125:                                 mtmp->mflee = 1;
  126:                                 mtmp->mfleetim += 2;
  127:                         }
  128:                 }
  129:                 if (mtmp->mblinded && !--mtmp->mblinded)
  130:                         mtmp->mcansee = 1;
  131:                 if (mtmp->mfleetim && !--mtmp->mfleetim)
  132:                         mtmp->mflee = 0;
  133:                 if (mtmp->mimic)
  134:                         continue;
  135:                 if (mtmp->mspeed != MSLOW || !(moves % 2)) {
  136:                         /* continue if the monster died fighting */
  137:                         fr = -1;
  138:                         if (Conflict && cansee(mtmp->mx, mtmp->my)
  139:                             && (fr = fightm(mtmp)) == 2)
  140:                                 continue;
  141:                         if (fr < 0 && dochugw(mtmp))
  142:                                 continue;
  143:                 }
  144:                 if (mtmp->mspeed == MFAST && dochugw(mtmp))
  145:                         continue;
  146:         }
  147: 
  148:         warnlevel -= u.ulevel;
  149:         if (warnlevel >= SIZE(warnings))
  150:                 warnlevel = SIZE(warnings) - 1;
  151:         if (warnlevel >= 0)
  152:                 if (warnlevel > lastwarnlev || moves > lastwarntime + 5) {
  153:                         const char           *rr;
  154:                         switch (Warning & (LEFT_RING | RIGHT_RING)) {
  155:                         case LEFT_RING:
  156:                                 rr = "Your left ring glows";
  157:                                 break;
  158:                         case RIGHT_RING:
  159:                                 rr = "Your right ring glows";
  160:                                 break;
  161:                         case LEFT_RING | RIGHT_RING:
  162:                                 rr = "Both your rings glow";
  163:                                 break;
  164:                         default:
  165:                                 rr = "Your fingertips glow";
  166:                                 break;
  167:                         }
  168:                         pline("%s %s!", rr, warnings[warnlevel]);
  169:                         lastwarntime = moves;
  170:                         lastwarnlev = warnlevel;
  171:                 }
  172:         dmonsfree();           /* remove all dead monsters */
  173: }
  174: 
  175: void
  176: justswld(mtmp, name)
  177:         struct monst   *mtmp;
  178:         const char           *name;
  179: {
  180: 
  181:         mtmp->mx = u.ux;
  182:         mtmp->my = u.uy;
  183:         u.ustuck = mtmp;
  184:         pmon(mtmp);
  185:         kludge("%s swallows you!", name);
  186:         more();
  187:         seeoff(1);
  188:         u.uswallow = 1;
  189:         u.uswldtim = 0;
  190:         swallowed();
  191: }
  192: 
  193: void
  194: youswld(mtmp, dam, die, name)
  195:         struct monst   *mtmp;
  196:         int            dam, die;
  197:         const char           *name;
  198: {
  199:         if (mtmp != u.ustuck)
  200:                 return;
  201:         kludge("%s digests you!", name);
  202:         u.uhp -= dam;
  203:         if ((int)u.uswldtim++ >= die) {        /* a3 */
  204:                 pline("It totally digests you!");
  205:                 u.uhp = -1;
  206:         }
  207:         if (u.uhp < 1)
  208:                 done_in_by(mtmp);
  209: #if 0
  210:         flags.botlx = 1;               /* should we show status line ? */
  211: #endif
  212: }
  213: 
  214: int
  215: dochugw(mtmp)
  216:         struct monst   *mtmp;
  217: {
  218:         int x = mtmp->mx;
  219:         int y = mtmp->my;
  220:         int d = dochug(mtmp);
  221:         int dd;
  222:         if (!d)                        /* monster still alive */
  223:                 if (Warning)
  224:                         if (!mtmp->mpeaceful)
  225:                                 if (mtmp->data->mlevel > warnlevel)
  226:                                         if ((dd = dist(mtmp->mx, mtmp->my)) < dist(x, y))
  227:                                                 if (dd < 100)
  228:                                                         if (!canseemon(mtmp))
  229:                                                                 warnlevel = mtmp->data->mlevel;
  230:         return (d);
  231: }
  232: 
  233: /* returns 1 if monster died moving, 0 otherwise */
  234: int
  235: dochug(mtmp)
  236:         struct monst   *mtmp;
  237: {
  238:         const struct permonst *mdat;
  239:         int tmp = 0, nearby, scared;
  240: 
  241:         if (mtmp->cham && !rn2(6))
  242:                 (void) newcham(mtmp, &mons[dlevel + 14 + rn2(CMNUM - 14 - dlevel)]);
  243:         mdat = mtmp->data;
  244:         if (mdat->mlevel < 0)
  245:                 panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel);
  246: 
  247:         /* regenerate monsters */
  248:         if ((!(moves % 20) || strchr(MREGEN, mdat->mlet)) &&
  249:             mtmp->mhp < mtmp->mhpmax)
  250:                 mtmp->mhp++;
  251: 
  252:         if (mtmp->mfroz)
  253:                 return (0);   /* frozen monsters don't do anything */
  254: 
  255:         if (mtmp->msleep) {
  256:                 /* wake up, or get out of here. */
  257:                 /* ettins are hard to surprise */
  258:                 /* Nymphs and Leprechauns do not easily wake up */
  259:                 if (cansee(mtmp->mx, mtmp->my) &&
  260:                     (!Stealth || (mdat->mlet == 'e' && rn2(10))) &&
  261:                     (!strchr("NL", mdat->mlet) || !rn2(50)) &&
  262:                     (Aggravate_monster || strchr("d1", mdat->mlet)
  263:                      || (!rn2(7) && !mtmp->mimic)))
  264:                         mtmp->msleep = 0;
  265:                 else
  266:                         return (0);
  267:         }
  268:         /* not frozen or sleeping: wipe out texts written in the dust */
  269:         wipe_engr_at(mtmp->mx, mtmp->my, 1);
  270: 
  271:         /* confused monsters get unconfused with small probability */
  272:         if (mtmp->mconf && !rn2(50))
  273:                 mtmp->mconf = 0;
  274: 
  275:         /* some monsters teleport */
  276:         if (mtmp->mflee && strchr("tNL", mdat->mlet) && !rn2(40)) {
  277:                 rloc(mtmp);
  278:                 return (0);
  279:         }
  280:         if (mdat->mmove < rnd(6))
  281:                 return (0);
  282: 
  283:         /* fleeing monsters might regain courage */
  284:         if (mtmp->mflee && !mtmp->mfleetim
  285:             && mtmp->mhp == mtmp->mhpmax && !rn2(25))
  286:                 mtmp->mflee = 0;
  287: 
  288:         nearby = (dist(mtmp->mx, mtmp->my) < 3);
  289:         scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) ||
  290:                              sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)));
  291:         if (scared && !mtmp->mflee) {
  292:                 mtmp->mflee = 1;
  293:                 mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100));
  294:         }
  295:         if (!nearby ||
  296:             mtmp->mflee ||
  297:             mtmp->mconf ||
  298:             (mtmp->minvis && !rn2(3)) ||
  299:             (strchr("BIuy", mdat->mlet) && !rn2(4)) ||
  300:             (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) ||
  301:             (!mtmp->mcansee && !rn2(4)) ||
  302:             mtmp->mpeaceful
  303:                 ) {
  304:                 tmp = m_move(mtmp, 0);        /* 2: monster died moving */
  305:                 if (tmp == 2 || (tmp && mdat->mmove <= 12))
  306:                         return (tmp == 2);
  307:         }
  308:         if (!strchr("Ea", mdat->mlet) && nearby &&
  309:             !mtmp->mpeaceful && u.uhp > 0 && !scared) {
  310:                 if (mhitu(mtmp))
  311:                         return (1);  /* monster died (e.g. 'y' or 'F') */
  312:         }
  313:         /* extra movement for fast monsters */
  314:         if (mdat->mmove - 12 > rnd(12))
  315:                 tmp = m_move(mtmp, 1);
  316:         return (tmp == 2);
  317: }
  318: 
  319: int
  320: m_move(struct monst *mtmp, int after)
  321: {
  322:         struct monst   *mtmp2;
  323:         int            nx, ny, omx, omy, appr, nearer, cnt, i, j;
  324:         xchar           gx, gy, nix, niy, chcnt;
  325:         schar           chi;
  326:         boolean         likegold = 0, likegems = 0, likeobjs = 0;
  327:         char            msym = mtmp->data->mlet;
  328:         schar           mmoved = 0;    /* not strictly nec.: chi >= 0 will
  329:                                          * do */
  330:         coord           poss[9];
  331:         int             info[9];
  332: 
  333:         if (mtmp->mfroz || mtmp->msleep)
  334:                 return (0);
  335:         if (mtmp->mtrapped) {
  336:                 i = mintrap(mtmp);
  337:                 if (i == 2)
  338:                         return (2);  /* he died */
  339:                 if (i == 1)
  340:                         return (0);  /* still in trap, so didnt move */
  341:         }
  342:         if (mtmp->mhide && o_at(mtmp->mx, mtmp->my) && rn2(10))
  343:                 return (0);   /* do not leave hiding place */
  344: 
  345: #ifndef NOWORM
  346:         if (mtmp->wormno)
  347:                 goto not_special;
  348: #endif  /* NOWORM */
  349: 
  350:         /* my dog gets a special treatment */
  351:         if (mtmp->mtame) {
  352:                 return (dog_move(mtmp, after));
  353:         }
  354:         /* likewise for shopkeeper */
  355:         if (mtmp->isshk) {
  356:                 mmoved = shk_move(mtmp);
  357:                 if (mmoved >= 0)
  358:                         goto postmov;
  359:                 mmoved = 0;   /* follow player outside shop */
  360:         }
  361:         /* and for the guard */
  362:         if (mtmp->isgd) {
  363:                 mmoved = gd_move();
  364:                 goto postmov;
  365:         }
  366:         /*
  367:          * teleport if that lies in our nature ('t') or when badly wounded
  368:          * ('1')
  369:          */
  370:         if ((msym == 't' && !rn2(5))
  371:             || (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5))
  372:                                 || levl[u.ux][u.uy].typ == STAIRS))) {
  373:                 if (mtmp->mhp < 7 || (msym == 't' && rn2(2)))
  374:                         rloc(mtmp);
  375:                 else
  376:                         mnexto(mtmp);
  377:                 mmoved = 1;
  378:                 goto postmov;
  379:         }
  380:         /* spit fire ('D') or use a wand ('1') when appropriate */
  381:         if (strchr("D1", msym))
  382:                 inrange(mtmp);
  383: 
  384:         if (msym == 'U' && !mtmp->mcan && canseemon(mtmp) &&
  385:             mtmp->mcansee && rn2(5)) {
  386:                 if (!Confusion)
  387:                         pline("%s's gaze has confused you!", Monnam(mtmp));
  388:                 else
  389:                         pline("You are getting more and more confused.");
  390:                 if (rn2(3))
  391:                         mtmp->mcan = 1;
  392:                 Confusion += d(3, 4); /* timeout */
  393:         }
  394: not_special:
  395:         if (!mtmp->mflee && u.uswallow && u.ustuck != mtmp)
  396:                 return (1);
  397:         appr = 1;
  398:         if (mtmp->mflee)
  399:                 appr = -1;
  400:         if (mtmp->mconf || Invis || !mtmp->mcansee ||
  401:             (strchr("BIy", msym) && !rn2(3)))
  402:                 appr = 0;
  403:         omx = mtmp->mx;
  404:         omy = mtmp->my;
  405:         gx = u.ux;
  406:         gy = u.uy;
  407:         if (msym == 'L' && appr == 1 && mtmp->mgold > u.ugold)
  408:                 appr = -1;
  409: 
  410:         /*
  411:          * random criterion for 'smell' or track finding ability should use
  412:          * mtmp->msmell or sth
  413:          */
  414:         if (msym == '@' ||
  415:             ('a' <= msym && msym <= 'z')) {
  416:                 coord          *cp;
  417:                 schar           mroom;
  418:                 mroom = inroom(omx, omy);
  419:                 if (mroom < 0 || mroom != inroom(u.ux, u.uy)) {
  420:                         cp = gettrack(omx, omy);
  421:                         if (cp) {
  422:                                 gx = cp->x;
  423:                                 gy = cp->y;
  424:                         }
  425:                 }
  426:         }
  427:         /* look for gold or jewels nearby */
  428:         likegold = (strchr("LOD", msym) != NULL);
  429:         likegems = (strchr("ODu", msym) != NULL);
  430:         likeobjs = mtmp->mhide;
  431: #define SRCHRADIUS      25
  432:         {
  433:                 xchar           mind = SRCHRADIUS;    /* not too far away */
  434:                 int             dd;
  435:                 if (likegold) {
  436:                         struct gold    *gold;
  437:                         for (gold = fgold; gold; gold = gold->ngold)
  438:                                 if ((dd = DIST(omx, omy, gold->gx, gold->gy)) < mind) {
  439:                                         mind = dd;
  440:                                         gx = gold->gx;
  441:                                         gy = gold->gy;
  442:                                 }
  443:                 }
  444:                 if (likegems || likeobjs) {
  445:                         struct obj     *otmp;
  446:                         for (otmp = fobj; otmp; otmp = otmp->nobj)
  447:                                 if (likeobjs || otmp->olet == GEM_SYM)
  448:                                         if (msym != 'u' ||
  449:                                             objects[otmp->otyp].g_val != 0)
  450:                                                 if ((dd = DIST(omx, omy, otmp->ox, otmp->oy)) < mind) {
  451:                                                         mind = dd;
  452:                                                         gx = otmp->ox;
  453:                                                         gy = otmp->oy;
  454:                                                 }
  455:                 }
  456:                 if (mind < SRCHRADIUS && appr == -1) {
  457:                         if (dist(omx, omy) < 10) {
  458:                                 gx = u.ux;
  459:                                 gy = u.uy;
  460:                         } else
  461:                                 appr = 1;
  462:                 }
  463:         }
  464:         nix = omx;
  465:         niy = omy;
  466:         cnt = mfndpos(mtmp, poss, info,
  467:                       msym == 'u' ? NOTONL :
  468:                   (msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) :
  469:                       strchr(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS);
  470:         /* ALLOW_ROCK for some monsters ? */
  471:         chcnt = 0;
  472:         chi = -1;
  473:         for (i = 0; i < cnt; i++) {
  474:                 nx = poss[i].x;
  475:                 ny = poss[i].y;
  476:                 for (j = 0; j < MTSZ && j < cnt - 1; j++)
  477:                         if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
  478:                                 if (rn2(4 * (cnt - j)))
  479:                                         goto nxti;
  480: #ifdef STUPID
  481:                 /* some stupid compilers think that this is too complicated */
  482:                 {
  483:                         int             d1 = DIST(nx, ny, gx, gy);
  484:                         int             d2 = DIST(nix, niy, gx, gy);
  485:                         nearer = (d1 < d2);
  486:                 }
  487: #else
  488:                 nearer = (DIST(nx, ny, gx, gy) < DIST(nix, niy, gx, gy));
  489: #endif  /* STUPID */
  490:                 if ((appr == 1 && nearer) || (appr == -1 && !nearer) ||
  491:                     !mmoved ||
  492:                     (!appr && !rn2(++chcnt))) {
  493:                         nix = nx;
  494:                         niy = ny;
  495:                         chi = i;
  496:                         mmoved = 1;
  497:                 }
  498: nxti:           ;
  499:         }
  500:         if (mmoved) {
  501:                 if (info[chi] & ALLOW_M) {
  502:                         mtmp2 = m_at(nix, niy);
  503:                         if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
  504:                             hitmm(mtmp2, mtmp) == 2)
  505:                                 return (2);
  506:                         return (0);
  507:                 }
  508:                 if (info[chi] & ALLOW_U) {
  509:                         (void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd) + 1);
  510:                         return (0);
  511:                 }
  512:                 mtmp->mx = nix;
  513:                 mtmp->my = niy;
  514:                 for (j = MTSZ - 1; j > 0; j--)
  515:                         mtmp->mtrack[j] = mtmp->mtrack[j - 1];
  516:                 mtmp->mtrack[0].x = omx;
  517:                 mtmp->mtrack[0].y = omy;
  518: #ifndef NOWORM
  519: