Source:NetHack 3.6.0/src/pickup.c

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

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

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

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

Top of file[edit]

  1.  /* NetHack 3.6	pickup.c	$NHDT-Date: 1445556881 2015/10/22 23:34:41 $  $NHDT-Branch: master $:$NHDT-Revision: 1.162 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  /*
  6.   *	Contains code for picking objects up, and container use.
  7.   */
  8.  
  9.  #include "hack.h"
  10.  
  11.  #define CONTAINED_SYM '>' /* from invent.c */
  12.  
  13.  STATIC_DCL void FDECL(simple_look, (struct obj *, BOOLEAN_P));
  14.  STATIC_DCL boolean
  15.  FDECL(query_classes, (char *, boolean *, boolean *, const char *,
  16.                        struct obj *, BOOLEAN_P, int *));
  17.  STATIC_DCL boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P));
  18.  STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
  19.  STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
  20.  STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
  21.  #if 0 /* not used */
  22.  STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
  23.  #endif
  24.  STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **));
  25.  STATIC_DCL int FDECL(count_categories, (struct obj *, int));
  26.  STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
  27.                                      BOOLEAN_P, int *, int *));
  28.  STATIC_DCL int FDECL(lift_object,
  29.                       (struct obj *, struct obj *, long *, BOOLEAN_P));
  30.  STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *, int));
  31.  STATIC_PTR int FDECL(in_container, (struct obj *));
  32.  STATIC_PTR int FDECL(out_container, (struct obj *));
  33.  STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *));
  34.  STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
  35.  STATIC_DCL void NDECL(explain_container_prompt);
  36.  STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
  37.  STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
  38.  STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P,
  39.                                         BOOLEAN_P, BOOLEAN_P));
  40.  STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
  41.  STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P));
  42.  STATIC_DCL boolean NDECL(reverse_loot);
  43.  STATIC_DCL boolean FDECL(mon_beside, (int, int));
  44.  STATIC_DCL int FDECL(do_loot_cont, (struct obj **));
  45.  STATIC_DCL void FDECL(tipcontainer, (struct obj *));
  46.  
  47.  /* define for query_objlist() and autopickup() */
  48.  #define FOLLOW(curr, flags) \
  49.      (((flags) &BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
  50.  
  51.  /*
  52.   *  How much the weight of the given container will change when the given
  53.   *  object is removed from it.  This calculation must match the one used
  54.   *  by weight() in mkobj.c.
  55.   */
  56.  #define DELTA_CWT(cont, obj)                                      \
  57.      ((cont)->cursed ? (obj)->owt * 2 : (cont)->blessed            \
  58.                                             ? ((obj)->owt + 3) / 4 \
  59.                                             : ((obj)->owt + 1) / 2)
  60.  #define GOLD_WT(n) (((n) + 50L) / 100L)
  61.  /* if you can figure this out, give yourself a hearty pat on the back... */
  62.  #define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
  63.  
  64.  /* A variable set in use_container(), to be used by the callback routines  */
  65.  /* in_container() and out_container() from askchain() and use_container(). */
  66.  /* Also used by menu_loot() and container_gone().			   */
  67.  static NEARDATA struct obj *current_container;
  68.  #define Icebox (current_container->otyp == ICE_BOX)
  69.  
  70.  static const char moderateloadmsg[] = "You have a little trouble lifting";
  71.  static const char nearloadmsg[] = "You have much trouble lifting";
  72.  static const char overloadmsg[] = "You have extreme difficulty lifting";
  73.  

simple_look[edit]

  1.  /* BUG: this lets you look at cockatrice corpses while blind without
  2.     touching them */
  3.  /* much simpler version of the look-here code; used by query_classes() */
  4.  STATIC_OVL void
  5.  simple_look(otmp, here)
  6.  struct obj *otmp; /* list of objects */
  7.  boolean here;     /* flag for type of obj list linkage */
  8.  {
  9.      /* Neither of the first two cases is expected to happen, since
  10.       * we're only called after multiple classes of objects have been
  11.       * detected, hence multiple objects must be present.
  12.       */
  13.      if (!otmp) {
  14.          impossible("simple_look(null)");
  15.      } else if (!(here ? otmp->nexthere : otmp->nobj)) {
  16.          pline1(doname(otmp));
  17.      } else {
  18.          winid tmpwin = create_nhwindow(NHW_MENU);
  19.          putstr(tmpwin, 0, "");
  20.          do {
  21.              putstr(tmpwin, 0, doname(otmp));
  22.              otmp = here ? otmp->nexthere : otmp->nobj;
  23.          } while (otmp);
  24.          display_nhwindow(tmpwin, TRUE);
  25.          destroy_nhwindow(tmpwin);
  26.      }
  27.  }
  28.  

collect_obj_classes[edit]

  1.  int
  2.  collect_obj_classes(ilets, otmp, here, filter, itemcount)
  3.  char ilets[];
  4.  register struct obj *otmp;
  5.  boolean here;
  6.  boolean FDECL((*filter), (OBJ_P));
  7.  int *itemcount;
  8.  {
  9.      register int iletct = 0;
  10.      register char c;
  11.  
  12.      *itemcount = 0;
  13.      ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
  14.      while (otmp) {
  15.          c = def_oc_syms[(int) otmp->oclass].sym;
  16.          if (!index(ilets, c) && (!filter || (*filter)(otmp)))
  17.              ilets[iletct++] = c, ilets[iletct] = '\0';
  18.          *itemcount += 1;
  19.          otmp = here ? otmp->nexthere : otmp->nobj;
  20.      }
  21.  
  22.      return iletct;
  23.  }
  24.  

query_classes[edit]

  1.  /*
  2.   * Suppose some '?' and '!' objects are present, but '/' objects aren't:
  3.   *	"a" picks all items without further prompting;
  4.   *	"A" steps through all items, asking one by one;
  5.   *	"?" steps through '?' items, asking, and ignores '!' ones;
  6.   *	"/" becomes 'A', since no '/' present;
  7.   *	"?a" or "a?" picks all '?' without further prompting;
  8.   *	"/a" or "a/" becomes 'A' since there aren't any '/'
  9.   *	    (bug fix:  3.1.0 thru 3.1.3 treated it as "a");
  10.   *	"?/a" or "a?/" or "/a?",&c picks all '?' even though no '/'
  11.   *	    (ie, treated as if it had just been "?a").
  12.   */
  13.  STATIC_OVL boolean
  14.  query_classes(oclasses, one_at_a_time, everything, action, objs, here,
  15.                menu_on_demand)
  16.  char oclasses[];
  17.  boolean *one_at_a_time, *everything;
  18.  const char *action;
  19.  struct obj *objs;
  20.  boolean here;
  21.  int *menu_on_demand;
  22.  {
  23.      char ilets[30], inbuf[BUFSZ]; /* FIXME: hardcoded ilets[] length */
  24.      int iletct, oclassct;
  25.      boolean not_everything;
  26.      char qbuf[QBUFSZ];
  27.      boolean m_seen;
  28.      int itemcount;
  29.  
  30.      oclasses[oclassct = 0] = '\0';
  31.      *one_at_a_time = *everything = m_seen = FALSE;
  32.      iletct = collect_obj_classes(ilets, objs, here,
  33.                                   (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
  34.      if (iletct == 0) {
  35.          return FALSE;
  36.      } else if (iletct == 1) {
  37.          oclasses[0] = def_char_to_objclass(ilets[0]);
  38.          oclasses[1] = '\0';
  39.          if (itemcount && menu_on_demand) {
  40.              ilets[iletct++] = 'm';
  41.              *menu_on_demand = 0;
  42.              ilets[iletct] = '\0';
  43.          }
  44.      } else { /* more than one choice available */
  45.          const char *where = 0;
  46.          register char sym, oc_of_sym, *p;
  47.          /* additional choices */
  48.          ilets[iletct++] = ' ';
  49.          ilets[iletct++] = 'a';
  50.          ilets[iletct++] = 'A';
  51.          ilets[iletct++] = (objs == invent ? 'i' : ':');
  52.          if (menu_on_demand) {
  53.              ilets[iletct++] = 'm';
  54.              *menu_on_demand = 0;
  55.          }
  56.          ilets[iletct] = '\0';
  57.      ask_again:
  58.          oclasses[oclassct = 0] = '\0';
  59.          *one_at_a_time = *everything = FALSE;
  60.          not_everything = FALSE;
  61.          Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", action,
  62.                  ilets);
  63.          getlin(qbuf, inbuf);
  64.          if (*inbuf == '\033')
  65.              return FALSE;
  66.  
  67.          for (p = inbuf; (sym = *p++);) {
  68.              /* new A function (selective all) added by GAN 01/09/87 */
  69.              if (sym == ' ')
  70.                  continue;
  71.              else if (sym == 'A')
  72.                  *one_at_a_time = TRUE;
  73.              else if (sym == 'a')
  74.                  *everything = TRUE;
  75.              else if (sym == ':') {
  76.                  simple_look(objs, here); /* dumb if objs==invent */
  77.                  /* if we just scanned the contents of a container
  78.                     then mark it as having known contents */
  79.                  if (objs->where == OBJ_CONTAINED)
  80.                      objs->ocontainer->cknown = 1;
  81.                  goto ask_again;
  82.              } else if (sym == 'i') {
  83.                  (void) display_inventory((char *) 0, TRUE);
  84.                  goto ask_again;
  85.              } else if (sym == 'm') {
  86.                  m_seen = TRUE;
  87.              } else {
  88.                  oc_of_sym = def_char_to_objclass(sym);
  89.                  if (index(ilets, sym)) {
  90.                      add_valid_menu_class(oc_of_sym);
  91.                      oclasses[oclassct++] = oc_of_sym;
  92.                      oclasses[oclassct] = '\0';
  93.                  } else {
  94.                      if (!where)
  95.                          where =
  96.                              !strcmp(action, "pick up")
  97.                                  ? "here"
  98.                                  : !strcmp(action, "take out") ? "inside" : "";
  99.                      if (*where)
  100.                          There("are no %c's %s.", sym, where);
  101.                      else
  102.                          You("have no %c's.", sym);
  103.                      not_everything = TRUE;
  104.                  }
  105.              }
  106.          }
  107.          if (m_seen && menu_on_demand) {
  108.              *menu_on_demand = (*everything || !oclassct) ? -2 : -3;
  109.              return FALSE;
  110.          }
  111.          if (!oclassct && (!*everything || not_everything)) {
  112.              /* didn't pick anything,
  113.                 or tried to pick something that's not present */
  114.              *one_at_a_time = TRUE; /* force 'A' */
  115.              *everything = FALSE;   /* inhibit 'a' */
  116.          }
  117.      }
  118.      return TRUE;
  119.  }
  120.  

fatal_corpse_mistake[edit]

  1.  /* check whether hero is bare-handedly touching a cockatrice corpse */
  2.  STATIC_OVL boolean
  3.  fatal_corpse_mistake(obj, remotely)
  4.  struct obj *obj;
  5.  boolean remotely;
  6.  {
  7.      if (uarmg || remotely || obj->otyp != CORPSE
  8.          || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance)
  9.          return FALSE;
  10.  
  11.      if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
  12.          display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */
  13.          return FALSE;
  14.      }
  15.  
  16.      pline("Touching %s is a fatal mistake.",
  17.            corpse_xname(obj, (const char *) 0, CXN_SINGULAR | CXN_ARTICLE));
  18.      instapetrify(killer_xname(obj));
  19.      return TRUE;
  20.  }
  21.  

rider_corpse_revival[edit]

  1.  /* attempting to manipulate a Rider's corpse triggers its revival */
  2.  boolean
  3.  rider_corpse_revival(obj, remotely)
  4.  struct obj *obj;
  5.  boolean remotely;
  6.  {
  7.      if (!obj || obj->otyp != CORPSE || !is_rider(&mons[obj->corpsenm]))
  8.          return FALSE;
  9.  
  10.      pline("At your %s, the corpse suddenly moves...",
  11.            remotely ? "attempted acquisition" : "touch");
  12.      (void) revive_corpse(obj);
  13.      exercise(A_WIS, FALSE);
  14.      return TRUE;
  15.  }
  16.  

check_here[edit]

  1.  /* look at the objects at our location, unless there are too many of them */
  2.  STATIC_OVL void
  3.  check_here(picked_some)
  4.  boolean picked_some;
  5.  {
  6.      register struct obj *obj;
  7.      register int ct = 0;
  8.  
  9.      /* count the objects here */
  10.      for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
  11.          if (obj != uchain)
  12.              ct++;
  13.      }
  14.  
  15.      /* If there are objects here, take a look. */
  16.      if (ct) {
  17.          if (context.run)
  18.              nomul(0);
  19.          flush_screen(1);
  20.          (void) look_here(ct, picked_some);
  21.      } else {
  22.          read_engr_at(u.ux, u.uy);
  23.      }
  24.  }
  25.  

n_or_more[edit]

  1.  /* Value set by query_objlist() for n_or_more(). */
  2.  static long val_for_n_or_more;
  3.  
  4.  /* query_objlist callback: return TRUE if obj's count is >= reference value */
  5.  STATIC_OVL boolean
  6.  n_or_more(obj)
  7.  struct obj *obj;
  8.  {
  9.      if (obj == uchain)
  10.          return FALSE;
  11.      return (boolean) (obj->quan >= val_for_n_or_more);
  12.  }
  13.  

add_valid_menu_class[edit]

  1.  /* list of valid menu classes for query_objlist() and allow_category callback
  2.     (with room for all object classes, 'u'npaid, BUCX, and terminator) */
  3.  static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1];
  4.  static boolean class_filter, bucx_filter, shop_filter;
  5.  
  6.  void
  7.  add_valid_menu_class(c)
  8.  int c;
  9.  {
  10.      static int vmc_count = 0;
  11.  
  12.      if (c == 0) { /* reset */
  13.          vmc_count = 0;
  14.          class_filter = bucx_filter = shop_filter = FALSE;
  15.      } else {
  16.          valid_menu_classes[vmc_count++] = (char) c;
  17.          /* categorize the new class */
  18.          switch (c) {
  19.          case 'B':
  20.          case 'U':
  21.          case 'C': /*FALLTHRU*/
  22.          case 'X':
  23.              bucx_filter = TRUE;
  24.              break;
  25.          case 'u':
  26.              shop_filter = TRUE;
  27.              break;
  28.          default:
  29.              class_filter = TRUE;
  30.              break;
  31.          }
  32.      }
  33.      valid_menu_classes[vmc_count] = '\0';
  34.  }
  35.  

all_but_uchain[edit]

  1.  /* query_objlist callback: return TRUE if not uchain */
  2.  STATIC_OVL boolean
  3.  all_but_uchain(obj)
  4.  struct obj *obj;
  5.  {
  6.      return (boolean) (obj != uchain);
  7.  }
  8.  

