Difference between revisions of "Source:NetHack 3.4.3/src/dogmove.c"

From NetHackWiki
Jump to navigation Jump to search
(Automated source code upload)
 
m (Add headers.)
Line 1: Line 1:
 +
Below is the full text to src/dogmove.c from NetHack 3.4.3. To link to a particular line, write [[dogmove.c#line123|<nowiki>[[dogmove.c#line123]]</nowiki>]], for example.
 +
 +
== Top of file ==
  
Below is the full text to src/dogmove.c from NetHack 3.4.3. To link to a particular line, write [[dogmove.c#line123|<nowiki>[[dogmove.c#line123]]</nowiki>]], for example.
 
 
  <span id="line1">1.    /* SCCS Id: @(#)dogmove.c 3.4 2002/09/10 */</span>
 
  <span id="line1">1.    /* SCCS Id: @(#)dogmove.c 3.4 2002/09/10 */</span>
 
  <span id="line2">2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */</span>
 
  <span id="line2">2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */</span>
Line 26: Line 28:
 
  <span id="line21">21.  STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));</span>
 
  <span id="line21">21.  STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));</span>
 
  <span id="line22">22.  </span>
 
  <span id="line22">22.  </span>
 +
 +
== DROPPABLES ==
 +
 
  <span id="line23">23.  STATIC_OVL struct obj *</span>
 
  <span id="line23">23.  STATIC_OVL struct obj *</span>
 
  <span id="line24">24.  DROPPABLES(mon)</span>
 
  <span id="line24">24.  DROPPABLES(mon)</span>
Line 63: Line 68:
 
  <span id="line58">58.  STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));</span>
 
  <span id="line58">58.  STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));</span>
 
  <span id="line59">59.  </span>
 
  <span id="line59">59.  </span>
 +
 +
== cursed_object_at ==
 +
 
  <span id="line60">60.  #ifdef OVLB</span>
 
  <span id="line60">60.  #ifdef OVLB</span>
 
  <span id="line61">61.  STATIC_OVL boolean</span>
 
  <span id="line61">61.  STATIC_OVL boolean</span>
Line 75: Line 83:
 
  <span id="line70">70.  }</span>
 
  <span id="line70">70.  }</span>
 
  <span id="line71">71.  </span>
 
  <span id="line71">71.  </span>
 +
 +
== dog_nutrition ==
 +
 
  <span id="line72">72.  int</span>
 
  <span id="line72">72.  int</span>
 
  <span id="line73">73.  dog_nutrition(mtmp, obj)</span>
 
  <span id="line73">73.  dog_nutrition(mtmp, obj)</span>
Line 124: Line 135:
 
  <span id="line119">119.  }</span>
 
  <span id="line119">119.  }</span>
 
  <span id="line120">120.  </span>
 
  <span id="line120">120.  </span>
 +
 +
== dog_eat ==
 +
 
  <span id="line121">121.  /* returns 2 if pet dies, otherwise 1 */</span>
 
  <span id="line121">121.  /* returns 2 if pet dies, otherwise 1 */</span>
 
  <span id="line122">122.  int</span>
 
  <span id="line122">122.  int</span>
Line 212: Line 226:
 
  <span id="line207">207.  </span>
 
  <span id="line207">207.  </span>
 
  <span id="line208">208.  #endif /* OVLB */</span>
 
  <span id="line208">208.  #endif /* OVLB */</span>
 +
 +
== dog_hunger ==
 +
 
  <span id="line209">209.  #ifdef OVL0</span>
 
  <span id="line209">209.  #ifdef OVL0</span>
 
  <span id="line210">210.  </span>
 
  <span id="line210">210.  </span>
Line 260: Line 277:
 
  <span id="line255">255.  }</span>
 
  <span id="line255">255.  }</span>
 
  <span id="line256">256.  </span>
 
  <span id="line256">256.  </span>
 +
 +
== dog_invent ==
 +
 
  <span id="line257">257.  /* do something with object (drop, pick up, eat) at current position</span>
 
  <span id="line257">257.  /* do something with object (drop, pick up, eat) at current position</span>
 
  <span id="line258">258.  * returns 1 if object eaten (since that counts as dog's move), 2 if died</span>
 
  <span id="line258">258.  * returns 1 if object eaten (since that counts as dog's move), 2 if died</span>
Line 330: Line 350:
 
  <span id="line325">325.  }</span>
 
  <span id="line325">325.  }</span>
 
  <span id="line326">326.  </span>
 
  <span id="line326">326.  </span>
 +
 +
== dog_goal ==
 +
 
  <span id="line327">327.  /* set dog's goal -- gtyp, gx, gy</span>
 
  <span id="line327">327.  /* set dog's goal -- gtyp, gx, gy</span>
 
  <span id="line328">328.  * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)</span>
 
  <span id="line328">328.  * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)</span>
Line 480: Line 503:
 
  <span id="line475">475.  }</span>
 
  <span id="line475">475.  }</span>
 
  <span id="line476">476.  </span>
 
  <span id="line476">476.  </span>
 +
 +
== dog_move ==
 +
 
  <span id="line477">477.  /* return 0 (no move), 1 (move) or 2 (dead) */</span>
 
  <span id="line477">477.  /* return 0 (no move), 1 (move) or 2 (dead) */</span>
 
  <span id="line478">478.  int</span>
 
  <span id="line478">478.  int</span>
