Wikia

Wikihack

Source:Dogmove.c

2,032pages on
this wiki
Talk0

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 Edit

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.
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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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 Edit

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*/

Around Wikia's network

Random Wiki