allow_all[edit]

  1.  /* query_objlist callback: return TRUE */
  2.  /*ARGUSED*/
  3.  boolean
  4.  allow_all(obj)
  5.  struct obj *obj UNUSED;
  6.  {
  7.      return TRUE;
  8.  }
  9.  

allow_category[edit]

  1.  boolean
  2.  allow_category(obj)
  3.  struct obj *obj;
  4.  {
  5.      /* unpaid and BUC checks don't apply to coins */
  6.      if (obj->oclass == COIN_CLASS)
  7.          return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE;
  8.  
  9.      if (Role_if(PM_PRIEST))
  10.          obj->bknown = TRUE;
  11.      /*
  12.       * There are three types of filters possible and the first and
  13.       * third can have more than one entry:
  14.       *  1) object class (armor, potion, &c);
  15.       *  2) unpaid shop item;
  16.       *  3) bless/curse state (blessed, uncursed, cursed, BUC-unknown).
  17.       * When only one type is present, the situation is simple:
  18.       * to be accepted, obj's status must match one of the entries.
  19.       * When more than one type is present, the obj will now only
  20.       * be accepted when it matches one entry of each type.
  21.       * So ?!B will accept blessed scrolls or potions, and [u will
  22.       * accept unpaid armor.  (In 3.4.3, an object was accepted by
  23.       * this filter if it met any entry of any type, so ?!B resulted
  24.       * in accepting all scrolls and potions regardless of bless/curse
  25.       * state plus all blessed non-scroll, non-potion objects.)
  26.       */
  27.      /* if class is expected but obj's class is not in the list, reject */
  28.      if (class_filter && !index(valid_menu_classes, obj->oclass))
  29.          return FALSE;
  30.      /* if unpaid is expected and obj isn't unpaid, reject (treat a container
  31.         holding any unpaid object as unpaid even if isn't unpaid itself) */
  32.      if (shop_filter && !obj->unpaid
  33.          && !(Has_contents(obj) && count_unpaid(obj->cobj) > 0))
  34.          return FALSE;
  35.      /* check for particular bless/curse state */
  36.      if (bucx_filter) {
  37.          /* first categorize this object's bless/curse state */
  38.          char bucx =
  39.              !obj->bknown ? 'X' : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U';
  40.  
  41.          /* if its category is not in the list, reject */
  42.          if (!index(valid_menu_classes, bucx))
  43.              return FALSE;
  44.      }
  45.      /* obj didn't fail any of the filter checks, so accept */
  46.      return TRUE;
  47.  }
  48.  

allow_cat_no_uchain[edit]

  1.  #if 0 /* not used */
  2.  /* query_objlist callback: return TRUE if valid category (class), no uchain */
  3.  STATIC_OVL boolean
  4.  allow_cat_no_uchain(obj)
  5.  struct obj *obj;
  6.  {
  7.      if (obj != uchain
  8.  	&& ((index(valid_menu_classes,'u') && obj->unpaid)
  9.              || index(valid_menu_classes, obj->oclass)))
  10.  	return TRUE;
  11.      else
  12.  	return FALSE;
  13.  }
  14.  #endif
  15.  

is_worn_by_type[edit]

  1.  /* query_objlist callback: return TRUE if valid class and worn */
  2.  boolean
  3.  is_worn_by_type(otmp)
  4.  register struct obj *otmp;
  5.  {
  6.      return (boolean) (!!(otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON))
  7.                        && index(valid_menu_classes, otmp->oclass) != 0);
  8.  }
  9.  

pickup[edit]

  1.  /*
  2.   * Have the hero pick things from the ground
  3.   * or a monster's inventory if swallowed.
  4.   *
  5.   * Arg what:
  6.   *	>0  autopickup
  7.   *	=0  interactive
  8.   *	<0  pickup count of something
  9.   *
  10.   * Returns 1 if tried to pick something up, whether
  11.   * or not it succeeded.
  12.   */
  13.  int
  14.  pickup(what)
  15.  int what; /* should be a long */
  16.  {
  17.      int i, n, res, count, n_tried = 0, n_picked = 0;
  18.      menu_item *pick_list = (menu_item *) 0;
  19.      boolean autopickup = what > 0;
  20.      struct obj *objchain;
  21.      int traverse_how;
  22.  
  23.      /* we might have arrived here while fainted or sleeping, via
  24.         random teleport or levitation timeout; if so, skip check_here
  25.         and read_engr_at in addition to bypassing autopickup itself
  26.         [probably ought to check whether hero is using a cockatrice
  27.         corpse for a pillow here... (also at initial faint/sleep)] */
  28.      if (autopickup && multi < 0 && unconscious())
  29.          return 0;
  30.  
  31.      if (what < 0) /* pick N of something */
  32.          count = -what;
  33.      else /* pick anything */
  34.          count = 0;
  35.  
  36.      if (!u.uswallow) {
  37.          struct trap *ttmp = t_at(u.ux, u.uy);
  38.          /* no auto-pick if no-pick move, nothing there, or in a pool */
  39.          if (autopickup && (context.nopick || !OBJ_AT(u.ux, u.uy)
  40.                             || (is_pool(u.ux, u.uy) && !Underwater)
  41.                             || is_lava(u.ux, u.uy))) {
  42.              read_engr_at(u.ux, u.uy);
  43.              return 0;
  44.          }
  45.  
  46.          /* no pickup if levitating & not on air or water level */
  47.          if (!can_reach_floor(TRUE)) {
  48.              if ((multi && !context.run) || (autopickup && !flags.pickup)
  49.                  || (ttmp && uteetering_at_seen_pit(ttmp)))
  50.                  read_engr_at(u.ux, u.uy);
  51.              return 0;
  52.          }
  53.          /* multi && !context.run means they are in the middle of some other
  54.           * action, or possibly paralyzed, sleeping, etc.... and they just
  55.           * teleported onto the object.  They shouldn't pick it up.
  56.           */
  57.          if ((multi && !context.run) || (autopickup && !flags.pickup)) {
  58.              check_here(FALSE);
  59.              return 0;
  60.          }
  61.          if (notake(youmonst.data)) {
  62.              if (!autopickup)
  63.                  You("are physically incapable of picking anything up.");
  64.              else
  65.                  check_here(FALSE);
  66.              return 0;
  67.          }
  68.  
  69.          /* if there's anything here, stop running */
  70.          if (OBJ_AT(u.ux, u.uy) && context.run && context.run != 8
  71.              && !context.nopick)
  72.              nomul(0);
  73.      }
  74.  
  75.      add_valid_menu_class(0); /* reset */
  76.      if (!u.uswallow) {
  77.          objchain = level.objects[u.ux][u.uy];
  78.          traverse_how = BY_NEXTHERE;
  79.      } else {
  80.          objchain = u.ustuck->minvent;
  81.          traverse_how = 0; /* nobj */
  82.      }
  83.      /*
  84.       * Start the actual pickup process.  This is split into two main
  85.       * sections, the newer menu and the older "traditional" methods.
  86.       * Automatic pickup has been split into its own menu-style routine
  87.       * to make things less confusing.
  88.       */
  89.      if (autopickup) {
  90.          n = autopick(objchain, traverse_how, &pick_list);
  91.          goto menu_pickup;
  92.      }
  93.  
  94.      if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
  95.          /* use menus exclusively */
  96.          if (count) { /* looking for N of something */
  97.              char buf[QBUFSZ];
  98.              Sprintf(buf, "Pick %d of what?", count);
  99.              val_for_n_or_more = count; /* set up callback selector */
  100.              n = query_objlist(buf, objchain, traverse_how | AUTOSELECT_SINGLE
  101.                                                   | INVORDER_SORT,
  102.                                &pick_list, PICK_ONE, n_or_more);
  103.              /* correct counts, if any given */
  104.              for (i = 0; i < n; i++)
  105.                  pick_list[i].count = count;
  106.          } else {
  107.              n = query_objlist("Pick up what?", objchain,
  108.                                traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT
  109.                                    | FEEL_COCKATRICE,
  110.                                &pick_list, PICK_ANY, all_but_uchain);
  111.          }
  112.      menu_pickup:
  113.          n_tried = n;
  114.          for (n_picked = i = 0; i < n; i++) {
  115.              res = pickup_object(pick_list[i].item.a_obj, pick_list[i].count,
  116.                                  FALSE);
  117.              if (res < 0)
  118.                  break; /* can't continue */
  119.              n_picked += res;
  120.          }
  121.          if (pick_list)
  122.              free((genericptr_t) pick_list);
  123.  
  124.      } else {
  125.          /* old style interface */
  126.          int ct = 0;
  127.          long lcount;
  128.          boolean all_of_a_type, selective;
  129.          char oclasses[MAXOCLASSES];
  130.          struct obj *obj, *obj2;
  131.  
  132.          oclasses[0] = '\0';   /* types to consider (empty for all) */
  133.          all_of_a_type = TRUE; /* take all of considered types */
  134.          selective = FALSE;    /* ask for each item */
  135.  
  136.          /* check for more than one object */
  137.          for (obj = objchain; obj;
  138.               obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
  139.              ct++;
  140.  
  141.          if (ct == 1 && count) {
  142.              /* if only one thing, then pick it */
  143.              obj = objchain;
  144.              lcount = min(obj->quan, (long) count);
  145.              n_tried++;
  146.              if (pickup_object(obj, lcount, FALSE) > 0)
  147.                  n_picked++; /* picked something */
  148.              goto end_query;
  149.  
  150.          } else if (ct >= 2) {
  151.              int via_menu = 0;
  152.  
  153.              There("are %s objects here.", (ct <= 10) ? "several" : "many");
  154.              if (!query_classes(oclasses, &selective, &all_of_a_type,
  155.                                 "pick up", objchain,
  156.                                 traverse_how == BY_NEXTHERE, &via_menu)) {
  157.                  if (!via_menu)
  158.                      return 0;
  159.                  n = query_objlist(
  160.                      "Pick up what?", objchain,
  161.                      traverse_how | (selective ? 0 : INVORDER_SORT),
  162.                      &pick_list, PICK_ANY,
  163.                      via_menu == -2 ? allow_all : allow_category);
  164.                  goto menu_pickup;
  165.              }
  166.          }
  167.  
  168.          for (obj = objchain; obj; obj = obj2) {
  169.              if (traverse_how == BY_NEXTHERE)
  170.                  obj2 = obj->nexthere; /* perhaps obj will be picked up */
  171.              else
  172.                  obj2 = obj->nobj;
  173.              lcount = -1L;
  174.  
  175.              if (!selective && oclasses[0] && !index(oclasses, obj->oclass))
  176.                  continue;
  177.  
  178.              if (!all_of_a_type) {
  179.                  char qbuf[BUFSZ];
  180.  
  181.                  (void) safe_qbuf(qbuf, "Pick up ", "?", obj, doname,
  182.                                   ansimpleoname, something);
  183.                  switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
  184.                  case 'q':
  185.                      goto end_query; /* out 2 levels */
  186.                  case 'n':
  187.                      continue;
  188.                  case 'a':
  189.                      all_of_a_type = TRUE;
  190.                      if (selective) {
  191.                          selective = FALSE;
  192.                          oclasses[0] = obj->oclass;
  193.                          oclasses[1] = '\0';
  194.                      }
  195.                      break;
  196.                  case '#': /* count was entered */
  197.                      if (!yn_number)
  198.                          continue; /* 0 count => No */
  199.                      lcount = (long) yn_number;
  200.                      if (lcount > obj->quan)
  201.                          lcount = obj->quan;
  202.                  /* fall thru */
  203.                  default: /* 'y' */
  204.                      break;
  205.                  }
  206.              }
  207.              if (lcount == -1L)
  208.                  lcount = obj->quan;
  209.  
  210.              n_tried++;
  211.              if ((res = pickup_object(obj, lcount, FALSE)) < 0)
  212.                  break;
  213.              n_picked += res;
  214.          }
  215.      end_query:
  216.          ; /* semicolon needed by brain-damaged compilers */
  217.      }
  218.  
  219.      if (!u.uswallow) {
  220.          if (hides_under(youmonst.data))
  221.              (void) hideunder(&youmonst);
  222.  
  223.          /* position may need updating (invisible hero) */
  224.          if (n_picked)
  225.              newsym(u.ux, u.uy);
  226.  
  227.          /* check if there's anything else here after auto-pickup is done */
  228.          if (autopickup)
  229.              check_here(n_picked > 0);
  230.      }
  231.      return (n_tried > 0);
  232.  }
  233.  

is_autopickup_exception[edit]

  1.  boolean
  2.  is_autopickup_exception(obj, grab)
  3.  struct obj *obj;
  4.  boolean grab; /* forced pickup, rather than forced leave behind? */
  5.  {
  6.      /*
  7.       *  Does the text description of this match an exception?
  8.       */
  9.      char *objdesc = makesingular(doname(obj));
  10.      struct autopickup_exception *ape =
  11.          (grab) ? iflags.autopickup_exceptions[AP_GRAB]
  12.                 : iflags.autopickup_exceptions[AP_LEAVE];
  13.      while (ape) {
  14.          if (regex_match(objdesc, ape->regex))
  15.              return TRUE;
  16.          ape = ape->next;
  17.      }
  18.      return FALSE;
  19.  }
  20.  

autopick[edit]

  1.  /*
  2.   * Pick from the given list using flags.pickup_types.  Return the number
  3.   * of items picked (not counts).  Create an array that returns pointers
  4.   * and counts of the items to be picked up.  If the number of items
  5.   * picked is zero, the pickup list is left alone.  The caller of this
  6.   * function must free the pickup list.
  7.   */
  8.  STATIC_OVL int
  9.  autopick(olist, follow, pick_list)
  10.  struct obj *olist;     /* the object list */
  11.  int follow;            /* how to follow the object list */
  12.  menu_item **pick_list; /* list of objects and counts to pick up */
  13.  {
  14.      menu_item *pi; /* pick item */
  15.      struct obj *curr;
  16.      int n;
  17.      boolean pickit;
  18.      const char *otypes = flags.pickup_types;
  19.  
  20.      /* first count the number of eligible items */
  21.      for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
  22.          pickit = (!*otypes || index(otypes, curr->oclass));
  23.          /* check for "always pick up */
  24.          if (!pickit)
  25.              pickit = is_autopickup_exception(curr, TRUE);
  26.          /* then for "never pick up */
  27.          if (pickit)
  28.              pickit = !is_autopickup_exception(curr, FALSE);
  29.          /* pickup_thrown overrides pickup_types and exceptions */
  30.          if (!pickit)
  31.              pickit = (flags.pickup_thrown && curr->was_thrown);
  32.          /* finally, do we count this object? */
  33.          if (pickit)
  34.              ++n;
  35.      }
  36.  
  37.      if (n) {
  38.          *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n);
  39.          for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
  40.              pickit = (!*otypes || index(otypes, curr->oclass));
  41.              if (!pickit)
  42.                  pickit = is_autopickup_exception(curr, TRUE);
  43.              if (pickit)
  44.                  pickit = !is_autopickup_exception(curr, FALSE);
  45.              if (!pickit)
  46.                  pickit = (flags.pickup_thrown && curr->was_thrown);
  47.              if (pickit) {
  48.                  pi[n].item.a_obj = curr;
  49.                  pi[n].count = curr->quan;
  50.                  n++;
  51.              }
  52.          }
  53.      }
  54.      return n;
  55.  }
  56.  

