]> granicus.if.org Git - nethack/commitdiff
Merge branch 'master' into derek-farming
authorDerek S. Ray <derekray@gmail.com>
Sun, 29 Mar 2015 21:32:12 +0000 (17:32 -0400)
committerDerek S. Ray <derekray@gmail.com>
Sun, 29 Mar 2015 21:32:12 +0000 (17:32 -0400)
* master: (41 commits)
  Add more explicit helpless reasons
  add data.base suggestion for whistle
  Use existing function to count containers
  ...

Conflicts:
src/do.c
src/hack.c
src/invent.c
src/mon.c
src/objnam.c

1  2 
include/extern.h
include/obj.h
src/do.c
src/hack.c
src/invent.c
src/mon.c
src/objnam.c
src/read.c

Simple merge
diff --cc include/obj.h
Simple merge
diff --cc src/do.c
index 1fe18d7c5d206f72ee5a8e1767c5bf604ab78bb2,c690ad4faffde67d9f8d5a367cc40270200f7071..d253af1330539d34e3497f0c2c0884b7218f62e4
+++ b/src/do.c
@@@ -1034,382 -1026,383 +1034,383 @@@ boolean at_stairs, falling, portal
         *       -1   11.46  12.50  12.5
         *       -2    5.21   4.17   0.0
         *       -3    2.08   0.0    0.0
 -       */
 -      if (Inhell && up && u.uhave.amulet && !newdungeon && !portal &&
 -                              (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
 -              if (!rn2(4)) {
 -                  int odds = 3 + (int)u.ualign.type,          /* 2..4 */
 -                      diff = odds <= 1 ? 0 : rn2(odds);       /* paranoia */
 -
 -                  if (diff != 0) {
 -                      assign_rnd_level(newlevel, &u.uz, diff);
 -                      /* if inside the tower, stay inside */
 -                      if (was_in_W_tower &&
 -                          !On_W_tower_level(newlevel)) diff = 0;
 -                  }
 -                  if (diff == 0)
 -                      assign_level(newlevel, &u.uz);
 -
 -                  new_ledger = ledger_no(newlevel);
 -
 -                  pline("A mysterious force momentarily surrounds you...");
 -                  if (on_level(newlevel, &u.uz)) {
 -                      (void) safe_teleds(FALSE);
 -                      (void) next_to_u();
 -                      return;
 -                  } else
 -                      at_stairs = at_ladder = FALSE;
 -              }
 -      }
 +     */
 +    if (Inhell && up && u.uhave.amulet && !newdungeon && !portal &&
 +                (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
 +        if (!rn2(4)) {
 +            int odds = 3 + (int)u.ualign.type,                /* 2..4 */
 +            diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */
 +
 +            if (diff != 0) {
 +            assign_rnd_level(newlevel, &u.uz, diff);
 +            /* if inside the tower, stay inside */
 +            if (was_in_W_tower &&
 +                !On_W_tower_level(newlevel)) diff = 0;
 +            }
 +            if (diff == 0)
 +            assign_level(newlevel, &u.uz);
 +
 +            new_ledger = ledger_no(newlevel);
 +
 +            pline("A mysterious force momentarily surrounds you...");
 +            if (on_level(newlevel, &u.uz)) {
 +            (void) safe_teleds(FALSE);
 +            (void) next_to_u();
 +            return;
 +            } else
 +            at_stairs = at_ladder = FALSE;
 +        }
 +    }
  
 -      /* Prevent the player from going past the first quest level unless
 -       * (s)he has been given the go-ahead by the leader.
 -       */
 -      if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
 -              pline("A mysterious force prevents you from descending.");
 -              return;
 -      }
 +    /* Prevent the player from going past the first quest level unless
 +     * (s)he has been given the go-ahead by the leader.
 +     */
 +    if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
 +        pline("A mysterious force prevents you from descending.");
 +        return;
 +    }
  
 -      if (on_level(newlevel, &u.uz)) return;          /* this can happen */
 -
 -      /* tethered movement makes level change while trapped feasible */
 -      if (u.utrap && u.utraptype == TT_BURIEDBALL)
 -          buried_ball_to_punishment(); /* (before we save/leave old level) */
 -
 -      fd = currentlevel_rewrite();
 -      if (fd < 0) return;
 -
 -      if (falling) /* assuming this is only trap door or hole */
 -          impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
 -
 -      check_special_room(TRUE);               /* probably was a trap door */
 -      if (Punished) unplacebc();
 -      u.utrap = 0;                            /* needed in level_tele */
 -      fill_pit(u.ux, u.uy);
 -      u.ustuck = 0;                           /* idem */
 -      u.uinwater = 0;
 -      u.uundetected = 0;      /* not hidden, even if means are available */
 -      keepdogs(FALSE);
 -      if (u.uswallow)                         /* idem */
 -              u.uswldtim = u.uswallow = 0;
 -      recalc_mapseen(); /* recalculate map overview before we leave the level */
 -      /*
 -       *  We no longer see anything on the level.  Make sure that this
 -       *  follows u.uswallow set to null since uswallow overrides all
 -       *  normal vision.
 -       */
 -      vision_recalc(2);
 -
 -      /*
 -       * Save the level we're leaving.  If we're entering the endgame,
 -       * we can get rid of all existing levels because they cannot be
 -       * reached any more.  We still need to use savelev()'s cleanup
 -       * for the level being left, to recover dynamic memory in use and
 -       * to avoid dangling timers and light sources.
 -       */
 -      cant_go_back = (newdungeon && In_endgame(newlevel));
 -      if (!cant_go_back) {
 -          update_mlstmv();    /* current monsters are becoming inactive */
 -          bufon(fd);          /* use buffered output */
 -      }
 -      savelev(fd, ledger_no(&u.uz),
 -              cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
 -      bclose(fd);
 -      if (cant_go_back) {
 -          /* discard unreachable levels; keep #0 */
 -          for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
 -              delete_levelfile(l_idx);
 -          /* mark #overview data for all dungeon branches as uninteresting */
 -          for (l_idx = 0; l_idx < n_dgns; ++l_idx)
 -              remdun_mapseen(l_idx);
 -      }
 +    if (on_level(newlevel, &u.uz)) return;            /* this can happen */
 +
 +    /* tethered movement makes level change while trapped feasible */
 +    if (u.utrap && u.utraptype == TT_BURIEDBALL)
 +        buried_ball_to_punishment(); /* (before we save/leave old level) */
 +
 +    fd = currentlevel_rewrite();
 +    if (fd < 0) return;
 +
 +    if (falling) /* assuming this is only trap door or hole */
 +        impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
 +
 +    check_special_room(TRUE);         /* probably was a trap door */
 +    if (Punished) unplacebc();
 +    u.utrap = 0;                              /* needed in level_tele */
 +    fill_pit(u.ux, u.uy);
 +    u.ustuck = 0;                             /* idem */
 +    u.uinwater = 0;
 +    u.uundetected = 0;        /* not hidden, even if means are available */
 +    keepdogs(FALSE);
 +    if (u.uswallow)                           /* idem */
 +        u.uswldtim = u.uswallow = 0;
 +    recalc_mapseen(); /* recalculate map overview before we leave the level */
 +    /*
 +     *  We no longer see anything on the level.  Make sure that this
 +     *  follows u.uswallow set to null since uswallow overrides all
 +     *  normal vision.
 +     */
 +    vision_recalc(2);
 +
 +    /*
 +     * Save the level we're leaving.  If we're entering the endgame,
 +     * we can get rid of all existing levels because they cannot be
 +     * reached any more.  We still need to use savelev()'s cleanup
 +     * for the level being left, to recover dynamic memory in use and
 +     * to avoid dangling timers and light sources.
 +     */
 +    cant_go_back = (newdungeon && In_endgame(newlevel));
 +    if (!cant_go_back) {
 +        update_mlstmv();      /* current monsters are becoming inactive */
 +        bufon(fd);            /* use buffered output */
 +    }
 +    savelev(fd, ledger_no(&u.uz),
 +        cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
 +    bclose(fd);
 +    if (cant_go_back) {
 +        /* discard unreachable levels; keep #0 */
 +        for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
 +        delete_levelfile(l_idx);
 +        /* mark #overview data for all dungeon branches as uninteresting */
 +        for (l_idx = 0; l_idx < n_dgns; ++l_idx)
 +        remdun_mapseen(l_idx);
 +    }
  
 -      if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
 -              assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY);
 +    if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
 +        assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY);
  #ifdef USE_TILES
 -      substitute_tiles(newlevel);
 +    substitute_tiles(newlevel);
  #endif
 -      /* record this level transition as a potential seen branch unless using
 -       * some non-standard means of transportation (level teleport).
 -       */
 -      if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
 -              recbranch_mapseen(&u.uz, newlevel);
 -      assign_level(&u.uz0, &u.uz);
 -      assign_level(&u.uz, newlevel);
 -      assign_level(&u.utolev, newlevel);
 -      u.utotype = 0;
 -      if (dunlev_reached(&u.uz) < dunlev(&u.uz))
 -              dunlev_reached(&u.uz) = dunlev(&u.uz);
 -      reset_rndmonst(NON_PM);   /* u.uz change affects monster generation */
 -
 -      /* set default level change destination areas */
 -      /* the special level code may override these */
 -      (void) memset((genericptr_t) &updest, 0, sizeof updest);
 -      (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
 -
 -      if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
 -              /* entering this level for first time; make it now */
 -              if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
 -                  impossible("goto_level: returning to discarded level?");
 -                  level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
 -              }
 -              mklev();
 -              new = TRUE;     /* made the level */
 -      } else {
 -              /* returning to previously visited level; reload it */
 -              fd = open_levelfile(new_ledger, whynot);
 -              if (fd < 0) {
 -                      pline1(whynot);
 -                      pline("Probably someone removed it.");
 -                      Strcpy(killer.name, whynot);
 -                      done(TRICKED);
 -                      /* we'll reach here if running in wizard mode */
 -                      error("Cannot continue this game.");
 -              }
 -              minit();        /* ZEROCOMP */
 -              getlev(fd, hackpid, new_ledger, FALSE);
 -              (void) close(fd);
 -              oinit(); /* reassign level dependent obj probabilities */
 -      }
 -      /* do this prior to level-change pline messages */
 -      vision_reset();         /* clear old level's line-of-sight */
 -      vision_full_recalc = 0; /* don't let that reenable vision yet */
 -      flush_screen(-1);       /* ensure all map flushes are postponed */
 -
 -      if (portal && !In_endgame(&u.uz)) {
 -          /* find the portal on the new level */
 -          register struct trap *ttrap;
 -
 -          for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
 -              if (ttrap->ttyp == MAGIC_PORTAL) break;
 -
 -          if (!ttrap) panic("goto_level: no corresponding portal!");
 -          seetrap(ttrap);
 -          u_on_newpos(ttrap->tx, ttrap->ty);
 -      } else if (at_stairs && !In_endgame(&u.uz)) {
 -          if (up) {
 -              if (at_ladder)
 -                  u_on_newpos(xdnladder, ydnladder);
 -              else if (newdungeon)
 -                  u_on_sstairs(1);
 -              else
 -                  u_on_dnstairs();
 -              /* you climb up the {stairs|ladder};
 -                 fly up the stairs; fly up along the ladder */
 -              pline("%s %s up%s the %s.",
 -                    (Punished && !Levitation) ? "With great effort you" :
 -                                                "You",
 -                    Flying ? "fly" : "climb",
 -                    (Flying && at_ladder) ? " along" : "",
 -                    at_ladder ? "ladder" : "stairs");
 -          } else {    /* down */
 -              if (at_ladder)
 -                  u_on_newpos(xupladder, yupladder);
 -              else if (newdungeon)
 -                  u_on_sstairs(0);
 -              else
 -                  u_on_upstairs();
 -              if (!u.dz) {
 -                  ;   /* stayed on same level? (no transit effects) */
 -              } else if (Flying) {
 -                  if (flags.verbose)
 -                      You("fly down %s.",
 -                          at_ladder ? "along the ladder" : "the stairs");
 -              } else if (near_capacity() > UNENCUMBERED ||
 -                      Punished || Fumbling) {
 -                  You("fall down the %s.", at_ladder ? "ladder" : "stairs");
 -                  if (Punished) {
 -                      drag_down();
 -                      if (carried(uball)) {
 -                          if (uwep == uball)
 -                              setuwep((struct obj *)0);
 -                          if (uswapwep == uball)
 -                              setuswapwep((struct obj *)0);
 -                          if (uquiver == uball)
 -                              setuqwep((struct obj *)0);
 -                          freeinv(uball);
 -                      }
 -                  }
 -                  /* falling off steed has its own losehp() call */
 -                  if (u.usteed)
 -                      dismount_steed(DISMOUNT_FELL);
 -                  else
 -                      losehp(Maybe_Half_Phys(rnd(3)),
 -                             at_ladder ? "falling off a ladder" :
 -                                         "tumbling down a flight of stairs",
 -                             KILLED_BY);
 -                  selftouch("Falling, you");
 -              } else {        /* ordinary descent */
 -                  if (flags.verbose)
 -                      You("%s.", at_ladder ? "climb down the ladder" :
 -                                             "descend the stairs");
 -              }
 -          }
 -      } else {        /* trap door or level_tele or In_endgame */
 -          u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0));
 -          if (falling) {
 -              if (Punished) ballfall();
 -              selftouch("Falling, you");
 -          }
 -      }
 +    /* record this level transition as a potential seen branch unless using
 +     * some non-standard means of transportation (level teleport).
 +     */
 +    if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
 +        recbranch_mapseen(&u.uz, newlevel);
 +    assign_level(&u.uz0, &u.uz);
 +    assign_level(&u.uz, newlevel);
 +    assign_level(&u.utolev, newlevel);
 +    u.utotype = 0;
 +    if (dunlev_reached(&u.uz) < dunlev(&u.uz))
 +        dunlev_reached(&u.uz) = dunlev(&u.uz);
 +    reset_rndmonst(NON_PM);   /* u.uz change affects monster generation */
 +
 +    /* set default level change destination areas */
 +    /* the special level code may override these */
 +    (void) memset((genericptr_t) &updest, 0, sizeof updest);
 +    (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
 +
 +    if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
 +        /* entering this level for first time; make it now */
 +        if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
 +            impossible("goto_level: returning to discarded level?");
 +            level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
 +        }
 +        mklev();
 +        new = TRUE;   /* made the level */
 +    } else {
 +        /* returning to previously visited level; reload it */
 +        fd = open_levelfile(new_ledger, whynot);
 +        if (fd < 0) {
 +            pline1(whynot);
 +            pline("Probably someone removed it.");
 +            Strcpy(killer.name, whynot);
 +            done(TRICKED);
 +            /* we'll reach here if running in wizard mode */
 +            error("Cannot continue this game.");
 +        }
 +        minit();      /* ZEROCOMP */
 +        getlev(fd, hackpid, new_ledger, FALSE);
 +        (void) close(fd);
 +        oinit(); /* reassign level dependent obj probabilities */
 +    }
 +    /* do this prior to level-change pline messages */
 +    vision_reset();           /* clear old level's line-of-sight */
 +    vision_full_recalc = 0;   /* don't let that reenable vision yet */
 +    flush_screen(-1); /* ensure all map flushes are postponed */
 +
 +    if (portal && !In_endgame(&u.uz)) {
 +        /* find the portal on the new level */
 +        register struct trap *ttrap;
 +
 +        for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
 +        if (ttrap->ttyp == MAGIC_PORTAL) break;
 +
 +        if (!ttrap) panic("goto_level: no corresponding portal!");
 +        seetrap(ttrap);
 +        u_on_newpos(ttrap->tx, ttrap->ty);
 +    } else if (at_stairs && !In_endgame(&u.uz)) {
 +        if (up) {
 +        if (at_ladder)
 +            u_on_newpos(xdnladder, ydnladder);
 +        else if (newdungeon)
 +            u_on_sstairs(1);
 +        else
 +            u_on_dnstairs();
 +        /* you climb up the {stairs|ladder};
 +           fly up the stairs; fly up along the ladder */
 +        pline("%s %s up%s the %s.",
 +              (Punished && !Levitation) ? "With great effort you" :
 +                          "You",
 +              Flying ? "fly" : "climb",
 +              (Flying && at_ladder) ? " along" : "",
 +              at_ladder ? "ladder" : "stairs");
 +        } else {      /* down */
 +        if (at_ladder)
 +            u_on_newpos(xupladder, yupladder);
 +        else if (newdungeon)
 +            u_on_sstairs(0);
 +        else
 +            u_on_upstairs();
 +        if (!u.dz) {
 +            ; /* stayed on same level? (no transit effects) */
 +        } else if (Flying) {
 +            if (flags.verbose)
 +            You("fly down %s.",
 +                at_ladder ? "along the ladder" : "the stairs");
 +        } else if (near_capacity() > UNENCUMBERED ||
 +            Punished || Fumbling) {
 +            You("fall down the %s.", at_ladder ? "ladder" : "stairs");
 +            if (Punished) {
 +            drag_down();
 +            if (carried(uball)) {
 +                if (uwep == uball)
 +                setuwep((struct obj *)0);
 +                if (uswapwep == uball)
 +                setuswapwep((struct obj *)0);
 +                if (uquiver == uball)
 +                setuqwep((struct obj *)0);
 +                freeinv(uball);
 +            }
 +            }
 +            /* falling off steed has its own losehp() call */
 +            if (u.usteed)
 +            dismount_steed(DISMOUNT_FELL);
 +            else
 +            losehp(Maybe_Half_Phys(rnd(3)),
 +                   at_ladder ? "falling off a ladder" :
 +                       "tumbling down a flight of stairs",
 +                   KILLED_BY);
 +            selftouch("Falling, you");
 +        } else {      /* ordinary descent */
 +            if (flags.verbose)
 +            You("%s.", at_ladder ? "climb down the ladder" :
 +                           "descend the stairs");
 +        }
 +        }
 +    } else {  /* trap door or level_tele or In_endgame */
 +        u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0));
 +        if (falling) {
 +        if (Punished) ballfall();
 +        selftouch("Falling, you");
 +        }
 +    }
  
 -      if (Punished) placebc();
 -      obj_delivery(FALSE);
 -      losedogs();
 -      kill_genocided_monsters();  /* for those wiped out while in limbo */
 -      /*
 -       * Expire all timers that have gone off while away.  Must be
 -       * after migrating monsters and objects are delivered
 -       * (losedogs and obj_delivery).
 -       */
 -      run_timers();
 -
 -      initrack();
 -
 -      if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) {
 -          /* There's a monster at your target destination; it might be one
 -             which accompanied you--see mon_arrive(dogmove.c)--or perhaps
 -             it was already here.  Randomly move you to an adjacent spot
 -             or else the monster to any nearby location.  Prior to 3.3.0
 -             the latter was done unconditionally. */
 -          coord cc;
 -
 -          if (!rn2(2) &&
 -                  enexto(&cc, u.ux, u.uy, youmonst.data) &&
 -                  distu(cc.x, cc.y) <= 2)
 -              u_on_newpos(cc.x, cc.y);        /*[maybe give message here?]*/
 -          else
 -              mnexto(mtmp);
 -
 -          if ((mtmp = m_at(u.ux, u.uy)) != 0) {
 -              /* there was an unconditional impossible("mnearto failed")
 -                 here, but it's not impossible and we're prepared to cope
 -                 with the situation, so only say something when debugging */
 -              if (wizard) pline("(monster in hero's way)");
 -              if (!rloc(mtmp, TRUE))
 -                  /* no room to move it; send it away, to return later */
 -                  migrate_to_level(mtmp, ledger_no(&u.uz),
 -                                   MIGR_RANDOM, (coord *)0);
 -          }
 -      }
 +    if (Punished) placebc();
 +    obj_delivery(FALSE);
 +    losedogs();
 +    kill_genocided_monsters();  /* for those wiped out while in limbo */
 +    /*
 +     * Expire all timers that have gone off while away.  Must be
 +     * after migrating monsters and objects are delivered
 +     * (losedogs and obj_delivery).
 +     */
 +    run_timers();
 +
 +    initrack();
 +
 +    if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) {
 +        /* There's a monster at your target destination; it might be one
 +           which accompanied you--see mon_arrive(dogmove.c)--or perhaps
 +           it was already here.  Randomly move you to an adjacent spot
 +           or else the monster to any nearby location.  Prior to 3.3.0
 +           the latter was done unconditionally. */
 +        coord cc;
 +
 +        if (!rn2(2) &&
 +            enexto(&cc, u.ux, u.uy, youmonst.data) &&
 +            distu(cc.x, cc.y) <= 2)
 +        u_on_newpos(cc.x, cc.y);      /*[maybe give message here?]*/
 +        else
 +        mnexto(mtmp);
 +
 +        if ((mtmp = m_at(u.ux, u.uy)) != 0) {
 +        /* there was an unconditional impossible("mnearto failed")
 +           here, but it's not impossible and we're prepared to cope
 +           with the situation, so only say something when debugging */
 +        if (wizard) pline("(monster in hero's way)");
 +        if (!rloc(mtmp, TRUE))
 +            /* no room to move it; send it away, to return later */
 +            migrate_to_level(mtmp, ledger_no(&u.uz),
 +                     MIGR_RANDOM, (coord *)0);
 +        }
 +    }
  
 -      /* initial movement of bubbles just before vision_recalc */
 -      if (Is_waterlevel(&u.uz))
 -              movebubbles();
 +    /* initial movement of bubbles just before vision_recalc */
 +    if (Is_waterlevel(&u.uz))
 +        movebubbles();
  
 -      if (level_info[new_ledger].flags & FORGOTTEN) {
 -          forget_map(ALL_MAP);        /* forget the map */
 -          forget_traps();             /* forget all traps too */
 -          familiar = TRUE;
 -          level_info[new_ledger].flags &= ~FORGOTTEN;
 -      }
 +    if (level_info[new_ledger].flags & FORGOTTEN) {
 +        forget_map(ALL_MAP);  /* forget the map */
 +        forget_traps();               /* forget all traps too */
 +        familiar = TRUE;
 +        level_info[new_ledger].flags &= ~FORGOTTEN;
 +    }
  
 -      /* Reset the screen. */
 -      vision_reset();         /* reset the blockages */
 -      docrt();                /* does a full vision recalc */
 -      flush_screen(-1);
 +    /* Reset the screen. */
 +    vision_reset();           /* reset the blockages */
 +    docrt();          /* does a full vision recalc */
 +    flush_screen(-1);
  
 -      /*
 -       *  Move all plines beyond the screen reset.
 -       */
 +    /*
 +     *  Move all plines beyond the screen reset.
 +     */
  
 -      /* special levels can have a custom arrival message */
 -      deliver_splev_message();
 +    /* special levels can have a custom arrival message */
 +    deliver_splev_message();
  
 -      /* give room entrance message, if any */
 -      check_special_room(FALSE);
 +    /* give room entrance message, if any */
 +    check_special_room(FALSE);
  
 -      /* deliver objects traveling with player */
 -      obj_delivery(TRUE);
 +    /* deliver objects traveling with player */
 +    obj_delivery(TRUE);
  
 -      /* Check whether we just entered Gehennom. */
 -      if (!In_hell(&u.uz0) && Inhell) {
 -          if (Is_valley(&u.uz)) {
 -              You("arrive at the Valley of the Dead...");
 -              pline_The("odor of burnt flesh and decay pervades the air.");
 +    /* Check whether we just entered Gehennom. */
 +    if (!In_hell(&u.uz0) && Inhell) {
 +        if (Is_valley(&u.uz)) {
 +        You("arrive at the Valley of the Dead...");
 +        pline_The("odor of burnt flesh and decay pervades the air.");
  #ifdef MICRO
 -              display_nhwindow(WIN_MESSAGE, FALSE);
 +        display_nhwindow(WIN_MESSAGE, FALSE);
  #endif
 -              You_hear("groans and moans everywhere.");
 -          } else pline("It is hot here.  You smell smoke...");
 +        You_hear("groans and moans everywhere.");
 +        } else pline("It is hot here.  You smell smoke...");
            u.uachieve.enter_gehennom = 1;
 -      }
 -      /* in case we've managed to bypass the Valley's stairway down */
 -      if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1;
 -
 -      if (familiar) {
 -          static const char * const fam_msgs[4] = {
 -              "You have a sense of deja vu.",
 -              "You feel like you've been here before.",
 -              "This place %s familiar...",
 -              0       /* no message */
 -          };
 -          static const char * const halu_fam_msgs[4] = {
 -              "Whoa!  Everything %s different.",
 -              "You are surrounded by twisty little passages, all alike.",
 -              "Gee, this %s like uncle Conan's place...",
 -              0       /* no message */
 -          };
 -          const char *mesg;
 -          char buf[BUFSZ];
 -          int which = rn2(4);
 -
 -          if (Hallucination)
 -              mesg = halu_fam_msgs[which];
 -          else
 -              mesg = fam_msgs[which];
 -          if (mesg && index(mesg, '%')) {
 -              Sprintf(buf, mesg, !Blind ? "looks" : "seems");
 -              mesg = buf;
 -          }
 -          if (mesg) pline1(mesg);
 -      }
 +    }
 +    /* in case we've managed to bypass the Valley's stairway down */
 +    if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1;
 +
 +    if (familiar) {
 +        static const char * const fam_msgs[4] = {
 +        "You have a sense of deja vu.",
 +        "You feel like you've been here before.",
 +        "This place %s familiar...",
 +        0     /* no message */
 +        };
 +        static const char * const halu_fam_msgs[4] = {
 +        "Whoa!  Everything %s different.",
 +        "You are surrounded by twisty little passages, all alike.",
 +        "Gee, this %s like uncle Conan's place...",
 +        0     /* no message */
 +        };
 +        const char *mesg;
 +        char buf[BUFSZ];
 +        int which = rn2(4);
 +
 +        if (Hallucination)
 +        mesg = halu_fam_msgs[which];
 +        else
 +        mesg = fam_msgs[which];
 +        if (mesg && index(mesg, '%')) {
 +        Sprintf(buf, mesg, !Blind ? "looks" : "seems");
 +        mesg = buf;
 +        }
 +        if (mesg) pline1(mesg);
 +    }
  
 -      /* special location arrival messages/events */
 -      if (In_endgame(&u.uz)) {
 -          if (new && on_level(&u.uz, &astral_level))
 -              final_level();  /* guardian angel,&c */
 -          else if (newdungeon && u.uhave.amulet)
 -              resurrect();    /* force confrontation with Wizard */
 -      } else if (In_quest(&u.uz)) {
 -          onquest();          /* might be reaching locate|goal level */
 -      } else if (In_V_tower(&u.uz)) {
 -          if (newdungeon && In_hell(&u.uz0))
 -              pline_The("heat and smoke are gone.");
 -      } else if (Is_knox(&u.uz)) {
 -          /* alarm stops working once Croesus has died */
 -          if (new || !mvitals[PM_CROESUS].died) {
 -              You("have penetrated a high security area!");
 -              pline("An alarm sounds!");
 -              for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 -                  if (DEADMONSTER(mtmp)) continue;
 -                  mtmp->msleeping = 0;
 -              }
 -          }
 -      } else {
 -          if (new && Is_rogue_level(&u.uz))
 -              You("enter what seems to be an older, more primitive world.");
 -          /* main dungeon message from your quest leader */
 -          if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
 -                  !(u.uevent.qcompleted || u.uevent.qexpelled ||
 -                    quest_status.leader_is_dead)) {
 -              if (!u.uevent.qcalled) {
 -                  u.uevent.qcalled = 1;
 -                  com_pager(2);   /* main "leader needs help" message */
 -              } else {            /* reminder message */
 -                  com_pager(Role_if(PM_ROGUE) ? 4 : 3);
 -              }
 -          }
 -      }
 +    /* special location arrival messages/events */
 +    if (In_endgame(&u.uz)) {
 +        if (new && on_level(&u.uz, &astral_level))
 +        final_level();        /* guardian angel,&c */
 +        else if (newdungeon && u.uhave.amulet)
 +        resurrect();  /* force confrontation with Wizard */
 +    } else if (In_quest(&u.uz)) {
 +        onquest();            /* might be reaching locate|goal level */
 +    } else if (In_V_tower(&u.uz)) {
 +        if (newdungeon && In_hell(&u.uz0))
 +        pline_The("heat and smoke are gone.");
 +    } else if (Is_knox(&u.uz)) {
 +        /* alarm stops working once Croesus has died */
 +        if (new || !mvitals[PM_CROESUS].died) {
 +        You("have penetrated a high security area!");
 +        pline("An alarm sounds!");
 +        for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
 +            if (DEADMONSTER(mtmp)) continue;
 +            mtmp->msleeping = 0;
 +        }
 +        }
 +    } else {
 +        if (new && Is_rogue_level(&u.uz))
 +        You("enter what seems to be an older, more primitive world.");
 +        /* main dungeon message from your quest leader */
 +        if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
 +            !(u.uevent.qcompleted || u.uevent.qexpelled ||
 +              quest_status.leader_is_dead)) {
 +        if (!u.uevent.qcalled) {
 +            u.uevent.qcalled = 1;
 +            com_pager(2);   /* main "leader needs help" message */
 +        } else {          /* reminder message */
 +            com_pager(Role_if(PM_ROGUE) ? 4 : 3);
 +        }
 +        }
 +    }
  
 -      assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
 +    assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
  #ifdef INSURANCE
 -      save_currentstate();
 +    save_currentstate();
  #endif
  
 -      /* assume this will always return TRUE when changing level */
 -      (void) in_out_region(u.ux, u.uy);
 -      (void) pickup(1);
 +    /* assume this will always return TRUE when changing level */
 +    (void) in_out_region(u.ux, u.uy);
 +    (void) pickup(1);