Line 797: Line 823:
 
  <span id="line792">792.  }</span>
 
  <span id="line792">792.  }</span>
 
  <span id="line793">793.  </span>
 
  <span id="line793">793.  </span>
 +
 +
== could_reach_item ==
 +
 
  <span id="line794">794.  /* check if a monster could pick up objects from a location */</span>
 
  <span id="line794">794.  /* check if a monster could pick up objects from a location */</span>
 
  <span id="line795">795.  STATIC_OVL boolean</span>
 
  <span id="line795">795.  STATIC_OVL boolean</span>
Line 810: Line 839:
 
  <span id="line805">805.  }</span>
 
  <span id="line805">805.  }</span>
 
  <span id="line806">806.  </span>
 
  <span id="line806">806.  </span>
 +
 +
== can_reach_location ==
 +
 
  <span id="line807">807.  /* Hack to prevent a dog from being endlessly stuck near an object that</span>
 
  <span id="line807">807.  /* Hack to prevent a dog from being endlessly stuck near an object that</span>
 
  <span id="line808">808.  * it can't reach, such as caught in a teleport scroll niche.  It recursively</span>
 
  <span id="line808">808.  * it can't reach, such as caught in a teleport scroll niche.  It recursively</span>
Line 851: Line 883:
 
  <span id="line846">846.  </span>
 
  <span id="line846">846.  </span>
 
  <span id="line847">847.  #endif /* OVL0 */</span>
 
  <span id="line847">847.  #endif /* OVL0 */</span>
 +
 +
== wantdoor ==
 +
 
  <span id="line848">848.  #ifdef OVLB</span>
 
  <span id="line848">848.  #ifdef OVLB</span>
 
  <span id="line849">849.  </span>
 
  <span id="line849">849.  </span>

Revision as of 22:11, 19 August 2006

Below is the full text to src/dogmove.c from NetHack 3.4.3. To link to a particular line, write [[dogmove.c#line123]], for example.

Top of file

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.    

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.

5.    #include "hack.h"
6.    
7.    #include "mfndpos.h"
8.    #include "edog.h"
9.    
10.   extern boolean notonhead;
11.   
12.   #ifdef OVL0
13.   
14.   STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *));
15.   STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int));
16.   STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
17.   
18.   STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *));
19.   STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P,
20.       XCHAR_P,XCHAR_P));
21.   STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));
22.   

DROPPABLES

23.   STATIC_OVL struct obj *
24.   DROPPABLES(mon)
25.   register struct monst *mon;
26.   {
27.   	register struct obj *obj;
28.   	struct obj *wep = MON_WEP(mon);
29.   	boolean item1 = FALSE, item2 = FALSE;
30.   
31.   	if (is_animal(mon->data) || mindless(mon->data))
32.   		item1 = item2 = TRUE;
33.   	if (!tunnels(mon->data) || !needspick(mon->data))
34.   		item1 = TRUE;
35.   	for(obj = mon->minvent; obj; obj = obj->nobj) {
36.   		if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK
37.   						|| !which_armor(mon, W_ARMS))) {
38.   			item1 = TRUE;
39.   			continue;
40.   		}
41.   		if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) {
42.   			item2 = TRUE;
43.   			continue;
44.   		}
45.   		if (!obj->owornmask && obj != wep) return obj;
46.   	}
47.   	return (struct obj *)0;
48.   }
49.   
50.   static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
51.   
52.   #endif /* OVL0 */
53.   
54.   STATIC_OVL boolean FDECL(cursed_object_at, (int, int));
55.   
56.   STATIC_VAR xchar gtyp, gx, gy;	/* type and position of dog's current goal */
57.   
58.   STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
59.   

cursed_object_at

60.   #ifdef OVLB
61.   STATIC_OVL boolean
62.   cursed_object_at(x, y)
63.   int x, y;
64.   {
65.   	struct obj *otmp;
66.   
67.   	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
68.   		if (otmp->cursed) return TRUE;
69.   	return FALSE;
70.   }
71.   

dog_nutrition