query_objlist[edit]

  1.  /*
  2.   * Put up a menu using the given object list.  Only those objects on the
  3.   * list that meet the approval of the allow function are displayed.  Return
  4.   * a count of the number of items selected, as well as an allocated array of
  5.   * menu_items, containing pointers to the objects selected and counts.  The
  6.   * returned counts are guaranteed to be in bounds and non-zero.
  7.   *
  8.   * Query flags:
  9.   *	BY_NEXTHERE	  - Follow object list via nexthere instead of nobj.
  10.   *	AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just
  11.   *			    use it.
  12.   *	USE_INVLET	  - Use object's invlet.
  13.   *	INVORDER_SORT	  - Use hero's pack order.
  14.   *	INCLUDE_HERO	  - Showing engulfer's invent; show hero too.
  15.   *	SIGNAL_NOMENU	  - Return -1 rather than 0 if nothing passes "allow".
  16.   *	SIGNAL_ESCAPE	  - Return -1 rather than 0 if player uses ESC to
  17.   *			    pick nothing.
  18.   */
  19.  int
  20.  query_objlist(qstr, olist, qflags, pick_list, how, allow)
  21.  const char *qstr;                 /* query string */
  22.  struct obj *olist;                /* the list to pick from */
  23.  int qflags;                       /* options to control the query */
  24.  menu_item **pick_list;            /* return list of items picked */
  25.  int how;                          /* type of query */
  26.  boolean FDECL((*allow), (OBJ_P)); /* allow function */
  27.  {
  28.      int i, n, actualn;
  29.      winid win;
  30.      struct obj *curr, *last, fake_hero_object;
  31.      struct obj **oarray;
  32.      char *pack;
  33.      anything any;
  34.      boolean printed_type_name, sorted = (qflags & INVORDER_SORT) != 0,
  35.                                 engulfer = (qflags & INCLUDE_HERO) != 0;
  36.  
  37.      *pick_list = (menu_item *) 0;
  38.      if (!olist && !engulfer)
  39.          return 0;
  40.  
  41.      /* count the number of items allowed */
  42.      for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags))
  43.          if ((*allow)(curr)) {
  44.              last = curr;
  45.              n++;
  46.          }
  47.      actualn = n;
  48.      if (engulfer) {
  49.          ++n;
  50.          /* don't autoselect swallowed hero if it's the only choice */
  51.          qflags &= ~AUTOSELECT_SINGLE;
  52.      }
  53.  
  54.      if (n == 0) /* nothing to pick here */
  55.          return (qflags & SIGNAL_NOMENU) ? -1 : 0;
  56.  
  57.      if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
  58.          *pick_list = (menu_item *) alloc(sizeof(menu_item));
  59.          (*pick_list)->item.a_obj = last;
  60.          (*pick_list)->count = last->quan;
  61.          return 1;
  62.      }
  63.  
  64.      oarray = objarr_init(actualn);
  65.      /* Add objects to the array */
  66.      i = 0;
  67.      for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
  68.          if ((*allow)(curr)) {
  69.              objarr_set(curr, i++, oarray, (flags.sortloot == 'f'
  70.                                             || (flags.sortloot == 'l'
  71.                                                 && !(qflags & USE_INVLET))));
  72.          }
  73.      }
  74.  
  75.      win = create_nhwindow(NHW_MENU);
  76.      start_menu(win);
  77.      any = zeroany;
  78.  
  79.      /*
  80.       * Run through the list and add the objects to the menu.  If
  81.       * INVORDER_SORT is set, we'll run through the list once for
  82.       * each type so we can group them.  The allow function will only
  83.       * be called once per object in the list.
  84.       */
  85.      pack = flags.inv_order;
  86.      do {
  87.          printed_type_name = FALSE;
  88.          for (i = 0; i < actualn; i++) {
  89.              curr = oarray[i];
  90.              if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
  91.                  && will_feel_cockatrice(curr, FALSE)) {
  92.                  destroy_nhwindow(win); /* stop the menu and revert */
  93.                  (void) look_here(0, FALSE);
  94.                  return 0;
  95.              }
  96.              if ((!sorted || curr->oclass == *pack) && (*allow)(curr)) {
  97.                  /* if sorting, print type name (once only) */
  98.                  if (sorted && !printed_type_name) {
  99.                      any = zeroany;
  100.                      add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  101.                               let_to_name(*pack, FALSE,
  102.                                           (how != PICK_NONE)
  103.                                               && iflags.menu_head_objsym),
  104.                               MENU_UNSELECTED);
  105.                      printed_type_name = TRUE;
  106.                  }
  107.  
  108.                  any.a_obj = curr;
  109.                  add_menu(win, obj_to_glyph(curr), &any,
  110.                           (qflags & USE_INVLET) ? curr->invlet : 0,
  111.                           def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
  112.                           ATR_NONE, doname_with_price(curr), MENU_UNSELECTED);
  113.              }
  114.          }
  115.          pack++;
  116.      } while (sorted && *pack);
  117.      free(oarray);
  118.  
  119.      if (engulfer) {
  120.          char buf[BUFSZ];
  121.  
  122.          any = zeroany;
  123.          if (sorted && n > 1) {
  124.              Sprintf(buf, "%s Creatures",
  125.                      is_animal(u.ustuck->data) ? "Swallowed" : "Engulfed");
  126.              add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf,
  127.                       MENU_UNSELECTED);
  128.          }
  129.          fake_hero_object = zeroobj;
  130.          fake_hero_object.quan = 1L; /* not strictly necessary... */
  131.          any.a_obj = &fake_hero_object;
  132.          add_menu(win, mon_to_glyph(&youmonst), &any,
  133.                   /* fake inventory letter, no group accelerator */
  134.                   CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)),
  135.                   MENU_UNSELECTED);
  136.      }
  137.  
  138.      end_menu(win, qstr);
  139.      n = select_menu(win, how, pick_list);
  140.      destroy_nhwindow(win);
  141.  
  142.      if (n > 0) {
  143.          menu_item *mi;
  144.          int k;
  145.  
  146.          /* fix up counts:  -1 means no count used => pick all;
  147.             if fake_hero_object was picked, discard that choice */
  148.          for (i = k = 0, mi = *pick_list; i < n; i++, mi++) {
  149.              if (mi->item.a_obj == &fake_hero_object)
  150.                  continue;
  151.              if (mi->count == -1L || mi->count > mi->item.a_obj->quan)
  152.                  mi->count = mi->item.a_obj->quan;
  153.              if (k < i)
  154.                  (*pick_list)[k] = *mi;
  155.              ++k;
  156.          }
  157.          if (!k) {
  158.              /* fake_hero was only choice so discard whole list */
  159.              free((genericptr_t) *pick_list);
  160.              *pick_list = 0;
  161.              n = 0;
  162.          } else if (k < n) {
  163.              /* other stuff plus fake_hero; last slot is now unused */
  164.              (*pick_list)[k].item = zeroany;
  165.              (*pick_list)[k].count = 0L;
  166.              n = k;
  167.          }
  168.      } else if (n < 0) {
  169.          /* -1 is used for SIGNAL_NOMENU, so callers don't expect it
  170.             to indicate that the player declined to make a choice */
  171.          n = (qflags & SIGNAL_ESCAPE) ? -2 : 0;
  172.      }
  173.      return n;
  174.  }
  175.  

query_category[edit]

  1.  /*
  2.   * allow menu-based category (class) selection (for Drop,take off etc.)
  3.   *
  4.   */
  5.  int
  6.  query_category(qstr, olist, qflags, pick_list, how)
  7.  const char *qstr;      /* query string */
  8.  struct obj *olist;     /* the list to pick from */
  9.  int qflags;            /* behaviour modification flags */
  10.  menu_item **pick_list; /* return list of items picked */
  11.  int how;               /* type of query */
  12.  {
  13.      int n;
  14.      winid win;
  15.      struct obj *curr;
  16.      char *pack;
  17.      anything any;
  18.      boolean collected_type_name;
  19.      char invlet;
  20.      int ccount;
  21.      boolean do_unpaid = FALSE;
  22.      boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE,
  23.              do_buc_unknown = FALSE;
  24.      int num_buc_types = 0;
  25.  
  26.      *pick_list = (menu_item *) 0;
  27.      if (!olist)
  28.          return 0;
  29.      if ((qflags & UNPAID_TYPES) && count_unpaid(olist))
  30.          do_unpaid = TRUE;
  31.      if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) {
  32.          do_blessed = TRUE;
  33.          num_buc_types++;
  34.      }
  35.      if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) {
  36.          do_cursed = TRUE;
  37.          num_buc_types++;
  38.      }
  39.      if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) {
  40.          do_uncursed = TRUE;
  41.          num_buc_types++;
  42.      }
  43.      if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) {
  44.          do_buc_unknown = TRUE;
  45.          num_buc_types++;
  46.      }
  47.  
  48.      ccount = count_categories(olist, qflags);
  49.      /* no point in actually showing a menu for a single category */
  50.      if (ccount == 1 && !do_unpaid && num_buc_types <= 1
  51.          && !(qflags & BILLED_TYPES)) {
  52.          for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
  53.              if ((qflags & WORN_TYPES)
  54.                  && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
  55.                  continue;
  56.              break;
  57.          }
  58.          if (curr) {
  59.              *pick_list = (menu_item *) alloc(sizeof(menu_item));
  60.              (*pick_list)->item.a_int = curr->oclass;
  61.              return 1;
  62.          } else {
  63.              debugpline0("query_category: no single object match");
  64.          }
  65.          return 0;
  66.      }
  67.  
  68.      win = create_nhwindow(NHW_MENU);
  69.      start_menu(win);
  70.      pack = flags.inv_order;
  71.      if ((qflags & ALL_TYPES) && (ccount > 1)) {
  72.          invlet = 'a';
  73.          any = zeroany;
  74.          any.a_int = ALL_TYPES_SELECTED;
  75.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  76.                   (qflags & WORN_TYPES) ? "All worn types" : "All types",
  77.                   MENU_UNSELECTED);
  78.          invlet = 'b';
  79.      } else
  80.          invlet = 'a';
  81.      do {
  82.          collected_type_name = FALSE;
  83.          for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
  84.              if (curr->oclass == *pack) {
  85.                  if ((qflags & WORN_TYPES)
  86.                      && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
  87.                      continue;
  88.                  if (!collected_type_name) {
  89.                      any = zeroany;
  90.                      any.a_int = curr->oclass;
  91.                      add_menu(
  92.                          win, NO_GLYPH, &any, invlet++,
  93.                          def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
  94.                          ATR_NONE, let_to_name(*pack, FALSE,
  95.                                                (how != PICK_NONE)
  96.                                                    && iflags.menu_head_objsym),
  97.                          MENU_UNSELECTED);
  98.                      collected_type_name = TRUE;
  99.                  }
  100.              }
  101.          }
  102.          pack++;
  103.          if (invlet >= 'u') {
  104.              impossible("query_category: too many categories");
  105.              return 0;
  106.          }
  107.      } while (*pack);
  108.      /* unpaid items if there are any */
  109.      if (do_unpaid) {
  110.          invlet = 'u';
  111.          any = zeroany;
  112.          any.a_int = 'u';
  113.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items",
  114.                   MENU_UNSELECTED);
  115.      }
  116.      /* billed items: checked by caller, so always include if BILLED_TYPES */
  117.      if (qflags & BILLED_TYPES) {
  118.          invlet = 'x';
  119.          any = zeroany;
  120.          any.a_int = 'x';
  121.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  122.                   "Unpaid items already used up", MENU_UNSELECTED);
  123.      }
  124.      if (qflags & CHOOSE_ALL) {
  125.          invlet = 'A';
  126.          any = zeroany;
  127.          any.a_int = 'A';
  128.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  129.                   (qflags & WORN_TYPES) ? "Auto-select every item being worn"
  130.                                         : "Auto-select every item",
  131.                   MENU_UNSELECTED);
  132.      }
  133.      /* items with b/u/c/unknown if there are any */
  134.      if (do_blessed) {
  135.          invlet = 'B';
  136.          any = zeroany;
  137.          any.a_int = 'B';
  138.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  139.                   "Items known to be Blessed", MENU_UNSELECTED);
  140.      }
  141.      if (do_cursed) {
  142.          invlet = 'C';
  143.          any = zeroany;
  144.          any.a_int = 'C';
  145.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  146.                   "Items known to be Cursed", MENU_UNSELECTED);
  147.      }
  148.      if (do_uncursed) {
  149.          invlet = 'U';
  150.          any = zeroany;
  151.          any.a_int = 'U';
  152.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  153.                   "Items known to be Uncursed", MENU_UNSELECTED);
  154.      }
  155.      if (do_buc_unknown) {
  156.          invlet = 'X';
  157.          any = zeroany;
  158.          any.a_int = 'X';
  159.          add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE,
  160.                   "Items of unknown B/C/U status", MENU_UNSELECTED);
  161.      }
  162.      end_menu(win, qstr);
  163.      n = select_menu(win, how, pick_list);
  164.      destroy_nhwindow(win);
  165.      if (n < 0)
  166.          n = 0; /* caller's don't expect -1 */
  167.      return n;
  168.  }
  169.  

count_categories[edit]

  1.  STATIC_OVL int
  2.  count_categories(olist, qflags)
  3.  struct obj *olist;
  4.  int qflags;
  5.  {
  6.      char *pack;
  7.      boolean counted_category;
  8.      int ccount = 0;
  9.      struct obj *curr;
  10.  
  11.      pack = flags.inv_order;
  12.      do {
  13.          counted_category = FALSE;
  14.          for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
  15.              if (curr->oclass == *pack) {
  16.                  if ((qflags & WORN_TYPES)
  17.                      && !(curr->owornmask & (W_ARMOR | W_ACCESSORY | W_WEAPON)))
  18.                      continue;
  19.                  if (!counted_category) {
  20.                      ccount++;
  21.                      counted_category = TRUE;
  22.                  }
  23.              }
  24.          }
  25.          pack++;
  26.      } while (*pack);
  27.      return ccount;
  28.  }
  29.  