+       context.polearm.hitmon = NULL;
  }
  
  STATIC_OVL void
diff --cc src/hack.c
index 1eb9eac97016105c6ad9c306716bb33f361ca5f9,32ceb8e69e413c56a6c8c470db7c6fb798624396..ef8c90a52de5ddafac5fa23b7372767e12ae482a
@@@ -1101,490 -1101,491 +1101,491 @@@ struct trap *desttrap;    /* nonnull if an
  void
  domove()
  {
 -      register struct monst *mtmp;
 -      register struct rm *tmpr;
 -      register xchar x,y;
 -      struct trap *trap;
 -      int wtcap;
 -      boolean on_ice;
 -      xchar chainx, chainy, ballx, bally;     /* ball&chain new positions */
 -      int bc_control;                         /* control for ball&chain */
 -      boolean cause_delay = FALSE;    /* dragging ball will skip a move */
 -
 -      u_wipe_engr(rnd(5));
 -
 -      if (context.travel) {
 -          if (!findtravelpath(FALSE))
 -              (void) findtravelpath(TRUE);
 -          context.travel1 = 0;
 -      }
 -
 -      if(((wtcap = near_capacity()) >= OVERLOADED
 -          || (wtcap > SLT_ENCUMBER &&
 -              (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
 -                      : (u.uhp < 10 && u.uhp != u.uhpmax))))
 -         && !Is_airlevel(&u.uz)) {
 -          if(wtcap < OVERLOADED) {
 -              You("don't have enough stamina to move.");
 -              exercise(A_CON, FALSE);
 -          } else
 -              You("collapse under your load.");
 -          nomul(0);
 -          return;
 -      }
 -      if(u.uswallow) {
 -              u.dx = u.dy = 0;
 -              u.ux = x = u.ustuck->mx;
 -              u.uy = y = u.ustuck->my;
 -              mtmp = u.ustuck;
 -      } else {
 -              if (Is_airlevel(&u.uz) && rn2(4) &&
 -                      !Levitation && !Flying) {
 -                  switch(rn2(3)) {
 -                  case 0:
 -                      You("tumble in place.");
 -                      exercise(A_DEX, FALSE);
 -                      break;
 -                  case 1:
 -                      You_cant("control your movements very well."); break;
 -                  case 2:
 -                      pline("It's hard to walk in thin air.");
 -                      exercise(A_DEX, TRUE);
 -                      break;
 -                  }
 -                  return;
 -              }
 -
 -              /* check slippery ice */
 -              on_ice = !Levitation && is_ice(u.ux, u.uy);
 -              if (on_ice) {
 -                  static int skates = 0;
 -                  if (!skates) skates = find_skates();
 -                  if ((uarmf && uarmf->otyp == skates)
 -                          || resists_cold(&youmonst) || Flying
 -                          || is_floater(youmonst.data) || is_clinger(youmonst.data)
 -                          || is_whirly(youmonst.data))
 -                      on_ice = FALSE;
 -                  else if (!rn2(Cold_resistance ? 3 : 2)) {
 -                      HFumbling |= FROMOUTSIDE;
 -                      HFumbling &= ~TIMEOUT;
 -                      HFumbling += 1;  /* slip on next move */
 -                  }
 -              }
 -              if (!on_ice && (HFumbling & FROMOUTSIDE))
 -                  HFumbling &= ~FROMOUTSIDE;
 -
 -              x = u.ux + u.dx;
 -              y = u.uy + u.dy;
 -              if(Stunned || (Confusion && !rn2(5))) {
 -                      register int tries = 0;
 -
 -                      do {
 -                              if(tries++ > 50) {
 -                                      nomul(0);
 -                                      return;
 -                              }
 -                              confdir();
 -                              x = u.ux + u.dx;
 -                              y = u.uy + u.dy;
 -                      } while(!isok(x, y) || bad_rock(youmonst.data, x, y));
 -              }
 -              /* turbulence might alter your actual destination */
 -              if (u.uinwater) {
 -                      water_friction();
 -                      if (!u.dx && !u.dy) {
 -                              nomul(0);
 -                              return;
 -                      }
 -                      x = u.ux + u.dx;
 -                      y = u.uy + u.dy;
 -              }
 -              if(!isok(x, y)) {
 -                      nomul(0);
 -                      return;
 -              }
 -              if (((trap = t_at(x, y)) && trap->tseen) ||
 -                  (Blind && !Levitation && !Flying &&
 -                   !is_clinger(youmonst.data) &&
 -                   is_pool_or_lava(x, y) && levl[x][y].seenv)) {
 -                      if(context.run >= 2) {
 -                              nomul(0);
 -                              context.move = 0;
 -                              return;
 -                      } else
 -                              nomul(0);
 -              }
 -
 -              if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
 -                  if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
 -                      /* perhaps it fled (or was teleported or ... ) */
 -                      u.ustuck = 0;
 -                  } else if (sticks(youmonst.data)) {
 -                      /* When polymorphed into a sticking monster,
 -                       * u.ustuck means it's stuck to you, not you to it.
 -                       */
 -                      You("release %s.", mon_nam(u.ustuck));
 -                      u.ustuck = 0;
 -                  } else {
 -                      /* If holder is asleep or paralyzed:
 -                       *      37.5% chance of getting away,
 -                       *      12.5% chance of waking/releasing it;
 -                       * otherwise:
 -                       *       7.5% chance of getting away.
 -                       * [strength ought to be a factor]
 -                       * If holder is tame and there is no conflict,
 -                       * guaranteed escape.
 -                       */
 -                      switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
 -                      case 0: case 1: case 2:
 -                      pull_free:
 -                          You("pull free from %s.", mon_nam(u.ustuck));
 -                          u.ustuck = 0;
 -                          break;
 -                      case 3:
 -                          if (!u.ustuck->mcanmove) {
 -                              /* it's free to move on next turn */
 -                              u.ustuck->mfrozen = 1;
 -                              u.ustuck->msleeping = 0;
 -                          }
 -                          /*FALLTHRU*/
 -                      default:
 -                          if (u.ustuck->mtame &&
 -                              !Conflict && !u.ustuck->mconf)
 -                              goto pull_free;
 -                          You("cannot escape from %s!", mon_nam(u.ustuck));
 -                          nomul(0);
 -                          return;
 -                      }
 -                  }
 -              }
 -
 -              mtmp = m_at(x,y);
 -              if (mtmp) {
 -                      /* Don't attack if you're running, and can see it */
 -                      /* We should never get here if forcefight */
 -                      if (context.run &&
 -                          ((!Blind && mon_visible(mtmp) &&
 -                            ((mtmp->m_ap_type != M_AP_FURNITURE &&
 -                              mtmp->m_ap_type != M_AP_OBJECT) ||
 -                             Protection_from_shape_changers)) ||
 -                           sensemon(mtmp))) {
 -                              nomul(0);
 -                              context.move = 0;
 -                              return;
 -                      }
 -              }
 -      }
 -
 -      u.ux0 = u.ux;
 -      u.uy0 = u.uy;
 -      bhitpos.x = x;
 -      bhitpos.y = y;
 -      tmpr = &levl[x][y];
 -
 -      /* attack monster */
 -      if(mtmp) {
 -          nomul(0);
 -          /* only attack if we know it's there */
 -          /* or if we used the 'F' command to fight blindly */
 -          /* or if it hides_under, in which case we call attack() to print
 -           * the Wait! message.
 -           * This is different from ceiling hiders, who aren't handled in
 -           * attack().
 -           */
 -
 -          /* If they used a 'm' command, trying to move onto a monster
 -           * prints the below message and wastes a turn.  The exception is
 -           * if the monster is unseen and the player doesn't remember an
 -           * invisible monster--then, we fall through to attack() and
 -           * attack_check(), which still wastes a turn, but prints a
 -           * different message and makes the player remember the monster.                  */
 -          if(context.nopick &&
 -                (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
 -              if(mtmp->m_ap_type && !Protection_from_shape_changers
 -                                                  && !sensemon(mtmp))
 -                  stumble_onto_mimic(mtmp);
 -              else if (mtmp->mpeaceful && !Hallucination)
 -                  pline("Pardon me, %s.", m_monnam(mtmp));
 -              else
 -                  You("move right into %s.", mon_nam(mtmp));
 -              return;
 -          }
 -          if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
 -                  ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
 -                      !is_safepet(mtmp))){
 -              /* try to attack; note that it might evade */
 -              /* also, we don't attack tame when _safepet_ */
 -              if(attack(mtmp)) return;
 -          }
 -      }
 -
 -      /* specifying 'F' with no monster wastes a turn */
 -      if (context.forcefight ||
 -          /* remembered an 'I' && didn't use a move command */
 -          (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) {
 -              struct obj *boulder = sobj_at(BOULDER, x, y);
 -              boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)),
 -                      solid = !accessible(x, y);
 -              int glyph = glyph_at(x, y);     /* might be monster */
 -              char buf[BUFSZ];
 -
 -              /* if a statue is displayed at the target location,
 -                 player is attempting to attack it [and boulder
 -                 handlng below is suitable for handling that] */
 -              if (glyph_is_statue(glyph) ||
 -                      (Hallucination && glyph_is_monster(glyph)))
 -                  boulder = sobj_at(STATUE, x, y);
 -
 -              /* force fight at boulder/statue or wall/door while wielding
 -                 pick:  start digging to break the boulder or wall */
 -              if (context.forcefight &&
 -                      /* can we dig? */
 -                      uwep && dig_typ(uwep, x, y) &&
 -                      /* should we dig? */
 -                      !glyph_is_invisible(glyph) &&
 -                      !glyph_is_monster(glyph)) {
 -                  (void)use_pick_axe2(uwep);
 -                  return;
 -              }
 -
 -              if (boulder)
 -                  Strcpy(buf, ansimpleoname(boulder));
 -              else if (solid)
 -                  Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation));
 -              else if (!Underwater)
 -                  Strcpy(buf, "thin air");
 -              else if (is_pool(x, y))
 -                  Strcpy(buf, "empty water");
 -              else    /* Underwater, targetting non-water */
 -                  Sprintf(buf, "a vacant spot on the %s", surface(x,y));
 -              You("%s%s %s.",
 -                  !(boulder || solid) ? "" :
 -                      !explo ? "harmlessly " : "futilely ",
 -                  explo ? "explode at" : "attack",
 -                  buf);
 -              unmap_object(x, y); /* known empty -- remove 'I' if present */
 -              if (boulder) map_object(boulder, TRUE);
 -              newsym(x, y);
 -              nomul(0);
 -              if (explo) {
 -                  wake_nearby();
 -                  u.mh = -1;          /* dead in the current form */
 -                  rehumanize();
 -              }
 -              return;
 -      }
 -      if (glyph_is_invisible(levl[x][y].glyph)) {
 -          unmap_object(x, y);
 -          newsym(x, y);
 -      }
 -      /* not attacking an animal, so we try to move */
 -      if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) {
 -              nomul(0);
 -              return;
 -      }
 -      if(!youmonst.data->mmove) {
 -              You("are rooted %s.",
 -                  Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
 -                  "in place" : "to the ground");
 -              nomul(0);
 -              return;
 -      }
 -      if(u.utrap) {
 -          if (!trapmove(x, y, trap)) return;
 -      }
 -
 -      if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
 -          context.move = 0;
 -          nomul(0);
 -          return;
 -      }
 -
 -      /* Move ball and chain.  */
 -      if (Punished)
 -          if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
 -                      &cause_delay, TRUE))
 -              return;
 -
 -      /* Check regions entering/leaving */
 -      if (!in_out_region(x,y))
 -          return;
 -
 -      /* now move the hero */
 -      mtmp = m_at(x, y);
 -      u.ux += u.dx;
 -      u.uy += u.dy;
 -      /* Move your steed, too */
 -      if (u.usteed) {
 -              u.usteed->mx = u.ux;
 -              u.usteed->my = u.uy;
 -              exercise_steed();
 -      }
 -
 -      /*
 -       * If safepet at destination then move the pet to the hero's
 -       * previous location using the same conditions as in attack().
 -       * there are special extenuating circumstances:
 -       * (1) if the pet dies then your god angers,
 -       * (2) if the pet gets trapped then your god may disapprove,
 -       * (3) if the pet was already trapped and you attempt to free it
 -       * not only do you encounter the trap but you may frighten your
 -       * pet causing it to go wild!  moral: don't abuse this privilege.
 -       *
 -       * Ceiling-hiding pets are skipped by this section of code, to
 -       * be caught by the normal falling-monster code.
 -       */
 -      if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
 -          /* if trapped, there's a chance the pet goes wild */
 -          if (mtmp->mtrapped) {
 -              if (!rn2(mtmp->mtame)) {
 -                  mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
 -                  if (mtmp->mleashed) m_unleash(mtmp, TRUE);
 -                  growl(mtmp);
 -              } else {
 -                  yelp(mtmp);
 -              }
 -          }
 -          mtmp->mundetected = 0;
 -          if (mtmp->m_ap_type) seemimic(mtmp);
 -          else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
 -
 -          if (mtmp->mtrapped &&
 -                  (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
 -                  (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
 -                  sobj_at(BOULDER, trap->tx, trap->ty)) {
 -              /* can't swap places with pet pinned in a pit by a boulder */
 -              u.ux = u.ux0,  u.uy = u.uy0;    /* didn't move after all */
 -          } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
 -              /* can't swap places when pet can't move to your spot */
 -              u.ux = u.ux0,  u.uy = u.uy0;
 -              You("stop.  %s can't move diagonally.",
 -                  upstart(y_monnam(mtmp)));
 -          } else if (u.ux0 != x && u.uy0 != y &&
 -                     bad_rock(mtmp->data, x, u.uy0) &&
 -                     bad_rock(mtmp->data, u.ux0, y) &&
 -                     (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
 -              /* can't swap places when pet won't fit thru the opening */
 -              u.ux = u.ux0,  u.uy = u.uy0;    /* didn't move after all */
 -              You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
 -          } else {
 -              char pnambuf[BUFSZ];
 -
 -              /* save its current description in case of polymorph */
 -              Strcpy(pnambuf, y_monnam(mtmp));
 -              mtmp->mtrapped = 0;
 -              remove_monster(x, y);
 -              place_monster(mtmp, u.ux0, u.uy0);
 -              newsym(x, y);
 -              newsym(u.ux0, u.uy0);
 -
 -              You("%s %s.", mtmp->mtame ? "swap places with" : "frighten",
 -                  pnambuf);
 -
 -              /* check for displacing it into pools and traps */
 -              switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
 -              case 0:
 -                  break;
 -              case 1:         /* trapped */
 -              case 3:         /* changed levels */
 -                  /* there's already been a trap message, reinforce it */
 -                  abuse_dog(mtmp);
 -                  adjalign(-3);
 -                  break;
 -              case 2:
 -                  /* drowned or died...
 -                   * you killed your pet by direct action, so get experience
 -                   * and possibly penalties;
 -                   * we want the level gain message, if it happens, to occur
 -                   * before the guilt message below
 -                   */
 -                {
 -                  /* minliquid() and mintrap() call mondead() rather than
 -                     killed() so we duplicate some of the latter here */
 -                  int tmp, mndx;
 -
 -                  u.uconduct.killer++;
 -                  mndx = monsndx(mtmp->data);
 -                  tmp = experience(mtmp, (int)mvitals[mndx].died);
 -                  more_experienced(tmp, 0);
 -                  newexplevel();      /* will decide if you go up */
 -                }
 -                  /* That's no way to treat a pet!  Your god gets angry.
 -                   *
 -                   * [This has always been pretty iffy.  Why does your
 -                   * patron deity care at all, let alone enough to get mad?]
 -                   */
 -                  if (rn2(4)) {
 -                      You_feel("guilty about losing your pet like this.");
 -                      u.ugangr++;
 -                      adjalign(-15);
 -                  }
 -                  break;
 -              default:
 -                  pline("that's strange, unknown mintrap result!");
 -                  break;
 -              }
 -          }
 -      }
 -
 -      reset_occupations();
 -      if (context.run) {
 -          if ( context.run < 8 )
 -              if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
 -                      IS_FURNITURE(tmpr->typ))
 -                  nomul(0);
 -      }
 -
 -      if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) ||
 -          u.dx || u.dy)
 -          (void) hideunder(&youmonst);
 -
 -      /*
 -       * Mimics (or whatever) become noticeable if they move and are
 -       * imitating something that doesn't move.  We could extend this
 -       * to non-moving monsters...
 -       */
 -      if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
 -                              || youmonst.m_ap_type == M_AP_FURNITURE))
 -          youmonst.m_ap_type = M_AP_NOTHING;
 -
 -      check_leash(u.ux0,u.uy0);
 -
 -      if(u.ux0 != u.ux || u.uy0 != u.uy) {
 -          u.umoved = TRUE;
 -          /* Clean old position -- vision_recalc() will print our new one. */
 -          newsym(u.ux0,u.uy0);
 -          /* Since the hero has moved, adjust what can be seen/unseen. */
 -          vision_recalc(1);   /* Do the work now in the recover time. */
 -          invocation_message();
 -      }
 -
 -      if (Punished)                           /* put back ball and chain */
 -          move_bc(0,bc_control,ballx,bally,chainx,chainy);
 -
 -      spoteffects(TRUE);
 -
 -      /* delay next move because of ball dragging */
 -      /* must come after we finished picking up, in spoteffects() */
 -      if (cause_delay) {
 -          nomul(-2);
 +    register struct monst *mtmp;
 +    register struct rm *tmpr;
 +    register xchar x,y;
 +    struct trap *trap = NULL;
 +    int wtcap;
 +    boolean on_ice;
 +    xchar chainx, chainy, ballx, bally;       /* ball&chain new positions */
 +    int bc_control;                           /* control for ball&chain */
 +    boolean cause_delay = FALSE;      /* dragging ball will skip a move */
 +
 +    u_wipe_engr(rnd(5));
 +
 +    if (context.travel) {
 +        if (!findtravelpath(FALSE))
 +        (void) findtravelpath(TRUE);
 +        context.travel1 = 0;
 +    }
 +
 +    if(((wtcap = near_capacity()) >= OVERLOADED
 +        || (wtcap > SLT_ENCUMBER &&
 +        (Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
 +            : (u.uhp < 10 && u.uhp != u.uhpmax))))
 +       && !Is_airlevel(&u.uz)) {
 +        if(wtcap < OVERLOADED) {
 +        You("don't have enough stamina to move.");
 +        exercise(A_CON, FALSE);
 +        } else
 +        You("collapse under your load.");
 +        nomul(0);
 +        return;
 +    }
 +    if(u.uswallow) {
 +        u.dx = u.dy = 0;
 +        u.ux = x = u.ustuck->mx;
 +        u.uy = y = u.ustuck->my;
 +        mtmp = u.ustuck;
 +    } else {
 +        if (Is_airlevel(&u.uz) && rn2(4) &&
 +            !Levitation && !Flying) {
 +            switch(rn2(3)) {
 +            case 0:
 +            You("tumble in place.");
 +            exercise(A_DEX, FALSE);
 +            break;
 +            case 1:
 +            You_cant("control your movements very well."); break;
 +            case 2:
 +            pline("It's hard to walk in thin air.");
 +            exercise(A_DEX, TRUE);
 +            break;
 +            }
 +            return;
 +        }
 +
 +        /* check slippery ice */
 +        on_ice = !Levitation && is_ice(u.ux, u.uy);
 +        if (on_ice) {
 +            static int skates = 0;
 +            if (!skates) skates = find_skates();
 +            if ((uarmf && uarmf->otyp == skates)
 +                || resists_cold(&youmonst) || Flying
 +                || is_floater(youmonst.data) || is_clinger(youmonst.data)
 +                || is_whirly(youmonst.data))
 +            on_ice = FALSE;
 +            else if (!rn2(Cold_resistance ? 3 : 2)) {
 +            HFumbling |= FROMOUTSIDE;
 +            HFumbling &= ~TIMEOUT;
 +            HFumbling += 1;  /* slip on next move */
 +            }
 +        }
 +        if (!on_ice && (HFumbling & FROMOUTSIDE))
 +            HFumbling &= ~FROMOUTSIDE;
 +
 +        x = u.ux + u.dx;
 +        y = u.uy + u.dy;
 +        if(Stunned || (Confusion && !rn2(5))) {
 +            register int tries = 0;
 +
 +            do {
 +                if(tries++ > 50) {
 +                    nomul(0);
 +                    return;
 +                }
 +                confdir();
 +                x = u.ux + u.dx;
 +                y = u.uy + u.dy;
 +            } while(!isok(x, y) || bad_rock(youmonst.data, x, y));
 +        }
 +        /* turbulence might alter your actual destination */
 +        if (u.uinwater) {
 +            water_friction();
 +            if (!u.dx && !u.dy) {
 +                nomul(0);
 +                return;
 +            }
 +            x = u.ux + u.dx;
 +            y = u.uy + u.dy;
 +        }
 +        if(!isok(x, y)) {
 +            nomul(0);
 +            return;
 +        }
 +        if (((trap = t_at(x, y)) && trap->tseen) ||
 +            (Blind && !Levitation && !Flying &&
 +             !is_clinger(youmonst.data) &&
 +             is_pool_or_lava(x, y) && levl[x][y].seenv)) {
 +            if(context.run >= 2) {
 +                nomul(0);
 +                context.move = 0;
 +                return;
 +            } else
 +                nomul(0);
 +        }
 +
 +        if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
 +            if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
 +            /* perhaps it fled (or was teleported or ... ) */
 +            u.ustuck = 0;
 +            } else if (sticks(youmonst.data)) {
 +            /* When polymorphed into a sticking monster,
 +             * u.ustuck means it's stuck to you, not you to it.
 +             */
 +            You("release %s.", mon_nam(u.ustuck));
 +            u.ustuck = 0;
 +            } else {
 +            /* If holder is asleep or paralyzed:
 +             *        37.5% chance of getting away,
 +             *        12.5% chance of waking/releasing it;
 +             * otherwise:
 +             *         7.5% chance of getting away.
 +             * [strength ought to be a factor]
 +             * If holder is tame and there is no conflict,
 +             * guaranteed escape.
 +             */
 +            switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
 +            case 0: case 1: case 2:
 +            pull_free:
 +                You("pull free from %s.", mon_nam(u.ustuck));
 +                u.ustuck = 0;
 +                break;
 +            case 3:
 +                if (!u.ustuck->mcanmove) {
 +                /* it's free to move on next turn */
 +                u.ustuck->mfrozen = 1;
 +                u.ustuck->msleeping = 0;
 +                }
 +                /*FALLTHRU*/
 +            default:
 +                if (u.ustuck->mtame &&
 +                !Conflict && !u.ustuck->mconf)
 +                goto pull_free;
 +                You("cannot escape from %s!", mon_nam(u.ustuck));
 +                nomul(0);
 +                return;
 +            }
 +            }
 +        }
 +
 +        mtmp = m_at(x,y);
 +        if (mtmp) {
 +            /* Don't attack if you're running, and can see it */
 +            /* We should never get here if forcefight */
 +            if (context.run &&
 +                ((!Blind && mon_visible(mtmp) &&
 +                  ((mtmp->m_ap_type != M_AP_FURNITURE &&
 +                mtmp->m_ap_type != M_AP_OBJECT) ||
 +                   Protection_from_shape_changers)) ||
 +                 sensemon(mtmp))) {
 +                nomul(0);
 +                context.move = 0;
 +                return;
 +            }
 +        }
 +    }
 +
 +    u.ux0 = u.ux;
 +    u.uy0 = u.uy;
 +    bhitpos.x = x;
 +    bhitpos.y = y;
 +    tmpr = &levl[x][y];
 +
 +    /* attack monster */
 +    if(mtmp) {
 +        nomul(0);
 +        /* only attack if we know it's there */
 +        /* or if we used the 'F' command to fight blindly */
 +        /* or if it hides_under, in which case we call attack() to print
 +         * the Wait! message.
 +         * This is different from ceiling hiders, who aren't handled in
 +         * attack().
 +         */
 +
 +        /* If they used a 'm' command, trying to move onto a monster
 +         * prints the below message and wastes a turn.  The exception is
 +         * if the monster is unseen and the player doesn't remember an
 +         * invisible monster--then, we fall through to attack() and
 +         * attack_check(), which still wastes a turn, but prints a
 +         * different message and makes the player remember the monster.                    */
 +        if(context.nopick &&
 +          (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
 +        if(mtmp->m_ap_type && !Protection_from_shape_changers
 +                            && !sensemon(mtmp))
 +            stumble_onto_mimic(mtmp);
 +        else if (mtmp->mpeaceful && !Hallucination)
 +            pline("Pardon me, %s.", m_monnam(mtmp));
 +        else
 +            You("move right into %s.", mon_nam(mtmp));
 +        return;
 +        }
 +        if(context.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
 +            ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
 +            !is_safepet(mtmp))){
 +        /* try to attack; note that it might evade */
 +        /* also, we don't attack tame when _safepet_ */
 +        if(attack(mtmp)) return;
 +        }
 +    }
 +
 +    /* specifying 'F' with no monster wastes a turn */
 +    if (context.forcefight ||
 +        /* remembered an 'I' && didn't use a move command */
 +        (glyph_is_invisible(levl[x][y].glyph) && !context.nopick)) {
 +        struct obj *boulder = sobj_at(BOULDER, x, y);
 +        boolean explo = (Upolyd && attacktype(youmonst.data, AT_EXPL)),
 +            solid = !accessible(x, y);
 +        int glyph = glyph_at(x, y);   /* might be monster */
 +        char buf[BUFSZ];
 +
 +        /* if a statue is displayed at the target location,
 +           player is attempting to attack it [and boulder
 +           handlng below is suitable for handling that] */
 +        if (glyph_is_statue(glyph) ||
 +            (Hallucination && glyph_is_monster(glyph)))
 +            boulder = sobj_at(STATUE, x, y);
 +
 +        /* force fight at boulder/statue or wall/door while wielding
 +           pick:  start digging to break the boulder or wall */
 +        if (context.forcefight &&
 +            /* can we dig? */
 +            uwep && dig_typ(uwep, x, y) &&
 +            /* should we dig? */
 +            !glyph_is_invisible(glyph) &&
 +            !glyph_is_monster(glyph)) {
 +            (void)use_pick_axe2(uwep);
 +            return;
 +        }
 +
 +        if (boulder)
 +            Strcpy(buf, ansimpleoname(boulder));
 +        else if (solid)
 +            Strcpy(buf, the(defsyms[glyph_to_cmap(glyph)].explanation));
 +        else if (!Underwater)
 +            Strcpy(buf, "thin air");
 +        else if (is_pool(x, y))
 +            Strcpy(buf, "empty water");
 +        else  /* Underwater, targetting non-water */
 +            Sprintf(buf, "a vacant spot on the %s", surface(x,y));
 +        You("%s%s %s.",
 +            !(boulder || solid) ? "" :
 +            !explo ? "harmlessly " : "futilely ",
 +            explo ? "explode at" : "attack",
 +            buf);
 +        unmap_object(x, y); /* known empty -- remove 'I' if present */
 +        if (boulder) map_object(boulder, TRUE);
 +        newsym(x, y);
 +        nomul(0);
 +        if (explo) {
 +            wake_nearby();
 +            u.mh = -1;                /* dead in the current form */
 +            rehumanize();
 +        }
 +        return;
 +    }
 +    if (glyph_is_invisible(levl[x][y].glyph)) {
 +        unmap_object(x, y);
 +        newsym(x, y);
 +    }
 +    /* not attacking an animal, so we try to move */
 +    if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) {
 +        nomul(0);
 +        return;
 +    }
 +    if(!youmonst.data->mmove) {
 +        You("are rooted %s.",
 +            Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
 +            "in place" : "to the ground");
 +        nomul(0);
 +        return;
 +    }
 +    if(u.utrap) {
 +        if (!trapmove(x, y, trap)) return;
 +    }
 +
 +    if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) {
 +        context.move = 0;
 +        nomul(0);
 +        return;
 +    }
 +
 +    /* Move ball and chain.  */
 +    if (Punished)
 +        if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
 +            &cause_delay, TRUE))
 +        return;
 +
 +    /* Check regions entering/leaving */
 +    if (!in_out_region(x,y))
 +        return;
 +
 +    /* now move the hero */
 +    mtmp = m_at(x, y);
 +    u.ux += u.dx;
 +    u.uy += u.dy;
 +    /* Move your steed, too */
 +    if (u.usteed) {
 +        u.usteed->mx = u.ux;
 +        u.usteed->my = u.uy;
 +        exercise_steed();
 +    }
 +
 +    /*
 +     * If safepet at destination then move the pet to the hero's
 +     * previous location using the same conditions as in attack().
 +     * there are special extenuating circumstances:
 +     * (1) if the pet dies then your god angers,
 +     * (2) if the pet gets trapped then your god may disapprove,
 +     * (3) if the pet was already trapped and you attempt to free it
 +     * not only do you encounter the trap but you may frighten your
 +     * pet causing it to go wild!  moral: don't abuse this privilege.
 +     *
 +     * Ceiling-hiding pets are skipped by this section of code, to
 +     * be caught by the normal falling-monster code.
 +     */
 +    if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
 +        /* if trapped, there's a chance the pet goes wild */
 +        if (mtmp->mtrapped) {
 +        if (!rn2(mtmp->mtame)) {
 +            mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
 +            if (mtmp->mleashed) m_unleash(mtmp, TRUE);
 +            growl(mtmp);
 +        } else {
 +            yelp(mtmp);
 +        }
 +        }
 +        mtmp->mundetected = 0;
 +        if (mtmp->m_ap_type) seemimic(mtmp);
 +        else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
 +
 +        if (mtmp->mtrapped &&
 +            (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
 +            (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
 +            sobj_at(BOULDER, trap->tx, trap->ty)) {
 +        /* can't swap places with pet pinned in a pit by a boulder */
 +        u.ux = u.ux0,  u.uy = u.uy0;  /* didn't move after all */
 +        } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
 +        /* can't swap places when pet can't move to your spot */
 +        u.ux = u.ux0,  u.uy = u.uy0;
 +        You("stop.  %s can't move diagonally.",
 +            upstart(y_monnam(mtmp)));
 +        } else if (u.ux0 != x && u.uy0 != y &&
 +               bad_rock(mtmp->data, x, u.uy0) &&
 +               bad_rock(mtmp->data, u.ux0, y) &&
 +               (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
 +        /* can't swap places when pet won't fit thru the opening */
 +        u.ux = u.ux0,  u.uy = u.uy0;  /* didn't move after all */
 +        You("stop.  %s won't fit through.", upstart(y_monnam(mtmp)));
 +        } else {
 +        char pnambuf[BUFSZ];
 +
 +        /* save its current description in case of polymorph */
 +        Strcpy(pnambuf, y_monnam(mtmp));
 +        mtmp->mtrapped = 0;
 +        remove_monster(x, y);
 +        place_monster(mtmp, u.ux0, u.uy0);
 +        newsym(x, y);
 +        newsym(u.ux0, u.uy0);
 +
 +        You("%s %s.", mtmp->mtame ? "swap places with" : "frighten",
 +            pnambuf);
 +
 +        /* check for displacing it into pools and traps */
 +        switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) {
 +        case 0:
 +            break;
 +        case 1:               /* trapped */
 +        case 3:               /* changed levels */
 +            /* there's already been a trap message, reinforce it */
 +            abuse_dog(mtmp);
 +            adjalign(-3);
 +            break;
 +        case 2:
 +            /* drowned or died...
 +             * you killed your pet by direct action, so get experience
 +             * and possibly penalties;
 +             * we want the level gain message, if it happens, to occur
 +             * before the guilt message below
 +             */
 +          {
 +            /* minliquid() and mintrap() call mondead() rather than
 +               killed() so we duplicate some of the latter here */
 +            int tmp, mndx;
 +
 +            u.uconduct.killer++;
 +            mndx = monsndx(mtmp->data);
 +            tmp = experience(mtmp, (int)mvitals[mndx].died);
 +            more_experienced(tmp, 0);
 +            newexplevel();    /* will decide if you go up */
 +          }
 +            /* That's no way to treat a pet!  Your god gets angry.
 +             *
 +             * [This has always been pretty iffy.  Why does your
 +             * patron deity care at all, let alone enough to get mad?]
 +             */
 +            if (rn2(4)) {
 +            You_feel("guilty about losing your pet like this.");
 +            u.ugangr++;
 +            adjalign(-15);
 +            }
 +            break;
 +        default:
 +            pline("that's strange, unknown mintrap result!");
 +            break;
 +        }
 +        }
 +    }
 +
 +    reset_occupations();
 +    if (context.run) {
 +        if ( context.run < 8 )
 +        if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
 +            IS_FURNITURE(tmpr->typ))
 +            nomul(0);
 +    }
 +
 +    if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) ||
 +        u.dx || u.dy)
 +        (void) hideunder(&youmonst);
 +
 +    /*
 +     * Mimics (or whatever) become noticeable if they move and are
 +     * imitating something that doesn't move.  We could extend this
 +     * to non-moving monsters...
 +     */
 +    if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
 +                || youmonst.m_ap_type == M_AP_FURNITURE))
 +        youmonst.m_ap_type = M_AP_NOTHING;
 +
 +    check_leash(u.ux0,u.uy0);
 +
 +    if(u.ux0 != u.ux || u.uy0 != u.uy) {
 +        u.umoved = TRUE;
 +        /* Clean old position -- vision_recalc() will print our new one. */
 +        newsym(u.ux0,u.uy0);
 +        /* Since the hero has moved, adjust what can be seen/unseen. */
 +        vision_recalc(1);     /* Do the work now in the recover time. */
 +        invocation_message();
 +    }
 +
 +    if (Punished)                             /* put back ball and chain */
 +        move_bc(0,bc_control,ballx,bally,chainx,chainy);
 +
 +    spoteffects(TRUE);
 +
 +    /* delay next move because of ball dragging */
 +    /* must come after we finished picking up, in spoteffects() */
 +    if (cause_delay) {
 +        nomul(-2);
+           multi_reason = "dragging an iron ball";
 -          nomovemsg = "";
 -      }
 -
 -      if (context.run && flags.runmode != RUN_TPORT) {
 -          /* display every step or every 7th step depending upon mode */
 -          if (flags.runmode != RUN_LEAP || !(moves % 7L)) {
 -              if (flags.time) context.botl = 1;
 -              curs_on_u();
 -              delay_output();
 -              if (flags.runmode == RUN_CRAWL) {
 -                  delay_output();
 -                  delay_output();
 -                  delay_output();
 -                  delay_output();
 -              }
 -          }
 -      }
 +        nomovemsg = "";
 +    }
 +
 +    if (context.run && flags.runmode != RUN_TPORT) {
 +        /* display every step or every 7th step depending upon mode */
 +        if (flags.runmode != RUN_LEAP || !(moves % 7L)) {
 +        if (flags.time) context.botl = 1;
 +        curs_on_u();
 +        delay_output();
 +        if (flags.runmode == RUN_CRAWL) {
 +            delay_output();
 +            delay_output();
 +            delay_output();
 +            delay_output();
 +        }
 +        }
 +    }
  }
  
  /* combat increases metabolism */
