OSDN Git Service

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