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