Source:NetHack 3.6.0/src/hack.c

From NetHackWiki
(Redirected from Source:Hack.c)
Jump to: navigation, search

Below is the full text to hack.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/hack.c#line123]], for example.

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1.  /* NetHack 3.6	hack.c	$NHDT-Date: 1446604111 2015/11/04 02:28:31 $  $NHDT-Branch: master $:$NHDT-Revision: 1.155 $ */
  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.  /* #define DEBUG */ /* uncomment for debugging */
  8.  
  9.  STATIC_DCL void NDECL(maybe_wail);
  10.  STATIC_DCL int NDECL(moverock);
  11.  STATIC_DCL int FDECL(still_chewing, (XCHAR_P, XCHAR_P));
  12.  STATIC_DCL void NDECL(dosinkfall);
  13.  STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P));
  14.  STATIC_DCL boolean FDECL(trapmove, (int, int, struct trap *));
  15.  STATIC_DCL void NDECL(switch_terrain);
  16.  STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *, int));
  17.  STATIC_DCL boolean FDECL(doorless_door, (int, int));
  18.  STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
  19.  
  20.  #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
  21.  
  22.  static anything tmp_anything;
  23.  

uint_to_any

  1.  anything *
  2.  uint_to_any(ui)
  3.  unsigned ui;
  4.  {
  5.      tmp_anything = zeroany;
  6.      tmp_anything.a_uint = ui;
  7.      return &tmp_anything;
  8.  }
  9.  

long_to_any

  1.  anything *
  2.  long_to_any(lng)
  3.  long lng;
  4.  {
  5.      tmp_anything = zeroany;
  6.      tmp_anything.a_long = lng;
  7.      return &tmp_anything;
  8.  }
  9.  

monst_to_any

  1.  anything *
  2.  monst_to_any(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      tmp_anything = zeroany;
  6.      tmp_anything.a_monst = mtmp;
  7.      return &tmp_anything;
  8.  }
  9.  

obj_to_any

  1.  anything *
  2.  obj_to_any(obj)
  3.  struct obj *obj;
  4.  {
  5.      tmp_anything = zeroany;
  6.      tmp_anything.a_obj = obj;
  7.      return &tmp_anything;
  8.  }
  9.  

revive_nasty

  1.  boolean
  2.  revive_nasty(x, y, msg)
  3.  int x, y;
  4.  const char *msg;
  5.  {
  6.      register struct obj *otmp, *otmp2;
  7.      struct monst *mtmp;
  8.      coord cc;
  9.      boolean revived = FALSE;
  10.  
  11.      for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
  12.          otmp2 = otmp->nexthere;
  13.          if (otmp->otyp == CORPSE
  14.              && (is_rider(&mons[otmp->corpsenm])
  15.                  || otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
  16.              /* move any living monster already at that location */
  17.              if ((mtmp = m_at(x, y)) && enexto(&cc, x, y, mtmp->data))
  18.                  rloc_to(mtmp, cc.x, cc.y);
  19.              if (msg)
  20.                  Norep("%s", msg);
  21.              revived = revive_corpse(otmp);
  22.          }
  23.      }
  24.  
  25.      /* this location might not be safe, if not, move revived monster */
  26.      if (revived) {
  27.          mtmp = m_at(x, y);
  28.          if (mtmp && !goodpos(x, y, mtmp, 0)
  29.              && enexto(&cc, x, y, mtmp->data)) {
  30.              rloc_to(mtmp, cc.x, cc.y);
  31.          }
  32.          /* else impossible? */
  33.      }
  34.  
  35.      return revived;
  36.  }
  37.  

moverock

  1.  STATIC_OVL int
  2.  moverock()
  3.  {
  4.      register xchar rx, ry, sx, sy;
  5.      register struct obj *otmp;
  6.      register struct trap *ttmp;
  7.      register struct monst *mtmp;
  8.  
  9.      sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */
  10.      while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
  11.          /* make sure that this boulder is visible as the top object */
  12.          if (otmp != level.objects[sx][sy])
  13.              movobj(otmp, sx, sy);
  14.  
  15.          rx = u.ux + 2 * u.dx; /* boulder destination position */
  16.          ry = u.uy + 2 * u.dy;
  17.          nomul(0);
  18.          if (Levitation || Is_airlevel(&u.uz)) {
  19.              if (Blind)
  20.                  feel_location(sx, sy);
  21.              You("don't have enough leverage to push %s.", the(xname(otmp)));
  22.              /* Give them a chance to climb over it? */
  23.              return -1;
  24.          }
  25.          if (verysmall(youmonst.data) && !u.usteed) {
  26.              if (Blind)
  27.                  feel_location(sx, sy);
  28.              pline("You're too small to push that %s.", xname(otmp));
  29.              goto cannot_push;
  30.          }
  31.          if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ)
  32.              && levl[rx][ry].typ != IRONBARS
  33.              && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy)
  34.                  || doorless_door(rx, ry)) && !sobj_at(BOULDER, rx, ry)) {
  35.              ttmp = t_at(rx, ry);
  36.              mtmp = m_at(rx, ry);
  37.  
  38.              /* KMH -- Sokoban doesn't let you push boulders diagonally */
  39.              if (Sokoban && u.dx && u.dy) {
  40.                  if (Blind)
  41.                      feel_location(sx, sy);
  42.                  pline("%s won't roll diagonally on this %s.",
  43.                        The(xname(otmp)), surface(sx, sy));
  44.                  goto cannot_push;
  45.              }
  46.  
  47.              if (revive_nasty(rx, ry, "You sense movement on the other side."))
  48.                  return -1;
  49.  
  50.              if (mtmp && !noncorporeal(mtmp->data)
  51.                  && (!mtmp->mtrapped
  52.                      || !(ttmp && ((ttmp->ttyp == PIT)
  53.                                    || (ttmp->ttyp == SPIKED_PIT))))) {
  54.                  if (Blind)
  55.                      feel_location(sx, sy);
  56.                  if (canspotmon(mtmp))
  57.                      pline("There's %s on the other side.", a_monnam(mtmp));
  58.                  else {
  59.                      You_hear("a monster behind %s.", the(xname(otmp)));
  60.                      map_invisible(rx, ry);
  61.                  }
  62.                  if (flags.verbose)
  63.                      pline("Perhaps that's why %s cannot move it.",
  64.                            u.usteed ? y_monnam(u.usteed) : "you");
  65.                  goto cannot_push;
  66.              }
  67.  
  68.              if (ttmp) {
  69.                  /* if a trap operates on the boulder, don't attempt
  70.                     to move any others at this location; return -1
  71.                     if another boulder is in hero's way, or 0 if he
  72.                     should advance to the vacated boulder position */
  73.                  switch (ttmp->ttyp) {
  74.                  case LANDMINE:
  75.                      if (rn2(10)) {
  76.                          obj_extract_self(otmp);
  77.                          place_object(otmp, rx, ry);
  78.                          newsym(sx, sy);
  79.                          pline("KAABLAMM!!!  %s %s land mine.",
  80.                                Tobjnam(otmp, "trigger"),
  81.                                ttmp->madeby_u ? "your" : "a");
  82.                          blow_up_landmine(ttmp);
  83.                          /* if the boulder remains, it should fill the pit */
  84.                          fill_pit(u.ux, u.uy);
  85.                          if (cansee(rx, ry))
  86.                              newsym(rx, ry);
  87.                          return sobj_at(BOULDER, sx, sy) ? -1 : 0;
  88.                      }
  89.                      break;
  90.                  case SPIKED_PIT:
  91.                  case PIT:
  92.                      obj_extract_self(otmp);
  93.                      /* vision kludge to get messages right;
  94.                         the pit will temporarily be seen even
  95.                         if this is one among multiple boulders */
  96.                      if (!Blind)
  97.                          viz_array[ry][rx] |= IN_SIGHT;
  98.                      if (!flooreffects(otmp, rx, ry, "fall")) {
  99.                          place_object(otmp, rx, ry);
  100.                      }
  101.                      if (mtmp && !Blind)
  102.                          newsym(rx, ry);
  103.                      return sobj_at(BOULDER, sx, sy) ? -1 : 0;
  104.                  case HOLE:
  105.                  case TRAPDOOR:
  106.                      if (Blind)
  107.                          pline("Kerplunk!  You no longer feel %s.",
  108.                                the(xname(otmp)));
  109.                      else
  110.                          pline("%s%s and %s a %s in the %s!",
  111.                                Tobjnam(otmp, (ttmp->ttyp == TRAPDOOR)
  112.                                                  ? "trigger"
  113.                                                  : "fall"),
  114.                                (ttmp->ttyp == TRAPDOOR) ? "" : " into",
  115.                                otense(otmp, "plug"),
  116.                                (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
  117.                                surface(rx, ry));
  118.                      deltrap(ttmp);
  119.                      delobj(otmp);
  120.                      bury_objs(rx, ry);
  121.                      levl[rx][ry].wall_info &= ~W_NONDIGGABLE;
  122.                      levl[rx][ry].candig = 1;
  123.                      if (cansee(rx, ry))
  124.                          newsym(rx, ry);
  125.                      return sobj_at(BOULDER, sx, sy) ? -1 : 0;
  126.                  case LEVEL_TELEP:
  127.                  case TELEP_TRAP: {
  128.                      int newlev = 0; /* lint suppression */
  129.                      d_level dest;
  130.  
  131.                      if (ttmp->ttyp == LEVEL_TELEP) {
  132.                          newlev = random_teleport_level();
  133.                          if (newlev == depth(&u.uz) || In_endgame(&u.uz))
  134.                              /* trap didn't work; skip "disappears" message */
  135.                              goto dopush;
  136.                      }
  137.                      if (u.usteed)
  138.                          pline("%s pushes %s and suddenly it disappears!",
  139.                                upstart(y_monnam(u.usteed)), the(xname(otmp)));
  140.                      else
  141.                          You("push %s and suddenly it disappears!",
  142.                              the(xname(otmp)));
  143.                      if (ttmp->ttyp == TELEP_TRAP) {
  144.                          (void) rloco(otmp);
  145.                      } else {
  146.                          obj_extract_self(otmp);
  147.                          add_to_migration(otmp);
  148.                          get_level(&dest, newlev);
  149.                          otmp->ox = dest.dnum;
  150.                          otmp->oy = dest.dlevel;
  151.                          otmp->owornmask = (long) MIGR_RANDOM;
  152.                      }
  153.                      seetrap(ttmp);
  154.                      return sobj_at(BOULDER, sx, sy) ? -1 : 0;
  155.                  }
  156.                  default:
  157.                      break; /* boulder not affected by this trap */
  158.                  }
  159.              }
  160.  
  161.              if (closed_door(rx, ry))
  162.                  goto nopushmsg;
  163.              if (boulder_hits_pool(otmp, rx, ry, TRUE))
  164.                  continue;
  165.              /*
  166.               * Re-link at top of fobj chain so that pile order is preserved
  167.               * when level is restored.
  168.               */
  169.              if (otmp != fobj) {
  170.                  remove_object(otmp);
  171.                  place_object(otmp, otmp->ox, otmp->oy);
  172.              }
  173.  
  174.              {
  175.  #ifdef LINT /* static long lastmovetime; */
  176.                  long lastmovetime;
  177.                  lastmovetime = 0;
  178.  #else
  179.                  /* note: reset to zero after save/restore cycle */
  180.                  static NEARDATA long lastmovetime;
  181.  #endif
  182.              dopush:
  183.                  if (!u.usteed) {
  184.                      if (moves > lastmovetime + 2 || moves < lastmovetime)
  185.                          pline("With %s effort you move %s.",
  186.                                throws_rocks(youmonst.data) ? "little"
  187.                                                            : "great",
  188.                                the(xname(otmp)));
  189.                      exercise(A_STR, TRUE);
  190.                  } else
  191.                      pline("%s moves %s.", upstart(y_monnam(u.usteed)),
  192.                            the(xname(otmp)));
  193.                  lastmovetime = moves;
  194.              }
  195.  
  196.              /* Move the boulder *after* the message. */
  197.              if (glyph_is_invisible(levl[rx][ry].glyph))
  198.                  unmap_object(rx, ry);
  199.              movobj(otmp, rx, ry); /* does newsym(rx,ry) */
  200.              if (Blind) {
  201.                  feel_location(rx, ry);
  202.                  feel_location(sx, sy);
  203.              } else {
  204.                  newsym(sx, sy);
  205.              }
  206.          } else {
  207.          nopushmsg:
  208.              if (u.usteed)
  209.                  pline("%s tries to move %s, but cannot.",
  210.                        upstart(y_monnam(u.usteed)), the(xname(otmp)));
  211.              else
  212.                  You("try to move %s, but in vain.", the(xname(otmp)));
  213.              if (Blind)
  214.                  feel_location(sx, sy);
  215.          cannot_push:
  216.              if (throws_rocks(youmonst.data)) {
  217.                  if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
  218.                      You("aren't skilled enough to %s %s from %s.",
  219.                          (flags.pickup && !Sokoban) ? "pick up" : "push aside",
  220.                          the(xname(otmp)), y_monnam(u.usteed));
  221.                  } else {
  222.                      pline("However, you can easily %s.",
  223.                            (flags.pickup && !Sokoban) ? "pick it up"
  224.                                                       : "push it aside");
  225.                      sokoban_guilt();
  226.                      break;
  227.                  }
  228.                  break;
  229.              }
  230.  
  231.              if (!u.usteed
  232.                  && (((!invent || inv_weight() <= -850)
  233.                       && (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
  234.                                              && IS_ROCK(levl[sx][u.uy].typ))))
  235.                      || verysmall(youmonst.data))) {
  236.                  pline(
  237.                     "However, you can squeeze yourself into a small opening.");
  238.                  sokoban_guilt();
  239.                  break;
  240.              } else
  241.                  return -1;
  242.          }
  243.      }
  244.      return 0;
  245.  }
  246.  

