Source:Dogmove.c

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

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