1/*	SCCS Id: @(#)hack.c	3.4	2003/04/30	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6
7#ifdef OVL1
8STATIC_DCL void NDECL(maybe_wail);
9#endif /*OVL1*/
10STATIC_DCL int NDECL(moverock);
11STATIC_DCL int FDECL(still_chewing,(XCHAR_P,XCHAR_P));
12#ifdef SINKS
13STATIC_DCL void NDECL(dosinkfall);
14#endif
15STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
16STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
17
18STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
19
20#define IS_SHOP(x)	(rooms[x].rtype >= SHOPBASE)
21
22#ifdef OVL2
23
24boolean
25revive_nasty(x, y, msg)
26int x,y;
27const char *msg;
28{
29    register struct obj *otmp, *otmp2;
30    struct monst *mtmp;
31    coord cc;
32    boolean revived = FALSE;
33
34    for(otmp = level.objects[x][y]; otmp; otmp = otmp2) {
35	otmp2 = otmp->nexthere;
36	if (otmp->otyp == CORPSE &&
37	    (is_rider(&mons[otmp->corpsenm]) ||
38	     otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
39	    /* move any living monster already at that location */
40	    if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data))
41		rloc_to(mtmp, cc.x, cc.y);
42	    if(msg) Norep("%s", msg);
43	    revived = revive_corpse(otmp);
44	}
45    }
46
47    /* this location might not be safe, if not, move revived monster */
48    if (revived) {
49	mtmp = m_at(x,y);
50	if (mtmp && !goodpos(x, y, mtmp, 0) &&
51	    enexto(&cc, x, y, mtmp->data)) {
52	    rloc_to(mtmp, cc.x, cc.y);
53	}
54	/* else impossible? */
55    }
56
57    return (revived);
58}
59
60STATIC_OVL int
61moverock()
62{
63    register xchar rx, ry, sx, sy;
64    register struct obj *otmp;
65    register struct trap *ttmp;
66    register struct monst *mtmp;
67
68    sx = u.ux + u.dx,  sy = u.uy + u.dy;	/* boulder starting position */
69    while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
70	/* make sure that this boulder is visible as the top object */
71	if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy);
72
73	rx = u.ux + 2 * u.dx;	/* boulder destination position */
74	ry = u.uy + 2 * u.dy;
75	nomul(0);
76	if (Levitation || Is_airlevel(&u.uz)) {
77	    if (Blind) feel_location(sx, sy);
78	    You("don't have enough leverage to push %s.", the(xname(otmp)));
79	    /* Give them a chance to climb over it? */
80	    return -1;
81	}
82	if (verysmall(youmonst.data)
83#ifdef STEED
84		 && !u.usteed
85#endif
86				    ) {
87	    if (Blind) feel_location(sx, sy);
88	    pline("You're too small to push that %s.", xname(otmp));
89	    goto cannot_push;
90	}
91	if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
92	    levl[rx][ry].typ != IRONBARS &&
93	    (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || (
94#ifdef REINCARNATION
95		!Is_rogue_level(&u.uz) &&
96#endif
97		(levl[rx][ry].doormask & ~D_BROKEN) == D_NODOOR)) &&
98	    !sobj_at(BOULDER, rx, ry)) {
99	    ttmp = t_at(rx, ry);
100	    mtmp = m_at(rx, ry);
101
102		/* KMH -- Sokoban doesn't let you push boulders diagonally */
103	    if (In_sokoban(&u.uz) && u.dx && u.dy) {
104	    	if (Blind) feel_location(sx,sy);
105	    	pline("%s won't roll diagonally on this %s.",
106	        		The(xname(otmp)), surface(sx, sy));
107	    	goto cannot_push;
108	    }
109
110	    if (revive_nasty(rx, ry, "You sense movement on the other side."))
111		return (-1);
112
113	    if (mtmp && !noncorporeal(mtmp->data) &&
114		    (!mtmp->mtrapped ||
115			 !(ttmp && ((ttmp->ttyp == PIT) ||
116				    (ttmp->ttyp == SPIKED_PIT))))) {
117		if (Blind) feel_location(sx, sy);
118		if (canspotmon(mtmp))
119		    pline("There's %s on the other side.", a_monnam(mtmp));
120		else {
121		    You_hear("a monster behind %s.", the(xname(otmp)));
122		    map_invisible(rx, ry);
123		}
124		if (flags.verbose)
125		    pline("Perhaps that's why %s cannot move it.",
126#ifdef STEED
127				u.usteed ? y_monnam(u.usteed) :
128#endif
129				"you");
130		goto cannot_push;
131	    }
132
133	    if (ttmp)
134		switch(ttmp->ttyp) {
135		case LANDMINE:
136		    if (rn2(10)) {
137			obj_extract_self(otmp);
138			place_object(otmp, rx, ry);
139			unblock_point(sx, sy);
140			newsym(sx, sy);
141			pline("KAABLAMM!!!  %s %s land mine.",
142			      Tobjnam(otmp, "trigger"),
143			      ttmp->madeby_u ? "your" : "a");
144			blow_up_landmine(ttmp);
145			/* if the boulder remains, it should fill the pit */
146			fill_pit(u.ux, u.uy);
147			if (cansee(rx,ry)) newsym(rx,ry);
148			continue;
149		    }
150		    break;
151		case SPIKED_PIT:
152		case PIT:
153		    obj_extract_self(otmp);
154		    /* vision kludge to get messages right;
155		       the pit will temporarily be seen even
156		       if this is one among multiple boulders */
157		    if (!Blind) viz_array[ry][rx] |= IN_SIGHT;
158		    if (!flooreffects(otmp, rx, ry, "fall")) {
159			place_object(otmp, rx, ry);
160		    }
161		    if (mtmp && !Blind) newsym(rx, ry);
162		    continue;
163		case HOLE:
164		case TRAPDOOR:
165		    if (Blind)
166			pline("Kerplunk!  You no longer feel %s.",
167				the(xname(otmp)));
168		    else
169			pline("%s%s and %s a %s in the %s!",
170			  Tobjnam(otmp,
171			   (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"),
172			  (ttmp->ttyp == TRAPDOOR) ? nul : " into",
173			  otense(otmp, "plug"),
174			  (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
175			  surface(rx, ry));
176		    deltrap(ttmp);
177		    delobj(otmp);
178		    bury_objs(rx, ry);
179		    if (cansee(rx,ry)) newsym(rx,ry);
180		    continue;
181		case LEVEL_TELEP:
182		case TELEP_TRAP:
183#ifdef STEED
184		    if (u.usteed)
185			pline("%s pushes %s and suddenly it disappears!",
186			      upstart(y_monnam(u.usteed)), the(xname(otmp)));
187		    else
188#endif
189		    You("push %s and suddenly it disappears!",
190			the(xname(otmp)));
191		    if (ttmp->ttyp == TELEP_TRAP)
192			rloco(otmp);
193		    else {
194			int newlev = random_teleport_level();
195			d_level dest;
196
197			if (newlev == depth(&u.uz) || In_endgame(&u.uz))
198			    continue;
199			obj_extract_self(otmp);
200			add_to_migration(otmp);
201			get_level(&dest, newlev);
202			otmp->ox = dest.dnum;
203			otmp->oy = dest.dlevel;
204			otmp->owornmask = (long)MIGR_RANDOM;
205		    }
206		    seetrap(ttmp);
207		    continue;
208		}
209	    if (closed_door(rx, ry))
210		goto nopushmsg;
211	    if (boulder_hits_pool(otmp, rx, ry, TRUE))
212		continue;
213	    /*
214	     * Re-link at top of fobj chain so that pile order is preserved
215	     * when level is restored.
216	     */
217	    if (otmp != fobj) {
218		remove_object(otmp);
219		place_object(otmp, otmp->ox, otmp->oy);
220	    }
221
222	    {
223#ifdef LINT /* static long lastmovetime; */
224		long lastmovetime;
225		lastmovetime = 0;
226#else
227		/* note: reset to zero after save/restore cycle */
228		static NEARDATA long lastmovetime;
229#endif
230#ifdef STEED
231		if (!u.usteed) {
232#endif
233		  if (moves > lastmovetime+2 || moves < lastmovetime)
234		    pline("With %s effort you move %s.",
235			  throws_rocks(youmonst.data) ? "little" : "great",
236			  the(xname(otmp)));
237		  exercise(A_STR, TRUE);
238#ifdef STEED
239		} else
240		    pline("%s moves %s.",
241			  upstart(y_monnam(u.usteed)), the(xname(otmp)));
242#endif
243		lastmovetime = moves;
244	    }
245
246	    /* Move the boulder *after* the message. */
247	    if (glyph_is_invisible(levl[rx][ry].glyph))
248		unmap_object(rx, ry);
249	    movobj(otmp, rx, ry);	/* does newsym(rx,ry) */
250	    if (Blind) {
251		feel_location(rx,ry);
252		feel_location(sx, sy);
253	    } else {
254		newsym(sx, sy);
255	    }
256	} else {
257	nopushmsg:
258#ifdef STEED
259	  if (u.usteed)
260	    pline("%s tries to move %s, but cannot.",
261		  upstart(y_monnam(u.usteed)), the(xname(otmp)));
262	  else
263#endif
264	    You("try to move %s, but in vain.", the(xname(otmp)));
265	    if (Blind) feel_location(sx, sy);
266	cannot_push:
267	    if (throws_rocks(youmonst.data)) {
268#ifdef STEED
269		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
270		    You("aren't skilled enough to %s %s from %s.",
271			(flags.pickup && !In_sokoban(&u.uz))
272			    ? "pick up" : "push aside",
273			the(xname(otmp)), y_monnam(u.usteed));
274		} else
275#endif
276		{
277		    pline("However, you can easily %s.",
278			(flags.pickup && !In_sokoban(&u.uz))
279			    ? "pick it up" : "push it aside");
280		    if (In_sokoban(&u.uz))
281			change_luck(-1);	/* Sokoban guilt */
282		    break;
283		}
284		break;
285	    }
286
287	    if (
288#ifdef STEED
289		!u.usteed &&
290#endif
291		(((!invent || inv_weight() <= -850) &&
292		 (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
293				     && IS_ROCK(levl[sx][u.uy].typ))))
294		|| verysmall(youmonst.data))) {
295		pline("However, you can squeeze yourself into a small opening.");
296		if (In_sokoban(&u.uz))
297		    change_luck(-1);	/* Sokoban guilt */
298		break;
299	    } else
300		return (-1);
301	}
302    }
303    return (0);
304}
305
306/*
307 *  still_chewing()
308 *
309 *  Chew on a wall, door, or boulder.  Returns TRUE if still eating, FALSE
310 *  when done.
311 */
312STATIC_OVL int
313still_chewing(x,y)
314    xchar x, y;
315{
316    struct rm *lev = &levl[x][y];
317    struct obj *boulder = sobj_at(BOULDER,x,y);
318    const char *digtxt = (char *)0, *dmgtxt = (char *)0;
319
320    if (digging.down)		/* not continuing previous dig (w/ pick-axe) */
321	(void) memset((genericptr_t)&digging, 0, sizeof digging);
322
323    if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) {
324	You("hurt your teeth on the %s.",
325	    IS_TREE(lev->typ) ? "tree" : "hard stone");
326	nomul(0);
327	return 1;
328    } else if (digging.pos.x != x || digging.pos.y != y ||
329		!on_level(&digging.level, &u.uz)) {
330	digging.down = FALSE;
331	digging.chew = TRUE;
332	digging.warned = FALSE;
333	digging.pos.x = x;
334	digging.pos.y = y;
335	assign_level(&digging.level, &u.uz);
336	/* solid rock takes more work & time to dig through */
337	digging.effort =
338	    (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
339	You("start chewing %s %s.",
340	    (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the",
341	    boulder ? "boulder" :
342	    IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door");
343	watch_dig((struct monst *)0, x, y, FALSE);
344	return 1;
345    } else if ((digging.effort += (30 + u.udaminc)) <= 100)  {
346	if (flags.verbose)
347	    You("%s chewing on the %s.",
348		digging.chew ? "continue" : "begin",
349		boulder ? "boulder" :
350		IS_TREE(lev->typ) ? "tree" :
351		IS_ROCK(lev->typ) ? "rock" : "door");
352	digging.chew = TRUE;
353	watch_dig((struct monst *)0, x, y, FALSE);
354	return 1;
355    }
356
357    /* Okay, you've chewed through something */
358    u.uconduct.food++;
359    u.uhunger += rnd(20);
360
361    if (boulder) {
362	delobj(boulder);		/* boulder goes bye-bye */
363	You("eat the boulder.");	/* yum */
364
365	/*
366	 *  The location could still block because of
367	 *	1. More than one boulder
368	 *	2. Boulder stuck in a wall/stone/door.
369	 *
370	 *  [perhaps use does_block() below (from vision.c)]
371	 */
372	if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) {
373	    block_point(x,y);	/* delobj will unblock the point */
374	    /* reset dig state */
375	    (void) memset((genericptr_t)&digging, 0, sizeof digging);
376	    return 1;
377	}
378
379    } else if (IS_WALL(lev->typ)) {
380	if (*in_rooms(x, y, SHOPBASE)) {
381	    add_damage(x, y, 10L * ACURRSTR);
382	    dmgtxt = "damage";
383	}
384	digtxt = "chew a hole in the wall.";
385	if (level.flags.is_maze_lev) {
386	    lev->typ = ROOM;
387	} else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
388	    lev->typ = CORR;
389	} else {
390	    lev->typ = DOOR;
391	    lev->doormask = D_NODOOR;
392	}
393    } else if (IS_TREE(lev->typ)) {
394	digtxt = "chew through the tree.";
395	lev->typ = ROOM;
396    } else if (lev->typ == SDOOR) {
397	if (lev->doormask & D_TRAPPED) {
398	    lev->doormask = D_NODOOR;
399	    b_trapped("secret door", 0);
400	} else {
401	    digtxt = "chew through the secret door.";
402	    lev->doormask = D_BROKEN;
403	}
404	lev->typ = DOOR;
405
406    } else if (IS_DOOR(lev->typ)) {
407	if (*in_rooms(x, y, SHOPBASE)) {
408	    add_damage(x, y, 400L);
409	    dmgtxt = "break";
410	}
411	if (lev->doormask & D_TRAPPED) {
412	    lev->doormask = D_NODOOR;
413	    b_trapped("door", 0);
414	} else {
415	    digtxt = "chew through the door.";
416	    lev->doormask = D_BROKEN;
417	}
418
419    } else { /* STONE or SCORR */
420	digtxt = "chew a passage through the rock.";
421	lev->typ = CORR;
422    }
423
424    unblock_point(x, y);	/* vision */
425    newsym(x, y);
426    if (digtxt) You(digtxt);	/* after newsym */
427    if (dmgtxt) pay_for_damage(dmgtxt, FALSE);
428    (void) memset((genericptr_t)&digging, 0, sizeof digging);
429    return 0;
430}
431
432#endif /* OVL2 */
433#ifdef OVLB
434
435void
436movobj(obj, ox, oy)
437register struct obj *obj;
438register xchar ox, oy;
439{
440	/* optimize by leaving on the fobj chain? */
441	remove_object(obj);
442	newsym(obj->ox, obj->oy);
443	place_object(obj, ox, oy);
444	newsym(ox, oy);
445}
446
447#ifdef SINKS
448static NEARDATA const char fell_on_sink[] = "fell onto a sink";
449
450STATIC_OVL void
451dosinkfall()
452{
453	register struct obj *obj;
454
455	if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) {
456	    You("wobble unsteadily for a moment.");
457	} else {
458	    long save_ELev = ELevitation, save_HLev = HLevitation;
459
460	    /* fake removal of levitation in advance so that final
461	       disclosure will be right in case this turns out to
462	       be fatal; fortunately the fact that rings and boots
463	       are really still worn has no effect on bones data */
464	    ELevitation = HLevitation = 0L;
465	    You("crash to the floor!");
466	    losehp(rn1(8, 25 - (int)ACURR(A_CON)),
467		   fell_on_sink, NO_KILLER_PREFIX);
468	    exercise(A_DEX, FALSE);
469	    selftouch("Falling, you");
470	    for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
471		if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
472		    You("fell on %s.", doname(obj));
473		    losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX);
474		    exercise(A_CON, FALSE);
475		}
476	    ELevitation = save_ELev;
477	    HLevitation = save_HLev;
478	}
479
480	ELevitation &= ~W_ARTI;
481	HLevitation &= ~(I_SPECIAL|TIMEOUT);
482	HLevitation++;
483	if(uleft && uleft->otyp == RIN_LEVITATION) {
484	    obj = uleft;
485	    Ring_off(obj);
486	    off_msg(obj);
487	}
488	if(uright && uright->otyp == RIN_LEVITATION) {
489	    obj = uright;
490	    Ring_off(obj);
491	    off_msg(obj);
492	}
493	if(uarmf && uarmf->otyp == LEVITATION_BOOTS) {
494	    obj = uarmf;
495	    (void)Boots_off();
496	    off_msg(obj);
497	}
498	HLevitation--;
499}
500#endif
501
502boolean
503may_dig(x,y)
504register xchar x,y;
505/* intended to be called only on ROCKs */
506{
507    return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
508			(levl[x][y].wall_info & W_NONDIGGABLE)));
509}
510
511boolean
512may_passwall(x,y)
513register xchar x,y;
514{
515   return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
516			(levl[x][y].wall_info & W_NONPASSWALL)));
517}
518
519#endif /* OVLB */
520#ifdef OVL1
521
522boolean
523bad_rock(mdat,x,y)
524struct permonst *mdat;
525register xchar x,y;
526{
527	return((boolean) ((In_sokoban(&u.uz) && sobj_at(BOULDER,x,y)) ||
528	       (IS_ROCK(levl[x][y].typ)
529		    && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y))
530		    && !(passes_walls(mdat) && may_passwall(x,y)))));
531}
532
533boolean
534invocation_pos(x, y)
535xchar x, y;
536{
537	return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y));
538}
539
540#endif /* OVL1 */
541#ifdef OVL3
542
543/* return TRUE if (dx,dy) is an OK place to move
544 * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV
545 */
546boolean
547test_move(ux, uy, dx, dy, mode)
548int ux, uy, dx, dy;
549int mode;
550{
551    int x = ux+dx;
552    int y = uy+dy;
553    register struct rm *tmpr = &levl[x][y];
554    register struct rm *ust;
555
556    /*
557     *  Check for physical obstacles.  First, the place we are going.
558     */
559    if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
560	if (Blind && mode == DO_MOVE) feel_location(x,y);
561	if (Passes_walls && may_passwall(x,y)) {
562	    ;	/* do nothing */
563	} else if (tmpr->typ == IRONBARS) {
564	    if (!(Passes_walls || passes_bars(youmonst.data)))
565		return FALSE;
566	} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
567	    /* Eat the rock. */
568	    if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
569	} else if (flags.autodig && !flags.run && !flags.nopick &&
570		   uwep && is_pick(uwep)) {
571	/* MRKR: Automatic digging when wielding the appropriate tool */
572	    if (mode == DO_MOVE)
573		(void) use_pick_axe2(uwep);
574	    return FALSE;
575	} else {
576	    if (mode == DO_MOVE) {
577		if (Is_stronghold(&u.uz) && is_db_wall(x,y))
578		    pline_The("drawbridge is up!");
579		if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz))
580		    pline_The("Sokoban walls resist your ability.");
581	    }
582	    return FALSE;
583	}
584    } else if (IS_DOOR(tmpr->typ)) {
585	if (closed_door(x,y)) {
586	    if (Blind && mode == DO_MOVE) feel_location(x,y);
587	    if (Passes_walls)
588		;	/* do nothing */
589	    else if (can_ooze(&youmonst)) {
590		if (mode == DO_MOVE) You("ooze under the door.");
591	    } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
592		/* Eat the door. */
593		if (mode == DO_MOVE && still_chewing(x,y)) return FALSE;
594	    } else {
595		if (mode == DO_MOVE) {
596		    if (amorphous(youmonst.data))
597			You("try to ooze under the door, but can't squeeze your possessions through.");
598		    else if (x == ux || y == uy) {
599			if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {
600#ifdef STEED
601			    if (u.usteed) {
602				You_cant("lead %s through that closed door.",
603				         y_monnam(u.usteed));
604			    } else
605#endif
606			    {
607			        pline("Ouch!  You bump into a door.");
608			        exercise(A_DEX, FALSE);
609			    }
610			} else pline("That door is closed.");
611		    }
612		} else if (mode == TEST_TRAV) goto testdiag;
613		return FALSE;
614	    }
615	} else {
616	testdiag:
617	    if (dx && dy && !Passes_walls
618		&& ((tmpr->doormask & ~D_BROKEN)
619#ifdef REINCARNATION
620		    || Is_rogue_level(&u.uz)
621#endif
622		    || block_door(x,y))) {
623		/* Diagonal moves into a door are not allowed. */
624		if (Blind && mode == DO_MOVE)
625		    feel_location(x,y);
626		return FALSE;
627	    }
628	}
629    }
630    if (dx && dy
631	    && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) {
632	/* Move at a diagonal. */
633	if (In_sokoban(&u.uz)) {
634	    if (mode == DO_MOVE)
635		You("cannot pass that way.");
636	    return FALSE;
637	}
638	if (bigmonst(youmonst.data)) {
639	    if (mode == DO_MOVE)
640		Your("body is too large to fit through.");
641	    return FALSE;
642	}
643	if (invent && (inv_weight() + weight_cap() > 600)) {
644	    if (mode == DO_MOVE)
645		You("are carrying too much to get through.");
646	    return FALSE;
647	}
648    }
649    /* Pick travel path that does not require crossing a trap.
650     * Avoid water and lava using the usual running rules.
651     * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
652    if (flags.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) {
653	struct trap* t = t_at(x, y);
654
655	if ((t && t->tseen) ||
656	    (!Levitation && !Flying &&
657	     !is_clinger(youmonst.data) &&
658	     (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv))
659	    return FALSE;
660    }
661
662    ust = &levl[ux][uy];
663
664    /* Now see if other things block our way . . */
665    if (dx && dy && !Passes_walls
666		     && (IS_DOOR(ust->typ) && ((ust->doormask & ~D_BROKEN)
667#ifdef REINCARNATION
668			     || Is_rogue_level(&u.uz)
669#endif
670			     || block_entry(x, y))
671			 )) {
672	/* Can't move at a diagonal out of a doorway with door. */
673	return FALSE;
674    }
675
676    if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) {
677	if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV)
678	    return FALSE;
679	if (mode == DO_MOVE) {
680	    /* tunneling monsters will chew before pushing */
681	    if (tunnels(youmonst.data) && !needspick(youmonst.data) &&
682		!In_sokoban(&u.uz)) {
683		if (still_chewing(x,y)) return FALSE;
684	    } else
685		if (moverock() < 0) return FALSE;
686	} else if (mode == TEST_TRAV) {
687	    struct obj* obj;
688
689	    /* don't pick two boulders in a row, unless there's a way thru */
690	    if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) {
691		if (!Passes_walls &&
692		    !(tunnels(youmonst.data) && !needspick(youmonst.data)) &&
693		    !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) &&
694		    !((obj = carrying(WAN_DIGGING)) &&
695		      !objects[obj->otyp].oc_name_known))
696		    return FALSE;
697	    }
698	}
699	/* assume you'll be able to push it when you get there... */
700    }
701
702    /* OK, it is a legal place to move. */
703    return TRUE;
704}
705
706/*
707 * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
708 * A shortest path is returned.  If guess is TRUE, consider various
709 * inaccessible locations as valid intermediate path points.
710 * Returns TRUE if a path was found.
711 */
712static boolean
713findtravelpath(guess)
714boolean guess;
715{
716    /* if travel to adjacent, reachable location, use normal movement rules */
717    if (!guess && iflags.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1) {
718	flags.run = 0;
719	if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) {
720	    u.dx = u.tx-u.ux;
721	    u.dy = u.ty-u.uy;
722	    nomul(0);
723	    iflags.travelcc.x = iflags.travelcc.y = -1;
724	    return TRUE;
725	}
726	flags.run = 8;
727    }
728    if (u.tx != u.ux || u.ty != u.uy) {
729	xchar travel[COLNO][ROWNO];
730	xchar travelstepx[2][COLNO*ROWNO];
731	xchar travelstepy[2][COLNO*ROWNO];
732	xchar tx, ty, ux, uy;
733	int n = 1;			/* max offset in travelsteps */
734	int set = 0;			/* two sets current and previous */
735	int radius = 1;			/* search radius */
736	int i;
737
738	/* If guessing, first find an "obvious" goal location.  The obvious
739	 * goal is the position the player knows of, or might figure out
740	 * (couldsee) that is closest to the target on a straight path.
741	 */
742	if (guess) {
743	    tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty;
744	} else {
745	    tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy;
746	}
747
748    noguess:
749	(void) memset((genericptr_t)travel, 0, sizeof(travel));
750	travelstepx[0][0] = tx;
751	travelstepy[0][0] = ty;
752
753	while (n != 0) {
754	    int nn = 0;
755
756	    for (i = 0; i < n; i++) {
757		int dir;
758		int x = travelstepx[set][i];
759		int y = travelstepy[set][i];
760		static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
761		/* no diagonal movement for grid bugs */
762		int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8;
763
764		for (dir = 0; dir < dirmax; ++dir) {
765		    int nx = x+xdir[ordered[dir]];
766		    int ny = y+ydir[ordered[dir]];
767
768		    if (!isok(nx, ny)) continue;
769		    if ((!Passes_walls && !can_ooze(&youmonst) &&
770			closed_door(x, y)) || sobj_at(BOULDER, x, y)) {
771			/* closed doors and boulders usually
772			 * cause a delay, so prefer another path */
773			if (travel[x][y] > radius-3) {
774			    travelstepx[1-set][nn] = x;
775			    travelstepy[1-set][nn] = y;
776			    /* don't change travel matrix! */
777			    nn++;
778			    continue;
779			}
780		    }
781		    if (test_move(x, y, nx-x, ny-y, TEST_TRAV) &&
782			(levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) {
783			if (nx == ux && ny == uy) {
784			    if (!guess) {
785				u.dx = x-ux;
786				u.dy = y-uy;
787				if (x == u.tx && y == u.ty) {
788				    nomul(0);
789				    /* reset run so domove run checks work */
790				    flags.run = 8;
791				    iflags.travelcc.x = iflags.travelcc.y = -1;
792				}
793				return TRUE;
794			    }
795			} else if (!travel[nx][ny]) {
796			    travelstepx[1-set][nn] = nx;
797			    travelstepy[1-set][nn] = ny;
798			    travel[nx][ny] = radius;
799			    nn++;
800			}
801		    }
802		}
803	    }
804
805	    n = nn;
806	    set = 1-set;
807	    radius++;
808	}
809
810	/* if guessing, find best location in travel matrix and go there */
811	if (guess) {
812	    int px = tx, py = ty;	/* pick location */
813	    int dist, nxtdist, d2, nd2;
814
815	    dist = distmin(ux, uy, tx, ty);
816	    d2 = dist2(ux, uy, tx, ty);
817	    for (tx = 1; tx < COLNO; ++tx)
818		for (ty = 0; ty < ROWNO; ++ty)
819		    if (travel[tx][ty]) {
820			nxtdist = distmin(ux, uy, tx, ty);
821			if (nxtdist == dist && couldsee(tx, ty)) {
822			    nd2 = dist2(ux, uy, tx, ty);
823			    if (nd2 < d2) {
824				/* prefer non-zigzag path */
825				px = tx; py = ty;
826				d2 = nd2;
827			    }
828			} else if (nxtdist < dist && couldsee(tx, ty)) {
829			    px = tx; py = ty;
830			    dist = nxtdist;
831			    d2 = dist2(ux, uy, tx, ty);
832			}
833		    }
834
835	    if (px == u.ux && py == u.uy) {
836		/* no guesses, just go in the general direction */
837		u.dx = sgn(u.tx - u.ux);
838		u.dy = sgn(u.ty - u.uy);
839		if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
840		    return TRUE;
841		goto found;
842	    }
843	    tx = px;
844	    ty = py;
845	    ux = u.ux;
846	    uy = u.uy;
847	    set = 0;
848	    n = radius = 1;
849	    guess = FALSE;
850	    goto noguess;
851	}
852	return FALSE;
853    }
854
855found:
856    u.dx = 0;
857    u.dy = 0;
858    nomul(0);
859    return FALSE;
860}
861
862void
863domove()
864{
865	register struct monst *mtmp;
866	register struct rm *tmpr;
867	register xchar x,y;
868	struct trap *trap;
869	int wtcap;
870	boolean on_ice;
871	xchar chainx, chainy, ballx, bally;	/* ball&chain new positions */
872	int bc_control;				/* control for ball&chain */
873	boolean cause_delay = FALSE;	/* dragging ball will skip a move */
874	const char *predicament;
875
876	u_wipe_engr(rnd(5));
877
878	if (flags.travel) {
879	    if (!findtravelpath(FALSE))
880		(void) findtravelpath(TRUE);
881	    iflags.travel1 = 0;
882	}
883
884	if(((wtcap = near_capacity()) >= OVERLOADED
885	    || (wtcap > SLT_ENCUMBER &&
886		(Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
887			: (u.uhp < 10 && u.uhp != u.uhpmax))))
888	   && !Is_airlevel(&u.uz)) {
889	    if(wtcap < OVERLOADED) {
890		You("don't have enough stamina to move.");
891		exercise(A_CON, FALSE);
892	    } else
893		You("collapse under your load.");
894	    nomul(0);
895	    return;
896	}
897	if(u.uswallow) {
898		u.dx = u.dy = 0;
899		u.ux = x = u.ustuck->mx;
900		u.uy = y = u.ustuck->my;
901		mtmp = u.ustuck;
902	} else {
903		if (Is_airlevel(&u.uz) && rn2(4) &&
904			!Levitation && !Flying) {
905		    switch(rn2(3)) {
906		    case 0:
907			You("tumble in place.");
908			exercise(A_DEX, FALSE);
909			break;
910		    case 1:
911			You_cant("control your movements very well."); break;
912		    case 2:
913			pline("It's hard to walk in thin air.");
914			exercise(A_DEX, TRUE);
915			break;
916		    }
917		    return;
918		}
919
920		/* check slippery ice */
921		on_ice = !Levitation && is_ice(u.ux, u.uy);
922		if (on_ice) {
923		    static int skates = 0;
924		    if (!skates) skates = find_skates();
925		    if ((uarmf && uarmf->otyp == skates)
926			    || resists_cold(&youmonst) || Flying
927			    || is_floater(youmonst.data) || is_clinger(youmonst.data)
928			    || is_whirly(youmonst.data))
929			on_ice = FALSE;
930		    else if (!rn2(Cold_resistance ? 3 : 2)) {
931			HFumbling |= FROMOUTSIDE;
932			HFumbling &= ~TIMEOUT;
933			HFumbling += 1;  /* slip on next move */
934		    }
935		}
936		if (!on_ice && (HFumbling & FROMOUTSIDE))
937		    HFumbling &= ~FROMOUTSIDE;
938
939		x = u.ux + u.dx;
940		y = u.uy + u.dy;
941		if(Stunned || (Confusion && !rn2(5))) {
942			register int tries = 0;
943
944			do {
945				if(tries++ > 50) {
946					nomul(0);
947					return;
948				}
949				confdir();
950				x = u.ux + u.dx;
951				y = u.uy + u.dy;
952			} while(!isok(x, y) || bad_rock(youmonst.data, x, y));
953		}
954		/* turbulence might alter your actual destination */
955		if (u.uinwater) {
956			water_friction();
957			if (!u.dx && !u.dy) {
958				nomul(0);
959				return;
960			}
961			x = u.ux + u.dx;
962			y = u.uy + u.dy;
963		}
964		if(!isok(x, y)) {
965			nomul(0);
966			return;
967		}
968		if (((trap = t_at(x, y)) && trap->tseen) ||
969		    (Blind && !Levitation && !Flying &&
970		     !is_clinger(youmonst.data) &&
971		     (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) {
972			if(flags.run >= 2) {
973				nomul(0);
974				flags.move = 0;
975				return;
976			} else
977				nomul(0);
978		}
979
980		if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
981		    if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
982			/* perhaps it fled (or was teleported or ... ) */
983			u.ustuck = 0;
984		    } else if (sticks(youmonst.data)) {
985			/* When polymorphed into a sticking monster,
986			 * u.ustuck means it's stuck to you, not you to it.
987			 */
988			You("release %s.", mon_nam(u.ustuck));
989			u.ustuck = 0;
990		    } else {
991			/* If holder is asleep or paralyzed:
992			 *	37.5% chance of getting away,
993			 *	12.5% chance of waking/releasing it;
994			 * otherwise:
995			 *	 7.5% chance of getting away.
996			 * [strength ought to be a factor]
997			 * If holder is tame and there is no conflict,
998			 * guaranteed escape.
999			 */
1000			switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
1001			case 0: case 1: case 2:
1002			pull_free:
1003			    You("pull free from %s.", mon_nam(u.ustuck));
1004			    u.ustuck = 0;
1005			    break;
1006			case 3:
1007			    if (!u.ustuck->mcanmove) {
1008				/* it's free to move on next turn */
1009				u.ustuck->mfrozen = 1;
1010				u.ustuck->msleeping = 0;
1011			    }
1012			    /*FALLTHRU*/
1013			default:
1014			    if (u.ustuck->mtame &&
1015				!Conflict && !u.ustuck->mconf)
1016				goto pull_free;
1017			    You("cannot escape from %s!", mon_nam(u.ustuck));
1018			    nomul(0);
1019			    return;
1020			}
1021		    }
1022		}
1023
1024		mtmp = m_at(x,y);
1025		if (mtmp) {
1026			/* Don't attack if you're running, and can see it */
1027			/* We should never get here if forcefight */
1028			if (flags.run &&
1029			    ((!Blind && mon_visible(mtmp) &&
1030			      ((mtmp->m_ap_type != M_AP_FURNITURE &&
1031				mtmp->m_ap_type != M_AP_OBJECT) ||
1032			       Protection_from_shape_changers)) ||
1033			     sensemon(mtmp))) {
1034				nomul(0);
1035				flags.move = 0;
1036				return;
1037			}
1038		}
1039	}
1040
1041	u.ux0 = u.ux;
1042	u.uy0 = u.uy;
1043	bhitpos.x = x;
1044	bhitpos.y = y;
1045	tmpr = &levl[x][y];
1046
1047	/* attack monster */
1048	if(mtmp) {
1049	    nomul(0);
1050	    /* only attack if we know it's there */
1051	    /* or if we used the 'F' command to fight blindly */
1052	    /* or if it hides_under, in which case we call attack() to print
1053	     * the Wait! message.
1054	     * This is different from ceiling hiders, who aren't handled in
1055	     * attack().
1056	     */
1057
1058	    /* If they used a 'm' command, trying to move onto a monster
1059	     * prints the below message and wastes a turn.  The exception is
1060	     * if the monster is unseen and the player doesn't remember an
1061	     * invisible monster--then, we fall through to attack() and
1062	     * attack_check(), which still wastes a turn, but prints a
1063	     * different message and makes the player remember the monster.		     */
1064	    if(flags.nopick &&
1065		  (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
1066		if(mtmp->m_ap_type && !Protection_from_shape_changers
1067						    && !sensemon(mtmp))
1068		    stumble_onto_mimic(mtmp);
1069		else if (mtmp->mpeaceful && !Hallucination)
1070		    pline("Pardon me, %s.", m_monnam(mtmp));
1071		else
1072		    You("move right into %s.", mon_nam(mtmp));
1073		return;
1074	    }
1075	    if(flags.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
1076		    ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
1077			!is_safepet(mtmp))){
1078		gethungry();
1079		if(wtcap >= HVY_ENCUMBER && moves%3) {
1080		    if (Upolyd && u.mh > 1) {
1081			u.mh--;
1082		    } else if (!Upolyd && u.uhp > 1) {
1083			u.uhp--;
1084		    } else {
1085			You("pass out from exertion!");
1086			exercise(A_CON, FALSE);
1087			fall_asleep(-10, FALSE);
1088		    }
1089		}
1090		if(multi < 0) return;	/* we just fainted */
1091
1092		/* try to attack; note that it might evade */
1093		/* also, we don't attack tame when _safepet_ */
1094		if(attack(mtmp)) return;
1095	    }
1096	}
1097
1098	/* specifying 'F' with no monster wastes a turn */
1099	if (flags.forcefight ||
1100	    /* remembered an 'I' && didn't use a move command */
1101	    (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) {
1102		boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL));
1103	    	char buf[BUFSZ];
1104		Sprintf(buf,"a vacant spot on the %s", surface(x,y));
1105		You("%s %s.",
1106		    expl ? "explode at" : "attack",
1107		    !Underwater ? "thin air" :
1108		    is_pool(x,y) ? "empty water" : buf);
1109		unmap_object(x, y); /* known empty -- remove 'I' if present */
1110		newsym(x, y);
1111		nomul(0);
1112		if (expl) {
1113		    u.mh = -1;		/* dead in the current form */
1114		    rehumanize();
1115		}
1116		return;
1117	}
1118	if (glyph_is_invisible(levl[x][y].glyph)) {
1119	    unmap_object(x, y);
1120	    newsym(x, y);
1121	}
1122	/* not attacking an animal, so we try to move */
1123#ifdef STEED
1124	if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) {
1125		pline("%s won't move!", upstart(y_monnam(u.usteed)));
1126		nomul(0);
1127		return;
1128	} else
1129#endif
1130	if(!youmonst.data->mmove) {
1131		You("are rooted %s.",
1132		    Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
1133		    "in place" : "to the ground");
1134		nomul(0);
1135		return;
1136	}
1137	if(u.utrap) {
1138		if(u.utraptype == TT_PIT) {
1139		    if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) {
1140			Your("%s gets stuck in a crevice.", body_part(LEG));
1141			display_nhwindow(WIN_MESSAGE, FALSE);
1142			clear_nhwindow(WIN_MESSAGE);
1143			You("free your %s.", body_part(LEG));
1144		    } else if (!(--u.utrap)) {
1145			You("%s to the edge of the pit.",
1146				(In_sokoban(&u.uz) && Levitation) ?
1147				"struggle against the air currents and float" :
1148#ifdef STEED
1149				u.usteed ? "ride" :
1150#endif
1151				"crawl");
1152			fill_pit(u.ux, u.uy);
1153			vision_full_recalc = 1;	/* vision limits change */
1154		    } else if (flags.verbose) {
1155#ifdef STEED
1156			if (u.usteed)
1157			    Norep("%s is still in a pit.",
1158				  upstart(y_monnam(u.usteed)));
1159			else
1160#endif
1161			Norep( (Hallucination && !rn2(5)) ?
1162				"You've fallen, and you can't get up." :
1163				"You are still in a pit." );
1164		    }
1165		} else if (u.utraptype == TT_LAVA) {
1166		    if(flags.verbose) {
1167			predicament = "stuck in the lava";
1168#ifdef STEED
1169			if (u.usteed)
1170			    Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1171				  predicament);
1172			else
1173#endif
1174			Norep("You are %s.", predicament);
1175		    }
1176		    if(!is_lava(x,y)) {
1177			u.utrap--;
1178			if((u.utrap & 0xff) == 0) {
1179#ifdef STEED
1180			    if (u.usteed)
1181				You("lead %s to the edge of the lava.",
1182				    y_monnam(u.usteed));
1183			    else
1184#endif
1185			     You("pull yourself to the edge of the lava.");
1186			    u.utrap = 0;
1187			}
1188		    }
1189		    u.umoved = TRUE;
1190		} else if (u.utraptype == TT_WEB) {
1191		    if(uwep && uwep->oartifact == ART_STING) {
1192			u.utrap = 0;
1193			pline("Sting cuts through the web!");
1194			return;
1195		    }
1196		    if(--u.utrap) {
1197			if(flags.verbose) {
1198			    predicament = "stuck to the web";
1199#ifdef STEED
1200			    if (u.usteed)
1201				Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1202				      predicament);
1203			    else
1204#endif
1205			    Norep("You are %s.", predicament);
1206			}
1207		    } else {
1208#ifdef STEED
1209			if (u.usteed)
1210			    pline("%s breaks out of the web.",
1211				  upstart(y_monnam(u.usteed)));
1212			else
1213#endif
1214			You("disentangle yourself.");
1215		    }
1216		} else if (u.utraptype == TT_INFLOOR) {
1217		    if(--u.utrap) {
1218			if(flags.verbose) {
1219			    predicament = "stuck in the";
1220#ifdef STEED
1221			    if (u.usteed)
1222				Norep("%s is %s %s.",
1223				      upstart(y_monnam(u.usteed)),
1224				      predicament, surface(u.ux, u.uy));
1225			    else
1226#endif
1227			    Norep("You are %s %s.", predicament,
1228				  surface(u.ux, u.uy));
1229			}
1230		    } else {
1231#ifdef STEED
1232			if (u.usteed)
1233			    pline("%s finally wiggles free.",
1234				  upstart(y_monnam(u.usteed)));
1235			else
1236#endif
1237			You("finally wiggle free.");
1238		    }
1239		} else {
1240		    if(flags.verbose) {
1241			predicament = "caught in a bear trap";
1242#ifdef STEED
1243			if (u.usteed)
1244			    Norep("%s is %s.", upstart(y_monnam(u.usteed)),
1245				  predicament);
1246			else
1247#endif
1248			Norep("You are %s.", predicament);
1249		    }
1250		    if((u.dx && u.dy) || !rn2(5)) u.utrap--;
1251		}
1252		return;
1253	}
1254
1255	if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
1256	    flags.move = 0;
1257	    nomul(0);
1258	    return;
1259	}
1260
1261	/* Move ball and chain.  */
1262	if (Punished)
1263	    if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
1264			&cause_delay, TRUE))
1265		return;
1266
1267	/* Check regions entering/leaving */
1268	if (!in_out_region(x,y))
1269	    return;
1270
1271 	/* now move the hero */
1272	mtmp = m_at(x, y);
1273	u.ux += u.dx;
1274	u.uy += u.dy;
1275#ifdef STEED
1276	/* Move your steed, too */
1277	if (u.usteed) {
1278		u.usteed->mx = u.ux;
1279		u.usteed->my = u.uy;
1280		exercise_steed();
1281	}
1282#endif
1283
1284	/*
1285	 * If safepet at destination then move the pet to the hero's
1286	 * previous location using the same conditions as in attack().
1287	 * there are special extenuating circumstances:
1288	 * (1) if the pet dies then your god angers,
1289	 * (2) if the pet gets trapped then your god may disapprove,
1290	 * (3) if the pet was already trapped and you attempt to free it
1291	 * not only do you encounter the trap but you may frighten your
1292	 * pet causing it to go wild!  moral: don't abuse this privilege.
1293	 *
1294	 * Ceiling-hiding pets are skipped by this section of code, to
1295	 * be caught by the normal falling-monster code.
1296	 */
1297	if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
1298	    /* if trapped, there's a chance the pet goes wild */
1299	    if (mtmp->mtrapped) {
1300		if (!rn2(mtmp->mtame)) {
1301		    mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
1302		    if (mtmp->mleashed) m_unleash(mtmp, TRUE);
1303		    growl(mtmp);
1304		} else {
1305		    yelp(mtmp);
1306		}
1307	    }
1308	    mtmp->mundetected = 0;
1309	    if (mtmp->m_ap_type) seemimic(mtmp);
1310	    else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
1311
1312	    if (mtmp->mtrapped &&
1313		    (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
1314		    (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
1315		    sobj_at(BOULDER, trap->tx, trap->ty)) {
1316		/* can't swap places with pet pinned in a pit by a boulder */
1317		u.ux = u.ux0,  u.uy = u.uy0;	/* didn't move after all */
1318	    } else if (u.ux0 != x && u.uy0 != y &&
1319		       bad_rock(mtmp->data, x, u.uy0) &&
1320		       bad_rock(mtmp->data, u.ux0, y) &&
1321		       (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
1322		/* can't swap places when pet won't fit thru the opening */
1323		u.ux = u.ux0,  u.uy = u.uy0;	/* didn't move after all */
1324		You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
1325	    } else {
1326		char pnambuf[BUFSZ];
1327
1328		/* save its current description in case of polymorph */
1329		Strcpy(pnambuf, y_monnam(mtmp));
1330		mtmp->mtrapped = 0;
1331		remove_monster(x, y);
1332		place_monster(mtmp, u.ux0, u.uy0);
1333
1334		/* check for displacing it into pools and traps */
1335		switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
1336		case 0:
1337		    You("%s %s.", mtmp->mtame ? "displaced" : "frightened",
1338			pnambuf);
1339		    break;
1340		case 1:		/* trapped */
1341		case 3:		/* changed levels */
1342		    /* there's already been a trap message, reinforce it */
1343		    abuse_dog(mtmp);
1344		    adjalign(-3);
1345		    break;
1346		case 2:
1347		    /* it may have drowned or died.  that's no way to
1348		     * treat a pet!  your god gets angry.
1349		     */
1350		    if (rn2(4)) {
1351			You_feel("guilty about losing your pet like this.");
1352			u.ugangr++;
1353			adjalign(-15);
1354		    }
1355
1356		    /* you killed your pet by direct action.
1357		     * minliquid and mintrap don't know to do this
1358		     */
1359		    u.uconduct.killer++;
1360		    break;
1361		default:
1362		    pline("that's strange, unknown mintrap result!");
1363		    break;
1364		}
1365	    }
1366	}
1367
1368	reset_occupations();
1369	if (flags.run) {
1370	    if ( flags.run < 8 )
1371		if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
1372			IS_FURNITURE(tmpr->typ))
1373		    nomul(0);
1374	}
1375
1376	if (hides_under(youmonst.data))
1377	    u.uundetected = OBJ_AT(u.ux, u.uy);
1378	else if (youmonst.data->mlet == S_EEL)
1379	    u.uundetected = is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz);
1380	else if (u.dx || u.dy)
1381	    u.uundetected = 0;
1382
1383	/*
1384	 * Mimics (or whatever) become noticeable if they move and are
1385	 * imitating something that doesn't move.  We could extend this
1386	 * to non-moving monsters...
1387	 */
1388	if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
1389				|| youmonst.m_ap_type == M_AP_FURNITURE))
1390	    youmonst.m_ap_type = M_AP_NOTHING;
1391
1392	check_leash(u.ux0,u.uy0);
1393
1394	if(u.ux0 != u.ux || u.uy0 != u.uy) {
1395	    u.umoved = TRUE;
1396	    /* Clean old position -- vision_recalc() will print our new one. */
1397	    newsym(u.ux0,u.uy0);
1398	    /* Since the hero has moved, adjust what can be seen/unseen. */
1399	    vision_recalc(1);	/* Do the work now in the recover time. */
1400	    invocation_message();
1401	}
1402
1403	if (Punished)				/* put back ball and chain */
1404	    move_bc(0,bc_control,ballx,bally,chainx,chainy);
1405
1406	spoteffects(TRUE);
1407
1408	/* delay next move because of ball dragging */
1409	/* must come after we finished picking up, in spoteffects() */
1410	if (cause_delay) {
1411	    nomul(-2);
1412	    nomovemsg = "";
1413	}
1414
1415	if (flags.run && iflags.runmode != RUN_TPORT) {
1416	    /* display every step or every 7th step depending upon mode */
1417	    if (iflags.runmode != RUN_LEAP || !(moves % 7L)) {
1418		if (flags.time) flags.botl = 1;
1419		curs_on_u();
1420		delay_output();
1421		if (iflags.runmode == RUN_CRAWL) {
1422		    delay_output();
1423		    delay_output();
1424		    delay_output();
1425		    delay_output();
1426		}
1427	    }
1428	}
1429}
1430
1431void
1432invocation_message()
1433{
1434	/* a special clue-msg when on the Invocation position */
1435	if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
1436	    char buf[BUFSZ];
1437	    struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
1438
1439	    nomul(0);		/* stop running or travelling */
1440#ifdef STEED
1441	    if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed));
1442	    else
1443#endif
1444	    if (Levitation || Flying) Strcpy(buf, "beneath you");
1445	    else Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
1446
1447	    You_feel("a strange vibration %s.", buf);
1448	    if (otmp && otmp->spe == 7 && otmp->lamplit)
1449		pline("%s %s!", The(xname(otmp)),
1450		    Blind ? "throbs palpably" : "glows with a strange light");
1451	}
1452}
1453
1454#endif /* OVL3 */
1455#ifdef OVL2
1456
1457void
1458spoteffects(pick)
1459boolean pick;
1460{
1461	register struct monst *mtmp;
1462
1463	if(u.uinwater) {
1464		int was_underwater;
1465
1466		if (!is_pool(u.ux,u.uy)) {
1467			if (Is_waterlevel(&u.uz))
1468				You("pop into an air bubble.");
1469			else if (is_lava(u.ux, u.uy))
1470				You("leave the water...");	/* oops! */
1471			else
1472				You("are on solid %s again.",
1473				    is_ice(u.ux, u.uy) ? "ice" : "land");
1474		}
1475		else if (Is_waterlevel(&u.uz))
1476			goto stillinwater;
1477		else if (Levitation)
1478			You("pop out of the water like a cork!");
1479		else if (Flying)
1480			You("fly out of the water.");
1481		else if (Wwalking)
1482			You("slowly rise above the surface.");
1483		else
1484			goto stillinwater;
1485		was_underwater = Underwater && !Is_waterlevel(&u.uz);
1486		u.uinwater = 0;		/* leave the water */
1487		if (was_underwater) {	/* restore vision */
1488			docrt();
1489			vision_full_recalc = 1;
1490		}
1491	}
1492stillinwater:;
1493	if (!Levitation && !u.ustuck && !Flying) {
1494	    /* limit recursive calls through teleds() */
1495	    if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) {
1496#ifdef STEED
1497		if (u.usteed && !is_flyer(u.usteed->data) &&
1498			!is_floater(u.usteed->data) &&
1499			!is_clinger(u.usteed->data)) {
1500		    dismount_steed(Underwater ?
1501			    DISMOUNT_FELL : DISMOUNT_GENERIC);
1502		    /* dismount_steed() -> float_down() -> pickup() */
1503		    if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz))
1504			pick = FALSE;
1505		} else
1506#endif
1507		if (is_lava(u.ux, u.uy)) {
1508		    if (lava_effects()) return;
1509		} else if (!Wwalking && drown())
1510		    return;
1511	    }
1512	}
1513	check_special_room(FALSE);
1514#ifdef SINKS
1515	if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
1516		dosinkfall();
1517#endif
1518	if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
1519		struct trap *trap = t_at(u.ux, u.uy);
1520		boolean pit;
1521		pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT));
1522		if (trap && pit)
1523			dotrap(trap, 0);	/* fall into pit */
1524		if (pick) (void) pickup(1);
1525		if (trap && !pit)
1526			dotrap(trap, 0);	/* fall into arrow trap, etc. */
1527	}
1528	if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
1529		mtmp->mundetected = mtmp->msleeping = 0;
1530		switch(mtmp->data->mlet) {
1531		    case S_PIERCER:
1532			pline("%s suddenly drops from the %s!",
1533			      Amonnam(mtmp), ceiling(u.ux,u.uy));
1534			if(mtmp->mtame) /* jumps to greet you, not attack */
1535			    ;
1536			else if(uarmh && is_metallic(uarmh))
1537			    pline("Its blow glances off your helmet.");
1538			else if (u.uac + 3 <= rnd(20))
1539			    You("are almost hit by %s!",
1540				x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1541			else {
1542			    int dmg;
1543			    You("are hit by %s!",
1544				x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1545			    dmg = d(4,6);
1546			    if(Half_physical_damage) dmg = (dmg+1) / 2;
1547			    mdamageu(mtmp, dmg);
1548			}
1549			break;
1550		    default:	/* monster surprises you. */
1551			if(mtmp->mtame)
1552			    pline("%s jumps near you from the %s.",
1553					Amonnam(mtmp), ceiling(u.ux,u.uy));
1554			else if(mtmp->mpeaceful) {
1555				You("surprise %s!",
1556				    Blind && !sensemon(mtmp) ?
1557				    something : a_monnam(mtmp));
1558				mtmp->mpeaceful = 0;
1559			} else
1560			    pline("%s attacks you by surprise!",
1561					Amonnam(mtmp));
1562			break;
1563		}
1564		mnexto(mtmp); /* have to move the monster */
1565	}
1566}
1567
1568STATIC_OVL boolean
1569monstinroom(mdat,roomno)
1570struct permonst *mdat;
1571int roomno;
1572{
1573	register struct monst *mtmp;
1574
1575	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1576		if(!DEADMONSTER(mtmp) && mtmp->data == mdat &&
1577		   index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
1578			return(TRUE);
1579	return(FALSE);
1580}
1581
1582char *
1583in_rooms(x, y, typewanted)
1584register xchar x, y;
1585register int typewanted;
1586{
1587	static char buf[5];
1588	char rno, *ptr = &buf[4];
1589	int typefound, min_x, min_y, max_x, max_y_offset, step;
1590	register struct rm *lev;
1591
1592#define goodtype(rno) (!typewanted || \
1593	     ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \
1594	     ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \
1595
1596	switch (rno = levl[x][y].roomno) {
1597		case NO_ROOM:
1598			return(ptr);
1599		case SHARED:
1600			step = 2;
1601			break;
1602		case SHARED_PLUS:
1603			step = 1;
1604			break;
1605		default:			/* i.e. a regular room # */
1606			if (goodtype(rno))
1607				*(--ptr) = rno;
1608			return(ptr);
1609	}
1610
1611	min_x = x - 1;
1612	max_x = x + 1;
1613	if (x < 1)
1614		min_x += step;
1615	else
1616	if (x >= COLNO)
1617		max_x -= step;
1618
1619	min_y = y - 1;
1620	max_y_offset = 2;
1621	if (min_y < 0) {
1622		min_y += step;
1623		max_y_offset -= step;
1624	} else
1625	if ((min_y + max_y_offset) >= ROWNO)
1626		max_y_offset -= step;
1627
1628	for (x = min_x; x <= max_x; x += step) {
1629		lev = &levl[x][min_y];
1630		y = 0;
1631		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1632		    !index(ptr, rno) && goodtype(rno))
1633			*(--ptr) = rno;
1634		y += step;
1635		if (y > max_y_offset)
1636			continue;
1637		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1638		    !index(ptr, rno) && goodtype(rno))
1639			*(--ptr) = rno;
1640		y += step;
1641		if (y > max_y_offset)
1642			continue;
1643		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1644		    !index(ptr, rno) && goodtype(rno))
1645			*(--ptr) = rno;
1646	}
1647	return(ptr);
1648}
1649
1650/* is (x,y) in a town? */
1651boolean
1652in_town(x, y)
1653register int x, y;
1654{
1655	s_level *slev = Is_special(&u.uz);
1656	register struct mkroom *sroom;
1657	boolean has_subrooms = FALSE;
1658
1659	if (!slev || !slev->flags.town) return FALSE;
1660
1661	/*
1662	 * See if (x,y) is in a room with subrooms, if so, assume it's the
1663	 * town.  If there are no subrooms, the whole level is in town.
1664	 */
1665	for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
1666	    if (sroom->nsubrooms > 0) {
1667		has_subrooms = TRUE;
1668		if (inside_room(sroom, x, y)) return TRUE;
1669	    }
1670	}
1671
1672	return !has_subrooms;
1673}
1674
1675STATIC_OVL void
1676move_update(newlev)
1677register boolean newlev;
1678{
1679	char *ptr1, *ptr2, *ptr3, *ptr4;
1680
1681	Strcpy(u.urooms0, u.urooms);
1682	Strcpy(u.ushops0, u.ushops);
1683	if (newlev) {
1684		u.urooms[0] = '\0';
1685		u.uentered[0] = '\0';
1686		u.ushops[0] = '\0';
1687		u.ushops_entered[0] = '\0';
1688		Strcpy(u.ushops_left, u.ushops0);
1689		return;
1690	}
1691	Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
1692
1693	for (ptr1 = &u.urooms[0],
1694	     ptr2 = &u.uentered[0],
1695	     ptr3 = &u.ushops[0],
1696	     ptr4 = &u.ushops_entered[0];
1697	     *ptr1; ptr1++) {
1698		if (!index(u.urooms0, *ptr1))
1699			*(ptr2++) = *ptr1;
1700		if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
1701			*(ptr3++) = *ptr1;
1702			if (!index(u.ushops0, *ptr1))
1703				*(ptr4++) = *ptr1;
1704		}
1705	}
1706	*ptr2 = '\0';
1707	*ptr3 = '\0';
1708	*ptr4 = '\0';
1709
1710	/* filter u.ushops0 -> u.ushops_left */
1711	for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
1712		if (!index(u.ushops, *ptr1))
1713			*(ptr2++) = *ptr1;
1714	*ptr2 = '\0';
1715}
1716
1717void
1718check_special_room(newlev)
1719register boolean newlev;
1720{
1721	register struct monst *mtmp;
1722	char *ptr;
1723
1724	move_update(newlev);
1725
1726	if (*u.ushops0)
1727	    u_left_shop(u.ushops_left, newlev);
1728
1729	if (!*u.uentered && !*u.ushops_entered)		/* implied by newlev */
1730	    return;		/* no entrance messages necessary */
1731
1732	/* Did we just enter a shop? */
1733	if (*u.ushops_entered)
1734	    u_entered_shop(u.ushops_entered);
1735
1736	for (ptr = &u.uentered[0]; *ptr; ptr++) {
1737	    register int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
1738
1739	    /* Did we just enter some other special room? */
1740	    /* vault.c insists that a vault remain a VAULT,
1741	     * and temples should remain TEMPLEs,
1742	     * but everything else gives a message only the first time */
1743	    switch (rt) {
1744		case ZOO:
1745		    pline("Welcome to David's treasure zoo!");
1746		    break;
1747		case SWAMP:
1748		    pline("It %s rather %s down here.",
1749			  Blind ? "feels" : "looks",
1750			  Blind ? "humid" : "muddy");
1751		    break;
1752		case COURT:
1753		    You("enter an opulent throne room!");
1754		    break;
1755		case LEPREHALL:
1756		    You("enter a leprechaun hall!");
1757		    break;
1758		case MORGUE:
1759		    if(midnight()) {
1760			const char *run = locomotion(youmonst.data, "Run");
1761			pline("%s away!  %s away!", run, run);
1762		    } else
1763			You("have an uncanny feeling...");
1764		    break;
1765		case BEEHIVE:
1766		    You("enter a giant beehive!");
1767		    break;
1768		case COCKNEST:
1769		    You("enter a disgusting nest!");
1770		    break;
1771		case ANTHOLE:
1772		    You("enter an anthole!");
1773		    break;
1774		case BARRACKS:
1775		    if(monstinroom(&mons[PM_SOLDIER], roomno) ||
1776			monstinroom(&mons[PM_SERGEANT], roomno) ||
1777			monstinroom(&mons[PM_LIEUTENANT], roomno) ||
1778			monstinroom(&mons[PM_CAPTAIN], roomno))
1779			You("enter a military barracks!");
1780		    else
1781			You("enter an abandoned barracks.");
1782		    break;
1783		case DELPHI:
1784		    if(monstinroom(&mons[PM_ORACLE], roomno))
1785			verbalize("%s, %s, welcome to Delphi!",
1786					Hello((struct monst *) 0), plname);
1787		    break;
1788		case TEMPLE:
1789		    intemple(roomno + ROOMOFFSET);
1790		    /* fall through */
1791		default:
1792		    rt = 0;
1793	    }
1794
1795	    if (rt != 0) {
1796		rooms[roomno].rtype = OROOM;
1797		if (!search_special(rt)) {
1798			/* No more room of that type */
1799			switch(rt) {
1800			    case COURT:
1801				level.flags.has_court = 0;
1802				break;
1803			    case SWAMP:
1804				level.flags.has_swamp = 0;
1805				break;
1806			    case MORGUE:
1807				level.flags.has_morgue = 0;
1808				break;
1809			    case ZOO:
1810				level.flags.has_zoo = 0;
1811				break;
1812			    case BARRACKS:
1813				level.flags.has_barracks = 0;
1814				break;
1815			    case TEMPLE:
1816				level.flags.has_temple = 0;
1817				break;
1818			    case BEEHIVE:
1819				level.flags.has_beehive = 0;
1820				break;
1821			}
1822		}
1823		if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
1824		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1825			if (!DEADMONSTER(mtmp) && !Stealth && !rn2(3)) mtmp->msleeping = 0;
1826	    }
1827	}
1828
1829	return;
1830}
1831
1832#endif /* OVL2 */
1833#ifdef OVLB
1834
1835int
1836dopickup()
1837{
1838	int count;
1839	struct trap *traphere = t_at(u.ux, u.uy);
1840 	/* awful kludge to work around parse()'s pre-decrement */
1841	count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
1842	multi = 0;	/* always reset */
1843	/* uswallow case added by GAN 01/29/87 */
1844	if(u.uswallow) {
1845	    if (!u.ustuck->minvent) {
1846		if (is_animal(u.ustuck->data)) {
1847		    You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
1848		    pline("But it's kind of slimy, so you drop it.");
1849		} else
1850		    You("don't %s anything in here to pick up.",
1851			  Blind ? "feel" : "see");
1852		return(1);
1853	    } else {
1854	    	int tmpcount = -count;
1855		return loot_mon(u.ustuck, &tmpcount, (boolean *)0);
1856	    }
1857	}
1858	if(is_pool(u.ux, u.uy)) {
1859	    if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1860			|| (Flying && !Breathless)) {
1861		You("cannot dive into the water to pick things up.");
1862		return(0);
1863	    } else if (!Underwater) {
1864		You_cant("even see the bottom, let alone pick up %s.",
1865				something);
1866		return(0);
1867	    }
1868	}
1869	if (is_lava(u.ux, u.uy)) {
1870	    if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1871			|| (Flying && !Breathless)) {
1872		You_cant("reach the bottom to pick things up.");
1873		return(0);
1874	    } else if (!likes_lava(youmonst.data)) {
1875		You("would burn to a crisp trying to pick things up.");
1876		return(0);
1877	    }
1878	}
1879	if(!OBJ_AT(u.ux, u.uy)) {
1880		There("is nothing here to pick up.");
1881		return(0);
1882	}
1883	if (!can_reach_floor()) {
1884#ifdef STEED
1885		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1886		    You("aren't skilled enough to reach from %s.",
1887			y_monnam(u.usteed));
1888		else
1889#endif
1890		You("cannot reach the %s.", surface(u.ux,u.uy));
1891		return(0);
1892	}
1893
1894 	if (traphere && traphere->tseen) {
1895		/* Allow pickup from holes and trap doors that you escaped from
1896		 * because that stuff is teetering on the edge just like you, but
1897		 * not pits, because there is an elevation discrepancy with stuff
1898		 * in pits.
1899		 */
1900		if ((traphere->ttyp == PIT || traphere->ttyp == SPIKED_PIT) &&
1901		     (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) {
1902			You("cannot reach the bottom of the pit.");
1903			return(0);
1904		}
1905	}
1906
1907	return (pickup(-count));
1908}
1909
1910#endif /* OVLB */
1911#ifdef OVL2
1912
1913/* stop running if we see something interesting */
1914/* turn around a corner if that is the only way we can proceed */
1915/* do not turn left or right twice */
1916void
1917lookaround()
1918{
1919    register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
1920    register int corrct = 0, noturn = 0;
1921    register struct monst *mtmp;
1922    register struct trap *trap;
1923
1924    /* Grid bugs stop if trying to move diagonal, even if blind.  Maybe */
1925    /* they polymorphed while in the middle of a long move. */
1926    if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) {
1927	nomul(0);
1928	return;
1929    }
1930
1931    if(Blind || flags.run == 0) return;
1932    for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) {
1933	if(!isok(x,y)) continue;
1934
1935	if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue;
1936
1937	if(x == u.ux && y == u.uy) continue;
1938
1939	if((mtmp = m_at(x,y)) &&
1940		    mtmp->m_ap_type != M_AP_FURNITURE &&
1941		    mtmp->m_ap_type != M_AP_OBJECT &&
1942		    (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
1943	    if((flags.run != 1 && !mtmp->mtame)
1944					|| (x == u.ux+u.dx && y == u.uy+u.dy))
1945		goto stop;
1946	}
1947
1948	if (levl[x][y].typ == STONE) continue;
1949	if (x == u.ux-u.dx && y == u.uy-u.dy) continue;
1950
1951	if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) ||
1952	    IS_AIR(levl[x][y].typ))
1953	    continue;
1954	else if (closed_door(x,y) ||
1955		 (mtmp && mtmp->m_ap_type == M_AP_FURNITURE &&
1956		  (mtmp->mappearance == S_hcdoor ||
1957		   mtmp->mappearance == S_vcdoor))) {
1958	    if(x != u.ux && y != u.uy) continue;
1959	    if(flags.run != 1) goto stop;
1960	    goto bcorr;
1961	} else if (levl[x][y].typ == CORR) {
1962bcorr:
1963	    if(levl[u.ux][u.uy].typ != ROOM) {
1964		if(flags.run == 1 || flags.run == 3 || flags.run == 8) {
1965		    i = dist2(x,y,u.ux+u.dx,u.uy+u.dy);
1966		    if(i > 2) continue;
1967		    if(corrct == 1 && dist2(x,y,x0,y0) != 1)
1968			noturn = 1;
1969		    if(i < i0) {
1970			i0 = i;
1971			x0 = x;
1972			y0 = y;
1973			m0 = mtmp ? 1 : 0;
1974		    }
1975		}
1976		corrct++;
1977	    }
1978	    continue;
1979	} else if ((trap = t_at(x,y)) && trap->tseen) {
1980	    if(flags.run == 1) goto bcorr;	/* if you must */
1981	    if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
1982	    continue;
1983	} else if (is_pool(x,y) || is_lava(x,y)) {
1984	    /* water and lava only stop you if directly in front, and stop
1985	     * you even if you are running
1986	     */
1987	    if(!Levitation && !Flying && !is_clinger(youmonst.data) &&
1988				x == u.ux+u.dx && y == u.uy+u.dy)
1989			/* No Wwalking check; otherwise they'd be able
1990			 * to test boots by trying to SHIFT-direction
1991			 * into a pool and seeing if the game allowed it
1992			 */
1993			goto stop;
1994	    continue;
1995	} else {		/* e.g. objects or trap or stairs */
1996	    if(flags.run == 1) goto bcorr;
1997	    if(flags.run == 8) continue;
1998	    if(mtmp) continue;		/* d */
1999	    if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) ||
2000	       ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
2001	       continue;
2002	}
2003stop:
2004	nomul(0);
2005	return;
2006    } /* end for loops */
2007
2008    if(corrct > 1 && flags.run == 2) goto stop;
2009    if((flags.run == 1 || flags.run == 3 || flags.run == 8) &&
2010	!noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1)))
2011    {
2012	/* make sure that we do not turn too far */
2013	if(i0 == 2) {
2014	    if(u.dx == y0-u.uy && u.dy == u.ux-x0)
2015		i = 2;		/* straight turn right */
2016	    else
2017		i = -2;		/* straight turn left */
2018	} else if(u.dx && u.dy) {
2019	    if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
2020		i = -1;		/* half turn left */
2021	    else
2022		i = 1;		/* half turn right */
2023	} else {
2024	    if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy))
2025		i = 1;		/* half turn right */
2026	    else
2027		i = -1;		/* half turn left */
2028	}
2029
2030	i += u.last_str_turn;
2031	if(i <= 2 && i >= -2) {
2032	    u.last_str_turn = i;
2033	    u.dx = x0-u.ux;
2034	    u.dy = y0-u.uy;
2035	}
2036    }
2037}
2038
2039/* something like lookaround, but we are not running */
2040/* react only to monsters that might hit us */
2041int
2042monster_nearby()
2043{
2044	register int x,y;
2045	register struct monst *mtmp;
2046
2047	/* Also see the similar check in dochugw() in monmove.c */
2048	for(x = u.ux-1; x <= u.ux+1; x++)
2049	    for(y = u.uy-1; y <= u.uy+1; y++) {
2050		if(!isok(x,y)) continue;
2051		if(x == u.ux && y == u.uy) continue;
2052		if((mtmp = m_at(x,y)) &&
2053		   mtmp->m_ap_type != M_AP_FURNITURE &&
2054		   mtmp->m_ap_type != M_AP_OBJECT &&
2055		   (!mtmp->mpeaceful || Hallucination) &&
2056		   (!is_hider(mtmp->data) || !mtmp->mundetected) &&
2057		   !noattacks(mtmp->data) &&
2058		   mtmp->mcanmove && !mtmp->msleeping &&  /* aplvax!jcn */
2059		   !onscary(u.ux, u.uy, mtmp) &&
2060		   canspotmon(mtmp))
2061			return(1);
2062	}
2063	return(0);
2064}
2065
2066void
2067nomul(nval)
2068	register int nval;
2069{
2070	if(multi < nval) return;	/* This is a bug fix by ab@unido */
2071	u.uinvulnerable = FALSE;	/* Kludge to avoid ctrl-C bug -dlc */
2072	u.usleep = 0;
2073	multi = nval;
2074	flags.travel = iflags.travel1 = flags.mv = flags.run = 0;
2075}
2076
2077/* called when a non-movement, multi-turn action has completed */
2078void
2079unmul(msg_override)
2080const char *msg_override;
2081{
2082	multi = 0;	/* caller will usually have done this already */
2083	if (msg_override) nomovemsg = msg_override;
2084	else if (!nomovemsg) nomovemsg = You_can_move_again;
2085	if (*nomovemsg) pline(nomovemsg);
2086	nomovemsg = 0;
2087	u.usleep = 0;
2088	if (afternmv) (*afternmv)();
2089	afternmv = 0;
2090}
2091
2092#endif /* OVL2 */
2093#ifdef OVL1
2094
2095STATIC_OVL void
2096maybe_wail()
2097{
2098    static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
2099			      SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
2100			      TELEPORT_CONTROL, STEALTH, FAST, INVIS };
2101
2102    if (moves <= wailmsg + 50) return;
2103
2104    wailmsg = moves;
2105    if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
2106	const char *who;
2107	int i, powercnt;
2108
2109	who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
2110		urole.name.m : "Elf";
2111	if (u.uhp == 1) {
2112	    pline("%s is about to die.", who);
2113	} else {
2114	    for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
2115		if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt;
2116
2117	    pline(powercnt >= 4 ? "%s, all your powers will be lost..."
2118				: "%s, your life force is running out.", who);
2119	}
2120    } else {
2121	You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
2122			    : "the howling of the CwnAnnwn...");
2123    }
2124}
2125
2126void
2127losehp(n, knam, k_format)
2128register int n;
2129register const char *knam;
2130boolean k_format;
2131{
2132	if (Upolyd) {
2133		u.mh -= n;
2134		if (u.mhmax < u.mh) u.mhmax = u.mh;
2135		flags.botl = 1;
2136		if (u.mh < 1)
2137		    rehumanize();
2138		else if (n > 0 && u.mh*10 < u.mhmax && Unchanging)
2139		    maybe_wail();
2140		return;
2141	}
2142
2143	u.uhp -= n;
2144	if(u.uhp > u.uhpmax)
2145		u.uhpmax = u.uhp;	/* perhaps n was negative */
2146	flags.botl = 1;
2147	if(u.uhp < 1) {
2148		killer_format = k_format;
2149		killer = knam;		/* the thing that killed you */
2150		You("die...");
2151		done(DIED);
2152	} else if (n > 0 && u.uhp*10 < u.uhpmax) {
2153		maybe_wail();
2154	}
2155}
2156
2157int
2158weight_cap()
2159{
2160	register long carrcap;
2161
2162	carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50;
2163	if (Upolyd) {
2164		/* consistent with can_carry() in mon.c */
2165		if (youmonst.data->mlet == S_NYMPH)
2166			carrcap = MAX_CARR_CAP;
2167		else if (!youmonst.data->cwt)
2168			carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN;
2169		else if (!strongmonst(youmonst.data)
2170			|| (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN)))
2171			carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN);
2172	}
2173
2174	if (Levitation || Is_airlevel(&u.uz)    /* pugh@cornell */
2175#ifdef STEED
2176			|| (u.usteed && strongmonst(u.usteed->data))
2177#endif
2178	)
2179		carrcap = MAX_CARR_CAP;
2180	else {
2181		if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
2182		if (!Flying) {
2183			if(EWounded_legs & LEFT_SIDE) carrcap -= 100;
2184			if(EWounded_legs & RIGHT_SIDE) carrcap -= 100;
2185		}
2186		if (carrcap < 0) carrcap = 0;
2187	}
2188	return((int) carrcap);
2189}
2190
2191static int wc;	/* current weight_cap(); valid after call to inv_weight() */
2192
2193/* returns how far beyond the normal capacity the player is currently. */
2194/* inv_weight() is negative if the player is below normal capacity. */
2195int
2196inv_weight()
2197{
2198	register struct obj *otmp = invent;
2199	register int wt = 0;
2200
2201#ifndef GOLDOBJ
2202	/* when putting stuff into containers, gold is inserted at the head
2203	   of invent for easier manipulation by askchain & co, but it's also
2204	   retained in u.ugold in order to keep the status line accurate; we
2205	   mustn't add its weight in twice under that circumstance */
2206	wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 :
2207		(int)((u.ugold + 50L) / 100L);
2208#endif
2209	while (otmp) {
2210#ifndef GOLDOBJ
2211		if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
2212#else
2213		if (otmp->oclass == COIN_CLASS)
2214			wt += (int)(((long)otmp->quan + 50L) / 100L);
2215		else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
2216#endif
2217			wt += otmp->owt;
2218		otmp = otmp->nobj;
2219	}
2220	wc = weight_cap();
2221	return (wt - wc);
2222}
2223
2224/*
2225 * Returns 0 if below normal capacity, or the number of "capacity units"
2226 * over the normal capacity the player is loaded.  Max is 5.
2227 */
2228int
2229calc_capacity(xtra_wt)
2230int xtra_wt;
2231{
2232    int cap, wt = inv_weight() + xtra_wt;
2233
2234    if (wt <= 0) return UNENCUMBERED;
2235    if (wc <= 1) return OVERLOADED;
2236    cap = (wt*2 / wc) + 1;
2237    return min(cap, OVERLOADED);
2238}
2239
2240int
2241near_capacity()
2242{
2243    return calc_capacity(0);
2244}
2245
2246int
2247max_capacity()
2248{
2249    int wt = inv_weight();
2250
2251    return (wt - (2 * wc));
2252}
2253
2254boolean
2255check_capacity(str)
2256const char *str;
2257{
2258    if(near_capacity() >= EXT_ENCUMBER) {
2259	if(str)
2260	    pline(str);
2261	else
2262	    You_cant("do that while carrying so much stuff.");
2263	return 1;
2264    }
2265    return 0;
2266}
2267
2268#endif /* OVL1 */
2269#ifdef OVLB
2270
2271int
2272inv_cnt()
2273{
2274	register struct obj *otmp = invent;
2275	register int ct = 0;
2276
2277	while(otmp){
2278		ct++;
2279		otmp = otmp->nobj;
2280	}
2281	return(ct);
2282}
2283
2284#ifdef GOLDOBJ
2285/* Counts the money in an object chain. */
2286/* Intended use is for your or some monsters inventory, */
2287/* now that u.gold/m.gold is gone.*/
2288/* Counting money in a container might be possible too. */
2289long
2290money_cnt(otmp)
2291struct obj *otmp;
2292{
2293        while(otmp) {
2294	        /* Must change when silver & copper is implemented: */
2295 	        if (otmp->oclass == COIN_CLASS) return otmp->quan;
2296  	        otmp = otmp->nobj;
2297	}
2298	return 0;
2299}
2300#endif
2301#endif /* OVLB */
2302
2303/*hack.c*/
2304