still_chewing

  1.  /*
  2.   *  still_chewing()
  3.   *
  4.   *  Chew on a wall, door, or boulder.  Returns TRUE if still eating, FALSE
  5.   *  when done.
  6.   */
  7.  STATIC_OVL int
  8.  still_chewing(x, y)
  9.  xchar x, y;
  10.  {
  11.      struct rm *lev = &levl[x][y];
  12.      struct obj *boulder = sobj_at(BOULDER, x, y);
  13.      const char *digtxt = (char *) 0, *dmgtxt = (char *) 0;
  14.  
  15.      if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */
  16.          (void) memset((genericptr_t) &context.digging, 0,
  17.                        sizeof(struct dig_info));
  18.  
  19.      if (!boulder && IS_ROCK(lev->typ) && !may_dig(x, y)) {
  20.          You("hurt your teeth on the %s.",
  21.              (lev->typ == IRONBARS)
  22.                  ? "bars"
  23.                  : IS_TREE(lev->typ)
  24.                      ? "tree"
  25.                      : "hard stone");
  26.          nomul(0);
  27.          return 1;
  28.      } else if (context.digging.pos.x != x || context.digging.pos.y != y
  29.                 || !on_level(&context.digging.level, &u.uz)) {
  30.          context.digging.down = FALSE;
  31.          context.digging.chew = TRUE;
  32.          context.digging.warned = FALSE;
  33.          context.digging.pos.x = x;
  34.          context.digging.pos.y = y;
  35.          assign_level(&context.digging.level, &u.uz);
  36.          /* solid rock takes more work & time to dig through */
  37.          context.digging.effort =
  38.              (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc;
  39.          You("start chewing %s %s.",
  40.              (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS)
  41.                  ? "on a"
  42.                  : "a hole in the",
  43.              boulder
  44.                  ? "boulder"
  45.                  : IS_TREE(lev->typ)
  46.                      ? "tree"
  47.                      : IS_ROCK(lev->typ)
  48.                          ? "rock"
  49.                          : lev->typ == IRONBARS
  50.                              ? "bar"
  51.                              : "door");
  52.          watch_dig((struct monst *) 0, x, y, FALSE);
  53.          return 1;
  54.      } else if ((context.digging.effort += (30 + u.udaminc)) <= 100) {
  55.          if (flags.verbose)
  56.              You("%s chewing on the %s.",
  57.                  context.digging.chew ? "continue" : "begin",
  58.                  boulder
  59.                      ? "boulder"
  60.                      : IS_TREE(lev->typ)
  61.                          ? "tree"
  62.                          : IS_ROCK(lev->typ)
  63.                              ? "rock"
  64.                              : (lev->typ == IRONBARS)
  65.                                  ? "bars"
  66.                                  : "door");
  67.          context.digging.chew = TRUE;
  68.          watch_dig((struct monst *) 0, x, y, FALSE);
  69.          return 1;
  70.      }
  71.  
  72.      /* Okay, you've chewed through something */
  73.      u.uconduct.food++;
  74.      u.uhunger += rnd(20);
  75.  
  76.      if (boulder) {
  77.          delobj(boulder);         /* boulder goes bye-bye */
  78.          You("eat the boulder."); /* yum */
  79.  
  80.          /*
  81.           *  The location could still block because of
  82.           *      1. More than one boulder
  83.           *      2. Boulder stuck in a wall/stone/door.
  84.           *
  85.           *  [perhaps use does_block() below (from vision.c)]
  86.           */
  87.          if (IS_ROCK(lev->typ) || closed_door(x, y)
  88.              || sobj_at(BOULDER, x, y)) {
  89.              block_point(x, y); /* delobj will unblock the point */
  90.              /* reset dig state */
  91.              (void) memset((genericptr_t) &context.digging, 0,
  92.                            sizeof(struct dig_info));
  93.              return 1;
  94.          }
  95.  
  96.      } else if (IS_WALL(lev->typ)) {
  97.          if (*in_rooms(x, y, SHOPBASE)) {
  98.              add_damage(x, y, 10L * ACURRSTR);
  99.              dmgtxt = "damage";
  100.          }
  101.          digtxt = "chew a hole in the wall.";
  102.          if (level.flags.is_maze_lev) {
  103.              lev->typ = ROOM;
  104.          } else if (level.flags.is_cavernous_lev && !in_town(x, y)) {
  105.              lev->typ = CORR;
  106.          } else {
  107.              lev->typ = DOOR;
  108.              lev->doormask = D_NODOOR;
  109.          }
  110.      } else if (IS_TREE(lev->typ)) {
  111.          digtxt = "chew through the tree.";
  112.          lev->typ = ROOM;
  113.      } else if (lev->typ == IRONBARS) {
  114.          digtxt = "eat through the bars.";
  115.          dissolve_bars(x, y);
  116.      } else if (lev->typ == SDOOR) {
  117.          if (lev->doormask & D_TRAPPED) {
  118.              lev->doormask = D_NODOOR;
  119.              b_trapped("secret door", 0);
  120.          } else {
  121.              digtxt = "chew through the secret door.";
  122.              lev->doormask = D_BROKEN;
  123.          }
  124.          lev->typ = DOOR;
  125.  
  126.      } else if (IS_DOOR(lev->typ)) {
  127.          if (*in_rooms(x, y, SHOPBASE)) {
  128.              add_damage(x, y, 400L);
  129.              dmgtxt = "break";
  130.          }
  131.          if (lev->doormask & D_TRAPPED) {
  132.              lev->doormask = D_NODOOR;
  133.              b_trapped("door", 0);
  134.          } else {
  135.              digtxt = "chew through the door.";
  136.              lev->doormask = D_BROKEN;
  137.          }
  138.  
  139.      } else { /* STONE or SCORR */
  140.          digtxt = "chew a passage through the rock.";
  141.          lev->typ = CORR;
  142.      }
  143.  
  144.      unblock_point(x, y); /* vision */
  145.      newsym(x, y);
  146.      if (digtxt)
  147.          You1(digtxt); /* after newsym */
  148.      if (dmgtxt)
  149.          pay_for_damage(dmgtxt, FALSE);
  150.      (void) memset((genericptr_t) &context.digging, 0,
  151.                    sizeof(struct dig_info));
  152.      return 0;
  153.  }
  154.  

moveobj

  1.  void
  2.  movobj(obj, ox, oy)
  3.  register struct obj *obj;
  4.  register xchar ox, oy;
  5.  {
  6.      /* optimize by leaving on the fobj chain? */
  7.      remove_object(obj);
  8.      newsym(obj->ox, obj->oy);
  9.      place_object(obj, ox, oy);
  10.      newsym(ox, oy);
  11.  }
  12.  

dosinkfall

  1.  static NEARDATA const char fell_on_sink[] = "fell onto a sink";
  2.  
  3.  STATIC_OVL void
  4.  dosinkfall()
  5.  {
  6.      register struct obj *obj;
  7.      int dmg;
  8.      boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS),
  9.              innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L),
  10.              ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */
  11.  
  12.      if (!ufall) {
  13.          You(innate_lev ? "wobble unsteadily for a moment."
  14.                         : "gain control of your flight.");
  15.      } else {
  16.          long save_ELev = ELevitation, save_HLev = HLevitation;
  17.  
  18.          /* fake removal of levitation in advance so that final
  19.             disclosure will be right in case this turns out to
  20.             be fatal; fortunately the fact that rings and boots
  21.             are really still worn has no effect on bones data */
  22.          ELevitation = HLevitation = 0L;
  23.          You("crash to the floor!");
  24.          dmg = rn1(8, 25 - (int) ACURR(A_CON));
  25.          losehp(Maybe_Half_Phys(dmg), fell_on_sink, NO_KILLER_PREFIX);
  26.          exercise(A_DEX, FALSE);
  27.          selftouch("Falling, you");
  28.          for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
  29.              if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) {
  30.                  You("fell on %s.", doname(obj));
  31.                  losehp(Maybe_Half_Phys(rnd(3)), fell_on_sink,
  32.                         NO_KILLER_PREFIX);
  33.                  exercise(A_CON, FALSE);
  34.              }
  35.          ELevitation = save_ELev;
  36.          HLevitation = save_HLev;
  37.      }
  38.  
  39.      /*
  40.       * Interrupt multi-turn putting on/taking off of armor (in which
  41.       * case we reached the sink due to being teleported while busy;
  42.       * in 3.4.3, Boots_on()/Boots_off() [called via (*aftermv)() when
  43.       * 'multi' reaches 0] triggered a crash if we were donning/doffing
  44.       * levitation boots [because the Boots_off() below causes 'uarmf'
  45.       * to be null by the time 'aftermv' gets called]).
  46.       *
  47.       * Interrupt donning/doffing if we fall onto the sink, or if the
  48.       * code below is going to remove levitation boots even when we
  49.       * haven't fallen (innate floating or flying becoming unblocked).
  50.       */
  51.      if (ufall || lev_boots) {
  52.          (void) stop_donning(lev_boots ? uarmf : (struct obj *) 0);
  53.          /* recalculate in case uarmf just got set to null */
  54.          lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS);
  55.      }
  56.  
  57.      /* remove worn levitation items */
  58.      ELevitation &= ~W_ARTI;
  59.      HLevitation &= ~(I_SPECIAL | TIMEOUT);
  60.      HLevitation++;
  61.      if (uleft && uleft->otyp == RIN_LEVITATION) {
  62.          obj = uleft;
  63.          Ring_off(obj);
  64.          off_msg(obj);
  65.      }
  66.      if (uright && uright->otyp == RIN_LEVITATION) {
  67.          obj = uright;
  68.          Ring_off(obj);
  69.          off_msg(obj);
  70.      }
  71.      if (lev_boots) {
  72.          obj = uarmf;
  73.          (void) Boots_off();
  74.          off_msg(obj);
  75.      }
  76.      HLevitation--;
  77.      /* probably moot; we're either still levitating or went
  78.         through float_down(), but make sure BFlying is up to date */
  79.      float_vs_flight();
  80.  }
  81.  

may_dig

  1.  /* intended to be called only on ROCKs or TREEs */
  2.  boolean
  3.  may_dig(x, y)
  4.  register xchar x, y;
  5.  {
  6.      struct rm *lev = &levl[x][y];
  7.  
  8.      return (boolean) !((IS_STWALL(lev->typ) || IS_TREE(lev->typ))
  9.                         && (lev->wall_info & W_NONDIGGABLE));
  10.  }
  11.  

may_passwall

  1.  boolean
  2.  may_passwall(x, y)
  3.  register xchar x, y;
  4.  {
  5.      return (boolean) !(IS_STWALL(levl[x][y].typ)
  6.                         && (levl[x][y].wall_info & W_NONPASSWALL));
  7.  }
  8.  

bad_rock

  1.  boolean
  2.  bad_rock(mdat, x, y)
  3.  struct permonst *mdat;
  4.  register xchar x, y;
  5.  {
  6.      return (boolean) ((Sokoban && sobj_at(BOULDER, x, y))
  7.                        || (IS_ROCK(levl[x][y].typ)
  8.                            && (!tunnels(mdat) || needspick(mdat)
  9.                                || !may_dig(x, y))
  10.                            && !(passes_walls(mdat) && may_passwall(x, y))));
  11.  }
  12.  

cantsqueezethru

  1.  /* caller has already decided that it's a tight diagonal; check whether a
  2.     monster--who might be the hero--can fit through, and if not then return
  3.     the reason why:  1: can't fit, 2: possessions won't fit, 3: sokoban */
  4.  int /* returns 0 if we can squeeze through */
  5.      cant_squeeze_thru(mon)
  6.  struct monst *mon;
  7.  {
  8.      int amt;
  9.      struct permonst *ptr = mon->data;
  10.  
  11.      /* too big? */
  12.      if (bigmonst(ptr)
  13.          && !(amorphous(ptr) || is_whirly(ptr) || noncorporeal(ptr)
  14.               || slithy(ptr) || can_fog(mon)))
  15.          return 1;
  16.  
  17.      /* lugging too much junk? */
  18.      amt =
  19.          (mon == &youmonst) ? inv_weight() + weight_cap() : curr_mon_load(mon);
  20.      if (amt > 600)
  21.          return 2;
  22.  
  23.      /* Sokoban restriction applies to hero only */
  24.      if (mon == &youmonst && Sokoban)
  25.          return 3;
  26.  
  27.      /* can squeeze through */
  28.      return 0;
  29.  }
  30.  

invocation_pos

  1.  boolean
  2.  invocation_pos(x, y)
  3.  xchar x, y;
  4.  {
  5.      return (boolean) (Invocation_lev(&u.uz)
  6.                        && x == inv_pos.x && y == inv_pos.y);
  7.  }
  8.  