72.   int
73.   dog_nutrition(mtmp, obj)
74.   struct monst *mtmp;
75.   struct obj *obj;
76.   {
77.   	int nutrit;
78.   
79.   	/*
80.   	 * It is arbitrary that the pet takes the same length of time to eat
81.   	 * as a human, but gets more nutritional value.
82.   	 */
83.   	if (obj->oclass == FOOD_CLASS) {
84.   	    if(obj->otyp == CORPSE) {
85.   		mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
86.   		nutrit = mons[obj->corpsenm].cnutrit;
87.   	    } else {
88.   		mtmp->meating = objects[obj->otyp].oc_delay;
89.   		nutrit = objects[obj->otyp].oc_nutrition;
90.   	    }
91.   	    switch(mtmp->data->msize) {
92.   		case MZ_TINY: nutrit *= 8; break;
93.   		case MZ_SMALL: nutrit *= 6; break;
94.   		default:
95.   		case MZ_MEDIUM: nutrit *= 5; break;
96.   		case MZ_LARGE: nutrit *= 4; break;
97.   		case MZ_HUGE: nutrit *= 3; break;
98.   		case MZ_GIGANTIC: nutrit *= 2; break;
99.   	    }
100.  	    if(obj->oeaten) {
101.  		mtmp->meating = eaten_stat(mtmp->meating, obj);
102.  		nutrit = eaten_stat(nutrit, obj);
103.  	    }
104.  	} else if (obj->oclass == COIN_CLASS) {
105.  	    mtmp->meating = (int)(obj->quan/2000) + 1;
106.  	    if (mtmp->meating < 0) mtmp->meating = 1;
107.  	    nutrit = (int)(obj->quan/20);
108.  	    if (nutrit < 0) nutrit = 0;
109.  	} else {
110.  	    /* Unusual pet such as gelatinous cube eating odd stuff.
111.  	     * meating made consistent with wild monsters in mon.c.
112.  	     * nutrit made consistent with polymorphed player nutrit in
113.  	     * eat.c.  (This also applies to pets eating gold.)
114.  	     */
115.  	    mtmp->meating = obj->owt/20 + 1;
116.  	    nutrit = 5*objects[obj->otyp].oc_nutrition;
117.  	}
118.  	return nutrit;
119.  }
120.  

dog_eat

121.  /* returns 2 if pet dies, otherwise 1 */
122.  int
123.  dog_eat(mtmp, obj, x, y, devour)
124.  register struct monst *mtmp;
125.  register struct obj * obj;
126.  int x, y;
127.  boolean devour;
128.  {
129.  	register struct edog *edog = EDOG(mtmp);
130.  	boolean poly = FALSE, grow = FALSE, heal = FALSE;
131.  	int nutrit;
132.  
133.  	if(edog->hungrytime < monstermoves)
134.  	    edog->hungrytime = monstermoves;
135.  	nutrit = dog_nutrition(mtmp, obj);
136.  	poly = polyfodder(obj);
137.  	grow = mlevelgain(obj);
138.  	heal = mhealup(obj);
139.  	if (devour) {
140.  	    if (mtmp->meating > 1) mtmp->meating /= 2;
141.  	    if (nutrit > 1) nutrit = (nutrit * 3) / 4;
142.  	}
143.  	edog->hungrytime += nutrit;
144.  	mtmp->mconf = 0;
145.  	if (edog->mhpmax_penalty) {
146.  	    /* no longer starving */
147.  	    mtmp->mhpmax += edog->mhpmax_penalty;
148.  	    edog->mhpmax_penalty = 0;
149.  	}
150.  	if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2;
151.  	if (mtmp->mtame < 20) mtmp->mtame++;
152.  	if (x != mtmp->mx || y != mtmp->my) {	/* moved & ate on same turn */
153.  	    newsym(x, y);
154.  	    newsym(mtmp->mx, mtmp->my);
155.  	}
156.  	if (is_pool(x, y) && !Underwater) {
157.  	    /* Don't print obj */
158.  	    /* TODO: Reveal presence of sea monster (especially sharks) */
159.  	} else
160.  	/* hack: observe the action if either new or old location is in view */
161.  	/* However, invisible monsters should still be "it" even though out of
162.  	   sight locations should not. */
163.  	if (cansee(x, y) || cansee(mtmp->mx, mtmp->my))
164.  	    pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It",
165.  		  devour ? "devours" : "eats",
166.  		  (obj->oclass == FOOD_CLASS) ?
167.  			singular(obj, doname) : doname(obj));
168.  	/* It's a reward if it's DOGFOOD and the player dropped/threw it. */
169.  	/* We know the player had it if invlet is set -dlc */
170.  	if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
171.  #ifdef LINT
172.  	    edog->apport = 0;
173.  #else
174.  	    edog->apport += (int)(200L/
175.  		((long)edog->dropdist + monstermoves - edog->droptime));
176.  #endif
177.  	if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
178.  	    /* The object's rustproofing is gone now */
179.  	    obj->oerodeproof = 0;
180.  	    mtmp->mstun = 1;
181.  	    if (canseemon(mtmp) && flags.verbose) {
182.  		pline("%s spits %s out in disgust!",
183.  		      Monnam(mtmp), distant_name(obj,doname));
184.  	    }
185.  	} else if (obj == uball) {
186.  	    unpunish();
187.  	    delobj(obj);
188.  	} else if (obj == uchain)
189.  	    unpunish();
190.  	else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) {
191.  	    obj->quan--;
192.  	    obj->owt = weight(obj);
193.  	} else
194.  	    delobj(obj);
195.  
196.  	if (poly) {
197.  	    (void) newcham(mtmp, (struct permonst *)0, FALSE,
198.  			   cansee(mtmp->mx, mtmp->my));
199.  	}
200.  	/* limit "instant" growth to prevent potential abuse */
201.  	if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) {
202.  	    if (!grow_up(mtmp, (struct monst *)0)) return 2;
203.  	}
204.  	if (heal) mtmp->mhp = mtmp->mhpmax;
205.  	return 1;
206.  }
207.  
208.  #endif /* OVLB */

dog_hunger