carry_count[edit]

  1.  /* could we carry `obj'? if not, could we carry some of it/them? */
  2.  STATIC_OVL long
  3.  carry_count(obj, container, count, telekinesis, wt_before, wt_after)
  4.  struct obj *obj, *container; /* object to pick up, bag it's coming out of */
  5.  long count;
  6.  boolean telekinesis;
  7.  int *wt_before, *wt_after;
  8.  {
  9.      boolean adjust_wt = container && carried(container),
  10.              is_gold = obj->oclass == COIN_CLASS;
  11.      int wt, iw, ow, oow;
  12.      long qq, savequan, umoney;
  13.      unsigned saveowt;
  14.      const char *verb, *prefx1, *prefx2, *suffx;
  15.      char obj_nambuf[BUFSZ], where[BUFSZ];
  16.  
  17.      savequan = obj->quan;
  18.      saveowt = obj->owt;
  19.      umoney = money_cnt(invent);
  20.      iw = max_capacity();
  21.  
  22.      if (count != savequan) {
  23.          obj->quan = count;
  24.          obj->owt = (unsigned) weight(obj);
  25.      }
  26.      wt = iw + (int) obj->owt;
  27.      if (adjust_wt)
  28.          wt -= (container->otyp == BAG_OF_HOLDING)
  29.                    ? (int) DELTA_CWT(container, obj)
  30.                    : (int) obj->owt;
  31.      /* This will go with silver+copper & new gold weight */
  32.      if (is_gold) /* merged gold might affect cumulative weight */
  33.          wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count));
  34.      if (count != savequan) {
  35.          obj->quan = savequan;
  36.          obj->owt = saveowt;
  37.      }
  38.      *wt_before = iw;
  39.      *wt_after = wt;
  40.  
  41.      if (wt < 0)
  42.          return count;
  43.  
  44.      /* see how many we can lift */
  45.      if (is_gold) {
  46.          iw -= (int) GOLD_WT(umoney);
  47.          if (!adjust_wt) {
  48.              qq = GOLD_CAPACITY((long) iw, umoney);
  49.          } else {
  50.              oow = 0;
  51.              qq = 50L - (umoney % 100L) - 1L;
  52.              if (qq < 0L)
  53.                  qq += 100L;
  54.              for (; qq <= count; qq += 100L) {
  55.                  obj->quan = qq;
  56.                  obj->owt = (unsigned) GOLD_WT(qq);
  57.                  ow = (int) GOLD_WT(umoney + qq);
  58.                  ow -= (container->otyp == BAG_OF_HOLDING)
  59.                            ? (int) DELTA_CWT(container, obj)
  60.                            : (int) obj->owt;
  61.                  if (iw + ow >= 0)
  62.                      break;
  63.                  oow = ow;
  64.              }
  65.              iw -= oow;
  66.              qq -= 100L;
  67.          }
  68.          if (qq < 0L)
  69.              qq = 0L;
  70.          else if (qq > count)
  71.              qq = count;
  72.          wt = iw + (int) GOLD_WT(umoney + qq);
  73.      } else if (count > 1 || count < obj->quan) {
  74.          /*
  75.           * Ugh. Calc num to lift by changing the quan of of the
  76.           * object and calling weight.
  77.           *
  78.           * This works for containers only because containers
  79.           * don't merge.		-dean
  80.           */
  81.          for (qq = 1L; qq <= count; qq++) {
  82.              obj->quan = qq;
  83.              obj->owt = (unsigned) (ow = weight(obj));
  84.              if (adjust_wt)
  85.                  ow -= (container->otyp == BAG_OF_HOLDING)
  86.                            ? (int) DELTA_CWT(container, obj)
  87.                            : (int) obj->owt;
  88.              if (iw + ow >= 0)
  89.                  break;
  90.              wt = iw + ow;
  91.          }
  92.          --qq;
  93.      } else {
  94.          /* there's only one, and we can't lift it */
  95.          qq = 0L;
  96.      }
  97.      obj->quan = savequan;
  98.      obj->owt = saveowt;
  99.  
  100.      if (qq < count) {
  101.          /* some message will be given */
  102.          Strcpy(obj_nambuf, doname(obj));
  103.          if (container) {
  104.              Sprintf(where, "in %s", the(xname(container)));
  105.              verb = "carry";
  106.          } else {
  107.              Strcpy(where, "lying here");
  108.              verb = telekinesis ? "acquire" : "lift";
  109.          }
  110.      } else {
  111.          /* lint suppression */
  112.          *obj_nambuf = *where = '\0';
  113.          verb = "";
  114.      }
  115.      /* we can carry qq of them */
  116.      if (qq > 0) {
  117.          if (qq < count)
  118.              You("can only %s %s of the %s %s.", verb,
  119.                  (qq == 1L) ? "one" : "some", obj_nambuf, where);
  120.          *wt_after = wt;
  121.          return qq;
  122.      }
  123.  
  124.      if (!container)
  125.          Strcpy(where, "here"); /* slightly shorter form */
  126.      if (invent || umoney) {
  127.          prefx1 = "you cannot ";
  128.          prefx2 = "";
  129.          suffx = " any more";
  130.      } else {
  131.          prefx1 = (obj->quan == 1L) ? "it " : "even one ";
  132.          prefx2 = "is too heavy for you to ";
  133.          suffx = "";
  134.      }
  135.      There("%s %s %s, but %s%s%s%s.", otense(obj, "are"), obj_nambuf, where,
  136.            prefx1, prefx2, verb, suffx);
  137.  
  138.      /* *wt_after = iw; */
  139.      return 0L;
  140.  }
  141.  

lift_object[edit]

  1.  /* determine whether character is able and player is willing to carry `obj' */
  2.  STATIC_OVL
  3.  int
  4.  lift_object(obj, container, cnt_p, telekinesis)
  5.  struct obj *obj, *container; /* object to pick up, bag it's coming out of */
  6.  long *cnt_p;
  7.  boolean telekinesis;
  8.  {
  9.      int result, old_wt, new_wt, prev_encumbr, next_encumbr;
  10.  
  11.      if (obj->otyp == BOULDER && Sokoban) {
  12.          You("cannot get your %s around this %s.", body_part(HAND),
  13.              xname(obj));
  14.          return -1;
  15.      }
  16.      /* override weight consideration for loadstone picked up by anybody
  17.         and for boulder picked up by hero poly'd into a giant; override
  18.         availability of open inventory slot iff not already carrying one */
  19.      if (obj->otyp == LOADSTONE
  20.          || (obj->otyp == BOULDER && throws_rocks(youmonst.data))) {
  21.          if (inv_cnt(FALSE) < 52 || !carrying(obj->otyp)
  22.              || merge_choice(invent, obj))
  23.              return 1; /* lift regardless of current situation */
  24.          /* if we reach here, we're out of slots and already have at least
  25.             one of these, so treat this one more like a normal item */
  26.          You("are carrying too much stuff to pick up %s %s.",
  27.              (obj->quan == 1L) ? "another" : "more", simpleonames(obj));
  28.          return -1;
  29.      }
  30.  
  31.      *cnt_p =
  32.          carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt);
  33.      if (*cnt_p < 1L) {
  34.          result = -1; /* nothing lifted */
  35.      } else if (obj->oclass != COIN_CLASS
  36.                 /* [exception for gold coins will have to change
  37.                     if silver/copper ones ever get implemented] */
  38.                 && inv_cnt(FALSE) >= 52 && !merge_choice(invent, obj)) {
  39.          Your("knapsack cannot accommodate any more items.");
  40.          result = -1; /* nothing lifted */
  41.      } else {
  42.          result = 1;
  43.          prev_encumbr = near_capacity();
  44.          if (prev_encumbr < flags.pickup_burden)
  45.              prev_encumbr = flags.pickup_burden;
  46.          next_encumbr = calc_capacity(new_wt - old_wt);
  47.          if (next_encumbr > prev_encumbr) {
  48.              if (telekinesis) {
  49.                  result = 0; /* don't lift */
  50.              } else {
  51.                  char qbuf[BUFSZ];
  52.                  long savequan = obj->quan;
  53.  
  54.                  obj->quan = *cnt_p;
  55.                  Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER)
  56.                                   ? overloadmsg
  57.                                   : (next_encumbr > MOD_ENCUMBER)
  58.                                         ? nearloadmsg
  59.                                         : moderateloadmsg);
  60.                  if (container)
  61.                      (void) strsubst(qbuf, "lifting", "removing");
  62.                  Strcat(qbuf, " ");
  63.                  (void) safe_qbuf(qbuf, qbuf, ".  Continue?", obj, doname,
  64.                                   ansimpleoname, something);
  65.                  obj->quan = savequan;
  66.                  switch (ynq(qbuf)) {
  67.                  case 'q':
  68.                      result = -1;
  69.                      break;
  70.                  case 'n':
  71.                      result = 0;
  72.                      break;
  73.                  default:
  74.                      break; /* 'y' => result == 1 */
  75.                  }
  76.                  clear_nhwindow(WIN_MESSAGE);
  77.              }
  78.          }
  79.      }
  80.  
  81.      if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container)
  82.          obj->spe = 0;
  83.      return result;
  84.  }
  85.  

pickup_object[edit]

  1.  /*
  2.   * Pick up <count> of obj from the ground and add it to the hero's inventory.
  3.   * Returns -1 if caller should break out of its loop, 0 if nothing picked
  4.   * up, 1 if otherwise.
  5.   */
  6.  int
  7.  pickup_object(obj, count, telekinesis)
  8.  struct obj *obj;
  9.  long count;
  10.  boolean telekinesis; /* not picking it up directly by hand */
  11.  {
  12.      int res, nearload;
  13.  
  14.      if (obj->quan < count) {
  15.          impossible("pickup_object: count %ld > quan %ld?", count, obj->quan);
  16.          return 0;
  17.      }
  18.  
  19.      /* In case of auto-pickup, where we haven't had a chance
  20.         to look at it yet; affects docall(SCR_SCARE_MONSTER). */
  21.      if (!Blind)
  22.          obj->dknown = 1;
  23.  
  24.      if (obj == uchain) { /* do not pick up attached chain */
  25.          return 0;
  26.      } else if (obj->oartifact && !touch_artifact(obj, &youmonst)) {
  27.          return 0;
  28.      } else if (obj->otyp == CORPSE) {
  29.          if (fatal_corpse_mistake(obj, telekinesis)
  30.              || rider_corpse_revival(obj, telekinesis))
  31.              return -1;
  32.      } else if (obj->otyp == SCR_SCARE_MONSTER) {
  33.          if (obj->blessed)
  34.              obj->blessed = 0;
  35.          else if (!obj->spe && !obj->cursed)
  36.              obj->spe = 1;
  37.          else {
  38.              pline_The("scroll%s %s to dust as you %s %s up.", plur(obj->quan),
  39.                        otense(obj, "turn"), telekinesis ? "raise" : "pick",
  40.                        (obj->quan == 1L) ? "it" : "them");
  41.              if (!(objects[SCR_SCARE_MONSTER].oc_name_known)
  42.                  && !(objects[SCR_SCARE_MONSTER].oc_uname))
  43.                  docall(obj);
  44.              useupf(obj, obj->quan);
  45.              return 1; /* tried to pick something up and failed, but
  46.                           don't want to terminate pickup loop yet   */
  47.          }
  48.      }
  49.  
  50.      if ((res = lift_object(obj, (struct obj *) 0, &count, telekinesis)) <= 0)
  51.          return res;
  52.  
  53.      /* Whats left of the special case for gold :-) */
  54.      if (obj->oclass == COIN_CLASS)
  55.          context.botl = 1;
  56.      if (obj->quan != count && obj->otyp != LOADSTONE)
  57.          obj = splitobj(obj, count);
  58.  
  59.      obj = pick_obj(obj);
  60.  
  61.      if (uwep && uwep == obj)
  62.          mrg_to_wielded = TRUE;
  63.      nearload = near_capacity();
  64.      prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj,
  65.            count);
  66.      mrg_to_wielded = FALSE;
  67.      return 1;
  68.  }
  69.  

pick_obj[edit]

  1.  /*
  2.   * Do the actual work of picking otmp from the floor or monster's interior
  3.   * and putting it in the hero's inventory.  Take care of billing.  Return a
  4.   * pointer to the object where otmp ends up.  This may be different
  5.   * from otmp because of merging.
  6.   */
  7.  struct obj *
  8.  pick_obj(otmp)
  9.  struct obj *otmp;
  10.  {
  11.      obj_extract_self(otmp);
  12.      if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) {
  13.          char saveushops[5], fakeshop[2];
  14.  
  15.          /* addtobill cares about your location rather than the object's;
  16.             usually they'll be the same, but not when using telekinesis
  17.             (if ever implemented) or a grappling hook */
  18.          Strcpy(saveushops, u.ushops);
  19.          fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE);
  20.          fakeshop[1] = '\0';
  21.          Strcpy(u.ushops, fakeshop);
  22.          /* sets obj->unpaid if necessary */
  23.          addtobill(otmp, TRUE, FALSE, FALSE);
  24.          Strcpy(u.ushops, saveushops);
  25.          /* if you're outside the shop, make shk notice */
  26.          if (!index(u.ushops, *fakeshop))
  27.              remote_burglary(otmp->ox, otmp->oy);
  28.      }
  29.      newsym(otmp->ox, otmp->oy);
  30.      return addinv(otmp); /* might merge it with other objects */
  31.  }
  32.  

encumber_msg[edit]

  1.  /*
  2.   * prints a message if encumbrance changed since the last check and
  3.   * returns the new encumbrance value (from near_capacity()).
  4.   */
  5.  int
  6.  encumber_msg()
  7.  {
  8.      static int oldcap = UNENCUMBERED;
  9.      int newcap = near_capacity();
  10.  
  11.      if (oldcap < newcap) {
  12.          switch (newcap) {
  13.          case 1:
  14.              Your("movements are slowed slightly because of your load.");
  15.              break;
  16.          case 2:
  17.              You("rebalance your load.  Movement is difficult.");
  18.              break;
  19.          case 3:
  20.              You("%s under your heavy load.  Movement is very hard.",
  21.                  stagger(youmonst.data, "stagger"));
  22.              break;
  23.          default:
  24.              You("%s move a handspan with this load!",
  25.                  newcap == 4 ? "can barely" : "can't even");
  26.              break;
  27.          }
  28.          context.botl = 1;
  29.      } else if (oldcap > newcap) {
  30.          switch (newcap) {
  31.          case 0:
  32.              Your("movements are now unencumbered.");
  33.              break;
  34.          case 1:
  35.              Your("movements are only slowed slightly by your load.");
  36.              break;
  37.          case 2:
  38.              You("rebalance your load.  Movement is still difficult.");
  39.              break;
  40.          case 3:
  41.              You("%s under your load.  Movement is still very hard.",
  42.                  stagger(youmonst.data, "stagger"));
  43.              break;
  44.          }
  45.          context.botl = 1;
  46.      }
  47.  
  48.      oldcap = newcap;
  49.      return newcap;
  50.  }
  51.  