test_move

  1.  /* return TRUE if (dx,dy) is an OK place to move
  2.   * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV
  3.   */
  4.  boolean
  5.  test_move(ux, uy, dx, dy, mode)
  6.  int ux, uy, dx, dy;
  7.  int mode;
  8.  {
  9.      int x = ux + dx;
  10.      int y = uy + dy;
  11.      register struct rm *tmpr = &levl[x][y];
  12.      register struct rm *ust;
  13.  
  14.      context.door_opened = FALSE;
  15.      /*
  16.       *  Check for physical obstacles.  First, the place we are going.
  17.       */
  18.      if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
  19.          if (Blind && mode == DO_MOVE)
  20.              feel_location(x, y);
  21.          if (Passes_walls && may_passwall(x, y)) {
  22.              ; /* do nothing */
  23.          } else if (tmpr->typ == IRONBARS) {
  24.              if ((dmgtype(youmonst.data, AD_RUST)
  25.                   || dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE
  26.                  && still_chewing(x, y)) {
  27.                  return FALSE;
  28.              }
  29.              if (!(Passes_walls || passes_bars(youmonst.data))) {
  30.                  if (iflags.mention_walls)
  31.                      You("cannot pass through the bars.");
  32.                  return FALSE;
  33.              }
  34.          } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
  35.              /* Eat the rock. */
  36.              if (mode == DO_MOVE && still_chewing(x, y))
  37.                  return FALSE;
  38.          } else if (flags.autodig && !context.run && !context.nopick && uwep
  39.                     && is_pick(uwep)) {
  40.              /* MRKR: Automatic digging when wielding the appropriate tool */
  41.              if (mode == DO_MOVE)
  42.                  (void) use_pick_axe2(uwep);
  43.              return FALSE;
  44.          } else {
  45.              if (mode == DO_MOVE) {
  46.                  if (Is_stronghold(&u.uz) && is_db_wall(x, y))
  47.                      pline_The("drawbridge is up!");
  48.                  /* sokoban restriction stays even after puzzle is solved */
  49.                  else if (Passes_walls && !may_passwall(x, y)
  50.                           && In_sokoban(&u.uz))
  51.                      pline_The("Sokoban walls resist your ability.");
  52.                  else if (iflags.mention_walls)
  53.                      pline("It's a wall.");
  54.              }
  55.              return FALSE;
  56.          }
  57.      } else if (IS_DOOR(tmpr->typ)) {
  58.          if (closed_door(x, y)) {
  59.              if (Blind && mode == DO_MOVE)
  60.                  feel_location(x, y);
  61.              if (Passes_walls)
  62.                  ; /* do nothing */
  63.              else if (can_ooze(&youmonst)) {
  64.                  if (mode == DO_MOVE)
  65.                      You("ooze under the door.");
  66.              } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
  67.                  /* Eat the door. */
  68.                  if (mode == DO_MOVE && still_chewing(x, y))
  69.                      return FALSE;
  70.              } else {
  71.                  if (mode == DO_MOVE) {
  72.                      if (amorphous(youmonst.data))
  73.                          You(
  74.     "try to ooze under the door, but can't squeeze your possessions through.");
  75.                      if (flags.autoopen && !context.run && !Confusion
  76.                          && !Stunned && !Fumbling) {
  77.                          context.door_opened = context.move =
  78.                              doopen_indir(x, y);
  79.                      } else if (x == ux || y == uy) {
  80.                          if (Blind || Stunned || ACURR(A_DEX) < 10
  81.                              || Fumbling) {
  82.                              if (u.usteed) {
  83.                                  You_cant("lead %s through that closed door.",
  84.                                           y_monnam(u.usteed));
  85.                              } else {
  86.                                  pline("Ouch!  You bump into a door.");
  87.                                  exercise(A_DEX, FALSE);
  88.                              }
  89.                          } else
  90.                              pline("That door is closed.");
  91.                      }
  92.                  } else if (mode == TEST_TRAV)
  93.                      goto testdiag;
  94.                  return FALSE;
  95.              }
  96.          } else {
  97.          testdiag:
  98.              if (dx && dy && !Passes_walls
  99.                  && (!doorless_door(x, y) || block_door(x, y))) {
  100.                  /* Diagonal moves into a door are not allowed. */
  101.                  if (Blind && mode == DO_MOVE)
  102.                      feel_location(x, y);
  103.                  return FALSE;
  104.              }
  105.          }
  106.      }
  107.      if (dx && dy && bad_rock(youmonst.data, ux, y)
  108.          && bad_rock(youmonst.data, x, uy)) {
  109.          /* Move at a diagonal. */
  110.          switch (cant_squeeze_thru(&youmonst)) {
  111.          case 3:
  112.              if (mode == DO_MOVE)
  113.                  You("cannot pass that way.");
  114.              return FALSE;
  115.          case 2:
  116.              if (mode == DO_MOVE)
  117.                  You("are carrying too much to get through.");
  118.              return FALSE;
  119.          case 1:
  120.              if (mode == DO_MOVE)
  121.                  Your("body is too large to fit through.");
  122.              return FALSE;
  123.          default:
  124.              break; /* can squeeze through */
  125.          }
  126.      } else if (dx && dy && worm_cross(ux, uy, x, y)) {
  127.          /* consecutive long worm segments are at <ux,y> and <x,uy> */
  128.          if (mode == DO_MOVE)
  129.              pline("%s is in your way.", Monnam(m_at(ux, y)));
  130.          return FALSE;
  131.      }
  132.      /* Pick travel path that does not require crossing a trap.
  133.       * Avoid water and lava using the usual running rules.
  134.       * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
  135.      if (context.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) {
  136.          struct trap *t = t_at(x, y);
  137.  
  138.          if ((t && t->tseen)
  139.              || (!Levitation && !Flying && !is_clinger(youmonst.data)
  140.                  && is_pool_or_lava(x, y) && levl[x][y].seenv))
  141.              return FALSE;
  142.      }
  143.  
  144.      ust = &levl[ux][uy];
  145.  
  146.      /* Now see if other things block our way . . */
  147.      if (dx && dy && !Passes_walls && IS_DOOR(ust->typ)
  148.          && (!doorless_door(ux, uy) || block_entry(x, y))) {
  149.          /* Can't move at a diagonal out of a doorway with door. */
  150.          return FALSE;
  151.      }
  152.  
  153.      if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) {
  154.          if (!(Blind || Hallucination) && (context.run >= 2)
  155.              && mode != TEST_TRAV)
  156.              return FALSE;
  157.          if (mode == DO_MOVE) {
  158.              /* tunneling monsters will chew before pushing */
  159.              if (tunnels(youmonst.data) && !needspick(youmonst.data)
  160.                  && !Sokoban) {
  161.                  if (still_chewing(x, y))
  162.                      return FALSE;
  163.              } else if (moverock() < 0)
  164.                  return FALSE;
  165.          } else if (mode == TEST_TRAV) {
  166.              struct obj *obj;
  167.  
  168.              /* don't pick two boulders in a row, unless there's a way thru */
  169.              if (sobj_at(BOULDER, ux, uy) && !Sokoban) {
  170.                  if (!Passes_walls
  171.                      && !(tunnels(youmonst.data) && !needspick(youmonst.data))
  172.                      && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK)
  173.                      && !((obj = carrying(WAN_DIGGING))
  174.                           && !objects[obj->otyp].oc_name_known))
  175.                      return FALSE;
  176.              }
  177.          }
  178.          /* assume you'll be able to push it when you get there... */
  179.      }
  180.  
  181.      /* OK, it is a legal place to move. */
  182.      return TRUE;
  183.  }
  184.  

wiz_debug_cmd_traveldisplay

  1.  #ifdef DEBUG
  2.  static boolean trav_debug = FALSE;
  3.  
  4.  /* in this case, toggle display of travel debug info */
  5.  int wiz_debug_cmd_traveldisplay()
  6.  {
  7.      trav_debug = !trav_debug;
  8.      return 0;
  9.  }
  10.  #endif /* DEBUG */
  1.  

findtravelpath

  1.  /*
  2.   * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy).
  3.   * A shortest path is returned.  If guess is TRUE, consider various
  4.   * inaccessible locations as valid intermediate path points.
  5.   * Returns TRUE if a path was found.
  6.   */
  7.  STATIC_OVL boolean
  8.  findtravelpath(guess)
  9.  boolean guess;
  10.  {
  11.      /* if travel to adjacent, reachable location, use normal movement rules */
  12.      if (!guess && context.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1
  13.          && !(u.ux != u.tx && u.uy != u.ty && NODIAG(u.umonnum))) {
  14.          context.run = 0;
  15.          if (test_move(u.ux, u.uy, u.tx - u.ux, u.ty - u.uy, TEST_MOVE)) {
  16.              u.dx = u.tx - u.ux;
  17.              u.dy = u.ty - u.uy;
  18.              nomul(0);
  19.              iflags.travelcc.x = iflags.travelcc.y = -1;
  20.              return TRUE;
  21.          }
  22.          context.run = 8;
  23.      }
  24.      if (u.tx != u.ux || u.ty != u.uy) {
  25.          xchar travel[COLNO][ROWNO];
  26.          xchar travelstepx[2][COLNO * ROWNO];
  27.          xchar travelstepy[2][COLNO * ROWNO];
  28.          xchar tx, ty, ux, uy;
  29.          int n = 1;      /* max offset in travelsteps */
  30.          int set = 0;    /* two sets current and previous */
  31.          int radius = 1; /* search radius */
  32.          int i;
  33.  
  34.          /* If guessing, first find an "obvious" goal location.  The obvious
  35.           * goal is the position the player knows of, or might figure out
  36.           * (couldsee) that is closest to the target on a straight path.
  37.           */
  38.          if (guess) {
  39.              tx = u.ux;
  40.              ty = u.uy;
  41.              ux = u.tx;
  42.              uy = u.ty;
  43.          } else {
  44.              tx = u.tx;
  45.              ty = u.ty;
  46.              ux = u.ux;
  47.              uy = u.uy;
  48.          }
  49.  
  50.      noguess:
  51.          (void) memset((genericptr_t) travel, 0, sizeof(travel));
  52.          travelstepx[0][0] = tx;
  53.          travelstepy[0][0] = ty;
  54.  
  55.          while (n != 0) {
  56.              int nn = 0;
  57.  
  58.              for (i = 0; i < n; i++) {
  59.                  int dir;
  60.                  int x = travelstepx[set][i];
  61.                  int y = travelstepy[set][i];
  62.                  static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
  63.                  /* no diagonal movement for grid bugs */
  64.                  int dirmax = NODIAG(u.umonnum) ? 4 : 8;
  65.  
  66.                  for (dir = 0; dir < dirmax; ++dir) {
  67.                      int nx = x + xdir[ordered[dir]];
  68.                      int ny = y + ydir[ordered[dir]];
  69.  
  70.                      if (!isok(nx, ny))
  71.                          continue;
  72.                      if ((!Passes_walls && !can_ooze(&youmonst)
  73.                           && closed_door(x, y)) || sobj_at(BOULDER, x, y)) {
  74.                          /* closed doors and boulders usually
  75.                           * cause a delay, so prefer another path */
  76.                          if (travel[x][y] > radius - 3) {
  77.                              travelstepx[1 - set][nn] = x;
  78.                              travelstepy[1 - set][nn] = y;
  79.                              /* don't change travel matrix! */
  80.                              nn++;
  81.                              continue;
  82.                          }
  83.                      }
  84.                      if (test_move(x, y, nx - x, ny - y, TEST_TRAV)
  85.                          && (levl[nx][ny].seenv
  86.                              || (!Blind && couldsee(nx, ny)))) {
  87.                          if (nx == ux && ny == uy) {
  88.                              if (!guess) {
  89.                                  u.dx = x - ux;
  90.                                  u.dy = y - uy;
  91.                                  if (x == u.tx && y == u.ty) {
  92.                                      nomul(0);
  93.                                      /* reset run so domove run checks work */
  94.                                      context.run = 8;
  95.                                      iflags.travelcc.x = iflags.travelcc.y =
  96.                                          -1;
  97.                                  }
  98.                                  return TRUE;
  99.                              }
  100.                          } else if (!travel[nx][ny]) {
  101.                              travelstepx[1 - set][nn] = nx;
  102.                              travelstepy[1 - set][nn] = ny;
  103.                              travel[nx][ny] = radius;
  104.                              nn++;
  105.                          }
  106.                      }
  107.                  }
  108.              }
  109.  
  110.  #ifdef DEBUG
  111.              if (trav_debug) {
  112.                  /* Use of warning glyph is arbitrary. It stands out. */
  113.                  tmp_at(DISP_ALL, warning_to_glyph(1));
  114.                  for (i = 0; i < nn; ++i) {
  115.                      tmp_at(travelstepx[1 - set][i], travelstepy[1 - set][i]);
  116.                  }
  117.                  delay_output();
  118.                  if (flags.runmode == RUN_CRAWL) {
  119.                      delay_output();
  120.                      delay_output();
  121.                  }
  122.                  tmp_at(DISP_END, 0);
  123.              }
  124.  #endif /* DEBUG */
  125.  
  126.              n = nn;
  127.              set = 1 - set;
  128.              radius++;
  129.          }
  130.  
  131.          /* if guessing, find best location in travel matrix and go there */
  132.          if (guess) {
  133.              int px = tx, py = ty; /* pick location */
  134.              int dist, nxtdist, d2, nd2;
  135.  
  136.              dist = distmin(ux, uy, tx, ty);
  137.              d2 = dist2(ux, uy, tx, ty);
  138.              for (tx = 1; tx < COLNO; ++tx)
  139.                  for (ty = 0; ty < ROWNO; ++ty)
  140.                      if (travel[tx][ty]) {
  141.                          nxtdist = distmin(ux, uy, tx, ty);
  142.                          if (nxtdist == dist && couldsee(tx, ty)) {
  143.                              nd2 = dist2(ux, uy, tx, ty);
  144.                              if (nd2 < d2) {
  145.                                  /* prefer non-zigzag path */
  146.                                  px = tx;
  147.                                  py = ty;
  148.                                  d2 = nd2;
  149.                              }
  150.                          } else if (nxtdist < dist && couldsee(tx, ty)) {
  151.                              px = tx;
  152.                              py = ty;
  153.                              dist = nxtdist;
  154.                              d2 = dist2(ux, uy, tx, ty);
  155.                          }
  156.                      }
  157.  
  158.              if (px == u.ux && py == u.uy) {
  159.                  /* no guesses, just go in the general direction */
  160.                  u.dx = sgn(u.tx - u.ux);
  161.                  u.dy = sgn(u.ty - u.uy);
  162.                  if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE))
  163.                      return TRUE;
  164.                  goto found;
  165.              }
  166.  #ifdef DEBUG
  167.              if (trav_debug) {
  168.                  /* Use of warning glyph is arbitrary. It stands out. */
  169.                  tmp_at(DISP_ALL, warning_to_glyph(2));
  170.                  tmp_at(px, py);
  171.                  delay_output();
  172.                  if (flags.runmode == RUN_CRAWL) {
  173.                      delay_output();
  174.                      delay_output();
  175.                      delay_output();
  176.                      delay_output();
  177.                  }
  178.                  tmp_at(DISP_END, 0);
  179.              }
  180.  #endif /* DEBUG */
  181.              tx = px;
  182.              ty = py;
  183.              ux = u.ux;
  184.              uy = u.uy;
  185.              set = 0;
  186.              n = radius = 1;
  187.              guess = FALSE;
  188.              goto noguess;
  189.          }
  190.          return FALSE;
  191.      }
  192.  
  193.  found:
  194.      u.dx = 0;
  195.      u.dy = 0;
  196.      nomul(0);
  197.      return FALSE;
  198.  }
  199.  

