Source:SLASH'EM 0.0.7E7F2/dogmove.c

Below is the full text to dogmove.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/dogmove.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

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.    #include "emin.h"  10. #include "epri.h" 11. 12.  /* #define DEBUG */	/* uncomment to enable debugging */ 13.   14.   #ifdef DEBUG 15.  # ifdef WIZARD 16.  #define debugpline      if (wizard) pline 17.  # else 18.  #define debugpline      pline 19.  # endif 20.  #endif 21.   22.   extern boolean notonhead; 23.   24.   #ifdef OVL0 25.   26.   STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *)); 27.  STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int)); 28.  STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); 29.   30.   STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *)); 31.  STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P, 32.      XCHAR_P,XCHAR_P)); 33.  STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P)); 34.   35.   STATIC_OVL struct obj * 36.  DROPPABLES(mon) 37.  register struct monst *mon; 38.  {  39.   	register struct obj *obj; 40.  	struct obj *wep = MON_WEP(mon); 41.  	boolean item1 = FALSE, item2 = FALSE; 42.   43.   	if (is_animal(mon->data) || mindless(mon->data)) 44.  		item1 = item2 = TRUE; 45.  	if (!tunnels(mon->data) || !needspick(mon->data)) 46.  		item1 = TRUE; 47.  	for(obj = mon->minvent; obj; obj = obj->nobj) { 48.  		if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK 49.  						|| !which_armor(mon, W_ARMS))) { 50.  			item1 = TRUE; 51.  			continue; 52.  		}  53.   		if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) { 54.  			item2 = TRUE; 55.  			continue; 56.  		}  57.   		if (!obj->owornmask && obj != wep) return obj; 58.  	}  59.   	return (struct obj *)0; 60.  }  61.    62.   static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; 63.   64.   #endif /* OVL0 */ 65.   66.   STATIC_OVL boolean FDECL(cursed_object_at, (struct monst *, int, int)); 67.   68.   STATIC_VAR xchar gtyp, gx, gy;	/* type and position of dog's current goal */ 69.   70.   STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); 71.   72.   #ifdef OVLB 73.  STATIC_OVL boolean 74.  cursed_object_at(mtmp, x, y)  75. register struct monst *mtmp; 76.  int x, y;  77. { 78.   	struct obj *otmp; 79.   80.   	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 81.  		/* [Tom] demons & undead don't care, though */ 82.  		/* [ALI] demons & undead avoid blessed items instead */ 83.  		if ((is_demon(mtmp->data) || is_undead(mtmp->data)) ?  84.   		    otmp->blessed : otmp->cursed) 85.  	{  86.   #ifdef DEBUG 87.  		debugpline("%s thinks %s at (%d,%d) is `cursed'",  88.   		  noit_Monnam(mtmp), doname(otmp), x, y); 89.  #endif 90.  		return TRUE; 91.  	}  92.   	return FALSE; 93.  }  94.    95.   int 96.  dog_nutrition(mtmp, obj) 97.  struct monst *mtmp; 98.  struct obj *obj; 99.  {  100.  	int nutrit; 101.  102.  	/*  103.  	 * It is arbitrary that the pet takes the same length of time to eat 104. 	 * as a human, but gets more nutritional value. 105. 	 */  106.  	if (obj->oclass == FOOD_CLASS) { 107. 	    if(obj->otyp == CORPSE) { 108. 		mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); 109. 		nutrit = mons[obj->corpsenm].cnutrit; 110. 	    } else { 111. 		mtmp->meating = objects[obj->otyp].oc_delay; 112. 		nutrit = objects[obj->otyp].oc_nutrition; 113. 	    }  114.  	    switch(mtmp->data->msize) { 115. 		case MZ_TINY: nutrit *= 8; break; 116. 		case MZ_SMALL: nutrit *= 6; break; 117. 		default: 118. 		case MZ_MEDIUM: nutrit *= 5; break; 119. 		case MZ_LARGE: nutrit *= 4; break; 120. 		case MZ_HUGE: nutrit *= 3; break; 121. 		case MZ_GIGANTIC: nutrit *= 2; break; 122. 	    }  123.  	    if(obj->oeaten) { 124. 		mtmp->meating = eaten_stat(mtmp->meating, obj); 125. 		nutrit = eaten_stat(nutrit, obj); 126. 	    }  127.  	} else if (obj->oclass == COIN_CLASS) { 128. 	    mtmp->meating = (int)(obj->quan/2000) + 1; 129. 	    if (mtmp->meating < 0) mtmp->meating = 1; 130. 	    nutrit = (int)(obj->quan/20); 131. 	    if (nutrit < 0) nutrit = 0; 132. 	} else { 133. 	    /* Unusual pet such as gelatinous cube eating odd stuff. 134. 	     * meating made consistent with wild monsters in mon.c.  135. * nutrit made consistent with polymorphed player nutrit in 136. * eat.c. (This also applies to pets eating gold.) 137. 	     */  138.  	    mtmp->meating = obj->owt/20 + 1; 139. 	    nutrit = 5*objects[obj->otyp].oc_nutrition; 140. 	}  141.  	return nutrit; 142. }  143.   144.  /* returns 2 if pet dies, otherwise 1 */ 145. int 146. dog_eat(mtmp, obj, x, y, devour) 147. register struct monst *mtmp; 148. register struct obj * obj; 149. int x, y;  150. boolean devour; 151. {  152.  	register struct edog *edog = EDOG(mtmp); 153. 	boolean poly = FALSE, grow = FALSE, heal = FALSE; 154. 	int nutrit; 155. 	boolean vis = (cansee(x, y) || cansee(mtmp->mx, mtmp->my)); 156. 	boolean vampiric = is_vampire(mtmp->data); 157.  158.  	if(edog->hungrytime < monstermoves) 159. 	    edog->hungrytime = monstermoves; 160. 	nutrit = dog_nutrition(mtmp, obj); 161. 	poly = polyfodder(obj); 162. 	grow = mlevelgain(obj); 163. 	heal = mhealup(obj); 164. 	if (devour) { 165. 	    if (mtmp->meating > 1) mtmp->meating /= 2; 166. 	    if (nutrit > 1) nutrit = (nutrit * 3) / 4; 167. 	}  168.   169.  	/* vampires only get 1/5 normal nutrition */ 170. 	if (vampiric) { 171. 	    mtmp->meating = (mtmp->meating + 4) / 5; 172. 	    nutrit = (nutrit + 4) / 5; 173. 	}  174.  	  175.  	edog->hungrytime += nutrit; 176. 	mtmp->mconf = 0; 177. 	if (edog->mhpmax_penalty) { 178. 	    /* no longer starving */ 179. 	    mtmp->mhpmax += edog->mhpmax_penalty; 180. 	    edog->mhpmax_penalty = 0; 181. 	}  182.  	if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; 183. 	if (mtmp->mtame < 20) mtmp->mtame++; 184. 	if (x != mtmp->mx || y != mtmp->my) {	/* moved & ate on same turn */ 185. 	    newsym(x, y); 186. 	    newsym(mtmp->mx, mtmp->my); 187. 	}  188.  	if (is_pool(x, y) && !Underwater) { 189. 	    /* Don't print obj */ 190. 	    /* TODO: Reveal presence of sea monster (especially sharks) */ 191. 	} else 192. 	/* hack: observe the action if either new or old location is in view */ 193. 	/* However, invisible monsters should still be "it" even though out of  194. sight locations should not. */ 195.  	if (vis) 196. 	    pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It",  197.  		  vampiric ? "drains" : devour ? "devours" : "eats",  198.  		  (obj->oclass == FOOD_CLASS) ?  199.  			singular(obj, doname) : doname(obj)); 200. 	/* It's a reward if it's DOGFOOD and the player dropped/threw it. */ 201.  	/* We know the player had it if invlet is set -dlc */ 202. 	if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet) 203. #ifdef LINT 204. 	    edog->apport = 0; 205. #else 206. 	    edog->apport += (int)(200L/  207.  		((long)edog->dropdist + monstermoves - edog->droptime)); 208. #endif 209. 	if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { 210. 	    /* The object's rustproofing is gone now */ 211. 	    obj->oerodeproof = 0; 212. 	    mtmp->mstun = 1; 213. 	    if (canseemon(mtmp) && flags.verbose) { 214. 		pline("%s spits %s out in disgust!",  215.  		      Monnam(mtmp), distant_name(obj,doname)); 216. 	    }  217.  	} else if (vampiric) { 218. 		/* Split Object */ 219. 		if (obj->quan > 1L) { 220. 		    if(!carried(obj)) { 221. 			(void) splitobj(obj, 1L); 222. 		    } else { 223. 		    	/* Carried */ 224. 			obj = splitobj(obj, obj->quan - 1L); 225. 			  226.  			freeinv(obj); 227. 			if (inv_cnt >= 52 && !merge_choice(invent, obj)) 228. 			    dropy(obj); 229. 			else 230. 			    obj = addinv(obj); /* unlikely but a merge is possible */ 231. 		    }  232.  #ifdef DEBUG 233. 		    debugpline("split object,"); 234. #endif 235. 		}  236.  		  237.  		/* Take away blood nutrition */ 238. 	    	obj->oeaten = drainlevel(obj); 239. 		obj->odrained = 1; 240. 	} else if (obj == uball) { 241. 	    unpunish; 242. 	    delobj(obj); 243. 	} else if (obj == uchain) 244. 	    unpunish; 245. 	else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) { 246. 	    obj->quan--; 247. 	    obj->owt = weight(obj); 248. 	} else 249. 	    delobj(obj); 250.  251.  	if (poly) { 252. 	    (void) mon_spec_poly(mtmp, (struct permonst *)0, 0L, FALSE,  253.  		    cansee(mtmp->mx, mtmp->my), FALSE, FALSE); 254. #if 0 255. 	    (void) newcham(mtmp, (struct permonst *)0, FALSE,  256.  			   cansee(mtmp->mx, mtmp->my)); 257. #endif 258. 	}  259.  	/* limit "instant" growth to prevent potential abuse */ 260. 	if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { 261. 	    if (!grow_up(mtmp, (struct monst *)0)) return 2; 262. 	}  263.  	if (heal) mtmp->mhp = mtmp->mhpmax; 264. 	return 1; 265. }  266.   267.  #endif /* OVLB */ 268. #ifdef OVL0 269.  270.  /* hunger effects -- returns TRUE on starvation */ 271. STATIC_OVL boolean 272. dog_hunger(mtmp, edog) 273. register struct monst *mtmp; 274. register struct edog *edog; 275. {  276.  	if (monstermoves > edog->hungrytime + 500) { 277. 	    if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { 278. 		edog->hungrytime = monstermoves + 500; 279. 		/* but not too high; it might polymorph */ 280. 	    } else if (!edog->mhpmax_penalty) { 281. 		/* starving pets are limited in healing */ 282. 		int newmhpmax = mtmp->mhpmax / 3; 283. 		mtmp->mconf = 1; 284. 		edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax; 285. 		mtmp->mhpmax = newmhpmax; 286. 		if (mtmp->mhp > mtmp->mhpmax) 287. 		    mtmp->mhp = mtmp->mhpmax; 288. 		if (mtmp->mhp < 1) goto dog_died; 289. 		if (cansee(mtmp->mx, mtmp->my)) 290. 		    pline("%s is confused from hunger.", Monnam(mtmp)); 291. 		else if (couldsee(mtmp->mx, mtmp->my)) 292. 		    beg(mtmp); 293. 		else 294. 		    You_feel("worried about %s.", y_monnam(mtmp)); 295. 		stop_occupation; 296. 	    } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { 297.  dog_died: 298. 		if (mtmp->mleashed  299.  #ifdef STEED  300.  		    && mtmp != u.usteed  301.  #endif  302.  		    ) 303. 		    Your("leash goes slack."); 304. 		else if (cansee(mtmp->mx, mtmp->my)) 305. 		    pline("%s starves.", Monnam(mtmp)); 306. 		else 307. 		    You_feel("%s for a moment.",  308.  			Hallucination ? "bummed" : "sad"); 309. 		mondied(mtmp); 310. 		return(TRUE); 311. 	    }  312.  	}  313.  	return(FALSE); 314. }  315.   316.  /* do something with object (drop, pick up, eat) at current position 317.  * returns 1 if object eaten (since that counts as dog's move), 2 if died 318.  */  319.  STATIC_OVL int 320. dog_invent(mtmp, edog, udist) 321. register struct monst *mtmp; 322. register struct edog *edog; 323. int udist; 324. {  325.  	/* KMH, balance patch -- quantity picked up should depend on dog's level */ 326. 	int dogquan = 10 * mtmp->m_lev; 327. 	register int omx, omy; 328. 	struct obj *obj; 329. /*  330.  	struct obj *floor_obj; 331. 	int temp_quan; 332.  */  333.  	if (mtmp->msleeping || !mtmp->mcanmove) return(0); 334.  335.  	omx = mtmp->mx; 336. 	omy = mtmp->my; 337.  338.  	/* if we are carrying sth then we drop it (perhaps near @) */ 339. 	/* Note: if apport == 1 then our behaviour is independent of udist */ 340. 	/* Use udist+1 so steed won't cause divide by zero */ 341. #ifndef GOLDOBJ 342. 	if(DROPPABLES(mtmp) || mtmp->mgold) { 343. #else 344. 	if(DROPPABLES(mtmp)) { 345. #endif 346. 	    if (!rn2(udist+1) || !rn2(edog->apport)) 347. 		if(rn2(10) < edog->apport){ 348. 		    relobj(mtmp, (int)mtmp->minvis, TRUE); 349. 		    if(edog->apport > 1) edog->apport--; 350. 		    edog->dropdist = udist;		/* hpscdi!jon */ 351. 		    edog->droptime = moves; 352. 		}  353.  	} else { 354. 	    if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass)  355.  #ifdef MAIL  356.  			&& obj->otyp != SCR_MAIL  357.  #endif  358.  									){ 359. 		int edible = dogfood(mtmp, obj); 360.  361.  		if ((edible <= CADAVER || 362. 			/* starving pet is more aggressive about eating */ 363. 			(edog->mhpmax_penalty && edible == ACCFOOD)) &&  364.  		    could_reach_item(mtmp, obj->ox, obj->oy)) 365. 		    return dog_eat(mtmp, obj, omx, omy, FALSE); 366.  367.  		/* [Tom] demonic & undead pets don't mind cursed items */ 368. 		if(can_carry(mtmp, obj) &&  369.  		  could_reach_item(mtmp, obj->ox, obj->oy) &&  370.  		  (!obj->cursed || is_demon(mtmp->data) || is_undead(mtmp->data)) &&  371.  		  (!obj->blessed || (!is_demon(mtmp->data) && !is_undead(mtmp->data)))) { 372. 		    if(rn2(20) < edog->apport+3) { 373. 			if (rn2(udist) || !rn2(edog->apport)) { 374. 			    if ((!nohands(mtmp->data)) ||  375.  						/* KMH, balance patch -- 10*level */  376.  						(obj->quan <= dogquan)) 377. 			    {  378.  			    if (cansee(omx, omy) && flags.verbose) 379. 				pline("%s picks up %s.", Monnam(mtmp),  380.  				    distant_name(obj, doname)); 381. 			    obj_extract_self(obj); 382. 			    newsym(omx,omy); 383. 			    (void) mpickobj(mtmp,obj); 384. 			    }                             385.  			    else /* picking up a few objects from a pile... */ 386.  				/* KMH -- fix picking up zero quantity */ 387. 			    if (dogquan > 0) { 388. 				if (obj->oclass == COIN_CLASS) { 389. 				    /* KMH, balance patch -- 10*level */ 390. #ifndef GOLDOBJ 391. 				    obj->quan -= dogquan; 392. 				    if (cansee(omx, omy) && flags.verbose) 393. 					pline("%s picks up %d gold pieces.",  394.  							Monnam(mtmp),  395.  							dogquan); 396. 				    mtmp->mgold += dogquan; 397. #else 398. 						if (obj->quan != dogquan) 399. 							obj = splitobj(obj, dogquan); 400. 				    if (cansee(omx, omy) && flags.verbose) 401. 							pline("%s picks up %s.",  402.  							Monnam(mtmp),  403.  							doname(obj)); 404. 							obj_extract_self(obj); 405. 				    	newsym(omx,omy); 406. 							(void) mpickobj(mtmp,obj); 407. #endif 408. 				} else { 409. /*  410.                                  struct obj *floor_obj; 411.                                 int temp_quan; 412.  413.                                  obj->quan -= dogquan; 414. 				temp_quan = obj->quan; 415. 				floor_obj = level.objects[omx][omy]; 416. 				mpickobj(mtmp,obj); 417. 				obj->quan = dogquan; 418. 				if (cansee(omx, omy) && flags.verbose) 419. 				pline("%s picks up %s.", Monnam(mtmp),  420.  				    distant_name(obj, doname)); 421. 				floor_obj->quan = temp_quan;*/ 422. 				}  423.  			    }  424.  			    if (attacktype(mtmp->data, AT_WEAP) &&  425.  					mtmp->weapon_check == NEED_WEAPON) { 426. 				mtmp->weapon_check = NEED_HTH_WEAPON; 427. 				(void) mon_wield_item(mtmp); 428. 			    }  429.  			    m_dowear(mtmp, FALSE); 430. 			}  431.  		    }  432.  		}  433.  	    }  434.  	}  435.  	return 0; 436. }  437.   438.  /* set dog's goal -- gtyp, gx, gy  439. * returns -1/0/1 (dog's desire to approach player) or -2 (abort move) 440.  */  441.  STATIC_OVL int 442. dog_goal(mtmp, edog, after, udist, whappr) 443. register struct monst *mtmp; 444. struct edog *edog; 445. int after, udist, whappr; 446. {  447.  	register int omx, omy; 448. 	boolean in_masters_sight, dog_has_minvent; 449. 	register struct obj *obj; 450. 	xchar otyp; 451. 	int appr; 452.  453.  #ifdef STEED 454. 	/* Steeds don't move on their own will */ 455. 	if (mtmp == u.usteed) 456. 		return (-2); 457. #endif 458.  459.  	omx = mtmp->mx; 460. 	omy = mtmp->my; 461.  462.  	in_masters_sight = couldsee(omx, omy); 463. 	dog_has_minvent = (DROPPABLES(mtmp) != 0); 464.  465.  	if (!edog || mtmp->mleashed) {	/* he's not going anywhere... */ 466.  	    gtyp = APPORT; 467. 	    gx = u.ux; 468. 	    gy = u.uy; 469. 	} else { 470. #define DDIST(x,y) (dist2(x,y,omx,omy)) 471. #define SQSRCHRADIUS 5 472. 	    int min_x, max_x, min_y, max_y; 473. 	    register int nx, ny; 474.  475.  	    gtyp = UNDEF;	/* no goal as yet */ 476. 	    gx = gy = 0;	/* suppress 'used before set' message */ 477.  478.  	    if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; 479. 	    if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; 480. 	    if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; 481. 	    if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; 482.  483.  	    /* nearby food is the first choice, then other objects */ 484. 	    for (obj = fobj; obj; obj = obj->nobj) { 485. 		nx = obj->ox; 486. 		ny = obj->oy; 487. 		if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { 488. 		    otyp = dogfood(mtmp, obj); 489. 		    /* skip inferior goals */ 490. 		    if (otyp > gtyp || otyp == UNDEF) 491. 			continue; 492. 		    /* avoid cursed items unless starving */ 493. 		    if (cursed_object_at(mtmp, nx, ny) &&  494.  			    !(edog->mhpmax_penalty && otyp < MANFOOD)) 495. 			continue; 496. 		    /* skip completely unreacheable goals */ 497. 		    if (!could_reach_item(mtmp, nx, ny) ||  498.  		        !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny)) 499. 			continue; 500. 		    if (otyp < MANFOOD) { 501. 			if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) { 502. 			    gx = nx; 503. 			    gy = ny; 504. 			    gtyp = otyp; 505. 			}  506.  		    } else if(gtyp == UNDEF && in_masters_sight &&  507.  			      !dog_has_minvent &&  508.  			      (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) &&  509.  			      (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) &&  510.  			      edog->apport > rn2(8) &&  511.  			      can_carry(mtmp,obj)) { 512. 			gx = nx; 513. 			gy = ny; 514. 			gtyp = APPORT; 515. 		    }  516.  		}  517.  	    }  518.  	}  519.   520.  	/* follow player if appropriate */ 521. 	if (gtyp == UNDEF ||  522.  	    (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) { 523. 		gx = u.ux; 524. 		gy = u.uy; 525. 		if (after && udist <= 4 && gx == u.ux && gy == u.uy) 526. 			return(-2); 527. 		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; 528.  		if (udist > 1) { 529. 			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||  530.  			   whappr ||  531.  			   (dog_has_minvent && rn2(edog->apport))) 532. 				appr = 1; 533. 		}  534.  		/* if you have dog food it'll follow you more closely */ 535. 		if (appr == 0) { 536. 			obj = invent; 537. 			while (obj) { 538. 				if(dogfood(mtmp, obj) == DOGFOOD) { 539. 					appr = 1; 540. 					break; 541. 				}  542.  				obj = obj->nobj; 543. 			}  544.  		}  545.  	} else 546. 	    appr = 1;	/* gtyp != UNDEF */ 547. 	if(mtmp->mconf) 548. 	    appr = 0; 549.  550.  #define FARAWAY (COLNO + 2)		/* position outside screen */ 551. 	if (gx == u.ux && gy == u.uy && !in_masters_sight) { 552. 	    register coord *cp; 553.  554.  	    cp = gettrack(omx,omy); 555. 	    if (cp) { 556. 		gx = cp->x; 557. 		gy = cp->y; 558. 		if(edog) edog->ogoal.x = 0; 559. 	    } else { 560. 		/* assume master hasn't moved far, and reuse previous goal */ 561. 		if(edog && edog->ogoal.x &&  562.  		   ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { 563. 		    gx = edog->ogoal.x;  564. gy = edog->ogoal.y; 565. edog->ogoal.x = 0; 566. 		} else { 567. 		    int fardist = FARAWAY * FARAWAY; 568. 		    gx = gy = FARAWAY; /* random */ 569. 		    do_clear_area(omx, omy, 9, wantdoor,  570.  				  (genericptr_t)&fardist); 571.  572.  		    /* here gx == FARAWAY e.g. when dog is in a vault */ 573. 		    if (gx == FARAWAY || (gx == omx && gy == omy)) { 574. 			gx = u.ux; 575. 			gy = u.uy; 576. 		    } else if(edog) { 577. 			edog->ogoal.x = gx; 578. 			edog->ogoal.y = gy; 579. 		    }  580.  		}  581.  	    }  582.  	} else if(edog) { 583. 	    edog->ogoal.x = 0; 584. 	}  585.  	return appr; 586. }  587.   588.  #ifdef DEBUG 589. #define CHECK_ALLOW(flag,str)	if ((allowflags & (flag)) == (flag)) { \ 590. 				    allowflags ^= (flag); \ 591. 				    if (bp != buf) { *bp++=','; *bp++=' '; } \ 592. 				    Strcpy(bp, str); \ 593. 				    bp += strlen(bp); \ 594. 				} else 595.  596.  STATIC_OVL char * 597. allow_set(allowflags) 598. long allowflags; 599. {  600.      static char buf[500]; 601.     char *bp = buf; 602.     if (allowflags == 0) 603. 	return "(none)"; 604.     *bp = '\0'; 605.     CHECK_ALLOW(ALLOW_TRAPS, "can enter traps"); 606.     CHECK_ALLOW(ALLOW_U, "can attack you"); 607.     CHECK_ALLOW(ALLOW_M, "can attack other monsters"); 608.     CHECK_ALLOW(ALLOW_TM, "can attack tame monsters"); 609.     CHECK_ALLOW(NOTONL, "avoids direct line to player"); 610.     CHECK_ALLOW(OPENDOOR, "opens closed doors"); 611.     CHECK_ALLOW(UNLOCKDOOR, "unlocks locked doors"); 612.     CHECK_ALLOW(BUSTDOOR, "breaks any doors"); 613.     CHECK_ALLOW(ALLOW_ROCK, "pushes rocks"); 614.     CHECK_ALLOW(ALLOW_WALL, "walks thru walls"); 615.     CHECK_ALLOW(ALLOW_DIG, "digs"); 616.     CHECK_ALLOW(ALLOW_SANCT, "enters temples"); 617.     CHECK_ALLOW(ALLOW_SSM, "ignores scare monster"); 618.     CHECK_ALLOW(NOGARLIC, "hates garlic"); 619.     if (allowflags) { 620. 	if (bp != buf) { *bp++=','; *bp++=' '; } 621. 	sprintf(bp, "0x%lX", allowflags); 622.     }  623.      return buf; 624. }  625.   626.  #undef CHECK_ALLOW 627. #endif 628.  629.  boolean 630. betrayed(mtmp) 631. register struct monst *mtmp; 632. {  633.      boolean has_edog = !mtmp->isminion; 634.     struct edog *edog = EDOG(mtmp); 635.     int udist = distu(mtmp->mx, mtmp->my); 636.  637.      if (udist < 4 && has_edog && !mtmp->isspell && !rn2(3)  638.  		    && can_betray(mtmp->data)  639.  		    && !mindless(mtmp->data)  640.  		    && mtmp->mhp >= u.uhp	/* Pet is buff enough */  641.  		    && rn2(22) > mtmp->mtame	/* Roll against tameness */  642.  		    && rn2(edog->abuse + 2)) { 643. 	/* Treason */ 644. 	if (canseemon(mtmp)) 645. 	    pline("%s turns on you!", Monnam(mtmp)); 646. 	else 647. 	    pline("You feel uneasy about %s.", y_monnam(mtmp)); 648. 	mtmp->mpeaceful = 0; 649. 	mtmp->mtame = 0; 650. 	mtmp->mtraitor = TRUE; 651.  652.  	/* Do we need to call newsym here? */ 653.  	newsym(mtmp->mx, mtmp->my); 654. 	return TRUE; 655.     }  656.      return FALSE; 657. }  658.   659.  /* return 0 (no move), 1 (move) or 2 (dead) */ 660. int 661. dog_move(mtmp, after) 662. register struct monst *mtmp; 663. register int after;	/* this is extra fast monster movement */ 664. {  665.  	int omx, omy;		/* original mtmp position */ 666. 	int appr, whappr, udist; 667. 	int i, j, k;  668. register struct edog *edog = EDOG(mtmp); 669. 	struct obj *obj = (struct obj *) 0; 670. 	xchar otyp; 671. 	boolean has_edog, cursemsg[9], is_spell, do_eat = FALSE; 672. 	xchar nix, niy;		/* position mtmp is (considering) moving to */ 673. 	register int nx, ny;	/* temporary coordinates */ 674. 	xchar cnt, uncursedcnt, chcnt; 675. 	int chi = -1, nidist, ndist; 676. 	coord poss[9]; 677. 	long info[9], allowflags; 678. #define GDIST(x,y) (dist2(x,y,gx,gy)) 679.  680.  	/*  681.  	 * Tame Angels have isminion set and an ispriest structure instead of  682. * an edog structure. Fortunately, guardian Angels need not worry 683. 	 * about mundane things like eating and fetching objects, and can 684. 	 * spend all their energy defending the player. (They are the only 685.  	 * monsters with other structures that can be tame.) 686. 	 */  687.  	has_edog = !mtmp->isminion; 688.  689.  	/*  690.  	 * Similar to Angels and Guardians are spell beings - temporary 691. 	 * magical manifestations of the spellcaster's mind. 692. 	 * They don't eat/pickup objects - only fight. 693. 	 * But,  they aren't dismissed by conflict. 694. 	 */  695.  	is_spell = mtmp->isspell; 696.  697.  	omx = mtmp->mx; 698. 	omy = mtmp->my; 699. 	if (has_edog && !is_spell && dog_hunger(mtmp, edog)) return(2);      /* starved */ 700.  701.  	udist = distu(omx,omy); 702. #ifdef STEED 703. 	/* Let steeds eat and maybe throw rider during Conflict */ 704. 	if (mtmp == u.usteed) { 705. 	    if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { 706. 		dismount_steed(DISMOUNT_THROWN); 707. 		return (1); 708. 	    }  709.  	    udist = 1; 710. 	} else 711. #endif 712. 	/* maybe we tamed him while being swallowed --jgm */ 713. 	if (!udist) return(0); 714.  715.  	/* Intelligent pets may rebel (apart from minions, spell beings) */ 716. 	if (!rn2(850) && betrayed(mtmp)) return 1; 717.  718.  	nix = omx;	/* set before newdogpos */ 719. 	niy = omy; 720. 	cursemsg[0] = FALSE;	/* lint suppression */ 721. 	info[0] = 0;		/* ditto */ 722.  723.  	if (has_edog && !is_spell) { 724. 	    j = dog_invent(mtmp, edog, udist); 725. 	    if (j == 2) return 2;		/* died */ 726. 	    else if (j == 1) goto newdogpos;	/* eating something */ 727.  728.  	    whappr = (monstermoves - edog->whistletime < 5); 729. 	} else 730. 	    whappr = 0; 731.  732.  	appr = dog_goal(mtmp, (has_edog && !is_spell) ? edog : (struct edog *)0,  733.  							after, udist, whappr); 734. #ifdef DEBUG 735. 	{  736.  	    char *goal; 737. 	    switch(gtyp) 738. 	    {  739.  		case DOGFOOD:	goal = "dogfood"; break; 740. 		case CADAVER:	goal = "cadaver"; break; 741. 		case ACCFOOD:	goal = "accfood"; break; 742. 		case MANFOOD:	goal = "manfood"; break; 743. 		case APPORT:	goal = "apport"; break; 744. 		case POISON:	goal = "poison"; break; 745. 		case UNDEF:	goal = "undef"; break; 746. 		case TABU:	goal = "tabu"; break; 747. 		default:	goal = "???"; break; 748. 	    }  749.  	    debugpline("G(%s): %s @ (%d,%d), appr = %d",  750.  	      mon_nam(mtmp), goal, gx, gy, appr); 751. 	}  752.  #endif 753. 	if (appr == -2) return(0); 754.  755.  	allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; 756. 	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); 757. 	if (passes_bars(mtmp->data) && !In_sokoban(&u.uz)) 758. 	    allowflags |= ALLOW_BARS; 759. 	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; 760. 	if (Conflict && !resist(mtmp, RING_CLASS, 0, 0) && In_endgame(&u.uz)) { 761. 	    allowflags |= ALLOW_U; 762. 	    if (!has_edog && !is_spell) { 763. 		coord mm; 764. 		/* Guardian angel refuses to be conflicted; rather, 765. 		 * it disappears, angrily, and sends in some nasties 766. 		 */  767.  		if (canspotmon(mtmp)) { 768. 		    pline("%s rebukes you, saying:", Monnam(mtmp)); 769. 		    verbalize("Since you desire conflict, have some more!"); 770. 		}  771.  		mongone(mtmp); 772. 		i = rnd(4); 773. 		while(i--) { 774. 		    mm.x = u.ux; 775. 		    mm.y = u.uy; 776. 		    if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) 777. 			(void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,  778.  					 mm.x, mm.y, FALSE); 779. 		}  780.  		return(2); 781.  782.  	    }  783.  	}  784.   785.  	/* ALI -- Mindless pets shouldn't attack monsters when 786. 	 * scared; they have no sense of allegiance to the hero, 787. 	 * only self-preservation. This prevents weak pets blocking 788. 	 * your exit from a shop by constantly missing shopkeeper. 789. 	 */  790.  	if (mindless(mtmp->data) && mtmp->mflee) 791. 	    allowflags &= ~ALLOW_M; 792.  793.  	if (!Conflict && !mtmp->mconf &&  794.  	    mtmp == u.ustuck && !sticks(youmonst.data)) { 795. 	    unstuck(mtmp);	/* swallowed case handled above */ 796. 	    You("get released!"); 797. 	}  798.  	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { 799. 		allowflags |= OPENDOOR; 800. 		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; 801. 	}  802.  	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; 803. 	if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; 804. 	cnt = mfndpos(mtmp, poss, info, allowflags); 805. #ifdef DEBUG 806. 	debugpline("%d positions found with allow: %s", cnt,  807.  	  allow_set(allowflags)); 808. 	for (i = 0; i < cnt; i++) { 809. 	    debugpline("[%d] %s @ (%d, %d)", i,  810.  	      allow_set(info[i]), poss[i].x, poss[i].y); 811. 	}  812.  #endif 813.  814.  	/* Normally dogs don't step on cursed items, but if they have no  815. * other choice they will. This requires checking ahead of time 816. 	 * to see how many uncursed item squares are around. 817. 	 */  818.   819.  	uncursedcnt = 0; 820. 	for (i = 0; i < cnt; i++) { 821. 		nx = poss[i].x; ny = poss[i].y;  822. if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue; 823. 		if (cursed_object_at(mtmp, nx, ny)) continue; 824. 		uncursedcnt++; 825. 	}  826.   827.  	chcnt = 0; 828. 	chi = -1; 829. 	nidist = GDIST(nix,niy); 830.  831.  	for (i = 0; i < cnt; i++) { 832. 		nx = poss[i].x;  833. ny = poss[i].y; 834. cursemsg[i] = FALSE; 835.  836.  		/* if leashed, we drag him along. */ 837.  		if (mtmp->mleashed && distu(nx, ny) > 4) continue; 838.  839.  		/* if a guardian, try to stay close by choice */ 840. 		if ((!has_edog || is_spell) &&  841.  		    (j = distu(nx, ny)) > 16 && j >= udist) continue; 842.  843.  		if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { 844. 		    int mstatus; 845. 		    register struct monst *mtmp2 = m_at(nx,ny); 846. 		    aligntyp align1, align2; /* For priests, minions etc. */ 847.  848.  		    if (mtmp->isminion) align1 = EMIN(mtmp)->min_align; 849. 		    else if (is_unicorn(mtmp->data)) 850. 			align1 = sgn(mtmp->data->maligntyp); 851. 		    else if (mtmp->ispriest) align1 = EPRI(mtmp)->shralign; 852. 		    else align1 = A_NONE; 853. 		    if (mtmp2->isminion) align2 = EMIN(mtmp2)->min_align; 854. 		    else if (is_unicorn(mtmp2->data)) 855. 			align2 = sgn(mtmp2->data->maligntyp); 856. 		    else if (mtmp2->ispriest) align2 = EPRI(mtmp2)->shralign; 857. 		    else align2 = A_NONE; 858.  859.  		    /* Mindless monsters and spelled monsters have no fear of  860. * attacking higher level monsters 861. 		     */  862.  		    if (((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 && !is_spell && 863. 			    !mindless(mtmp->data)) ||  864.  			(mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && 865. 			 mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee 866. 			 && (perceives(mtmp->data) || !mtmp2->minvis)) ||  867.  			(mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) ||  868.  			(mtmp2->data==&mons[PM_GAS_SPORE] && rn2(16)) ||  869.  			(!attacktype(mtmp->data, AT_EXPL) && 870. 			 max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) ||  871.  			/* Minions/Angels don't attack  872.  			 * coaligned minions/priests/angels/unicorns.  873.  			 */  874.  			(align1 == align2 && align1 != A_NONE) ||  875.  			((mtmp->mhp*4 < mtmp->mhpmax  876.  			  || mtmp2->data->msound == MS_GUARDIAN  877.  			  || mtmp2->data->msound == MS_LEADER) && 878. 			 mtmp2->mpeaceful && !Conflict) ||  879.  			   (touch_petrifies(mtmp2->data) && 880. 				!resists_ston(mtmp))) 881. 			continue; 882.  883.  		    if (after) return(0); /* hit only once each move */ 884.  885.  		    notonhead = 0; 886. 		    mstatus = mattackm(mtmp, mtmp2); 887.  888.  		    /* aggressor (pet) died */ 889. 		    if (mstatus & MM_AGR_DIED) return 2; 890.  891.  		    if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) &&  892.  			    rn2(4) && mtmp2->mlstmv != monstermoves &&  893.  			    !onscary(mtmp->mx, mtmp->my, mtmp2) &&  894.  			    /* monnear check needed: long worms hit on tail */  895.  			    monnear(mtmp2, mtmp->mx, mtmp->my)) { 896. 			mstatus = mattackm(mtmp2, mtmp);  /* return attack */ 897. 			if (mstatus & MM_DEF_DIED) return 2; 898. 		    }  899.   900.  		    return 0; 901. 		}  902.   903.  		{   /* Dog avoids harmful traps, but perhaps it has to pass one 904. 		     * in order to follow player. (Non-harmful traps do not 905.  		     * have ALLOW_TRAPS in info[].)  The dog only avoids the 906. 		     * trap if you've seen it, unlike enemies who avoid traps 907. 		     * if they've seen some trap of that type sometime in the 908. 		     * past. (Neither behavior is really realistic.) 909. 		     */  910.  		    struct trap *trap; 911.  912.  		    if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) { 913. 			if (mtmp->mleashed) { 914. 			    if (flags.soundok) whimper(mtmp); 915. 			} else 916. 			    /* 1/40 chance of stepping on it anyway, in case 917. 			     * it has to pass one to follow the player...  918. */ 919.  			    if (trap->tseen && rn2(40)) continue; 920. 		    }  921.  		}  922.   923.  		/* dog eschews cursed objects, but likes dog food */ 924. 		/* [Tom] except demons & undead, who don't care */ 925. 		/* (minion isn't interested; `cursemsg' stays FALSE) */ 926. 		if (has_edog && !is_spell) { 927. 		for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { 928. 		    if ((obj->cursed) && has_edog && !is_demon(mtmp->data)  929.  		    && !is_undead(mtmp->data)) cursemsg[i] = TRUE; 930. 		    if (obj->blessed && has_edog && (is_demon(mtmp->data) 931. 		    || is_undead(mtmp->data))) cursemsg[i] = TRUE; 932. 		    else if ((otyp = dogfood(mtmp, obj)) < MANFOOD &&  933.  			     (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) { 934. 			/* Note: our dog likes the food so much that he  935. * might eat it even when it conceals a cursed object */ 936. 			nix = nx; 937. 			niy = ny; 938. 			chi = i;  939. do_eat = TRUE; 940. 			cursemsg[i] = FALSE;	/* not reluctant */ 941. 			goto newdogpos; 942. 		    }  943.  		}  944.  		}  945.  		/* didn't find something to eat; if we saw a cursed item and 946. 		   aren't being forced to walk on it, usually keep looking */ 947. 		if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 &&  948.  		    rn2(13 * uncursedcnt)) continue; 949.  950.  		/* lessen the chance of backtracking to previous position(s) */ 951. 		k = (has_edog && !is_spell) ? uncursedcnt : cnt; 952. 		for (j = 0; j < MTSZ && j < k - 1; j++) 953. 			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)  954. if (rn2(MTSZ * (k - j))) goto nxti; 955.  956.  		j = ((ndist = GDIST(nx,ny)) - nidist) * appr; 957. 		if ((j == 0 && !rn2(++chcnt)) || j < 0 ||  958.  			(j > 0 && !whappr && 959. 				((omx == nix && omy == niy && !rn2(3))  960.  					|| !rn2(12)) 961. 			)) {  962.  			nix = nx; 963. 			niy = ny; 964. 			nidist = ndist; 965. 			if(j < 0) chcnt = 0; 966. 			chi = i;  967. } 968.  	nxti:	; 969. 	}  970.  newdogpos: 971. 	if (nix != omx || niy != omy) { 972. 		struct obj *mw_tmp; 973.  974.  		if (info[chi] & ALLOW_U) { 975. 			if (mtmp->mleashed) { /* play it safe */ 976. 				pline("%s breaks loose of %s leash!",  977.  				      Monnam(mtmp), mhis(mtmp)); 978. 				m_unleash(mtmp, FALSE); 979. 			}  980.  			(void) mattacku(mtmp); 981. 			return(0); 982. 		}  983.  		if (!m_in_out_region(mtmp, nix, niy)) 984. 		    return 1; 985. 		if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || 986. 		     closed_door(nix, niy)) &&  987.  		    mtmp->weapon_check != NO_WEAPON_WANTED &&  988.  		    tunnels(mtmp->data) && needspick(mtmp->data)) { 989. 		    if (closed_door(nix, niy)) { 990. 			if (!(mw_tmp = MON_WEP(mtmp)) ||  991.  			    !is_pick(mw_tmp) || !is_axe(mw_tmp)) 992. 			    mtmp->weapon_check = NEED_PICK_OR_AXE; 993. 		    } else if (IS_TREE(levl[nix][niy].typ)) { 994. 			if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) 995. 			    mtmp->weapon_check = NEED_AXE; 996. 		    } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { 997. 			mtmp->weapon_check = NEED_PICK_AXE; 998. 		    }  999.  		    if (mtmp->weapon_check >= NEED_PICK_AXE &&  1000. 			mon_wield_item(mtmp)) 1001. 			return 0; 1002. 		} 1003. 		/* insert a worm_move if worms ever begin to eat things */ 1004. 		remove_monster(omx, omy); 1005. 		place_monster(mtmp, nix, niy); 1006. 		if (has_edog && !is_spell && cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy))) 1007. 			pline("%s moves only reluctantly.", Monnam(mtmp)); 1008. 		for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; 1009. 		mtmp->mtrack[0].x = omx; 1010. 		mtmp->mtrack[0].y = omy; 1011. 		/* We have to know if the pet's gonna do a combined eat and 1012. 		 * move before moving it, but it can't eat until after being 1013. 		 * moved. Thus the do_eat flag. 1014. 		 */ 1015. 		if (do_eat) { 1016. 		   if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; 1017. 		} 1018. 	} else if (mtmp->mleashed && distu(omx, omy) > 4) { 1019. 		/* an incredible kludge, but the only way to keep pooch near 1020. 		 * after it spends time eating or in a trap, etc. 1021. 		 */ 1022. 		coord cc; 1023. 1024. 		nx = sgn(omx - u.ux); 1025. 		ny = sgn(omy - u.uy); 1026. 		cc.x = u.ux + nx; 1027. 		cc.y = u.uy + ny; 1028. 		if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1029. 1030. 		i  = xytod(nx, ny); 1031. 		for (j = (i + 7)%8; j < (i + 1)%8; j++) { 1032. 			dtoxy(&cc, j); 1033. 			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1034. 		} 1035. 		for (j = (i + 6)%8; j < (i + 2)%8; j++) { 1036. 			dtoxy(&cc, j); 1037. 			if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1038. 		} 1039. 		cc.x = mtmp->mx; 1040. 		cc.y = mtmp->my; 1041. dognext: 1042. 		if (!m_in_out_region(mtmp, nix, niy)) 1043. 		 return 1; 1044. 		remove_monster(mtmp->mx, mtmp->my); 1045. 		place_monster(mtmp, cc.x, cc.y); 1046. 		newsym(cc.x,cc.y); 1047. 		set_apparxy(mtmp); 1048. 	} 1049. 	return(1); 1050. } 1051.  1052. /* check if a monster could pick up objects from a location */ 1053. STATIC_OVL boolean 1054. could_reach_item(mon, nx, ny) 1055. struct monst *mon; 1056. xchar nx, ny; 1057. { 1058.     if ((!is_pool(nx,ny) || is_swimmer(mon->data)) &&  1059. 	(!is_lava(nx,ny) || likes_lava(mon->data)) &&  1060. 	(!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data))) 1061.    	return TRUE; 1062.    return FALSE; 1063. } 1064.  1065. /* Hack to prevent a dog from being endlessly stuck near an object that 1066. * it can't reach, such as caught in a teleport scroll niche. It recursively 1067. * checks to see if the squares in between are good. The checking could be a 1068. * little smarter; a full check would probably be useful in m_move too. 1069. * Since the maximum food distance is 5, this should never be more than 5 calls 1070. * deep. 1071. */  1072. STATIC_OVL boolean 1073. can_reach_location(mon, mx, my, fx, fy) 1074. struct monst *mon; 1075. xchar mx, my, fx, fy; 1076. { 1077.     int i, j;  1078. int dist; 1079. 1080.     if (mx == fx && my == fy) return TRUE; 1081.    if (!isok(mx, my)) return FALSE; /* should not happen */ 1082.     1083.     dist = dist2(mx, my, fx, fy); 1084.    for(i=mx-1; i<=mx+1; i++) { 1085. 	for(j=my-1; j<=my+1; j++) { 1086. 	   if (!isok(i, j)) 1087. 		continue; 1088. 	   if (dist2(i, j, fx, fy) >= dist) 1089. 		continue; 1090. 	   if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) &&  1091. 				    (!may_dig(i,j) || !tunnels(mon->data))) 1092. 		continue; 1093. 	   if (IS_DOOR(levl[i][j].typ) &&  1094. 				(levl[i][j].doormask & (D_CLOSED | D_LOCKED))) 1095. 		continue; 1096. 	   if (!could_reach_item(mon, i, j)) 1097. 		continue; 1098. 	   if (can_reach_location(mon, i, j, fx, fy)) 1099. 		return TRUE; 1100. 	} 1101.     }  1102.     return FALSE; 1103. } 1104.  1105. #endif /* OVL0 */ 1106. #ifdef OVLB 1107. 1108. /*ARGSUSED*/	/* do_clear_area client */ 1109. STATIC_PTR void 1110. wantdoor(x, y, distance) 1111. int x, y; 1112. genericptr_t distance; 1113. { 1114.     int ndist; 1115. 1116.     if (*(int*)distance > (ndist = distu(x, y))) { 1117. 	gx = x; 1118. gy = y; 1119. *(int*)distance = ndist; 1120.    }  1121. }  1122.  1123. #endif /* OVLB */ 1124. 1125. /*dogmove.c*/