@@@ -2165,64 -2166,76 +2166,76 @@@ register boolean newlev
  int
  dopickup()
  {
 -      int count;
 -      struct trap *traphere = t_at(u.ux, u.uy);
 -      /* awful kludge to work around parse()'s pre-decrement */
 -      count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
 -      multi = 0;      /* always reset */
 -      /* uswallow case added by GAN 01/29/87 */
 -      if(u.uswallow) {
 -          if (!u.ustuck->minvent) {
 -              if (is_animal(u.ustuck->data)) {
 -                  You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
 -                  pline("But it's kind of slimy, so you drop it.");
 -              } else
 -                  You("don't %s anything in here to pick up.",
 -                        Blind ? "feel" : "see");
 -              return(1);
 -          } else {
 -              int tmpcount = -count;
 -              return loot_mon(u.ustuck, &tmpcount, (boolean *)0);
 -          }
 -      }
 -      if(is_pool(u.ux, u.uy)) {
 -          if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
 -                      || (Flying && !Breathless)) {
 -              You("cannot dive into the water to pick things up.");
 -              return(0);
 -          } else if (!Underwater) {
 -              You_cant("even see the bottom, let alone pick up %s.",
 -                              something);
 -              return(0);
 -          }
 -      }
 -      if (is_lava(u.ux, u.uy)) {
 -          if (Wwalking || is_floater(youmonst.data) ||
 -                  is_clinger(youmonst.data) || (Flying && !Breathless)) {
 -              You_cant("reach the bottom to pick things up.");
 -              return(0);
 -          } else if (!likes_lava(youmonst.data)) {
 -              You("would burn to a crisp trying to pick things up.");
 -              return(0);
 -          }
 -      }
 -      if (!OBJ_AT(u.ux, u.uy)) {
 +    int count;
 +    struct trap *traphere = t_at(u.ux, u.uy);
 +    /* awful kludge to work around parse()'s pre-decrement */
 +    count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
 +    multi = 0;        /* always reset */
 +    /* uswallow case added by GAN 01/29/87 */
 +    if(u.uswallow) {
 +        if (!u.ustuck->minvent) {
 +        if (is_animal(u.ustuck->data)) {
 +            You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
 +            pline("But it's kind of slimy, so you drop it.");
 +        } else
 +            You("don't %s anything in here to pick up.",
 +              Blind ? "feel" : "see");
 +        return(1);
 +        } else {
 +            int tmpcount = -count;
 +        return loot_mon(u.ustuck, &tmpcount, (boolean *)0);
 +        }
 +    }
 +    if(is_pool(u.ux, u.uy)) {
 +        if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
 +            || (Flying && !Breathless)) {
 +        You("cannot dive into the water to pick things up.");
 +        return(0);
 +        } else if (!Underwater) {
 +        You_cant("even see the bottom, let alone pick up %s.",
 +                something);
 +        return(0);
 +        }
 +    }
 +    if (is_lava(u.ux, u.uy)) {
 +        if (Wwalking || is_floater(youmonst.data) ||
 +            is_clinger(youmonst.data) || (Flying && !Breathless)) {
 +        You_cant("reach the bottom to pick things up.");
 +        return(0);
 +        } else if (!likes_lava(youmonst.data)) {
 +        You("would burn to a crisp trying to pick things up.");
 +        return(0);
 +        }
 +    }
 +    if (!OBJ_AT(u.ux, u.uy)) {
-         There("is nothing here to pick up.");
+           register struct rm *lev = &levl[u.ux][u.uy];
+           if (IS_THRONE(lev->typ))
+               pline("It must weigh%s a ton!",
+                     lev->looted ? " almost" : "");
+           else if (IS_SINK(lev->typ))
+               pline_The("plumbing connects it to the floor.");
+           else if (IS_GRAVE(lev->typ))
+               You("don't need a gravestone.  Yet.");
+           else if (IS_FOUNTAIN(lev->typ))
+               You("could drink the water...");
+           else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
+               pline("It won't come off the hinges.");
+           else There("is nothing here to pick up.");
 -          return 0;
 -      }
 -      if (!can_reach_floor(TRUE)) {
 -          if (traphere && uteetering_at_seen_pit(traphere))
 -              You("cannot reach the bottom of the pit.");
 -          else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
 -              rider_cant_reach();
 -          else if (Blind && !can_reach_floor(TRUE))
 -              You("cannot reach anything here.");
 -          else
 -              You("cannot reach the %s.", surface(u.ux,u.uy));
 -          return 0;
 -      }
 -
 -      return (pickup(-count));
 +        return 0;
 +    }
 +    if (!can_reach_floor(TRUE)) {
 +        if (traphere && uteetering_at_seen_pit(traphere))
 +        You("cannot reach the bottom of the pit.");
 +        else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
 +        rider_cant_reach();
 +        else if (Blind && !can_reach_floor(TRUE))
 +            You("cannot reach anything here.");
 +        else
 +        You("cannot reach the %s.", surface(u.ux,u.uy));
 +        return 0;
 +    }
 +
 +    return (pickup(-count));
  }
  
  /* stop running if we see something interesting */