trapremove

  1.  /* try to escape being stuck in a trapped state by walking out of it;
  2.     return true iff moving should continue to intended destination
  3.     (all failures and most successful escapes leave hero at original spot) */
  4.  STATIC_OVL boolean
  5.  trapmove(x, y, desttrap)
  6.  int x, y;              /* targetted destination, <u.ux+u.dx,u.uy+u.dy> */
  7.  struct trap *desttrap; /* nonnull if another trap at <x,y> */
  8.  {
  9.      boolean anchored;
  10.      const char *predicament, *culprit;
  11.      char *steedname = !u.usteed ? (char *) 0 : y_monnam(u.usteed);
  12.  
  13.      if (!u.utrap)
  14.          return TRUE; /* sanity check */
  15.  
  16.      switch (u.utraptype) {
  17.      case TT_BEARTRAP:
  18.          if (flags.verbose) {
  19.              predicament = "caught in a bear trap";
  20.              if (u.usteed)
  21.                  Norep("%s is %s.", upstart(steedname), predicament);
  22.              else
  23.                  Norep("You are %s.", predicament);
  24.          }
  25.          /* [why does diagonal movement give quickest escape?] */
  26.          if ((u.dx && u.dy) || !rn2(5))
  27.              u.utrap--;
  28.          break;
  29.      case TT_PIT:
  30.          if (desttrap && desttrap->tseen
  31.              && (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT))
  32.              return TRUE; /* move into adjacent pit */
  33.          /* try to escape; position stays same regardless of success */
  34.          climb_pit();
  35.          break;
  36.      case TT_WEB:
  37.          if (uwep && uwep->oartifact == ART_STING) {
  38.              u.utrap = 0;
  39.              pline("Sting cuts through the web!");
  40.              break; /* escape trap but don't move */
  41.          }
  42.          if (--u.utrap) {
  43.              if (flags.verbose) {
  44.                  predicament = "stuck to the web";
  45.                  if (u.usteed)
  46.                      Norep("%s is %s.", upstart(steedname), predicament);
  47.                  else
  48.                      Norep("You are %s.", predicament);
  49.              }
  50.          } else {
  51.              if (u.usteed)
  52.                  pline("%s breaks out of the web.", upstart(steedname));
  53.              else
  54.                  You("disentangle yourself.");
  55.          }
  56.          break;
  57.      case TT_LAVA:
  58.          if (flags.verbose) {
  59.              predicament = "stuck in the lava";
  60.              if (u.usteed)
  61.                  Norep("%s is %s.", upstart(steedname), predicament);
  62.              else
  63.                  Norep("You are %s.", predicament);
  64.          }
  65.          if (!is_lava(x, y)) {
  66.              u.utrap--;
  67.              if ((u.utrap & 0xff) == 0) {
  68.                  u.utrap = 0;
  69.                  if (u.usteed)
  70.                      You("lead %s to the edge of the lava.", steedname);
  71.                  else
  72.                      You("pull yourself to the edge of the lava.");
  73.              }
  74.          }
  75.          u.umoved = TRUE;
  76.          break;
  77.      case TT_INFLOOR:
  78.      case TT_BURIEDBALL:
  79.          anchored = (u.utraptype == TT_BURIEDBALL);
  80.          if (anchored) {
  81.              coord cc;
  82.  
  83.              cc.x = u.ux, cc.y = u.uy;
  84.              /* can move normally within radius 1 of buried ball */
  85.              if (buried_ball(&cc) && dist2(x, y, cc.x, cc.y) <= 2) {
  86.                  /* ugly hack: we need to issue some message here
  87.                     in case "you are chained to the buried ball"
  88.                     was the most recent message given, otherwise
  89.                     our next attempt to move out of tether range
  90.                     after this successful move would have its
  91.                     can't-do-that message suppressed by Norep */
  92.                  if (flags.verbose)
  93.                      Norep("You move within the chain's reach.");
  94.                  return TRUE;
  95.              }
  96.          }
  97.          if (--u.utrap) {
  98.              if (flags.verbose) {
  99.                  if (anchored) {
  100.                      predicament = "chained to the";
  101.                      culprit = "buried ball";
  102.                  } else {
  103.                      predicament = "stuck in the";
  104.                      culprit = surface(u.ux, u.uy);
  105.                  }
  106.                  if (u.usteed) {
  107.                      if (anchored)
  108.                          Norep("You and %s are %s %s.", steedname, predicament,
  109.                                culprit);
  110.                      else
  111.                          Norep("%s is %s %s.", upstart(steedname), predicament,
  112.                                culprit);
  113.                  } else
  114.                      Norep("You are %s %s.", predicament, culprit);
  115.              }
  116.          } else {
  117.              if (u.usteed)
  118.                  pline("%s finally %s free.", upstart(steedname),
  119.                        !anchored ? "lurches" : "wrenches the ball");
  120.              else
  121.                  You("finally %s free.",
  122.                      !anchored ? "wriggle" : "wrench the ball");
  123.              if (anchored)
  124.                  buried_ball_to_punishment();
  125.          }
  126.          break;
  127.      default:
  128.          impossible("trapmove: stuck in unknown trap? (%d)",
  129.                     (int) u.utraptype);
  130.          break;
  131.      }
  132.      return FALSE;
  133.  }
  134.  

u_rooted

  1.  boolean
  2.  u_rooted()
  3.  {
  4.      if (!youmonst.data->mmove) {
  5.          You("are rooted %s.",
  6.              Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
  7.                  ? "in place"
  8.                  : "to the ground");
  9.          nomul(0);
  10.          return TRUE;
  11.      }
  12.      return FALSE;
  13.  }
  14.  