209.  #ifdef OVL0
210.  
211.  /* hunger effects -- returns TRUE on starvation */
212.  STATIC_OVL boolean
213.  dog_hunger(mtmp, edog)
214.  register struct monst *mtmp;
215.  register struct edog *edog;
216.  {
217.  	if (monstermoves > edog->hungrytime + 500) {
218.  	    if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
219.  		edog->hungrytime = monstermoves + 500;
220.  		/* but not too high; it might polymorph */
221.  	    } else if (!edog->mhpmax_penalty) {
222.  		/* starving pets are limited in healing */
223.  		int newmhpmax = mtmp->mhpmax / 3;
224.  		mtmp->mconf = 1;
225.  		edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
226.  		mtmp->mhpmax = newmhpmax;
227.  		if (mtmp->mhp > mtmp->mhpmax)
228.  		    mtmp->mhp = mtmp->mhpmax;
229.  		if (mtmp->mhp < 1) goto dog_died;
230.  		if (cansee(mtmp->mx, mtmp->my))
231.  		    pline("%s is confused from hunger.", Monnam(mtmp));
232.  		else if (couldsee(mtmp->mx, mtmp->my))
233.  		    beg(mtmp);
234.  		else
235.  		    You_feel("worried about %s.", y_monnam(mtmp));
236.  		stop_occupation();
237.  	    } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
238.   dog_died:
239.  		if (mtmp->mleashed
240.  #ifdef STEED
241.  		    && mtmp != u.usteed
242.  #endif
243.  		    )
244.  		    Your("leash goes slack.");
245.  		else if (cansee(mtmp->mx, mtmp->my))
246.  		    pline("%s starves.", Monnam(mtmp));
247.  		else
248.  		    You_feel("%s for a moment.",
249.  			Hallucination ? "bummed" : "sad");
250.  		mondied(mtmp);
251.  		return(TRUE);
252.  	    }
253.  	}
254.  	return(FALSE);
255.  }
256.  

dog_invent

257.  /* do something with object (drop, pick up, eat) at current position
258.   * returns 1 if object eaten (since that counts as dog's move), 2 if died
259.   */
260.  STATIC_OVL int
261.  dog_invent(mtmp, edog, udist)
262.  register struct monst *mtmp;
263.  register struct edog *edog;
264.  int udist;
265.  {
266.  	register int omx, omy;
267.  	struct obj *obj;
268.  
269.  	if (mtmp->msleeping || !mtmp->mcanmove) return(0);
270.  
271.  	omx = mtmp->mx;
272.  	omy = mtmp->my;
273.  
274.  	/* if we are carrying sth then we drop it (perhaps near @) */
275.  	/* Note: if apport == 1 then our behaviour is independent of udist */
276.  	/* Use udist+1 so steed won't cause divide by zero */
277.  #ifndef GOLDOBJ
278.  	if(DROPPABLES(mtmp) || mtmp->mgold) {
279.  #else
280.  	if(DROPPABLES(mtmp)) {
281.  #endif
282.  	    if (!rn2(udist+1) || !rn2(edog->apport))
283.  		if(rn2(10) < edog->apport){
284.  		    relobj(mtmp, (int)mtmp->minvis, TRUE);
285.  		    if(edog->apport > 1) edog->apport--;
286.  		    edog->dropdist = udist;		/* hpscdi!jon */
287.  		    edog->droptime = monstermoves;
288.  		}
289.  	} else {
290.  	    if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)
291.  #ifdef MAIL
292.  			&& obj->otyp != SCR_MAIL
293.  #endif
294.  									){
295.  		int edible = dogfood(mtmp, obj);
296.  
297.  		if ((edible <= CADAVER ||
298.  			/* starving pet is more aggressive about eating */
299.  			(edog->mhpmax_penalty && edible == ACCFOOD)) &&
300.  		    could_reach_item(mtmp, obj->ox, obj->oy))
301.  		    return dog_eat(mtmp, obj, omx, omy, FALSE);
302.  
303.  		if(can_carry(mtmp, obj) && !obj->cursed &&
304.  			could_reach_item(mtmp, obj->ox, obj->oy)) {
305.  		    if(rn2(20) < edog->apport+3) {
306.  			if (rn2(udist) || !rn2(edog->apport)) {
307.  			    if (cansee(omx, omy) && flags.verbose)
308.  				pline("%s picks up %s.", Monnam(mtmp),
309.  				    distant_name(obj, doname));
310.  			    obj_extract_self(obj);
311.  			    newsym(omx,omy);
312.  			    (void) mpickobj(mtmp,obj);
313.  			    if (attacktype(mtmp->data, AT_WEAP) &&
314.  					mtmp->weapon_check == NEED_WEAPON) {
315.  				mtmp->weapon_check = NEED_HTH_WEAPON;
316.  				(void) mon_wield_item(mtmp);
317.  			    }
318.  			    m_dowear(mtmp, FALSE);
319.  			}
320.  		    }
321.  		}
322.  	    }
323.  	}
324.  	return 0;
325.  }
326.  

dog_goal

