Source:Hack 1.0/hack.dog.c

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

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; idata->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; jmtrack[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. }