domove

  1.  void
  2.  domove()
  3.  {
  4.      register struct monst *mtmp;
  5.      register struct rm *tmpr;
  6.      register xchar x, y;
  7.      struct trap *trap = NULL;
  8.      int wtcap;
  9.      boolean on_ice;
  10.      xchar chainx = 0, chainy = 0,
  11.            ballx = 0, bally = 0;         /* ball&chain new positions */
  12.      int bc_control = 0;                 /* control for ball&chain */
  13.      boolean cause_delay = FALSE;        /* dragging ball will skip a move */
  14.  
  15.      u_wipe_engr(rnd(5));
  16.  
  17.      if (context.travel) {
  18.          if (!findtravelpath(FALSE))
  19.              (void) findtravelpath(TRUE);
  20.          context.travel1 = 0;
  21.      }
  22.  
  23.      if (((wtcap = near_capacity()) >= OVERLOADED
  24.           || (wtcap > SLT_ENCUMBER
  25.               && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
  26.                          : (u.uhp < 10 && u.uhp != u.uhpmax))))
  27.          && !Is_airlevel(&u.uz)) {
  28.          if (wtcap < OVERLOADED) {
  29.              You("don't have enough stamina to move.");
  30.              exercise(A_CON, FALSE);
  31.          } else
  32.              You("collapse under your load.");
  33.          nomul(0);
  34.          return;
  35.      }
  36.      if (u.uswallow) {
  37.          u.dx = u.dy = 0;
  38.          u.ux = x = u.ustuck->mx;
  39.          u.uy = y = u.ustuck->my;
  40.          mtmp = u.ustuck;
  41.      } else {
  42.          if (Is_airlevel(&u.uz) && rn2(4) && !Levitation && !Flying) {
  43.              switch (rn2(3)) {
  44.              case 0:
  45.                  You("tumble in place.");
  46.                  exercise(A_DEX, FALSE);
  47.                  break;
  48.              case 1:
  49.                  You_cant("control your movements very well.");
  50.                  break;
  51.              case 2:
  52.                  pline("It's hard to walk in thin air.");
  53.                  exercise(A_DEX, TRUE);
  54.                  break;
  55.              }
  56.              return;
  57.          }
  58.  
  59.          /* check slippery ice */
  60.          on_ice = !Levitation && is_ice(u.ux, u.uy);
  61.          if (on_ice) {
  62.              static int skates = 0;
  63.              if (!skates)
  64.                  skates = find_skates();
  65.              if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst)
  66.                  || Flying || is_floater(youmonst.data)
  67.                  || is_clinger(youmonst.data) || is_whirly(youmonst.data))
  68.                  on_ice = FALSE;
  69.              else if (!rn2(Cold_resistance ? 3 : 2)) {
  70.                  HFumbling |= FROMOUTSIDE;
  71.                  HFumbling &= ~TIMEOUT;
  72.                  HFumbling += 1; /* slip on next move */
  73.              }
  74.          }
  75.          if (!on_ice && (HFumbling & FROMOUTSIDE))
  76.              HFumbling &= ~FROMOUTSIDE;
  77.  
  78.          x = u.ux + u.dx;
  79.          y = u.uy + u.dy;
  80.          if (Stunned || (Confusion && !rn2(5))) {
  81.              register int tries = 0;
  82.  
  83.              do {
  84.                  if (tries++ > 50) {
  85.                      nomul(0);
  86.                      return;
  87.                  }
  88.                  confdir();
  89.                  x = u.ux + u.dx;
  90.                  y = u.uy + u.dy;
  91.              } while (!isok(x, y) || bad_rock(youmonst.data, x, y));
  92.          }
  93.          /* turbulence might alter your actual destination */
  94.          if (u.uinwater) {
  95.              water_friction();
  96.              if (!u.dx && !u.dy) {
  97.                  nomul(0);
  98.                  return;
  99.              }
  100.              x = u.ux + u.dx;
  101.              y = u.uy + u.dy;
  102.          }
  103.          if (!isok(x, y)) {
  104.              nomul(0);
  105.              return;
  106.          }
  107.          if (((trap = t_at(x, y)) && trap->tseen)
  108.              || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data)
  109.                  && is_pool_or_lava(x, y) && levl[x][y].seenv)) {
  110.              if (context.run >= 2) {
  111.                  nomul(0);
  112.                  context.move = 0;
  113.                  return;
  114.              } else
  115.                  nomul(0);
  116.          }
  117.  
  118.          if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
  119.              if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
  120.                  /* perhaps it fled (or was teleported or ... ) */
  121.                  u.ustuck = 0;
  122.              } else if (sticks(youmonst.data)) {
  123.                  /* When polymorphed into a sticking monster,
  124.                   * u.ustuck means it's stuck to you, not you to it.
  125.                   */
  126.                  You("release %s.", mon_nam(u.ustuck));
  127.                  u.ustuck = 0;
  128.              } else {
  129.                  /* If holder is asleep or paralyzed:
  130.                   *      37.5% chance of getting away,
  131.                   *      12.5% chance of waking/releasing it;
  132.                   * otherwise:
  133.                   *       7.5% chance of getting away.
  134.                   * [strength ought to be a factor]
  135.                   * If holder is tame and there is no conflict,
  136.                   * guaranteed escape.
  137.                   */
  138.                  switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
  139.                  case 0:
  140.                  case 1:
  141.                  case 2:
  142.                  pull_free:
  143.                      You("pull free from %s.", mon_nam(u.ustuck));
  144.                      u.ustuck = 0;
  145.                      break;
  146.                  case 3:
  147.                      if (!u.ustuck->mcanmove) {
  148.                          /* it's free to move on next turn */
  149.                          u.ustuck->mfrozen = 1;
  150.                          u.ustuck->msleeping = 0;
  151.                      }
  152.                  /*FALLTHRU*/
  153.                  default:
  154.                      if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf)
  155.                          goto pull_free;
  156.                      You("cannot escape from %s!", mon_nam(u.ustuck));
  157.                      nomul(0);
  158.                      return;
  159.                  }
  160.              }
  161.          }
  162.  
  163.          mtmp = m_at(x, y);
  164.          if (mtmp) {
  165.              /* Don't attack if you're running, and can see it */
  166.              /* We should never get here if forcefight */
  167.              if (context.run && ((!Blind && mon_visible(mtmp)
  168.                                   && ((mtmp->m_ap_type != M_AP_FURNITURE
  169.                                        && mtmp->m_ap_type != M_AP_OBJECT)
  170.                                       || Protection_from_shape_changers))
  171.                                  || sensemon(mtmp))) {
  172.                  nomul(0);
  173.                  context.move = 0;
  174.                  return;
  175.              }
  176.          }
  177.      }
  178.  
  179.      u.ux0 = u.ux;
  180.      u.uy0 = u.uy;
  181.      bhitpos.x = x;
  182.      bhitpos.y = y;
  183.      tmpr = &levl[x][y];
  184.  
  185.      /* attack monster */
  186.      if (mtmp) {
  187.          nomul(0);
  188.          /* only attack if we know it's there */
  189.          /* or if we used the 'F' command to fight blindly */
  190.          /* or if it hides_under, in which case we call attack() to print
  191.           * the Wait! message.
  192.           * This is different from ceiling hiders, who aren't handled in
  193.           * attack().
  194.           */
  195.  
  196.          /* If they used a 'm' command, trying to move onto a monster
  197.           * prints the below message and wastes a turn.  The exception is
  198.           * if the monster is unseen and the player doesn't remember an
  199.           * invisible monster--then, we fall through to attack() and
  200.           * attack_check(), which still wastes a turn, but prints a
  201.           * different message and makes the player remember the monster.
  202.           */
  203.          if (context.nopick
  204.              && (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))) {
  205.              if (mtmp->m_ap_type && !Protection_from_shape_changers
  206.                  && !sensemon(mtmp))
  207.                  stumble_onto_mimic(mtmp);
  208.              else if (mtmp->mpeaceful && !Hallucination)
  209.                  pline("Pardon me, %s.", m_monnam(mtmp));
  210.              else
  211.                  You("move right into %s.", mon_nam(mtmp));
  212.              return;
  213.          }
  214.          if (context.forcefight || !mtmp->mundetected || sensemon(mtmp)
  215.              || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)
  216.                  && !is_safepet(mtmp))) {
  217.              /* try to attack; note that it might evade */
  218.              /* also, we don't attack tame when _safepet_ */
  219.              if (attack(mtmp))
  220.                  return;
  221.          }
  222.      }
  223.  
  224.      /* specifying 'F' with no monster wastes a turn */
  225.      if (context.forcefight
  226.          /* remembered an 'I' && didn't use a move command */
  227.          || (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) {
  228.          struct obj *boulder = 0;
  229.          boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)),
  230.                  solid = !accessible(x, y);
  231.          int glyph = glyph_at(x, y); /* might be monster */
  232.          char buf[BUFSZ];
  233.  
  234.          if (!Underwater) {
  235.              boulder = sobj_at(BOULDER, x, y);
  236.              /* if a statue is displayed at the target location,
  237.                 player is attempting to attack it [and boulder
  238.                 handling below is suitable for handling that] */
  239.              if (glyph_is_statue(glyph)
  240.                  || (Hallucination && glyph_is_monster(glyph)))
  241.                  boulder = sobj_at(STATUE, x, y);
  242.  
  243.              /* force fight at boulder/statue or wall/door while wielding
  244.                 pick:  start digging to break the boulder or wall */
  245.              if (context.forcefight
  246.                  /* can we dig? */
  247.                  && uwep && dig_typ(uwep, x, y)
  248.                  /* should we dig? */
  249.                  && !glyph_is_invisible(glyph) && !glyph_is_monster(glyph)) {
  250.                  (void) use_pick_axe2(uwep);
  251.                  return;
  252.              }
  253.          }
  254.  
  255.          /* about to become known empty -- remove 'I' if present */
  256.          unmap_object(x, y);
  257.          if (boulder)
  258.              map_object(boulder, TRUE);
  259.          newsym(x, y);
  260.          glyph = glyph_at(x, y); /* might have just changed */
  261.  
  262.          if (boulder)
  263.              Strcpy(buf, ansimpleoname(boulder));
  264.          else if (Underwater && !is_pool(x, y))
  265.              /* Underwater, targetting non-water; the map just shows blank
  266.                 because you don't see remembered terrain while underwater;
  267.                 although the hero can attack an adjacent monster this way,
  268.                 assume he can't reach out far enough to distinguish terrain */
  269.              Sprintf(buf, (Is_waterlevel(&u.uz) && levl[x][y].typ == AIR)
  270.                               ? "an air bubble"
  271.                               : "nothing");
  272.          else if (solid)
  273.              /* glyph might indicate unseen terrain if hero is blind;
  274.                 unlike searching, this won't reveal what that terrain is
  275.                 (except for solid rock, where the glyph would otherwise
  276.                 yield ludicrous "dark part of a room") */
  277.              Strcpy(buf,
  278.                     (levl[x][y].typ == STONE)
  279.                         ? "solid rock"
  280.                         : glyph_is_cmap(glyph)
  281.                              ? the(defsyms[glyph_to_cmap(glyph)].explanation)
  282.                              : (const char *) "an unknown obstacle");
  283.          /* note: 'solid' is misleadingly named and catches pools
  284.             of water and lava as well as rock and walls */
  285.          else
  286.              Strcpy(buf, "thin air");
  287.          You("%s%s %s.",
  288.              !(boulder || solid) ? "" : !explo ? "harmlessly " : "futilely ",
  289.              explo ? "explode at" : "attack", buf);
  290.  
  291.          nomul(0);
  292.          if (explo) {
  293.              wake_nearby();
  294.              u.mh = -1; /* dead in the current form */
  295.              rehumanize();
  296.          }
  297.          return;
  298.      }
  299.      if (glyph_is_invisible(levl[x][y].glyph)) {
  300.          unmap_object(x, y);
  301.          newsym(x, y);
  302.      }
  303.      /* not attacking an animal, so we try to move */
  304.      if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) {
  305.          nomul(0);
  306.          return;
  307.      }
  308.  
  309.      if (u_rooted())
  310.          return;
  311.  
  312.      if (u.utrap) {
  313.          if (!trapmove(x, y, trap))
  314.              return;
  315.      }
  316.  
  317.      if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) {
  318.          if (!context.door_opened) {
  319.              context.move = 0;
  320.              nomul(0);
  321.          }
  322.          return;
  323.      }
  324.  
  325.      /* Move ball and chain.  */
  326.      if (Punished)
  327.          if (!drag_ball(x, y, &bc_control, &ballx, &bally, &chainx, &chainy,
  328.                         &cause_delay, TRUE))
  329.              return;
  330.  
  331.      /* Check regions entering/leaving */
  332.      if (!in_out_region(x, y))
  333.          return;
  334.  
  335.      /* now move the hero */
  336.      mtmp = m_at(x, y);
  337.      u.ux += u.dx;
  338.      u.uy += u.dy;
  339.      /* Move your steed, too */
  340.      if (u.usteed) {
  341.          u.usteed->mx = u.ux;
  342.          u.usteed->my = u.uy;
  343.          exercise_steed();
  344.      }
  345.  
  346.      /*
  347.       * If safepet at destination then move the pet to the hero's
  348.       * previous location using the same conditions as in attack().
  349.       * there are special extenuating circumstances:
  350.       * (1) if the pet dies then your god angers,
  351.       * (2) if the pet gets trapped then your god may disapprove,
  352.       * (3) if the pet was already trapped and you attempt to free it
  353.       * not only do you encounter the trap but you may frighten your
  354.       * pet causing it to go wild!  moral: don't abuse this privilege.
  355.       *
  356.       * Ceiling-hiding pets are skipped by this section of code, to
  357.       * be caught by the normal falling-monster code.
  358.       */
  359.      if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
  360.          /* if trapped, there's a chance the pet goes wild */
  361.          if (mtmp->mtrapped) {
  362.              if (!rn2(mtmp->mtame)) {
  363.                  mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
  364.                  if (mtmp->mleashed)
  365.                      m_unleash(mtmp, TRUE);
  366.                  growl(mtmp);
  367.              } else {
  368.                  yelp(mtmp);
  369.              }
  370.          }
  371.          mtmp->mundetected = 0;
  372.          if (mtmp->m_ap_type)
  373.              seemimic(mtmp);
  374.          else if (!mtmp->mtame)
  375.              newsym(mtmp->mx, mtmp->my);
  376.  
  377.          if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0
  378.              && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)
  379.              && sobj_at(BOULDER, trap->tx, trap->ty)) {
  380.              /* can't swap places with pet pinned in a pit by a boulder */
  381.              u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
  382.          } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
  383.              /* can't swap places when pet can't move to your spot */
  384.              u.ux = u.ux0, u.uy = u.uy0;
  385.              You("stop.  %s can't move diagonally.", upstart(y_monnam(mtmp)));
  386.          } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0)
  387.                     && bad_rock(mtmp->data, u.ux0, y)
  388.                     && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
  389.              /* can't swap places when pet won't fit thru the opening */
  390.              u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
  391.              You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
  392.          } else {
  393.              char pnambuf[BUFSZ];
  394.  
  395.              /* save its current description in case of polymorph */
  396.              Strcpy(pnambuf, y_monnam(mtmp));
  397.              mtmp->mtrapped = 0;
  398.              remove_monster(x, y);
  399.              place_monster(mtmp, u.ux0, u.uy0);
  400.              newsym(x, y);
  401.              newsym(u.ux0, u.uy0);
  402.  
  403.              You("%s %s.", mtmp->mtame ? "swap places with" : "frighten",
  404.                  pnambuf);
  405.  
  406.              /* check for displacing it into pools and traps */
  407.              switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
  408.              case 0:
  409.                  break;
  410.              case 1: /* trapped */
  411.              case 3: /* changed levels */
  412.                  /* there's already been a trap message, reinforce it */
  413.                  abuse_dog(mtmp);
  414.                  adjalign(-3);
  415.                  break;
  416.              case 2:
  417.                  /* drowned or died...
  418.                   * you killed your pet by direct action, so get experience
  419.                   * and possibly penalties;
  420.                   * we want the level gain message, if it happens, to occur
  421.                   * before the guilt message below
  422.                   */
  423.                  {
  424.                      /* minliquid() and mintrap() call mondead() rather than
  425.                         killed() so we duplicate some of the latter here */
  426.                      int tmp, mndx;
  427.  
  428.                      u.uconduct.killer++;
  429.                      mndx = monsndx(mtmp->data);
  430.                      tmp = experience(mtmp, (int) mvitals[mndx].died);
  431.                      more_experienced(tmp, 0);
  432.                      newexplevel(); /* will decide if you go up */
  433.                  }
  434.                  /* That's no way to treat a pet!  Your god gets angry.
  435.                   *
  436.                   * [This has always been pretty iffy.  Why does your
  437.                   * patron deity care at all, let alone enough to get mad?]
  438.                   */
  439.                  if (rn2(4)) {
  440.                      You_feel("guilty about losing your pet like this.");
  441.                      u.ugangr++;
  442.                      adjalign(-15);
  443.                  }
  444.                  break;
  445.              default:
  446.                  pline("that's strange, unknown mintrap result!");
  447.                  break;
  448.              }
  449.          }
  450.      }
  451.  
  452.      reset_occupations();
  453.      if (context.run) {
  454.          if (context.run < 8)
  455.              if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ)
  456.                  || IS_FURNITURE(tmpr->typ))
  457.                  nomul(0);
  458.      }
  459.  
  460.      if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || u.dx
  461.          || u.dy)
  462.          (void) hideunder(&youmonst);
  463.  
  464.      /*
  465.       * Mimics (or whatever) become noticeable if they move and are
  466.       * imitating something that doesn't move.  We could extend this
  467.       * to non-moving monsters...
  468.       */
  469.      if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
  470.                             || youmonst.m_ap_type == M_AP_FURNITURE))
  471.          youmonst.m_ap_type = M_AP_NOTHING;
  472.  
  473.      check_leash(u.ux0, u.uy0);
  474.  
  475.      if (u.ux0 != u.ux || u.uy0 != u.uy) {
  476.          u.umoved = TRUE;
  477.          /* Clean old position -- vision_recalc() will print our new one. */
  478.          newsym(u.ux0, u.uy0);
  479.          /* Since the hero has moved, adjust what can be seen/unseen. */
  480.          vision_recalc(1); /* Do the work now in the recover time. */
  481.          invocation_message();
  482.      }
  483.  
  484.      if (Punished) /* put back ball and chain */
  485.          move_bc(0, bc_control, ballx, bally, chainx, chainy);
  486.  
  487.      spoteffects(TRUE);
  488.  
  489.      /* delay next move because of ball dragging */
  490.      /* must come after we finished picking up, in spoteffects() */
  491.      if (cause_delay) {
  492.          nomul(-2);
  493.          multi_reason = "dragging an iron ball";
  494.          nomovemsg = "";
  495.      }
  496.  
  497.      if (context.run && flags.runmode != RUN_TPORT) {
  498.          /* display every step or every 7th step depending upon mode */
  499.          if (flags.runmode != RUN_LEAP || !(moves % 7L)) {
  500.              if (flags.time)
  501.                  context.botl = 1;
  502.              curs_on_u();
  503.              delay_output();
  504.              if (flags.runmode == RUN_CRAWL) {
  505.                  delay_output();
  506.                  delay_output();
  507.                  delay_output();
  508.                  delay_output();
  509.              }
  510.          }
  511.      }
  512.  }
  513.  