container_at[edit]

  1.  /* Is there a container at x,y. Optional: return count of containers at x,y */
  2.  STATIC_OVL int
  3.  container_at(x, y, countem)
  4.  int x, y;
  5.  boolean countem;
  6.  {
  7.      struct obj *cobj, *nobj;
  8.      int container_count = 0;
  9.  
  10.      for (cobj = level.objects[x][y]; cobj; cobj = nobj) {
  11.          nobj = cobj->nexthere;
  12.          if (Is_container(cobj)) {
  13.              container_count++;
  14.              if (!countem)
  15.                  break;
  16.          }
  17.      }
  18.      return container_count;
  19.  }
  20.  

able_to_loot[edit]

  1.  STATIC_OVL boolean
  2.  able_to_loot(x, y, looting)
  3.  int x, y;
  4.  boolean looting; /* loot vs tip */
  5.  {
  6.      const char *verb = looting ? "loot" : "tip";
  7.  
  8.      if (!can_reach_floor(TRUE)) {
  9.          if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
  10.              rider_cant_reach(); /* not skilled enough to reach */
  11.          else
  12.              cant_reach_floor(x, y, FALSE, TRUE);
  13.          return FALSE;
  14.      } else if ((is_pool(x, y) && (looting || !Underwater)) || is_lava(x, y)) {
  15.          /* at present, can't loot in water even when Underwater;
  16.             can tip underwater, but not when over--or stuck in--lava */
  17.          You("cannot %s things that are deep in the %s.", verb,
  18.              is_lava(x, y) ? "lava" : "water");
  19.          return FALSE;
  20.      } else if (nolimbs(youmonst.data)) {
  21.          pline("Without limbs, you cannot %s anything.", verb);
  22.          return FALSE;
  23.      } else if (looting && !freehand()) {
  24.          pline("Without a free %s, you cannot loot anything.",
  25.                body_part(HAND));
  26.          return FALSE;
  27.      }
  28.      return TRUE;
  29.  }
  30.  

mon_beside[edit]

  1.  STATIC_OVL boolean
  2.  mon_beside(x, y)
  3.  int x, y;
  4.  {
  5.      int i, j, nx, ny;
  6.      for (i = -1; i <= 1; i++)
  7.          for (j = -1; j <= 1; j++) {
  8.              nx = x + i;
  9.              ny = y + j;
  10.              if (isok(nx, ny) && MON_AT(nx, ny))
  11.                  return TRUE;
  12.          }
  13.      return FALSE;
  14.  }
  15.  

do_loot_cont[edit]

  1.  int
  2.  do_loot_cont(cobjp)
  3.  struct obj **cobjp;
  4.  {
  5.      struct obj *cobj = *cobjp;
  6.      if (!cobj)
  7.          return 0;
  8.      if (cobj->olocked) {
  9.          pline("%s locked.",
  10.                cobj->lknown ? "It is" : "Hmmm, it turns out to be");
  11.          cobj->lknown = 1;
  12.          return 0;
  13.      }
  14.      cobj->lknown = 1;
  15.  
  16.      if (cobj->otyp == BAG_OF_TRICKS) {
  17.          int tmp;
  18.          You("carefully open the bag...");
  19.          pline("It develops a huge set of teeth and bites you!");
  20.          tmp = rnd(10);
  21.          losehp(Maybe_Half_Phys(tmp), "carnivorous bag", KILLED_BY_AN);
  22.          makeknown(BAG_OF_TRICKS);
  23.          return 1;
  24.      }
  25.  
  26.      You("%sopen %s...", (!cobj->cknown || !cobj->lknown) ? "carefully " : "",
  27.          the(xname(cobj)));
  28.      return use_container(cobjp, 0);
  29.  }
  30.  

doloot[edit]

  1.  /* loot a container on the floor or loot saddle from mon. */
  2.  int
  3.  doloot()
  4.  {
  5.      struct obj *cobj, *nobj;
  6.      register int c = -1;
  7.      int timepassed = 0;
  8.      coord cc;
  9.      boolean underfoot = TRUE;
  10.      const char *dont_find_anything = "don't find anything";
  11.      struct monst *mtmp;
  12.      char qbuf[BUFSZ];
  13.      int prev_inquiry = 0;
  14.      boolean prev_loot = FALSE;
  15.      int num_conts;
  16.  
  17.      if (check_capacity((char *) 0)) {
  18.          /* "Can't do that while carrying so much stuff." */
  19.          return 0;
  20.      }
  21.      if (nohands(youmonst.data)) {
  22.          You("have no hands!"); /* not `body_part(HAND)' */
  23.          return 0;
  24.      }
  25.      if (Confusion) {
  26.          if (rn2(6) && reverse_loot())
  27.              return 1;
  28.          if (rn2(2)) {
  29.              pline("Being confused, you find nothing to loot.");
  30.              return 1; /* costs a turn */
  31.          }             /* else fallthrough to normal looting */
  32.      }
  33.      cc.x = u.ux;
  34.      cc.y = u.uy;
  35.  
  36.  lootcont:
  37.  
  38.      if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) {
  39.          boolean anyfound = FALSE;
  40.  
  41.          if (!able_to_loot(cc.x, cc.y, TRUE))
  42.              return 0;
  43.  
  44.          if (num_conts > 1) {
  45.              /* use a menu to loot many containers */
  46.              int n, i;
  47.              winid win;
  48.              anything any;
  49.              menu_item *pick_list = NULL;
  50.  
  51.              any.a_void = 0;
  52.              win = create_nhwindow(NHW_MENU);
  53.              start_menu(win);
  54.  
  55.              for (cobj = level.objects[cc.x][cc.y]; cobj;
  56.                   cobj = cobj->nexthere)
  57.                  if (Is_container(cobj)) {
  58.                      any.a_obj = cobj;
  59.                      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
  60.                               doname(cobj), MENU_UNSELECTED);
  61.                  }
  62.              end_menu(win, "Loot which containers?");
  63.              n = select_menu(win, PICK_ANY, &pick_list);
  64.              destroy_nhwindow(win);
  65.  
  66.              if (n > 0) {
  67.                  for (i = 0; i < n; i++) {
  68.                      timepassed |= do_loot_cont(&pick_list[i].item.a_obj);
  69.                      if (multi < 0 || !pick_list[i].item.a_obj) {
  70.                          free((genericptr_t) pick_list);
  71.                          return 1;
  72.                      }
  73.                  }
  74.              }
  75.              if (pick_list)
  76.                  free((genericptr_t) pick_list);
  77.              if (n != 0)
  78.                  c = 'y';
  79.          } else {
  80.              for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
  81.                  nobj = cobj->nexthere;
  82.  
  83.                  if (Is_container(cobj)) {
  84.                      c = ynq(safe_qbuf(qbuf, "There is ", " here, loot it?",
  85.                                        cobj, doname, ansimpleoname,
  86.                                        "a container"));
  87.                      if (c == 'q')
  88.                          return timepassed;
  89.                      if (c == 'n')
  90.                          continue;
  91.                      anyfound = TRUE;
  92.  
  93.                      timepassed |= do_loot_cont(&cobj);
  94.                      /* might have triggered chest trap or magic bag explosion
  95.                       */
  96.                      if (multi < 0 || !cobj)
  97.                          return 1;
  98.                  }
  99.              }
  100.              if (anyfound)
  101.                  c = 'y';
  102.          }
  103.      } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) {
  104.          You("need to dig up the grave to effectively loot it...");
  105.      }
  106.      /*
  107.       * 3.3.1 introduced directional looting for some things.
  108.       */
  109.      if (c != 'y' && mon_beside(u.ux, u.uy)) {
  110.          if (!get_adjacent_loc("Loot in what direction?",
  111.                                "Invalid loot location", u.ux, u.uy, &cc))
  112.              return 0;
  113.          if (cc.x == u.ux && cc.y == u.uy) {
  114.              underfoot = TRUE;
  115.              if (container_at(cc.x, cc.y, FALSE))
  116.                  goto lootcont;
  117.          } else
  118.              underfoot = FALSE;
  119.          if (u.dz < 0) {
  120.              You("%s to loot on the %s.", dont_find_anything,
  121.                  ceiling(cc.x, cc.y));
  122.              timepassed = 1;
  123.              return timepassed;
  124.          }
  125.          mtmp = m_at(cc.x, cc.y);
  126.          if (mtmp)
  127.              timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot);
  128.          /* always use a turn when choosing a direction is impaired,
  129.             even if you've successfully targetted a saddled creature
  130.             and then answered "no" to the "remove its saddle?" prompt */
  131.          if (Confusion || Stunned)
  132.              timepassed = 1;
  133.  
  134.          /* Preserve pre-3.3.1 behaviour for containers.
  135.           * Adjust this if-block to allow container looting
  136.           * from one square away to change that in the future.
  137.           */
  138.          if (!underfoot) {
  139.              if (container_at(cc.x, cc.y, FALSE)) {
  140.                  if (mtmp) {
  141.                      You_cant("loot anything %sthere with %s in the way.",
  142.                               prev_inquiry ? "else " : "", mon_nam(mtmp));
  143.                      return timepassed;
  144.                  } else {
  145.                      You("have to be at a container to loot it.");
  146.                  }
  147.              } else {
  148.                  You("%s %sthere to loot.", dont_find_anything,
  149.                      (prev_inquiry || prev_loot) ? "else " : "");
  150.                  return timepassed;
  151.              }
  152.          }
  153.      } else if (c != 'y' && c != 'n') {
  154.          You("%s %s to loot.", dont_find_anything,
  155.              underfoot ? "here" : "there");
  156.      }
  157.      return timepassed;
  158.  }
  159.  

reverse_loot[edit]

  1.  /* called when attempting to #loot while confused */
  2.  STATIC_OVL boolean
  3.  reverse_loot()
  4.  {
  5.      struct obj *goldob = 0, *coffers, *otmp, boxdummy;
  6.      struct monst *mon;
  7.      long contribution;
  8.      int n, x = u.ux, y = u.uy;
  9.  
  10.      if (!rn2(3)) {
  11.          /* n objects: 1/(n+1) chance per object plus 1/(n+1) to fall off end
  12.           */
  13.          for (n = inv_cnt(TRUE), otmp = invent; otmp; --n, otmp = otmp->nobj)
  14.              if (!rn2(n + 1)) {
  15.                  prinv("You find old loot:", otmp, 0L);
  16.                  return TRUE;
  17.              }
  18.          return FALSE;
  19.      }
  20.  
  21.      /* find a money object to mess with */
  22.      for (goldob = invent; goldob; goldob = goldob->nobj)
  23.          if (goldob->oclass == COIN_CLASS) {
  24.              contribution = ((long) rnd(5) * goldob->quan + 4L) / 5L;
  25.              if (contribution < goldob->quan)
  26.                  goldob = splitobj(goldob, contribution);
  27.              break;
  28.          }
  29.      if (!goldob)
  30.          return FALSE;
  31.  
  32.      if (!IS_THRONE(levl[x][y].typ)) {
  33.          dropx(goldob);
  34.          /* the dropped gold might have fallen to lower level */
  35.          if (g_at(x, y))
  36.              pline("Ok, now there is loot here.");
  37.      } else {
  38.          /* find original coffers chest if present, otherwise use nearest one
  39.           */
  40.          otmp = 0;
  41.          for (coffers = fobj; coffers; coffers = coffers->nobj)
  42.              if (coffers->otyp == CHEST) {
  43.                  if (coffers->spe == 2)
  44.                      break; /* a throne room chest */
  45.                  if (!otmp
  46.                      || distu(coffers->ox, coffers->oy)
  47.                             < distu(otmp->ox, otmp->oy))
  48.                      otmp = coffers; /* remember closest ordinary chest */
  49.              }
  50.          if (!coffers)
  51.              coffers = otmp;
  52.  
  53.          if (coffers) {
  54.              verbalize("Thank you for your contribution to reduce the debt.");
  55.              freeinv(goldob);
  56.              (void) add_to_container(coffers, goldob);
  57.              coffers->owt = weight(coffers);
  58.              coffers->cknown = 0;
  59.              if (!coffers->olocked) {
  60.                  boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK;
  61.                  (void) boxlock(coffers, &boxdummy);
  62.              }
  63.          } else if (levl[x][y].looted != T_LOOTED &&
  64.                     (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
  65.              freeinv(goldob);
  66.              add_to_minv(mon, goldob);
  67.              pline("The exchequer accepts your contribution.");
  68.              if (!rn2(10))
  69.                  levl[x][y].looted = T_LOOTED;
  70.          } else {
  71.              You("drop %s.", doname(goldob));
  72.              dropx(goldob);
  73.          }
  74.      }
  75.      return TRUE;
  76.  }
  77.  

loot_mon[edit]

  1.  /* loot_mon() returns amount of time passed.
  2.   */
  3.  int
  4.  loot_mon(mtmp, passed_info, prev_loot)
  5.  struct monst *mtmp;
  6.  int *passed_info;
  7.  boolean *prev_loot;
  8.  {
  9.      int c = -1;
  10.      int timepassed = 0;
  11.      struct obj *otmp;
  12.      char qbuf[QBUFSZ];
  13.  
  14.      /* 3.3.1 introduced the ability to remove saddle from a steed */
  15.      /* 	*passed_info is set to TRUE if a loot query was given. */
  16.      /*	*prev_loot is set to TRUE if something was actually acquired in here.
  17.       */
  18.      if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
  19.          long unwornmask;
  20.          if (passed_info)
  21.              *passed_info = 1;
  22.          Sprintf(
  23.              qbuf, "Do you want to remove the saddle from %s?",
  24.              x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE));
  25.          if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
  26.              if (nolimbs(youmonst.data)) {
  27.                  You_cant("do that without limbs."); /* not body_part(HAND) */
  28.                  return 0;
  29.              }
  30.              if (otmp->cursed) {
  31.                  You("can't.  The saddle seems to be stuck to %s.",
  32.                      x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE,
  33.                               FALSE));
  34.                  /* the attempt costs you time */
  35.                  return 1;
  36.              }
  37.              obj_extract_self(otmp);
  38.              if ((unwornmask = otmp->owornmask) != 0L) {
  39.                  mtmp->misc_worn_check &= ~unwornmask;
  40.                  otmp->owornmask = 0L;
  41.                  update_mon_intrinsics(mtmp, otmp, FALSE, FALSE);
  42.              }
  43.              otmp = hold_another_object(otmp, "You drop %s!", doname(otmp),
  44.                                         (const char *) 0);
  45.              timepassed = rnd(3);
  46.              if (prev_loot)
  47.                  *prev_loot = TRUE;
  48.          } else if (c == 'q') {
  49.              return 0;
  50.          }
  51.      }
  52.      /* 3.4.0 introduced the ability to pick things up from within swallower's
  53.       * stomach */
  54.      if (u.uswallow) {
  55.          int count = passed_info ? *passed_info : 0;
  56.          timepassed = pickup(count);
  57.      }
  58.      return timepassed;
  59.  }
  60.  

