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