@@@ -2416,13 -2429,14 +2429,14 @@@ monster_nearby(
  
  void
  nomul(nval)
 -      register int nval;
 +    register int nval;
  {
 -      if(multi < nval) return;        /* This is a bug fix by ab@unido */
 -      u.uinvulnerable = FALSE;        /* Kludge to avoid ctrl-C bug -dlc */
 -      u.usleep = 0;
 -      multi = nval;
 +    if(multi < nval) return;  /* This is a bug fix by ab@unido */
 +    u.uinvulnerable = FALSE;  /* Kludge to avoid ctrl-C bug -dlc */
 +    u.usleep = 0;
 +    multi = nval;
+       if (nval == 0) multi_reason = NULL;
 -      context.travel = context.travel1 = context.mv = context.run = 0;
 +    context.travel = context.travel1 = context.mv = context.run = 0;
  }
  
  /* called when a non-movement, multi-turn action has completed */
  unmul(msg_override)
  const char *msg_override;
  {
 -      multi = 0;      /* caller will usually have done this already */
 -      if (msg_override) nomovemsg = msg_override;
 -      else if (!nomovemsg) nomovemsg = You_can_move_again;
 -      if (*nomovemsg) pline1(nomovemsg);
 -      nomovemsg = 0;
 -      u.usleep = 0;
 +    multi = 0;        /* caller will usually have done this already */
 +    if (msg_override) nomovemsg = msg_override;
 +    else if (!nomovemsg) nomovemsg = You_can_move_again;
 +    if (*nomovemsg) pline1(nomovemsg);
 +    nomovemsg = 0;
 +    u.usleep = 0;
+       multi_reason = NULL;
 -      if (afternmv) (*afternmv)();
 -      afternmv = 0;
 +    if (afternmv) (*afternmv)();
 +    afternmv = 0;
  }
  
  STATIC_OVL void
diff --cc src/invent.c
index 1a6e7673e2ff832dd8a37f5bef3e8c9dbaa80c51,2cc9e90044f66d7c5532dd90e12cc15d879fdfa0..f1a38683ac4af048ab2434e2ecb74bc668fc21cb
@@@ -765,225 -753,225 +765,225 @@@ struct obj 
  getobj(let,word)
  register const char *let,*word;
  {
 -      register struct obj *otmp;
 -      register char ilet;
 -      char buf[BUFSZ], qbuf[QBUFSZ];
 -      char lets[BUFSZ], altlets[BUFSZ], *ap;
 -      register int foo = 0;
 -      register char *bp = buf;
 -      xchar allowcnt = 0;     /* 0, 1 or 2 */
 -      struct obj *firstobj = invent;
 -      boolean usegold = FALSE;        /* can't use gold because its illegal */
 -      boolean allowall = FALSE;
 -      boolean allownone = FALSE;
 -      boolean useboulder = FALSE;
 -      xchar foox = 0;
 -      long cnt, prevcnt;
 -      boolean prezero;
 -      long dummymask;
 -
 -      if(*let == ALLOW_COUNT) let++, allowcnt = 1;
 -      if(*let == COIN_CLASS) let++, usegold = TRUE;
 -
 -      /* Equivalent of an "ugly check" for gold */
 -      if (usegold && !strcmp(word, "eat") &&
 -          (!metallivorous(youmonst.data)
 -           || youmonst.data == &mons[PM_RUST_MONSTER]))
 -              usegold = FALSE;
 -
 -      if(*let == ALL_CLASSES) let++, allowall = TRUE;
 -      if(*let == ALLOW_NONE) let++, allownone = TRUE;
 -      /* "ugly check" for reading fortune cookies, part 1 */
 -      /* The normal 'ugly check' keeps the object on the inventory list.
 -       * We don't want to do that for shirts/cookies, so the check for
 -       * them is handled a bit differently (and also requires that we set
 -       * allowall in the caller)
 -       */
 -      if(allowall && !strcmp(word, "read")) allowall = FALSE;
 -
 -      /* another ugly check: show boulders (not statues) */
 -      if(*let == WEAPON_CLASS &&
 -         !strcmp(word, "throw") && throws_rocks(youmonst.data))
 -          useboulder = TRUE;
 -
 -      if(allownone) *bp++ = '-';
 -      if(bp > buf && bp[-1] == '-') *bp++ = ' ';
 -      ap = altlets;
 -
 -      if (!flags.invlet_constant) reassign();
 -
 -      for (otmp = firstobj; otmp; otmp = otmp->nobj) {
 -          if (&bp[foo] == &buf[sizeof buf - 1] ||
 -                  ap == &altlets[sizeof altlets - 1]) {
 -              /* we must have a huge number of NOINVSYM items somehow */
 -              impossible("getobj: inventory overflow");
 -              break;
 -          }
 +    register struct obj *otmp;
 +    register char ilet;
 +    char buf[BUFSZ], qbuf[QBUFSZ];
 +    char lets[BUFSZ], altlets[BUFSZ], *ap;
 +    register int foo = 0;
 +    register char *bp = buf;
 +    xchar allowcnt = 0;       /* 0, 1 or 2 */
 +    struct obj *firstobj = invent;
 +    boolean usegold = FALSE;  /* can't use gold because its illegal */
 +    boolean allowall = FALSE;
 +    boolean allownone = FALSE;
 +    boolean useboulder = FALSE;
 +    xchar foox = 0;
 +    long cnt, prevcnt;
 +    boolean prezero;
 +    long dummymask;
 +
 +    if(*let == ALLOW_COUNT) let++, allowcnt = 1;
 +    if(*let == COIN_CLASS) let++, usegold = TRUE;
 +
 +    /* Equivalent of an "ugly check" for gold */
 +    if (usegold && !strcmp(word, "eat") &&
 +        (!metallivorous(youmonst.data)
 +         || youmonst.data == &mons[PM_RUST_MONSTER]))
 +        usegold = FALSE;
 +
 +    if(*let == ALL_CLASSES) let++, allowall = TRUE;
 +    if(*let == ALLOW_NONE) let++, allownone = TRUE;
 +    /* "ugly check" for reading fortune cookies, part 1 */
 +    /* The normal 'ugly check' keeps the object on the inventory list.
 +     * We don't want to do that for shirts/cookies, so the check for
 +     * them is handled a bit differently (and also requires that we set
 +     * allowall in the caller)
 +     */
 +    if(allowall && !strcmp(word, "read")) allowall = FALSE;
 +
 +    /* another ugly check: show boulders (not statues) */
 +    if(*let == WEAPON_CLASS &&
 +       !strcmp(word, "throw") && throws_rocks(youmonst.data))
 +        useboulder = TRUE;
 +
 +    if(allownone) *bp++ = '-';
 +    if(bp > buf && bp[-1] == '-') *bp++ = ' ';
 +    ap = altlets;
 +
 +    if (!flags.invlet_constant) reassign();
  
 -          if (!*let || index(let, otmp->oclass)
 -              || (usegold && otmp->invlet == GOLD_SYM)
 -              || (useboulder && otmp->otyp == BOULDER)
 -              ) {
 -              register int otyp = otmp->otyp;
 -              bp[foo++] = otmp->invlet;
 -
 -              /* ugly check: remove inappropriate things */
 -              if ((taking_off(word) &&
 -                  !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 -              || (putting_on(word) &&
 -                   (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 -                                                      /* already worn */
 +    for (otmp = firstobj; otmp; otmp = otmp->nobj) {
 +        if (&bp[foo] == &buf[sizeof buf - 1] ||
 +            ap == &altlets[sizeof altlets - 1]) {
 +        /* we must have a huge number of NOINVSYM items somehow */
 +        impossible("getobj: inventory overflow");
 +        break;
 +        }
 +
 +        if (!*let || index(let, otmp->oclass)
 +        || (usegold && otmp->invlet == GOLD_SYM)
 +        || (useboulder && otmp->otyp == BOULDER)
 +        ) {
 +        register int otyp = otmp->otyp;
 +        bp[foo++] = otmp->invlet;
 +
 +        /* ugly check: remove inappropriate things */
 +        if ((taking_off(word) &&
 +            !(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 +        || (putting_on(word) &&
 +             (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
 +                            /* already worn */
  #if 0 /* 3.4.1 -- include currently wielded weapon among the choices */
 -              || (!strcmp(word, "wield") &&
 -                  (otmp->owornmask & W_WEP))
 +        || (!strcmp(word, "wield") &&
 +            (otmp->owornmask & W_WEP))
  #endif
 -              || (!strcmp(word, "ready") &&
 -                  (otmp == uwep || (otmp == uswapwep && u.twoweap)))
 -              || ((!strcmp(word, "dip") || !strcmp(word, "grease")) &&
 -                  inaccessible_equipment(otmp, (const char *)0 , FALSE))
 -                  ) {
 -                      foo--;
 -                      foox++;
 -              }
 -
 -              /* Second ugly check; unlike the first it won't trigger an
 -               * "else" in "you don't have anything else to ___".
 -               */
 -              else if ((putting_on(word) &&
 -                  ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
 -                  (otmp->oclass == TOOL_CLASS &&
 -                   otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
 -              || (!strcmp(word, "wield") &&
 -                  (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
 -              || (!strcmp(word, "eat") && !is_edible(otmp))
 -              || (!strcmp(word, "sacrifice") &&
 -                  (otyp != CORPSE &&
 -                   otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
 -              || (!strcmp(word, "write with") &&
 -                  (otmp->oclass == TOOL_CLASS &&
 -                   otyp != MAGIC_MARKER && otyp != TOWEL))
 -              || (!strcmp(word, "tin") &&
 -                  (otyp != CORPSE || !tinnable(otmp)))
 -              || (!strcmp(word, "rub") &&
 -                  ((otmp->oclass == TOOL_CLASS &&
 -                    otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
 -                    otyp != BRASS_LANTERN) ||
 -                   (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
 -              || ((!strcmp(word, "use or apply") ||
 -                      !strcmp(word, "untrap with")) &&
 -                   /* Picks, axes, pole-weapons, bullwhips */
 -                  ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
 -                    !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
 -                   (otmp->oclass == POTION_CLASS &&
 -                   /* only applicable potion is oil, and it will only
 -                      be offered as a choice when already discovered */
 -                   (otyp != POT_OIL || !otmp->dknown ||
 -                    !objects[POT_OIL].oc_name_known)) ||
 -                   (otmp->oclass == FOOD_CLASS &&
 -                    otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
 -                   (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
 -              || (!strcmp(word, "invoke") &&
 -                  (!otmp->oartifact && !objects[otyp].oc_unique &&
 -                   (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
 -                   otyp != CRYSTAL_BALL &&    /* #invoke synonym for apply */
 -                 /* note: presenting the possibility of invoking non-artifact
 -                    mirrors and/or lamps is a simply a cruel deception... */
 -                   otyp != MIRROR && otyp != MAGIC_LAMP &&
 -                   (otyp != OIL_LAMP ||       /* don't list known oil lamp */
 -                    (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
 -              || (!strcmp(word, "untrap with") &&
 -                  (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
 -              || (!strcmp(word, "tip") && !Is_container(otmp) &&
 -                 /* include horn of plenty if sufficiently discovered */
 -                  (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown ||
 -                      !objects[HORN_OF_PLENTY].oc_name_known))
 -              || (!strcmp(word, "charge") && !is_chargeable(otmp))
 -              || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
 -                  )
 -                      foo--;
 -              /* ugly check for unworn armor that can't be worn */
 -              else if ((putting_on(word) && *let == ARMOR_CLASS &&
 -                        !canwearobj(otmp, &dummymask, FALSE))
 -              /* or unsuitable items rubbed on known touchstone */
 -              || (!strncmp(word, "rub on the stone", 16) &&
 -                  *let == GEM_CLASS &&
 -                  otmp->dknown && objects[otyp].oc_name_known)
 -              /* suppress corpses on astral, amulets elsewhere */
 -              || (!strcmp(word, "sacrifice") &&
 -                  /* (!astral && amulet) || (astral && !amulet) */
 -                  (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
 -              /* suppress container being stashed into */
 -              || (!strcmp(word, "stash") && !ck_bag(otmp))
 -              /* worn armor or accessory covered by cursed worn armor */
 -              || (taking_off(word) &&
 -                  inaccessible_equipment(otmp, (const char *)0, TRUE))
 -                  ) {
 -                      /* acceptable but not listed as likely candidate */
 -                      foo--;
 -                      allowall = TRUE;
 -                      *ap++ = otmp->invlet;
 -              }
 -          } else {
 -
 -              /* "ugly check" for reading fortune cookies, part 2 */
 -              if ((!strcmp(word, "read")
 +        || (!strcmp(word, "ready") &&
 +            (otmp == uwep || (otmp == uswapwep && u.twoweap)))
 +        || ((!strcmp(word, "dip") || !strcmp(word, "grease")) &&
 +            inaccessible_equipment(otmp, (const char *)0 , FALSE))
 +            ) {
 +            foo--;
 +            foox++;
 +        }
 +
 +        /* Second ugly check; unlike the first it won't trigger an
 +         * "else" in "you don't have anything else to ___".
 +         */
 +        else if ((putting_on(word) &&
 +            ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) ||
 +            (otmp->oclass == TOOL_CLASS &&
 +             otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES)))
 +        || (!strcmp(word, "wield") &&
 +            (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
 +        || (!strcmp(word, "eat") && !is_edible(otmp))
 +        || (!strcmp(word, "sacrifice") &&
 +            (otyp != CORPSE &&
 +             otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
 +        || (!strcmp(word, "write with") &&
 +            (otmp->oclass == TOOL_CLASS &&
 +             otyp != MAGIC_MARKER && otyp != TOWEL))
 +        || (!strcmp(word, "tin") &&
 +            (otyp != CORPSE || !tinnable(otmp)))
 +        || (!strcmp(word, "rub") &&
 +            ((otmp->oclass == TOOL_CLASS &&
 +              otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
 +              otyp != BRASS_LANTERN) ||
 +             (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
 +        || ((!strcmp(word, "use or apply") ||
 +            !strcmp(word, "untrap with")) &&
 +             /* Picks, axes, pole-weapons, bullwhips */
 +            ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) &&
 +              !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) ||
 +             (otmp->oclass == POTION_CLASS &&
 +             /* only applicable potion is oil, and it will only
 +            be offered as a choice when already discovered */
 +             (otyp != POT_OIL || !otmp->dknown ||
 +              !objects[POT_OIL].oc_name_known)) ||
 +             (otmp->oclass == FOOD_CLASS &&
 +              otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) ||
 +             (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
 +        || (!strcmp(word, "invoke") &&
 +            (!otmp->oartifact && !objects[otyp].oc_unique &&
 +             (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
 +             otyp != CRYSTAL_BALL &&  /* #invoke synonym for apply */
 +           /* note: presenting the possibility of invoking non-artifact
 +              mirrors and/or lamps is a simply a cruel deception... */
 +             otyp != MIRROR && otyp != MAGIC_LAMP &&
 +             (otyp != OIL_LAMP ||     /* don't list known oil lamp */
 +              (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
 +        || (!strcmp(word, "untrap with") &&
 +            (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
 +        || (!strcmp(word, "tip") && !Is_container(otmp) &&
 +           /* include horn of plenty if sufficiently discovered */
 +            (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown ||
 +            !objects[HORN_OF_PLENTY].oc_name_known))
 +        || (!strcmp(word, "charge") && !is_chargeable(otmp))
 +        || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
 +            )
 +            foo--;
 +        /* ugly check for unworn armor that can't be worn */
 +        else if ((putting_on(word) && *let == ARMOR_CLASS &&
 +              !canwearobj(otmp, &dummymask, FALSE))
 +        /* or unsuitable items rubbed on known touchstone */
 +        || (!strncmp(word, "rub on the stone", 16) &&
 +            *let == GEM_CLASS &&
 +            otmp->dknown && objects[otyp].oc_name_known)
 +        /* suppress corpses on astral, amulets elsewhere */
 +        || (!strcmp(word, "sacrifice") &&
 +            /* (!astral && amulet) || (astral && !amulet) */
 +            (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
 +        /* suppress container being stashed into */
 +        || (!strcmp(word, "stash") && !ck_bag(otmp))
 +        /* worn armor or accessory covered by cursed worn armor */
 +        || (taking_off(word) &&
 +            inaccessible_equipment(otmp, (const char *)0, TRUE))
 +            ) {
 +            /* acceptable but not listed as likely candidate */
 +            foo--;
 +            allowall = TRUE;
 +            *ap++ = otmp->invlet;
 +        }
 +        } else {
 +
 +        /* "ugly check" for reading fortune cookies, part 2 */
 +        if ((!strcmp(word, "read")
-               && (otmp->otyp == FORTUNE_COOKIE || otmp->otyp == T_SHIRT)))
-             allowall = TRUE;
+                    && is_readable(otmp)))
+                       allowall = usegold = TRUE;
 -          }
 -      }
 -      bp[foo] = 0;
 -      if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
 -      Strcpy(lets, bp);       /* necessary since we destroy buf */
 -      if(foo > 5)                     /* compactify string */
 -              compactify(bp);
 -      *ap = '\0';
 -
 -      if(!foo && !allowall && !allownone) {
 -              You("don't have anything %sto %s.",
 -                      foox ? "else " : "", word);
 -              return((struct obj *)0);
 -      }
 -      for(;;) {
 -              cnt = 0;
 -              if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
 -              prezero = FALSE;
 -              if(!buf[0]) {
 -                      Sprintf(qbuf, "What do you want to %s? [*]", word);
 -              } else {
 -                      Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
 -                              word, buf);
 -              }
 -              if (in_doagain)
 -                  ilet = readchar();
 -              else
 -                  ilet = yn_function(qbuf, (char *)0, '\0');
 -              if (digit(ilet) && !allowcnt) {
 -                  pline("No count allowed with this command.");
 -                  continue;
 -              }
 -              if (ilet == '0') prezero = TRUE;
 -              while (digit(ilet)) {
 -                  if (ilet != '?' && ilet != '*') savech(ilet);
 -                  /* accumulate unless cnt has overflowed */
 -                  if (allowcnt < 3) {
 -                      prevcnt = cnt;
 -                      cnt = 10L * cnt + (long)(ilet - '0');
 -                      /* signal presence of cnt */
 -                      allowcnt = (cnt >= prevcnt) ? 2 : 3;
 -                  }
 -                  ilet = readchar();
 -              }
 -              if (allowcnt == 3) {
 -                  /* overflow detected; force cnt to be invalid */
 -                  cnt = -1L;
 -                  allowcnt = 2;
 -              }
 -              if(index(quitchars,ilet)) {
 -                  if(flags.verbose)
 -                      pline1(Never_mind);
 -                  return((struct obj *)0);
 -              }
 -              if(ilet == '-') {
 +        }
 +    }
 +    bp[foo] = 0;
 +    if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
 +    Strcpy(lets, bp); /* necessary since we destroy buf */
 +    if(foo > 5)                       /* compactify string */
 +        compactify(bp);
 +    *ap = '\0';
 +
 +    if(!foo && !allowall && !allownone) {
 +        You("don't have anything %sto %s.",
 +            foox ? "else " : "", word);
 +        return((struct obj *)0);
 +    }
 +    for(;;) {
 +        cnt = 0;
 +        if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
 +        prezero = FALSE;
 +        if(!buf[0]) {
 +            Sprintf(qbuf, "What do you want to %s? [*]", word);
 +        } else {
 +            Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
 +                word, buf);
 +        }
 +        if (in_doagain)
 +            ilet = readchar();
 +        else
 +            ilet = yn_function(qbuf, (char *)0, '\0');
 +        if (digit(ilet) && !allowcnt) {
 +            pline("No count allowed with this command.");
 +            continue;
 +        }
 +        if (ilet == '0') prezero = TRUE;
 +        while (digit(ilet)) {
 +            if (ilet != '?' && ilet != '*') savech(ilet);
 +            /* accumulate unless cnt has overflowed */
 +            if (allowcnt < 3) {
 +            prevcnt = cnt;
 +            cnt = 10L * cnt + (long)(ilet - '0');
 +            /* signal presence of cnt */
 +            allowcnt = (cnt >= prevcnt) ? 2 : 3;
 +            }
 +            ilet = readchar();
 +        }
 +        if (allowcnt == 3) {
 +            /* overflow detected; force cnt to be invalid */
 +            cnt = -1L;
 +            allowcnt = 2;
 +        }
 +        if(index(quitchars,ilet)) {
 +            if(flags.verbose)
 +            pline1(Never_mind);
 +            return((struct obj *)0);
 +        }
 +        if(ilet == '-') {
                    if (!allownone) {
                        char *suf = NULL;
                        strcpy(buf, word);
diff --cc src/mon.c
index 2da55e37fd6c0c1859e9795efaae2e6a2ad70bc9,41d17e6715d361d1215f34c85b2f7b9cc4aefc83..9e511670b6d7d1a00cd4a54de55f7a15369abac1
+++ b/src/mon.c
@@@ -622,91 -603,92 +622,92 @@@ movemon(
   */
  int
  meatmetal(mtmp)
 -      register struct monst *mtmp;
 +    register struct monst *mtmp;
  {
 -      register struct obj *otmp;
 -      struct permonst *ptr;
 -      int poly, grow, heal, mstone;
 +    register struct obj *otmp;
 +    struct permonst *ptr;
 +    int poly, grow, heal, mstone;
  
 -      /* If a pet, eating is handled separately, in dog.c */
 -      if (mtmp->mtame) return 0;
 +    /* If a pet, eating is handled separately, in dog.c */
 +    if (mtmp->mtame) return 0;
  
 -      /* Eats topmost metal object if it is there */
 -      for (otmp = level.objects[mtmp->mx][mtmp->my];
 -                                              otmp; otmp = otmp->nexthere) {
 +    /* Eats topmost metal object if it is there */
 +    for (otmp = level.objects[mtmp->mx][mtmp->my];
 +                        otmp; otmp = otmp->nexthere) {
-         if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp))
+           /* Don't eat indigestible/choking/inappropriate objects */
+           if ((mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) ||
+               (otmp->otyp == AMULET_OF_STRANGULATION) ||
+               (otmp->otyp == RIN_SLOW_DIGESTION))
 -              continue;
 -          if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) &&
 -              touch_artifact(otmp,mtmp)) {
 -              if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) {
 -                  if (canseemon(mtmp) && flags.verbose) {
 -                      pline("%s eats %s!",
 -                              Monnam(mtmp),
 -                              distant_name(otmp,doname));
 -                  }
 -                  /* The object's rustproofing is gone now */
 -                  otmp->oerodeproof = 0;
 -                  mtmp->mstun = 1;
 -                  if (canseemon(mtmp) && flags.verbose) {
 -                      pline("%s spits %s out in disgust!",
 -                            Monnam(mtmp), distant_name(otmp,doname));
 -                  }
 +        continue;
 +        if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) &&
 +        touch_artifact(otmp,mtmp)) {
 +        if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) {
 +            if (canseemon(mtmp) && flags.verbose) {
 +            pline("%s eats %s!",
 +                Monnam(mtmp),
 +                distant_name(otmp,doname));
 +            }
 +            /* The object's rustproofing is gone now */
 +            otmp->oerodeproof = 0;
 +            mtmp->mstun = 1;
 +            if (canseemon(mtmp) && flags.verbose) {
 +            pline("%s spits %s out in disgust!",
 +                  Monnam(mtmp), distant_name(otmp,doname));
 +            }
-         /* KMH -- Don't eat indigestible/choking objects */
-         } else if (otmp->otyp != AMULET_OF_STRANGULATION &&
-                 otmp->otyp != RIN_SLOW_DIGESTION) {
+               } else {
 -                  if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
 -                      pline("%s eats %s!", Monnam(mtmp),
 -                              distant_name(otmp,doname));
 -                  else if (flags.verbose)
 -                      You_hear("a crunching sound.");
 -                  mtmp->meating = otmp->owt/2 + 1;
 -                  /* Heal up to the object's weight in hp */
 -                  if (mtmp->mhp < mtmp->mhpmax) {
 -                      mtmp->mhp += objects[otmp->otyp].oc_weight;
 -                      if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
 -                  }
 -                  if(otmp == uball) {
 -                      unpunish();
 -                      delobj(otmp);
 -                  } else if (otmp == uchain) {
 -                      unpunish();     /* frees uchain */
 -                  } else {
 -                      poly = polyfodder(otmp);
 -                      grow = mlevelgain(otmp);
 -                      heal = mhealup(otmp);
 -                      mstone = mstoning(otmp);
 -                      delobj(otmp);
 -                      ptr = mtmp->data;
 -                      if (poly) {
 -                          if (newcham(mtmp, (struct permonst *)0,
 -                                      FALSE, FALSE))
 -                              ptr = mtmp->data;
 -                      } else if (grow) {
 -                          ptr = grow_up(mtmp, (struct monst *)0);
 -                      } else if (mstone) {
 -                          if (poly_when_stoned(ptr)) {
 -                              mon_to_stone(mtmp);
 -                              ptr = mtmp->data;
 -                          } else if (!resists_ston(mtmp)) {
 -                              if (canseemon(mtmp))
 -                                  pline("%s turns to stone!", Monnam(mtmp));
 -                              monstone(mtmp);
 -                              ptr = (struct permonst *)0;
 -                          }
 -                      } else if (heal) {
 -                          mtmp->mhp = mtmp->mhpmax;
 -                      }
 -                      if (!ptr) return 2;              /* it died */
 -                  }
 -                  /* Left behind a pile? */
 -                  if (rnd(25) < 3)
 -                      (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE);
 -                  newsym(mtmp->mx, mtmp->my);
 -                  return 1;
 -              }
 -          }
 -      }
 -      return 0;
 +            if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
 +            pline("%s eats %s!", Monnam(mtmp),
 +                distant_name(otmp,doname));
 +            else if (flags.verbose)
 +            You_hear("a crunching sound.");
 +            mtmp->meating = otmp->owt/2 + 1;
 +            /* Heal up to the object's weight in hp */
 +            if (mtmp->mhp < mtmp->mhpmax) {
 +            mtmp->mhp += objects[otmp->otyp].oc_weight;
 +            if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
 +            }
 +            if(otmp == uball) {
 +            unpunish();
 +            delobj(otmp);
 +            } else if (otmp == uchain) {
 +            unpunish();       /* frees uchain */
 +            } else {
 +            poly = polyfodder(otmp);
 +            grow = mlevelgain(otmp);
 +            heal = mhealup(otmp);
 +            mstone = mstoning(otmp);
 +            delobj(otmp);
 +            ptr = mtmp->data;
 +            if (poly) {
 +                if (newcham(mtmp, (struct permonst *)0,
 +                    FALSE, FALSE))
 +                ptr = mtmp->data;
 +            } else if (grow) {
 +                ptr = grow_up(mtmp, (struct monst *)0);
 +            } else if (mstone) {
 +                if (poly_when_stoned(ptr)) {
 +                mon_to_stone(mtmp);
 +                ptr = mtmp->data;
 +                } else if (!resists_ston(mtmp)) {
 +                if (canseemon(mtmp))
 +                    pline("%s turns to stone!", Monnam(mtmp));
 +                monstone(mtmp);
 +                ptr = (struct permonst *)0;
 +                }
 +            } else if (heal) {
 +                mtmp->mhp = mtmp->mhpmax;
 +            }
 +            if (!ptr) return 2;                /* it died */
 +            }
 +            /* Left behind a pile? */
 +            if (rnd(25) < 3)
 +            (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE);
 +            newsym(mtmp->mx, mtmp->my);
 +            return 1;
 +        }
 +        }
 +    }
 +    return 0;
  }
  
  /* monster eats a pile of objects */
@@@ -1254,13 -1236,15 +1255,15 @@@ dmonsfree(
      int count = 0;
  
      for (mtmp = &fmon; *mtmp;) {
 -      freetmp = *mtmp;
 -      if (freetmp->mhp <= 0 && !freetmp->isgd) {
 +    freetmp = *mtmp;
 +    if (freetmp->mhp <= 0 && !freetmp->isgd) {
+           if (freetmp == context.polearm.hitmon)
+               context.polearm.hitmon = NULL;
 -          *mtmp = freetmp->nmon;
 -          dealloc_monst(freetmp);
 -          count++;
 -      } else
 -          mtmp = &(freetmp->nmon);
 +        *mtmp = freetmp->nmon;
 +        dealloc_monst(freetmp);
 +        count++;
 +    } else
 +        mtmp = &(freetmp->nmon);
      }
  
      if (count != iflags.purge_monsters)
diff --cc src/objnam.c
index 13a14504361931fac27bc83695e6fbf166511170,f40222c3b5dfbe4de805acc14d4aaa74b69862b8..a1115f5afd5fd2a8ec16dd09f3d7202418ec59e3
@@@ -239,272 -239,269 +239,277 @@@ char 
  xname(obj)
  register struct obj *obj;
  {
 -      register char *buf;
 -      register int typ = obj->otyp;
 -      register struct objclass *ocl = &objects[typ];
 -      int nn = ocl->oc_name_known, omndx = obj->corpsenm;
 -      const char *actualn = OBJ_NAME(*ocl);
 -      const char *dn = OBJ_DESCR(*ocl);
 -      const char *un = ocl->oc_uname;
 -      boolean pluralize = (obj->quan != 1L);
 -      boolean known, dknown, bknown;
 -
 -      buf = nextobuf() + PREFIX;      /* leave room for "17 -3 " */
 -      if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
 -              actualn = Japanese_item_name(typ);
 -
 -      buf[0] = '\0';
 -      /*
 -       * clean up known when it's tied to oc_name_known, eg after AD_DRIN
 -       * This is only required for unique objects since the article
 -       * printed for the object is tied to the combination of the two
 -       * and printing the wrong article gives away information.
 -       */
 -      if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
 -      if (!Blind) obj->dknown = TRUE;
 -      if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
 +    register char *buf;
 +    register int typ = obj->otyp;
 +    register struct objclass *ocl = &objects[typ];
 +    int nn = ocl->oc_name_known, omndx = obj->corpsenm;
 +    const char *actualn = OBJ_NAME(*ocl);
 +    const char *dn = OBJ_DESCR(*ocl);
 +    const char *un = ocl->oc_uname;
 +    boolean pluralize = (obj->quan != 1L);
 +    boolean known, dknown, bknown;
 +
 +    buf = nextobuf() + PREFIX;        /* leave room for "17 -3 " */
 +    if (Role_if(PM_SAMURAI) && Japanese_item_name(typ))
 +        actualn = Japanese_item_name(typ);
 +
 +    buf[0] = '\0';
 +    /*
 +     * clean up known when it's tied to oc_name_known, eg after AD_DRIN
 +     * This is only required for unique objects since the article
 +     * printed for the object is tied to the combination of the two
 +     * and printing the wrong article gives away information.
 +     */
 +    if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0;
 +    if (!Blind) obj->dknown = TRUE;
 +    if (Role_if(PM_PRIEST)) obj->bknown = TRUE;
  
 -      if (iflags.override_ID) {
 -              known = dknown = bknown = TRUE;
 -              nn = 1;
 -      } else {
 -              known = obj->known;
 -              dknown = obj->dknown;
 -              bknown = obj->bknown;
 -      }
 +    if (iflags.override_ID) {
 +        known = dknown = bknown = TRUE;
 +        nn = 1;
 +    } else {
 +        known = obj->known;
 +        dknown = obj->dknown;
 +        bknown = obj->bknown;
 +    }
  
 -      if (obj_is_pname(obj))
 -          goto nameit;
 -      switch (obj->oclass) {
 -          case AMULET_CLASS:
 -              if (!dknown)
 -                      Strcpy(buf, "amulet");
 -              else if (typ == AMULET_OF_YENDOR ||
 -                       typ == FAKE_AMULET_OF_YENDOR)
 -                      /* each must be identified individually */
 -                      Strcpy(buf, known ? actualn : dn);
 -              else if (nn)
 -                      Strcpy(buf, actualn);
 -              else if (un)
 -                      Sprintf(buf,"amulet called %s", un);
 -              else
 -                      Sprintf(buf,"%s amulet", dn);
 -              break;
 -          case WEAPON_CLASS:
 -              if (is_poisonable(obj) && obj->opoisoned)
 -                      Strcpy(buf, "poisoned ");
 -          case VENOM_CLASS:
 -          case TOOL_CLASS:
 -              if (typ == LENSES)
 -                      Strcpy(buf, "pair of ");
 -
 -              if (!dknown)
 -                      Strcat(buf, dn ? dn : actualn);
 -              else if (nn)
 -                      Strcat(buf, actualn);
 -              else if (un) {
 -                      Strcat(buf, dn ? dn : actualn);
 -                      Strcat(buf, " called ");
 -                      Strcat(buf, un);
 -              } else
 -                      Strcat(buf, dn ? dn : actualn);
 -              /* If we use an() here we'd have to remember never to use */
 -              /* it whenever calling doname() or xname(). */
 -              if (typ == FIGURINE && omndx != NON_PM)
 -                  Sprintf(eos(buf), " of a%s %s",
 -                          index(vowels, *mons[omndx].mname) ? "n" : "",
 -                          mons[omndx].mname);
 -              break;
 -          case ARMOR_CLASS:
 -              /* depends on order of the dragon scales objects */
 -              if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
 -                      Sprintf(buf, "set of %s", actualn);
 -                      break;
 -              }
 -              if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
 -
 -              if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
 -                              && !dknown) {
 -                      Strcpy(buf, "shield");
 -                      break;
 -              }
 -              if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) {
 -                      Strcpy(buf, "smooth shield");
 -                      break;
 -              }
 -
 -              if(nn)  Strcat(buf, actualn);
 -              else if(un) {
 -                      if(is_boots(obj))
 -                              Strcat(buf,"boots");
 -                      else if(is_gloves(obj))
 -                              Strcat(buf,"gloves");
 -                      else if(is_cloak(obj))
 -                              Strcpy(buf,"cloak");
 -                      else if(is_helmet(obj))
 -                              Strcpy(buf,"helmet");
 -                      else if(is_shield(obj))
 -                              Strcpy(buf,"shield");
 -                      else
 -                              Strcpy(buf,"armor");
 -                      Strcat(buf, " called ");
 -                      Strcat(buf, un);
 -              } else  Strcat(buf, dn);
 -              break;
 -          case FOOD_CLASS:
 -              if (typ == SLIME_MOLD) {
 -                      register struct fruit *f;
 -
 -                      for(f=ffruit; f; f = f->nextf) {
 -                              if(f->fid == obj->spe) {
 -                                      Strcpy(buf, f->fname);
 -                                      break;
 -                              }
 -                      }
 -                      if (!f) {
 -                          impossible("Bad fruit #%d?", obj->spe);
 -                          Strcpy(buf, "fruit");
 -                      } else if (pluralize) {
 -                          /* ick; already pluralized fruit names
 -                             are allowed--we want to try to avoid
 -                             adding a redundant plural suffix */
 -                          Strcpy(buf, makeplural(makesingular(buf)));
 -                          pluralize = FALSE;
 -                      }
 -                      break;
 -              }
 -
 -              Strcpy(buf, actualn);
 -              if (typ == TIN && known)
 -                      tin_details(obj, omndx, buf);
 -              break;
 -          case COIN_CLASS:
 -          case CHAIN_CLASS:
 -              Strcpy(buf, actualn);
 -              break;
 -          case ROCK_CLASS:
 -              if (typ == STATUE && omndx != NON_PM)
 -                  Sprintf(buf, "%s%s of %s%s",
 -                      (Role_if(PM_ARCHEOLOGIST) &&
 -                          (obj->spe & STATUE_HISTORIC)) ? "historic " : "",
 -                      actualn,
 -                      type_is_pname(&mons[omndx]) ? "" :
 -                        the_unique_pm(&mons[omndx]) ? "the " :
 -                          index(vowels, *mons[omndx].mname) ? "an " : "a ",
 -                      mons[omndx].mname);
 -              else Strcpy(buf, actualn);
 -              break;
 -          case BALL_CLASS:
 -              Sprintf(buf, "%sheavy iron ball",
 -                      (obj->owt > ocl->oc_weight) ? "very " : "");
 -              break;
 -          case POTION_CLASS:
 -              if (dknown && obj->odiluted)
 -                      Strcpy(buf, "diluted ");
 -              if(nn || un || !dknown) {
 -                      Strcat(buf, "potion");
 -                      if(!dknown) break;
 -                      if(nn) {
 -                          Strcat(buf, " of ");
 -                          if (typ == POT_WATER &&
 -                              bknown && (obj->blessed || obj->cursed)) {
 -                              Strcat(buf, obj->blessed ? "holy " : "unholy ");
 -                          }
 -                          Strcat(buf, actualn);
 -                      } else {
 -                              Strcat(buf, " called ");
 -                              Strcat(buf, un);
 -                      }
 -              } else {
 -                      Strcat(buf, dn);
 -                      Strcat(buf, " potion");
 -              }
 -              break;
 -      case SCROLL_CLASS:
 -              Strcpy(buf, "scroll");
 -              if(!dknown) break;
 -              if(nn) {
 -                      Strcat(buf, " of ");
 -                      Strcat(buf, actualn);
 -              } else if(un) {
 -                      Strcat(buf, " called ");
 -                      Strcat(buf, un);
 -              } else if (ocl->oc_magic) {
 -                      Strcat(buf, " labeled ");
 -                      Strcat(buf, dn);
 -              } else {
 -                      Strcpy(buf, dn);
 -                      Strcat(buf, " scroll");
 -              }
 -              break;
 -      case WAND_CLASS:
 -              if(!dknown)
 -                      Strcpy(buf, "wand");
 -              else if(nn)
 -                      Sprintf(buf, "wand of %s", actualn);
 -              else if(un)
 -                      Sprintf(buf, "wand called %s", un);
 -              else
 -                      Sprintf(buf, "%s wand", dn);
 -              break;
 -      case SPBOOK_CLASS:
 -              if (!dknown) {
 -                      Strcpy(buf, "spellbook");
 -              } else if (nn) {
 -                      if (typ != SPE_BOOK_OF_THE_DEAD)
 -                          Strcpy(buf, "spellbook of ");
 -                      Strcat(buf, actualn);
 -              } else if (un) {
 -                      Sprintf(buf, "spellbook called %s", un);
 -              } else
 -                      Sprintf(buf, "%s spellbook", dn);
 -              break;
 -      case RING_CLASS:
 -              if(!dknown)
 -                      Strcpy(buf, "ring");
 -              else if(nn)
 -                      Sprintf(buf, "ring of %s", actualn);
 -              else if(un)
 -                      Sprintf(buf, "ring called %s", un);
 -              else
 -                      Sprintf(buf, "%s ring", dn);
 -              break;
 -      case GEM_CLASS:
 -          {
 -              const char *rock =
 -                          (ocl->oc_material == MINERAL) ? "stone" : "gem";
 -              if (!dknown) {
 -                  Strcpy(buf, rock);
 -              } else if (!nn) {
 -                  if (un) Sprintf(buf,"%s called %s", rock, un);
 -                  else Sprintf(buf, "%s %s", dn, rock);
 -              } else {
 -                  Strcpy(buf, actualn);
 -                  if (GemStone(typ)) Strcat(buf, " stone");
 -              }
 -              break;
 -          }
 -      default:
 -              Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
 -      }
 -      if (pluralize) Strcpy(buf, makeplural(buf));
 +    if (obj_is_pname(obj))
 +        goto nameit;
 +    switch (obj->oclass) {
 +        case AMULET_CLASS:
 +        if (!dknown)
 +            Strcpy(buf, "amulet");
 +        else if (typ == AMULET_OF_YENDOR ||
 +             typ == FAKE_AMULET_OF_YENDOR)
 +            /* each must be identified individually */
 +            Strcpy(buf, known ? actualn : dn);
 +        else if (nn)
 +            Strcpy(buf, actualn);
 +        else if (un)
 +            Sprintf(buf,"amulet called %s", un);
 +        else
 +            Sprintf(buf,"%s amulet", dn);
 +        break;
 +        case WEAPON_CLASS:
 +        if (is_poisonable(obj) && obj->opoisoned)
 +            Strcpy(buf, "poisoned ");
 +        case VENOM_CLASS:
 +        case TOOL_CLASS:
 +        if (typ == LENSES)
 +            Strcpy(buf, "pair of ");
 +
 +        if (!dknown)
 +            Strcat(buf, dn ? dn : actualn);
 +        else if (nn)
 +            Strcat(buf, actualn);
 +        else if (un) {
 +            Strcat(buf, dn ? dn : actualn);
 +            Strcat(buf, " called ");
 +            Strcat(buf, un);
 +        } else
 +            Strcat(buf, dn ? dn : actualn);
 +        /* If we use an() here we'd have to remember never to use */
 +        /* it whenever calling doname() or xname(). */
 +        if (typ == FIGURINE && omndx != NON_PM)
 +            Sprintf(eos(buf), " of a%s %s",
 +                index(vowels, *mons[omndx].mname) ? "n" : "",
 +                mons[omndx].mname);
 +        break;
 +        case ARMOR_CLASS:
 +        /* depends on order of the dragon scales objects */
 +        if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) {
 +            Sprintf(buf, "set of %s", actualn);
 +            break;
 +        }
 +        if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of ");
 +
 +        if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD
 +                && !dknown) {
 +            Strcpy(buf, "shield");
 +            break;
 +        }
 +        if(obj->otyp == SHIELD_OF_REFLECTION && !dknown) {
 +            Strcpy(buf, "smooth shield");
 +            break;
 +        }
 +
 +        if(nn)        Strcat(buf, actualn);
 +        else if(un) {
 +            if(is_boots(obj))
 +                Strcat(buf,"boots");
 +            else if(is_gloves(obj))
 +                Strcat(buf,"gloves");
 +            else if(is_cloak(obj))
 +                Strcpy(buf,"cloak");
 +            else if(is_helmet(obj))
 +                Strcpy(buf,"helmet");
 +            else if(is_shield(obj))
 +                Strcpy(buf,"shield");
 +            else
 +                Strcpy(buf,"armor");
 +            Strcat(buf, " called ");
 +            Strcat(buf, un);
 +        } else        Strcat(buf, dn);
 +        break;
 +        case FOOD_CLASS:
 +        if (typ == SLIME_MOLD) {
 +            register struct fruit *f;
 +
 +            for(f=ffruit; f; f = f->nextf) {
 +                if(f->fid == obj->spe) {
 +                    Strcpy(buf, f->fname);
 +                    break;
 +                }
 +            }
 +            if (!f) {
 +                impossible("Bad fruit #%d?", obj->spe);
 +                Strcpy(buf, "fruit");
 +            } else if (pluralize) {
 +                /* ick; already pluralized fruit names
 +                   are allowed--we want to try to avoid
 +                   adding a redundant plural suffix */
 +                Strcpy(buf, makeplural(makesingular(buf)));
 +                pluralize = FALSE;
 +            }
 +            break;
 +        }
 +        if (Is_pudding(obj)) {
 +            Sprintf(buf, "%s%s",
 +                        obj->owt < 100 ? "small " 
 +                          : obj->owt > 500 ? "very large "
 +                            : obj->owt > 300 ? "large "
 +                              : "", actualn);
 +            break;
 +        }
 +
 +        Strcpy(buf, actualn);
 +        if (typ == TIN && known)
 +            tin_details(obj, omndx, buf);
 +        break;
 +        case COIN_CLASS:
 +        case CHAIN_CLASS:
 +        Strcpy(buf, actualn);
 +        break;
 +        case ROCK_CLASS:
 +        if (typ == STATUE && omndx != NON_PM)
 +            Sprintf(buf, "%s%s of %s%s",
 +            (Role_if(PM_ARCHEOLOGIST) &&
 +                (obj->spe & STATUE_HISTORIC)) ? "historic " : "",
 +            actualn,
 +            type_is_pname(&mons[omndx]) ? "" :
 +              the_unique_pm(&mons[omndx]) ? "the " :
 +                index(vowels, *mons[omndx].mname) ? "an " : "a ",
 +            mons[omndx].mname);
 +        else Strcpy(buf, actualn);
 +        break;
 +        case BALL_CLASS:
 +        Sprintf(buf, "%sheavy iron ball",
 +            (obj->owt > ocl->oc_weight) ? "very " : "");
 +        break;
 +        case POTION_CLASS:
 +        if (dknown && obj->odiluted)
 +            Strcpy(buf, "diluted ");
 +        if(nn || un || !dknown) {
 +            Strcat(buf, "potion");
 +            if(!dknown) break;
 +            if(nn) {
 +                Strcat(buf, " of ");
 +                if (typ == POT_WATER &&
 +                bknown && (obj->blessed || obj->cursed)) {
 +                Strcat(buf, obj->blessed ? "holy " : "unholy ");
 +                }
 +                Strcat(buf, actualn);
 +            } else {
 +                Strcat(buf, " called ");
 +                Strcat(buf, un);
 +            }
 +        } else {
 +            Strcat(buf, dn);
 +            Strcat(buf, " potion");
 +        }
 +        break;
 +    case SCROLL_CLASS:
 +        Strcpy(buf, "scroll");
 +        if(!dknown) break;
 +        if(nn) {
 +            Strcat(buf, " of ");
 +            Strcat(buf, actualn);
 +        } else if(un) {
 +            Strcat(buf, " called ");
 +            Strcat(buf, un);
 +        } else if (ocl->oc_magic) {
 +            Strcat(buf, " labeled ");
 +            Strcat(buf, dn);
 +        } else {
 +            Strcpy(buf, dn);
 +            Strcat(buf, " scroll");
 +        }
 +        break;
 +    case WAND_CLASS:
 +        if(!dknown)
 +            Strcpy(buf, "wand");
 +        else if(nn)
 +            Sprintf(buf, "wand of %s", actualn);
 +        else if(un)
 +            Sprintf(buf, "wand called %s", un);
 +        else
 +            Sprintf(buf, "%s wand", dn);
 +        break;
 +    case SPBOOK_CLASS:
 +        if (!dknown) {
 +            Strcpy(buf, "spellbook");
 +        } else if (nn) {
 +            if (typ != SPE_BOOK_OF_THE_DEAD)
 +                Strcpy(buf, "spellbook of ");
 +            Strcat(buf, actualn);
 +        } else if (un) {
 +            Sprintf(buf, "spellbook called %s", un);
 +        } else
 +            Sprintf(buf, "%s spellbook", dn);
 +        break;
 +    case RING_CLASS:
 +        if(!dknown)
 +            Strcpy(buf, "ring");
 +        else if(nn)
 +            Sprintf(buf, "ring of %s", actualn);
 +        else if(un)
 +            Sprintf(buf, "ring called %s", un);
 +        else
 +            Sprintf(buf, "%s ring", dn);
 +        break;
 +    case GEM_CLASS:
 +        {
 +        const char *rock =
 +                (ocl->oc_material == MINERAL) ? "stone" : "gem";
 +        if (!dknown) {
 +            Strcpy(buf, rock);
 +        } else if (!nn) {
 +            if (un) Sprintf(buf,"%s called %s", rock, un);
 +            else Sprintf(buf, "%s %s", dn, rock);
 +        } else {
 +            Strcpy(buf, actualn);
 +            if (GemStone(typ)) Strcat(buf, " stone");
 +        }
 +        break;
 +        }
 +    default:
 +        Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe);
 +    }
 +    if (pluralize) Strcpy(buf, makeplural(buf));
  
 -      if (has_oname(obj) && dknown) {
 -              Strcat(buf, " named ");
+       if (obj->otyp == T_SHIRT && program_state.gameover) {
+           char tmpbuf[BUFSZ];
+           Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf));
+       }
 +    if (has_oname(obj) && dknown) {
 +        Strcat(buf, " named ");
  nameit:
 -              Strcat(buf, ONAME(obj));
 -      }
 +        Strcat(buf, ONAME(obj));
 +    }
  
 -      if (!strncmpi(buf, "the ", 4)) buf += 4;
 -      return(buf);
 +    if (!strncmpi(buf, "the ", 4)) buf += 4;
 +    return(buf);
  }
  
  /* similar to simple_typename but minimal_xname operates on a particular
@@@ -649,287 -646,293 +654,296 @@@ char 
  doname(obj)
  register struct obj *obj;
  {
 -      boolean ispoisoned = FALSE;
 -      boolean known, cknown, bknown, lknown;
 -      int omndx = obj->corpsenm;
 -      char prefix[PREFIX];
 -      char tmpbuf[PREFIX+1];
 -      /* when we have to add something at the start of prefix instead of the
 -       * end (Strcat is used on the end)
 -       */
 -      register char *bp = xname(obj);
 +    boolean ispoisoned = FALSE;
 +    boolean known, cknown, bknown, lknown;
 +    int omndx = obj->corpsenm;
 +    char prefix[PREFIX];
 +    char tmpbuf[PREFIX+1];
 +    /* when we have to add something at the start of prefix instead of the
 +     * end (Strcat is used on the end)
 +     */
 +    register char *bp = xname(obj);
  
-     if (iflags.override_ID) known = cknown = bknown = lknown = TRUE;
-     else {
+       if (iflags.override_ID) {
+               known = cknown = bknown = lknown = TRUE;
+       } else {
 -              known = obj->known;
 -              cknown = obj->cknown;
 -              bknown = obj->bknown;
 -              lknown = obj->lknown;
 -      }
 +        known = obj->known;
 +        cknown = obj->cknown;
 +        bknown = obj->bknown;
 +        lknown = obj->lknown;
 +    }
  
 -      /* When using xname, we want "poisoned arrow", and when using
 -       * doname, we want "poisoned +0 arrow".  This kludge is about the only
 -       * way to do it, at least until someone overhauls xname() and doname(),
 -       * combining both into one function taking a parameter.
 -       */
 -      /* must check opoisoned--someone can have a weirdly-named fruit */
 -      if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
 -              bp += 9;
 -              ispoisoned = TRUE;
 -      }
 +    /* When using xname, we want "poisoned arrow", and when using
 +     * doname, we want "poisoned +0 arrow".  This kludge is about the only
 +     * way to do it, at least until someone overhauls xname() and doname(),
 +     * combining both into one function taking a parameter.
 +     */
 +    /* must check opoisoned--someone can have a weirdly-named fruit */
 +    if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) {
 +        bp += 9;
 +        ispoisoned = TRUE;
 +    }
  
 -      if(obj->quan != 1L)
 -              Sprintf(prefix, "%ld ", obj->quan);
 -      else if (obj->otyp == CORPSE)
 -              /* skip article prefix for corpses [else corpse_xname()
 -                 would have to be taught how to strip it off again] */
 -              *prefix = '\0';
 -      else if (obj_is_pname(obj) || the_unique_obj(obj)) {
 -              if (!strncmpi(bp, "the ", 4))
 -                  bp += 4;
 -              Strcpy(prefix, "the ");
 -      } else
 -              Strcpy(prefix, "a ");
 -
 -      /* "empty" goes at the beginning, but item count goes at the end */
 -      if (cknown &&
 +    if(obj->quan != 1L)
 +        Sprintf(prefix, "%ld ", obj->quan);
 +    else if (obj->otyp == CORPSE)
 +        /* skip article prefix for corpses [else corpse_xname()
 +           would have to be taught how to strip it off again] */
 +        *prefix = '\0';
 +    else if (obj_is_pname(obj) || the_unique_obj(obj)) {
 +        if (!strncmpi(bp, "the ", 4))
 +            bp += 4;
 +        Strcpy(prefix, "the ");
 +    } else
 +        Strcpy(prefix, "a ");
 +
 +    /* "empty" goes at the beginning, but item count goes at the end */
 +    if (cknown &&
-         (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj))
+           /* bag of tricks: include "empty" prefix if it's known to
+              be empty but its precise number of charges isn't known
+              (when that is known, suffix of "(n:0)" will be appended,
+              making the prefix be redundant; note that 'known' flag
+              isn't set when emptiness gets discovered because then
+              charging magic would yield known number of new charges) */
+           (obj->otyp == BAG_OF_TRICKS ? (obj->spe == 0 && !obj->known) :
+            /* not bag of tricks: empty if container which has no contents */
+            (Is_container(obj) || obj->otyp == STATUE) && !Has_contents(obj)))
 -              Strcat(prefix, "empty ");
 -
 -      if (bknown &&
 -          obj->oclass != COIN_CLASS &&
 -          (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
 -              || (!obj->cursed && !obj->blessed))) {
 -          /* allow 'blessed clear potion' if we don't know it's holy water;
 -           * always allow "uncursed potion of water"
 -           */
 -          if (obj->cursed)
 -              Strcat(prefix, "cursed ");
 -          else if (obj->blessed)
 -              Strcat(prefix, "blessed ");
 -          else if ((!known || !objects[obj->otyp].oc_charged ||
 -                    (obj->oclass == ARMOR_CLASS ||
 -                     obj->oclass == RING_CLASS))
 -              /* For most items with charges or +/-, if you know how many
 -               * charges are left or what the +/- is, then you must have
 -               * totally identified the item, so "uncursed" is unneccesary,
 -               * because an identified object not described as "blessed" or
 -               * "cursed" must be uncursed.
 -               *
 -               * If the charges or +/- is not known, "uncursed" must be
 -               * printed to avoid ambiguity between an item whose curse
 -               * status is unknown, and an item known to be uncursed.
 -               */
 +        Strcat(prefix, "empty ");
 +
 +    if (bknown &&
 +        obj->oclass != COIN_CLASS &&
 +        (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known
 +        || (!obj->cursed && !obj->blessed))) {
 +        /* allow 'blessed clear potion' if we don't know it's holy water;
 +         * always allow "uncursed potion of water"
 +         */
 +        if (obj->cursed)
 +        Strcat(prefix, "cursed ");
 +        else if (obj->blessed)
 +        Strcat(prefix, "blessed ");
 +        else if ((!known || !objects[obj->otyp].oc_charged ||
 +              (obj->oclass == ARMOR_CLASS ||
 +               obj->oclass == RING_CLASS))
 +        /* For most items with charges or +/-, if you know how many
 +         * charges are left or what the +/- is, then you must have
 +         * totally identified the item, so "uncursed" is unneccesary,
 +         * because an identified object not described as "blessed" or
 +         * "cursed" must be uncursed.
 +         *
 +         * If the charges or +/- is not known, "uncursed" must be
 +         * printed to avoid ambiguity between an item whose curse
 +         * status is unknown, and an item known to be uncursed.
 +         */
  #ifdef MAIL
 -                      && obj->otyp != SCR_MAIL
 +            && obj->otyp != SCR_MAIL
  #endif
 -                      && obj->otyp != FAKE_AMULET_OF_YENDOR
 -                      && obj->otyp != AMULET_OF_YENDOR
 -                      && !Role_if(PM_PRIEST))
 -              Strcat(prefix, "uncursed ");
 -      }
 +            && obj->otyp != FAKE_AMULET_OF_YENDOR
 +            && obj->otyp != AMULET_OF_YENDOR
 +            && !Role_if(PM_PRIEST))
 +        Strcat(prefix, "uncursed ");
 +    }
  
 -      if (lknown && Is_box(obj)) {
 -          if (obj->obroken)
 -              Strcat(prefix, "unlockable ");
 -          else if (obj->olocked)
 -              Strcat(prefix, "locked ");
 -          else
 -              Strcat(prefix, "unlocked ");
 -      }
 +    if (lknown && Is_box(obj)) {
 +        if (obj->obroken)
 +            Strcat(prefix, "unlockable ");
 +        else if (obj->olocked)
 +        Strcat(prefix, "locked ");
 +        else
 +        Strcat(prefix, "unlocked ");
 +    }
  
 -      if (obj->greased) Strcat(prefix, "greased ");
 +    if (obj->greased) Strcat(prefix, "greased ");
  
 -      if (cknown && Has_contents(obj)) {
 -          /* we count all objects (obj->quantity); perhaps we should
 -             count seperate stacks instead (or even introduce a user
 -             preference option to choose between the two alternatives)
 -             since it's somewhat odd so see "containing 1002 items"
 -             when there are 2 scrolls plus 1000 gold pieces */
 -          long itemcount = count_contents(obj, FALSE, TRUE, TRUE);
 +    if (cknown && Has_contents(obj)) {
 +        /* we count all objects (obj->quantity); perhaps we should
 +           count seperate stacks instead (or even introduce a user
 +           preference option to choose between the two alternatives)
 +           since it's somewhat odd so see "containing 1002 items"
 +           when there are 2 scrolls plus 1000 gold pieces */
 +        long itemcount = count_contents(obj, FALSE, TRUE, TRUE);
  
 -          Sprintf(eos(bp), " containing %ld item%s",
 -                  itemcount, plur(itemcount));
 -      }
 +        Sprintf(eos(bp), " containing %ld item%s",
 +            itemcount, plur(itemcount));
 +    }
  
 -      switch(obj->oclass) {
 -      case AMULET_CLASS:
 -              if(obj->owornmask & W_AMUL)
 -                      Strcat(bp, " (being worn)");
 -              break;
 -      case WEAPON_CLASS:
 -              if(ispoisoned)
 -                      Strcat(prefix, "poisoned ");
 +    switch(obj->oclass) {
 +    case AMULET_CLASS:
 +        if(obj->owornmask & W_AMUL)
 +            Strcat(bp, " (being worn)");
 +        break;
 +    case WEAPON_CLASS:
 +        if(ispoisoned)
 +            Strcat(prefix, "poisoned ");
  plus:
 -              add_erosion_words(obj, prefix);
 -              if(known) {
 -                      Strcat(prefix, sitoa(obj->spe));
 -                      Strcat(prefix, " ");
 -              }
 -              break;
 -      case ARMOR_CLASS:
 -              if(obj->owornmask & W_ARMOR)
 -                      Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
 -                              " (being worn)");
 -              goto plus;
 -      case TOOL_CLASS:
 -              /* weptools already get this done when we go to the +n code */
 -              if (!is_weptool(obj))
 -                  add_erosion_words(obj, prefix);
 -              if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) {
 -                      Strcat(bp, " (being worn)");
 -                      break;
 -              }
 -              if (obj->otyp == LEASH && obj->leashmon != 0) {
 -                      Strcat(bp, " (in use)");
 -                      break;
 -              }
 -              if (is_weptool(obj))
 -                      goto plus;
 -              if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
 -                      if (!obj->spe)
 -                          Strcpy(tmpbuf, "no");
 -                      else
 -                          Sprintf(tmpbuf, "%d", obj->spe);
 -                      Sprintf(eos(bp), " (%s candle%s%s)",
 -                              tmpbuf, plur(obj->spe),
 -                              !obj->lamplit ? " attached" : ", lit");
 -                      break;
 -              } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
 -                      obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
 -                      if (Is_candle(obj) &&
 -                          obj->age < 20L * (long)objects[obj->otyp].oc_cost)
 -                              Strcat(prefix, "partly used ");
 -                      if(obj->lamplit)
 -                              Strcat(bp, " (lit)");
 -                      break;
 -              }
 -              if(objects[obj->otyp].oc_charged)
 -                  goto charges;
 -              break;
 -      case WAND_CLASS:
 -              add_erosion_words(obj, prefix);
 +        add_erosion_words(obj, prefix);
 +        if(known) {
 +            Strcat(prefix, sitoa(obj->spe));
 +            Strcat(prefix, " ");
 +        }
 +        break;
 +    case ARMOR_CLASS:
 +        if(obj->owornmask & W_ARMOR)
 +            Strcat(bp, (obj == uskin) ? " (embedded in your skin)" :
 +                " (being worn)");
 +        goto plus;
 +    case TOOL_CLASS:
 +        /* weptools already get this done when we go to the +n code */
 +        if (!is_weptool(obj))
 +            add_erosion_words(obj, prefix);
 +        if(obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) {
 +            Strcat(bp, " (being worn)");
 +            break;
 +        }
 +        if (obj->otyp == LEASH && obj->leashmon != 0) {
 +            Strcat(bp, " (in use)");
 +            break;
 +        }
 +        if (is_weptool(obj))
 +            goto plus;
 +        if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
 +            if (!obj->spe)
 +                Strcpy(tmpbuf, "no");
 +            else
 +                Sprintf(tmpbuf, "%d", obj->spe);
 +            Sprintf(eos(bp), " (%s candle%s%s)",
 +                tmpbuf, plur(obj->spe),
 +                !obj->lamplit ? " attached" : ", lit");
 +            break;
 +        } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP ||
 +            obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
 +            if (Is_candle(obj) &&
 +                obj->age < 20L * (long)objects[obj->otyp].oc_cost)
 +                Strcat(prefix, "partly used ");
 +            if(obj->lamplit)
 +                Strcat(bp, " (lit)");
 +            break;
 +        }
 +        if(objects[obj->otyp].oc_charged)
 +            goto charges;
 +        break;
 +    case WAND_CLASS:
 +        add_erosion_words(obj, prefix);
  charges:
 -              if(known)
 -                  Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
 -              break;
 -      case POTION_CLASS:
 -              if (obj->otyp == POT_OIL && obj->lamplit)
 -                  Strcat(bp, " (lit)");
 -              break;
 -      case RING_CLASS:
 -              add_erosion_words(obj, prefix);
 +        if(known)
 +            Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe);
 +        break;
 +    case POTION_CLASS:
 +        if (obj->otyp == POT_OIL && obj->lamplit)
 +            Strcat(bp, " (lit)");
 +        break;
 +    case RING_CLASS:
 +        add_erosion_words(obj, prefix);
  ring:
 -              if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
 -              if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
 -              if(obj->owornmask & W_RING) {
 -                  Strcat(bp, body_part(HAND));
 -                  Strcat(bp, ")");
 -              }
 -              if(known && objects[obj->otyp].oc_charged) {
 -                      Strcat(prefix, sitoa(obj->spe));
 -                      Strcat(prefix, " ");
 -              }
 -              break;
 -      case FOOD_CLASS:
 -              if (obj->oeaten)
 -                  Strcat(prefix, "partly eaten ");
 -              if (obj->otyp == CORPSE) {
 -                  Sprintf(prefix, "%s ",
 -                          corpse_xname(obj, prefix,
 -                                       CXN_ARTICLE|CXN_NOCORPSE));
 -              } else if (obj->otyp == EGG) {
 +        if(obj->owornmask & W_RINGR) Strcat(bp, " (on right ");
 +        if(obj->owornmask & W_RINGL) Strcat(bp, " (on left ");
 +        if(obj->owornmask & W_RING) {
 +            Strcat(bp, body_part(HAND));
 +            Strcat(bp, ")");
 +        }
 +        if(known && objects[obj->otyp].oc_charged) {
 +            Strcat(prefix, sitoa(obj->spe));
 +            Strcat(prefix, " ");
 +        }
 +        break;
 +    case FOOD_CLASS:
 +        if (obj->oeaten)
 +            Strcat(prefix, "partly eaten ");
 +        if (obj->otyp == CORPSE) {
 +            Sprintf(prefix, "%s ",
 +                corpse_xname(obj, prefix,
 +                     CXN_ARTICLE|CXN_NOCORPSE));
 +        } else if (obj->otyp == EGG) {
  #if 0 /* corpses don't tell if they're stale either */
 -                  if (known && stale_egg(obj))
 -                      Strcat(prefix, "stale ");
 +            if (known && stale_egg(obj))
 +            Strcat(prefix, "stale ");
  #endif
 -                  if (omndx >= LOW_PM && (known ||
 -                                  (mvitals[omndx].mvflags & MV_KNOWS_EGG))) {
 -                      Strcat(prefix, mons[omndx].mname);
 -                      Strcat(prefix, " ");
 -                      if (obj->spe)
 -                          Strcat(bp, " (laid by you)");
 -                  }
 -              }
 -              if (obj->otyp == MEAT_RING) goto ring;
 -              break;
 -      case BALL_CLASS:
 -      case CHAIN_CLASS:
 -              add_erosion_words(obj, prefix);
 -              if(obj->owornmask & W_BALL)
 -                      Strcat(bp, " (chained to you)");
 -                      break;
 -      }
 +            if (omndx >= LOW_PM && (known ||
 +                    (mvitals[omndx].mvflags & MV_KNOWS_EGG))) {
 +            Strcat(prefix, mons[omndx].mname);
 +            Strcat(prefix, " ");
 +            if (obj->spe)
 +                Strcat(bp, " (laid by you)");
 +            }
 +        }
 +        if (wizard) {
 +            Sprintf(eos(bp), " (%d aum)", obj->owt);
 +        }
 +        if (obj->otyp == MEAT_RING) goto ring;
 +        break;
 +    case BALL_CLASS:
 +    case CHAIN_CLASS:
 +        add_erosion_words(obj, prefix);
 +        if(obj->owornmask & W_BALL)
 +            Strcat(bp, " (chained to you)");
 +            break;
 +    }
  
 -      if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
 -              if (obj->quan != 1L) {
 -                      Strcat(bp, " (wielded)");
 -              } else {
 -                      const char *hand_s = body_part(HAND);
 +    if((obj->owornmask & W_WEP) && !mrg_to_wielded) {
 +        if (obj->quan != 1L) {
 +            Strcat(bp, " (wielded)");
 +        } else {
 +            const char *hand_s = body_part(HAND);
  
 -                      if (bimanual(obj)) hand_s = makeplural(hand_s);
 -                      Sprintf(eos(bp), " (weapon in %s)", hand_s);
 -              }
 -      }
 -      if(obj->owornmask & W_SWAPWEP) {
 -              if (u.twoweap)
 -                      Sprintf(eos(bp), " (wielded in other %s)",
 -                              body_part(HAND));
 -              else
 -                      Strcat(bp, " (alternate weapon; not wielded)");
 -      }
 -      if(obj->owornmask & W_QUIVER){
 -              switch(obj->oclass){
 -              case WEAPON_CLASS:
 -                      if(is_ammo(obj)){
 -                              if(objects[obj->otyp].oc_skill == -P_BOW){
 -                                              /* Ammo for a bow */
 -                                      Strcat(bp, " (in quiver)");
 -                                      break;
 -                              } else {
 -                                              /* Ammo not for a bow */
 -                                      Strcat(bp, " (in quiver pouch)");
 -                                      break;
 -                              }
 -                      } else {
 -                                      /* Weapons not considered ammo */
 -                              Strcat(bp, " (at the ready)");
 -                              break;
 -                      }
 -
 -                              /* Small things and ammo not for a bow */
 -              case RING_CLASS:
 -              case AMULET_CLASS:
 -              case WAND_CLASS:
 -              case COIN_CLASS:
 -              case GEM_CLASS:
 -                      Strcat(bp, " (in quiver pouch)");
 -                      break;
 -              default:        /* odd things */
 -                      Strcat(bp, " (at the ready)");
 -              }
 -      }
 -      if (!iflags.suppress_price && is_unpaid(obj)) {
 -              long quotedprice = unpaid_cost(obj, TRUE);
 +            if (bimanual(obj)) hand_s = makeplural(hand_s);
 +            Sprintf(eos(bp), " (weapon in %s)", hand_s);
 +        }
 +    }
 +    if(obj->owornmask & W_SWAPWEP) {
 +        if (u.twoweap)
 +            Sprintf(eos(bp), " (wielded in other %s)",
 +                body_part(HAND));
 +        else
 +            Strcat(bp, " (alternate weapon; not wielded)");
 +    }
 +    if(obj->owornmask & W_QUIVER){
 +        switch(obj->oclass){
 +        case WEAPON_CLASS:
 +            if(is_ammo(obj)){
 +                if(objects[obj->otyp].oc_skill == -P_BOW){
 +                        /* Ammo for a bow */
 +                    Strcat(bp, " (in quiver)");
 +                    break;
 +                } else {
 +                        /* Ammo not for a bow */
 +                    Strcat(bp, " (in quiver pouch)");
 +                    break;
 +                }
 +            } else {
 +                    /* Weapons not considered ammo */
 +                Strcat(bp, " (at the ready)");
 +                break;
 +            }
 +
 +                /* Small things and ammo not for a bow */
 +        case RING_CLASS:
 +        case AMULET_CLASS:
 +        case WAND_CLASS:
 +        case COIN_CLASS:
 +        case GEM_CLASS:
 +            Strcat(bp, " (in quiver pouch)");
 +            break;
 +        default:      /* odd things */
 +            Strcat(bp, " (at the ready)");
 +        }
 +    }
 +    if (!iflags.suppress_price && is_unpaid(obj)) {
 +        long quotedprice = unpaid_cost(obj, TRUE);
  
 -              Sprintf(eos(bp), " (%s, %ld %s)",
 -                      obj->unpaid ? "unpaid" : "contents",
 -                      quotedprice, currency(quotedprice));
 -      }
 -      if (!strncmp(prefix, "a ", 2) &&
 -                      index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
 -                      && (*(prefix+2) || (strncmp(bp, "uranium", 7)
 -                              && strncmp(bp, "unicorn", 7)
 -                              && strncmp(bp, "eucalyptus", 10)))) {
 -              Strcpy(tmpbuf, prefix);
 -              Strcpy(prefix, "an ");
 -              Strcpy(prefix+3, tmpbuf+2);
 -      }
 -      bp = strprepend(bp, prefix);
 -      return(bp);
 +        Sprintf(eos(bp), " (%s, %ld %s)",
 +            obj->unpaid ? "unpaid" : "contents",
 +            quotedprice, currency(quotedprice));
 +    }
 +    if (!strncmp(prefix, "a ", 2) &&
 +            index(vowels, *(prefix+2) ? *(prefix+2) : *bp)
 +            && (*(prefix+2) || (strncmp(bp, "uranium", 7)
 +                && strncmp(bp, "unicorn", 7)
 +                && strncmp(bp, "eucalyptus", 10)))) {
 +        Strcpy(tmpbuf, prefix);
 +        Strcpy(prefix, "an ");
 +        Strcpy(prefix+3, tmpbuf+2);
 +    }
 +    bp = strprepend(bp, prefix);
 +    return(bp);
  }
  
  /* used from invent.c */
diff --cc src/read.c
Simple merge