327.  /* set dog's goal -- gtyp, gx, gy
328.   * returns -1/0/1 (dog's desire to approach player) or -2 (abort move)
329.   */
330.  STATIC_OVL int
331.  dog_goal(mtmp, edog, after, udist, whappr)
332.  register struct monst *mtmp;
333.  struct edog *edog;
334.  int after, udist, whappr;
335.  {
336.  	register int omx, omy;
337.  	boolean in_masters_sight, dog_has_minvent;
338.  	register struct obj *obj;
339.  	xchar otyp;
340.  	int appr;
341.  
342.  #ifdef STEED
343.  	/* Steeds don't move on their own will */
344.  	if (mtmp == u.usteed)
345.  		return (-2);
346.  #endif
347.  
348.  	omx = mtmp->mx;
349.  	omy = mtmp->my;
350.  
351.  	in_masters_sight = couldsee(omx, omy);
352.  	dog_has_minvent = (DROPPABLES(mtmp) != 0);
353.  
354.  	if (!edog || mtmp->mleashed) {	/* he's not going anywhere... */
355.  	    gtyp = APPORT;
356.  	    gx = u.ux;
357.  	    gy = u.uy;
358.  	} else {
359.  #define DDIST(x,y) (dist2(x,y,omx,omy))
360.  #define SQSRCHRADIUS 5
361.  	    int min_x, max_x, min_y, max_y;
362.  	    register int nx, ny;
363.  
364.  	    gtyp = UNDEF;	/* no goal as yet */
365.  	    gx = gy = 0;	/* suppress 'used before set' message */
366.  
367.  	    if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1;
368.  	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1;
369.  	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0;
370.  	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1;
371.  
372.  	    /* nearby food is the first choice, then other objects */
373.  	    for (obj = fobj; obj; obj = obj->nobj) {
374.  		nx = obj->ox;
375.  		ny = obj->oy;
376.  		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
377.  		    otyp = dogfood(mtmp, obj);
378.  		    /* skip inferior goals */
379.  		    if (otyp > gtyp || otyp == UNDEF)
380.  			continue;
381.  		    /* avoid cursed items unless starving */
382.  		    if (cursed_object_at(nx, ny) &&
383.  			    !(edog->mhpmax_penalty && otyp < MANFOOD))
384.  			continue;
385.  		    /* skip completely unreacheable goals */
386.  		    if (!could_reach_item(mtmp, nx, ny) ||
387.  		        !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
388.  			continue;
389.  		    if (otyp < MANFOOD) {
390.  			if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) {
391.  			    gx = nx;
392.  			    gy = ny;
393.  			    gtyp = otyp;
394.  			}
395.  		    } else if(gtyp == UNDEF && in_masters_sight &&
396.  			      !dog_has_minvent &&
397.  			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&
398.  			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&
399.  			      edog->apport > rn2(8) &&
400.  			      can_carry(mtmp,obj)) {
401.  			gx = nx;
402.  			gy = ny;
403.  			gtyp = APPORT;
404.  		    }
405.  		}
406.  	    }
407.  	}
408.  
409.  	/* follow player if appropriate */
410.  	if (gtyp == UNDEF ||
411.  	    (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) {
412.  		gx = u.ux;
413.  		gy = u.uy;
414.  		if (after && udist <= 4 && gx == u.ux && gy == u.uy)
415.  			return(-2);
416.  		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
417.  		if (udist > 1) {
418.  			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
419.  			   whappr ||
420.  			   (dog_has_minvent && rn2(edog->apport)))
421.  				appr = 1;
422.  		}
423.  		/* if you have dog food it'll follow you more closely */
424.  		if (appr == 0) {
425.  			obj = invent;
426.  			while (obj) {
427.  				if(dogfood(mtmp, obj) == DOGFOOD) {
428.  					appr = 1;
429.  					break;
430.  				}
431.  				obj = obj->nobj;
432.  			}
433.  		}
434.  	} else
435.  	    appr = 1;	/* gtyp != UNDEF */
436.  	if(mtmp->mconf)
437.  	    appr = 0;
438.  
439.  #define FARAWAY (COLNO + 2)		/* position outside screen */
440.  	if (gx == u.ux && gy == u.uy && !in_masters_sight) {
441.  	    register coord *cp;
442.  
443.  	    cp = gettrack(omx,omy);
444.  	    if (cp) {
445.  		gx = cp->x;
446.  		gy = cp->y;
447.  		if(edog) edog->ogoal.x = 0;
448.  	    } else {
449.  		/* assume master hasn't moved far, and reuse previous goal */
450.  		if(edog && edog->ogoal.x &&
451.  		   ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
452.  		    gx = edog->ogoal.x;
453.  		    gy = edog->ogoal.y;
454.  		    edog->ogoal.x = 0;
455.  		} else {
456.  		    int fardist = FARAWAY * FARAWAY;
457.  		    gx = gy = FARAWAY; /* random */
458.  		    do_clear_area(omx, omy, 9, wantdoor,
459.  				  (genericptr_t)&fardist);
460.  
461.  		    /* here gx == FARAWAY e.g. when dog is in a vault */
462.  		    if (gx == FARAWAY || (gx == omx && gy == omy)) {
463.  			gx = u.ux;
464.  			gy = u.uy;
465.  		    } else if(edog) {
466.  			edog->ogoal.x = gx;
467.  			edog->ogoal.y = gy;
468.  		    }
469.  		}
470.  	    }
471.  	} else if(edog) {
472.  	    edog->ogoal.x = 0;
473.  	}
474.  	return appr;
475.  }
476.  

dog_move

