Wikia

Wikihack

Source:SLASH'EM 0.0.7E7F2/dogmove.c

2,032pages on
this wiki
Talk0

Below is the full text to dogmove.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/dogmove.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)dogmove.c	3.4	2002/09/10	*/
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.    #include "emin.h"
10.   #include "epri.h"
11.   
12.   /* #define DEBUG */	/* uncomment to enable debugging */
13.   
14.   #ifdef DEBUG
15.   # ifdef WIZARD
16.   #define debugpline      if (wizard) pline
17.   # else
18.   #define debugpline      pline
19.   # endif
20.   #endif
21.   
22.   extern boolean notonhead;
23.   
24.   #ifdef OVL0
25.   
26.   STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *));
27.   STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int));
28.   STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
29.   
30.   STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *));
31.   STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P,
32.       XCHAR_P,XCHAR_P));
33.   STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));
34.   
35.   STATIC_OVL struct obj *
36.   DROPPABLES(mon)
37.   register struct monst *mon;
38.   {
39.   	register struct obj *obj;
40.   	struct obj *wep = MON_WEP(mon);
41.   	boolean item1 = FALSE, item2 = FALSE;
42.   
43.   	if (is_animal(mon->data) || mindless(mon->data))
44.   		item1 = item2 = TRUE;
45.   	if (!tunnels(mon->data) || !needspick(mon->data))
46.   		item1 = TRUE;
47.   	for(obj = mon->minvent; obj; obj = obj->nobj) {
48.   		if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK
49.   						|| !which_armor(mon, W_ARMS))) {
50.   			item1 = TRUE;
51.   			continue;
52.   		}
53.   		if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) {
54.   			item2 = TRUE;
55.   			continue;
56.   		}
57.   		if (!obj->owornmask && obj != wep) return obj;
58.   	}
59.   	return (struct obj *)0;
60.   }
61.   
62.   static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
63.   
64.   #endif /* OVL0 */
65.   
66.   STATIC_OVL boolean FDECL(cursed_object_at, (struct monst *, int, int));
67.   
68.   STATIC_VAR xchar gtyp, gx, gy;	/* type and position of dog's current goal */
69.   
70.   STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
71.   
72.   #ifdef OVLB
73.   STATIC_OVL boolean
74.   cursed_object_at(mtmp, x, y)
75.   register struct monst *mtmp;
76.   int x, y;
77.   {
78.   	struct obj *otmp;
79.   
80.   	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
81.   		/* [Tom] demons & undead don't care, though */
82.   		/* [ALI] demons & undead avoid blessed items instead */
83.   		if ((is_demon(mtmp->data) || is_undead(mtmp->data)) ?
84.   		    otmp->blessed : otmp->cursed)
85.   	{
86.   #ifdef DEBUG
87.   		debugpline("%s thinks %s at (%d,%d) is `cursed'",
88.   		  noit_Monnam(mtmp), doname(otmp), x, y);
89.   #endif
90.   		return TRUE;
91.   	}
92.   	return FALSE;
93.   }
94.   
95.   int
96.   dog_nutrition(mtmp, obj)
97.   struct monst *mtmp;
98.   struct obj *obj;
99.   {
100.  	int nutrit;
101.  
102.  	/*
103.  	 * It is arbitrary that the pet takes the same length of time to eat
104.  	 * as a human, but gets more nutritional value.
105.  	 */
106.  	if (obj->oclass == FOOD_CLASS) {
107.  	    if(obj->otyp == CORPSE) {
108.  		mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
109.  		nutrit = mons[obj->corpsenm].cnutrit;
110.  	    } else {
111.  		mtmp->meating = objects[obj->otyp].oc_delay;
112.  		nutrit = objects[obj->otyp].oc_nutrition;
113.  	    }
114.  	    switch(mtmp->data->msize) {
115.  		case MZ_TINY: nutrit *= 8; break;
116.  		case MZ_SMALL: nutrit *= 6; break;
117.  		default:
118.  		case MZ_MEDIUM: nutrit *= 5; break;
119.  		case MZ_LARGE: nutrit *= 4; break;
120.  		case MZ_HUGE: nutrit *= 3; break;
121.  		case MZ_GIGANTIC: nutrit *= 2; break;
122.  	    }
123.  	    if(obj->oeaten) {
124.  		mtmp->meating = eaten_stat(mtmp->meating, obj);
125.  		nutrit = eaten_stat(nutrit, obj);
126.  	    }
127.  	} else if (obj->oclass == COIN_CLASS) {
128.  	    mtmp->meating = (int)(obj->quan/2000) + 1;
129.  	    if (mtmp->meating < 0) mtmp->meating = 1;
130.  	    nutrit = (int)(obj->quan/20);
131.  	    if (nutrit < 0) nutrit = 0;
132.  	} else {
133.  	    /* Unusual pet such as gelatinous cube eating odd stuff.
134.  	     * meating made consistent with wild monsters in mon.c.
135.  	     * nutrit made consistent with polymorphed player nutrit in
136.  	     * eat.c.  (This also applies to pets eating gold.)
137.  	     */
138.  	    mtmp->meating = obj->owt/20 + 1;
139.  	    nutrit = 5*objects[obj->otyp].oc_nutrition;
140.  	}
141.  	return nutrit;
142.  }
143.  
144.  /* returns 2 if pet dies, otherwise 1 */
145.  int
146.  dog_eat(mtmp, obj, x, y, devour)
147.  register struct monst *mtmp;
148.  register struct obj * obj;
149.  int x, y;
150.  boolean devour;
151.  {
152.  	register struct edog *edog = EDOG(mtmp);
153.  	boolean poly = FALSE, grow = FALSE, heal = FALSE;
154.  	int nutrit;
155.  	boolean vis = (cansee(x, y) || cansee(mtmp->mx, mtmp->my));
156.  	boolean vampiric = is_vampire(mtmp->data);
157.  
158.  	if(edog->hungrytime < monstermoves)
159.  	    edog->hungrytime = monstermoves;
160.  	nutrit = dog_nutrition(mtmp, obj);
161.  	poly = polyfodder(obj);
162.  	grow = mlevelgain(obj);
163.  	heal = mhealup(obj);
164.  	if (devour) {
165.  	    if (mtmp->meating > 1) mtmp->meating /= 2;
166.  	    if (nutrit > 1) nutrit = (nutrit * 3) / 4;
167.  	}
168.  
169.  	/* vampires only get 1/5 normal nutrition */
170.  	if (vampiric) {
171.  	    mtmp->meating = (mtmp->meating + 4) / 5;
172.  	    nutrit = (nutrit + 4) / 5;
173.  	}
174.  	
175.  	edog->hungrytime += nutrit;
176.  	mtmp->mconf = 0;
177.  	if (edog->mhpmax_penalty) {
178.  	    /* no longer starving */
179.  	    mtmp->mhpmax += edog->mhpmax_penalty;
180.  	    edog->mhpmax_penalty = 0;
181.  	}
182.  	if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2;
183.  	if (mtmp->mtame < 20) mtmp->mtame++;
184.  	if (x != mtmp->mx || y != mtmp->my) {	/* moved & ate on same turn */
185.  	    newsym(x, y);
186.  	    newsym(mtmp->mx, mtmp->my);
187.  	}
188.  	if (is_pool(x, y) && !Underwater) {
189.  	    /* Don't print obj */
190.  	    /* TODO: Reveal presence of sea monster (especially sharks) */
191.  	} else
192.  	/* hack: observe the action if either new or old location is in view */
193.  	/* However, invisible monsters should still be "it" even though out of
194.  	   sight locations should not. */
195.  	if (vis)
196.  	    pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It",
197.  		  vampiric ? "drains" : devour ? "devours" : "eats",
198.  		  (obj->oclass == FOOD_CLASS) ?
199.  			singular(obj, doname) : doname(obj));
200.  	/* It's a reward if it's DOGFOOD and the player dropped/threw it. */
201.  	/* We know the player had it if invlet is set -dlc */
202.  	if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
203.  #ifdef LINT
204.  	    edog->apport = 0;
205.  #else
206.  	    edog->apport += (int)(200L/
207.  		((long)edog->dropdist + monstermoves - edog->droptime));
208.  #endif
209.  	if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
210.  	    /* The object's rustproofing is gone now */
211.  	    obj->oerodeproof = 0;
212.  	    mtmp->mstun = 1;
213.  	    if (canseemon(mtmp) && flags.verbose) {
214.  		pline("%s spits %s out in disgust!",
215.  		      Monnam(mtmp), distant_name(obj,doname));
216.  	    }
217.  	} else if (vampiric) {
218.  		/* Split Object */
219.  		if (obj->quan > 1L) {
220.  		    if(!carried(obj)) {
221.  			(void) splitobj(obj, 1L);
222.  		    } else {
223.  		    	/* Carried */
224.  			obj = splitobj(obj, obj->quan - 1L);
225.  			
226.  			freeinv(obj);
227.  			if (inv_cnt() >= 52 && !merge_choice(invent, obj))
228.  			    dropy(obj);
229.  			else
230.  			    obj = addinv(obj); /* unlikely but a merge is possible */			
231.  		    }
232.  #ifdef DEBUG
233.  		    debugpline("split object,");
234.  #endif
235.  		}
236.  		
237.  		/* Take away blood nutrition */
238.  	    	obj->oeaten = drainlevel(obj);
239.  		obj->odrained = 1;
240.  	} else if (obj == uball) {
241.  	    unpunish();
242.  	    delobj(obj);
243.  	} else if (obj == uchain)
244.  	    unpunish();
245.  	else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) {
246.  	    obj->quan--;
247.  	    obj->owt = weight(obj);
248.  	} else
249.  	    delobj(obj);
250.  
251.  	if (poly) {
252.  	    (void) mon_spec_poly(mtmp, (struct permonst *)0, 0L, FALSE,
253.  		    cansee(mtmp->mx, mtmp->my), FALSE, FALSE);
254.  #if 0
255.  	    (void) newcham(mtmp, (struct permonst *)0, FALSE,
256.  			   cansee(mtmp->mx, mtmp->my));
257.  #endif
258.  	}
259.  	/* limit "instant" growth to prevent potential abuse */
260.  	if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) {
261.  	    if (!grow_up(mtmp, (struct monst *)0)) return 2;
262.  	}
263.  	if (heal) mtmp->mhp = mtmp->mhpmax;
264.  	return 1;
265.  }
266.  
267.  #endif /* OVLB */
268.  #ifdef OVL0
269.  
270.  /* hunger effects -- returns TRUE on starvation */
271.  STATIC_OVL boolean
272.  dog_hunger(mtmp, edog)
273.  register struct monst *mtmp;
274.  register struct edog *edog;
275.  {
276.  	if (monstermoves > edog->hungrytime + 500) {
277.  	    if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
278.  		edog->hungrytime = monstermoves + 500;
279.  		/* but not too high; it might polymorph */
280.  	    } else if (!edog->mhpmax_penalty) {
281.  		/* starving pets are limited in healing */
282.  		int newmhpmax = mtmp->mhpmax / 3;
283.  		mtmp->mconf = 1;
284.  		edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
285.  		mtmp->mhpmax = newmhpmax;
286.  		if (mtmp->mhp > mtmp->mhpmax)
287.  		    mtmp->mhp = mtmp->mhpmax;
288.  		if (mtmp->mhp < 1) goto dog_died;
289.  		if (cansee(mtmp->mx, mtmp->my))
290.  		    pline("%s is confused from hunger.", Monnam(mtmp));
291.  		else if (couldsee(mtmp->mx, mtmp->my))
292.  		    beg(mtmp);
293.  		else
294.  		    You_feel("worried about %s.", y_monnam(mtmp));
295.  		stop_occupation();
296.  	    } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
297.   dog_died:
298.  		if (mtmp->mleashed
299.  #ifdef STEED
300.  		    && mtmp != u.usteed
301.  #endif
302.  		    )
303.  		    Your("leash goes slack.");
304.  		else if (cansee(mtmp->mx, mtmp->my))
305.  		    pline("%s starves.", Monnam(mtmp));
306.  		else
307.  		    You_feel("%s for a moment.",
308.  			Hallucination ? "bummed" : "sad");
309.  		mondied(mtmp);
310.  		return(TRUE);
311.  	    }
312.  	}
313.  	return(FALSE);
314.  }
315.  
316.  /* do something with object (drop, pick up, eat) at current position
317.   * returns 1 if object eaten (since that counts as dog's move), 2 if died
318.   */
319.  STATIC_OVL int
320.  dog_invent(mtmp, edog, udist)
321.  register struct monst *mtmp;
322.  register struct edog *edog;
323.  int udist;
324.  {
325.  	/* KMH, balance patch -- quantity picked up should depend on dog's level */
326.  	int dogquan = 10 * mtmp->m_lev;
327.  	register int omx, omy;
328.  	struct obj *obj;
329.  /*
330.  	struct obj *floor_obj;
331.  	int temp_quan;
332.   */
333.  	if (mtmp->msleeping || !mtmp->mcanmove) return(0);
334.  
335.  	omx = mtmp->mx;
336.  	omy = mtmp->my;
337.  
338.  	/* if we are carrying sth then we drop it (perhaps near @) */
339.  	/* Note: if apport == 1 then our behaviour is independent of udist */
340.  	/* Use udist+1 so steed won't cause divide by zero */
341.  #ifndef GOLDOBJ
342.  	if(DROPPABLES(mtmp) || mtmp->mgold) {
343.  #else
344.  	if(DROPPABLES(mtmp)) {
345.  #endif
346.  	    if (!rn2(udist+1) || !rn2(edog->apport))
347.  		if(rn2(10) < edog->apport){
348.  		    relobj(mtmp, (int)mtmp->minvis, TRUE);
349.  		    if(edog->apport > 1) edog->apport--;
350.  		    edog->dropdist = udist;		/* hpscdi!jon */
351.  		    edog->droptime = moves;
352.  		}
353.  	} else {
354.  	    if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
355.  #ifdef MAIL
356.  			&& obj->otyp != SCR_MAIL
357.  #endif
358.  									){
359.  		int edible = dogfood(mtmp, obj);
360.  
361.  		if ((edible <= CADAVER ||
362.  			/* starving pet is more aggressive about eating */
363.  			(edog->mhpmax_penalty && edible == ACCFOOD)) &&
364.  		    could_reach_item(mtmp, obj->ox, obj->oy))
365.  		    return dog_eat(mtmp, obj, omx, omy, FALSE);
366.  
367.  		/* [Tom] demonic & undead pets don't mind cursed items */                
368.  		if(can_carry(mtmp, obj) &&
369.  		  could_reach_item(mtmp, obj->ox, obj->oy) &&
370.  		  (!obj->cursed || is_demon(mtmp->data) || is_undead(mtmp->data)) &&
371.  		  (!obj->blessed || (!is_demon(mtmp->data) && !is_undead(mtmp->data)))) {
372.  		    if(rn2(20) < edog->apport+3) {
373.  			if (rn2(udist) || !rn2(edog->apport)) {
374.  			    if ((!nohands(mtmp->data)) ||
375.  						/* KMH, balance patch -- 10*level */
376.  						(obj->quan <= dogquan))
377.  			    {
378.  			    if (cansee(omx, omy) && flags.verbose)
379.  				pline("%s picks up %s.", Monnam(mtmp),
380.  				    distant_name(obj, doname));
381.  			    obj_extract_self(obj);
382.  			    newsym(omx,omy);
383.  			    (void) mpickobj(mtmp,obj);
384.  			    }                            
385.  			    else /* picking up a few objects from a pile... */
386.  				/* KMH -- fix picking up zero quantity */
387.  			    if (dogquan > 0) {
388.  				if (obj->oclass == COIN_CLASS) {
389.  				    /* KMH, balance patch -- 10*level */
390.  #ifndef GOLDOBJ
391.  				    obj->quan -= dogquan;
392.  				    if (cansee(omx, omy) && flags.verbose)
393.  					pline("%s picks up %d gold pieces.", 
394.  							Monnam(mtmp),
395.  							dogquan);
396.  				    mtmp->mgold += dogquan;
397.  #else
398.  						if (obj->quan != dogquan)
399.  							obj = splitobj(obj, dogquan);
400.  				    if (cansee(omx, omy) && flags.verbose)
401.  							pline("%s picks up %s.", 
402.  							Monnam(mtmp),
403.  							doname(obj));
404.  							obj_extract_self(obj);
405.  				    	newsym(omx,omy);
406.  							(void) mpickobj(mtmp,obj);
407.  #endif
408.  				} else {
409.  /*
410.                                  struct obj *floor_obj;
411.                                  int temp_quan;
412.  
413.                                  obj->quan -= dogquan;
414.  				temp_quan = obj->quan;
415.  				floor_obj = level.objects[omx][omy];
416.  				mpickobj(mtmp,obj);
417.  				obj->quan = dogquan;
418.  				if (cansee(omx, omy) && flags.verbose)
419.  				pline("%s picks up %s.", Monnam(mtmp),
420.  				    distant_name(obj, doname));
421.  				floor_obj->quan = temp_quan;*/
422.  				}
423.  			    }
424.  			    if (attacktype(mtmp->data, AT_WEAP) &&
425.  					mtmp->weapon_check == NEED_WEAPON) {
426.  				mtmp->weapon_check = NEED_HTH_WEAPON;
427.  				(void) mon_wield_item(mtmp);
428.  			    }
429.  			    m_dowear(mtmp, FALSE);
430.  			}
431.  		    }
432.  		}
433.  	    }
434.  	}
435.  	return 0;
436.  }
437.  
438.  /* set dog's goal -- gtyp, gx, gy
439.   * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
440.   */
441.  STATIC_OVL int
442.  dog_goal(mtmp, edog, after, udist, whappr)
443.  register struct monst *mtmp;
444.  struct edog *edog;
445.  int after, udist, whappr;
446.  {
447.  	register int omx, omy;
448.  	boolean in_masters_sight, dog_has_minvent;
449.  	register struct obj *obj;
450.  	xchar otyp;
451.  	int appr;
452.  
453.  #ifdef STEED
454.  	/* Steeds don't move on their own will */
455.  	if (mtmp == u.usteed)
456.  		return (-2);
457.  #endif
458.  
459.  	omx = mtmp->mx;
460.  	omy = mtmp->my;
461.  
462.  	in_masters_sight = couldsee(omx, omy);
463.  	dog_has_minvent = (DROPPABLES(mtmp) != 0);
464.  
465.  	if (!edog || mtmp->mleashed) {	/* he's not going anywhere... */
466.  	    gtyp = APPORT;
467.  	    gx = u.ux;
468.  	    gy = u.uy;
469.  	} else {
470.  #define DDIST(x,y) (dist2(x,y,omx,omy))
471.  #define SQSRCHRADIUS 5
472.  	    int min_x, max_x, min_y, max_y;
473.  	    register int nx, ny;
474.  
475.  	    gtyp = UNDEF;	/* no goal as yet */
476.  	    gx = gy = 0;	/* suppress 'used before set' message */
477.  
478.  	    if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1;
479.  	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
480.  	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
481.  	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
482.  
483.  	    /* nearby food is the first choice, then other objects */
484.  	    for (obj = fobj; obj; obj = obj->nobj) {
485.  		nx = obj->ox;
486.  		ny = obj->oy;
487.  		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
488.  		    otyp = dogfood(mtmp, obj);
489.  		    /* skip inferior goals */
490.  		    if (otyp > gtyp || otyp == UNDEF)
491.  			continue;
492.  		    /* avoid cursed items unless starving */
493.  		    if (cursed_object_at(mtmp, nx, ny) &&
494.  			    !(edog->mhpmax_penalty && otyp < MANFOOD))
495.  			continue;
496.  		    /* skip completely unreacheable goals */
497.  		    if (!could_reach_item(mtmp, nx, ny) ||
498.  		        !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
499.  			continue;
500.  		    if (otyp < MANFOOD) {
501.  			if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
502.  			    gx = nx;
503.  			    gy = ny;
504.  			    gtyp = otyp;
505.  			}
506.  		    } else if(gtyp == UNDEF && in_masters_sight &&
507.  			      !dog_has_minvent &&
508.  			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
509.  			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
510.  			      edog->apport > rn2(8) &&
511.  			      can_carry(mtmp,obj)) {
512.  			gx = nx;
513.  			gy = ny;
514.  			gtyp = APPORT;
515.  		    }
516.  		}
517.  	    }
518.  	}
519.  
520.  	/* follow player if appropriate */
521.  	if (gtyp == UNDEF ||
522.  	    (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) {
523.  		gx = u.ux;
524.  		gy = u.uy;
525.  		if (after && udist <= 4 && gx == u.ux && gy == u.uy)
526.  			return(-2);
527.  		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
528.  		if (udist > 1) {
529.  			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
530.  			   whappr ||
531.  			   (dog_has_minvent && rn2(edog->apport)))
532.  				appr = 1;
533.  		}
534.  		/* if you have dog food it'll follow you more closely */
535.  		if (appr == 0) {
536.  			obj = invent;
537.  			while (obj) {
538.  				if(dogfood(mtmp, obj) == DOGFOOD) {
539.  					appr = 1;
540.  					break;
541.  				}
542.  				obj = obj->nobj;
543.  			}
544.  		}
545.  	} else
546.  	    appr = 1;	/* gtyp != UNDEF */
547.  	if(mtmp->mconf)
548.  	    appr = 0;
549.  
550.  #define FARAWAY (COLNO + 2)		/* position outside screen */
551.  	if (gx == u.ux && gy == u.uy && !in_masters_sight) {
552.  	    register coord *cp;
553.  
554.  	    cp = gettrack(omx,omy);
555.  	    if (cp) {
556.  		gx = cp->x;
557.  		gy = cp->y;
558.  		if(edog) edog->ogoal.x = 0;
559.  	    } else {
560.  		/* assume master hasn't moved far, and reuse previous goal */
561.  		if(edog && edog->ogoal.x &&
562.  		   ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
563.  		    gx = edog->ogoal.x;
564.  		    gy = edog->ogoal.y;
565.  		    edog->ogoal.x = 0;
566.  		} else {
567.  		    int fardist = FARAWAY * FARAWAY;
568.  		    gx = gy = FARAWAY; /* random */
569.  		    do_clear_area(omx, omy, 9, wantdoor,
570.  				  (genericptr_t)&fardist);
571.  
572.  		    /* here gx == FARAWAY e.g. when dog is in a vault */
573.  		    if (gx == FARAWAY || (gx == omx && gy == omy)) {
574.  			gx = u.ux;
575.  			gy = u.uy;
576.  		    } else if(edog) {
577.  			edog->ogoal.x = gx;
578.  			edog->ogoal.y = gy;
579.  		    }
580.  		}
581.  	    }
582.  	} else if(edog) {
583.  	    edog->ogoal.x = 0;
584.  	}
585.  	return appr;
586.  }
587.  
588.  #ifdef DEBUG
589.  #define CHECK_ALLOW(flag,str)	if ((allowflags & (flag)) == (flag)) { \
590.  				    allowflags ^= (flag); \
591.  				    if (bp != buf) { *bp++=','; *bp++=' '; } \
592.  				    Strcpy(bp, str); \
593.  				    bp += strlen(bp); \
594.  				} else
595.  
596.  STATIC_OVL char *
597.  allow_set(allowflags)
598.  long allowflags;
599.  {
600.      static char buf[500];
601.      char *bp = buf;
602.      if (allowflags == 0)
603.  	return "(none)";
604.      *bp = '\0';
605.      CHECK_ALLOW(ALLOW_TRAPS, "can enter traps");
606.      CHECK_ALLOW(ALLOW_U, "can attack you");
607.      CHECK_ALLOW(ALLOW_M, "can attack other monsters");
608.      CHECK_ALLOW(ALLOW_TM, "can attack tame monsters");
609.      CHECK_ALLOW(NOTONL, "avoids direct line to player");
610.      CHECK_ALLOW(OPENDOOR, "opens closed doors");
611.      CHECK_ALLOW(UNLOCKDOOR, "unlocks locked doors");
612.      CHECK_ALLOW(BUSTDOOR, "breaks any doors");
613.      CHECK_ALLOW(ALLOW_ROCK, "pushes rocks");
614.      CHECK_ALLOW(ALLOW_WALL, "walks thru walls");
615.      CHECK_ALLOW(ALLOW_DIG, "digs");
616.      CHECK_ALLOW(ALLOW_SANCT, "enters temples");
617.      CHECK_ALLOW(ALLOW_SSM, "ignores scare monster");
618.      CHECK_ALLOW(NOGARLIC, "hates garlic");
619.      if (allowflags) {
620.  	if (bp != buf) { *bp++=','; *bp++=' '; }
621.  	sprintf(bp, "0x%lX", allowflags);
622.      }
623.      return buf;
624.  }
625.  
626.  #undef CHECK_ALLOW
627.  #endif
628.  
629.  boolean
630.  betrayed(mtmp)
631.  register struct monst *mtmp;
632.  {
633.      boolean has_edog = !mtmp->isminion;
634.      struct edog *edog = EDOG(mtmp);
635.      int udist = distu(mtmp->mx, mtmp->my);
636.  
637.      if (udist < 4 && has_edog && !mtmp->isspell && !rn2(3)
638.  		    && can_betray(mtmp->data)
639.  		    && !mindless(mtmp->data)
640.  		    && mtmp->mhp >= u.uhp	/* Pet is buff enough */
641.  		    && rn2(22) > mtmp->mtame	/* Roll against tameness */
642.  		    && rn2(edog->abuse + 2)) {
643.  	/* Treason */
644.  	if (canseemon(mtmp))
645.  	    pline("%s turns on you!", Monnam(mtmp));
646.  	else
647.  	    pline("You feel uneasy about %s.", y_monnam(mtmp));
648.  	mtmp->mpeaceful = 0;
649.  	mtmp->mtame = 0;
650.  	mtmp->mtraitor = TRUE;
651.  
652.  	/* Do we need to call newsym() here? */
653.  	newsym(mtmp->mx, mtmp->my);
654.  	return TRUE;
655.      }
656.      return FALSE;
657.  }
658.  
659.  /* return 0 (no move), 1 (move) or 2 (dead) */
660.  int
661.  dog_move(mtmp, after)
662.  register struct monst *mtmp;
663.  register int after;	/* this is extra fast monster movement */
664.  {
665.  	int omx, omy;		/* original mtmp position */
666.  	int appr, whappr, udist;
667.  	int i, j, k;
668.  	register struct edog *edog = EDOG(mtmp);
669.  	struct obj *obj = (struct obj *) 0;
670.  	xchar otyp;
671.  	boolean has_edog, cursemsg[9], is_spell, do_eat = FALSE;
672.  	xchar nix, niy;		/* position mtmp is (considering) moving to */
673.  	register int nx, ny;	/* temporary coordinates */
674.  	xchar cnt, uncursedcnt, chcnt;
675.  	int chi = -1, nidist, ndist;
676.  	coord poss[9];
677.  	long info[9], allowflags;
678.  #define GDIST(x,y) (dist2(x,y,gx,gy))
679.  
680.  	/*
681.  	 * Tame Angels have isminion set and an ispriest structure instead of
682.  	 * an edog structure.  Fortunately, guardian Angels need not worry
683.  	 * about mundane things like eating and fetching objects, and can
684.  	 * spend all their energy defending the player.  (They are the only
685.  	 * monsters with other structures that can be tame.)
686.  	 */
687.  	has_edog = !mtmp->isminion;
688.  
689.  	/*
690.  	 * Similar to Angels and Guardians are spell beings - temporary
691.  	 * magical manifestations of the spellcaster's mind.
692.  	 * They don't eat/pickup objects - only fight.
693.  	 * But,  they aren't dismissed by conflict.
694.  	 */
695.  	is_spell = mtmp->isspell;
696.  
697.  	omx = mtmp->mx;
698.  	omy = mtmp->my;
699.  	if (has_edog && !is_spell && dog_hunger(mtmp, edog)) return(2);      /* starved */
700.  
701.  	udist = distu(omx,omy);
702.  #ifdef STEED
703.  	/* Let steeds eat and maybe throw rider during Conflict */
704.  	if (mtmp == u.usteed) {
705.  	    if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
706.  		dismount_steed(DISMOUNT_THROWN);
707.  		return (1);
708.  	    }
709.  	    udist = 1;
710.  	} else
711.  #endif
712.  	/* maybe we tamed him while being swallowed --jgm */
713.  	if (!udist) return(0);
714.  
715.  	/* Intelligent pets may rebel (apart from minions, spell beings) */
716.  	if (!rn2(850) && betrayed(mtmp)) return 1;
717.  
718.  	nix = omx;	/* set before newdogpos */
719.  	niy = omy;
720.  	cursemsg[0] = FALSE;	/* lint suppression */
721.  	info[0] = 0;		/* ditto */
722.  
723.  	if (has_edog && !is_spell) {
724.  	    j = dog_invent(mtmp, edog, udist);
725.  	    if (j == 2) return 2;		/* died */
726.  	    else if (j == 1) goto newdogpos;	/* eating something */
727.  
728.  	    whappr = (monstermoves - edog->whistletime < 5);
729.  	} else
730.  	    whappr = 0;
731.  
732.  	appr = dog_goal(mtmp, (has_edog && !is_spell) ? edog : (struct edog *)0,
733.  							after, udist, whappr);
734.  #ifdef DEBUG
735.  	{
736.  	    char *goal;
737.  	    switch(gtyp)
738.  	    {
739.  		case DOGFOOD:	goal = "dogfood"; break;
740.  		case CADAVER:	goal = "cadaver"; break;
741.  		case ACCFOOD:	goal = "accfood"; break;
742.  		case MANFOOD:	goal = "manfood"; break;
743.  		case APPORT:	goal = "apport"; break;
744.  		case POISON:	goal = "poison"; break;
745.  		case UNDEF:	goal = "undef"; break;
746.  		case TABU:	goal = "tabu"; break;
747.  		default:	goal = "???"; break;
748.  	    }
749.  	    debugpline("G(%s): %s @ (%d,%d), appr = %d",
750.  	      mon_nam(mtmp), goal, gx, gy, appr);
751.  	}
752.  #endif
753.  	if (appr == -2) return(0);
754.  
755.  	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
756.  	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL);
757.  	if (passes_bars(mtmp->data) && !In_sokoban(&u.uz))
758.  	    allowflags |= ALLOW_BARS;
759.  	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
760.  	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0) && In_endgame(&u.uz)) {
761.  	    allowflags |= ALLOW_U;
762.  	    if (!has_edog && !is_spell) {
763.  		coord mm;
764.  		/* Guardian angel refuses to be conflicted; rather,
765.  		 * it disappears, angrily, and sends in some nasties
766.  		 */
767.  		if (canspotmon(mtmp)) {
768.  		    pline("%s rebukes you, saying:", Monnam(mtmp));
769.  		    verbalize("Since you desire conflict, have some more!");
770.  		}
771.  		mongone(mtmp);
772.  		i = rnd(4);
773.  		while(i--) {
774.  		    mm.x = u.ux;
775.  		    mm.y = u.uy;
776.  		    if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
777.  			(void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
778.  					 mm.x, mm.y, FALSE);
779.  		}
780.  		return(2);
781.  
782.  	    }
783.  	}
784.  
785.  	/* ALI -- Mindless pets shouldn't attack monsters when
786.  	 * scared; they have no sense of allegiance to the hero,
787.  	 * only self-preservation. This prevents weak pets blocking
788.  	 * your exit from a shop by constantly missing shopkeeper.
789.  	 */
790.  	if (mindless(mtmp->data) && mtmp->mflee)
791.  	    allowflags &= ~ALLOW_M;
792.  
793.  	if (!Conflict && !mtmp->mconf &&
794.  	    mtmp == u.ustuck && !sticks(youmonst.data)) {
795.  	    unstuck(mtmp);	/* swallowed case handled above */
796.  	    You("get released!");
797.  	}
798.  	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
799.  		allowflags |= OPENDOOR;
800.  		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
801.  	}
802.  	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
803.  	if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
804.  	cnt = mfndpos(mtmp, poss, info, allowflags);
805.  #ifdef DEBUG
806.  	debugpline("%d positions found with allow: %s", cnt,
807.  	  allow_set(allowflags));
808.  	for (i = 0; i < cnt; i++) {
809.  	    debugpline("[%d] %s @ (%d, %d)", i,
810.  	      allow_set(info[i]), poss[i].x, poss[i].y);
811.  	}
812.  #endif
813.  
814.  	/* Normally dogs don't step on cursed items, but if they have no
815.  	 * other choice they will.  This requires checking ahead of time
816.  	 * to see how many uncursed item squares are around.
817.  	 */
818.  
819.  	uncursedcnt = 0;
820.  	for (i = 0; i < cnt; i++) {
821.  		nx = poss[i].x; ny = poss[i].y;
822.  		if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue;
823.  		if (cursed_object_at(mtmp, nx, ny)) continue;
824.  		uncursedcnt++;
825.  	}
826.  
827.  	chcnt = 0;
828.  	chi = -1;
829.  	nidist = GDIST(nix,niy);
830.  
831.  	for (i = 0; i < cnt; i++) {
832.  		nx = poss[i].x;
833.  		ny = poss[i].y;
834.  		cursemsg[i] = FALSE;
835.  
836.  		/* if leashed, we drag him along. */
837.  		if (mtmp->mleashed && distu(nx, ny) > 4) continue;
838.  
839.  		/* if a guardian, try to stay close by choice */
840.  		if ((!has_edog || is_spell) &&
841.  		    (j = distu(nx, ny)) > 16 && j >= udist) continue;
842.  
843.  		if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
844.  		    int mstatus;
845.  		    register struct monst *mtmp2 = m_at(nx,ny);
846.  		    aligntyp align1, align2; /* For priests, minions etc. */
847.  
848.  		    if (mtmp->isminion) align1 = EMIN(mtmp)->min_align;
849.  		    else if (is_unicorn(mtmp->data))
850.  			align1 = sgn(mtmp->data->maligntyp);
851.  		    else if (mtmp->ispriest) align1 = EPRI(mtmp)->shralign;
852.  		    else align1 = A_NONE;
853.  		    if (mtmp2->isminion) align2 = EMIN(mtmp2)->min_align;
854.  		    else if (is_unicorn(mtmp2->data))
855.  			align2 = sgn(mtmp2->data->maligntyp);
856.  		    else if (mtmp2->ispriest) align2 = EPRI(mtmp2)->shralign;
857.  		    else align2 = A_NONE;
858.  
859.  		    /* Mindless monsters and spelled monsters have no fear of 
860.  		     * attacking higher level monsters 
861.  		     */
862.  		    if (((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 && !is_spell && 
863.  			    !mindless(mtmp->data)) ||
864.  			(mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
865.  			 mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
866.  			 && (perceives(mtmp->data) || !mtmp2->minvis)) ||
867.  			(mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
868.  			(mtmp2->data==&mons[PM_GAS_SPORE] && rn2(16)) ||
869.  			(!attacktype(mtmp->data, AT_EXPL) &&
870.  			 max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
871.  			/* Minions/Angels don't attack
872.  			 * coaligned minions/priests/angels/unicorns.
873.  			 */
874.  			(align1 == align2 && align1 != A_NONE) ||
875.  			((mtmp->mhp*4 < mtmp->mhpmax
876.  			  || mtmp2->data->msound == MS_GUARDIAN
877.  			  || mtmp2->data->msound == MS_LEADER) &&
878.  			 mtmp2->mpeaceful && !Conflict) ||
879.  			   (touch_petrifies(mtmp2->data) &&
880.  				!resists_ston(mtmp)))
881.  			continue;
882.  
883.  		    if (after) return(0); /* hit only once each move */
884.  
885.  		    notonhead = 0;
886.  		    mstatus = mattackm(mtmp, mtmp2);
887.  
888.  		    /* aggressor (pet) died */
889.  		    if (mstatus & MM_AGR_DIED) return 2;
890.  
891.  		    if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&
892.  			    rn2(4) && mtmp2->mlstmv != monstermoves &&
893.  			    !onscary(mtmp->mx, mtmp->my, mtmp2) &&
894.  			    /* monnear check needed: long worms hit on tail */
895.  			    monnear(mtmp2, mtmp->mx, mtmp->my)) {
896.  			mstatus = mattackm(mtmp2, mtmp);  /* return attack */
897.  			if (mstatus & MM_DEF_DIED) return 2;
898.  		    }
899.  
900.  		    return 0;
901.  		}
902.  
903.  		{   /* Dog avoids harmful traps, but perhaps it has to pass one
904.  		     * in order to follow player.  (Non-harmful traps do not
905.  		     * have ALLOW_TRAPS in info[].)  The dog only avoids the
906.  		     * trap if you've seen it, unlike enemies who avoid traps
907.  		     * if they've seen some trap of that type sometime in the
908.  		     * past.  (Neither behavior is really realistic.)
909.  		     */
910.  		    struct trap *trap;
911.  
912.  		    if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
913.  			if (mtmp->mleashed) {
914.  			    if (flags.soundok) whimper(mtmp);
915.  			} else
916.  			    /* 1/40 chance of stepping on it anyway, in case
917.  			     * it has to pass one to follow the player...
918.  			     */
919.  			    if (trap->tseen && rn2(40)) continue;
920.  		    }
921.  		}
922.  
923.  		/* dog eschews cursed objects, but likes dog food */
924.  		/* [Tom] except demons & undead, who don't care */  
925.  		/* (minion isn't interested; `cursemsg' stays FALSE) */
926.  		if (has_edog && !is_spell) {
927.  		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
928.  		    if ((obj->cursed) && has_edog && !is_demon(mtmp->data) 
929.  		    && !is_undead(mtmp->data)) cursemsg[i] = TRUE;
930.  		    if (obj->blessed && has_edog && (is_demon(mtmp->data) 
931.  		    || is_undead(mtmp->data))) cursemsg[i] = TRUE;
932.  		    else if ((otyp = dogfood(mtmp, obj)) < MANFOOD &&
933.  			     (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) {
934.  			/* Note: our dog likes the food so much that he
935.  			 * might eat it even when it conceals a cursed object */
936.  			nix = nx;
937.  			niy = ny;
938.  			chi = i;
939.  			do_eat = TRUE;
940.  			cursemsg[i] = FALSE;	/* not reluctant */
941.  			goto newdogpos;
942.  		    }
943.  		}
944.  		}
945.  		/* didn't find something to eat; if we saw a cursed item and
946.  		   aren't being forced to walk on it, usually keep looking */
947.  		if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 &&
948.  		    rn2(13 * uncursedcnt)) continue;
949.  
950.  		/* lessen the chance of backtracking to previous position(s) */
951.  		k = (has_edog && !is_spell) ? uncursedcnt : cnt;
952.  		for (j = 0; j < MTSZ && j < k - 1; j++)
953.  			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
954.  				if (rn2(MTSZ * (k - j))) goto nxti;
955.  
956.  		j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
957.  		if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
958.  			(j > 0 && !whappr &&
959.  				((omx == nix && omy == niy && !rn2(3))
960.  					|| !rn2(12))
961.  			)) {
962.  			nix = nx;
963.  			niy = ny;
964.  			nidist = ndist;
965.  			if(j < 0) chcnt = 0;
966.  			chi = i;
967.  		}
968.  	nxti:	;
969.  	}
970.  newdogpos:
971.  	if (nix != omx || niy != omy) {
972.  		struct obj *mw_tmp;
973.  
974.  		if (info[chi] & ALLOW_U) {
975.  			if (mtmp->mleashed) { /* play it safe */
976.  				pline("%s breaks loose of %s leash!",
977.  				      Monnam(mtmp), mhis(mtmp));
978.  				m_unleash(mtmp, FALSE);
979.  			}
980.  			(void) mattacku(mtmp);
981.  			return(0);
982.  		}
983.  		if (!m_in_out_region(mtmp, nix, niy))
984.  		    return 1;
985.  		if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
986.  		     closed_door(nix, niy)) &&
987.  		    mtmp->weapon_check != NO_WEAPON_WANTED &&
988.  		    tunnels(mtmp->data) && needspick(mtmp->data)) {
989.  		    if (closed_door(nix, niy)) {
990.  			if (!(mw_tmp = MON_WEP(mtmp)) ||
991.  			    !is_pick(mw_tmp) || !is_axe(mw_tmp))
992.  			    mtmp->weapon_check = NEED_PICK_OR_AXE;
993.  		    } else if (IS_TREE(levl[nix][niy].typ)) {
994.  			if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
995.  			    mtmp->weapon_check = NEED_AXE;
996.  		    } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
997.  			mtmp->weapon_check = NEED_PICK_AXE;
998.  		    }
999.  		    if (mtmp->weapon_check >= NEED_PICK_AXE &&
1000. 			mon_wield_item(mtmp))
1001. 			return 0;
1002. 		}
1003. 		/* insert a worm_move() if worms ever begin to eat things */
1004. 		remove_monster(omx, omy);
1005. 		place_monster(mtmp, nix, niy);
1006. 		if (has_edog && !is_spell && cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy)))
1007. 			pline("%s moves only reluctantly.", Monnam(mtmp));
1008. 		for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
1009. 		mtmp->mtrack[0].x = omx;
1010. 		mtmp->mtrack[0].y = omy;
1011. 		/* We have to know if the pet's gonna do a combined eat and
1012. 		 * move before moving it, but it can't eat until after being
1013. 		 * moved.  Thus the do_eat flag.
1014. 		 */
1015. 		if (do_eat) {
1016. 		    if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2;
1017. 		}
1018. 	} else if (mtmp->mleashed && distu(omx, omy) > 4) {
1019. 		/* an incredible kludge, but the only way to keep pooch near
1020. 		 * after it spends time eating or in a trap, etc.
1021. 		 */
1022. 		coord cc;
1023. 
1024. 		nx = sgn(omx - u.ux);
1025. 		ny = sgn(omy - u.uy);
1026. 		cc.x = u.ux + nx;
1027. 		cc.y = u.uy + ny;
1028. 		if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
1029. 
1030. 		i  = xytod(nx, ny);
1031. 		for (j = (i + 7)%8; j < (i + 1)%8; j++) {
1032. 			dtoxy(&cc, j);
1033. 			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
1034. 		}
1035. 		for (j = (i + 6)%8; j < (i + 2)%8; j++) {
1036. 			dtoxy(&cc, j);
1037. 			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
1038. 		}
1039. 		cc.x = mtmp->mx;
1040. 		cc.y = mtmp->my;
1041. dognext:
1042. 		if (!m_in_out_region(mtmp, nix, niy))
1043. 		  return 1;
1044. 		remove_monster(mtmp->mx, mtmp->my);
1045. 		place_monster(mtmp, cc.x, cc.y);
1046. 		newsym(cc.x,cc.y);
1047. 		set_apparxy(mtmp);
1048. 	}
1049. 	return(1);
1050. }
1051. 
1052. /* check if a monster could pick up objects from a location */
1053. STATIC_OVL boolean
1054. could_reach_item(mon, nx, ny)
1055. struct monst *mon;
1056. xchar nx, ny;
1057. {
1058.     if ((!is_pool(nx,ny) || is_swimmer(mon->data)) &&
1059. 	(!is_lava(nx,ny) || likes_lava(mon->data)) &&
1060. 	(!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data)))
1061.     	return TRUE;
1062.     return FALSE;
1063. }
1064. 
1065. /* Hack to prevent a dog from being endlessly stuck near an object that
1066.  * it can't reach, such as caught in a teleport scroll niche.  It recursively
1067.  * checks to see if the squares in between are good.  The checking could be a
1068.  * little smarter; a full check would probably be useful in m_move() too.
1069.  * Since the maximum food distance is 5, this should never be more than 5 calls
1070.  * deep.
1071.  */
1072. STATIC_OVL boolean
1073. can_reach_location(mon, mx, my, fx, fy)
1074. struct monst *mon;
1075. xchar mx, my, fx, fy;
1076. {
1077.     int i, j;
1078.     int dist;
1079. 
1080.     if (mx == fx && my == fy) return TRUE;
1081.     if (!isok(mx, my)) return FALSE; /* should not happen */
1082.     
1083.     dist = dist2(mx, my, fx, fy);
1084.     for(i=mx-1; i<=mx+1; i++) {
1085. 	for(j=my-1; j<=my+1; j++) {
1086. 	    if (!isok(i, j))
1087. 		continue;
1088. 	    if (dist2(i, j, fx, fy) >= dist)
1089. 		continue;
1090. 	    if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) &&
1091. 				    (!may_dig(i,j) || !tunnels(mon->data)))
1092. 		continue;
1093. 	    if (IS_DOOR(levl[i][j].typ) &&
1094. 				(levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1095. 		continue;
1096. 	    if (!could_reach_item(mon, i, j))
1097. 		continue;
1098. 	    if (can_reach_location(mon, i, j, fx, fy))
1099. 		return TRUE;
1100. 	}
1101.     }
1102.     return FALSE;
1103. }
1104. 
1105. #endif /* OVL0 */
1106. #ifdef OVLB
1107. 
1108. /*ARGSUSED*/	/* do_clear_area client */
1109. STATIC_PTR void
1110. wantdoor(x, y, distance)
1111. int x, y;
1112. genericptr_t distance;
1113. {
1114.     int ndist;
1115. 
1116.     if (*(int*)distance > (ndist = distu(x, y))) {
1117. 	gx = x;
1118. 	gy = y;
1119. 	*(int*)distance = ndist;
1120.     }
1121. }
1122. 
1123. #endif /* OVLB */
1124. 
1125. /*dogmove.c*/

Around Wikia's network

Random Wiki