overexertion

  1.  /* combat increases metabolism */
  2.  boolean
  3.  overexertion()
  4.  {
  5.      /* this used to be part of domove() when moving to a monster's
  6.         position, but is now called by attack() so that it doesn't
  7.         execute if you decline to attack a peaceful monster */
  8.      gethungry();
  9.      if ((moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) {
  10.          int *hp = (!Upolyd ? &u.uhp : &u.mh);
  11.  
  12.          if (*hp > 1) {
  13.              *hp -= 1;
  14.          } else {
  15.              You("pass out from exertion!");
  16.              exercise(A_CON, FALSE);
  17.              fall_asleep(-10, FALSE);
  18.          }
  19.      }
  20.      return (boolean) (multi < 0); /* might have fainted (forced to sleep) */
  21.  }
  22.  

invocation_message

  1.  void
  2.  invocation_message()
  3.  {
  4.      /* a special clue-msg when on the Invocation position */
  5.      if (invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
  6.          char buf[BUFSZ];
  7.          struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
  8.  
  9.          nomul(0); /* stop running or travelling */
  10.          if (u.usteed)
  11.              Sprintf(buf, "beneath %s", y_monnam(u.usteed));
  12.          else if (Levitation || Flying)
  13.              Strcpy(buf, "beneath you");
  14.          else
  15.              Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
  16.  
  17.          You_feel("a strange vibration %s.", buf);
  18.          u.uevent.uvibrated = 1;
  19.          if (otmp && otmp->spe == 7 && otmp->lamplit)
  20.              pline("%s %s!", The(xname(otmp)),
  21.                    Blind ? "throbs palpably" : "glows with a strange light");
  22.      }
  23.  }
  24.  

switch_terrain

  1.  /* moving onto different terrain;
  2.     might be going into solid rock, inhibiting levitation or flight,
  3.     or coming back out of such, reinstating levitation/flying */
  4.  STATIC_OVL void
  5.  switch_terrain()
  6.  {
  7.      struct rm *lev = &levl[u.ux][u.uy];
  8.      boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy)
  9.                          || (Is_waterlevel(&u.uz) && lev->typ == WATER));
  10.  
  11.      if (blocklev) {
  12.          /* called from spoteffects(), skip float_down() */
  13.          if (Levitation)
  14.              You_cant("levitate in here.");
  15.          BLevitation |= FROMOUTSIDE;
  16.      } else if (BLevitation) {
  17.          BLevitation &= ~FROMOUTSIDE;
  18.          if (Levitation)
  19.              float_up();
  20.      }
  21.      /* the same terrain that blocks levitation also blocks flight */
  22.      if (blocklev) {
  23.          if (Flying)
  24.              You_cant("fly in here.");
  25.          BFlying |= FROMOUTSIDE;
  26.      } else if (BFlying) {
  27.          BFlying &= ~FROMOUTSIDE;
  28.          float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
  29.          /* [minor bug: we don't know whether this is beginning flight or
  30.             resuming it; that could be tracked so that this message could
  31.             be adjusted to "resume flying", but isn't worth the effort...] */
  32.          if (Flying)
  33.              You("start flying.");
  34.      }
  35.  }
  36.  

pooleffects

  1.  /* extracted from spoteffects; called by spoteffects to check for entering or
  2.     leaving a pool of water/lava, and by moveloop to check for staying on one
  3.  
  4.     returns true to skip rest of spoteffects */
  5.  boolean
  6.  pooleffects(newspot)
  7.  boolean newspot;             /* true if called by spoteffects */
  8.  {
  9.      /* check for leaving water */
  10.      if (u.uinwater) {
  11.          boolean still_inwater = FALSE; /* assume we're getting out */
  12.  
  13.          if (!is_pool(u.ux, u.uy)) {
  14.              if (Is_waterlevel(&u.uz))
  15.                  You("pop into an air bubble.");
  16.              else if (is_lava(u.ux, u.uy))
  17.                  You("leave the water..."); /* oops! */
  18.              else
  19.                  You("are on solid %s again.",
  20.                      is_ice(u.ux, u.uy) ? "ice" : "land");
  21.          } else if (Is_waterlevel(&u.uz)) {
  22.              still_inwater = TRUE;
  23.          } else if (Levitation) {
  24.              You("pop out of the water like a cork!");
  25.          } else if (Flying) {
  26.              You("fly out of the water.");
  27.          } else if (Wwalking) {
  28.              You("slowly rise above the surface.");
  29.          } else {
  30.              still_inwater = TRUE;
  31.          }
  32.          if (!still_inwater) {
  33.              boolean was_underwater = (Underwater && !Is_waterlevel(&u.uz));
  34.  
  35.              u.uinwater = 0;       /* leave the water */
  36.              if (was_underwater) { /* restore vision */
  37.                  docrt();
  38.                  vision_full_recalc = 1;
  39.              }
  40.          }
  41.      }
  42.  
  43.      /* check for entering water or lava */
  44.      if (!u.ustuck && !Levitation && !Flying && is_pool_or_lava(u.ux, u.uy)) {
  45.          if (u.usteed
  46.              && (is_flyer(u.usteed->data) || is_floater(u.usteed->data)
  47.                  || is_clinger(u.usteed->data))) {
  48.              /* floating or clinging steed keeps hero safe (is_flyer() test
  49.                 is redundant; it can't be true since Flying yielded false) */
  50.              return FALSE;
  51.          } else if (u.usteed) {
  52.              /* steed enters pool */
  53.              dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC);
  54.              /* dismount_steed() -> float_down() -> pickup()
  55.                 (float_down doesn't do autopickup on Air or Water) */
  56.              if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))
  57.                  return FALSE;
  58.              /* even if we actually end up at same location, float_down()
  59.                 has already done spoteffect()'s trap and pickup actions */
  60.              if (newspot)
  61.                  check_special_room(FALSE); /* spoteffects */
  62.              return TRUE;
  63.          }
  64.          /* not mounted */
  65.  
  66.          /* drown(),lava_effects() return true if hero changes
  67.             location while surviving the problem */
  68.          if (is_lava(u.ux, u.uy)) {
  69.              if (lava_effects())
  70.                  return TRUE;
  71.          } else if (!Wwalking
  72.                     && (newspot || !u.uinwater || !(Swimming || Amphibious))) {
  73.              if (drown())
  74.                  return TRUE;
  75.          }
  76.      }
  77.      return FALSE;
  78.  }
  79.  

spoteffects

  1.  void
  2.  spoteffects(pick)
  3.  boolean pick;
  4.  {
  5.      static int inspoteffects = 0;
  6.      static coord spotloc;
  7.      static int spotterrain;
  8.      static struct trap *spottrap = (struct trap *) 0;
  9.      static unsigned spottraptyp = NO_TRAP;
  10.      struct trap *trap = t_at(u.ux, u.uy);
  11.      register struct monst *mtmp;
  12.  
  13.      /* prevent recursion from affecting the hero all over again
  14.         [hero poly'd to iron golem enters water here, drown() inflicts
  15.         damage that triggers rehumanize() which calls spoteffects()...] */
  16.      if (inspoteffects && u.ux == spotloc.x && u.uy == spotloc.y
  17.          /* except when reason is transformed terrain (ice -> water) */
  18.          && spotterrain == levl[u.ux][u.uy].typ
  19.          /* or transformed trap (land mine -> pit) */
  20.          && (!spottrap || !trap || trap->ttyp == spottraptyp))
  21.          return;
  22.  
  23.      ++inspoteffects;
  24.      spotterrain = levl[u.ux][u.uy].typ;
  25.      spotloc.x = u.ux, spotloc.y = u.uy;
  26.  
  27.      /* moving onto different terrain might cause Levitation to toggle */
  28.      if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0))
  29.          switch_terrain();
  30.  
  31.      if (pooleffects(TRUE))
  32.          goto spotdone;
  33.  
  34.      check_special_room(FALSE);
  35.      if (IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
  36.          dosinkfall();
  37.      if (!in_steed_dismounting) { /* if dismounting, we'll check again later */
  38.          boolean pit;
  39.  
  40.          /* if levitation is due to time out at the end of this
  41.             turn, allowing it to do so could give the perception
  42.             that a trap here is being triggered twice, so adjust
  43.             the timeout to prevent that */
  44.          if (trap && (HLevitation & TIMEOUT) == 1L && !ELevitation
  45.              && !(HLevitation & ~TIMEOUT)) {
  46.              if (rn2(2)) { /* defer timeout */
  47.                  incr_itimeout(&HLevitation, 1L);
  48.              } else { /* timeout early */
  49.                  if (float_down(I_SPECIAL | TIMEOUT, 0L)) {
  50.                      /* levitation has ended; we've already triggered
  51.                         any trap and [usually] performed autopickup */
  52.                      trap = 0;
  53.                      pick = FALSE;
  54.                  }
  55.              }
  56.          }
  57.          /*
  58.       * If not a pit, pickup before triggering trap.
  59.       * If pit, trigger trap before pickup.
  60.       */
  61.          pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT));
  62.          if (pick && !pit)
  63.              (void) pickup(1);
  64.  
  65.          if (trap) {
  66.              /*
  67.           * dotrap on a fire trap calls melt_ice() which triggers
  68.           * spoteffects() (again) which can trigger the same fire
  69.           * trap (again). Use static spottrap to prevent that.
  70.           * We track spottraptyp because some traps morph
  71.           * (landmine to pit) and any new trap type
  72.           * should get triggered.
  73.           */
  74.              if (!spottrap || spottraptyp != trap->ttyp) {
  75.                  spottrap = trap;
  76.                  spottraptyp = trap->ttyp;
  77.                  dotrap(trap, 0); /* fall into arrow trap, etc. */
  78.                  spottrap = (struct trap *) 0;
  79.                  spottraptyp = NO_TRAP;
  80.              }
  81.          }
  82.          if (pick && pit)
  83.              (void) pickup(1);
  84.      }
  85.      /* Warning alerts you to ice danger */
  86.      if (Warning && is_ice(u.ux, u.uy)) {
  87.          static const char *const icewarnings[] = {
  88.              "The ice seems very soft and slushy.",
  89.              "You feel the ice shift beneath you!",
  90.              "The ice, is gonna BREAK!", /* The Dead Zone */
  91.          };
  92.          long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY);
  93.          if (time_left && time_left < 15L)
  94.              pline1((time_left < 5L) ? icewarnings[2] : (time_left < 10L)
  95.                                                             ? icewarnings[1]
  96.                                                             : icewarnings[0]);
  97.      }
  98.      if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
  99.          mtmp->mundetected = mtmp->msleeping = 0;
  100.          switch (mtmp->data->mlet) {
  101.          case S_PIERCER:
  102.              pline("%s suddenly drops from the %s!", Amonnam(mtmp),
  103.                    ceiling(u.ux, u.uy));
  104.              if (mtmp->mtame) /* jumps to greet you, not attack */
  105.                  ;
  106.              else if (uarmh && is_metallic(uarmh))
  107.                  pline("Its blow glances off your %s.",
  108.                        helm_simple_name(uarmh));
  109.              else if (u.uac + 3 <= rnd(20))
  110.                  You("are almost hit by %s!",
  111.                      x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
  112.              else {
  113.                  int dmg;
  114.                  You("are hit by %s!",
  115.                      x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
  116.                  dmg = d(4, 6);
  117.                  if (Half_physical_damage)
  118.                      dmg = (dmg + 1) / 2;
  119.                  mdamageu(mtmp, dmg);
  120.              }
  121.              break;
  122.          default: /* monster surprises you. */
  123.              if (mtmp->mtame)
  124.                  pline("%s jumps near you from the %s.", Amonnam(mtmp),
  125.                        ceiling(u.ux, u.uy));
  126.              else if (mtmp->mpeaceful) {
  127.                  You("surprise %s!",
  128.                      Blind && !sensemon(mtmp) ? something : a_monnam(mtmp));
  129.                  mtmp->mpeaceful = 0;
  130.              } else
  131.                  pline("%s attacks you by surprise!", Amonnam(mtmp));
  132.              break;
  133.          }
  134.          mnexto(mtmp); /* have to move the monster */
  135.      }
  136.  spotdone:
  137.      if (!--inspoteffects) {
  138.          spotterrain = STONE; /* 0 */
  139.          spotloc.x = spotloc.y = 0;
  140.      }
  141.      return;
  142.  }
  143.  

monstinroom

  1.  /* returns first matching monster */
  2.  STATIC_OVL struct monst *
  3.  monstinroom(mdat, roomno)
  4.  struct permonst *mdat;
  5.  int roomno;
  6.  {
  7.      register struct monst *mtmp;
  8.  
  9.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  10.          if (DEADMONSTER(mtmp))
  11.              continue;
  12.          if (mtmp->data == mdat
  13.              && index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
  14.              return mtmp;
  15.      }
  16.      return (struct monst *) 0;
  17.  }
  18.  

