1 /*	SCCS Id: @(#)monmove.c	3.3	2000/07/24	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 #include "mfndpos.h"
7 #include "artifact.h"
8 
9 extern boolean notonhead;
10 
11 #ifdef OVL0
12 
13 STATIC_DCL int FDECL(disturb,(struct monst *));
14 STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *));
15 STATIC_DCL int FDECL(m_arrival, (struct monst *));
16 STATIC_DCL void FDECL(watch_on_duty,(struct monst *));
17 
18 #endif /* OVL0 */
19 #ifdef OVLB
20 
21 boolean /* TRUE : mtmp died */
mb_trapped(mtmp)22 mb_trapped(mtmp)
23 register struct monst *mtmp;
24 {
25 	if (flags.verbose) {
26 	    if (cansee(mtmp->mx, mtmp->my))
27 		pline("KABOOM!!  You see a door explode.");
28 	    else if (flags.soundok)
29 		You_hear("a distant explosion.");
30 	}
31 	wake_nearto(mtmp->mx, mtmp->my, 7*7);
32 	mtmp->mstun = 1;
33 	mtmp->mhp -= rnd(15);
34 	if(mtmp->mhp <= 0) {
35 		mondied(mtmp);
36 		if (mtmp->mhp > 0) /* lifesaved */
37 			return(FALSE);
38 		else
39 			return(TRUE);
40 	}
41 	return(FALSE);
42 }
43 
44 #endif /* OVLB */
45 #ifdef OVL0
46 
47 STATIC_OVL void
watch_on_duty(mtmp)48 watch_on_duty(mtmp)
49 register struct monst *mtmp;
50 {
51 	register s_level *slev = Is_special(&u.uz);
52 	int	x, y;
53 
54 	if(slev && slev->flags.town && mtmp->mpeaceful &&
55 	   mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) {
56 
57 	    if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) &&
58 	       (levl[x][y].doormask & D_LOCKED)) {
59 
60 		if(couldsee(mtmp->mx, mtmp->my)) {
61 
62 		  pline("%s yells:", Amonnam(mtmp));
63 		  if(levl[x][y].looted & D_WARNED) {
64 			verbalize("Halt, thief!  You're under arrest!");
65 			(void) angry_guards(!(flags.soundok));
66 		  } else {
67 			verbalize("Hey, stop picking that lock!");
68 			levl[x][y].looted |=  D_WARNED;
69 		  }
70 		  stop_occupation();
71 		}
72 	    }
73 	}
74 }
75 
76 #endif /* OVL0 */
77 #ifdef OVL1
78 
79 int
dochugw(mtmp)80 dochugw(mtmp)
81 	register struct monst *mtmp;
82 {
83 	register int x = mtmp->mx, y = mtmp->my;
84 	boolean already_saw_mon = !occupation ? 0 : canspotmon(mtmp);
85 	int rd = dochug(mtmp);
86 #if 0
87 	/* part of the original warning code which was replaced in 3.3.1 */
88 	int dd;
89 
90 	if(Warning && !rd && !mtmp->mpeaceful &&
91 			(dd = distu(mtmp->mx,mtmp->my)) < distu(x,y) &&
92 			dd < 100 && !canseemon(mtmp)) {
93 	    /* Note: this assumes we only want to warn against the monster to
94 	     * which the weapon does extra damage, as there is no "monster
95 	     * which the weapon warns against" field.
96 	     */
97 	    if (spec_ability(uwep, SPFX_WARN) && spec_dbon(uwep, mtmp, 1))
98 		warnlevel = 100;
99 	    else if ((int) (mtmp->m_lev / 4) > warnlevel)
100 		warnlevel = (mtmp->m_lev / 4);
101 	}
102 #endif /* 0 */
103 
104 	/* a similar check is in monster_nearby() in hack.c */
105 	/* check whether hero notices monster and stops current activity */
106 	if (occupation && !rd && !Confusion &&
107 	    (!mtmp->mpeaceful || Hallucination) &&
108 	    /* it's close enough to be a threat */
109 	    distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1) &&
110 	    /* and either couldn't see it before, or it was too far away */
111 	    (!already_saw_mon || !couldsee(x,y) ||
112 		distu(x,y) > (BOLT_LIM+1)*(BOLT_LIM+1)) &&
113 	    /* can see it now, or sense it and would normally see it */
114 	    (canseemon(mtmp) ||
115 		(sensemon(mtmp) && couldsee(mtmp->mx,mtmp->my))) &&
116 	    !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp))
117 		stop_occupation();
118 
119 	return(rd);
120 }
121 
122 #endif /* OVL1 */
123 #ifdef OVL2
124 
125 boolean
onscary(x,y,mtmp)126 onscary(x, y, mtmp)
127 int x, y;
128 struct monst *mtmp;
129 {
130 	if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee ||
131 			mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN ||
132 			is_lminion(mtmp->data) || is_rider(mtmp->data) ||
133 			mtmp->data == &mons[PM_MINOTAUR])
134 		return(FALSE);
135 
136 	return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y)
137 #ifdef ELBERETH
138 			 || sengr_at("Elbereth", x, y)
139 #endif
140 			 || (mtmp->data->mlet == S_VAMPIRE
141 			     && IS_ALTAR(levl[x][y].typ)));
142 }
143 
144 #endif /* OVL2 */
145 #ifdef OVL0
146 
147 /* regenerate lost hit points */
148 void
mon_regen(mon,digest_meal)149 mon_regen(mon, digest_meal)
150 struct monst *mon;
151 boolean digest_meal;
152 {
153 	if (mon->mhp < mon->mhpmax &&
154 	    (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++;
155 	if (mon->mspec_used) mon->mspec_used--;
156 	if (digest_meal) {
157 	    if (mon->meating) mon->meating--;
158 	}
159 }
160 
161 /*
162  * Possibly awaken the given monster.  Return a 1 if the monster has been
163  * jolted awake.
164  */
165 STATIC_OVL int
disturb(mtmp)166 disturb(mtmp)
167 	register struct monst *mtmp;
168 {
169 	/*
170 	 * + Ettins are hard to surprise.
171 	 * + Nymphs, jabberwocks, and leprechauns do not easily wake up.
172 	 *
173 	 * Wake up if:
174 	 *	in direct LOS						AND
175 	 *	within 10 squares					AND
176 	 *	not stealthy or (mon is an ettin and 9/10)		AND
177 	 *	(mon is not a nymph, jabberwock, or leprechaun) or 1/50	AND
178 	 *	Aggravate or mon is (dog or human) or
179 	 *	    (1/7 and mon is not mimicing furniture or object)
180 	 */
181 	if(couldsee(mtmp->mx,mtmp->my) &&
182 		distu(mtmp->mx,mtmp->my) <= 100 &&
183 		(!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
184 		(!(mtmp->data->mlet == S_NYMPH
185 			|| mtmp->data == &mons[PM_JABBERWOCK]
186 #if 0	/* DEFERRED */
187 			|| mtmp->data == &mons[PM_VORPAL_JABBERWOCK]
188 #endif
189 			|| mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
190 		(Aggravate_monster
191 			|| (mtmp->data->mlet == S_DOG ||
192 				mtmp->data->mlet == S_HUMAN)
193 			|| (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE &&
194 				mtmp->m_ap_type != M_AP_OBJECT) )) {
195 		mtmp->msleeping = 0;
196 		return(1);
197 	}
198 	return(0);
199 }
200 
201 STATIC_OVL void
distfleeck(mtmp,inrange,nearby,scared)202 distfleeck(mtmp,inrange,nearby,scared)
203 register struct monst *mtmp;
204 int *inrange, *nearby, *scared;
205 {
206 	int seescaryx, seescaryy;
207 
208 	*inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
209 							(BOLT_LIM * BOLT_LIM));
210 	*nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy);
211 
212 	/* Note: if your image is displaced, the monster sees the Elbereth
213 	 * at your displaced position, thus never attacking your displaced
214 	 * position, but possibly attacking you by accident.  If you are
215 	 * invisible, it sees the Elbereth at your real position, thus never
216 	 * running into you by accident but possibly attacking the spot
217 	 * where it guesses you are.
218 	 */
219 	if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
220 		seescaryx = mtmp->mux;
221 		seescaryy = mtmp->muy;
222 	} else {
223 		seescaryx = u.ux;
224 		seescaryy = u.uy;
225 	}
226 	*scared = (*nearby && (onscary(seescaryx, seescaryy, mtmp) ||
227 			       (!mtmp->mpeaceful &&
228 				    in_your_sanctuary(mtmp, 0, 0))));
229 
230 	if(*scared && !mtmp->mflee) {
231 		if (!sticks(youmonst.data))
232 			unstuck(mtmp);	/* monster lets go when fleeing */
233 		mtmp->mflee = 1;
234 #ifdef STUPID
235 		if (rn2(7))
236 		    mtmp->mfleetim = rnd(10);
237 		else
238 		    mtmp->mfleetim = rnd(100);
239 #else
240 		mtmp->mfleetim = rnd(rn2(7) ? 10 : 100);
241 #endif
242 	}
243 
244 }
245 
246 /* perform a special one-time action for a monster; returns -1 if nothing
247    special happened, 0 if monster uses up its turn, 1 if monster is killed */
248 STATIC_OVL int
m_arrival(mon)249 m_arrival(mon)
250 struct monst *mon;
251 {
252 	mon->mstrategy &= ~STRAT_ARRIVE;	/* always reset */
253 
254 	return -1;
255 }
256 
257 /* returns 1 if monster died moving, 0 otherwise */
258 /* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti
259  * code. --KAA
260  */
261 int
dochug(mtmp)262 dochug(mtmp)
263 register struct monst *mtmp;
264 {
265 	register struct permonst *mdat;
266 	register int tmp=0;
267 	int inrange, nearby, scared;
268 
269 /*	Pre-movement adjustments	*/
270 
271 	mdat = mtmp->data;
272 
273 	if (mtmp->mstrategy & STRAT_ARRIVE) {
274 	    int res = m_arrival(mtmp);
275 	    if (res >= 0) return res;
276 	}
277 
278 	/* check for waitmask status change */
279 	if ((mtmp->mstrategy & STRAT_WAITFORU) &&
280 		(m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax))
281 	    mtmp->mstrategy &= ~STRAT_WAITFORU;
282 
283 	/* update quest status flags */
284 	quest_stat_check(mtmp);
285 
286 	if (!mtmp->mcanmove || (mtmp->mstrategy & STRAT_WAITMASK)) {
287 	    if (Hallucination) newsym(mtmp->mx,mtmp->my);
288 	    if (mtmp->mcanmove && (mtmp->mstrategy & STRAT_CLOSE) &&
289 	       !mtmp->msleeping && monnear(mtmp, u.ux, u.uy))
290 		quest_talk(mtmp);	/* give the leaders a chance to speak */
291 	    return(0);	/* other frozen monsters can't do anything */
292 	}
293 
294 	/* there is a chance we will wake it */
295 	if (mtmp->msleeping && !disturb(mtmp)) {
296 		if (Hallucination) newsym(mtmp->mx,mtmp->my);
297 		return(0);
298 	}
299 
300 	/* not frozen or sleeping: wipe out texts written in the dust */
301 	wipe_engr_at(mtmp->mx, mtmp->my, 1);
302 
303 	/* confused monsters get unconfused with small probability */
304 	if (mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
305 
306 	/* stunned monsters get un-stunned with larger probability */
307 	if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0;
308 
309 	/* some monsters teleport */
310 	if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz &&
311 	    !level.flags.noteleport) {
312 		rloc(mtmp);
313 		return(0);
314 	}
315 	if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1))
316 	    m_respond(mtmp);
317 	if (mdat == &mons[PM_MEDUSA] && cansee(mtmp->mx, mtmp->my))
318 	    m_respond(mtmp);
319 	if (mtmp->mhp <= 0) return(1); /* m_respond gaze can kill medusa */
320 
321 	/* fleeing monsters might regain courage */
322 	if (mtmp->mflee && !mtmp->mfleetim
323 	   && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0;
324 
325 	set_apparxy(mtmp);
326 	/* Must be done after you move and before the monster does.  The
327 	 * set_apparxy() call in m_move() doesn't suffice since the variables
328 	 * inrange, etc. all depend on stuff set by set_apparxy().
329 	 */
330 
331 	/* Monsters that want to acquire things */
332 	/* may teleport, so do it before inrange is set */
333 	if(is_covetous(mdat)) (void) tactics(mtmp);
334 
335 	/* check distance and scariness of attacks */
336 	distfleeck(mtmp,&inrange,&nearby,&scared);
337 
338 	if(find_defensive(mtmp)) {
339 		if (use_defensive(mtmp) != 0)
340 			return 1;
341 	} else if(find_misc(mtmp)) {
342 		if (use_misc(mtmp) != 0)
343 			return 1;
344 	}
345 
346 	/* Demonic Blackmail! */
347 	if(nearby && mdat->msound == MS_BRIBE &&
348 	   mtmp->mpeaceful && !mtmp->mtame && !u.uswallow) {
349 		if (mtmp->mux != u.ux || mtmp->muy != u.uy) {
350 			pline("%s whispers at thin air.",
351 			    cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It");
352 
353 			if (is_demon(youmonst.data)) {
354 			  /* "Good hunting, brother" */
355 			    if (!tele_restrict(mtmp)) rloc(mtmp);
356 			} else {
357 			    mtmp->minvis = mtmp->perminvis = 0;
358 			    /* Why?  For the same reason in real demon talk */
359 			    pline("%s gets angry!", Amonnam(mtmp));
360 			    mtmp->mpeaceful = 0;
361 			    /* since no way is an image going to pay it off */
362 			}
363 		} else if(demon_talk(mtmp)) return(1);	/* you paid it off */
364 	}
365 
366 	/* the watch will look around and see if you are up to no good :-) */
367 	if (mdat == &mons[PM_WATCHMAN] || mdat == &mons[PM_WATCH_CAPTAIN])
368 		watch_on_duty(mtmp);
369 
370 	else if (is_mind_flayer(mdat) && !rn2(20)) {
371 		struct monst *m2, *nmon = (struct monst *)0;
372 
373 		if (canseemon(mtmp))
374 			pline("%s concentrates.", Monnam(mtmp));
375 		if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) {
376 			You("sense a faint wave of psychic energy.");
377 			goto toofar;
378 		}
379 		pline("A wave of psychic energy pours over you!");
380 		if (mtmp->mpeaceful &&
381 		    (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
382 			pline("It feels quite soothing.");
383 		else {
384 			register boolean m_sen = sensemon(mtmp);
385 
386 			if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) {
387 				int dmg;
388 				pline("It locks on to your %s!",
389 					m_sen ? "telepathy" :
390 					Blind_telepat ? "latent telepathy" : "mind");
391 				dmg = rnd(15);
392 				if (Half_spell_damage) dmg = (dmg+1) / 2;
393 				losehp(dmg, "psychic blast", KILLED_BY_AN);
394 			}
395 		}
396 		for(m2=fmon; m2; m2 = nmon) {
397 			nmon = m2->nmon;
398 			if (DEADMONSTER(m2)) continue;
399 			if (m2->mpeaceful == mtmp->mpeaceful) continue;
400 			if (mindless(m2->data)) continue;
401 			if (m2 == mtmp) continue;
402 			if ((telepathic(m2->data) &&
403 			    (rn2(2) || m2->mblinded)) || !rn2(10)) {
404 				if (cansee(m2->mx, m2->my))
405 				    pline("It locks on to %s.", mon_nam(m2));
406 				m2->mhp -= rnd(15);
407 				if (m2->mhp <= 0)
408 				    monkilled(m2, "", AD_DRIN);
409 			}
410 		}
411 	}
412 toofar:
413 	/* If monster is nearby you, and has to wield a weapon, do so.   This
414 	 * costs the monster a move, of course.
415 	 */
416 	if((!mtmp->mpeaceful || Conflict) && inrange &&
417 	   dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8
418 	   && attacktype(mdat, AT_WEAP)) {
419 	    struct obj *mw_tmp;
420 
421 	    /* The scared check is necessary.  Otherwise a monster that is
422 	     * one square near the player but fleeing into a wall would keep
423 	     * switching between pick-axe and weapon.
424 	     */
425 	    mw_tmp = MON_WEP(mtmp);
426 	    if (!(scared && mw_tmp && is_pick(mw_tmp)) &&
427 		    mtmp->weapon_check == NEED_WEAPON) {
428 		mtmp->weapon_check = NEED_HTH_WEAPON;
429 		if (mon_wield_item(mtmp) != 0) return(0);
430 	    }
431 	}
432 
433 /*	Now the actual movement phase	*/
434 
435 	if(!nearby || mtmp->mflee || scared ||
436 	   mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) ||
437 	   (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) ||
438 	   (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) ||
439 	   (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) {
440 
441 		tmp = m_move(mtmp, 0);
442 		distfleeck(mtmp,&inrange,&nearby,&scared);	/* recalc */
443 
444 		switch (tmp) {
445 		    case 0:	/* no movement, but it can still attack you */
446 		    case 3:	/* absolutely no movement */
447 				/* for pets, case 0 and 3 are equivalent */
448 			/* During hallucination, monster appearance should
449 			 * still change - even if it doesn't move.
450 			 */
451 			if(Hallucination) newsym(mtmp->mx,mtmp->my);
452 			break;
453 		    case 1:	/* monster moved */
454 			/* Maybe it stepped on a trap and fell asleep... */
455 			if (mtmp->msleeping || !mtmp->mcanmove) return(0);
456 			if(!nearby &&
457 			  (ranged_attk(mdat) || find_offensive(mtmp)))
458 			    break;
459  			else if(u.uswallow && mtmp == u.ustuck) {
460 			    /* a monster that's digesting you can move at the
461 			     * same time -dlc
462 			     */
463 			    return(mattacku(mtmp));
464 			} else
465 				return(0);
466 			/*NOTREACHED*/
467 			break;
468 		    case 2:	/* monster died */
469 			return(1);
470 		}
471 	}
472 
473 /*	Now, attack the player if possible - one attack set per monst	*/
474 
475 	if (!mtmp->mpeaceful ||
476 	    (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) {
477 	    if(inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3)
478 		if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */
479 
480 	    if(mtmp->wormno) wormhitu(mtmp);
481 	}
482 	/* special speeches for quest monsters */
483 	if (!mtmp->msleeping && mtmp->mcanmove && nearby)
484 	    quest_talk(mtmp);
485 	/* extra emotional attack for vile monsters */
486 	if (inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful &&
487 		couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5))
488 	    cuss(mtmp);
489 
490 	return(tmp == 2);
491 }
492 
493 static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 };
494 static NEARDATA const char magical[] = {
495 	AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS,
496 	SPBOOK_CLASS, 0 };
497 static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 };
498 static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 };
499 static NEARDATA const char gem_class[] = { GEM_CLASS, 0 };
500 
501 boolean
itsstuck(mtmp)502 itsstuck(mtmp)
503 register struct monst *mtmp;
504 {
505 	if (sticks(youmonst.data) && mtmp==u.ustuck && !u.uswallow) {
506 		pline("%s cannot escape from you!", Monnam(mtmp));
507 		return(TRUE);
508 	}
509 	return(FALSE);
510 }
511 
512 /* Return values:
513  * 0: did not move, but can still attack and do other stuff.
514  * 1: moved, possibly can attack.
515  * 2: monster died.
516  * 3: did not move, and can't do anything else either.
517  */
518 int
m_move(mtmp,after)519 m_move(mtmp, after)
520 register struct monst *mtmp;
521 register int after;
522 {
523 	register int appr;
524 	xchar gx,gy,nix,niy,chcnt;
525 	int chi;	/* could be schar except for stupid Sun-2 compiler */
526 	boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0;
527 	boolean likerock=0, can_tunnel=0;
528 	boolean can_open=0, can_unlock=0, doorbuster=0;
529 	boolean uses_items=0;
530 	struct permonst *ptr;
531 	struct monst *mtoo;
532 	schar mmoved = 0;	/* not strictly nec.: chi >= 0 will do */
533 	long info[9];
534 	long flag;
535 	int  omx = mtmp->mx, omy = mtmp->my;
536 	struct obj *mw_tmp;
537 
538 	if(mtmp->mtrapped) {
539 	    int i = mintrap(mtmp);
540 	    if(i >= 2) { newsym(mtmp->mx,mtmp->my); return(2); }/* it died */
541 	    if(i == 1) return(0);	/* still in trap, so didn't move */
542 	}
543 	ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */
544 
545 	if (mtmp->meating) {
546 	    mtmp->meating--;
547 	    return 3;			/* still eating */
548 	}
549 	if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10))
550 	    return 0;		/* do not leave hiding place */
551 
552 	set_apparxy(mtmp);
553 	/* where does mtmp think you are? */
554 	/* Not necessary if m_move called from this file, but necessary in
555 	 * other calls of m_move (ex. leprechauns dodging)
556 	 */
557 	can_tunnel = tunnels(ptr) &&
558 #ifdef REINCARNATION
559 		!Is_rogue_level(&u.uz) &&
560 #endif
561 		(!needspick(ptr) || m_carrying(mtmp, PICK_AXE) ||
562 		(m_carrying(mtmp, DWARVISH_MATTOCK) && !which_armor(mtmp, W_ARMS)));
563 	can_open = !(nohands(ptr) || verysmall(ptr));
564 	can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) ||
565 		      mtmp->iswiz || is_rider(ptr));
566 	doorbuster = is_giant(ptr);
567 	if(mtmp->wormno) goto not_special;
568 	/* my dog gets special treatment */
569 	if(mtmp->mtame) {
570 	    mmoved = dog_move(mtmp, after);
571 	    goto postmov;
572 	}
573 
574 	/* likewise for shopkeeper */
575 	if(mtmp->isshk) {
576 	    mmoved = shk_move(mtmp);
577 	    if(mmoved == -2) return(2);
578 	    if(mmoved >= 0) goto postmov;
579 	    mmoved = 0;		/* follow player outside shop */
580 	}
581 
582 	/* and for the guard */
583 	if(mtmp->isgd) {
584 	    mmoved = gd_move(mtmp);
585 	    if(mmoved == -2) return(2);
586 	    if(mmoved >= 0) goto postmov;
587 	    mmoved = 0;
588 	}
589 
590 	/* and the acquisitive monsters get special treatment */
591 	if(is_covetous(ptr)) {
592 	    xchar tx = STRAT_GOALX(mtmp->mstrategy),
593 		  ty = STRAT_GOALY(mtmp->mstrategy);
594 	    struct monst *intruder = m_at(tx, ty);
595 	    /*
596 	     * if there's a monster on the object or in possesion of it,
597 	     * attack it.
598 	     */
599 	    if((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) &&
600 	       intruder && (intruder != mtmp)) {
601 
602 		notonhead = (intruder->mx != tx || intruder->my != ty);
603 		if(mattackm(mtmp, intruder) == 2) return(2);
604 		mmoved = 1;
605 	    } else mmoved = 0;
606 	    goto postmov;
607 	}
608 
609 	/* and for the priest */
610 	if(mtmp->ispriest) {
611 	    mmoved = pri_move(mtmp);
612 	    if(mmoved == -2) return(2);
613 	    if(mmoved >= 0) goto postmov;
614 	    mmoved = 0;
615 	}
616 
617 #ifdef MAIL
618 	if(ptr == &mons[PM_MAIL_DAEMON]) {
619 	    if(flags.soundok && canseemon(mtmp))
620 		verbalize("I'm late!");
621 	    mongone(mtmp);
622 	    return(2);
623 	}
624 #endif
625 
626 	/* teleport if that lies in our nature */
627 	if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan &&
628 	   !tele_restrict(mtmp)) {
629 	    if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
630 		rloc(mtmp);
631 	    else
632 		mnexto(mtmp);
633 	    mmoved = 1;
634 	    goto postmov;
635 	}
636 not_special:
637 	if(u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return(1);
638 	omx = mtmp->mx;
639 	omy = mtmp->my;
640 	gx = mtmp->mux;
641 	gy = mtmp->muy;
642 	appr = mtmp->mflee ? -1 : 1;
643 	if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck))
644 		appr = 0;
645 	else {
646 		boolean should_see = (couldsee(omx, omy) &&
647 				      (levl[gx][gy].lit ||
648 				       !levl[omx][omy].lit) &&
649 				      (dist2(omx, omy, gx, gy) <= 36));
650 
651 		if (!mtmp->mcansee ||
652 		    (should_see && Invis && !perceives(ptr) && rn2(11)) ||
653 		    (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected ||
654 		    (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == GOLD_PIECE && !likes_gold(ptr)) ||
655 		    (mtmp->mpeaceful && !mtmp->isshk) ||  /* allow shks to follow */
656 		    ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT ||
657 		      ptr->mlet == S_LIGHT) && !rn2(3)))
658 			appr = 0;
659 
660 		if(monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) &&
661 		   (mtmp->mgold > u.ugold))
662 			appr = -1;
663 
664 		if (!should_see && can_track(ptr)) {
665 			register coord *cp;
666 
667 			cp = gettrack(omx,omy);
668 			if (cp) {
669 				gx = cp->x;
670 				gy = cp->y;
671 			}
672 		}
673 	}
674 
675 	if ((!mtmp->mpeaceful || !rn2(10))
676 #ifdef REINCARNATION
677 				    && (!Is_rogue_level(&u.uz))
678 #endif
679 							    ) {
680 	    boolean in_line = lined_up(mtmp) &&
681 		(distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
682 		    (throws_rocks(youmonst.data) ? 20 : ACURRSTR/2+1)
683 		);
684 
685 	    if (appr != 1 || !in_line) {
686 		/* Monsters in combat won't pick stuff up, avoiding the
687 		 * situation where you toss arrows at it and it has nothing
688 		 * better to do than pick the arrows up.
689 		 */
690 		register int pctload = (curr_mon_load(mtmp) * 100) /
691 			max_mon_load(mtmp);
692 
693 		/* look for gold or jewels nearby */
694 		likegold = (likes_gold(ptr) && pctload < 95);
695 		likegems = (likes_gems(ptr) && pctload < 85);
696 		uses_items = (!mindless(ptr) && !is_animal(ptr)
697 			&& pctload < 75);
698 		likeobjs = (likes_objs(ptr) && pctload < 75);
699 		likemagic = (likes_magic(ptr) && pctload < 85);
700 		likerock = (throws_rocks(ptr) && pctload < 50 && !In_sokoban(&u.uz));
701 		conceals = hides_under(ptr);
702 	    }
703 	}
704 
705 #define SQSRCHRADIUS	5
706 
707       { register int minr = SQSRCHRADIUS;	/* not too far away */
708 	register struct obj *otmp;
709 	register int xx, yy;
710 	int oomx, oomy, lmx, lmy;
711 
712 	/* cut down the search radius if it thinks character is closer. */
713 	if(distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS &&
714 	    !mtmp->mpeaceful) minr--;
715 	/* guards shouldn't get too distracted */
716 	if(!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1;
717 
718 	if((likegold || likegems || likeobjs || likemagic || likerock || conceals)
719 	      && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) {
720 	look_for_obj:
721 	    oomx = min(COLNO-1, omx+minr);
722 	    oomy = min(ROWNO-1, omy+minr);
723 	    lmx = max(1, omx-minr);
724 	    lmy = max(0, omy-minr);
725 	    for(otmp = fobj; otmp; otmp = otmp->nobj) {
726 		/* monsters may pick rocks up, but won't go out of their way
727 		   to grab them; this might hamper sling wielders, but it cuts
728 		   down on move overhead by filtering out most common item */
729 		if (otmp->otyp == ROCK) continue;
730 		xx = otmp->ox;
731 		yy = otmp->oy;
732 		/* Nymphs take everything.  Most other creatures should not
733 		 * pick up corpses except as a special case like in
734 		 * searches_for_item().  We need to do this check in
735 		 * mpickstuff() as well.
736 		 */
737 		if(xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) {
738 		    /* don't get stuck circling around an object that's underneath
739 		       an immobile or hidden monster; paralysis victims excluded */
740 		    if ((mtoo = m_at(xx,yy)) != 0 &&
741 			(mtoo->msleeping || mtoo->mundetected ||
742 			 (mtoo->mappearance && !mtoo->iswiz) ||
743 			 !mtoo->data->mmove)) continue;
744 
745 		    if(((likegold && otmp->oclass == GOLD_CLASS) ||
746 		       (likeobjs && index(practical, otmp->oclass) &&
747 			(otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH
748 			   && !is_rider(&mons[otmp->corpsenm])))) ||
749 		       (likemagic && index(magical, otmp->oclass)) ||
750 		       (uses_items && searches_for_item(mtmp, otmp)) ||
751 		       (likerock && otmp->otyp == BOULDER) ||
752 		       (likegems && otmp->oclass == GEM_CLASS &&
753 			objects[otmp->otyp].oc_material != MINERAL) ||
754 		       (conceals && !cansee(otmp->ox,otmp->oy)) ||
755 		       (ptr == &mons[PM_GELATINOUS_CUBE] &&
756 			!index(indigestion, otmp->oclass) &&
757 			!(otmp->otyp == CORPSE &&
758 			  touch_petrifies(&mons[otmp->corpsenm])))
759 		      ) && touch_artifact(otmp,mtmp)) {
760 			if(can_carry(mtmp,otmp) &&
761 			   (throws_rocks(ptr) ||
762 				!sobj_at(BOULDER,xx,yy)) &&
763 			   (!is_unicorn(ptr) ||
764 			    objects[otmp->otyp].oc_material == GEMSTONE) &&
765 			   /* Don't get stuck circling an Elbereth */
766 			   !(onscary(xx, yy, mtmp))) {
767 			    minr = distmin(omx,omy,xx,yy);
768 			    oomx = min(COLNO-1, omx+minr);
769 			    oomy = min(ROWNO-1, omy+minr);
770 			    lmx = max(1, omx-minr);
771 			    lmy = max(0, omy-minr);
772 			    gx = otmp->ox;
773 			    gy = otmp->oy;
774 			    if (gx == omx && gy == omy) {
775 				mmoved = 3; /* actually unnecessary */
776 				goto postmov;
777 			    }
778 			}
779 		    }
780 		}
781 	    }
782 	} else if(likegold) {
783 	    /* don't try to pick up anything else, but use the same loop */
784 	    uses_items = 0;
785 	    likegems = likeobjs = likemagic = likerock = conceals = 0;
786 	    goto look_for_obj;
787 	}
788 
789 	if(minr < SQSRCHRADIUS && appr == -1) {
790 	    if(distmin(omx,omy,mtmp->mux,mtmp->muy) <= 3) {
791 		gx = mtmp->mux;
792 		gy = mtmp->muy;
793 	    } else
794 		appr = 1;
795 	}
796       }
797 
798 	if (can_tunnel && needspick(ptr) &&
799 		(mw_tmp = MON_WEP(mtmp)) != 0 && !is_pick(mw_tmp) &&
800 		mw_tmp->cursed && mtmp->weapon_check == NO_WEAPON_WANTED)
801 	    can_tunnel = FALSE;
802 
803 	nix = omx;
804 	niy = omy;
805 	flag = 0L;
806 	if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
807 	    flag |= (ALLOW_SANCT | ALLOW_SSM);
808 	else flag |= ALLOW_U;
809 	if (is_minion(ptr) || is_rider(ptr)) flag |= ALLOW_SANCT;
810 	if (is_unicorn(ptr)) flag |= NOTONL;
811 	if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK);
812 	if (can_tunnel) flag |= ALLOW_DIG;
813 	if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM;
814 	if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC;
815 	if (throws_rocks(ptr)) flag |= ALLOW_ROCK;
816 	if (can_open) flag |= OPENDOOR;
817 	if (can_unlock) flag |= UNLOCKDOOR;
818 	if (doorbuster) flag |= BUSTDOOR;
819 	{
820 	    register int i, j, nx, ny, nearer;
821 	    int jcnt, cnt;
822 	    int ndist, nidist;
823 	    register coord *mtrk;
824 	    coord poss[9];
825 
826 	    cnt = mfndpos(mtmp, poss, info, flag);
827 	    chcnt = 0;
828 	    jcnt = min(MTSZ, cnt-1);
829 	    chi = -1;
830 	    nidist = dist2(nix,niy,gx,gy);
831 	    /* allow monsters be shortsighted on some levels for balance */
832 	    if(!mtmp->mpeaceful && level.flags.shortsighted &&
833 	       nidist > (couldsee(nix,niy) ? 144 : 36) && appr == 1) appr = 0;
834 
835 	    for(i=0; i < cnt; i++) {
836 		nx = poss[i].x;
837 		ny = poss[i].y;
838 
839 		if (appr != 0) {
840 		    mtrk = &mtmp->mtrack[0];
841 		    for(j=0; j < jcnt; mtrk++, j++)
842 			if(nx == mtrk->x && ny == mtrk->y)
843 			    if(rn2(4*(cnt-j)))
844 				goto nxti;
845 		}
846 
847 		nearer = ((ndist = dist2(nx,ny,gx,gy)) < nidist);
848 
849 		if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
850 		   (!appr && !rn2(++chcnt)) || !mmoved) {
851 		    nix = nx;
852 		    niy = ny;
853 		    nidist = ndist;
854 		    chi = i;
855 		    mmoved = 1;
856 		}
857 	    nxti:	;
858 	    }
859 	}
860 
861 	if(mmoved) {
862 	    register int j;
863 
864 	    if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
865 		return(3);
866 
867 	    if(IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy) &&
868 		    mmoved==1 && can_tunnel && needspick(ptr) &&
869 		    (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))) {
870 		mtmp->weapon_check = NEED_PICK_AXE;
871 		if (mon_wield_item(mtmp))
872 		    return(3);
873 	    }
874 	    /* If ALLOW_U is set, either it's trying to attack you, or it
875 	     * thinks it is.  In either case, attack this spot in preference to
876 	     * all others.
877 	     */
878 	/* Actually, this whole section of code doesn't work as you'd expect.
879 	 * Most attacks are handled in dochug().  It calls distfleeck(), which
880 	 * among other things sets nearby if the monster is near you--and if
881 	 * nearby is set, we never call m_move unless it is a special case
882 	 * (confused, stun, etc.)  The effect is that this ALLOW_U (and
883 	 * mfndpos) has no effect for normal attacks, though it lets a confused
884 	 * monster attack you by accident.
885 	 */
886 	    if(info[chi] & ALLOW_U) {
887 		nix = mtmp->mux;
888 		niy = mtmp->muy;
889 	    }
890 	    if (nix == u.ux && niy == u.uy) {
891 		mtmp->mux = u.ux;
892 		mtmp->muy = u.uy;
893 		return(0);
894 	    }
895 	    /* The monster may attack another based on 1 of 2 conditions:
896 	     * 1 - It may be confused.
897 	     * 2 - It may mistake the monster for your (displaced) image.
898 	     * Pets get taken care of above and shouldn't reach this code.
899 	     * Conflict gets handled even farther away (movemon()).
900 	     */
901 	    if((info[chi] & ALLOW_M) ||
902 		   (nix == mtmp->mux && niy == mtmp->muy)) {
903 		struct monst *mtmp2;
904 		int mstatus;
905 		mtmp2 = m_at(nix,niy);
906 
907 		notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my);
908 		/* note: mstatus returns 0 if mtmp2 is nonexistent */
909 		mstatus = mattackm(mtmp, mtmp2);
910 
911 		if (mstatus & MM_AGR_DIED)		/* aggressor died */
912 		    return 2;
913 
914 		if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)  &&
915 		    rn2(4) && mtmp2->movement >= NORMAL_SPEED) {
916 		    mtmp2->movement -= NORMAL_SPEED;
917 		    notonhead = 0;
918 		    mstatus = mattackm(mtmp2, mtmp);	/* return attack */
919 		    if (mstatus & MM_DEF_DIED)
920 			return 2;
921 		}
922 		return 3;
923 	    }
924 
925 	    if (!m_in_out_region(mtmp,nix,niy))
926 	        return 3;
927 	    remove_monster(omx, omy);
928 	    place_monster(mtmp, nix, niy);
929 	    for(j = MTSZ-1; j > 0; j--)
930 		mtmp->mtrack[j] = mtmp->mtrack[j-1];
931 	    mtmp->mtrack[0].x = omx;
932 	    mtmp->mtrack[0].y = omy;
933 	    /* Place a segment at the old position. */
934 	    if (mtmp->wormno) worm_move(mtmp);
935 	} else {
936 	    if(is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) {
937 		rloc(mtmp);
938 		return(1);
939 	    }
940 	    if(mtmp->wormno) worm_nomove(mtmp);
941 	}
942 postmov:
943 	if(mmoved == 1 || mmoved == 3) {
944 	    boolean canseeit = cansee(mtmp->mx, mtmp->my);
945 
946 	    if(mmoved == 1) {
947 		newsym(omx,omy);		/* update the old position */
948 		if (mintrap(mtmp) >= 2) {
949 		    if(mtmp->mx) newsym(mtmp->mx,mtmp->my);
950 		    return(2);	/* it died */
951 		}
952 		ptr = mtmp->data;
953 
954 		/* open a door, or crash through it, if you can */
955 		if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ)
956 			&& !passes_walls(ptr) /* doesn't need to open doors */
957 			&& !can_tunnel /* taken care of below */
958 		      ) {
959 		    struct rm *here = &levl[mtmp->mx][mtmp->my];
960 		    boolean btrapped = (here->doormask & D_TRAPPED);
961 
962 		    if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) {
963 			if (flags.verbose && canseemon(mtmp))
964 			    pline("%s %ss under the door.", Monnam(mtmp),
965 				  (ptr == &mons[PM_FOG_CLOUD] ||
966 				   ptr == &mons[PM_YELLOW_LIGHT])
967 				  ? "flow" : "ooze");
968 		    } else if(here->doormask & D_LOCKED && can_unlock) {
969 			if(btrapped) {
970 			    here->doormask = D_NODOOR;
971 			    newsym(mtmp->mx, mtmp->my);
972 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
973 			    if(mb_trapped(mtmp)) return(2);
974 			} else {
975 			    if (flags.verbose) {
976 				if (canseeit)
977 				   You("see a door unlock and open.");
978 				else if (flags.soundok)
979 				   You_hear("a door unlock and open.");
980 			    }
981 			    here->doormask = D_ISOPEN;
982 			    /* newsym(mtmp->mx, mtmp->my); */
983 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
984 			}
985 		    } else if (here->doormask == D_CLOSED && can_open) {
986 			if(btrapped) {
987 			    here->doormask = D_NODOOR;
988 			    newsym(mtmp->mx, mtmp->my);
989 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
990 			    if(mb_trapped(mtmp)) return(2);
991 			} else {
992 			    if (flags.verbose) {
993 				if (canseeit)
994 				     You("see a door open.");
995 				else if (flags.soundok)
996 				     You_hear("a door open.");
997 			    }
998 			    here->doormask = D_ISOPEN;
999 			    /* newsym(mtmp->mx, mtmp->my); */  /* done below */
1000 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
1001 			}
1002 		    } else if (here->doormask & (D_LOCKED|D_CLOSED)) {
1003 			/* mfndpos guarantees this must be a doorbuster */
1004 			if(btrapped) {
1005 			    here->doormask = D_NODOOR;
1006 			    newsym(mtmp->mx, mtmp->my);
1007 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
1008 			    if(mb_trapped(mtmp)) return(2);
1009 			} else {
1010 			    if (flags.verbose) {
1011 				if (canseeit)
1012 				    You("see a door crash open.");
1013 				else if (flags.soundok)
1014 				    You_hear("a door crash open.");
1015 			    }
1016 			    if (here->doormask & D_LOCKED && !rn2(2))
1017 				    here->doormask = D_NODOOR;
1018 			    else here->doormask = D_BROKEN;
1019 			    /* newsym(mtmp->mx, mtmp->my); */ /* done below */
1020 			    unblock_point(mtmp->mx,mtmp->my); /* vision */
1021 			}
1022 			/* if it's a shop door, schedule repair */
1023 			if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
1024 			    add_damage(mtmp->mx, mtmp->my, 0L);
1025 		    }
1026 		}
1027 
1028 		/* possibly dig */
1029 		if (can_tunnel && mdig_tunnel(mtmp))
1030 			return(2);  /* mon died (position already updated) */
1031 
1032 		/* set also in domove(), hack.c */
1033 		if (u.uswallow && mtmp == u.ustuck &&
1034 					(mtmp->mx != omx || mtmp->my != omy)) {
1035 		    /* If the monster moved, then update */
1036 		    u.ux0 = u.ux;
1037 		    u.uy0 = u.uy;
1038 		    u.ux = mtmp->mx;
1039 		    u.uy = mtmp->my;
1040 		    swallowed(0);
1041 		} else
1042 		newsym(mtmp->mx,mtmp->my);
1043 	    }
1044 	    if(OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
1045 		/* Maybe a rock mole just ate some metal object */
1046 		if (metallivorous(ptr)) {
1047 		    if (meatgold(mtmp) == 2) return 2;	/* it died */
1048 		}
1049 
1050 		if(g_at(mtmp->mx,mtmp->my) && likegold) mpickgold(mtmp);
1051 
1052 		/* Maybe a cube ate just about anything */
1053 		if (ptr == &mons[PM_GELATINOUS_CUBE]) {
1054 		    if (meatobj(mtmp) == 2) return 2;	/* it died */
1055 		}
1056 
1057 		if(!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) {
1058 		    boolean picked = FALSE;
1059 
1060 		    if(likeobjs) picked |= mpickstuff(mtmp, practical);
1061 		    if(likemagic) picked |= mpickstuff(mtmp, magical);
1062 		    if(likerock) picked |= mpickstuff(mtmp, boulder_class);
1063 		    if(likegems) picked |= mpickstuff(mtmp, gem_class);
1064 		    if(uses_items) picked |= mpickstuff(mtmp, (char *)0);
1065 		    if(picked) mmoved = 3;
1066 		}
1067 
1068 		if(mtmp->minvis) {
1069 		    newsym(mtmp->mx, mtmp->my);
1070 		    if (mtmp->wormno) see_wsegs(mtmp);
1071 		}
1072 	    }
1073 
1074 	    if(hides_under(ptr) || ptr->mlet == S_EEL) {
1075 		/* Always set--or reset--mundetected if it's already hidden
1076 		   (just in case the object it was hiding under went away);
1077 		   usually set mundetected unless monster can't move.  */
1078 		if (mtmp->mundetected ||
1079 			(mtmp->mcanmove && !mtmp->msleeping && rn2(5)))
1080 		    mtmp->mundetected = (ptr->mlet != S_EEL) ?
1081 			OBJ_AT(mtmp->mx, mtmp->my) :
1082 			(is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz));
1083 		newsym(mtmp->mx, mtmp->my);
1084 	    }
1085 	}
1086 	return(mmoved);
1087 }
1088 
1089 #endif /* OVL0 */
1090 #ifdef OVL2
1091 
1092 boolean
closed_door(x,y)1093 closed_door(x, y)
1094 register int x, y;
1095 {
1096 	return((boolean)(IS_DOOR(levl[x][y].typ) &&
1097 			(levl[x][y].doormask & (D_LOCKED | D_CLOSED))));
1098 }
1099 
1100 boolean
accessible(x,y)1101 accessible(x, y)
1102 register int x, y;
1103 {
1104 	return((boolean)(ACCESSIBLE(levl[x][y].typ) && !closed_door(x, y)));
1105 }
1106 
1107 #endif /* OVL2 */
1108 #ifdef OVL0
1109 
1110 /* decide where the monster thinks you are standing */
1111 void
set_apparxy(mtmp)1112 set_apparxy(mtmp)
1113 register struct monst *mtmp;
1114 {
1115 	boolean notseen, gotu;
1116 	register int disp, mx = mtmp->mux, my = mtmp->muy;
1117 
1118 	/*
1119 	 * do cheapest and/or most likely tests first
1120 	 */
1121 
1122 	/* pet knows your smell; grabber still has hold of you */
1123 	if (mtmp->mtame || mtmp == u.ustuck) goto found_you;
1124 
1125 	/* monsters which know where you are don't suddenly forget,
1126 	   if you haven't moved away */
1127 	if (mx == u.ux && my == u.uy) goto found_you;
1128 
1129 	notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data)));
1130 	/* add cases as required.  eg. Displacement ... */
1131 	disp = ((notseen || Underwater) ? 1 :
1132 		Displaced ? (couldsee(mx, my) ? 2 : 1) : 0);
1133 	if (!disp) goto found_you;
1134 
1135 	/* without something like the following, invis. and displ.
1136 	   are too powerful */
1137 	gotu = notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE;
1138 
1139 #if 0		/* this never worked as intended & isn't needed anyway */
1140 	/* If invis but not displaced, staying around gets you 'discovered' */
1141 	gotu |= (!Displaced && u.dx == 0 && u.dy == 0);
1142 #endif
1143 
1144 	if (!gotu) {
1145 	    register int try_cnt = 0;
1146 	    do {
1147 		if (++try_cnt > 200) goto found_you;		/* punt */
1148 		mx = u.ux - disp + rn2(2*disp+1);
1149 		my = u.uy - disp + rn2(2*disp+1);
1150 	    } while (!isok(mx,my)
1151 		  || (disp != 2 && mx == mtmp->mx && my == mtmp->my)
1152 		  || ((mx != u.ux || my != u.uy) &&
1153 		      !passes_walls(mtmp->data) &&
1154 		      (!ACCESSIBLE(levl[mx][my].typ) ||
1155 			(closed_door(mx, my) && !can_ooze(mtmp)))));
1156 	} else {
1157 found_you:
1158 	    mx = u.ux;
1159 	    my = u.uy;
1160 	}
1161 
1162 	mtmp->mux = mx;
1163 	mtmp->muy = my;
1164 }
1165 
1166 boolean
can_ooze(mtmp)1167 can_ooze(mtmp)
1168 struct monst *mtmp;
1169 {
1170 	struct obj *chain, *obj;
1171 
1172 	if (!amorphous(mtmp->data)) return FALSE;
1173 	if (mtmp == &youmonst) {
1174 		if (u.ugold > 100L) return FALSE;
1175 		chain = invent;
1176 	} else {
1177 		if (mtmp->mgold > 100L) return FALSE;
1178 		chain = mtmp->minvent;
1179 	}
1180 	for (obj = chain; obj; obj = obj->nobj) {
1181 		int typ = obj->otyp;
1182 
1183 		if (obj->oclass != GEM_CLASS &&
1184 		    !(typ >= ARROW && typ <= BOOMERANG) &&
1185 		    !(typ >= DAGGER && typ <= CRYSKNIFE) &&
1186 		    typ != SLING &&
1187 		    !is_cloak(obj) && typ != FEDORA &&
1188 		    !is_gloves(obj) && typ != LEATHER_JACKET &&
1189 #ifdef TOURIST
1190 		    typ != CREDIT_CARD && !is_shirt(obj) &&
1191 #endif
1192 		    !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) &&
1193 		    typ != FORTUNE_COOKIE && typ != CANDY_BAR &&
1194 		    typ != PANCAKE && typ != LEMBAS_WAFER &&
1195 		    typ != LUMP_OF_ROYAL_JELLY &&
1196 		    obj->oclass != AMULET_CLASS &&
1197 		    obj->oclass != RING_CLASS &&
1198 #ifdef WIZARD
1199 		    obj->oclass != VENOM_CLASS &&
1200 #endif
1201 		    typ != SACK && typ != BAG_OF_HOLDING &&
1202 		    typ != BAG_OF_TRICKS && !Is_candle(obj) &&
1203 		    typ != OILSKIN_SACK && typ != LEASH &&
1204 		    typ != STETHOSCOPE && typ != BLINDFOLD && typ != TOWEL &&
1205 		    typ != TIN_WHISTLE && typ != MAGIC_WHISTLE &&
1206 		    typ != MAGIC_MARKER && typ != TIN_OPENER &&
1207 		    typ != SKELETON_KEY && typ != LOCK_PICK
1208 		) return FALSE;
1209 		if (Is_container(obj) && obj->cobj) return FALSE;
1210 
1211 	}
1212 	return TRUE;
1213 }
1214 
1215 #endif /* OVL0 */
1216 
1217 /*monmove.c*/
1218