mbag_explodes[edit]

  1.  /*
  2.   * Decide whether an object being placed into a magic bag will cause
  3.   * it to explode.  If the object is a bag itself, check recursively.
  4.   */
  5.  STATIC_OVL boolean
  6.  mbag_explodes(obj, depthin)
  7.  struct obj *obj;
  8.  int depthin;
  9.  {
  10.      /* these won't cause an explosion when they're empty */
  11.      if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS)
  12.          && obj->spe <= 0)
  13.          return FALSE;
  14.  
  15.      /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
  16.      if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION)
  17.          && (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
  18.          return TRUE;
  19.      else if (Has_contents(obj)) {
  20.          struct obj *otmp;
  21.  
  22.          for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  23.              if (mbag_explodes(otmp, depthin + 1))
  24.                  return TRUE;
  25.      }
  26.      return FALSE;
  27.  }
  28.  

in_container[edit]

  1.  /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */
  2.  STATIC_PTR int
  3.  in_container(obj)
  4.  register struct obj *obj;
  5.  {
  6.      boolean floor_container = !carried(current_container);
  7.      boolean was_unpaid = FALSE;
  8.      char buf[BUFSZ];
  9.  
  10.      if (!current_container) {
  11.          impossible("<in> no current_container?");
  12.          return 0;
  13.      } else if (obj == uball || obj == uchain) {
  14.          You("must be kidding.");
  15.          return 0;
  16.      } else if (obj == current_container) {
  17.          pline("That would be an interesting topological exercise.");
  18.          return 0;
  19.      } else if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
  20.          Norep("You cannot %s %s you are wearing.",
  21.                Icebox ? "refrigerate" : "stash", something);
  22.          return 0;
  23.      } else if ((obj->otyp == LOADSTONE) && obj->cursed) {
  24.          obj->bknown = 1;
  25.          pline_The("stone%s won't leave your person.", plur(obj->quan));
  26.          return 0;
  27.      } else if (obj->otyp == AMULET_OF_YENDOR
  28.                 || obj->otyp == CANDELABRUM_OF_INVOCATION
  29.                 || obj->otyp == BELL_OF_OPENING
  30.                 || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  31.          /* Prohibit Amulets in containers; if you allow it, monsters can't
  32.           * steal them.  It also becomes a pain to check to see if someone
  33.           * has the Amulet.  Ditto for the Candelabrum, the Bell and the Book.
  34.           */
  35.          pline("%s cannot be confined in such trappings.", The(xname(obj)));
  36.          return 0;
  37.      } else if (obj->otyp == LEASH && obj->leashmon != 0) {
  38.          pline("%s attached to your pet.", Tobjnam(obj, "are"));
  39.          return 0;
  40.      } else if (obj == uwep) {
  41.          if (welded(obj)) {
  42.              weldmsg(obj);
  43.              return 0;
  44.          }
  45.          setuwep((struct obj *) 0);
  46.          if (uwep)
  47.              return 0; /* unwielded, died, rewielded */
  48.      } else if (obj == uswapwep) {
  49.          setuswapwep((struct obj *) 0);
  50.          if (uswapwep)
  51.              return 0; /* unwielded, died, rewielded */
  52.      } else if (obj == uquiver) {
  53.          setuqwep((struct obj *) 0);
  54.          if (uquiver)
  55.              return 0; /* unwielded, died, rewielded */
  56.      }
  57.  
  58.      if (fatal_corpse_mistake(obj, FALSE))
  59.          return -1;
  60.  
  61.      /* boxes, boulders, and big statues can't fit into any container */
  62.      if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER
  63.          || (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) {
  64.          /*
  65.           *  xname() uses a static result array.  Save obj's name
  66.           *  before current_container's name is computed.  Don't
  67.           *  use the result of strcpy() within You() --- the order
  68.           *  of evaluation of the parameters is undefined.
  69.           */
  70.          Strcpy(buf, the(xname(obj)));
  71.          You("cannot fit %s into %s.", buf, the(xname(current_container)));
  72.          return 0;
  73.      }
  74.  
  75.      freeinv(obj);
  76.  
  77.      if (obj_is_burning(obj)) /* this used to be part of freeinv() */
  78.          (void) snuff_lit(obj);
  79.  
  80.      if (floor_container && costly_spot(u.ux, u.uy)) {
  81.          if (current_container->no_charge && !obj->unpaid) {
  82.              /* don't sell when putting the item into your own container */
  83.              obj->no_charge = 1;
  84.          } else if (obj->oclass != COIN_CLASS) {
  85.              /* sellobj() will take an unpaid item off the shop bill
  86.               * note: coins are handled later */
  87.              was_unpaid = obj->unpaid ? TRUE : FALSE;
  88.              sellobj_state(SELL_DELIBERATE);
  89.              sellobj(obj, u.ux, u.uy);
  90.              sellobj_state(SELL_NORMAL);
  91.          }
  92.      }
  93.      if (Icebox && !age_is_relative(obj)) {
  94.          obj->age = monstermoves - obj->age; /* actual age */
  95.          /* stop any corpse timeouts when frozen */
  96.          if (obj->otyp == CORPSE && obj->timed) {
  97.              long rot_alarm = stop_timer(ROT_CORPSE, obj_to_any(obj));
  98.              (void) stop_timer(REVIVE_MON, obj_to_any(obj));
  99.              /* mark a non-reviving corpse as such */
  100.              if (rot_alarm)
  101.                  obj->norevive = 1;
  102.          }
  103.      } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
  104.          /* explicitly mention what item is triggering the explosion */
  105.          pline("As you put %s inside, you are blasted by a magical explosion!",
  106.                doname(obj));
  107.          /* did not actually insert obj yet */
  108.          if (was_unpaid)
  109.              addtobill(obj, FALSE, FALSE, TRUE);
  110.          obfree(obj, (struct obj *) 0);
  111.          delete_contents(current_container);
  112.          if (!floor_container)
  113.              useup(current_container);
  114.          else if (obj_here(current_container, u.ux, u.uy))
  115.              useupf(current_container, current_container->quan);
  116.          else
  117.              panic("in_container:  bag not found.");
  118.  
  119.          losehp(d(6, 6), "magical explosion", KILLED_BY_AN);
  120.          current_container = 0; /* baggone = TRUE; */
  121.      }
  122.  
  123.      if (current_container) {
  124.          Strcpy(buf, the(xname(current_container)));
  125.          You("put %s into %s.", doname(obj), buf);
  126.  
  127.          /* gold in container always needs to be added to credit */
  128.          if (floor_container && obj->oclass == COIN_CLASS)
  129.              sellobj(obj, current_container->ox, current_container->oy);
  130.          (void) add_to_container(current_container, obj);
  131.          current_container->owt = weight(current_container);
  132.      }
  133.      /* gold needs this, and freeinv() many lines above may cause
  134.       * the encumbrance to disappear from the status, so just always
  135.       * update status immediately.
  136.       */
  137.      bot();
  138.  
  139.      return (current_container ? 1 : -1);
  140.  }
  141.  

ck_bag[edit]

  1.  int
  2.  ck_bag(obj)
  3.  struct obj *obj;
  4.  {
  5.      return current_container && obj != current_container;
  6.  }
  7.  

out_container[edit]

  1.  /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
  2.  STATIC_PTR int
  3.  out_container(obj)
  4.  register struct obj *obj;
  5.  {
  6.      register struct obj *otmp;
  7.      boolean is_gold = (obj->oclass == COIN_CLASS);
  8.      int res, loadlev;
  9.      long count;
  10.  
  11.      if (!current_container) {
  12.          impossible("<out> no current_container?");
  13.          return -1;
  14.      } else if (is_gold) {
  15.          obj->owt = weight(obj);
  16.      }
  17.  
  18.      if (obj->oartifact && !touch_artifact(obj, &youmonst))
  19.          return 0;
  20.  
  21.      if (fatal_corpse_mistake(obj, FALSE))
  22.          return -1;
  23.  
  24.      count = obj->quan;
  25.      if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0)
  26.          return res;
  27.  
  28.      if (obj->quan != count && obj->otyp != LOADSTONE)
  29.          obj = splitobj(obj, count);
  30.  
  31.      /* Remove the object from the list. */
  32.      obj_extract_self(obj);
  33.      current_container->owt = weight(current_container);
  34.  
  35.      if (Icebox && !age_is_relative(obj)) {
  36.          obj->age = monstermoves - obj->age; /* actual age */
  37.          if (obj->otyp == CORPSE)
  38.              start_corpse_timeout(obj);
  39.      }
  40.      /* simulated point of time */
  41.  
  42.      if (!obj->unpaid && !carried(current_container)
  43.          && costly_spot(current_container->ox, current_container->oy)) {
  44.          obj->ox = current_container->ox;
  45.          obj->oy = current_container->oy;
  46.          addtobill(obj, FALSE, FALSE, FALSE);
  47.      }
  48.      if (is_pick(obj))
  49.          pick_pick(obj); /* shopkeeper feedback */
  50.  
  51.      otmp = addinv(obj);
  52.      loadlev = near_capacity();
  53.      prinv(loadlev
  54.                ? (loadlev < MOD_ENCUMBER ? "You have a little trouble removing"
  55.                                          : "You have much trouble removing")
  56.                : (char *) 0,
  57.            otmp, count);
  58.  
  59.      if (is_gold) {
  60.          bot(); /* update character's gold piece count immediately */
  61.      }
  62.      return 1;
  63.  }
  64.  

mbag_item_gone[edit]

  1.  /* an object inside a cursed bag of holding is being destroyed */
  2.  STATIC_OVL long
  3.  mbag_item_gone(held, item)
  4.  int held;
  5.  struct obj *item;
  6.  {
  7.      struct monst *shkp;
  8.      long loss = 0L;
  9.  
  10.      if (item->dknown)
  11.          pline("%s %s vanished!", Doname2(item), otense(item, "have"));
  12.      else
  13.          You("%s %s disappear!", Blind ? "notice" : "see", doname(item));
  14.  
  15.      if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) {
  16.          if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy))
  17.              loss = stolen_value(item, u.ux, u.uy, (boolean) shkp->mpeaceful,
  18.                                  TRUE);
  19.      }
  20.      obfree(item, (struct obj *) 0);
  21.      return loss;
  22.  }
  23.  

observe_quantum_cat[edit]

  1.  STATIC_OVL void
  2.  observe_quantum_cat(box)
  3.  struct obj *box;
  4.  {
  5.      static NEARDATA const char sc[] = "Schroedinger's Cat";
  6.      struct obj *deadcat;
  7.      struct monst *livecat;
  8.      xchar ox, oy;
  9.  
  10.      box->spe = 0; /* box->owt will be updated below */
  11.      if (get_obj_location(box, &ox, &oy, 0))
  12.          box->ox = ox, box->oy = oy; /* in case it's being carried */
  13.  
  14.      /* this isn't really right, since any form of observation
  15.         (telepathic or monster/object/food detection) ought to
  16.         force the determination of alive vs dead state; but basing
  17.         it just on opening the box is much simpler to cope with */
  18.      livecat = rn2(2)
  19.                    ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT)
  20.                    : 0;
  21.      if (livecat) {
  22.          livecat->mpeaceful = 1;
  23.          set_malign(livecat);
  24.          if (!canspotmon(livecat))
  25.              You("think %s brushed your %s.", something, body_part(FOOT));
  26.          else
  27.              pline("%s inside the box is still alive!", Monnam(livecat));
  28.          (void) christen_monst(livecat, sc);
  29.      } else {
  30.          deadcat =
  31.              mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc);
  32.          if (deadcat) {
  33.              obj_extract_self(deadcat);
  34.              (void) add_to_container(box, deadcat);
  35.          }
  36.          pline_The("%s inside the box is dead!",
  37.                    Hallucination ? rndmonnam(NULL) : "housecat");
  38.      }
  39.      box->owt = weight(box);
  40.      return;
  41.  }
  42.  
  43.  #undef Icebox
  44.  

container_gone[edit]

  1.  /* used by askchain() to check for magic bag explosion */
  2.  boolean
  3.  container_gone(fn)
  4.  int FDECL((*fn), (OBJ_P));
  5.  {
  6.      /* result is only meaningful while use_container() is executing */
  7.      return ((fn == in_container || fn == out_container)
  8.              && !current_container);
  9.  }
  10.  

explain_container_prompt[edit]

  1.  STATIC_OVL void
  2.  explain_container_prompt()
  3.  {
  4.      static const char *const explaintext[] = {
  5.          "Container actions:", "", " : -- Look: examine contents",
  6.          " o -- Out: take things out", " i -- In: put things in",
  7.          " b -- Both: first take things out, then put things in",
  8.          " r -- Reversed: put things in, then take things out",
  9.          " s -- Stash: put one item in", " q -- Quit: do nothing",
  10.          " ? -- Help: display this text.", "", 0
  11.      };
  12.      const char *const *txtpp;
  13.      winid win;
  14.  
  15.      /* "Do what with <container>? [:oibrsq or ?] (q)" */
  16.      if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) {
  17.          for (txtpp = explaintext; *txtpp; ++txtpp)
  18.              putstr(win, 0, *txtpp);
  19.          display_nhwindow(win, FALSE);
  20.          destroy_nhwindow(win);
  21.      }
  22.  }
  23.  

u_handsy[edit]

  1.  boolean
  2.  u_handsy()
  3.  {
  4.      if (nohands(youmonst.data)) {
  5.          You("have no hands!"); /* not `body_part(HAND)' */
  6.          return FALSE;
  7.      } else if (!freehand()) {
  8.          You("have no free %s.", body_part(HAND));
  9.          return FALSE;
  10.      }
  11.      return TRUE;
  12.  }
  13.  

