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