477.  /* return 0 (no move), 1 (move) or 2 (dead) */
478.  int
479.  dog_move(mtmp, after)
480.  register struct monst *mtmp;
481.  register int after;	/* this is extra fast monster movement */
482.  {
483.  	int omx, omy;		/* original mtmp position */
484.  	int appr, whappr, udist;
485.  	int i, j, k;
486.  	register struct edog *edog = EDOG(mtmp);
487.  	struct obj *obj = (struct obj *) 0;
488.  	xchar otyp;
489.  	boolean has_edog, cursemsg[9], do_eat = FALSE;
490.  	xchar nix, niy;		/* position mtmp is (considering) moving to */
491.  	register int nx, ny;	/* temporary coordinates */
492.  	xchar cnt, uncursedcnt, chcnt;
493.  	int chi = -1, nidist, ndist;
494.  	coord poss[9];
495.  	long info[9], allowflags;
496.  #define GDIST(x,y) (dist2(x,y,gx,gy))
497.  
498.  	/*
499.  	 * Tame Angels have isminion set and an ispriest structure instead of
500.  	 * an edog structure.  Fortunately, guardian Angels need not worry
501.  	 * about mundane things like eating and fetching objects, and can
502.  	 * spend all their energy defending the player.  (They are the only
503.  	 * monsters with other structures that can be tame.)
504.  	 */
505.  	has_edog = !mtmp->isminion;
506.  
507.  	omx = mtmp->mx;
508.  	omy = mtmp->my;
509.  	if (has_edog && dog_hunger(mtmp, edog)) return(2);	/* starved */
510.  
511.  	udist = distu(omx,omy);
512.  #ifdef STEED
513.  	/* Let steeds eat and maybe throw rider during Conflict */
514.  	if (mtmp == u.usteed) {
515.  	    if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
516.  		dismount_steed(DISMOUNT_THROWN);
517.  		return (1);
518.  	    }
519.  	    udist = 1;
520.  	} else
521.  #endif
522.  	/* maybe we tamed him while being swallowed --jgm */
523.  	if (!udist) return(0);
524.  
525.  	nix = omx;	/* set before newdogpos */
526.  	niy = omy;
527.  	cursemsg[0] = FALSE;	/* lint suppression */
528.  	info[0] = 0;		/* ditto */
529.  
530.  	if (has_edog) {
531.  	    j = dog_invent(mtmp, edog, udist);
532.  	    if (j == 2) return 2;		/* died */
533.  	    else if (j == 1) goto newdogpos;	/* eating something */
534.  
535.  	    whappr = (monstermoves - edog->whistletime < 5);
536.  	} else
537.  	    whappr = 0;
538.  
539.  	appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,
540.  							after, udist, whappr);
541.  	if (appr == -2) return(0);
542.  
543.  	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
544.  	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL);
545.  	if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS;
546.  	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
547.  	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
548.  	    allowflags |= ALLOW_U;
549.  	    if (!has_edog) {
550.  		coord mm;
551.  		/* Guardian angel refuses to be conflicted; rather,
552.  		 * it disappears, angrily, and sends in some nasties
553.  		 */
554.  		if (canspotmon(mtmp)) {
555.  		    pline("%s rebukes you, saying:", Monnam(mtmp));
556.  		    verbalize("Since you desire conflict, have some more!");
557.  		}
558.  		mongone(mtmp);
559.  		i = rnd(4);
560.  		while(i--) {
561.  		    mm.x = u.ux;
562.  		    mm.y = u.uy;
563.  		    if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
564.  			(void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
565.  					 mm.x, mm.y, FALSE);
566.  		}
567.  		return(2);
568.  
569.  	    }
570.  	}
571.  	if (!Conflict && !mtmp->mconf &&
572.  	    mtmp == u.ustuck && !sticks(youmonst.data)) {
573.  	    unstuck(mtmp);	/* swallowed case handled above */
574.  	    You("get released!");
575.  	}
576.  	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
577.  		allowflags |= OPENDOOR;
578.  		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
579.  	}
580.  	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
581.  	if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG;
582.  	cnt = mfndpos(mtmp, poss, info, allowflags);
583.  
584.  	/* Normally dogs don't step on cursed items, but if they have no
585.  	 * other choice they will.  This requires checking ahead of time
586.  	 * to see how many uncursed item squares are around.
587.  	 */
588.  	uncursedcnt = 0;
589.  	for (i = 0; i < cnt; i++) {
590.  		nx = poss[i].x; ny = poss[i].y;
591.  		if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue;
592.  		if (cursed_object_at(nx, ny)) continue;
593.  		uncursedcnt++;
594.  	}
595.  
596.  	chcnt = 0;
597.  	chi = -1;
598.  	nidist = GDIST(nix,niy);
599.  
600.  	for (i = 0; i < cnt; i++) {
601.  		nx = poss[i].x;
602.  		ny = poss[i].y;
603.  		cursemsg[i] = FALSE;
604.  
605.  		/* if leashed, we drag him along. */
606.  		if (mtmp->mleashed && distu(nx, ny) > 4) continue;
607.  
608.  		/* if a guardian, try to stay close by choice */
609.  		if (!has_edog &&
610.  		    (j = distu(nx, ny)) > 16 && j >= udist) continue;
611.  
612.  		if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
613.  		    int mstatus;
614.  		    register struct monst *mtmp2 = m_at(nx,ny);
615.  
616.  		    if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||
617.  			(mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) &&
618.  			 mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
619.  			 && (perceives(mtmp->data) || !mtmp2->minvis)) ||
620.  			(mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||
621.  			(max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||
622.  			((mtmp->mhp*4 < mtmp->mhpmax
623.  			  || mtmp2->data->msound == MS_GUARDIAN
624.  			  || mtmp2->data->msound == MS_LEADER) &&
625.  			 mtmp2->mpeaceful && !Conflict) ||
626.  			   (touch_petrifies(mtmp2->data) &&
627.  				!resists_ston(mtmp)))
628.  			continue;
629.  
630.  		    if (after) return(0); /* hit only once each move */
631.  
632.  		    notonhead = 0;
633.  		    mstatus = mattackm(mtmp, mtmp2);
634.  
635.  		    /* aggressor (pet) died */
636.  		    if (mstatus & MM_AGR_DIED) return 2;
637.  
638.  		    if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&
639.  			    rn2(4) && mtmp2->mlstmv != monstermoves &&
640.  			    !onscary(mtmp->mx, mtmp->my, mtmp2) &&
641.  			    /* monnear check needed: long worms hit on tail */
642.  			    monnear(mtmp2, mtmp->mx, mtmp->my)) {
643.  			mstatus = mattackm(mtmp2, mtmp);  /* return attack */
644.  			if (mstatus & MM_DEF_DIED) return 2;
645.  		    }
646.  
647.  		    return 0;
648.  		}
649.  
650.  		{   /* Dog avoids harmful traps, but perhaps it has to pass one
651.  		     * in order to follow player.  (Non-harmful traps do not
652.  		     * have ALLOW_TRAPS in info[].)  The dog only avoids the
653.  		     * trap if you've seen it, unlike enemies who avoid traps
654.  		     * if they've seen some trap of that type sometime in the
655.  		     * past.  (Neither behavior is really realistic.)
656.  		     */
657.  		    struct trap *trap;
658.  
659.  		    if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) {
660.  			if (mtmp->mleashed) {
661.  			    if (flags.soundok) whimper(mtmp);
662.  			} else
663.  			    /* 1/40 chance of stepping on it anyway, in case
664.  			     * it has to pass one to follow the player...
665.  			     */
666.  			    if (trap->tseen && rn2(40)) continue;
667.  		    }
668.  		}
669.  
670.  		/* dog eschews cursed objects, but likes dog food */
671.  		/* (minion isn't interested; `cursemsg' stays FALSE) */
672.  		if (has_edog)
673.  		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
674.  		    if (obj->cursed) cursemsg[i] = TRUE;
675.  		    else if ((otyp = dogfood(mtmp, obj)) < MANFOOD &&
676.  			     (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) {
677.  			/* Note: our dog likes the food so much that he
678.  			 * might eat it even when it conceals a cursed object */
679.  			nix = nx;
680.  			niy = ny;
681.  			chi = i;
682.  			do_eat = TRUE;
683.  			cursemsg[i] = FALSE;	/* not reluctant */
684.  			goto newdogpos;
685.  		    }
686.  		}
687.  		/* didn't find something to eat; if we saw a cursed item and
688.  		   aren't being forced to walk on it, usually keep looking */
689.  		if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 &&
690.  		    rn2(13 * uncursedcnt)) continue;
691.  
692.  		/* lessen the chance of backtracking to previous position(s) */
693.  		k = has_edog ? uncursedcnt : cnt;
694.  		for (j = 0; j < MTSZ && j < k - 1; j++)
695.  			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
696.  				if (rn2(MTSZ * (k - j))) goto nxti;
697.  
698.  		j = ((ndist = GDIST(nx,ny)) - nidist) * appr;
699.  		if ((j == 0 && !rn2(++chcnt)) || j < 0 ||
700.  			(j > 0 && !whappr &&
701.  				((omx == nix && omy == niy && !rn2(3))
702.  					|| !rn2(12))
703.  			)) {
704.  			nix = nx;
705.  			niy = ny;
706.  			nidist = ndist;
707.  			if(j < 0) chcnt = 0;
708.  			chi = i;
709.  		}
710.  	nxti:	;
711.  	}
712.  newdogpos:
713.  	if (nix != omx || niy != omy) {
714.  		struct obj *mw_tmp;
715.  
716.  		if (info[chi] & ALLOW_U) {
717.  			if (mtmp->mleashed) { /* play it safe */
718.  				pline("%s breaks loose of %s leash!",
719.  				      Monnam(mtmp), mhis(mtmp));
720.  				m_unleash(mtmp, FALSE);
721.  			}
722.  			(void) mattacku(mtmp);
723.  			return(0);
724.  		}
725.  		if (!m_in_out_region(mtmp, nix, niy))
726.  		    return 1;
727.  		if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) ||
728.  		     closed_door(nix, niy)) &&
729.  		    mtmp->weapon_check != NO_WEAPON_WANTED &&
730.  		    tunnels(mtmp->data) && needspick(mtmp->data)) {
731.  		    if (closed_door(nix, niy)) {
732.  			if (!(mw_tmp = MON_WEP(mtmp)) ||
733.  			    !is_pick(mw_tmp) || !is_axe(mw_tmp))
734.  			    mtmp->weapon_check = NEED_PICK_OR_AXE;
735.  		    } else if (IS_TREE(levl[nix][niy].typ)) {
736.  			if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
737.  			    mtmp->weapon_check = NEED_AXE;
738.  		    } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
739.  			mtmp->weapon_check = NEED_PICK_AXE;
740.  		    }
741.  		    if (mtmp->weapon_check >= NEED_PICK_AXE &&
742.  			mon_wield_item(mtmp))
743.  			return 0;
744.  		}
745.  		/* insert a worm_move() if worms ever begin to eat things */
746.  		remove_monster(omx, omy);
747.  		place_monster(mtmp, nix, niy);
748.  		if (cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy)))
749.  			pline("%s moves only reluctantly.", Monnam(mtmp));
750.  		for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
751.  		mtmp->mtrack[0].x = omx;
752.  		mtmp->mtrack[0].y = omy;
753.  		/* We have to know if the pet's gonna do a combined eat and
754.  		 * move before moving it, but it can't eat until after being
755.  		 * moved.  Thus the do_eat flag.
756.  		 */
757.  		if (do_eat) {
758.  		    if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2;
759.  		}
760.  	} else if (mtmp->mleashed && distu(omx, omy) > 4) {
761.  		/* an incredible kludge, but the only way to keep pooch near
762.  		 * after it spends time eating or in a trap, etc.
763.  		 */
764.  		coord cc;
765.  
766.  		nx = sgn(omx - u.ux);
767.  		ny = sgn(omy - u.uy);
768.  		cc.x = u.ux + nx;
769.  		cc.y = u.uy + ny;
770.  		if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
771.  
772.  		i  = xytod(nx, ny);
773.  		for (j = (i + 7)%8; j < (i + 1)%8; j++) {
774.  			dtoxy(&cc, j);
775.  			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
776.  		}
777.  		for (j = (i + 6)%8; j < (i + 2)%8; j++) {
778.  			dtoxy(&cc, j);
779.  			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
780.  		}
781.  		cc.x = mtmp->mx;
782.  		cc.y = mtmp->my;
783.  dognext:
784.  		if (!m_in_out_region(mtmp, nix, niy))
785.  		  return 1;
786.  		remove_monster(mtmp->mx, mtmp->my);
787.  		place_monster(mtmp, cc.x, cc.y);
788.  		newsym(cc.x,cc.y);
789.  		set_apparxy(mtmp);
790.  	}
791.  	return(1);
792.  }
793.  