use_container[edit]

  1.  static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
  2.  
  3.  int
  4.  use_container(objp, held)
  5.  struct obj **objp;
  6.  int held;
  7.  {
  8.      struct obj *curr, *otmp, *obj = *objp;
  9.      boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first,
  10.          stash_one, inokay, outokay, outmaybe;
  11.      char c, emptymsg[BUFSZ], qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ];
  12.      int used = 0;
  13.  
  14.      emptymsg[0] = '\0';
  15.  
  16.      if (!u_handsy())
  17.          return 0;
  18.  
  19.      if (obj->olocked) {
  20.          pline("%s locked.", Tobjnam(obj, "are"));
  21.          if (held)
  22.              You("must put it down to unlock.");
  23.          obj->lknown = 1;
  24.          return 0;
  25.      } else if (obj->otrapped) {
  26.          if (held)
  27.              You("open %s...", the(xname(obj)));
  28.          obj->lknown = 1;
  29.          (void) chest_trap(obj, HAND, FALSE);
  30.          /* even if the trap fails, you've used up this turn */
  31.          if (multi >= 0) { /* in case we didn't become paralyzed */
  32.              nomul(-1);
  33.              multi_reason = "opening a container";
  34.              nomovemsg = "";
  35.          }
  36.          return 1;
  37.      }
  38.      obj->lknown = 1;
  39.  
  40.      current_container = obj; /* for use by in/out_container */
  41.      /* from here on out, all early returns go through containerdone */
  42.  
  43.      /* check for Schroedinger's Cat */
  44.      quantum_cat = SchroedingersBox(current_container);
  45.      if (quantum_cat) {
  46.          observe_quantum_cat(current_container);
  47.          used = 1;
  48.      }
  49.      /* sometimes toss objects if a cursed magic bag */
  50.      cursed_mbag = (Is_mbag(current_container) && current_container->cursed
  51.                     && Has_contents(current_container));
  52.      if (cursed_mbag) {
  53.          long loss = 0L;
  54.  
  55.          for (curr = current_container->cobj; curr; curr = otmp) {
  56.              otmp = curr->nobj;
  57.              if (!rn2(13)) {
  58.                  obj_extract_self(curr);
  59.                  loss += mbag_item_gone(held, curr);
  60.                  used = 1;
  61.              }
  62.          }
  63.          if (loss)
  64.              You("owe %ld %s for lost merchandise.", loss, currency(loss));
  65.          current_container->owt = weight(current_container);
  66.      }
  67.      inokay = (invent != 0
  68.                && !(invent == current_container && !current_container->nobj));
  69.      outokay = Has_contents(current_container);
  70.      if (!outokay) /* preformat the empty-container message */
  71.          Sprintf(emptymsg, "%s is %sempty.", Ysimple_name2(current_container),
  72.                  (quantum_cat || cursed_mbag) ? "now " : "");
  73.  
  74.      /*
  75.       * What-to-do prompt's list of possible actions:
  76.       * always include the look-inside choice (':');
  77.       * include the take-out choice ('o') if container
  78.       * has anything in it or if player doesn't yet know
  79.       * that it's empty (latter can change on subsequent
  80.       * iterations if player picks ':' response);
  81.       * include the put-in choices ('i','s') if hero
  82.       * carries any inventory (including gold);
  83.       * include do-both when 'o' is available, even if
  84.       * inventory is empty--taking out could alter that;
  85.       * include do-both-reversed when 'i' is available,
  86.       * even if container is empty--for similar reason;
  87.       * always include the quit choice ('q').
  88.       * include the help choice (" or ?") if `cmdassist'
  89.       * run-time option is set;
  90.       * (Player can pick any of (o,i,b,r,s,?) even when
  91.       * they're not listed among the available actions.)
  92.       *
  93.       * Do what with <the/your/Shk's container>? [:oibrsq or ?] (q)
  94.       * or
  95.       * <The/Your/Shk's container> is empty.  Do what with it? [:irsq or ?]
  96.       */
  97.      for (;;) { /* repeats if '?' or ":' gets chosen */
  98.          outmaybe = (outokay || !current_container->cknown);
  99.          if (!outmaybe)
  100.              (void) safe_qbuf(qbuf, (char *) 0, " is empty.  Do what with it?",
  101.                               current_container, Yname2, Ysimple_name2,
  102.                               "This");
  103.          else
  104.              (void) safe_qbuf(qbuf, "Do what with ", "?", current_container,
  105.                               yname, ysimple_name, "it");
  106.          /* ask player about what to do with this container */
  107.          if (flags.menu_style == MENU_FULL) {
  108.              if (!inokay && !outmaybe) {
  109.                  /* nothing to take out, nothing to put in;
  110.                     trying to do both will yield proper feedback */
  111.                  c = 'b';
  112.              } else {
  113.                  c = in_or_out_menu(qbuf, current_container, outmaybe, inokay,
  114.                                     (used != 0));
  115.              }
  116.          } else {               /* TRADITIONAL, COMBINATION, or PARTIAL */
  117.              xbuf[0] = '\0';    /* list of extra acceptable responses */
  118.              Strcpy(pbuf, ":"); /* look inside */
  119.              Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */
  120.              Strcat(inokay ? pbuf : xbuf, "i");   /* put in */
  121.              Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */
  122.              Strcat(inokay ? pbuf : xbuf, "rs");  /* reversed, stash */
  123.              Strcat(pbuf, "q");                   /* quit */
  124.              if (iflags.cmdassist)
  125.                  Strcat(pbuf, " or ?"); /* help */
  126.              else
  127.                  Strcat(xbuf, "?");
  128.              if (*xbuf)
  129.                  Strcat(strcat(pbuf, "\033"), xbuf);
  130.              c = yn_function(qbuf, pbuf, 'q');
  131.          } /* FULL vs other modes */
  132.  
  133.          if (c == '?') {
  134.              explain_container_prompt();
  135.          } else if (c == ':') { /* note: will set obj->cknown */
  136.              if (!current_container->cknown)
  137.                  used = 1; /* gaining info */
  138.              container_contents(current_container, FALSE, FALSE, TRUE);
  139.          } else
  140.              break;
  141.      } /* loop until something other than '?' or ':' is picked */
  142.  
  143.      if (c == 'q') /* [not strictly needed; falling through works] */
  144.          goto containerdone;
  145.      loot_out = (c == 'o' || c == 'b' || c == 'r');
  146.      loot_in = (c == 'i' || c == 'b' || c == 'r');
  147.      loot_in_first = (c == 'r'); /* both, reversed */
  148.      stash_one = (c == 's');
  149.  
  150.      /* out-only or out before in */
  151.      if (loot_out && !loot_in_first) {
  152.          if (!Has_contents(current_container)) {
  153.              pline1(emptymsg); /* <whatever> is empty. */
  154.              if (!current_container->cknown)
  155.                  used = 1;
  156.              current_container->cknown = 1;
  157.          } else {
  158.              add_valid_menu_class(0); /* reset */
  159.              if (flags.menu_style == MENU_TRADITIONAL)
  160.                  used |= traditional_loot(FALSE);
  161.              else
  162.                  used |= (menu_loot(0, FALSE) > 0);
  163.          }
  164.      }
  165.  
  166.      if ((loot_in || stash_one)
  167.          && (!invent || (invent == current_container && !invent->nobj))) {
  168.          You("don't have anything%s to %s.", invent ? " else" : "",
  169.              stash_one ? "stash" : "put in");
  170.          loot_in = stash_one = FALSE;
  171.      }
  172.  
  173.      /*
  174.       * Gone: being nice about only selecting food if we know we are
  175.       * putting things in an ice chest.
  176.       */
  177.      if (loot_in) {
  178.          add_valid_menu_class(0); /* reset */
  179.          if (flags.menu_style == MENU_TRADITIONAL)
  180.              used |= traditional_loot(TRUE);
  181.          else
  182.              used |= (menu_loot(0, TRUE) > 0);
  183.      } else if (stash_one) {
  184.          /* put one item into container */
  185.          if ((otmp = getobj(stashable, "stash")) != 0) {
  186.              if (in_container(otmp)) {
  187.                  used = 1;
  188.              } else {
  189.                  /* couldn't put selected item into container for some
  190.                     reason; might need to undo splitobj() */
  191.                  for (curr = invent; curr; curr = curr->nobj)
  192.                      if (curr->nobj == otmp)
  193.                          break;
  194.                  if (curr && curr->invlet == otmp->invlet)
  195.                      (void) merged(&curr, &otmp);
  196.              }
  197.          }
  198.      }
  199.      /* putting something in might have triggered magic bag explosion */
  200.      if (!current_container)
  201.          loot_out = FALSE;
  202.  
  203.      /* out after in */
  204.      if (loot_out && loot_in_first) {
  205.          if (!Has_contents(current_container)) {
  206.              pline1(emptymsg); /* <whatever> is empty. */
  207.              if (!current_container->cknown)
  208.                  used = 1;
  209.              current_container->cknown = 1;
  210.          } else {
  211.              add_valid_menu_class(0); /* reset */
  212.              if (flags.menu_style == MENU_TRADITIONAL)
  213.                  used |= traditional_loot(FALSE);
  214.              else
  215.                  used |= (menu_loot(0, FALSE) > 0);
  216.          }
  217.      }
  218.  
  219.  containerdone:
  220.      if (used) {
  221.          /* Not completely correct; if we put something in without knowing
  222.             whatever was already inside, now we suddenly do.  That can't
  223.             be helped unless we want to track things item by item and then
  224.             deal with containers whose contents are "partly known". */
  225.          if (current_container)
  226.              current_container->cknown = 1;
  227.          update_inventory();
  228.      }
  229.  
  230.      *objp = current_container; /* might have become null */
  231.      current_container = 0;     /* avoid hanging on to stale pointer */
  232.      return used;
  233.  }
  234.  

traditional_loot[edit]

  1.  /* loot current_container (take things out or put things in), by prompting */
  2.  STATIC_OVL int
  3.  traditional_loot(put_in)
  4.  boolean put_in;
  5.  {
  6.      int FDECL((*actionfunc), (OBJ_P)), FDECL((*checkfunc), (OBJ_P));
  7.      struct obj **objlist;
  8.      char selection[MAXOCLASSES + 1];
  9.      const char *action;
  10.      boolean one_by_one, allflag;
  11.      int used = 0, menu_on_request = 0;
  12.  
  13.      if (put_in) {
  14.          action = "put in";
  15.          objlist = &invent;
  16.          actionfunc = in_container;
  17.          checkfunc = ck_bag;
  18.      } else {
  19.          action = "take out";
  20.          objlist = &(current_container->cobj);
  21.          actionfunc = out_container;
  22.          checkfunc = (int FDECL((*), (OBJ_P))) 0;
  23.      }
  24.  
  25.      if (query_classes(selection, &one_by_one, &allflag, action, *objlist,
  26.                        FALSE, &menu_on_request)) {
  27.          if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag,
  28.                       actionfunc, checkfunc, 0, action))
  29.              used = 1;
  30.      } else if (menu_on_request < 0) {
  31.          used = (menu_loot(menu_on_request, put_in) > 0);
  32.      }
  33.      return used;
  34.  }
  35.  

menu_loot[edit]

  1.  /* loot current_container (take things out or put things in), using a menu */
  2.  STATIC_OVL int
  3.  menu_loot(retry, put_in)
  4.  int retry;
  5.  boolean put_in;
  6.  {
  7.      int n, i, n_looted = 0;
  8.      boolean all_categories = TRUE, loot_everything = FALSE;
  9.      char buf[BUFSZ];
  10.      const char *action = put_in ? "Put in" : "Take out";
  11.      struct obj *otmp, *otmp2;
  12.      menu_item *pick_list;
  13.      int mflags, res;
  14.      long count;
  15.  
  16.      if (retry) {
  17.          all_categories = (retry == -2);
  18.      } else if (flags.menu_style == MENU_FULL) {
  19.          all_categories = FALSE;
  20.          Sprintf(buf, "%s what type of objects?", action);
  21.          mflags = put_in
  22.                       ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN
  23.                       : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
  24.          n = query_category(buf, put_in ? invent : current_container->cobj,
  25.                             mflags, &pick_list, PICK_ANY);
  26.          if (!n)
  27.              return 0;
  28.          for (i = 0; i < n; i++) {
  29.              if (pick_list[i].item.a_int == 'A')
  30.                  loot_everything = TRUE;
  31.              else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
  32.                  all_categories = TRUE;
  33.              else
  34.                  add_valid_menu_class(pick_list[i].item.a_int);
  35.          }
  36.          free((genericptr_t) pick_list);
  37.      }
  38.  
  39.      if (loot_everything) {
  40.          current_container->cknown = 1;
  41.          for (otmp = current_container->cobj; otmp; otmp = otmp2) {
  42.              otmp2 = otmp->nobj;
  43.              res = out_container(otmp);
  44.              if (res < 0)
  45.                  break;
  46.          }
  47.      } else {
  48.          mflags = INVORDER_SORT;
  49.          if (put_in && flags.invlet_constant)
  50.              mflags |= USE_INVLET;
  51.          if (!put_in)
  52.              current_container->cknown = 1;
  53.          Sprintf(buf, "%s what?", action);
  54.          n = query_objlist(buf, put_in ? invent : current_container->cobj,
  55.                            mflags, &pick_list, PICK_ANY,
  56.                            all_categories ? allow_all : allow_category);
  57.          if (n) {
  58.              n_looted = n;
  59.              for (i = 0; i < n; i++) {
  60.                  otmp = pick_list[i].item.a_obj;
  61.                  count = pick_list[i].count;
  62.                  if (count > 0 && count < otmp->quan) {
  63.                      otmp = splitobj(otmp, count);
  64.                      /* special split case also handled by askchain() */
  65.                  }
  66.                  res = put_in ? in_container(otmp) : out_container(otmp);
  67.                  if (res < 0) {
  68.                      if (!current_container) {
  69.                          /* otmp caused current_container to explode;
  70.                             both are now gone */
  71.                          otmp = 0; /* and break loop */
  72.                      } else if (otmp && otmp != pick_list[i].item.a_obj) {
  73.                          /* split occurred, merge again */
  74.                          (void) merged(&pick_list[i].item.a_obj, &otmp);
  75.                      }
  76.                      break;
  77.                  }
  78.              }
  79.              free((genericptr_t) pick_list);
  80.          }
  81.      }
  82.      return n_looted;
  83.  }
  84.  

