home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / dogmove.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  17.8 KB  |  675 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)dogmove.c    3.1    93/05/15    */
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6.  
  7. #include "mfndpos.h"
  8. #include "edog.h"
  9.  
  10. #ifdef OVL0
  11.  
  12. static boolean FDECL(dog_hunger,(struct monst *,struct edog *));
  13. static boolean FDECL(dog_invent,(struct monst *,struct edog *,int));
  14. static int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
  15.  
  16. #ifndef MUSE
  17. #define DROPPABLES(mtmp) mtmp->minvent
  18. #else
  19. static struct obj *FDECL(DROPPABLES, (struct monst *));
  20.  
  21. static struct obj *
  22. DROPPABLES(mon)
  23. register struct monst *mon;
  24. {
  25.     register struct obj *obj;
  26.     struct obj *wep = MON_WEP(mon);
  27.  
  28.     for(obj = mon->minvent; obj; obj = obj->nobj)
  29.         if (!obj->owornmask && obj != wep) return obj;
  30.     return (struct obj *)0;
  31. }
  32. #endif
  33.  
  34. static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
  35.  
  36. #endif /* OVL0 */
  37.  
  38. STATIC_VAR xchar gtyp, gx, gy;    /* type and position of dog's current goal */
  39.  
  40. STATIC_DCL void FDECL(dog_eat, (struct monst *, struct obj *, int, int));
  41. STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
  42.  
  43. #ifdef OVLB
  44.  
  45. STATIC_OVL void
  46. dog_eat(mtmp, obj, x, y)
  47. register struct monst *mtmp;
  48. register struct obj * obj;
  49. int x, y;
  50. {
  51.     register struct edog *edog = EDOG(mtmp);
  52.     int nutrit;
  53.  
  54.     if(edog->hungrytime < moves)
  55.         edog->hungrytime = moves;
  56.     /*
  57.      * It is arbitrary that the pet takes the same length of time to eat
  58.      * as a human, but gets more nutritional value.
  59.      */
  60.     if (obj->oclass == FOOD_CLASS) {
  61.         if(obj->otyp == CORPSE) {
  62.         mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
  63.         nutrit = mons[obj->corpsenm].cnutrit;
  64.         } else {
  65.         mtmp->meating = objects[obj->otyp].oc_delay;
  66.         nutrit = objects[obj->otyp].oc_nutrition;
  67.         }
  68.         switch(mtmp->data->msize) {
  69.         case MZ_TINY: nutrit *= 8; break;
  70.         case MZ_SMALL: nutrit *= 6; break;
  71.         default:
  72.         case MZ_MEDIUM: nutrit *= 5; break;
  73.         case MZ_LARGE: nutrit *= 4; break;
  74.         case MZ_HUGE: nutrit *= 3; break;
  75.         case MZ_GIGANTIC: nutrit *= 2; break;
  76.         }
  77.         if(obj->oeaten) {
  78.         mtmp->meating = eaten_stat(mtmp->meating, obj);
  79.         nutrit = eaten_stat(nutrit, obj);
  80.         }
  81.     } else if (obj->oclass == GOLD_CLASS) {
  82.         mtmp->meating = ((int)obj->quan/2000) + 1;
  83.         nutrit = ((int)obj->quan/20);
  84.     } else {
  85.         /* Unusual pet such as gelatinous cube eating odd stuff.
  86.          * meating made consistent with wild monsters in mon.c.
  87.          * nutrit made consistent with polymorphed player nutrit in
  88.          * eat.c.  (This also applies to pets eating gold.)
  89.          */
  90.         mtmp->meating = obj->owt/20 + 1;
  91.         nutrit = 5*objects[obj->otyp].oc_nutrition;
  92.     }
  93.     edog->hungrytime += nutrit;
  94.     mtmp->mconf = 0;
  95.     if (mtmp->mtame < 20) mtmp->mtame++;
  96.     if(cansee(x,y))
  97.         pline("%s eats %s.", Monnam(mtmp), (obj->oclass==FOOD_CLASS)
  98.         ? singular(obj, doname) : doname(obj));
  99.     /* It's a reward if it's DOGFOOD and the player dropped/threw it. */
  100.     /* We know the player had it if invlet is set -dlc */
  101.     if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
  102. #ifdef LINT
  103.         edog->apport = 0;
  104. #else
  105.         edog->apport += (unsigned)(200L/
  106.         ((long)edog->dropdist+moves-edog->droptime));
  107. #endif
  108.     if (obj == uball) {
  109.         unpunish();
  110.         delobj(obj);
  111.     } else if (obj == uchain)
  112.         unpunish();
  113.     else if (obj->quan > 1L && obj->oclass == FOOD_CLASS)
  114.         obj->quan--;
  115.     else
  116.         delobj(obj);
  117. }
  118.  
  119. #endif /* OVLB */
  120. #ifdef OVL0
  121.  
  122. /* hunger effects -- returns TRUE on starvation */
  123. static boolean
  124. dog_hunger(mtmp, edog)
  125. register struct monst *mtmp;
  126. register struct edog *edog;
  127. {
  128.     if (moves > edog->hungrytime + 500) {
  129.         if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
  130.         edog->hungrytime = moves + 500;
  131.         /* but not too high; it might polymorph */
  132.         } else if (!mtmp->mconf) {
  133.         mtmp->mconf = 1;
  134.         mtmp->mhpmax /= 3;
  135.         if (mtmp->mhp > mtmp->mhpmax)
  136.             mtmp->mhp = mtmp->mhpmax;
  137.         if (mtmp->mhp < 1) goto dog_died;
  138.         if (cansee(mtmp->mx, mtmp->my))
  139.             pline("%s is confused from hunger.", Monnam(mtmp));
  140. #ifdef SOUNDS
  141.         else if (couldsee(mtmp->mx, mtmp->my))
  142.             beg(mtmp);
  143. #endif
  144.         else {
  145.             char buf[BUFSZ];
  146.  
  147.             Strcpy(buf, "the ");
  148.             You("feel worried about %s.", mtmp->mnamelth ?
  149.             NAME(mtmp) : strcat(buf, Hallucination
  150.             ? rndmonnam() : mtmp->data->mname));
  151.         }
  152.         } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
  153.         dog_died:
  154. #ifdef WALKIES
  155.         if (mtmp->mleashed)
  156.             Your("leash goes slack.");
  157.         else
  158. #endif
  159.         if (cansee(mtmp->mx, mtmp->my))
  160.             pline("%s dies%s.", Monnam(mtmp),
  161.                 (mtmp->mhp >= 1) ? "" : " from hunger");
  162.         else
  163.             You("feel %s for a moment.",
  164.             Hallucination ? "bummed" : "sad");
  165.         mondied(mtmp);
  166.         return(TRUE);
  167.         }
  168.     }
  169.     return(FALSE);
  170. }
  171.  
  172. /* do something with object (drop, pick up, eat) at current position
  173.  * returns TRUE if object eaten (since that counts as dog's move)
  174.  */
  175. static boolean
  176. dog_invent(mtmp, edog, udist)
  177. register struct monst *mtmp;
  178. register struct edog *edog;
  179. int udist;
  180. {
  181.     register int omx, omy;
  182.     struct obj *obj;
  183.  
  184.     omx = mtmp->mx;
  185.     omy = mtmp->my;
  186.  
  187.     /* if we are carrying sth then we drop it (perhaps near @) */
  188.     /* Note: if apport == 1 then our behaviour is independent of udist */
  189.     if(DROPPABLES(mtmp) || mtmp->mgold) {
  190.         if(!rn2(udist) || !rn2((int) edog->apport))
  191.         if(rn2(10) < edog->apport){
  192.             relobj(mtmp, (int)mtmp->minvis, TRUE);
  193.             if(edog->apport > 1) edog->apport--;
  194.             edog->dropdist = udist;        /* hpscdi!jon */
  195.             edog->droptime = moves;
  196.         }
  197.     } else {
  198.         if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
  199. #ifdef MAIL
  200.             && obj->otyp != SCR_MAIL
  201. #endif
  202.                                     ){
  203.         if (dogfood(mtmp, obj) <= CADAVER) {
  204.             dog_eat(mtmp, obj, omx, omy);
  205.             return TRUE;
  206.         }
  207.         if(can_carry(mtmp, obj) && !obj->cursed)
  208.             if(rn2(20) < edog->apport+3)
  209.             if(rn2(udist) || !rn2((int) edog->apport)) {
  210.                 if (cansee(omx, omy) && flags.verbose)
  211.                 pline("%s picks up %s.", Monnam(mtmp),
  212.                     distant_name(obj, doname));
  213.                 freeobj(obj);
  214.                 newsym(omx,omy);
  215.                 mpickobj(mtmp,obj);
  216. #ifdef MUSE
  217.                 if (attacktype(mtmp->data, AT_WEAP)) {
  218.                 mtmp->weapon_check = NEED_HTH_WEAPON;
  219.                 (void) mon_wield_item(mtmp);
  220.                 }
  221. #endif
  222.             }
  223.         }
  224.     }
  225.     return FALSE;
  226. }
  227.  
  228. /* set dog's goal -- gtyp, gx, gy
  229.  * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
  230.  */
  231. static int
  232. dog_goal(mtmp, edog, after, udist, whappr)
  233. register struct monst *mtmp;
  234. struct edog *edog;
  235. int after, udist, whappr;
  236. {
  237.     register int omx, omy;
  238.     boolean in_masters_sight;
  239.     register struct obj *obj;
  240.     xchar otyp;
  241.     int appr;
  242.  
  243.     omx = mtmp->mx;
  244.     omy = mtmp->my;
  245.  
  246.     in_masters_sight = couldsee(omx, omy);
  247.  
  248.     if (!edog
  249. #ifdef WALKIES
  250.             || mtmp->mleashed    /* he's not going anywhere... */
  251. #endif
  252.                     ) {
  253.         gtyp = APPORT;
  254.         gx = u.ux;
  255.         gy = u.uy;
  256.     } else {
  257. #define DDIST(x,y) (dist2(x,y,omx,omy))
  258. #define SQSRCHRADIUS 5
  259.         int min_x, max_x, min_y, max_y;
  260.         register int nx, ny;
  261.  
  262.         gtyp = UNDEF;    /* no goal as yet */
  263.         gx = gy = 0;    /* suppress 'used before set' message */
  264.  
  265.         if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0;
  266.         if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
  267.         if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
  268.         if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
  269.  
  270.         /* nearby food is the first choice, then other objects */
  271.         for (obj = fobj; obj; obj = obj->nobj) {
  272.         nx = obj->ox;
  273.         ny = obj->oy;
  274.         if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
  275.             otyp = dogfood(mtmp, obj);
  276.             if (otyp > gtyp || otyp == UNDEF)
  277.             continue;
  278.             if (otyp < MANFOOD) {
  279.             if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
  280.                 gx = nx;
  281.                 gy = ny;
  282.                 gtyp = otyp;
  283.             }
  284.             } else if(gtyp == UNDEF && in_masters_sight &&
  285.                   !mtmp->minvent &&
  286.                   (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
  287.                   (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
  288.                   edog->apport > rn2(8) &&
  289.                   can_carry(mtmp,obj)) {
  290.             gx = nx;
  291.             gy = ny;
  292.             gtyp = APPORT;
  293.             }
  294.         }
  295.         }
  296.     }
  297.  
  298.     /* follow player if appropriate */
  299.     if (gtyp == UNDEF ||
  300.         (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
  301.         gx = u.ux;
  302.         gy = u.uy;
  303.         if (after && udist <= 4 && gx == u.ux && gy == u.uy)
  304.             return(-2);
  305.         appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
  306.         if (udist > 1) {
  307.             if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
  308.                whappr ||
  309.                (mtmp->minvent && rn2((int) edog->apport)))
  310.                 appr = 1;
  311.         }
  312.         /* if you have dog food it'll follow you more closely */
  313.         if (appr == 0) {
  314.             obj = invent;
  315.             while (obj) {
  316.                 if(dogfood(mtmp, obj) == DOGFOOD) {
  317.                     appr = 1;
  318.                     break;
  319.                 }
  320.                 obj = obj->nobj;
  321.             }
  322.         }
  323.     } else
  324.         appr = 1;    /* gtyp != UNDEF */
  325.     if(mtmp->mconf)
  326.         appr = 0;
  327.  
  328. #define FARAWAY (COLNO + 2)        /* position outside screen */
  329.     if (gx == u.ux && gy == u.uy && !in_masters_sight) {
  330.         register coord *cp;
  331.  
  332.         cp = gettrack(omx,omy);
  333.         if (cp) {
  334.         gx = cp->x;
  335.         gy = cp->y;
  336.         if(edog) edog->ogoal.x = 0;
  337.         } else {
  338.         /* assume master hasn't moved far, and reuse previous goal */
  339.         if(edog && edog->ogoal.x &&
  340.            ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
  341.             gx = edog->ogoal.x;
  342.             gy = edog->ogoal.y;
  343.             edog->ogoal.x = 0;
  344.         } else {
  345.             int fardist = FARAWAY * FARAWAY;
  346.             gx = gy = FARAWAY; /* random */
  347.             do_clear_area(omx, omy, 9, wantdoor,
  348.                   (genericptr_t)&fardist);
  349.  
  350.             /* here gx == FARAWAY e.g. when dog is in a vault */
  351.             if (gx == FARAWAY || (gx == omx && gy == omy)) {
  352.             gx = u.ux;
  353.             gy = u.uy;
  354.             } else if(edog) {
  355.             edog->ogoal.x = gx;
  356.             edog->ogoal.y = gy;
  357.             }
  358.         }
  359.         }
  360.     } else if(edog) {
  361.         edog->ogoal.x = 0;
  362.     }
  363.     return appr;
  364. }
  365.  
  366. /* return 0 (no move), 1 (move) or 2 (dead) */
  367. int
  368. dog_move(mtmp, after)
  369. register struct monst *mtmp;
  370. register int after;    /* this is extra fast monster movement */
  371. {
  372.     int omx, omy;        /* original mtmp position */
  373.     int appr, whappr, udist;
  374.     int i, j;
  375.     register struct edog *edog = EDOG(mtmp);
  376.     struct obj *obj = (struct obj *) 0;
  377.     xchar otyp;
  378.     boolean has_edog, cursemsg = FALSE, do_eat = FALSE;
  379.     xchar nix, niy;        /* position mtmp is (considering) moving to */
  380.     register int nx, ny;    /* temporary coordinates */
  381.     xchar cnt, uncursedcnt, chcnt;
  382.     int chi = -1, nidist, ndist;
  383.     coord poss[9];
  384.     long info[9], allowflags;
  385. #define GDIST(x,y) (dist2(x,y,gx,gy))
  386.  
  387.     /*
  388.      * Tame Angels have isminion set and an ispriest structure instead of
  389.      * an edog structure.  Fortunately, guardian Angels need not worry
  390.      * about mundane things like eating and fetching objects, and can
  391.      * spend all their energy defending the player.  (They are the only
  392.      * monsters with other structures that can be tame.)
  393.      */
  394.     has_edog = !mtmp->isminion;
  395.  
  396.     omx = mtmp->mx;
  397.     omy = mtmp->my;
  398.     if (has_edog && dog_hunger(mtmp, edog)) return(2);    /* starved */
  399.  
  400.     udist = distu(omx,omy);
  401.     /* maybe we tamed him while being swallowed --jgm */
  402.     if (!udist) return(0);
  403.  
  404.     nix = omx;    /* set before newdogpos */
  405.     niy = omy;
  406.  
  407.     if (has_edog && dog_invent(mtmp, edog, udist))    /* eating something */
  408.         goto newdogpos;
  409.  
  410.     if (has_edog)
  411.         whappr = (moves - edog->whistletime < 5);
  412.     else
  413.         whappr = 0;
  414.  
  415.     appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,
  416.                             after, udist, whappr);
  417.     if (appr == -2) return(0);
  418.  
  419.     allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
  420.     if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
  421.     if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
  422.     if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
  423.         allowflags |= ALLOW_U;
  424.         if (!has_edog) {
  425.         coord mm;
  426.         /* Guardian angel refuses to be conflicted; rather,
  427.          * it disappears, angrily, and sends in some nasties
  428.          */
  429.         if (canseemon(mtmp) || sensemon(mtmp)) {
  430.             pline("%s rebukes you, saying:", Monnam(mtmp));
  431.             verbalize("Since you desire conflict, have some more!");
  432.         }
  433.         mongone(mtmp);
  434.         i = rnd(4);
  435.         while(i--) {
  436.             mm.x = u.ux;
  437.             mm.y = u.uy;
  438.             if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
  439.             (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
  440.                      mm.x, mm.y, FALSE);
  441.         }
  442.         return(2);
  443.  
  444.         }
  445.     }
  446.     if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
  447.         allowflags |= OPENDOOR;
  448.         if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
  449.     }
  450.     if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
  451.     if (tunnels(mtmp->data) && !needspick(mtmp->data))
  452.         allowflags |= ALLOW_DIG;
  453.     cnt = mfndpos(mtmp, poss, info, allowflags);
  454.  
  455.     /* Normally dogs don't step on cursed items, but if they have no
  456.      * other choice they will.  This requires checking ahead of time
  457.      * to see how many cursed item squares are around.
  458.      */
  459.     uncursedcnt = 0;
  460.     for (i = 0; i < cnt; i++) {
  461.         nx = poss[i].x; ny = poss[i].y;
  462.         if (MON_AT(nx,ny)) continue;
  463.         for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere)
  464.             if (obj->cursed) goto skipu;
  465.         uncursedcnt++;
  466. skipu:;
  467.     }
  468.  
  469.     chcnt = 0;
  470.     chi = -1;
  471.     nidist = GDIST(nix,niy);
  472.  
  473.     for (i = 0; i < cnt; i++) {
  474.         nx = poss[i].x;
  475.         ny = poss[i].y;
  476. #ifdef WALKIES
  477.         /* if leashed, we drag him along. */
  478.         if (mtmp->mleashed && distu(nx, ny) > 4) continue;
  479. #endif
  480.         /* if a guardian, try to stay close by choice */
  481.         if (!has_edog &&
  482.             (j = distu(nx, ny)) > 16 && j >= udist) continue;
  483.  
  484.         if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
  485.             int mstatus;
  486.             register struct monst *mtmp2 = m_at(nx,ny);
  487.  
  488.             if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||
  489.             (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
  490.              mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
  491.              && (perceives(mtmp->data) || !mtmp2->minvis)) ||
  492.             (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
  493.             (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
  494.             ((mtmp->mhp*4 < mtmp->mhpmax
  495. #ifdef MULDGN
  496.               || mtmp2->data->msound == MS_GUARDIAN
  497.               || mtmp2->data->msound == MS_LEADER
  498. #endif
  499.               ) &&
  500.              mtmp2->mpeaceful && !Conflict) ||
  501.                (mtmp2->data->mlet == S_COCKATRICE &&
  502.                 !resists_ston(mtmp->data)))
  503.             continue;
  504.  
  505.             if (after) return(0); /* hit only once each move */
  506.  
  507.             mstatus = mattackm(mtmp, mtmp2);
  508.  
  509.             /* aggressor (pet) died */
  510.             if (mstatus & MM_AGR_DIED) return 2;
  511.  
  512.             if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&
  513.             rn2(4) && mtmp2->mlstmv != monstermoves &&
  514.             !onscary(mtmp->mx, mtmp->my, mtmp2)) {
  515.             mstatus = mattackm(mtmp2, mtmp);    /* return attack */
  516.             if (mstatus & MM_DEF_DIED) return 2;
  517.             }
  518.  
  519.             return 0;
  520.         }
  521.  
  522.         {   /* dog avoids traps, but perhaps it has to pass a trap
  523.              * in order to follow player
  524.              */
  525.             struct trap *trap;
  526.  
  527.             if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
  528.             if ((trap->ttyp == RUST_TRAP
  529.                     && mtmp->data != &mons[PM_IRON_GOLEM])
  530.                 || trap->ttyp == STATUE_TRAP
  531.                 || ((trap->ttyp == PIT
  532.                     || trap->ttyp == SPIKED_PIT
  533.                     || (trap->ttyp == TRAPDOOR &&
  534.                     !Can_fall_thru(&u.uz)))
  535.                     && (is_flyer(mtmp->data) ||
  536.                     is_clinger(mtmp->data)))
  537.                 || (trap->ttyp == SLP_GAS_TRAP &&
  538.                     resists_sleep(mtmp->data))) {
  539.                 if (!trap->tseen || rn2(3)) continue;
  540.             } else
  541. #ifdef WALKIES
  542.             if (!mtmp->mleashed) {
  543. #endif
  544.                 if (!trap->tseen && rn2(40)) continue;
  545.                 if (rn2(10)) continue;
  546. #ifdef WALKIES
  547. # ifdef SOUNDS
  548.             } else if (flags.soundok) {
  549.                 whimper(mtmp);
  550. # endif
  551.             }
  552. #endif
  553.             }
  554.         }
  555.  
  556.         /* dog eschews cursed objects, but likes dog food */
  557.         for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
  558.             if (obj->cursed && !mtmp->mleashed && uncursedcnt &&
  559.             has_edog)
  560.             goto nxti;
  561.             if (obj->cursed) cursemsg = TRUE;
  562.             if (has_edog && (otyp = dogfood(mtmp, obj)) < MANFOOD &&
  563.                 (otyp < ACCFOOD || edog->hungrytime <= moves)){
  564.             /* Note: our dog likes the food so much that he
  565.              * might eat it even when it conceals a cursed object */
  566.             nix = nx;
  567.             niy = ny;
  568.             chi = i;
  569.             do_eat = TRUE;
  570.             goto newdogpos;
  571.             }
  572.         }
  573.  
  574.         for (j = 0; j < MTSZ && j < cnt-1; j++)
  575.             if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
  576.                 if (rn2(4*(cnt-j))) goto nxti;
  577.  
  578.         j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
  579.         if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
  580.             (j > 0 && !whappr &&
  581.                 ((omx == nix && omy == niy && !rn2(3))
  582.                     || !rn2(12))
  583.             )) {
  584.             nix = nx;
  585.             niy = ny;
  586.             nidist = ndist;
  587.             if(j < 0) chcnt = 0;
  588.             chi = i;
  589.         }
  590.     nxti:    ;
  591.     }
  592. newdogpos:
  593.     if (nix != omx || niy != omy) {
  594.         if (info[chi] & ALLOW_U) {
  595. #ifdef WALKIES
  596.             if (mtmp->mleashed) { /* play it safe */
  597.                 pline("%s breaks loose of %s leash!",
  598.                       Monnam(mtmp), his[pronoun_gender(mtmp)]);
  599.                 m_unleash(mtmp);
  600.             }
  601. #endif
  602.             (void) mattacku(mtmp);
  603.             return(0);
  604.         }
  605.         /* insert a worm_move() if worms ever begin to eat things */
  606.         remove_monster(omx, omy);
  607.         place_monster(mtmp, nix, niy);
  608.         if (cursemsg && (cansee(omx,omy) || cansee(nix,niy)))
  609.             pline("%s moves only reluctantly.", Monnam(mtmp));
  610.         for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
  611.         mtmp->mtrack[0].x = omx;
  612.         mtmp->mtrack[0].y = omy;
  613.         /* We have to know if the pet's gonna do a combined eat and
  614.          * move before moving it, but it can't eat until after being
  615.          * moved.  Thus the do_eat flag.
  616.          */
  617.         if (do_eat)
  618.             dog_eat(mtmp, obj, nix, niy);
  619.     }
  620. #ifdef WALKIES
  621.       /* an incredible kludge, but the only way to keep pooch near
  622.        * after it spends time eating or in a trap, etc.
  623.        */
  624.       else if (mtmp->mleashed && distu(omx, omy) > 4) {
  625.         coord cc;
  626.  
  627.         nx = sgn(omx - u.ux);
  628.         ny = sgn(omy - u.uy);
  629.         cc.x = u.ux + nx;
  630.         cc.y = u.uy + ny;
  631.         if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  632.  
  633.          i  = xytod(nx, ny);
  634.         for (j = (i + 7)%8; j < (i + 1)%8; j++) {
  635.             dtoxy(&cc, j);
  636.             if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  637.         }
  638.         for (j = (i + 6)%8; j < (i + 2)%8; j++) {
  639.             dtoxy(&cc, j);
  640.             if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
  641.         }
  642.         cc.x = mtmp->mx;
  643.         cc.y = mtmp->my;
  644. dognext:
  645.         remove_monster(mtmp->mx, mtmp->my);
  646.         place_monster(mtmp, cc.x, cc.y);
  647.         newsym(cc.x,cc.y);
  648.         set_apparxy(mtmp);
  649.     }
  650. #endif
  651.     return(1);
  652. }
  653.  
  654. #endif /* OVL0 */
  655. #ifdef OVLB
  656.  
  657. /*ARGSUSED*/    /* do_clear_area client */
  658. STATIC_PTR void
  659. wantdoor(x, y, distance)
  660. int x, y;
  661. genericptr_t distance;
  662. {
  663.     register ndist;
  664.  
  665.     if (*(int*)distance > (ndist = distu(x, y))) {
  666.     gx = x;
  667.     gy = y;
  668.     *(int*)distance = ndist;
  669.     }
  670. }
  671.  
  672. #endif /* OVLB */
  673.  
  674. /*dogmove.c*/
  675.