could_reach_item

794.  /* check if a monster could pick up objects from a location */
795.  STATIC_OVL boolean
796.  could_reach_item(mon, nx, ny)
797.  struct monst *mon;
798.  xchar nx, ny;
799.  {
800.      if ((!is_pool(nx,ny) || is_swimmer(mon->data)) &&
801.  	(!is_lava(nx,ny) || likes_lava(mon->data)) &&
802.  	(!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data)))
803.      	return TRUE;
804.      return FALSE;
805.  }
806.  

can_reach_location

807.  /* Hack to prevent a dog from being endlessly stuck near an object that
808.   * it can't reach, such as caught in a teleport scroll niche.  It recursively
809.   * checks to see if the squares in between are good.  The checking could be a
810.   * little smarter; a full check would probably be useful in m_move() too.
811.   * Since the maximum food distance is 5, this should never be more than 5 calls
812.   * deep.
813.   */
814.  STATIC_OVL boolean
815.  can_reach_location(mon, mx, my, fx, fy)
816.  struct monst *mon;
817.  xchar mx, my, fx, fy;
818.  {
819.      int i, j;
820.      int dist;
821.  
822.      if (mx == fx && my == fy) return TRUE;
823.      if (!isok(mx, my)) return FALSE; /* should not happen */
824.      
825.      dist = dist2(mx, my, fx, fy);
826.      for(i=mx-1; i<=mx+1; i++) {
827.  	for(j=my-1; j<=my+1; j++) {
828.  	    if (!isok(i, j))
829.  		continue;
830.  	    if (dist2(i, j, fx, fy) >= dist)
831.  		continue;
832.  	    if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) &&
833.  				    (!may_dig(i,j) || !tunnels(mon->data)))
834.  		continue;
835.  	    if (IS_DOOR(levl[i][j].typ) &&
836.  				(levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
837.  		continue;
838.  	    if (!could_reach_item(mon, i, j))
839.  		continue;
840.  	    if (can_reach_location(mon, i, j, fx, fy))
841.  		return TRUE;
842.  	}
843.      }
844.      return FALSE;
845.  }
846.  
847.  #endif /* OVL0 */

wantdoor

848.  #ifdef OVLB
849.  
850.  /*ARGSUSED*/	/* do_clear_area client */
851.  STATIC_PTR void
852.  wantdoor(x, y, distance)
853.  int x, y;
854.  genericptr_t distance;
855.  {
856.      int ndist;
857.  
858.      if (*(int*)distance > (ndist = distu(x, y))) {
859.  	gx = x;
860.  	gy = y;
861.  	*(int*)distance = ndist;
862.      }
863.  }
864.  
865.  #endif /* OVLB */
866.  
867.  /*dogmove.c*/