in_or_out_menu[edit]

  1.  STATIC_OVL char
  2.  in_or_out_menu(prompt, obj, outokay, inokay, alreadyused)
  3.  const char *prompt;
  4.  struct obj *obj;
  5.  boolean outokay, inokay, alreadyused;
  6.  {
  7.      /* underscore is not a choice; it's used to skip element [0] */
  8.      static const char lootchars[] = "_:oibrsq", abc_chars[] = "_:abcdeq";
  9.      winid win;
  10.      anything any;
  11.      menu_item *pick_list;
  12.      char buf[BUFSZ];
  13.      int n;
  14.      const char *menuselector = flags.lootabc ? abc_chars : lootchars;
  15.  
  16.      any = zeroany;
  17.      win = create_nhwindow(NHW_MENU);
  18.      start_menu(win);
  19.  
  20.      any.a_int = 1; /* ':' */
  21.      Sprintf(buf, "Look inside %s", thesimpleoname(obj));
  22.      add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
  23.               MENU_UNSELECTED);
  24.      if (outokay) {
  25.          any.a_int = 2; /* 'o' */
  26.          Sprintf(buf, "take %s out", something);
  27.          add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
  28.                   buf, MENU_UNSELECTED);
  29.      }
  30.      if (inokay) {
  31.          any.a_int = 3; /* 'i' */
  32.          Sprintf(buf, "put %s in", something);
  33.          add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
  34.                   buf, MENU_UNSELECTED);
  35.      }
  36.      if (outokay) {
  37.          any.a_int = 4; /* 'b' */
  38.          Sprintf(buf, "%stake out, then put in", inokay ? "both; " : "");
  39.          add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
  40.                   buf, MENU_UNSELECTED);
  41.      }
  42.      if (inokay) {
  43.          any.a_int = 5; /* 'r' */
  44.          Sprintf(buf, "%sput in, then take out",
  45.                  outokay ? "both reversed; " : "");
  46.          add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
  47.                   buf, MENU_UNSELECTED);
  48.          any.a_int = 6; /* 's' */
  49.          Sprintf(buf, "stash one item into %s", thesimpleoname(obj));
  50.          add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
  51.                   buf, MENU_UNSELECTED);
  52.      }
  53.      any.a_int = 7; /* 'q' */
  54.      Strcpy(buf, alreadyused ? "done" : "do nothing");
  55.      add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
  56.               MENU_SELECTED);
  57.  
  58.      end_menu(win, prompt);
  59.      n = select_menu(win, PICK_ONE, &pick_list);
  60.      destroy_nhwindow(win);
  61.      if (n > 0) {
  62.          n = pick_list[0].item.a_int;
  63.          free((genericptr_t) pick_list);
  64.          return lootchars[n]; /* :,o,i,b,r,s,q */
  65.      }
  66.      return 'q'; /* quit */
  67.  }
  68.  

dotip[edit]

  1.  static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 };
  2.  
  3.  /* #tip command -- empty container contents onto floor */
  4.  int
  5.  dotip()
  6.  {
  7.      struct obj *cobj, *nobj;
  8.      coord cc;
  9.      int boxes;
  10.      char c, buf[BUFSZ], qbuf[BUFSZ];
  11.      const char *spillage = 0;
  12.  
  13.      /*
  14.       * doesn't require free hands;
  15.       * limbs are needed to tip floor containers
  16.       */
  17.  
  18.      /* at present, can only tip things at current spot, not adjacent ones */
  19.      cc.x = u.ux, cc.y = u.uy;
  20.  
  21.      /* check floor container(s) first; at most one will be accessed */
  22.      if ((boxes = container_at(cc.x, cc.y, TRUE)) > 0) {
  23.          Sprintf(buf, "You can't tip %s while carrying so much.",
  24.                  !flags.verbose ? "a container" : (boxes > 1) ? "one" : "it");
  25.          if (!check_capacity(buf) && able_to_loot(cc.x, cc.y, FALSE)) {
  26.              if (boxes > 1 && (flags.menu_style != MENU_TRADITIONAL
  27.                                || iflags.menu_requested)) {
  28.                  /* use menu to pick a container to tip */
  29.                  int n, i;
  30.                  winid win;
  31.                  anything any;
  32.                  menu_item *pick_list = NULL;
  33.                  struct obj dummyobj, *otmp;
  34.  
  35.                  any = zeroany;
  36.                  win = create_nhwindow(NHW_MENU);
  37.                  start_menu(win);
  38.  
  39.                  for (cobj = level.objects[cc.x][cc.y], i = 0; cobj;
  40.                       cobj = cobj->nexthere)
  41.                      if (Is_container(cobj)) {
  42.                          ++i;
  43.                          any.a_obj = cobj;
  44.                          add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
  45.                                   doname(cobj), MENU_UNSELECTED);
  46.                      }
  47.                  if (invent) {
  48.                      any = zeroany;
  49.                      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
  50.                               "", MENU_UNSELECTED);
  51.                      any.a_obj = &dummyobj;
  52.                      /* use 'i' for inventory unless there are so many
  53.                         containers that it's already being used */
  54.                      i = (i <= 'i' - 'a' && !flags.lootabc) ? 'i' : 0;
  55.                      add_menu(win, NO_GLYPH, &any, i, 0, ATR_NONE,
  56.                               "tip something being carried", MENU_SELECTED);
  57.                  }
  58.                  end_menu(win, "Tip which container?");
  59.                  n = select_menu(win, PICK_ONE, &pick_list);
  60.                  destroy_nhwindow(win);
  61.                  /*
  62.                   * Deal with quirk of preselected item in pick-one menu:
  63.                   * n ==  0 => picked preselected entry, toggling it off;
  64.                   * n ==  1 => accepted preselected choice via SPACE or RETURN;
  65.                   * n ==  2 => picked something other than preselected entry;
  66.                   * n == -1 => cancelled via ESC;
  67.                   */
  68.                  otmp = (n <= 0) ? (struct obj *) 0 : pick_list[0].item.a_obj;
  69.                  if (n > 1 && otmp == &dummyobj)
  70.                      otmp = pick_list[1].item.a_obj;
  71.                  if (pick_list)
  72.                      free((genericptr_t) pick_list);
  73.                  if (otmp && otmp != &dummyobj) {
  74.                      tipcontainer(otmp);
  75.                      return 1;
  76.                  }
  77.                  if (n == -1)
  78.                      return 0;
  79.                  /* else pick-from-invent below */
  80.              } else {
  81.                  for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) {
  82.                      nobj = cobj->nexthere;
  83.                      if (!Is_container(cobj))
  84.                          continue;
  85.                      c = ynq(safe_qbuf(qbuf, "There is ", " here, tip it?",
  86.                                        cobj,
  87.                                        doname, ansimpleoname, "container"));
  88.                      if (c == 'q')
  89.                          return 0;
  90.                      if (c == 'n')
  91.                          continue;
  92.                      tipcontainer(cobj);
  93.                      /* can only tip one container at a time */
  94.                      return 1;
  95.                  }
  96.              }
  97.          }
  98.      }
  99.  
  100.      /* either no floor container(s) or couldn't tip one or didn't tip any */
  101.      cobj = getobj(tippables, "tip");
  102.      if (!cobj)
  103.          return 0;
  104.  
  105.      /* normal case */
  106.      if (Is_container(cobj) || cobj->otyp == HORN_OF_PLENTY) {
  107.          tipcontainer(cobj);
  108.          return 1;
  109.      }
  110.      /* assorted other cases */
  111.      if (Is_candle(cobj) && cobj->lamplit) {
  112.          /* note "wax" even for tallow candles to avoid giving away info */
  113.          spillage = "wax";
  114.      } else if ((cobj->otyp == POT_OIL && cobj->lamplit)
  115.                 || (cobj->otyp == OIL_LAMP && cobj->age != 0L)
  116.                 || (cobj->otyp == MAGIC_LAMP && cobj->spe != 0)) {
  117.          spillage = "oil";
  118.          /* todo: reduce potion's remaining burn timer or oil lamp's fuel */
  119.      } else if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) {
  120.          /* charged consumed below */
  121.          spillage = "grease";
  122.      } else if (cobj->otyp == FOOD_RATION || cobj->otyp == CRAM_RATION
  123.                 || cobj->otyp == LEMBAS_WAFER) {
  124.          spillage = "crumbs";
  125.      } else if (cobj->oclass == VENOM_CLASS) {
  126.          spillage = "venom";
  127.      }
  128.      if (spillage) {
  129.          buf[0] = '\0';
  130.          if (is_pool(u.ux, u.uy))
  131.              Sprintf(buf, " and gradually %s", vtense(spillage, "dissipate"));
  132.          else if (is_lava(u.ux, u.uy))
  133.              Sprintf(buf, " and immediately %s away",
  134.                      vtense(spillage, "burn"));
  135.          pline("Some %s %s onto the %s%s.", spillage,
  136.                vtense(spillage, "spill"), surface(u.ux, u.uy), buf);
  137.          /* shop usage message comes after the spill message */
  138.          if (cobj->otyp == CAN_OF_GREASE && cobj->spe > 0) {
  139.              consume_obj_charge(cobj, TRUE);
  140.          }
  141.          /* something [useless] happened */
  142.          return 1;
  143.      }
  144.      /* anything not covered yet */
  145.      if (cobj->oclass == POTION_CLASS) /* can't pour potions... */
  146.          pline_The("%s %s securely sealed.", xname(cobj), otense(cobj, "are"));
  147.      else if (cobj->otyp == STATUE)
  148.          pline("Nothing interesting happens.");
  149.      else
  150.          pline1(nothing_happens);
  151.      return 0;
  152.  }
  153.  

tipcontainer[edit]

  1.  STATIC_OVL void
  2.  tipcontainer(box)
  3.  struct obj *box; /* or bag */
  4.  {
  5.      xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */
  6.      boolean empty_it = FALSE,
  7.              /* Shop handling:  can't rely on the container's own unpaid
  8.                 or no_charge status because contents might differ with it.
  9.                 A carried container's contents will be flagged as unpaid
  10.                 or not, as appropriate, and need no special handling here.
  11.                 Items owned by the hero get sold to the shop without
  12.                 confirmation as with other uncontrolled drops.  A floor
  13.                 container's contents will be marked no_charge if owned by
  14.                 hero, otherwise they're owned by the shop.  By passing
  15.                 the contents through shop billing, they end up getting
  16.                 treated the same as in the carried case.   We do so one
  17.                 item at a time instead of doing whole container at once
  18.                 to reduce the chance of exhausting shk's billing capacity. */
  19.          maybeshopgoods = !carried(box) && costly_spot(ox, oy);
  20.  
  21.      /* caveat: this assumes that cknown, lknown, olocked, and otrapped
  22.         fields haven't been overloaded to mean something special for the
  23.         non-standard "container" horn of plenty */
  24.      box->lknown = 1;
  25.      if (box->olocked) {
  26.          pline("It's locked.");
  27.      } else if (box->otrapped) {
  28.          /* we're not reaching inside but we're still handling it... */
  29.          (void) chest_trap(box, HAND, FALSE);
  30.          /* even if the trap fails, you've used up this turn */
  31.          if (multi >= 0) { /* in case we didn't become paralyzed */
  32.              nomul(-1);
  33.              multi_reason = "tipping a container";
  34.              nomovemsg = "";
  35.          }
  36.      } else if (box->otyp == BAG_OF_TRICKS || box->otyp == HORN_OF_PLENTY) {
  37.          boolean bag = box->otyp == BAG_OF_TRICKS;
  38.          int old_spe = box->spe, seen = 0;
  39.  
  40.          if (maybeshopgoods && !box->no_charge)
  41.              addtobill(box, FALSE, FALSE, TRUE);
  42.          /* apply this bag/horn until empty or monster/object creation fails
  43.             (if the latter occurs, force the former...) */
  44.          do {
  45.              if (!(bag ? bagotricks(box, TRUE, &seen)
  46.                        : hornoplenty(box, TRUE)))
  47.                  break;
  48.          } while (box->spe > 0);
  49.  
  50.          if (box->spe < old_spe) {
  51.              if (bag)
  52.                  pline((seen == 0) ? "Nothing seems to happen."
  53.                                    : (seen == 1) ? "A monster appears."
  54.                                                  : "Monsters appear!");
  55.              /* check_unpaid wants to see a non-zero charge count */
  56.              box->spe = old_spe;
  57.              check_unpaid_usage(box, TRUE);
  58.              box->spe = 0; /* empty */
  59.              box->cknown = 1;
  60.          }
  61.          if (maybeshopgoods && !box->no_charge)
  62.              subfrombill(box, shop_keeper(*in_rooms(ox, oy, SHOPBASE)));
  63.      } else if (SchroedingersBox(box)) {
  64.          char yourbuf[BUFSZ];
  65.  
  66.          observe_quantum_cat(box);
  67.          if (!Has_contents(box)) /* evidently a live cat came out */
  68.              /* container type of "large box" is inferred */
  69.              pline("%sbox is now empty.", Shk_Your(yourbuf, box));
  70.          else /* holds cat corpse or other random stuff */
  71.              empty_it = TRUE;
  72.          box->cknown = 1;
  73.      } else if (!Has_contents(box)) {
  74.          box->cknown = 1;
  75.          pline("It's empty.");
  76.      } else {
  77.          empty_it = TRUE;
  78.      }
  79.  
  80.      if (empty_it) {
  81.          struct obj *otmp, *nobj;
  82.          boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE),
  83.                  altarizing = IS_ALTAR(levl[ox][oy].typ),
  84.                  cursed_mbag = (Is_mbag(box) && box->cursed);
  85.          int held = carried(box);
  86.          long loss = 0L;
  87.  
  88.          if (u.uswallow)
  89.              highdrop = altarizing = FALSE;
  90.          box->cknown = 1;
  91.          pline("%s out%c",
  92.                box->cobj->nobj ? "Objects spill" : "An object spills",
  93.                !(highdrop || altarizing) ? ':' : '.');
  94.          for (otmp = box->cobj; otmp; otmp = nobj) {
  95.              nobj = otmp->nobj;
  96.              obj_extract_self(otmp);
  97.              if (cursed_mbag && !rn2(13)) {
  98.                  loss += mbag_item_gone(held, otmp);
  99.                  /* abbreviated drop format is no longer appropriate */
  100.                  verbose = TRUE;
  101.                  continue;
  102.              }
  103.  
  104.              if (maybeshopgoods) {
  105.                  addtobill(otmp, FALSE, FALSE, TRUE);
  106.                  iflags.suppress_price++; /* doname formatting */
  107.              }
  108.  
  109.              if (highdrop) {
  110.                  /* might break or fall down stairs; handles altars itself */
  111.                  hitfloor(otmp);
  112.              } else {
  113.                  if (altarizing)
  114.                      doaltarobj(otmp);
  115.                  else if (verbose)
  116.                      pline("%s %s to the %s.", Doname2(otmp),
  117.                            otense(otmp, "drop"), surface(ox, oy));
  118.                  else
  119.                      pline("%s%c", doname(otmp), nobj ? ',' : '.');
  120.                  dropy(otmp);
  121.              }
  122.              if (maybeshopgoods)
  123.                  iflags.suppress_price--; /* reset */
  124.          }
  125.          if (loss) /* magic bag lost some shop goods */
  126.              You("owe %ld %s for lost merchandise.", loss, currency(loss));
  127.          box->owt = weight(box); /* mbag_item_gone() doesn't update this */
  128.          if (held)
  129.              (void) encumber_msg();
  130.      }
  131.  }
  132.  
  133.  /*pickup.c*/