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