Wikihack
Advertisement

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

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

Screenshots and source code from Hack are used under the CWI license.
1.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
2.    
3.    #include	"hack.h"
4.    #include	"hack.mfndpos.h"
5.    extern char POISONOUS[];
6.    extern struct monst *makemon();
7.    #include "def.edog.h"
8.    
9.    struct permonst li_dog =
10.   	{ "little dog", 'd',2,18,6,1,6,sizeof(struct edog) };
11.   struct permonst dog =
12.   	{ "dog", 'd',4,16,5,1,6,sizeof(struct edog) };
13.   struct permonst la_dog =
14.   	{ "large dog", 'd',6,15,4,2,4,sizeof(struct edog) };
15.   
16.   
17.   makedog(){
18.   register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy);
19.   	if(!mtmp) return; /* dogs were genocided */
20.   	initedog(mtmp);
21.   }
22.   
23.   initedog(mtmp) register struct monst *mtmp; {
24.   	mtmp->mtame = mtmp->mpeaceful = 1;
25.   	EDOG(mtmp)->hungrytime = 1000 + moves;
26.   	EDOG(mtmp)->eattime = 0;
27.   	EDOG(mtmp)->droptime = 0;
28.   	EDOG(mtmp)->dropdist = 10000;
29.   	EDOG(mtmp)->apport = 10;
30.   	EDOG(mtmp)->whistletime = 0;
31.   }
32.   
33.   /* attach the monsters that went down (or up) together with @ */
34.   struct monst *mydogs = 0;
35.   struct monst *fallen_down = 0;	/* monsters that fell through a trapdoor */
36.   
37.   losedogs(){
38.   register struct monst *mtmp;
39.   	while(mtmp = mydogs){
40.   		mydogs = mtmp->nmon;
41.   		mtmp->nmon = fmon;
42.   		fmon = mtmp;
43.   		mnexto(mtmp);
44.   	}
45.   	while(mtmp = fallen_down){
46.   		fallen_down = mtmp->nmon;
47.   		mtmp->nmon = fmon;
48.   		fmon = mtmp;
49.   		rloc(mtmp);
50.   	}
51.   }
52.   
53.   keepdogs(){
54.   register struct monst *mtmp;
55.   	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->mtame) {
56.   		if(dist(mtmp->mx,mtmp->my) > 2) {
57.   			mtmp->mtame = 0;	/* dog becomes wild */
58.   			mtmp->mpeaceful = 0;
59.   			continue;
60.   		}
61.   		relmon(mtmp);
62.   		mtmp->nmon = mydogs;
63.   		mydogs = mtmp;
64.   		unpmon(mtmp);
65.   		keepdogs();	/* we destroyed the link, so use recursion */
66.   		return;		/* (admittedly somewhat primitive) */
67.   	}
68.   }
69.   
70.   fall_down(mtmp) register struct monst *mtmp; {
71.   	relmon(mtmp);
72.   	mtmp->nmon = fallen_down;
73.   	fallen_down = mtmp;
74.   	unpmon(mtmp);
75.   	mtmp->mtame = 0;
76.   }
77.   
78.   /* return quality of food; the lower the better */
79.   #define	DOGFOOD	0
80.   #define	CADAVER	1
81.   #define	ACCFOOD	2
82.   #define	MANFOOD	3
83.   #define	APPORT	4
84.   #define	POISON	5
85.   #define	UNDEF	6
86.   dogfood(obj) register struct obj *obj; {
87.   	switch(obj->olet) {
88.   	case FOOD_SYM:
89.   	    return(
90.   		(obj->otyp == TRIPE_RATION) ? DOGFOOD :
91.   		(obj->otyp < CARROT) ? ACCFOOD :
92.   		(obj->otyp < CORPSE) ? MANFOOD :
93.   		(index(POISONOUS, obj->spe) || obj->age + 50 <= moves ||
94.   		    obj->otyp == DEAD_COCKATRICE)
95.   			? POISON : CADAVER
96.   	    );
97.   	default:
98.   	    if(!obj->cursed) return(APPORT);
99.   	    /* fall into next case */
100.  	case BALL_SYM:
101.  	case CHAIN_SYM:
102.  	case ROCK_SYM:
103.  	    return(UNDEF);
104.  	}
105.  }
106.  
107.  /* return 0 (no move), 1 (move) or 2 (dead) */
108.  dog_move(mtmp, after) register struct monst *mtmp; {
109.  register int nx,ny,omx,omy,appr,nearer,j;
110.  int udist,chi,i,whappr;
111.  register struct monst *mtmp2;
112.  register struct permonst *mdat = mtmp->data;
113.  register struct edog *edog = EDOG(mtmp);
114.  struct obj *obj;
115.  struct gen *trap;
116.  xchar cnt,chcnt,nix,niy;
117.  schar dogroom,uroom;
118.  xchar gx,gy,gtyp,otyp;	/* current goal */
119.  coord poss[9];
120.  int info[9];
121.  #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
122.  #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
123.  
124.  	if(moves <= edog->eattime) return(0);	/* dog is still eating */
125.  	omx = mtmp->mx;
126.  	omy = mtmp->my;
127.  	whappr = (moves - EDOG(mtmp)->whistletime < 5);
128.  	if(moves > edog->hungrytime + 500 && !mtmp->mconf){
129.  		mtmp->mconf = 1;
130.  		mtmp->orig_hp /= 3;
131.  		if(mtmp->mhp > mtmp->orig_hp)
132.  			mtmp->mhp = mtmp->orig_hp;
133.  		if(cansee(omx,omy))
134.  			pline("%s is confused from hunger", Monnam(mtmp));
135.  		else	pline("You feel worried about your %s.", monnam(mtmp));
136.  	} else
137.  	if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){
138.  		if(cansee(omx,omy))
139.  			pline("%s dies from hunger", Monnam(mtmp));
140.  		else
141.  		pline("You have a sad feeling for a moment, then it passes");
142.  		mondied(mtmp);
143.  		return(2);
144.  	}
145.  	dogroom = inroom(omx,omy);
146.  	uroom = inroom(u.ux,u.uy);
147.  	udist = dist(omx,omy);
148.  
149.  	/* if we are carrying sth then we drop it (perhaps near @) */
150.  	/* Note: if apport == 1 then our behaviour is independent of udist */
151.  	if(mtmp->minvent){
152.  		if(!rn2(udist) || !rn2((int) edog->apport))
153.  		if(rn2(10) < edog->apport){
154.  			relobj(mtmp,0);
155.  			if(edog->apport > 1) edog->apport--;
156.  		}
157.  	} else {
158.  		if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){
159.  		    if((otyp = dogfood(obj)) <= CADAVER){
160.  			nix = omx;
161.  			niy = omy;
162.  			goto eatobj;
163.  		    }
164.  		    if(obj->owt < 10*mtmp->data->mlevel)
165.  		    if(rn2(20) < edog->apport+3)
166.  		    if(rn2(udist) || !rn2((int) edog->apport)){
167.  			freeobj(obj);
168.  			unpobj(obj);
169.  			/* if(levl[omx][omy].scrsym == obj->olet)
170.  				newsym(omx,omy); */
171.  			mpickobj(mtmp,obj);
172.  		    }
173.  		}
174.  	}
175.  
176.  	/* first we look for food */
177.  	gtyp = UNDEF;	/* no goal as yet */
178.  #ifdef LINT
179.  	gx = gy = 0;
180.  #endif LINT
181.  	for(obj = fobj; obj; obj = obj->nobj) {
182.  		otyp = dogfood(obj);
183.  		if(otyp > gtyp || otyp == UNDEF) continue;
184.  		if(inroom(obj->ox,obj->oy) != dogroom) continue;
185.  		if(otyp < MANFOOD &&
186.  		 (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) {
187.  			if(otyp < gtyp || (otyp == gtyp &&
188.  				DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){
189.  				gx = obj->ox;
190.  				gy = obj->oy;
191.  				gtyp = otyp;
192.  			}
193.  		} else
194.  		if(gtyp == UNDEF && dogroom >= 0 &&
195.  		   uroom == dogroom &&
196.  		   !mtmp->minvent && edog->apport > rn2(8)){
197.  			gx = obj->ox;
198.  			gy = obj->oy;
199.  			gtyp = APPORT;
200.  		}
201.  	}
202.  	if(gtyp == UNDEF ||
203.  	  (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){
204.  		if(dogroom < 0 || dogroom == uroom){
205.  			gx = u.ux;
206.  			gy = u.uy;
207.  #ifndef QUEST
208.  		} else {
209.  			int tmp = rooms[dogroom].fdoor;
210.  			    cnt = rooms[dogroom].doorct;
211.  
212.  			gx = gy = FAR;	/* random, far away */
213.  			while(cnt--){
214.  			    if(dist(gx,gy) >
215.  				dist(doors[tmp].x, doors[tmp].y)){
216.  					gx = doors[tmp].x;
217.  					gy = doors[tmp].y;
218.  				}
219.  				tmp++;
220.  			}
221.  			/* here gx == FAR e.g. when dog is in a vault */
222.  			if(gx == FAR || (gx == omx && gy == omy)){
223.  				gx = u.ux;
224.  				gy = u.uy;
225.  			}
226.  #endif QUEST
227.  		}
228.  		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
229.  		if(after && udist <= 4 && gx == u.ux && gy == u.uy)
230.  			return(0);
231.  		if(udist > 1){
232.  			if(levl[u.ux][u.uy].typ < ROOM || !rn2(4) ||
233.  			   whappr ||
234.  			   (mtmp->minvent && rn2((int) edog->apport)))
235.  				appr = 1;
236.  		}
237.  		/* if you have dog food he'll follow you more closely */
238.  		if(appr == 0){
239.  			obj = invent;
240.  			while(obj){
241.  				if(obj->otyp == TRIPE_RATION){
242.  					appr = 1;
243.  					break;
244.  				}
245.  				obj = obj->nobj;
246.  			}
247.  		}
248.  	} else	appr = 1;	/* gtyp != UNDEF */
249.  	if(mtmp->mconf) appr = 0;
250.  #ifdef TRACK
251.  	if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){
252.  	extern coord *gettrack();
253.  	register coord *cp;
254.  		cp = gettrack(omx,omy);
255.  		if(cp){
256.  			gx = cp->x;
257.  			gy = cp->y;
258.  		}
259.  	}
260.  #endif TRACK
261.  	nix = omx;
262.  	niy = omy;
263.  	cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS);
264.  	chcnt = 0;
265.  	chi = -1;
266.  	for(i=0; i<cnt; i++){
267.  		nx = poss[i].x;
268.  		ny = poss[i].y;
269.  		if(info[i] & ALLOW_M){
270.  			mtmp2 = m_at(nx,ny);
271.  			if(mtmp2->data->mlevel >= mdat->mlevel+2 ||
272.  			  mtmp2->data->mlet == 'c')
273.  				continue;
274.  			if(after) return(0); /* hit only once each move */
275.  
276.  			if(hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
277.  			  mtmp2->mlstmv != moves &&
278.  			  hitmm(mtmp2,mtmp) == 2) return(2);
279.  			return(0);
280.  		}
281.  
282.  		/* dog avoids traps */
283.  		/* but perhaps we have to pass a trap in order to follow @ */
284.  		if((info[i] & ALLOW_TRAPS) && (trap = g_at(nx,ny,ftrap))){
285.  			if(!(trap->gflag & SEEN) && rn2(40)) continue;
286.  			if(rn2(10)) continue;
287.  		}
288.  
289.  		/* dog eschewes cursed objects */
290.  		/* but likes dog food */
291.  		obj = fobj;
292.  		while(obj){
293.  		    if(obj->ox != nx || obj->oy != ny)
294.  			goto nextobj;
295.  		    if(obj->cursed) goto nxti;
296.  		    if(obj->olet == FOOD_SYM &&
297.  			(otyp = dogfood(obj)) < MANFOOD &&
298.  			(otyp < ACCFOOD || edog->hungrytime <= moves)){
299.  			/* Note: our dog likes the food so much that he
300.  			might eat it even when it conceals a cursed object */
301.  			nix = nx;
302.  			niy = ny;
303.  			chi = i;
304.  		     eatobj:
305.  			edog->eattime = moves + objects[obj->otyp].oc_delay;
306.  			edog->hungrytime =
307.  				moves + 5*objects[obj->otyp].nutrition;
308.  			mtmp->mconf = 0;
309.  			if(cansee(nix,niy))
310.  				pline("%s ate %s.", Monnam(mtmp), doname(obj));
311.  			/* perhaps this was a reward */
312.  			if(otyp != CADAVER)
313.  			edog->apport += 200/(edog->dropdist+moves-edog->droptime);
314.  			delobj(obj);
315.  			goto newdogpos;
316.  		    }
317.  		nextobj:
318.  		    obj = obj->nobj;
319.  		}
320.  
321.  		for(j=0; j<MTSZ && j<cnt-1; j++)
322.  			if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
323.  				if(rn2(4*(cnt-j))) goto nxti;
324.  
325.  /* Some stupid C compilers cannot compute the whole expression at once. */
326.  		nearer = GDIST(nx,ny);
327.  		nearer -= GDIST(nix,niy);
328.  		nearer *= appr;
329.  		if((nearer == 0 && !rn2(++chcnt)) || nearer<0 ||
330.  			(nearer > 0 && !whappr &&
331.  				((omx == nix && omy == niy && !rn2(3))
332.  				|| !rn2(12))
333.  			)){
334.  			nix = nx;
335.  			niy = ny;
336.  			if(nearer < 0) chcnt = 0;
337.  			chi = i;
338.  		}
339.  	nxti:	;
340.  	}
341.  newdogpos:
342.  	if(nix != omx || niy != omy){
343.  		if(info[chi] & ALLOW_U){
344.  			(void) hitu(mtmp, d(mdat->damn, mdat->damd)+1);
345.  			return(0);
346.  		}
347.  		mtmp->mx = nix;
348.  		mtmp->my = niy;
349.  		for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1];
350.  		mtmp->mtrack[0].x = omx;
351.  		mtmp->mtrack[0].y = omy;
352.  	}
353.  	if(mintrap(mtmp) == 2)	/* he died */
354.  		return(2);
355.  	pmon(mtmp);
356.  	return(1);
357.  }
358.  
359.  /* return roomnumber or -1 */
360.  inroom(x,y) xchar x,y; {
361.  #ifndef QUEST
362.  	register struct mkroom *croom = &rooms[0];
363.  	while(croom->hx >= 0){
364.  		if(croom->hx >= x-1 && croom->lx <= x+1 &&
365.  		   croom->hy >= y-1 && croom->ly <= y+1)
366.  			return(croom - rooms);
367.  		croom++;
368.  	}
369.  #endif QUEST
370.  	return(-1);	/* not in room or on door */
371.  }
372.  
373.  tamedog(mtmp, obj)
374.  register struct monst *mtmp;
375.  register struct obj *obj;
376.  {
377.  register struct monst *mtmp2;
378.  	if(mtmp->mtame ||
379.  #ifndef NOWORM
380.  		mtmp->wormno ||
381.  #endif NOWORM
382.  		mtmp->isshk || mtmp->isgd)
383.  		return(0); /* no tame long worms? */
384.  	if(obj) {
385.  		if(dogfood(obj) >= MANFOOD) return(0);
386.  		if(cansee(mtmp->mx,mtmp->my)){
387.  			pline("%s devours the %s.", Monnam(mtmp),
388.  				objects[obj->otyp].oc_name);
389.  		}
390.  		obfree(obj, (struct obj *) 0);
391.  	}
392.  	mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
393.  	*mtmp2 = *mtmp;
394.  	mtmp2->mxlth = sizeof(struct edog);
395.  	if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp));
396.  	initedog(mtmp2);
397.  	replmon(mtmp,mtmp2);
398.  	return(1);
399.  }
Advertisement