Source:NetHack 3.1.0/dogmove.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to dogmove.c from the source code of NetHack 3.1.0.

Warning! This is the source code from an old release. For newer releases, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)dogmove.c	3.1	92/11/26	*/
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 const char NEARDATA 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.  		else {
141.  		    char buf[BUFSZ];
142.  
143.  		    Strcpy(buf, "the ");
144.  		    You("feel worried about %s.", mtmp->mnamelth ?
145.  			NAME(mtmp) : strcat(buf, Hallucination
146.  			? rndmonnam() : mtmp->data->mname));
147.  		}
148.  	    } else if(moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
149.  	    dog_died:
150.  #ifdef WALKIES
151.  		if(mtmp->mleashed)
152.  		    Your("leash goes slack.");
153.  #endif
154.  		if(cansee(mtmp->mx, mtmp->my))
155.  		    pline("%s dies%s.", Monnam(mtmp),
156.  			    (mtmp->mhp >= 1) ? "" : " from hunger");
157.  		else
158.  		    You("have a sad feeling for a moment, then it passes.");
159.  		mondied(mtmp);
160.  		return(TRUE);
161.  	    }
162.  	}
163.  	return(FALSE);
164.  }
165.  
166.  /* do something with object (drop, pick up, eat) at current position
167.   * returns TRUE if object eaten (since that counts as dog's move)
168.   */
169.  static boolean
170.  dog_invent(mtmp, edog, udist)
171.  register struct monst *mtmp;
172.  register struct edog *edog;
173.  int udist;
174.  {
175.  	register int omx, omy;
176.  	struct obj *obj;
177.  
178.  	omx = mtmp->mx;
179.  	omy = mtmp->my;
180.  
181.  	/* if we are carrying sth then we drop it (perhaps near @) */
182.  	/* Note: if apport == 1 then our behaviour is independent of udist */
183.  	if(DROPPABLES(mtmp) || mtmp->mgold) {
184.  	    if(!rn2(udist) || !rn2((int) edog->apport))
185.  		if(rn2(10) < edog->apport){
186.  		    relobj(mtmp, (int)mtmp->minvis, TRUE);
187.  		    if(edog->apport > 1) edog->apport--;
188.  		    edog->dropdist = udist;		/* hpscdi!jon */
189.  		    edog->droptime = moves;
190.  		}
191.  	} else {
192.  	    if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
193.  #ifdef MAIL
194.  			&& obj->otyp != SCR_MAIL
195.  #endif
196.  									){
197.  		if (dogfood(mtmp, obj) <= CADAVER) {
198.  		    dog_eat(mtmp, obj, omx, omy);
199.  		    return TRUE;
200.  		}
201.  		if(can_carry(mtmp, obj) && !obj->cursed)
202.  		    if(rn2(20) < edog->apport+3)
203.  			if(rn2(udist) || !rn2((int) edog->apport)) {
204.  			    if (cansee(omx, omy) && flags.verbose)
205.  				pline("%s picks up %s.", Monnam(mtmp),
206.  				    distant_name(obj, doname));
207.  			    freeobj(obj);
208.  			    newsym(omx,omy);
209.  			    mpickobj(mtmp,obj);
210.  			}
211.  	    }
212.  	}
213.  	return FALSE;
214.  }
215.  
216.  /* set dog's goal -- gtyp, gx, gy
217.   * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
218.   */
219.  static int
220.  dog_goal(mtmp, edog, after, udist, whappr)
221.  register struct monst *mtmp;
222.  struct edog *edog;
223.  int after, udist, whappr;
224.  {
225.  	register int omx, omy;
226.  	boolean in_masters_sight;
227.  	register struct obj *obj;
228.  	xchar otyp;
229.  	int appr;
230.  
231.  	omx = mtmp->mx;
232.  	omy = mtmp->my;
233.  
234.  	in_masters_sight = couldsee(omx, omy);
235.  
236.  	if (!edog
237.  #ifdef WALKIES
238.  		    || mtmp->mleashed	/* he's not going anywhere... */
239.  #endif
240.  					) {
241.  	    gtyp = APPORT;
242.  	    gx = u.ux;
243.  	    gy = u.uy;
244.  	} else {
245.  #define DDIST(x,y) (dist2(x,y,omx,omy))
246.  #define SQSRCHRADIUS 5
247.  	    int min_x, max_x, min_y, max_y;
248.  	    register int nx, ny;
249.  
250.  	    gtyp = UNDEF;	/* no goal as yet */
251.  	    gx = gy = 0;	/* suppress 'used before set' message */
252.  
253.  	    if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0;
254.  	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
255.  	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
256.  	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
257.  
258.  	    /* nearby food is the first choice, then other objects */
259.  	    for (obj = fobj; obj; obj = obj->nobj) {
260.  		nx = obj->ox;
261.  		ny = obj->oy;
262.  		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
263.  		    otyp = dogfood(mtmp, obj);
264.  		    if (otyp > gtyp || otyp == UNDEF)
265.  			continue;
266.  		    if (otyp < MANFOOD) {
267.  			if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
268.  			    gx = nx;
269.  			    gy = ny;
270.  			    gtyp = otyp;
271.  			}
272.  		    } else if(gtyp == UNDEF && in_masters_sight &&
273.  			      !mtmp->minvent &&
274.  			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
275.  			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
276.  			      edog->apport > rn2(8) &&
277.  			      can_carry(mtmp,obj)) {
278.  			gx = nx;
279.  			gy = ny;
280.  			gtyp = APPORT;
281.  		    }
282.  		}
283.  	    }
284.  	}
285.  
286.  	/* follow player if appropriate */
287.  	if (gtyp == UNDEF ||
288.  	    (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
289.  		gx = u.ux;
290.  		gy = u.uy;
291.  		if (after && udist <= 4 && gx == u.ux && gy == u.uy)
292.  			return(-2);
293.  		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
294.  		if (udist > 1) {
295.  			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
296.  			   whappr ||
297.  			   (mtmp->minvent && rn2((int) edog->apport)))
298.  				appr = 1;
299.  		}
300.  		/* if you have dog food it'll follow you more closely */
301.  		if (appr == 0) {
302.  			obj = invent;
303.  			while (obj) {
304.  				if(dogfood(mtmp, obj) == DOGFOOD) {
305.  					appr = 1;
306.  					break;
307.  				}
308.  				obj = obj->nobj;
309.  			}
310.  		}
311.  	} else
312.  	    appr = 1;	/* gtyp != UNDEF */
313.  	if(mtmp->mconf)
314.  	    appr = 0;
315.  
316.  #define FARAWAY (COLNO + 2)		/* position outside screen */
317.  	if (gx == u.ux && gy == u.uy && !in_masters_sight) {
318.  	    register coord *cp;
319.  
320.  	    cp = gettrack(omx,omy);
321.  	    if (cp) {
322.  		gx = cp->x;
323.  		gy = cp->y;
324.  		if(edog) edog->ogoal.x = 0;
325.  	    } else {
326.  		/* assume master hasn't moved far, and reuse previous goal */
327.  		if(edog && edog->ogoal.x &&
328.  		   ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
329.  		    gx = edog->ogoal.x;
330.  		    gy = edog->ogoal.y;
331.  		    edog->ogoal.x = 0;
332.  		} else {
333.  		    int fardist = FARAWAY * FARAWAY;
334.  		    gx = gy = FARAWAY; /* random */
335.  		    do_clear_area(omx, omy, 9, wantdoor,
336.  				  (genericptr_t)&fardist);
337.  
338.  		    /* here gx == FARAWAY e.g. when dog is in a vault */
339.  		    if (gx == FARAWAY || (gx == omx && gy == omy)) {
340.  			gx = u.ux;
341.  			gy = u.uy;
342.  		    } else if(edog) {
343.  			edog->ogoal.x = gx;
344.  			edog->ogoal.y = gy;
345.  		    }
346.  		}
347.  	    }
348.  	} else if(edog) {
349.  	    edog->ogoal.x = 0;
350.  	}
351.  	return appr;
352.  }
353.  
354.  /* return 0 (no move), 1 (move) or 2 (dead) */
355.  int
356.  dog_move(mtmp, after)
357.  register struct monst *mtmp;
358.  register int after;	/* this is extra fast monster movement */
359.  {
360.  	int omx, omy;		/* original mtmp position */
361.  	int appr, whappr, udist;
362.  	int i, j;
363.  	register struct edog *edog = EDOG(mtmp);
364.  	struct obj *obj = (struct obj *) 0;
365.  	xchar otyp;
366.  	boolean has_edog, cursemsg = FALSE, do_eat = FALSE;
367.  	xchar nix, niy;		/* position mtmp is (considering) moving to */
368.  	register int nx, ny;	/* temporary coordinates */
369.  	xchar cnt, uncursedcnt, chcnt;
370.  	int chi = -1, nidist, ndist;
371.  	coord poss[9];
372.  	long info[9], allowflags;
373.  #define GDIST(x,y) (dist2(x,y,gx,gy))
374.  
375.  	/*
376.  	 * Tame Angels have isminion set and an ispriest structure instead of
377.  	 * an edog structure.  Fortunately, guardian Angels need not worry
378.  	 * about mundane things like eating and fetching objects, and can
379.  	 * spend all their energy defending the player.  (They are the only
380.  	 * monsters with other structures that can be tame.)
381.  	 */
382.  	has_edog = !mtmp->isminion;
383.  
384.  	omx = mtmp->mx;
385.  	omy = mtmp->my;
386.  	if (has_edog && dog_hunger(mtmp, edog)) return(2);	/* starved */
387.  
388.  	udist = distu(omx,omy);
389.  	/* maybe we tamed him while being swallowed --jgm */
390.  	if (!udist) return(0);
391.  
392.  	nix = omx;	/* set before newdogpos */
393.  	niy = omy;
394.  
395.  	if (has_edog && dog_invent(mtmp, edog, udist))	/* eating something */
396.  		goto newdogpos;
397.  
398.  	if (has_edog)
399.  	    whappr = (moves - edog->whistletime < 5);
400.  	else
401.  	    whappr = 0;
402.  
403.  	appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,
404.  							after, udist, whappr);
405.  	if (appr == -2) return(0);
406.  
407.  	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
408.  	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
409.  	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
410.  	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
411.  	    allowflags |= ALLOW_U;
412.  	    if (!has_edog) {
413.  		coord mm;
414.  		/* Guardian angel refuses to be conflicted; rather,
415.  		 * it disappears, angrily, and sends in some nasties
416.  		 */
417.  		if (canseemon(mtmp) || sensemon(mtmp)) {
418.  		    pline("%s rebukes you, saying:", Monnam(mtmp));
419.  		    verbalize("Since you desire conflict, have some more!");
420.  		}
421.  		mongone(mtmp);
422.  		i = rnd(4);
423.  		while(i--) {
424.  		    mm.x = u.ux;
425.  		    mm.y = u.uy;
426.  		    if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
427.  			(void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
428.  					 mm.x, mm.y, FALSE);
429.  		}
430.  		return(2);
431.  
432.  	    }
433.  	}
434.  	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
435.  		allowflags |= OPENDOOR;
436.  		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
437.  	}
438.  	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
439.  	if (tunnels(mtmp->data) && !needspick(mtmp->data))
440.  		allowflags |= ALLOW_DIG;
441.  	cnt = mfndpos(mtmp, poss, info, allowflags);
442.  
443.  	/* Normally dogs don't step on cursed items, but if they have no
444.  	 * other choice they will.  This requires checking ahead of time
445.  	 * to see how many cursed item squares are around.
446.  	 */
447.  	uncursedcnt = 0;
448.  	for (i = 0; i < cnt; i++) {
449.  		nx = poss[i].x; ny = poss[i].y;
450.  		if (MON_AT(nx,ny)) continue;
451.  		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere)
452.  			if (obj->cursed) goto skipu;
453.  		uncursedcnt++;
454.  skipu:;
455.  	}
456.  
457.  	chcnt = 0;
458.  	chi = -1;
459.  	nidist = GDIST(nix,niy);
460.  
461.  	for (i = 0; i < cnt; i++) {
462.  		nx = poss[i].x;
463.  		ny = poss[i].y;
464.  #ifdef WALKIES
465.  		/* if leashed, we drag him along. */
466.  		if (mtmp->mleashed && distu(nx, ny) > 4) continue;
467.  #endif
468.  		/* if a guardian, try to stay close by choice */
469.  		if (!has_edog &&
470.  		    (j = distu(nx, ny)) > 16 && j >= udist) continue;
471.  
472.  		if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
473.  		    int stat;
474.  		    register struct monst *mtmp2 = m_at(nx,ny);
475.  
476.  		    if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||
477.  			(mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
478.  			 mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
479.  			 && (perceives(mtmp->data) || !mtmp2->minvis)) ||
480.  			(mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
481.  			(max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
482.  			(mtmp->mhp*4 < mtmp->mhpmax &&
483.  			 mtmp2->mpeaceful && !Conflict) ||
484.  			   (mtmp2->data->mlet == S_COCKATRICE &&
485.  				!resists_ston(mtmp->data)))
486.  			continue;
487.  
488.  		    if (after) return(0); /* hit only once each move */
489.  
490.  		    stat = mattackm(mtmp, mtmp2);
491.  
492.  		    /* aggressor (pet) died */
493.  		    if (stat & MM_AGR_DIED) return 2;
494.  
495.  		    if ((stat & MM_HIT) && !(stat & MM_DEF_DIED) &&
496.  			rn2(4) && mtmp2->mlstmv != monstermoves) {
497.  			stat = mattackm(mtmp2, mtmp);	/* return attack */
498.  			if (stat & MM_DEF_DIED) return 2;
499.  		    }
500.  
501.  		    return 0;
502.  		}
503.  
504.  		{   /* dog avoids traps, but perhaps it has to pass a trap
505.  		     * in order to follow player
506.  		     */
507.  		    struct trap *trap;
508.  
509.  		    if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
510.  			if ((trap->ttyp == RUST_TRAP
511.  					&& mtmp->data != &mons[PM_IRON_GOLEM])
512.  				|| trap->ttyp == STATUE_TRAP
513.  				|| ((trap->ttyp == PIT
514.  				    || trap->ttyp == SPIKED_PIT
515.  				    || (trap->ttyp == TRAPDOOR &&
516.  					!Can_fall_thru(&u.uz)))
517.  				    && (is_flyer(mtmp->data) ||
518.  					is_clinger(mtmp->data)))
519.  				|| (trap->ttyp == SLP_GAS_TRAP &&
520.  				    resists_sleep(mtmp->data)))
521.  			    if(!trap->tseen || rn2(3)) continue;
522.  #ifdef WALKIES
523.  			if (!mtmp->mleashed) {
524.  #endif
525.  			    if (!trap->tseen && rn2(40)) continue;
526.  			    if (rn2(10)) continue;
527.  #ifdef WALKIES
528.  			}
529.  # ifdef SOUNDS
530.  			else if (flags.soundok)
531.  				whimper(mtmp);
532.  # endif
533.  #endif
534.  		    }
535.  		}
536.  
537.  		/* dog eschews cursed objects, but likes dog food */
538.  		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
539.  		    if (obj->cursed && !mtmp->mleashed && uncursedcnt)
540.  			goto nxti;
541.  		    if (obj->cursed) cursemsg = TRUE;
542.  		    if (has_edog && (otyp = dogfood(mtmp, obj)) < MANFOOD &&
543.  				(otyp < ACCFOOD || edog->hungrytime <= moves)){
544.  			/* Note: our dog likes the food so much that he
545.  			 * might eat it even when it conceals a cursed object */
546.  			nix = nx;
547.  			niy = ny;
548.  			chi = i;
549.  			do_eat = TRUE;
550.  			goto newdogpos;
551.  		    }
552.  		}
553.  
554.  		for (j = 0; j < MTSZ && j < cnt-1; j++)
555.  			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
556.  				if (rn2(4*(cnt-j))) goto nxti;
557.  
558.  		j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
559.  		if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
560.  			(j > 0 && !whappr &&
561.  				((omx == nix && omy == niy && !rn2(3))
562.  					|| !rn2(12))
563.  			)) {
564.  			nix = nx;
565.  			niy = ny;
566.  			nidist = ndist;
567.  			if(j < 0) chcnt = 0;
568.  			chi = i;
569.  		}
570.  	nxti:	;
571.  	}
572.  newdogpos:
573.  	if (nix != omx || niy != omy) {
574.  		if (info[chi] & ALLOW_U) {
575.  #ifdef WALKIES
576.  			if (mtmp->mleashed) { /* play it safe */
577.  				pline("%s breaks loose of %s leash!",
578.  					Monnam(mtmp),
579.  					humanoid(mtmp->data)
580.  					    ? (mtmp->female ? "her" : "his")
581.  					    : "its");
582.  				m_unleash(mtmp);
583.  			}
584.  #endif
585.  			(void) mattacku(mtmp);
586.  			return(0);
587.  		}
588.  		/* insert a worm_move() if worms ever begin to eat things */
589.  		remove_monster(omx, omy);
590.  		place_monster(mtmp, nix, niy);
591.  		if (cursemsg && (cansee(omx,omy) || cansee(nix,niy)))
592.  			pline("%s moves only reluctantly.", Monnam(mtmp));
593.  		for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
594.  		mtmp->mtrack[0].x = omx;
595.  		mtmp->mtrack[0].y = omy;
596.  		/* We have to know if the pet's gonna do a combined eat and
597.  		 * move before moving it, but it can't eat until after being
598.  		 * moved.  Thus the do_eat flag.
599.  		 */
600.  		if (do_eat)
601.  			dog_eat(mtmp, obj, nix, niy);
602.  	}
603.  #ifdef WALKIES
604.  	  /* an incredible kludge, but the only way to keep pooch near
605.  	   * after it spends time eating or in a trap, etc.
606.  	   */
607.  	  else if (mtmp->mleashed && distu(omx, omy) > 4) {
608.  		coord cc;
609.  
610.  		nx = sgn(omx - u.ux);
611.  		ny = sgn(omy - u.uy);
612.  		cc.x = u.ux + nx;
613.  		cc.y = u.uy + ny;
614.  		if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
615.  
616.  	 	i  = xytod(nx, ny);
617.  		for (j = (i + 7)%8; j < (i + 1)%8; j++) {
618.  			dtoxy(&cc, j);
619.  			if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
620.  		}
621.  		for (j = (i + 6)%8; j < (i + 2)%8; j++) {
622.  			dtoxy(&cc, j);
623.  			if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext;
624.  		}
625.  		cc.x = mtmp->mx;
626.  		cc.y = mtmp->my;
627.  dognext:
628.  		remove_monster(mtmp->mx, mtmp->my);
629.  		place_monster(mtmp, cc.x, cc.y);
630.  		newsym(cc.x,cc.y);
631.  		set_apparxy(mtmp);
632.  	}
633.  #endif
634.  	return(1);
635.  }
636.  
637.  #endif /* OVL0 */
638.  #ifdef OVLB
639.  
640.  /*ARGSUSED*/	/* do_clear_area client */
641.  STATIC_PTR void
642.  wantdoor(x, y, distance)
643.  int x, y;
644.  genericptr_t distance;
645.  {
646.      register ndist;
647.  
648.      if (*(int*)distance > (ndist = distu(x, y))) {
649.  	gx = x;
650.  	gy = y;
651.  	*(int*)distance = ndist;
652.      }
653.  }
654.  
655.  #endif /* OVLB */
656.  
657.  /*dogmove.c*/