Wikihack
Advertisement

Below is the full text to dog.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/dog.c#line123]], for example.

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.
1.    /*	SCCS Id: @(#)dog.c	3.1	92/10/18	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    #include "edog.h"
7.    
8.    #define domestic(mtmp)	(mtmp->data->msound == MS_BARK || \
9.    			 mtmp->data->msound == MS_MEW)
10.   
11.   #ifdef OVLB
12.   
13.   static int NDECL(pet_type);
14.   
15.   void
16.   initedog(mtmp)
17.   register struct monst *mtmp;
18.   {
19.   	mtmp->mtame = domestic(mtmp) ? 10 : 5;
20.   	mtmp->mpeaceful = 1;
21.   	set_malign(mtmp); /* recalc alignment now that it's tamed */
22.   	mtmp->mleashed = 0;
23.   	mtmp->meating = 0;
24.   	EDOG(mtmp)->droptime = 0;
25.   	EDOG(mtmp)->dropdist = 10000;
26.   	EDOG(mtmp)->apport = 10;
27.   	EDOG(mtmp)->whistletime = 0;
28.   	EDOG(mtmp)->hungrytime = 1000 + moves;
29.   }
30.   
31.   static int
32.   pet_type()
33.   {
34.   	register int pettype;
35.   
36.   	switch (pl_character[0]) {
37.   		/* some character classes have restricted ideas of pets */
38.   		case 'C':
39.   		case 'S':
40.   			pettype = PM_LITTLE_DOG;
41.   			break;
42.   		case 'W':
43.   			pettype = PM_KITTEN;
44.   			break;
45.   		/* otherwise, see if the player has a preference */
46.   		default:
47.   			if (preferred_pet == 'c')
48.   				pettype = PM_KITTEN;
49.   			else if (preferred_pet == 'd')
50.   				pettype = PM_LITTLE_DOG;
51.   			else	pettype = rn2(2) ? PM_KITTEN : PM_LITTLE_DOG;
52.   			break;
53.   	}
54.   	return pettype;
55.   }
56.   
57.   void
58.   make_familiar(otmp,x,y)
59.   register struct obj *otmp;
60.   xchar x, y;
61.   {
62.   	register struct monst *mtmp;
63.   	register struct permonst *pm;
64.   
65.   top:
66.   	if (otmp) pm = &mons[otmp->corpsenm]; /* Figurine; otherwise spell */
67.   	else if (rn2(3)) {
68.   	    if (!(pm = rndmonst())) {
69.   		pline("There seems to be nothing available for a familiar.");
70.   		return;
71.   	    }
72.   	}
73.   	else pm = &mons[pet_type()];
74.   
75.   	pm->pxlth += sizeof(struct edog);
76.   	mtmp = makemon(pm, x, y);
77.   	pm->pxlth -= sizeof(struct edog);
78.   	if (!mtmp) { /* monster was genocided */
79.   	    if (otmp)
80.   		pline("The figurine writhes and then shatters into pieces!");
81.   	    else goto top;
82.   		/* rndmonst() returns something not genocided always, so this
83.   		 * means it was a cat or dog; loop back to try again until
84.   		 * either rndmonst() is called, or if only one of cat/dog
85.   		 * was genocided, they get the other.
86.   		 */
87.   	    return;
88.   	}
89.   	initedog(mtmp);
90.   	mtmp->msleep = 0;
91.   	if (otmp && otmp->cursed) { /* cursed figurine */
92.   		You("get a bad feeling about this.");
93.   		mtmp->mtame = mtmp->mpeaceful = 0;
94.   		newsym(mtmp->mx, mtmp->my);
95.   	}
96.   	set_malign(mtmp); /* more alignment changes */
97.   }
98.   
99.   struct monst *
100.  makedog()
101.  {
102.  	register struct monst *mtmp;
103.  	char *petname;
104.  	int   pettype;
105.  	static int petname_used = 0;
106.  
107.  	pettype = pet_type();
108.  	if (pettype == PM_LITTLE_DOG)
109.  		petname = dogname;
110.  	else
111.  		petname = catname;
112.  
113.  	mons[pettype].pxlth = sizeof(struct edog);
114.  	mtmp = makemon(&mons[pettype], u.ux, u.uy);
115.  	mons[pettype].pxlth = 0;
116.  
117.  	if(!mtmp) return((struct monst *) 0); /* pets were genocided */
118.  
119.  	if (!petname_used++ && *petname)
120.  		mtmp = christen_monst(mtmp, petname);
121.  
122.  	initedog(mtmp);
123.  	return(mtmp);
124.  }
125.  
126.  void
127.  losedogs()
128.  {
129.  	register struct monst *mtmp,*mtmp0,*mtmp2;
130.  	int num_segs;
131.  
132.  	while(mtmp = mydogs){
133.  		mydogs = mtmp->nmon;
134.  		mtmp->nmon = fmon;
135.  		fmon = mtmp;
136.  		if (mtmp->isshk)
137.  		    set_residency(mtmp, FALSE);
138.  
139.  		num_segs = mtmp->wormno;
140.  		/* baby long worms have no tail so don't use is_longworm() */
141.  		if ( (mtmp->data == &mons[PM_LONG_WORM]) &&
142.  		     (mtmp->wormno = get_wormno()) ) {
143.  		    initworm(mtmp, num_segs);
144.  		    /* tail segs are not yet initialized or displayed */
145.  		} else mtmp->wormno = 0;
146.  		mnexto(mtmp);
147.  	}
148.  
149.  #if defined(LINT) || defined(GCC_WARN)
150.  	mtmp0 = (struct monst *)0;
151.  #endif
152.  	for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
153.  		mtmp2 = mtmp->nmon;
154.  		if(mtmp->mx == u.uz.dnum && mtmp->mux == u.uz.dlevel) {
155.  		    mtmp->mx = 0;		   /* save xyloc in mtmp->my */
156.  		    mtmp->mux = u.ux; mtmp->muy = u.uy; /* not really req'd */
157.  		    if(mtmp == migrating_mons)
158.  			migrating_mons = mtmp->nmon;
159.  		    else
160.  			mtmp0->nmon = mtmp->nmon;
161.  		    mtmp->nmon = fmon;
162.  		    fmon = mtmp;
163.  		    num_segs = mtmp->wormno;
164.  		    if ( (mtmp->data == &mons[PM_LONG_WORM]) &&
165.  			 (mtmp->wormno = get_wormno()) ) {
166.  			initworm(mtmp, num_segs);
167.  			/* tail segs are not yet initialized or displayed */
168.  		    } else mtmp->wormno = 0;
169.  
170.  		    if(mtmp->mlstmv < monstermoves-1) {
171.  			/* heal monster for time spent in limbo */
172.  			long nmv = monstermoves - mtmp->mlstmv - 1;
173.  
174.  			/* might stop being afraid, blind or frozen */
175.  			/* set to 1 and allow final decrement in movemon() */
176.  			if(nmv >= (long)mtmp->mblinded) mtmp->mblinded = 1;
177.  			else mtmp->mblinded -= nmv;
178.  			if(nmv >= (long)mtmp->mfrozen) mtmp->mfrozen = 1;
179.  			else mtmp->mfrozen -= nmv;
180.  			if(nmv >= (long)mtmp->mfleetim) mtmp->mfleetim = 1;
181.  			else mtmp->mfleetim -= nmv;
182.  
183.  			/* might be able to use special ability again */
184.  			if(nmv > (long)mtmp->mspec_used) mtmp->mspec_used = 0;
185.  			else mtmp->mspec_used -= nmv;
186.  
187.  			if(!regenerates(mtmp->data)) nmv /= 20;
188.  			if((long)mtmp->mhp + nmv >= (long)mtmp->mhpmax)
189.  			    mtmp->mhp = mtmp->mhpmax;
190.  			else mtmp->mhp += nmv;
191.  			mtmp->mlstmv = monstermoves-1;
192.  		    }
193.  
194.  		    if (mtmp->data->geno & G_GENOD) {
195.  #ifdef KOPS
196.  			allow_kops = FALSE;
197.  #endif
198.  			mondead(mtmp);	/* must put in fmon list first */
199.  #ifdef KOPS
200.  			allow_kops = TRUE;
201.  #endif
202.  		    } else if (mtmp->isshk && mtmp->mpeaceful)
203.  			home_shk(mtmp, TRUE);
204.  		    else switch(mtmp->my) {
205.  			xchar *xlocale, *ylocale;
206.  
207.  			case 1: xlocale = &xupstair; ylocale = &yupstair;
208.  				goto common;
209.  			case 2: xlocale = &xdnstair; ylocale = &ydnstair;
210.  				goto common;
211.  			case 3: xlocale = &xupladder; ylocale = &yupladder;
212.  				goto common;
213.  			case 4: xlocale = &xdnladder; ylocale = &ydnladder;
214.  				goto common;
215.  			case 5: xlocale = &sstairs.sx; ylocale = &sstairs.sy;
216.  				goto common;
217.  common:
218.  				if (*xlocale && *ylocale) {
219.  			    (void) mnearto(mtmp, *xlocale, *ylocale, FALSE);
220.  				    break;
221.  				} /* else fall through */
222.  			default: 
223.  				rloc(mtmp);
224.  				break;
225.  			}
226.  		} else
227.  		    mtmp0 = mtmp;
228.  		if (mtmp->isshk)
229.  		    set_residency(mtmp, FALSE);
230.  	}
231.  }
232.  
233.  #endif /* OVLB */
234.  #ifdef OVL2
235.  
236.  void
237.  keepdogs()
238.  {
239.  	register struct monst *mtmp;
240.  	register struct obj *obj;
241.  	int num_segs = 0;
242.  
243.  	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
244.  	    if(((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) ||
245.  		/* the wiz will level t-port from anywhere to chase
246.  		   the amulet; if you don't have it, will chase you
247.  		   only if in range. -3. */
248.  			(u.uhave.amulet && mtmp->iswiz))
249.  			&& !mtmp->msleep && mtmp->mcanmove) {
250.  
251.  		/* long worms can now change levels! - Norm */
252.  
253.  		if (mtmp->mtame && mtmp->meating && canseemon(mtmp)) {
254.  			pline("%s is still eating.", Monnam(mtmp));
255.  			goto merge;
256.  		}
257.  		if (mon_has_amulet(mtmp)) {
258.  			pline("%s seems very disoriented for a moment.",
259.  				Monnam(mtmp));
260.  		merge:
261.  #ifdef WALKIES
262.  			if (mtmp->mleashed) {
263.  				pline("%s leash suddenly comes loose.",
264.  					humanoid(mtmp->data)
265.  					    ? (mtmp->female ? "Her" : "His")
266.  					    : "Its");
267.  				m_unleash(mtmp);
268.  			}
269.  #endif
270.  			continue;
271.  		}
272.  		if (mtmp->isshk)
273.  			set_residency(mtmp, TRUE);
274.  
275.  		if (mtmp->wormno) {
276.  		    /* NOTE: worm is truncated to # segs = max wormno size */
277.  		    num_segs = min(count_wsegs(mtmp), MAX_NUM_WORMS - 1);
278.  		    wormgone(mtmp);
279.  		}
280.  
281.  		/* set minvent's obj->no_charge to 0 */
282.  		for(obj = mtmp->minvent; obj; obj = obj->nobj) {
283.  		    if(Is_container(obj))
284.  		        picked_container(obj); /* does the right thing */
285.  		    obj->no_charge = 0;
286.  		}
287.  
288.  		relmon(mtmp);
289.  		newsym(mtmp->mx,mtmp->my);
290.  		mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */
291.  		mtmp->wormno = num_segs;
292.  		mtmp->nmon = mydogs;
293.  		mydogs = mtmp;
294.  		keepdogs();	/* we destroyed the link, so use recursion */
295.  		return;		/* (admittedly somewhat primitive) */
296.  	}
297.  }
298.  
299.  #endif /* OVL2 */
300.  #ifdef OVLB
301.  
302.  void
303.  migrate_to_level(mtmp, tolev, xyloc) 
304.  	register struct monst *mtmp; 
305.  	xchar tolev;  	/* destination level */
306.  	xchar xyloc;	/* destination xy location: */
307.  			/* 	0: rnd,
308.  			 *	1: <,
309.  			 *	2: >,
310.  			 *	3: < ladder,
311.  			 *	4: > ladder,
312.  			 *	5: sstairs
313.  			 */ 
314.  {
315.          register struct obj *obj;
316.  	int num_segs = 0;	/* count of worm segments */
317.  
318.  	if (mtmp->isshk)
319.  	    set_residency(mtmp, TRUE);
320.  
321.  	if (mtmp->wormno) {
322.  	  /* **** NOTE: worm is truncated to # segs = max wormno size **** */
323.  	    num_segs = min(count_wsegs(mtmp), MAX_NUM_WORMS - 1);
324.  	    wormgone(mtmp);
325.  	}
326.  
327.  	/* set minvent's obj->no_charge to 0 */
328.  	for(obj = mtmp->minvent; obj; obj = obj->nobj) {
329.  	    if(Is_container(obj))
330.  	        picked_container(obj); /* does the right thing */
331.  	    obj->no_charge = 0;
332.  	}
333.  
334.  	relmon(mtmp);
335.  	mtmp->nmon = migrating_mons;
336.  	migrating_mons = mtmp;
337.  #ifdef WALKIES
338.  	if (mtmp->mleashed)  {
339.  		pline("The leash comes off!");
340.  		m_unleash(mtmp);
341.  	}
342.  #endif
343.  	mtmp->mtame = 0;
344.  	newsym(mtmp->mx,mtmp->my);
345.  	/* make sure to reset mtmp->[mx,my] to 0 when releasing, */
346.  	/* so rloc() on next level doesn't affect MON_AT() state */
347.  	mtmp->mx = ledger_to_dnum((xchar)tolev); 
348.  	mtmp->mux = ledger_to_dlev((xchar)tolev); 
349.  	mtmp->my = xyloc;
350.  	mtmp->muy = 0;
351.  	mtmp->wormno = num_segs;
352.  	mtmp->mlstmv = monstermoves;
353.  }
354.  
355.  #endif /* OVLB */
356.  #ifdef OVL1
357.  
358.  /* return quality of food; the lower the better */
359.  /* fungi will eat even tainted food */
360.  int
361.  dogfood(mon,obj)
362.  struct monst *mon;
363.  register struct obj *obj;
364.  {
365.  	boolean carni = carnivorous(mon->data);
366.  	boolean herbi = herbivorous(mon->data);
367.  	struct permonst *fptr = &mons[obj->corpsenm];
368.  
369.  	switch(obj->oclass) {
370.  	case FOOD_CLASS:
371.  	    if (obj->otyp == CORPSE &&
372.  		((obj->corpsenm == PM_COCKATRICE && !resists_ston(mon->data))
373.  		 || is_rider(fptr)))
374.  		    return TABU;
375.  
376.  	    if (!carni && !herbi)
377.  		    return (obj->cursed ? UNDEF : APPORT);
378.  
379.  	    switch (obj->otyp) {
380.  		case TRIPE_RATION:
381.  		    return (carni ? DOGFOOD : MANFOOD);
382.  		case EGG:
383.  		    if (obj->corpsenm == PM_COCKATRICE &&
384.  						!resists_ston(mon->data))
385.  			return POISON;
386.  		    return (carni ? CADAVER : MANFOOD);
387.  		case CORPSE:
388.  		    if ((obj->age+50 <= monstermoves
389.  					    && obj->corpsenm != PM_LIZARD
390.  					    && mon->data->mlet != S_FUNGUS) ||
391.  			(acidic(&mons[obj->corpsenm]) &&
392.  						!resists_acid(mon->data)) ||
393.  			(poisonous(&mons[obj->corpsenm]) &&
394.  						!resists_poison(mon->data)))
395.  			return POISON;
396.  		    else if (fptr->mlet == S_FUNGUS)
397.  			return (herbi ? CADAVER : MANFOOD);
398.  		    else if (is_meaty(fptr))
399.  		        return (carni ? CADAVER : MANFOOD);
400.  		    else return (carni ? ACCFOOD : MANFOOD);
401.  		case CLOVE_OF_GARLIC:
402.  		    return (is_undead(mon->data) ? TABU :
403.  			    (herbi ? ACCFOOD : MANFOOD));
404.  		case TIN:
405.  		    return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
406.  		case APPLE:
407.  		case CARROT:
408.  		    return (herbi ? DOGFOOD : MANFOOD);
409.  		case BANANA:
410.  		    return ((mon->data->mlet == S_YETI) ? DOGFOOD :
411.  			    (herbi ? ACCFOOD : MANFOOD));
412.  		default:
413.  #ifdef TUTTI_FRUTTI
414.  		    return (obj->otyp > SLIME_MOLD ?
415.  #else
416.  		    return (obj->otyp > CLOVE_OF_GARLIC ?
417.  #endif
418.  			    (carni ? ACCFOOD : MANFOOD) :
419.  			    (herbi ? ACCFOOD : MANFOOD));
420.  	    }
421.  	default:
422.  	    if (hates_silver(mon->data) && 
423.  		objects[obj->otyp].oc_material == SILVER)
424.  		return(TABU);
425.  	    if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
426.  		return(ACCFOOD);
427.  	    if (metallivorous(mon->data) && is_metallic(obj))
428.  		/* Ferrous based metals are preferred. */
429.  		return(objects[obj->otyp].oc_material == IRON ? DOGFOOD :
430.  		       ACCFOOD);
431.  	    if(!obj->cursed && obj->oclass != BALL_CLASS &&
432.  						obj->oclass != CHAIN_CLASS)
433.  		return(APPORT);
434.  	    /* fall into next case */
435.  	case ROCK_CLASS:
436.  	    return(UNDEF);
437.  	}
438.  }
439.  
440.  #endif /* OVL1 */
441.  #ifdef OVLB
442.  
443.  struct monst *
444.  tamedog(mtmp, obj)
445.  register struct monst *mtmp;
446.  register struct obj *obj;
447.  {
448.  	register struct monst *mtmp2;
449.  
450.  	/* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */
451.  	if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA]
452.  #ifdef MULDGN
453.  	    || (mtmp->data->mflags3 & M3_WANTSARTI)
454.  #endif
455.  	    )
456.  		return((struct monst *)0);
457.  
458.  	/* worst case, at least he'll be peaceful. */
459.  	mtmp->mpeaceful = 1;
460.  	set_malign(mtmp);
461.  	if(flags.moonphase == FULL_MOON && night() && rn2(6) && obj
462.  						&& mtmp->data->mlet == S_DOG)
463.  		return((struct monst *)0);
464.  
465.  	/* If we cannot tame him, at least he's no longer afraid. */
466.  	mtmp->mflee = 0;
467.  	mtmp->mfleetim = 0;
468.  	if(mtmp->mtame || !mtmp->mcanmove ||
469.  	   /* monsters with conflicting structures cannot be tamed */
470.  	   mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion ||
471.  #ifdef POLYSELF
472.  	   is_human(mtmp->data) || (is_demon(mtmp->data) && !is_demon(uasmon))
473.  #else
474.  	   is_human(mtmp->data) || is_demon(mtmp->data)
475.  #endif
476.  	   || (mtmp->data->mflags3 &
477.  	       (M3_WANTSAMUL|M3_WANTSBELL|M3_WANTSBOOK|M3_WANTSCAND))
478.  	   )
479.  		return((struct monst *)0);
480.  	if(obj) {
481.  		if(dogfood(mtmp, obj) >= MANFOOD) return((struct monst *)0);
482.  		if(cansee(mtmp->mx,mtmp->my))
483.  			pline("%s devours the %s.", Monnam(mtmp), xname(obj));
484.  		obfree(obj, (struct obj *)0);
485.  	}
486.  	if (u.uswallow && mtmp == u.ustuck)
487.  		expels(mtmp, mtmp->data, TRUE);
488.  	mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
489.  	*mtmp2 = *mtmp;
490.  	mtmp2->mxlth = sizeof(struct edog);
491.  	if(mtmp->mnamelth) Strcpy(NAME(mtmp2), NAME(mtmp));
492.  	initedog(mtmp2);
493.  	replmon(mtmp,mtmp2);
494.  	newsym(mtmp2->mx, mtmp2->my);
495.  	return(mtmp2);
496.  }
497.  
498.  #endif /* OVLB */
499.  
500.  /*dog.c*/
Advertisement