in_rooms

  1.  char *
  2.  in_rooms(x, y, typewanted)
  3.  register xchar x, y;
  4.  register int typewanted;
  5.  {
  6.      static char buf[5];
  7.      char rno, *ptr = &buf[4];
  8.      int typefound, min_x, min_y, max_x, max_y_offset, step;
  9.      register struct rm *lev;
  10.  
  11.  #define goodtype(rno)                                               \
  12.      (!typewanted                                                    \
  13.       || ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) \
  14.       || ((typewanted == SHOPBASE) && (typefound > SHOPBASE)))
  15.  
  16.      switch (rno = levl[x][y].roomno) {
  17.      case NO_ROOM:
  18.          return ptr;
  19.      case SHARED:
  20.          step = 2;
  21.          break;
  22.      case SHARED_PLUS:
  23.          step = 1;
  24.          break;
  25.      default: /* i.e. a regular room # */
  26.          if (goodtype(rno))
  27.              *(--ptr) = rno;
  28.          return ptr;
  29.      }
  30.  
  31.      min_x = x - 1;
  32.      max_x = x + 1;
  33.      if (x < 1)
  34.          min_x += step;
  35.      else if (x >= COLNO)
  36.          max_x -= step;
  37.  
  38.      min_y = y - 1;
  39.      max_y_offset = 2;
  40.      if (min_y < 0) {
  41.          min_y += step;
  42.          max_y_offset -= step;
  43.      } else if ((min_y + max_y_offset) >= ROWNO)
  44.          max_y_offset -= step;
  45.  
  46.      for (x = min_x; x <= max_x; x += step) {
  47.          lev = &levl[x][min_y];
  48.          y = 0;
  49.          if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
  50.              && goodtype(rno))
  51.              *(--ptr) = rno;
  52.          y += step;
  53.          if (y > max_y_offset)
  54.              continue;
  55.          if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
  56.              && goodtype(rno))
  57.              *(--ptr) = rno;
  58.          y += step;
  59.          if (y > max_y_offset)
  60.              continue;
  61.          if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
  62.              && goodtype(rno))
  63.              *(--ptr) = rno;
  64.      }
  65.      return ptr;
  66.  }
  67.  

in_town

  1.  /* is (x,y) in a town? */
  2.  boolean
  3.  in_town(x, y)
  4.  register int x, y;
  5.  {
  6.      s_level *slev = Is_special(&u.uz);
  7.      register struct mkroom *sroom;
  8.      boolean has_subrooms = FALSE;
  9.  
  10.      if (!slev || !slev->flags.town)
  11.          return FALSE;
  12.  
  13.      /*
  14.       * See if (x,y) is in a room with subrooms, if so, assume it's the
  15.       * town.  If there are no subrooms, the whole level is in town.
  16.       */
  17.      for (sroom = &rooms[0]; sroom->hx > 0; sroom++) {
  18.          if (sroom->nsubrooms > 0) {
  19.              has_subrooms = TRUE;
  20.              if (inside_room(sroom, x, y))
  21.                  return TRUE;
  22.          }
  23.      }
  24.  
  25.      return !has_subrooms;
  26.  }
  27.  

move_update

  1.  STATIC_OVL void
  2.  move_update(newlev)
  3.  register boolean newlev;
  4.  {
  5.      char *ptr1, *ptr2, *ptr3, *ptr4;
  6.  
  7.      Strcpy(u.urooms0, u.urooms);
  8.      Strcpy(u.ushops0, u.ushops);
  9.      if (newlev) {
  10.          u.urooms[0] = '\0';
  11.          u.uentered[0] = '\0';
  12.          u.ushops[0] = '\0';
  13.          u.ushops_entered[0] = '\0';
  14.          Strcpy(u.ushops_left, u.ushops0);
  15.          return;
  16.      }
  17.      Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
  18.  
  19.      for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0],
  20.          ptr4 = &u.ushops_entered[0];
  21.           *ptr1; ptr1++) {
  22.          if (!index(u.urooms0, *ptr1))
  23.              *(ptr2++) = *ptr1;
  24.          if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
  25.              *(ptr3++) = *ptr1;
  26.              if (!index(u.ushops0, *ptr1))
  27.                  *(ptr4++) = *ptr1;
  28.          }
  29.      }
  30.      *ptr2 = '\0';
  31.      *ptr3 = '\0';
  32.      *ptr4 = '\0';
  33.  
  34.      /* filter u.ushops0 -> u.ushops_left */
  35.      for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
  36.          if (!index(u.ushops, *ptr1))
  37.              *(ptr2++) = *ptr1;
  38.      *ptr2 = '\0';
  39.  }
  40.  

check_special_room

  1.  void
  2.  check_special_room(newlev)
  3.  register boolean newlev;
  4.  {
  5.      register struct monst *mtmp;
  6.      char *ptr;
  7.  
  8.      move_update(newlev);
  9.  
  10.      if (*u.ushops0)
  11.          u_left_shop(u.ushops_left, newlev);
  12.  
  13.      if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */
  14.          return; /* no entrance messages necessary */
  15.  
  16.      /* Did we just enter a shop? */
  17.      if (*u.ushops_entered)
  18.          u_entered_shop(u.ushops_entered);
  19.  
  20.      for (ptr = &u.uentered[0]; *ptr; ptr++) {
  21.          int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
  22.          boolean msg_given = TRUE;
  23.  
  24.          /* Did we just enter some other special room? */
  25.          /* vault.c insists that a vault remain a VAULT,
  26.           * and temples should remain TEMPLEs,
  27.           * but everything else gives a message only the first time */
  28.          switch (rt) {
  29.          case ZOO:
  30.              pline("Welcome to David's treasure zoo!");
  31.              break;
  32.          case SWAMP:
  33.              pline("It %s rather %s down here.", Blind ? "feels" : "looks",
  34.                    Blind ? "humid" : "muddy");
  35.              break;
  36.          case COURT:
  37.              You("enter an opulent throne room!");
  38.              break;
  39.          case LEPREHALL:
  40.              You("enter a leprechaun hall!");
  41.              break;
  42.          case MORGUE:
  43.              if (midnight()) {
  44.                  const char *run = locomotion(youmonst.data, "Run");
  45.                  pline("%s away!  %s away!", run, run);
  46.              } else
  47.                  You("have an uncanny feeling...");
  48.              break;
  49.          case BEEHIVE:
  50.              You("enter a giant beehive!");
  51.              break;
  52.          case COCKNEST:
  53.              You("enter a disgusting nest!");
  54.              break;
  55.          case ANTHOLE:
  56.              You("enter an anthole!");
  57.              break;
  58.          case BARRACKS:
  59.              if (monstinroom(&mons[PM_SOLDIER], roomno)
  60.                  || monstinroom(&mons[PM_SERGEANT], roomno)
  61.                  || monstinroom(&mons[PM_LIEUTENANT], roomno)
  62.                  || monstinroom(&mons[PM_CAPTAIN], roomno))
  63.                  You("enter a military barracks!");
  64.              else
  65.                  You("enter an abandoned barracks.");
  66.              break;
  67.          case DELPHI: {
  68.              struct monst *oracle = monstinroom(&mons[PM_ORACLE], roomno);
  69.              if (oracle) {
  70.                  if (!oracle->mpeaceful)
  71.                      verbalize("You're in Delphi, %s.", plname);
  72.                  else
  73.                      verbalize("%s, %s, welcome to Delphi!",
  74.                                Hello((struct monst *) 0), plname);
  75.              } else
  76.                  msg_given = FALSE;
  77.              break;
  78.          }
  79.          case TEMPLE:
  80.              intemple(roomno + ROOMOFFSET);
  81.          /*FALLTHRU*/
  82.          default:
  83.              msg_given = (rt == TEMPLE);
  84.              rt = 0;
  85.              break;
  86.          }
  87.          if (msg_given)
  88.              room_discovered(roomno);
  89.  
  90.          if (rt != 0) {
  91.              rooms[roomno].rtype = OROOM;
  92.              if (!search_special(rt)) {
  93.                  /* No more room of that type */
  94.                  switch (rt) {
  95.                  case COURT:
  96.                      level.flags.has_court = 0;
  97.                      break;
  98.                  case SWAMP:
  99.                      level.flags.has_swamp = 0;
  100.                      break;
  101.                  case MORGUE:
  102.                      level.flags.has_morgue = 0;
  103.                      break;
  104.                  case ZOO:
  105.                      level.flags.has_zoo = 0;
  106.                      break;
  107.                  case BARRACKS:
  108.                      level.flags.has_barracks = 0;
  109.                      break;
  110.                  case TEMPLE:
  111.                      level.flags.has_temple = 0;
  112.                      break;
  113.                  case BEEHIVE:
  114.                      level.flags.has_beehive = 0;
  115.                      break;
  116.                  }
  117.              }
  118.              if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
  119.                  for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  120.                      if (DEADMONSTER(mtmp))
  121.                          continue;
  122.                      if (!Stealth && !rn2(3))
  123.                          mtmp->msleeping = 0;
  124.                  }
  125.          }
  126.      }
  127.  
  128.      return;
  129.  }
  130.  

dopickup

  1.  int
  2.  dopickup()
  3.  {
  4.      int count;
  5.      struct trap *traphere = t_at(u.ux, u.uy);
  6.      /* awful kludge to work around parse()'s pre-decrement */
  7.      count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
  8.      multi = 0; /* always reset */
  9.      /* uswallow case added by GAN 01/29/87 */
  10.      if (u.uswallow) {
  11.          if (!u.ustuck->minvent) {
  12.              if (is_animal(u.ustuck->data)) {
  13.                  You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
  14.                  pline("But it's kind of slimy, so you drop it.");
  15.              } else
  16.                  You("don't %s anything in here to pick up.",
  17.                      Blind ? "feel" : "see");
  18.              return 1;
  19.          } else {
  20.              int tmpcount = -count;
  21.              return loot_mon(u.ustuck, &tmpcount, (boolean *) 0);
  22.          }
  23.      }
  24.      if (is_pool(u.ux, u.uy)) {
  25.          if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
  26.              || (Flying && !Breathless)) {
  27.              You("cannot dive into the water to pick things up.");
  28.              return 0;
  29.          } else if (!Underwater) {
  30.              You_cant("even see the bottom, let alone pick up %s.", something);
  31.              return 0;
  32.          }
  33.      }
  34.      if (is_lava(u.ux, u.uy)) {
  35.          if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
  36.              || (Flying && !Breathless)) {
  37.              You_cant("reach the bottom to pick things up.");
  38.              return 0;
  39.          } else if (!likes_lava(youmonst.data)) {
  40.              You("would burn to a crisp trying to pick things up.");
  41.              return 0;
  42.          }
  43.      }
  44.      if (!OBJ_AT(u.ux, u.uy)) {
  45.          register struct rm *lev = &levl[u.ux][u.uy];
  46.          if (IS_THRONE(lev->typ))
  47.              pline("It must weigh%s a ton!", lev->looted ? " almost" : "");
  48.          else if (IS_SINK(lev->typ))
  49.              pline_The("plumbing connects it to the floor.");
  50.          else if (IS_GRAVE(lev->typ))
  51.              You("don't need a gravestone.  Yet.");
  52.          else if (IS_FOUNTAIN(lev->typ))
  53.              You("could drink the water...");
  54.          else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
  55.              pline("It won't come off the hinges.");
  56.          else
  57.              There("is nothing here to pick up.");
  58.          return 0;
  59.      }
  60.      if (!can_reach_floor(TRUE)) {
  61.          if (traphere && uteetering_at_seen_pit(traphere))
  62.              You("cannot reach the bottom of the pit.");
  63.          else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
  64.              rider_cant_reach();
  65.          else if (Blind && !can_reach_floor(TRUE))
  66.              You("cannot reach anything here.");
  67.          else
  68.              You("cannot reach the %s.", surface(u.ux, u.uy));
  69.          return 0;
  70.      }
  71.  
  72.      return pickup(-count);
  73.  }
  74.  

