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

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

    1: /*      $NetBSD: hack.dog.c,v 1.6 2003/04/02 18:36:36 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.dog.c,v 1.6 2003/04/02 18:36:36 jsm Exp $");
   67: #endif                          /* not lint */
   68: 
   69: #include "hack.h"
   70: #include "extern.h"
   71: #include "hack.mfndpos.h"
   72: #include "def.edog.h"
   73: #include "def.mkroom.h"
   74: 
   75: const struct permonst li_dog =
   76: {"little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog)};
   77: const struct permonst dog =
   78: {"dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog)};
   79: const struct permonst la_dog =
   80: {"large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog)};
   81: 
   82: 
   83: void
   84: makedog()
   85: {
   86:         struct monst   *mtmp = makemon(&li_dog, u.ux, u.uy);
   87:         if (!mtmp)
   88:                 return;               /* dogs were genocided */
   89:         initedog(mtmp);
   90: }
   91: 
   92: void
   93: initedog(mtmp)
   94:         struct monst   *mtmp;
   95: {
   96:         mtmp->mtame = mtmp->mpeaceful = 1;
   97:         EDOG(mtmp)->hungrytime = 1000 + moves;
   98:         EDOG(mtmp)->eattime = 0;
   99:         EDOG(mtmp)->droptime = 0;
  100:         EDOG(mtmp)->dropdist = 10000;
  101:         EDOG(mtmp)->apport = 10;
  102:         EDOG(mtmp)->whistletime = 0;
  103: }
  104: 
  105: /* attach the monsters that went down (or up) together with @ */
  106: struct monst   *mydogs = 0;
  107: struct monst   *fallen_down = 0;/* monsters that fell through a trapdoor */
  108: /* they will appear on the next level @ goes to, even if he goes up! */
  109: 
  110: void
  111: losedogs()
  112: {
  113:         struct monst   *mtmp;
  114:         while ((mtmp = mydogs) != NULL) {
  115:                 mydogs = mtmp->nmon;
  116:                 mtmp->nmon = fmon;
  117:                 fmon = mtmp;
  118:                 mnexto(mtmp);
  119:         }
  120:         while ((mtmp = fallen_down) != NULL) {
  121:                 fallen_down = mtmp->nmon;
  122:                 mtmp->nmon = fmon;
  123:                 fmon = mtmp;
  124:                 rloc(mtmp);
  125:         }
  126: }
  127: 
  128: void
  129: keepdogs()
  130: {
  131:         struct monst   *mtmp;
  132:         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  133:                 if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
  134:                     && !mtmp->msleep && !mtmp->mfroz) {
  135:                         relmon(mtmp);
  136:                         mtmp->nmon = mydogs;
  137:                         mydogs = mtmp;
  138:                         unpmon(mtmp);
  139:                         keepdogs();  /* we destroyed the link, so use
  140:                                          * recursion */
  141:                         return;      /* (admittedly somewhat primitive) */
  142:                 }
  143: }
  144: 
  145: void
  146: fall_down(mtmp)
  147:         struct monst   *mtmp;
  148: {
  149:         relmon(mtmp);
  150:         mtmp->nmon = fallen_down;
  151:         fallen_down = mtmp;
  152:         unpmon(mtmp);
  153:         mtmp->mtame = 0;
  154: }
  155: 
  156: /* return quality of food; the lower the better */
  157: #define DOGFOOD 0
  158: #define CADAVER 1
  159: #define ACCFOOD 2
  160: #define MANFOOD 3
  161: #define APPORT  4
  162: #define POISON  5
  163: #define UNDEF   6
  164: int
  165: dogfood(obj)
  166:         struct obj     *obj;
  167: {
  168:         switch (obj->olet) {
  169:         case FOOD_SYM:
  170:                 return (
  171:                         (obj->otyp == TRIPE_RATION) ? DOGFOOD :
  172:                         (obj->otyp < CARROT) ? ACCFOOD :
  173:                         (obj->otyp < CORPSE) ? MANFOOD :
  174:                         (poisonous(obj) || obj->age + 50 <= moves ||
  175:                          obj->otyp == DEAD_COCKATRICE)
  176:                         ? POISON : CADAVER
  177:                         );
  178:         default:
  179:                 if (!obj->cursed)
  180:                         return (APPORT);
  181:                 /* fall into next case */
  182:         case BALL_SYM:
  183:         case CHAIN_SYM:
  184:         case ROCK_SYM:
  185:                 return (UNDEF);
  186:         }
  187: }
  188: 
  189: /* return 0 (no move), 1 (move) or 2 (dead) */
  190: int
  191: dog_move(struct monst *mtmp, int after)
  192: {
  193:         int             nx, ny, omx, omy, appr, nearer, j;
  194:         int             udist, chi = 0, i, whappr;
  195:         struct monst   *mtmp2;
  196:         const struct permonst *mdat = mtmp->data;
  197:         struct edog    *edog = EDOG(mtmp);
  198:         struct obj     *obj;
  199:         struct trap    *trap;
  200:         xchar           cnt, chcnt, nix, niy;
  201:         schar           dogroom, uroom;
  202:         xchar           gx = 0, gy = 0, gtyp, otyp;    /* current goal */
  203:         coord           poss[9];
  204:         int             info[9];
  205: #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
  206: #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
  207: 
  208:         if (moves <= edog->eattime)
  209:                 return (0);   /* dog is still eating */
  210:         omx = mtmp->mx;
  211:         omy = mtmp->my;
  212:         whappr = (moves - EDOG(mtmp)->whistletime < 5);
  213:         if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
  214:                 mtmp->mconf = 1;
  215:                 mtmp->mhpmax /= 3;
  216:                 if (mtmp->mhp > mtmp->mhpmax)
  217:                         mtmp->mhp = mtmp->mhpmax;
  218:                 if (cansee(omx, omy))
  219:                         pline("%s is confused from hunger.", Monnam(mtmp));
  220:                 else
  221:                         pline("You feel worried about %s.", monnam(mtmp));
  222:         } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
  223:                 if (cansee(omx, omy))
  224:                         pline("%s dies from hunger.", Monnam(mtmp));
  225:                 else
  226:                         pline("You have a sad feeling for a moment, then it passes.");
  227:                 mondied(mtmp);
  228:                 return (2);
  229:         }
  230:         dogroom = inroom(omx, omy);
  231:         uroom = inroom(u.ux, u.uy);
  232:         udist = dist(omx, omy);
  233: 
  234:         /* maybe we tamed him while being swallowed --jgm */
  235:         if (!udist)
  236:                 return (0);
  237: 
  238:         /* if we are carrying sth then we drop it (perhaps near @) */
  239:         /* Note: if apport == 1 then our behaviour is independent of udist */
  240:         if (mtmp->minvent) {
  241:                 if (!rn2(udist) || !rn2((int) edog->apport))
  242:                         if ((unsigned)rn2(10) < edog->apport) {
  243:                                 relobj(mtmp, (int) mtmp->minvis);
  244:                                 if (edog->apport > 1)
  245:                                         edog->apport--;
  246:                                 edog->dropdist = udist;     /* hpscdi!jon */
  247:                                 edog->droptime = moves;
  248:                         }
  249:         } else {
  250:                 if ((obj = o_at(omx, omy)) != NULL)
  251:                         if (!strchr("0_", obj->olet)) {
  252:                                 if ((otyp = dogfood(obj)) <= CADAVER) {
  253:                                         nix = omx;
  254:                                         niy = omy;
  255:                                         goto eatobj;
  256:                                 }
  257:                                 if (obj->owt < 10 * mtmp->data->mlevel)
  258:                                         if ((unsigned)rn2(20) < edog->apport + 3)
  259:                                                 if (rn2(udist) || !rn2((int) edog->apport)) {
  260:                                                         freeobj(obj);
  261:                                                         unpobj(obj);
  262:                                                         /*
  263:                                                          * if(levl[omx][omy].s
  264:                                                          * crsym ==
  265:                                                          * obj->olet)
  266:                                                          * newsym(omx,omy);
  267:                                                          */
  268:                                                         mpickobj(mtmp, obj);
  269:                                                 }
  270:                         }
  271:         }
  272: 
  273:         /* first we look for food */
  274:         gtyp = UNDEF;          /* no goal as yet */
  275: #ifdef LINT
  276:         gx = gy = 0;           /* suppress 'used before set' message */
  277: #endif  /* LINT */
  278:         for (obj = fobj; obj; obj = obj->nobj) {
  279:                 otyp = dogfood(obj);
  280:                 if (otyp > gtyp || otyp == UNDEF)
  281:                         continue;
  282:                 if (inroom(obj->ox, obj->oy) != dogroom)
  283:                         continue;
  284:                 if (otyp < MANFOOD &&
  285:                     (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) {
  286:                         if (otyp < gtyp || (otyp == gtyp &&
  287:                                  DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) {
  288:                                 gx = obj->ox;
  289:                                 gy = obj->oy;
  290:                                 gtyp = otyp;
  291:                         }
  292:                 } else if (gtyp == UNDEF && dogroom >= 0 &&
  293:                            uroom == dogroom &&
  294:                            !mtmp->minvent && edog->apport > (unsigned)rn2(8)) {
  295:                         gx = obj->ox;
  296:                         gy = obj->oy;
  297:                         gtyp = APPORT;
  298:                 }
  299:         }
  300:         if (gtyp == UNDEF ||
  301:           (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
  302:                 if (dogroom < 0 || dogroom == uroom) {
  303:                         gx = u.ux;
  304:                         gy = u.uy;
  305: #ifndef QUEST
  306:                 } else {
  307:                         int             tmp = rooms[dogroom].fdoor;
  308:                         cnt = rooms[dogroom].doorct;
  309: 
  310:                         gx = gy = FAR;       /* random, far away */
  311:                         while (cnt--) {
  312:                                 if (dist(gx, gy) >
  313:                                     dist(doors[tmp].x, doors[tmp].y)) {
  314:                                         gx = doors[tmp].x;
  315:                                         gy = doors[tmp].y;
  316:                                 }
  317:                                 tmp++;
  318:                         }
  319:                         /* here gx == FAR e.g. when dog is in a vault */
  320:                         if (gx == FAR || (gx == omx && gy == omy)) {
  321:                                 gx = u.ux;
  322:                                 gy = u.uy;
  323:                         }
  324: #endif  /* QUEST */
  325:                 }
  326:                 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
  327:                 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
  328:                         return (0);
  329:                 if (udist > 1) {
  330:                         if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
  331:                             whappr ||
  332:                             (mtmp->minvent && rn2((int) edog->apport)))
  333:                                 appr = 1;
  334:                 }
  335:                 /* if you have dog food he'll follow you more closely */
  336:                 if (appr == 0) {
  337:                         obj = invent;
  338:                         while (obj) {
  339:                                 if (obj->otyp == TRIPE_RATION) {
  340:                                         appr = 1;
  341:                                         break;
  342:                                 }
  343:                                 obj = obj->nobj;
  344:                         }
  345:                 }
  346:         } else
  347:                 appr = 1;     /* gtyp != UNDEF */
  348:         if (mtmp->mconf)
  349:                 appr = 0;
  350: 
  351:         if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
  352:                 coord          *cp;
  353:                 cp = gettrack(omx, omy);
  354:                 if (cp) {
  355:                         gx = cp->x;
  356:                         gy = cp->y;
  357:                 }
  358:         }
  359:         nix = omx;
  360:         niy = omy;
  361:         cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
  362:         chcnt = 0;
  363:         chi = -1;
  364:         for (i = 0; i < cnt; i++) {
  365:                 nx = poss[i].x;
  366:                 ny = poss[i].y;
  367:                 if (info[i] & ALLOW_M) {
  368:                         mtmp2 = m_at(nx, ny);
  369:                         if (mtmp2->data->mlevel >= mdat->mlevel + 2 ||
  370:                             mtmp2->data->mlet == 'c')
  371:                                 continue;
  372:                         if (after)
  373:                                 return (0); /* hit only once each move */
  374: 
  375:                         if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
  376:                             mtmp2->mlstmv != moves &&
  377:                             hitmm(mtmp2, mtmp) == 2)
  378:                                 return (2);
  379:                         return (0);
  380:                 }
  381:                 /* dog avoids traps */
  382:                 /* but perhaps we have to pass a trap in order to follow @ */
  383:                 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
  384:                         if (!trap->tseen && rn2(40))
  385:                                 continue;
  386:                         if (rn2(10))
  387:                                 continue;
  388:                 }
  389:                 /* dog eschewes cursed objects */
  390:                 /* but likes dog food */
  391:                 obj = fobj;
  392:                 while (obj) {
  393:                         if (obj->ox != nx || obj->oy != ny)
  394:                                 goto nextobj;
  395:                         if (obj->cursed)
  396:                                 goto nxti;
  397:                         if (obj->olet == FOOD_SYM &&
  398:                             (otyp = dogfood(obj)) < MANFOOD &&
  399:                             (otyp < ACCFOOD || edog->hungrytime <= moves)) {
  400:                                 /*
  401:                                  * Note: our dog likes the food so much that
  402:                                  * he might eat it even when it conceals a
  403:                                  * cursed object
  404:                                  */
  405:                                 nix = nx;
  406:                                 niy = ny;
  407:                                 chi = i;
  408:                 eatobj:
  409:                                 edog->eattime =
  410:                                         moves + obj->quan * objects[obj->otyp].oc_delay;
  411:                                 if (edog->hungrytime < moves)
  412:                                         edog->hungrytime = moves;
  413:                                 edog->hungrytime +=
  414:                                         5 * obj->quan * objects[obj->otyp].nutrition;
  415:                                 mtmp->mconf = 0;
  416:                                 if (cansee(nix, niy))
  417:                                         pline("%s ate %s.", Monnam(mtmp), doname(obj));
  418:                                 /* perhaps this was a reward */
  419:                                 if (otyp != CADAVER)
  420:                                         edog->apport += 200 / (edog->dropdist + moves - edog->droptime);
  421:                                 delobj(obj);
  422:                                 goto newdogpos;
  423:                         }
  424:         nextobj:
  425:                         obj = obj->nobj;
  426:                 }
  427: 
  428:                 for (j = 0; j < MTSZ && j < cnt - 1; j++)
  429:                         if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
  430:                                 if (rn2(4 * (cnt - j)))
  431:                                         goto nxti;
  432: 
  433:                 /*
  434:                  * Some stupid C compilers cannot compute the whole
  435:                  * expression at once.
  436:                  */
  437:                 nearer = GDIST(nx, ny);
  438:                 nearer -= GDIST(nix, niy);
  439:                 nearer *= appr;
  440:                 if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
  441:                     (nearer > 0 && !whappr &&
  442:                      ((omx == nix && omy == niy && !rn2(3))
  443:                       || !rn2(12))
  444:                      )) {
  445:                         nix = nx;
  446:                         niy = ny;
  447:                         if (nearer < 0)
  448:                                 chcnt = 0;
  449:                         chi = i;
  450:                 }
  451: nxti:           ;
  452:         }
  453: newdogpos:
  454:         if (nix != omx || niy != omy) {
  455:                 if (info[chi] & ALLOW_U) {
  456:                         (void) hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
  457:                         return (0);
  458:                 }
  459:                 mtmp->mx = nix;
  460:                 mtmp->my = niy;
  461:                 for (j = MTSZ - 1; j > 0; j--)
  462:                         mtmp->mtrack[j] = mtmp->mtrack[j - 1];
  463:                 mtmp->mtrack[0].x = omx;
  464:                 mtmp->mtrack[0].y = omy;
  465:         }
  466:         if (mintrap(mtmp) == 2)        /* he died */
  467:                 return (2);
  468:         pmon(mtmp);
  469:         return (1);
  470: }
  471: 
  472: /* return roomnumber or -1 */
  473: int
  474: inroom(x, y)
  475:         xchar           x, y;
  476: {
  477: #ifndef QUEST
  478:         struct mkroom  *croom = &rooms[0];
  479:         while (croom->hx >= 0) {
  480:                 if (croom->hx >= x - 1 && croom->lx <= x + 1 &&
  481:                     croom->hy >= y - 1 && croom->ly <= y + 1)
  482:                         return (croom - rooms);
  483:                 croom++;
  484:         }
  485: #endif  /* QUEST */
  486:         return (-1);           /* not in room or on door */
  487: }
  488: 
  489: int
  490: tamedog(mtmp, obj)
  491:         struct monst   *mtmp;
  492:         struct obj     *obj;
  493: {
  494:         struct monst   *mtmp2;
  495: 
  496:         if (flags.moonphase == FULL_MOON && night() && rn2(6))
  497:                 return (0);
  498: 
  499:         /* If we cannot tame him, at least he's no longer afraid. */
  500:         mtmp->mflee = 0;
  501:         mtmp->mfleetim = 0;
  502:         if (mtmp->mtame || mtmp->mfroz ||
  503: #ifndef NOWORM
  504:             mtmp->wormno ||
  505: #endif  /* NOWORM */
  506:             mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
  507:                 return (0);   /* no tame long worms? */
  508:         if (obj) {
  509:                 if (dogfood(obj) >= MANFOOD)
  510:                         return (0);
  511:                 if (cansee(mtmp->mx, mtmp->my)) {
  512:                         pline("%s devours the %s.", Monnam(mtmp),
  513:                               objects[obj->