Source:NetHack 3.2.0/dogmove.c

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

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

1.   /*	SCCS Id: @(#)dogmove.c	3.2	95/12/21	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6. 7.   #include "mfndpos.h"  8.    #include "edog.h"  9. 10.  #ifdef OVL0 11.   12.   static boolean FDECL(dog_hunger,(struct monst *,struct edog *)); 13.  static int FDECL(dog_invent,(struct monst *,struct edog *,int)); 14.  static int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); 15.   16.   static struct obj *FDECL(DROPPABLES, (struct monst *)); 17.   18.   static struct obj * 19.  DROPPABLES(mon) 20.  register struct monst *mon; 21.  {  22.   	register struct obj *obj; 23.  	struct obj *wep = MON_WEP(mon); 24.   25.   	for(obj = mon->minvent; obj; obj = obj->nobj) 26.  		if (!obj->owornmask && obj != wep) return obj; 27.  	return (struct obj *)0; 28.  }  29.    30.   static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; 31.   32.   #endif /* OVL0 */ 33.   34.   STATIC_OVL boolean FDECL(cursed_object_at, (int, int)); 35.   36.   STATIC_VAR xchar gtyp, gx, gy;	/* type and position of dog's current goal */ 37.   38.   STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); 39.   40.   #ifdef OVLB 41.  STATIC_OVL boolean 42.  cursed_object_at(x, y)  43. int x, y; 44. { 45.   	struct obj *otmp; 46.   47.   	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 48.  		if (otmp->cursed) return TRUE; 49.  	return FALSE; 50.  }  51.    52.   int 53.  dog_nutrition(mtmp, obj) 54.  struct monst *mtmp; 55.  struct obj *obj; 56.  {  57.   	int nutrit; 58.   59.   	/*  60.   	 * It is arbitrary that the pet takes the same length of time to eat 61.  	 * as a human, but gets more nutritional value. 62.  	 */  63.   	if (obj->oclass == FOOD_CLASS) { 64.  	    if(obj->otyp == CORPSE) { 65.  		mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); 66.  		nutrit = mons[obj->corpsenm].cnutrit; 67.  	    } else { 68.  		mtmp->meating = objects[obj->otyp].oc_delay; 69.  		nutrit = objects[obj->otyp].oc_nutrition; 70.  	    }  71.   	    switch(mtmp->data->msize) { 72.  		case MZ_TINY: nutrit *= 8; break; 73.  		case MZ_SMALL: nutrit *= 6; break; 74.  		default: 75.  		case MZ_MEDIUM: nutrit *= 5; break; 76.  		case MZ_LARGE: nutrit *= 4; break; 77.  		case MZ_HUGE: nutrit *= 3; break; 78.  		case MZ_GIGANTIC: nutrit *= 2; break; 79.  	    }  80.   	    if(obj->oeaten) { 81.  		mtmp->meating = eaten_stat(mtmp->meating, obj); 82.  		nutrit = eaten_stat(nutrit, obj); 83.  	    }  84.   	} else if (obj->oclass == GOLD_CLASS) { 85.  	    mtmp->meating = ((int)obj->quan/2000) + 1; 86.  	    nutrit = ((int)obj->quan/20); 87.  	} else { 88.  	    /* Unusual pet such as gelatinous cube eating odd stuff. 89.  	     * meating made consistent with wild monsters in mon.c.  90. * nutrit made consistent with polymorphed player nutrit in 91. * eat.c. (This also applies to pets eating gold.) 92.  	     */  93.   	    mtmp->meating = obj->owt/20 + 1; 94.  	    nutrit = 5*objects[obj->otyp].oc_nutrition; 95.  	}  96.   	return nutrit; 97.  }  98.    99.   /* returns 2 if pet dies, otherwise 1 */ 100. int 101. dog_eat(mtmp, obj, x, y, devour) 102. register struct monst *mtmp; 103. register struct obj * obj; 104. int x, y;  105. boolean devour; 106. {  107.  	register struct edog *edog = EDOG(mtmp); 108. 	boolean poly = FALSE, grow = FALSE, heal = FALSE; 109. 	int nutrit; 110.  111.  	if(edog->hungrytime < moves) 112. 	    edog->hungrytime = moves; 113. 	nutrit = dog_nutrition(mtmp, obj); 114. 	poly = polyfodder(obj); 115. 	grow = mlevelgain(obj); 116. 	heal = mhealup(obj); 117. 	if (devour) { 118. 	    if (mtmp->meating > 1) mtmp->meating /= 2; 119. 	    if (nutrit > 1) nutrit = (nutrit * 3) / 4; 120. 	}  121.  	edog->hungrytime += nutrit; 122. 	mtmp->mconf = 0; 123. 	if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; 124. 	if (mtmp->mtame < 20) mtmp->mtame++; 125. 	if (x != mtmp->mx || y != mtmp->my) {	/* moved & ate on same turn */ 126. 	    newsym(x, y); 127. 	    newsym(mtmp->mx, mtmp->my); 128. 	}  129.  	/* hack: observe the action if either new or old location is in view */ 130. 	if (cansee(x, y) || cansee(mtmp->mx, mtmp->my)) 131. 	    pline("%s %s %s.", Monnam(mtmp),  132.  		  devour ? "devours" : "eats",  133.  		  (obj->oclass == FOOD_CLASS) ?  134.  			singular(obj, doname) : doname(obj)); 135. 	/* It's a reward if it's DOGFOOD and the player dropped/threw it. */ 136.  	/* We know the player had it if invlet is set -dlc */ 137. 	if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet) 138. #ifdef LINT 139. 	    edog->apport = 0; 140. #else 141. 	    edog->apport += (int)(200L/  142.  		((long)edog->dropdist + moves - edog->droptime)); 143. #endif 144. 	if (obj == uball) { 145. 	    unpunish; 146. 	    delobj(obj); 147. 	} else if (obj == uchain) 148. 	    unpunish; 149. 	else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) 150. 	    obj->quan--; 151. 	else 152. 	    delobj(obj); 153.  154.  	if (poly) { 155. 	    char oldpet[BUFSZ]; 156.  157.  	    Strcpy(oldpet, Monnam(mtmp)); 158. 	    if (newcham(mtmp, (struct permonst *)0) &&  159.  			cansee(mtmp->mx, mtmp->my)) { 160. 		uchar save_mnamelth = mtmp->mnamelth; 161. 		mtmp->mnamelth = 0; 162. 		pline("%s turns into %s!", oldpet, a_monnam(mtmp)); 163. 		mtmp->mnamelth = save_mnamelth; 164. 	    }  165.  	}  166.  	/* limit "instant" growth to prevent potential abuse */ 167. 	if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { 168. 	    if (!grow_up(mtmp, (struct monst *)0)) return 2; 169. 	}  170.  	if (heal) mtmp->mhp = mtmp->mhpmax; 171. 	return 1; 172. }  173.   174.  #endif /* OVLB */ 175. #ifdef OVL0 176.  177.  /* hunger effects -- returns TRUE on starvation */ 178. static boolean 179. dog_hunger(mtmp, edog) 180. register struct monst *mtmp; 181. register struct edog *edog; 182. {  183.  	if (moves > edog->hungrytime + 500) { 184. 	    if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { 185. 		edog->hungrytime = moves + 500; 186. 		/* but not too high; it might polymorph */ 187. 	    } else if (!mtmp->mconf) { 188. 		mtmp->mconf = 1; 189. 		mtmp->mhpmax /= 3; 190. 		if (mtmp->mhp > mtmp->mhpmax) 191. 		    mtmp->mhp = mtmp->mhpmax; 192. 		if (mtmp->mhp < 1) goto dog_died; 193. 		if (cansee(mtmp->mx, mtmp->my)) 194. 		    pline("%s is confused from hunger.", Monnam(mtmp)); 195. 		else if (couldsee(mtmp->mx, mtmp->my)) 196. 		    beg(mtmp); 197. 		else { 198. 		    char buf[BUFSZ]; 199.  200.  		    Strcpy(buf, "the "); 201. 		    You_feel("worried about %s.", mtmp->mnamelth ?  202.  			NAME(mtmp) : strcat(buf, Hallucination 203. 			? rndmonnam : mtmp->data->mname)); 204. 		}  205.  	    } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) { 206. 	    dog_died: 207. 		if (mtmp->mleashed) 208. 		    Your("leash goes slack."); 209. 		else if (cansee(mtmp->mx, mtmp->my)) 210. 		    pline("%s dies%s.", Monnam(mtmp),  211.  			    (mtmp->mhp >= 1) ? "" : " from hunger"); 212. 		else 213. 		    You_feel("%s for a moment.",  214.  			Hallucination ? "bummed" : "sad"); 215. 		mondied(mtmp); 216. 		return(TRUE); 217. 	    }  218.  	}  219.  	return(FALSE); 220. }  221.   222.  /* do something with object (drop, pick up, eat) at current position 223.  * returns 1 if object eaten (since that counts as dog's move), 2 if died 224.  */  225.  static int 226. dog_invent(mtmp, edog, udist) 227. register struct monst *mtmp; 228. register struct edog *edog; 229. int udist; 230. {  231.  	register int omx, omy; 232. 	struct obj *obj; 233.  234.  	if (mtmp->msleep || !mtmp->mcanmove) return(0); 235.  236.  	omx = mtmp->mx; 237. 	omy = mtmp->my; 238.  239.  	/* if we are carrying sth then we drop it (perhaps near @) */ 240. 	/* Note: if apport == 1 then our behaviour is independent of udist */ 241. 	if(DROPPABLES(mtmp) || mtmp->mgold) { 242. 	    if (!rn2(udist) || !rn2(edog->apport)) 243. 		if(rn2(10) < edog->apport){ 244. 		    relobj(mtmp, (int)mtmp->minvis, TRUE); 245. 		    if(edog->apport > 1) edog->apport--; 246. 		    edog->dropdist = udist;		/* hpscdi!jon */ 247. 		    edog->droptime = moves; 248. 		}  249.  	} else { 250. 	    if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)  251.  #ifdef MAIL  252.  			&& obj->otyp != SCR_MAIL  253.  #endif  254.  									){ 255. 		if (dogfood(mtmp, obj) <= CADAVER) 256. 		    return dog_eat(mtmp, obj, omx, omy, FALSE); 257.  258.  		if(can_carry(mtmp, obj) && !obj->cursed) 259. 		    if(rn2(20) < edog->apport+3) 260. 			if (rn2(udist) || !rn2(edog->apport)) { 261. 			    if (cansee(omx, omy) && flags.verbose) 262. 				pline("%s picks up %s.", Monnam(mtmp),  263.  				    distant_name(obj, doname)); 264. 			    obj_extract_self(obj); 265. 			    newsym(omx,omy); 266. 			    mpickobj(mtmp,obj); 267. 			    if (attacktype(mtmp->data, AT_WEAP)) { 268. 				mtmp->weapon_check = NEED_HTH_WEAPON; 269. 				(void) mon_wield_item(mtmp); 270. 			    }  271.  			}  272.  	    }  273.  	}  274.  	return 0; 275. }  276.   277.  /* set dog's goal -- gtyp, gx, gy  278. * returns -1/0/1 (dog's desire to approach player) or -2 (abort move) 279.  */  280.  static int 281. dog_goal(mtmp, edog, after, udist, whappr) 282. register struct monst *mtmp; 283. struct edog *edog; 284. int after, udist, whappr; 285. {  286.  	register int omx, omy; 287. 	boolean in_masters_sight; 288. 	register struct obj *obj; 289. 	xchar otyp; 290. 	int appr; 291.  292.  	omx = mtmp->mx; 293. 	omy = mtmp->my; 294.  295.  	in_masters_sight = couldsee(omx, omy); 296.  297.  	if (!edog || mtmp->mleashed) {	/* he's not going anywhere... */ 298.  	    gtyp = APPORT; 299. 	    gx = u.ux; 300. 	    gy = u.uy; 301. 	} else { 302. #define DDIST(x,y) (dist2(x,y,omx,omy)) 303. #define SQSRCHRADIUS 5 304. 	    int min_x, max_x, min_y, max_y; 305. 	    register int nx, ny; 306.  307.  	    gtyp = UNDEF;	/* no goal as yet */ 308. 	    gx = gy = 0;	/* suppress 'used before set' message */ 309.  310.  	    if ((min_x = omx - SQSRCHRADIUS) < 0) min_x = 0; 311. 	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; 312. 	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; 313. 	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; 314.  315.  	    /* nearby food is the first choice, then other objects */ 316. 	    for (obj = fobj; obj; obj = obj->nobj) { 317. 		nx = obj->ox; 318. 		ny = obj->oy; 319. 		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { 320. 		    otyp = dogfood(mtmp, obj); 321. 		    if (otyp > gtyp || otyp == UNDEF) 322. 			continue; 323. 		    if (cursed_object_at(nx, ny)) 324. 			continue; 325. 		    if (otyp < MANFOOD) { 326. 			if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) { 327. 			    gx = nx; 328. 			    gy = ny; 329. 			    gtyp = otyp; 330. 			}  331.  		    } else if(gtyp == UNDEF && in_masters_sight &&  332.  			      !mtmp->minvent &&  333.  			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&  334.  			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&  335.  			      edog->apport > rn2(8) &&  336.  			      can_carry(mtmp,obj)) { 337. 			gx = nx; 338. 			gy = ny; 339. 			gtyp = APPORT; 340. 		    }  341.  		}  342.  	    }  343.  	}  344.   345.  	/* follow player if appropriate */ 346. 	if (gtyp == UNDEF ||  347.  	    (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) { 348. 		gx = u.ux; 349. 		gy = u.uy; 350. 		if (after && udist <= 4 && gx == u.ux && gy == u.uy) 351. 			return(-2); 352. 		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; 353.  		if (udist > 1) { 354. 			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||  355.  			   whappr ||  356.  			   (mtmp->minvent && rn2(edog->apport))) 357. 				appr = 1; 358. 		}  359.  		/* if you have dog food it'll follow you more closely */ 360. 		if (appr == 0) { 361. 			obj = invent; 362. 			while (obj) { 363. 				if(dogfood(mtmp, obj) == DOGFOOD) { 364. 					appr = 1; 365. 					break; 366. 				}  367.  				obj = obj->nobj; 368. 			}  369.  		}  370.  	} else 371. 	    appr = 1;	/* gtyp != UNDEF */ 372. 	if(mtmp->mconf) 373. 	    appr = 0; 374.  375.  #define FARAWAY (COLNO + 2)		/* position outside screen */ 376. 	if (gx == u.ux && gy == u.uy && !in_masters_sight) { 377. 	    register coord *cp; 378.  379.  	    cp = gettrack(omx,omy); 380. 	    if (cp) { 381. 		gx = cp->x; 382. 		gy = cp->y; 383. 		if(edog) edog->ogoal.x = 0; 384. 	    } else { 385. 		/* assume master hasn't moved far, and reuse previous goal */ 386. 		if(edog && edog->ogoal.x &&  387.  		   ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { 388. 		    gx = edog->ogoal.x;  389. gy = edog->ogoal.y; 390. edog->ogoal.x = 0; 391. 		} else { 392. 		    int fardist = FARAWAY * FARAWAY; 393. 		    gx = gy = FARAWAY; /* random */ 394. 		    do_clear_area(omx, omy, 9, wantdoor,  395.  				  (genericptr_t)&fardist); 396.  397.  		    /* here gx == FARAWAY e.g. when dog is in a vault */ 398. 		    if (gx == FARAWAY || (gx == omx && gy == omy)) { 399. 			gx = u.ux; 400. 			gy = u.uy; 401. 		    } else if(edog) { 402. 			edog->ogoal.x = gx; 403. 			edog->ogoal.y = gy; 404. 		    }  405.  		}  406.  	    }  407.  	} else if(edog) { 408. 	    edog->ogoal.x = 0; 409. 	}  410.  	return appr; 411. }  412.   413.  /* return 0 (no move), 1 (move) or 2 (dead) */ 414. int 415. dog_move(mtmp, after) 416. register struct monst *mtmp; 417. register int after;	/* this is extra fast monster movement */ 418. {  419.  	int omx, omy;		/* original mtmp position */ 420. 	int appr, whappr, udist; 421. 	int i, j, k;  422. register struct edog *edog = EDOG(mtmp); 423. 	struct obj *obj = (struct obj *) 0; 424. 	xchar otyp; 425. 	boolean has_edog, cursemsg[9], do_eat = FALSE; 426. 	xchar nix, niy;		/* position mtmp is (considering) moving to */ 427. 	register int nx, ny;	/* temporary coordinates */ 428. 	xchar cnt, uncursedcnt, chcnt; 429. 	int chi = -1, nidist, ndist; 430. 	coord poss[9]; 431. 	long info[9], allowflags; 432. #define GDIST(x,y) (dist2(x,y,gx,gy)) 433.  434.  	/*  435.  	 * Tame Angels have isminion set and an ispriest structure instead of  436. * an edog structure. Fortunately, guardian Angels need not worry 437. 	 * about mundane things like eating and fetching objects, and can 438. 	 * spend all their energy defending the player. (They are the only 439.  	 * monsters with other structures that can be tame.) 440. 	 */  441.  	has_edog = !mtmp->isminion; 442.  443.  	omx = mtmp->mx; 444. 	omy = mtmp->my; 445. 	if (has_edog && dog_hunger(mtmp, edog)) return(2);	/* starved */ 446.  447.  	udist = distu(omx,omy); 448. 	/* maybe we tamed him while being swallowed --jgm */ 449. 	if (!udist) return(0); 450.  451.  	nix = omx;	/* set before newdogpos */ 452. 	niy = omy; 453. 	cursemsg[0] = FALSE;	/* lint suppression */ 454. 	info[0] = 0;		/* ditto */ 455.  456.  	if (has_edog) { 457. 	    j = dog_invent(mtmp, edog, udist); 458. 	    if (j == 2) return 2;		/* died */ 459. 	    else if (j == 1) goto newdogpos;	/* eating something */ 460.  461.  	    whappr = (moves - edog->whistletime < 5); 462. 	} else 463. 	    whappr = 0; 464.  465.  	appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0,  466.  							after, udist, whappr); 467. 	if (appr == -2) return(0); 468.  469.  	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; 470. 	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL); 471. 	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; 472. 	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { 473. 	    allowflags |= ALLOW_U; 474. 	    if (!has_edog) { 475. 		coord mm; 476. 		/* Guardian angel refuses to be conflicted; rather, 477. 		 * it disappears, angrily, and sends in some nasties 478. 		 */  479.  		if (canspotmon(mtmp)) { 480. 		    pline("%s rebukes you, saying:", Monnam(mtmp)); 481. 		    verbalize("Since you desire conflict, have some more!"); 482. 		}  483.  		mongone(mtmp); 484. 		i = rnd(4); 485. 		while(i--) { 486. 		    mm.x = u.ux; 487. 		    mm.y = u.uy; 488. 		    if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) 489. 			(void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,  490.  					 mm.x, mm.y, FALSE); 491. 		}  492.  		return(2); 493.  494.  	    }  495.  	}  496.  	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { 497. 		allowflags |= OPENDOOR; 498. 		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; 499. 	}  500.  	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; 501. 	if (tunnels(mtmp->data) && !needspick(mtmp->data)) 502. 		allowflags |= ALLOW_DIG; 503. 	cnt = mfndpos(mtmp, poss, info, allowflags); 504.  505.  	/* Normally dogs don't step on cursed items, but if they have no  506. * other choice they will. This requires checking ahead of time 507. 	 * to see how many uncursed item squares are around. 508. 	 */  509.  	uncursedcnt = 0; 510. 	for (i = 0; i < cnt; i++) { 511. 		nx = poss[i].x; ny = poss[i].y;  512. if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue; 513. 		if (cursed_object_at(nx, ny)) continue; 514. 		uncursedcnt++; 515. 	}  516.   517.  	chcnt = 0; 518. 	chi = -1; 519. 	nidist = GDIST(nix,niy); 520.  521.  	for (i = 0; i < cnt; i++) { 522. 		nx = poss[i].x;  523. ny = poss[i].y; 524. cursemsg[i] = FALSE; 525.  526.  		/* if leashed, we drag him along. */ 527.  		if (mtmp->mleashed && distu(nx, ny) > 4) continue; 528.  529.  		/* if a guardian, try to stay close by choice */ 530. 		if (!has_edog &&  531.  		    (j = distu(nx, ny)) > 16 && j >= udist) continue; 532.  533.  		if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { 534. 		    int mstatus; 535. 		    register struct monst *mtmp2 = m_at(nx,ny); 536.  537.  		    if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 ||  538.  			(mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && 539. 			 mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee 540. 			 && (perceives(mtmp->data) || !mtmp2->minvis)) ||  541.  			(mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||  542.  			(max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||  543.  			((mtmp->mhp*4 < mtmp->mhpmax  544.  			  || mtmp2->data->msound == MS_GUARDIAN  545.  			  || mtmp2->data->msound == MS_LEADER) && 546. 			 mtmp2->mpeaceful && !Conflict) ||  547.  			   (mtmp2->data->mlet == S_COCKATRICE && 548. 				!resists_ston(mtmp))) 549. 			continue; 550.  551.  		    if (after) return(0); /* hit only once each move */ 552.  553.  		    mstatus = mattackm(mtmp, mtmp2); 554.  555.  		    /* aggressor (pet) died */ 556. 		    if (mstatus & MM_AGR_DIED) return 2; 557.  558.  		    if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&  559.  			rn2(4) && mtmp2->mlstmv != monstermoves &&  560.  			!onscary(mtmp->mx, mtmp->my, mtmp2)) { 561. 			mstatus = mattackm(mtmp2, mtmp);  /* return attack */ 562. 			if (mstatus & MM_DEF_DIED) return 2; 563. 		    }  564.   565.  		    return 0; 566. 		}  567.   568.  		{   /* Dog avoids harmful traps, but perhaps it has to pass one 569. 		     * in order to follow player. (Non-harmful traps do not 570.  		     * have ALLOW_TRAPS in info[].)  The dog only avoids the 571. 		     * trap if you've seen it, unlike enemies who avoid traps 572. 		     * if they've seen some trap of that type sometime in the 573. 		     * past. (Neither behavior is really realistic.) 574. 		     */  575.  		    struct trap *trap; 576.  577.  		    if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) { 578. 			if (mtmp->mleashed) { 579. 			    if (flags.soundok) whimper(mtmp); 580. 			} else 581. 			    /* 1/40 chance of stepping on it anyway, in case 582. 			     * it has to pass one to follow the player...  583. */ 584.  			    if (trap->tseen && rn2(40)) continue; 585. 		    }  586.  		}  587.   588.  		/* dog eschews cursed objects, but likes dog food */ 589. 		/* (minion isn't interested; `cursemsg' stays FALSE) */ 590. 		if (has_edog) 591. 		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { 592. 		    if (obj->cursed) cursemsg[i] = TRUE; 593. 		    else if ((otyp = dogfood(mtmp, obj)) < MANFOOD &&  594.  			     (otyp < ACCFOOD || edog->hungrytime <= moves)) { 595. 			/* Note: our dog likes the food so much that he  596. * might eat it even when it conceals a cursed object */ 597. 			nix = nx; 598. 			niy = ny; 599. 			chi = i;  600. do_eat = TRUE; 601. 			cursemsg[i] = FALSE;	/* not reluctant */ 602. 			goto newdogpos; 603. 		    }  604.  		}  605.  		/* didn't find something to eat; if we saw a cursed item and 606. 		   aren't being forced to walk on it, usually keep looking */ 607. 		if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 &&  608.  		    rn2(13 * uncursedcnt)) continue; 609.  610.  		/* lessen the chance of backtracking to previous position(s) */ 611. 		k = has_edog ? uncursedcnt : cnt; 612. 		for (j = 0; j < MTSZ && j < k - 1; j++) 613. 			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)  614. if (rn2(MTSZ * (k - j))) goto nxti; 615.  616.  		j = ((ndist = GDIST(nx,ny)) - nidist) * appr; 617. 		if ((j == 0 && !rn2(++chcnt)) || j < 0 ||  618.  			(j > 0 && !whappr && 619. 				((omx == nix && omy == niy && !rn2(3))  620.  					|| !rn2(12)) 621. 			)) {  622.  			nix = nx; 623. 			niy = ny; 624. 			nidist = ndist; 625. 			if(j < 0) chcnt = 0; 626. 			chi = i;  627. } 628.  	nxti:	; 629. 	}  630.  newdogpos: 631. 	if (nix != omx || niy != omy) { 632. 		if (info[chi] & ALLOW_U) { 633. 			if (mtmp->mleashed) { /* play it safe */ 634. 				pline("%s breaks loose of %s leash!",  635.  				      Monnam(mtmp), his[pronoun_gender(mtmp)]); 636. 				m_unleash(mtmp); 637. 			}  638.  			(void) mattacku(mtmp); 639. 			return(0); 640. 		}  641.  		/* insert a worm_move if worms ever begin to eat things */ 642. 		remove_monster(omx, omy); 643. 		place_monster(mtmp, nix, niy); 644. 		if (cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy))) 645. 			pline("%s moves only reluctantly.", Monnam(mtmp)); 646. 		for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; 647. 		mtmp->mtrack[0].x = omx; 648. 		mtmp->mtrack[0].y = omy; 649. 		/* We have to know if the pet's gonna do a combined eat and 650. 		 * move before moving it, but it can't eat until after being 651. 		 * moved. Thus the do_eat flag. 652. 		 */  653.  		if (do_eat) { 654. 		    if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; 655. 		}  656.  	} else if (mtmp->mleashed && distu(omx, omy) > 4) { 657. 		/* an incredible kludge, but the only way to keep pooch near 658. 		 * after it spends time eating or in a trap, etc. 659. 		 */  660.  		coord cc; 661.  662.  		nx = sgn(omx - u.ux); 663. 		ny = sgn(omy - u.uy); 664. 		cc.x = u.ux + nx; 665. 		cc.y = u.uy + ny; 666. 		if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext; 667.  668.  		i  = xytod(nx, ny); 669. 		for (j = (i + 7)%8; j < (i + 1)%8; j++) { 670. 			dtoxy(&cc, j); 671. 			if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext; 672. 		}  673.  		for (j = (i + 6)%8; j < (i + 2)%8; j++) { 674. 			dtoxy(&cc, j); 675. 			if (goodpos(cc.x, cc.y, mtmp, mtmp->data)) goto dognext; 676. 		}  677.  		cc.x = mtmp->mx; 678. 		cc.y = mtmp->my; 679. dognext: 680. 		remove_monster(mtmp->mx, mtmp->my); 681. 		place_monster(mtmp, cc.x, cc.y); 682. 		newsym(cc.x,cc.y); 683. 		set_apparxy(mtmp); 684. 	}  685.  	return(1); 686. }  687.   688.  #endif /* OVL0 */ 689. #ifdef OVLB 690.  691.  /*ARGSUSED*/	/* do_clear_area client */ 692. STATIC_PTR void 693. wantdoor(x, y, distance) 694. int x, y;  695. genericptr_t distance; 696. {  697.      register ndist; 698.  699.      if (*(int*)distance > (ndist = distu(x, y))) { 700. 	gx = x;  701. gy = y; 702. *(int*)distance = ndist; 703.     }  704.  }  705.   706.  #endif /* OVLB */ 707.  708.  /*dogmove.c*/