lookaround

  1.  /* stop running if we see something interesting */
  2.  /* turn around a corner if that is the only way we can proceed */
  3.  /* do not turn left or right twice */
  4.  void
  5.  lookaround()
  6.  {
  7.      register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
  8.      register int corrct = 0, noturn = 0;
  9.      register struct monst *mtmp;
  10.      register struct trap *trap;
  11.  
  12.      /* Grid bugs stop if trying to move diagonal, even if blind.  Maybe */
  13.      /* they polymorphed while in the middle of a long move. */
  14.      if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) {
  15.          nomul(0);
  16.          return;
  17.      }
  18.  
  19.      if (Blind || context.run == 0)
  20.          return;
  21.      for (x = u.ux - 1; x <= u.ux + 1; x++)
  22.          for (y = u.uy - 1; y <= u.uy + 1; y++) {
  23.              if (!isok(x, y))
  24.                  continue;
  25.  
  26.              if (u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy)
  27.                  continue;
  28.  
  29.              if (x == u.ux && y == u.uy)
  30.                  continue;
  31.  
  32.              if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE
  33.                  && mtmp->m_ap_type != M_AP_OBJECT
  34.                  && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
  35.                  if ((context.run != 1 && !mtmp->mtame)
  36.                      || (x == u.ux + u.dx && y == u.uy + u.dy))
  37.                      goto stop;
  38.              }
  39.  
  40.              if (levl[x][y].typ == STONE)
  41.                  continue;
  42.              if (x == u.ux - u.dx && y == u.uy - u.dy)
  43.                  continue;
  44.  
  45.              if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM)
  46.                  || IS_AIR(levl[x][y].typ))
  47.                  continue;
  48.              else if (closed_door(x, y)
  49.                       || (mtmp && is_door_mappear(mtmp))) {
  50.                  if (x != u.ux && y != u.uy)
  51.                      continue;
  52.                  if (context.run != 1)
  53.                      goto stop;
  54.                  goto bcorr;
  55.              } else if (levl[x][y].typ == CORR) {
  56.              bcorr:
  57.                  if (levl[u.ux][u.uy].typ != ROOM) {
  58.                      if (context.run == 1 || context.run == 3
  59.                          || context.run == 8) {
  60.                          i = dist2(x, y, u.ux + u.dx, u.uy + u.dy);
  61.                          if (i > 2)
  62.                              continue;
  63.                          if (corrct == 1 && dist2(x, y, x0, y0) != 1)
  64.                              noturn = 1;
  65.                          if (i < i0) {
  66.                              i0 = i;
  67.                              x0 = x;
  68.                              y0 = y;
  69.                              m0 = mtmp ? 1 : 0;
  70.                          }
  71.                      }
  72.                      corrct++;
  73.                  }
  74.                  continue;
  75.              } else if ((trap = t_at(x, y)) && trap->tseen) {
  76.                  if (context.run == 1)
  77.                      goto bcorr; /* if you must */
  78.                  if (x == u.ux + u.dx && y == u.uy + u.dy)
  79.                      goto stop;
  80.                  continue;
  81.              } else if (is_pool_or_lava(x, y)) {
  82.                  /* water and lava only stop you if directly in front, and stop
  83.                   * you even if you are running
  84.                   */
  85.                  if (!Levitation && !Flying && !is_clinger(youmonst.data)
  86.                      && x == u.ux + u.dx && y == u.uy + u.dy)
  87.                      /* No Wwalking check; otherwise they'd be able
  88.                       * to test boots by trying to SHIFT-direction
  89.                       * into a pool and seeing if the game allowed it
  90.                       */
  91.                      goto stop;
  92.                  continue;
  93.              } else { /* e.g. objects or trap or stairs */
  94.                  if (context.run == 1)
  95.                      goto bcorr;
  96.                  if (context.run == 8)
  97.                      continue;
  98.                  if (mtmp)
  99.                      continue; /* d */
  100.                  if (((x == u.ux - u.dx) && (y != u.uy + u.dy))
  101.                      || ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
  102.                      continue;
  103.              }
  104.          stop:
  105.              nomul(0);
  106.              return;
  107.          } /* end for loops */
  108.  
  109.      if (corrct > 1 && context.run == 2)
  110.          goto stop;
  111.      if ((context.run == 1 || context.run == 3 || context.run == 8) && !noturn
  112.          && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) {
  113.          /* make sure that we do not turn too far */
  114.          if (i0 == 2) {
  115.              if (u.dx == y0 - u.uy && u.dy == u.ux - x0)
  116.                  i = 2; /* straight turn right */
  117.              else
  118.                  i = -2; /* straight turn left */
  119.          } else if (u.dx && u.dy) {
  120.              if ((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
  121.                  i = -1; /* half turn left */
  122.              else
  123.                  i = 1; /* half turn right */
  124.          } else {
  125.              if ((x0 - u.ux == y0 - u.uy && !u.dy)
  126.                  || (x0 - u.ux != y0 - u.uy && u.dy))
  127.                  i = 1; /* half turn right */
  128.              else
  129.                  i = -1; /* half turn left */
  130.          }
  131.  
  132.          i += u.last_str_turn;
  133.          if (i <= 2 && i >= -2) {
  134.              u.last_str_turn = i;
  135.              u.dx = x0 - u.ux;
  136.              u.dy = y0 - u.uy;
  137.          }
  138.      }
  139.  }
  140.  

doorless_door

  1.  /* check for a doorway which lacks its door (NODOOR or BROKEN) */
  2.  STATIC_OVL boolean
  3.  doorless_door(x, y)
  4.  int x, y;
  5.  {
  6.      struct rm *lev_p = &levl[x][y];
  7.  
  8.      if (!IS_DOOR(lev_p->typ))
  9.          return FALSE;
  10.      /* all rogue level doors are doorless but disallow diagonal access, so
  11.         we treat them as if their non-existant doors were actually present */
  12.      if (Is_rogue_level(&u.uz))
  13.          return FALSE;
  14.      return !(lev_p->doormask & ~(D_NODOOR | D_BROKEN));
  15.  }
  16.  

crawl_destination

  1.  /* used by drown() to check whether hero can crawl from water to <x,y> */
  2.  boolean
  3.  crawl_destination(x, y)
  4.  int x, y;
  5.  {
  6.      /* is location ok in general? */
  7.      if (!goodpos(x, y, &youmonst, 0))
  8.          return FALSE;
  9.  
  10.      /* orthogonal movement is unrestricted when destination is ok */
  11.      if (x == u.ux || y == u.uy)
  12.          return TRUE;
  13.  
  14.      /* diagonal movement has some restrictions */
  15.      if (NODIAG(u.umonnum))
  16.          return FALSE; /* poly'd into a grid bug... */
  17.      if (Passes_walls)
  18.          return TRUE; /* or a xorn... */
  19.      /* pool could be next to a door, conceivably even inside a shop */
  20.      if (IS_DOOR(levl[x][y].typ) && (!doorless_door(x, y) || block_door(x, y)))
  21.          return FALSE;
  22.      /* finally, are we trying to squeeze through a too-narrow gap? */
  23.      return !(bad_rock(youmonst.data, u.ux, y)
  24.               && bad_rock(youmonst.data, x, u.uy));
  25.  }
  26.  

monster_nearby

  1.  /* something like lookaround, but we are not running */
  2.  /* react only to monsters that might hit us */
  3.  int
  4.  monster_nearby()
  5.  {
  6.      register int x, y;
  7.      register struct monst *mtmp;
  8.  
  9.      /* Also see the similar check in dochugw() in monmove.c */
  10.      for (x = u.ux - 1; x <= u.ux + 1; x++)
  11.          for (y = u.uy - 1; y <= u.uy + 1; y++) {
  12.              if (!isok(x, y))
  13.                  continue;
  14.              if (x == u.ux && y == u.uy)
  15.                  continue;
  16.              if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE
  17.                  && mtmp->m_ap_type != M_AP_OBJECT
  18.                  && (!mtmp->mpeaceful || Hallucination)
  19.                  && (!is_hider(mtmp->data) || !mtmp->mundetected)
  20.                  && !noattacks(mtmp->data) && mtmp->mcanmove
  21.                  && !mtmp->msleeping  /* aplvax!jcn */
  22.                  && !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp))
  23.                  return 1;
  24.          }
  25.      return 0;
  26.  }
  27.  

nomul

  1.  void
  2.  nomul(nval)
  3.  register int nval;
  4.  {
  5.      if (multi < nval)
  6.          return;              /* This is a bug fix by ab@unido */
  7.      u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */
  8.      u.usleep = 0;
  9.      multi = nval;
  10.      if (nval == 0)
  11.          multi_reason = NULL;
  12.      context.travel = context.travel1 = context.mv = context.run = 0;
  13.  }
  14.  

unmul

  1.  /* called when a non-movement, multi-turn action has completed */
  2.  void
  3.  unmul(msg_override)
  4.  const char *msg_override;
  5.  {
  6.      multi = 0; /* caller will usually have done this already */
  7.      if (msg_override)
  8.          nomovemsg = msg_override;
  9.      else if (!nomovemsg)
  10.          nomovemsg = You_can_move_again;
  11.      if (*nomovemsg)
  12.          pline1(nomovemsg);
  13.      nomovemsg = 0;
  14.      u.usleep = 0;
  15.      multi_reason = NULL;
  16.      if (afternmv)
  17.          (*afternmv)();
  18.      afternmv = 0;
  19.  }
  20.  

maybe_wail

  1.  STATIC_OVL void
  2.  maybe_wail()
  3.  {
  4.      static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
  5.                                SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
  6.                                TELEPORT_CONTROL, STEALTH, FAST, INVIS };
  7.  
  8.      if (moves <= wailmsg + 50)
  9.          return;
  10.  
  11.      wailmsg = moves;
  12.      if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
  13.          const char *who;
  14.          int i, powercnt;
  15.  
  16.          who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m
  17.                                                             : "Elf";
  18.          if (u.uhp == 1) {
  19.              pline("%s is about to die.", who);
  20.          } else {
  21.              for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
  22.                  if (u.uprops[powers[i]].intrinsic & INTRINSIC)
  23.                      ++powercnt;
  24.  
  25.              pline(powercnt >= 4 ? "%s, all your powers will be lost..."
  26.                                  : "%s, your life force is running out.",
  27.                    who);
  28.          }
  29.      } else {
  30.          You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
  31.                              : "the howling of the CwnAnnwn...");
  32.      }
  33.  }
  34.  

losehp

  1.  void
  2.  losehp(n, knam, k_format)
  3.  register int n;
  4.  register const char *knam;
  5.  boolean k_format;
  6.  {
  7.      if (Upolyd) {
  8.          u.mh -= n;
  9.          if (u.mhmax < u.mh)
  10.              u.mhmax = u.mh;
  11.          context.botl = 1;
  12.          if (u.mh < 1)
  13.              rehumanize();
  14.          else if (n > 0 && u.mh * 10 < u.mhmax && Unchanging)
  15.              maybe_wail();
  16.          return;
  17.      }
  18.  
  19.      u.uhp -= n;
  20.      if (u.uhp > u.uhpmax)
  21.          u.uhpmax = u.uhp; /* perhaps n was negative */
  22.      context.botl = 1;
  23.      if (u.uhp < 1) {
  24.          killer.format = k_format;
  25.          if (killer.name != knam) /* the thing that killed you */
  26.              Strcpy(killer.name, knam ? knam : "");
  27.          You("die...");
  28.          done(DIED);
  29.      } else if (n > 0 && u.uhp * 10 < u.uhpmax) {
  30.          maybe_wail();
  31.      }
  32.  }
  33.  

weight_cap

  1.  int
  2.  weight_cap()
  3.  {
  4.      register long carrcap;
  5.  
  6.      carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50;
  7.      if (Upolyd) {
  8.          /* consistent with can_carry() in mon.c */
  9.          if (youmonst.data->mlet == S_NYMPH)
  10.              carrcap = MAX_CARR_CAP;
  11.          else if (!youmonst.data->cwt)
  12.              carrcap = (carrcap * (long) youmonst.data->msize) / MZ_HUMAN;
  13.          else if (!strongmonst(youmonst.data)
  14.                   || (strongmonst(youmonst.data)
  15.                       && (youmonst.data->cwt > WT_HUMAN)))
  16.              carrcap = (carrcap * (long) youmonst.data->cwt / WT_HUMAN);
  17.      }
  18.  
  19.      if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */
  20.          || (u.usteed && strongmonst(u.usteed->data)))
  21.          carrcap = MAX_CARR_CAP;
  22.      else {
  23.          if (carrcap > MAX_CARR_CAP)
  24.              carrcap = MAX_CARR_CAP;
  25.          if (!Flying) {
  26.              if (EWounded_legs & LEFT_SIDE)
  27.                  carrcap -= 100;
  28.              if (EWounded_legs & RIGHT_SIDE)
  29.                  carrcap -= 100;
  30.          }
  31.          if (carrcap < 0)
  32.              carrcap = 0;
  33.      }
  34.      return (int) carrcap;
  35.  }
  36.  

inv_weight

  1.  static int wc; /* current weight_cap(); valid after call to inv_weight() */
  2.  
  3.  /* returns how far beyond the normal capacity the player is currently. */
  4.  /* inv_weight() is negative if the player is below normal capacity. */
  5.  int
  6.  inv_weight()
  7.  {
  8.      register struct obj *otmp = invent;
  9.      register int wt = 0;
  10.  
  11.      while (otmp) {
  12.          if (otmp->oclass == COIN_CLASS)
  13.              wt += (int) (((long) otmp->quan + 50L) / 100L);
  14.          else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
  15.              wt += otmp->owt;
  16.          otmp = otmp->nobj;
  17.      }
  18.      wc = weight_cap();
  19.      return (wt - wc);
  20.  }
  21.  

calc_capacity

  1.  /*
  2.   * Returns 0 if below normal capacity, or the number of "capacity units"
  3.   * over the normal capacity the player is loaded.  Max is 5.
  4.   */
  5.  int
  6.  calc_capacity(xtra_wt)
  7.  int xtra_wt;
  8.  {
  9.      int cap, wt = inv_weight() + xtra_wt;
  10.  
  11.      if (wt <= 0)
  12.          return UNENCUMBERED;
  13.      if (wc <= 1)
  14.          return OVERLOADED;
  15.      cap = (wt * 2 / wc) + 1;
  16.      return min(cap, OVERLOADED);
  17.  }
  18.  

near_capacity

  1.  int
  2.  near_capacity()
  3.  {
  4.      return calc_capacity(0);
  5.  }
  6.  

max_capacity

  1.  int
  2.  max_capacity()
  3.  {
  4.      int wt = inv_weight();
  5.  
  6.      return (wt - (2 * wc));
  7.  }
  8.  

check_capacity

  1.  boolean
  2.  check_capacity(str)
  3.  const char *str;
  4.  {
  5.      if (near_capacity() >= EXT_ENCUMBER) {
  6.          if (str)
  7.              pline1(str);
  8.          else
  9.              You_cant("do that while carrying so much stuff.");
  10.          return 1;
  11.      }
  12.      return 0;
  13.  }
  14.  

inv_cnt

  1.  int
  2.  inv_cnt(incl_gold)
  3.  boolean incl_gold;
  4.  {
  5.      register struct obj *otmp = invent;
  6.      register int ct = 0;
  7.  
  8.      while (otmp) {
  9.          if (incl_gold || otmp->invlet != GOLD_SYM)
  10.              ct++;
  11.          otmp = otmp->nobj;
  12.      }
  13.      return ct;
  14.  }
  15.  

money_cnt

  1.  /* Counts the money in an object chain. */
  2.  /* Intended use is for your or some monsters inventory, */
  3.  /* now that u.gold/m.gold is gone.*/
  4.  /* Counting money in a container might be possible too. */
  5.  long
  6.  money_cnt(otmp)
  7.  struct obj *otmp;
  8.  {
  9.      while (otmp) {
  10.          /* Must change when silver & copper is implemented: */
  11.          if (otmp->oclass == COIN_CLASS)
  12.              return otmp->quan;
  13.          otmp = otmp->nobj;
  14.      }
  15.      return 0L;
  16.  }
  17.  
  18.  /*hack.c*/