Source:NetHack 3.6.0/src/invent.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to invent.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/invent.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

  1.  /* NetHack 3.6	invent.c	$NHDT-Date: 1447576348 2015/11/15 08:32:28 $  $NHDT-Branch: master $:$NHDT-Revision: 1.179 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  
  7.  #define NOINVSYM '#'
  8.  #define CONTAINED_SYM '>' /* designator for inside a container */
  9.  
  10.  STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *));
  11.  STATIC_DCL void NDECL(reorder_invent);
  12.  STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *));
  13.  STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
  14.  STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
  15.  STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
  16.  STATIC_DCL boolean FDECL(only_here, (struct obj *));
  17.  STATIC_DCL void FDECL(compactify, (char *));
  18.  STATIC_DCL boolean FDECL(splittable, (struct obj *));
  19.  STATIC_DCL boolean FDECL(taking_off, (const char *));
  20.  STATIC_DCL boolean FDECL(putting_on, (const char *));
  21.  STATIC_PTR int FDECL(ckunpaid, (struct obj *));
  22.  STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
  23.  STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
  24.  STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
  25.  STATIC_DCL char FDECL(display_pickinv, (const char *, BOOLEAN_P, long *));
  26.  STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
  27.  STATIC_DCL void FDECL(tally_BUCX,
  28.                        (struct obj *, int *, int *, int *, int *, int *));
  29.  STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
  30.  STATIC_DCL void NDECL(dounpaid);
  31.  STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
  32.  STATIC_DCL void FDECL(menu_identify, (int));
  33.  STATIC_DCL boolean FDECL(tool_in_use, (struct obj *));
  34.  STATIC_DCL char FDECL(obj_to_let, (struct obj *));
  35.  
  36.  static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
  37.  
  38.  /* wizards can wish for venom, which will become an invisible inventory
  39.   * item without this.  putting it in inv_order would mean venom would
  40.   * suddenly become a choice for all the inventory-class commands, which
  41.   * would probably cause mass confusion.  the test for inventory venom
  42.   * is only WIZARD and not wizard because the wizard can leave venom lying
  43.   * around on a bones level for normal players to find.  [Note to the
  44.   * confused:  'WIZARD' used to be a compile-time conditional so this was
  45.   * guarded by #ifdef WIZARD/.../#endif.]
  46.   */
  47.  static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
  48.  

sortloot_cmp

  1.  STATIC_OVL int CFDECLSPEC
  2.  sortloot_cmp(obj1, obj2)
  3.  struct obj *obj1;
  4.  struct obj *obj2;
  5.  {
  6.      int val1 = 0;
  7.      int val2 = 0;
  8.  
  9.      /* Sort object names in lexicographical order, ignoring quantity. */
  10.      int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
  11.  
  12.      if (name_cmp != 0) {
  13.          return name_cmp;
  14.      }
  15.  
  16.      /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown
  17.       * to 0. */
  18.      val1 = obj1->bknown
  19.                 ? (obj1->blessed << 2)
  20.                       + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
  21.                 : 0;
  22.      val2 = obj2->bknown
  23.                 ? (obj2->blessed << 2)
  24.                       + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
  25.                 : 0;
  26.      if (val1 != val2) {
  27.          return val2 - val1; /* Because bigger is better. */
  28.      }
  29.  
  30.      /* Sort by greasing. This will put the objects in degreasing order. */
  31.      val1 = obj1->greased;
  32.      val2 = obj2->greased;
  33.      if (val1 != val2) {
  34.          return val2 - val1; /* Because bigger is better. */
  35.      }
  36.  
  37.      /* Sort by erosion. The effective amount is what matters. */
  38.      val1 = greatest_erosion(obj1);
  39.      val2 = greatest_erosion(obj2);
  40.      if (val1 != val2) {
  41.          return val1 - val2; /* Because bigger is WORSE. */
  42.      }
  43.  
  44.      /* Sort by erodeproofing. Map known-invulnerable to 1, and both
  45.       * known-vulnerable and unknown-vulnerability to 0, because that's how
  46.       * they're displayed. */
  47.      val1 = obj1->rknown && obj1->oerodeproof;
  48.      val2 = obj2->rknown && obj2->oerodeproof;
  49.      if (val1 != val2) {
  50.          return val2 - val1; /* Because bigger is better. */
  51.      }
  52.  
  53.      /* Sort by enchantment. Map unknown to -1000, which is comfortably below
  54.       * the range of ->spe. */
  55.      val1 = obj1->known ? obj1->spe : -1000;
  56.      val2 = obj2->known ? obj2->spe : -1000;
  57.      if (val1 != val2) {
  58.          return val2 - val1; /* Because bigger is better. */
  59.      }
  60.  
  61.      /* They're identical, as far as we're concerned,
  62.         but we want to force a determistic order between them. */
  63.      return (obj1->o_id > obj2->o_id) ? 1 : -1;
  64.  }
  65.  

objarr_init

  1.  struct obj **
  2.  objarr_init(n)
  3.  int n;
  4.  {
  5.      return (struct obj **) alloc(n * sizeof(struct obj *));
  6.  }
  7.  

objarr_set

  1.  void
  2.  objarr_set(otmp, idx, oarray, dosort)
  3.  struct obj *otmp;
  4.  int idx;
  5.  struct obj **oarray;
  6.  boolean dosort;
  7.  {
  8.      if (dosort) {
  9.          int j;
  10.          for (j = idx; j; j--) {
  11.              if (sortloot_cmp(otmp, oarray[j - 1]) > 0)
  12.                  break;
  13.              oarray[j] = oarray[j - 1];
  14.          }
  15.          oarray[j] = otmp;
  16.      } else {
  17.          oarray[idx] = otmp;
  18.      }
  19.  }
  20.  

assigninvlet

  1.  void
  2.  assigninvlet(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      boolean inuse[52];
  6.      register int i;
  7.      register struct obj *obj;
  8.  
  9.      /* there should be at most one of these in inventory... */
  10.      if (otmp->oclass == COIN_CLASS) {
  11.          otmp->invlet = GOLD_SYM;
  12.          return;
  13.      }
  14.  
  15.      for (i = 0; i < 52; i++)
  16.          inuse[i] = FALSE;
  17.      for (obj = invent; obj; obj = obj->nobj)
  18.          if (obj != otmp) {
  19.              i = obj->invlet;
  20.              if ('a' <= i && i <= 'z')
  21.                  inuse[i - 'a'] = TRUE;
  22.              else if ('A' <= i && i <= 'Z')
  23.                  inuse[i - 'A' + 26] = TRUE;
  24.              if (i == otmp->invlet)
  25.                  otmp->invlet = 0;
  26.          }
  27.      if ((i = otmp->invlet)
  28.          && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  29.          return;
  30.      for (i = lastinvnr + 1; i != lastinvnr; i++) {
  31.          if (i == 52) {
  32.              i = -1;
  33.              continue;
  34.          }
  35.          if (!inuse[i])
  36.              break;
  37.      }
  38.      otmp->invlet =
  39.          (inuse[i] ? NOINVSYM : (i < 26) ? ('a' + i) : ('A' + i - 26));
  40.      lastinvnr = i;
  41.  }
  42.  

reorder_invent

  1.  /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
  2.  #define inv_rank(o) ((o)->invlet ^ 040)
  3.  
  4.  /* sort the inventory; used by addinv() and doorganize() */
  5.  STATIC_OVL void
  6.  reorder_invent()
  7.  {
  8.      struct obj *otmp, *prev, *next;
  9.      boolean need_more_sorting;
  10.  
  11.      do {
  12.          /*
  13.           * We expect at most one item to be out of order, so this
  14.           * isn't nearly as inefficient as it may first appear.
  15.           */
  16.          need_more_sorting = FALSE;
  17.          for (otmp = invent, prev = 0; otmp;) {
  18.              next = otmp->nobj;
  19.              if (next && inv_rank(next) < inv_rank(otmp)) {
  20.                  need_more_sorting = TRUE;
  21.                  if (prev)
  22.                      prev->nobj = next;
  23.                  else
  24.                      invent = next;
  25.                  otmp->nobj = next->nobj;
  26.                  next->nobj = otmp;
  27.                  prev = next;
  28.              } else {
  29.                  prev = otmp;
  30.                  otmp = next;
  31.              }
  32.          }
  33.      } while (need_more_sorting);
  34.  }
  35.  
  36.  #undef inv_rank
  37.  

merge_choice

  1.  /* scan a list of objects to see whether another object will merge with
  2.     one of them; used in pickup.c when all 52 inventory slots are in use,
  3.     to figure out whether another object could still be picked up */
  4.  struct obj *
  5.  merge_choice(objlist, obj)
  6.  struct obj *objlist, *obj;
  7.  {
  8.      struct monst *shkp;
  9.      int save_nocharge;
  10.  
  11.      if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */
  12.          return (struct obj *) 0;
  13.      /* if this is an item on the shop floor, the attributes it will
  14.         have when carried are different from what they are now; prevent
  15.         that from eliciting an incorrect result from mergable() */
  16.      save_nocharge = obj->no_charge;
  17.      if (objlist == invent && obj->where == OBJ_FLOOR
  18.          && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
  19.          if (obj->no_charge)
  20.              obj->no_charge = 0;
  21.          /* A billable object won't have its `unpaid' bit set, so would
  22.             erroneously seem to be a candidate to merge with a similar
  23.             ordinary object.  That's no good, because once it's really
  24.             picked up, it won't merge after all.  It might merge with
  25.             another unpaid object, but we can't check that here (depends
  26.             too much upon shk's bill) and if it doesn't merge it would
  27.             end up in the '#' overflow inventory slot, so reject it now. */
  28.          else if (inhishop(shkp))
  29.              return (struct obj *) 0;
  30.      }
  31.      while (objlist) {
  32.          if (mergable(objlist, obj))
  33.              break;
  34.          objlist = objlist->nobj;
  35.      }
  36.      obj->no_charge = save_nocharge;
  37.      return objlist;
  38.  }
  39.  

merged

  1.  /* merge obj with otmp and delete obj if types agree */
  2.  int
  3.  merged(potmp, pobj)
  4.  struct obj **potmp, **pobj;
  5.  {
  6.      register struct obj *otmp = *potmp, *obj = *pobj;
  7.  
  8.      if (mergable(otmp, obj)) {
  9.          /* Approximate age: we do it this way because if we were to
  10.           * do it "accurately" (merge only when ages are identical)
  11.           * we'd wind up never merging any corpses.
  12.           * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
  13.           *
  14.           * Don't do the age manipulation if lit.  We would need
  15.           * to stop the burn on both items, then merge the age,
  16.           * then restart the burn.
  17.           */
  18.          if (!obj->lamplit)
  19.              otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
  20.                          / (otmp->quan + obj->quan);
  21.  
  22.          otmp->quan += obj->quan;
  23.          /* temporary special case for gold objects!!!! */
  24.          if (otmp->oclass == COIN_CLASS)
  25.              otmp->owt = weight(otmp);
  26.          /* and puddings!!!1!!one! */
  27.          else if (!Is_pudding(otmp))
  28.              otmp->owt += obj->owt;
  29.          if (!has_oname(otmp) && has_oname(obj))
  30.              otmp = *potmp = oname(otmp, ONAME(obj));
  31.          obj_extract_self(obj);
  32.  
  33.          /* really should merge the timeouts */
  34.          if (obj->lamplit)
  35.              obj_merge_light_sources(obj, otmp);
  36.          if (obj->timed)
  37.              obj_stop_timers(obj); /* follows lights */
  38.  
  39.          /* fixup for `#adjust' merging wielded darts, daggers, &c */
  40.          if (obj->owornmask && carried(otmp)) {
  41.              long wmask = otmp->owornmask | obj->owornmask;
  42.  
  43.              /* Both the items might be worn in competing slots;
  44.                 merger preference (regardless of which is which):
  45.               primary weapon + alternate weapon -> primary weapon;
  46.               primary weapon + quiver -> primary weapon;
  47.               alternate weapon + quiver -> alternate weapon.
  48.                 (Prior to 3.3.0, it was not possible for the two
  49.                 stacks to be worn in different slots and `obj'
  50.                 didn't need to be unworn when merging.) */
  51.              if (wmask & W_WEP)
  52.                  wmask = W_WEP;
  53.              else if (wmask & W_SWAPWEP)
  54.                  wmask = W_SWAPWEP;
  55.              else if (wmask & W_QUIVER)
  56.                  wmask = W_QUIVER;
  57.              else {
  58.                  impossible("merging strangely worn items (%lx)", wmask);
  59.                  wmask = otmp->owornmask;
  60.              }
  61.              if ((otmp->owornmask & ~wmask) != 0L)
  62.                  setnotworn(otmp);
  63.              setworn(otmp, wmask);
  64.              setnotworn(obj);
  65.  #if 0
  66.          /* (this should not be necessary, since items
  67.              already in a monster's inventory don't ever get
  68.              merged into other objects [only vice versa]) */
  69.          } else if (obj->owornmask && mcarried(otmp)) {
  70.              if (obj == MON_WEP(otmp->ocarry)) {
  71.                  MON_WEP(otmp->ocarry) = otmp;
  72.                  otmp->owornmask = W_WEP;
  73.              }
  74.  #endif /*0*/
  75.          }
  76.  
  77.          /* handle puddings a bit differently; absorption will
  78.           * free the other object automatically so we can just
  79.           * return out from here.  */
  80.          if (Is_pudding(obj)) {
  81.              pudding_merge_message(otmp, obj);
  82.              obj_absorb(potmp, pobj);
  83.              return 1;
  84.          }
  85.  
  86.          obfree(obj, otmp); /* free(obj), bill->otmp */
  87.          return 1;
  88.      }
  89.      return 0;
  90.  }
  91.  

addinv_core1

  1.  /*
  2.   * Adjust hero intrinsics as if this object was being added to the hero's
  3.   * inventory.  Called _before_ the object has been added to the hero's
  4.   * inventory.
  5.   *
  6.   * This is called when adding objects to the hero's inventory normally (via
  7.   * addinv) or when an object in the hero's inventory has been polymorphed
  8.   * in-place.
  9.   *
  10.   * It may be valid to merge this code with with addinv_core2().
  11.   */
  12.  void
  13.  addinv_core1(obj)
  14.  struct obj *obj;
  15.  {
  16.      if (obj->oclass == COIN_CLASS) {
  17.          context.botl = 1;
  18.      } else if (obj->otyp == AMULET_OF_YENDOR) {
  19.          if (u.uhave.amulet)
  20.              impossible("already have amulet?");
  21.          u.uhave.amulet = 1;
  22.          u.uachieve.amulet = 1;
  23.      } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  24.          if (u.uhave.menorah)
  25.              impossible("already have candelabrum?");
  26.          u.uhave.menorah = 1;
  27.          u.uachieve.menorah = 1;
  28.      } else if (obj->otyp == BELL_OF_OPENING) {
  29.          if (u.uhave.bell)
  30.              impossible("already have silver bell?");
  31.          u.uhave.bell = 1;
  32.          u.uachieve.bell = 1;
  33.      } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  34.          if (u.uhave.book)
  35.              impossible("already have the book?");
  36.          u.uhave.book = 1;
  37.          u.uachieve.book = 1;
  38.      } else if (obj->oartifact) {
  39.          if (is_quest_artifact(obj)) {
  40.              if (u.uhave.questart)
  41.                  impossible("already have quest artifact?");
  42.              u.uhave.questart = 1;
  43.              artitouch(obj);
  44.          }
  45.          set_artifact_intrinsic(obj, 1, W_ART);
  46.      }
  47.      if (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
  48.          u.uachieve.mines_luckstone = 1;
  49.          obj->record_achieve_special = 0;
  50.      } else if ((obj->otyp == AMULET_OF_REFLECTION
  51.                  || obj->otyp == BAG_OF_HOLDING)
  52.                 && obj->record_achieve_special) {
  53.          u.uachieve.finish_sokoban = 1;
  54.          obj->record_achieve_special = 0;
  55.      }
  56.  }
  57.  

addinv_core2

  1.  /*
  2.   * Adjust hero intrinsics as if this object was being added to the hero's
  3.   * inventory.  Called _after_ the object has been added to the hero's
  4.   * inventory.
  5.   *
  6.   * This is called when adding objects to the hero's inventory normally (via
  7.   * addinv) or when an object in the hero's inventory has been polymorphed
  8.   * in-place.
  9.   */
  10.  void
  11.  addinv_core2(obj)
  12.  struct obj *obj;
  13.  {
  14.      if (confers_luck(obj)) {
  15.          /* new luckstone must be in inventory by this point
  16.           * for correct calculation */
  17.          set_moreluck();
  18.      }
  19.  }
  20.  

addinv

  1.  /*
  2.   * Add obj to the hero's inventory.  Make sure the object is "free".
  3.   * Adjust hero attributes as necessary.
  4.   */
  5.  struct obj *
  6.  addinv(obj)
  7.  struct obj *obj;
  8.  {
  9.      struct obj *otmp, *prev;
  10.      int saved_otyp = (int) obj->otyp; /* for panic */
  11.  
  12.      if (obj->where != OBJ_FREE)
  13.          panic("addinv: obj not free");
  14.      /* normally addtobill() clears no_charge when items in a shop are
  15.         picked up, but won't do so if the shop has become untended */
  16.      obj->no_charge = 0; /* should not be set in hero's invent */
  17.      if (Has_contents(obj))
  18.          picked_container(obj); /* clear no_charge */
  19.      obj->was_thrown = 0;       /* not meaningful for invent */
  20.  
  21.      addinv_core1(obj);
  22.  
  23.      /* merge with quiver in preference to any other inventory slot
  24.         in case quiver and wielded weapon are both eligible; adding
  25.         extra to quivered stack is more useful than to wielded one */
  26.      if (uquiver && merged(&uquiver, &obj)) {
  27.          obj = uquiver;
  28.          if (!obj)
  29.              panic("addinv: null obj after quiver merge otyp=%d", saved_otyp);
  30.          goto added;
  31.      }
  32.      /* merge if possible; find end of chain in the process */
  33.      for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
  34.          if (merged(&otmp, &obj)) {
  35.              obj = otmp;
  36.              if (!obj)
  37.                  panic("addinv: null obj after merge otyp=%d", saved_otyp);
  38.              goto added;
  39.          }
  40.      /* didn't merge, so insert into chain */
  41.      assigninvlet(obj);
  42.      if (flags.invlet_constant || !prev) {
  43.          obj->nobj = invent; /* insert at beginning */
  44.          invent = obj;
  45.          if (flags.invlet_constant)
  46.              reorder_invent();
  47.      } else {
  48.          prev->nobj = obj; /* insert at end */
  49.          obj->nobj = 0;
  50.      }
  51.      obj->where = OBJ_INVENT;
  52.  
  53.  added:
  54.      addinv_core2(obj);
  55.      carry_obj_effects(obj); /* carrying affects the obj */
  56.      update_inventory();
  57.      return obj;
  58.  }
  59.  

carry_obj_effects

  1.  /*
  2.   * Some objects are affected by being carried.
  3.   * Make those adjustments here. Called _after_ the object
  4.   * has been added to the hero's or monster's inventory,
  5.   * and after hero's intrinsics have been updated.
  6.   */
  7.  void
  8.  carry_obj_effects(obj)
  9.  struct obj *obj;
  10.  {
  11.      /* Cursed figurines can spontaneously transform
  12.         when carried. */
  13.      if (obj->otyp == FIGURINE) {
  14.          if (obj->cursed && obj->corpsenm != NON_PM
  15.              && !dead_species(obj->corpsenm, TRUE)) {
  16.              attach_fig_transform_timeout(obj);
  17.          }
  18.      }
  19.  }
  20.  

hold_another_object

  1.  /* Add an item to the inventory unless we're fumbling or it refuses to be
  2.   * held (via touch_artifact), and give a message.
  3.   * If there aren't any free inventory slots, we'll drop it instead.
  4.   * If both success and failure messages are NULL, then we're just doing the
  5.   * fumbling/slot-limit checking for a silent grab.  In any case,
  6.   * touch_artifact will print its own messages if they are warranted.
  7.   */
  8.  struct obj *
  9.  hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
  10.  struct obj *obj;
  11.  const char *drop_fmt, *drop_arg, *hold_msg;
  12.  {
  13.      char buf[BUFSZ];
  14.  
  15.      if (!Blind)
  16.          obj->dknown = 1; /* maximize mergibility */
  17.      if (obj->oartifact) {
  18.          /* place_object may change these */
  19.          boolean crysknife = (obj->otyp == CRYSKNIFE);
  20.          int oerode = obj->oerodeproof;
  21.          boolean wasUpolyd = Upolyd;
  22.  
  23.          /* in case touching this object turns out to be fatal */
  24.          place_object(obj, u.ux, u.uy);
  25.  
  26.          if (!touch_artifact(obj, &youmonst)) {
  27.              obj_extract_self(obj); /* remove it from the floor */
  28.              dropy(obj);            /* now put it back again :-) */
  29.              return obj;
  30.          } else if (wasUpolyd && !Upolyd) {
  31.              /* loose your grip if you revert your form */
  32.              if (drop_fmt)
  33.                  pline(drop_fmt, drop_arg);
  34.              obj_extract_self(obj);
  35.              dropy(obj);
  36.              return obj;
  37.          }
  38.          obj_extract_self(obj);
  39.          if (crysknife) {
  40.              obj->otyp = CRYSKNIFE;
  41.              obj->oerodeproof = oerode;
  42.          }
  43.      }
  44.      if (Fumbling) {
  45.          if (drop_fmt)
  46.              pline(drop_fmt, drop_arg);
  47.          dropy(obj);
  48.      } else {
  49.          long oquan = obj->quan;
  50.          int prev_encumbr = near_capacity(); /* before addinv() */
  51.  
  52.          /* encumbrance only matters if it would now become worse
  53.             than max( current_value, stressed ) */
  54.          if (prev_encumbr < MOD_ENCUMBER)
  55.              prev_encumbr = MOD_ENCUMBER;
  56.          /* addinv() may redraw the entire inventory, overwriting
  57.             drop_arg when it comes from something like doname() */
  58.          if (drop_arg)
  59.              drop_arg = strcpy(buf, drop_arg);
  60.  
  61.          obj = addinv(obj);
  62.          if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
  63.                                      && near_capacity() > prev_encumbr)) {
  64.              if (drop_fmt)
  65.                  pline(drop_fmt, drop_arg);
  66.              /* undo any merge which took place */
  67.              if (obj->quan > oquan)
  68.                  obj = splitobj(obj, oquan);
  69.              dropx(obj);
  70.          } else {
  71.              if (flags.autoquiver && !uquiver && !obj->owornmask
  72.                  && (is_missile(obj) || ammo_and_launcher(obj, uwep)
  73.                      || ammo_and_launcher(obj, uswapwep)))
  74.                  setuqwep(obj);
  75.              if (hold_msg || drop_fmt)
  76.                  prinv(hold_msg, obj, oquan);
  77.          }
  78.      }
  79.      return obj;
  80.  }
  81.  

useupall

  1.  /* useup() all of an item regardless of its quantity */
  2.  void
  3.  useupall(obj)
  4.  struct obj *obj;
  5.  {
  6.      setnotworn(obj);
  7.      freeinv(obj);
  8.      obfree(obj, (struct obj *) 0); /* deletes contents also */
  9.  }
  10.  

useup

  1.  void
  2.  useup(obj)
  3.  register struct obj *obj;
  4.  {
  5.      /* Note:  This works correctly for containers because they (containers)
  6.         don't merge. */
  7.      if (obj->quan > 1L) {
  8.          obj->in_use = FALSE; /* no longer in use */
  9.          obj->quan--;
  10.          obj->owt = weight(obj);
  11.          update_inventory();
  12.      } else {
  13.          useupall(obj);
  14.      }
  15.  }
  16.  

consume_obj_charge

  1.  /* use one charge from an item and possibly incur shop debt for it */
  2.  void
  3.  consume_obj_charge(obj, maybe_unpaid)
  4.  struct obj *obj;
  5.  boolean maybe_unpaid; /* false if caller handles shop billing */
  6.  {
  7.      if (maybe_unpaid)
  8.          check_unpaid(obj);
  9.      obj->spe -= 1;
  10.      if (obj->known)
  11.          update_inventory();
  12.  }
  13.  

freeinv_core

  1.  /*
  2.   * Adjust hero's attributes as if this object was being removed from the
  3.   * hero's inventory.  This should only be called from freeinv() and
  4.   * where we are polymorphing an object already in the hero's inventory.
  5.   *
  6.   * Should think of a better name...
  7.   */
  8.  void
  9.  freeinv_core(obj)
  10.  struct obj *obj;
  11.  {
  12.      if (obj->oclass == COIN_CLASS) {
  13.          context.botl = 1;
  14.          return;
  15.      } else if (obj->otyp == AMULET_OF_YENDOR) {
  16.          if (!u.uhave.amulet)
  17.              impossible("don't have amulet?");
  18.          u.uhave.amulet = 0;
  19.      } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  20.          if (!u.uhave.menorah)
  21.              impossible("don't have candelabrum?");
  22.          u.uhave.menorah = 0;
  23.      } else if (obj->otyp == BELL_OF_OPENING) {
  24.          if (!u.uhave.bell)
  25.              impossible("don't have silver bell?");
  26.          u.uhave.bell = 0;
  27.      } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  28.          if (!u.uhave.book)
  29.              impossible("don't have the book?");
  30.          u.uhave.book = 0;
  31.      } else if (obj->oartifact) {
  32.          if (is_quest_artifact(obj)) {
  33.              if (!u.uhave.questart)
  34.                  impossible("don't have quest artifact?");
  35.              u.uhave.questart = 0;
  36.          }
  37.          set_artifact_intrinsic(obj, 0, W_ART);
  38.      }
  39.  
  40.      if (obj->otyp == LOADSTONE) {
  41.          curse(obj);
  42.      } else if (confers_luck(obj)) {
  43.          set_moreluck();
  44.          context.botl = 1;
  45.      } else if (obj->otyp == FIGURINE && obj->timed) {
  46.          (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj));
  47.      }
  48.  }
  49.  

freeinv

  1.  /* remove an object from the hero's inventory */
  2.  void
  3.  freeinv(obj)
  4.  register struct obj *obj;
  5.  {
  6.      extract_nobj(obj, &invent);
  7.      freeinv_core(obj);
  8.      update_inventory();
  9.  }
  10.  

delallobj

  1.  void
  2.  delallobj(x, y)
  3.  int x, y;
  4.  {
  5.      struct obj *otmp, *otmp2;
  6.  
  7.      for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
  8.          if (otmp == uball)
  9.              unpunish();
  10.          /* after unpunish(), or might get deallocated chain */
  11.          otmp2 = otmp->nexthere;
  12.          if (otmp == uchain)
  13.              continue;
  14.          delobj(otmp);
  15.      }
  16.  }
  17.  

delobj

  1.  /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  2.  void
  3.  delobj(obj)
  4.  register struct obj *obj;
  5.  {
  6.      boolean update_map;
  7.  
  8.      if (obj->otyp == AMULET_OF_YENDOR
  9.          || obj->otyp == CANDELABRUM_OF_INVOCATION
  10.          || obj->otyp == BELL_OF_OPENING
  11.          || obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  12.          /* player might be doing something stupid, but we
  13.           * can't guarantee that.  assume special artifacts
  14.           * are indestructible via drawbridges, and exploding
  15.           * chests, and golem creation, and ...
  16.           */
  17.          return;
  18.      }
  19.      update_map = (obj->where == OBJ_FLOOR);
  20.      obj_extract_self(obj);
  21.      if (update_map)
  22.          newsym(obj->ox, obj->oy);
  23.      obfree(obj, (struct obj *) 0); /* frees contents also */
  24.  }
  25.  

sobj_at

  1.  /* try to find a particular type of object at designated map location */
  2.  struct obj *
  3.  sobj_at(otyp, x, y)
  4.  int otyp;
  5.  int x, y;
  6.  {
  7.      register struct obj *otmp;
  8.  
  9.      for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  10.          if (otmp->otyp == otyp)
  11.              break;
  12.  
  13.      return otmp;
  14.  }
  15.  

nxtobj

  1.  /* sobj_at(&c) traversal -- find next object of specified type */
  2.  struct obj *
  3.  nxtobj(obj, type, by_nexthere)
  4.  struct obj *obj;
  5.  int type;
  6.  boolean by_nexthere;
  7.  {
  8.      register struct obj *otmp;
  9.  
  10.      otmp = obj; /* start with the object after this one */
  11.      do {
  12.          otmp = !by_nexthere ? otmp->nobj : otmp->nexthere;
  13.          if (!otmp)
  14.              break;
  15.      } while (otmp->otyp != type);
  16.  
  17.      return otmp;
  18.  }
  19.  

carrying

  1.  struct obj *
  2.  carrying(type)
  3.  register int type;
  4.  {
  5.      register struct obj *otmp;
  6.  
  7.      for (otmp = invent; otmp; otmp = otmp->nobj)
  8.          if (otmp->otyp == type)
  9.              return  otmp;
  10.      return (struct obj *) 0;
  11.  }
  12.  

currency

  1.  /* Fictional and not-so-fictional currencies.
  2.   * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
  3.   */
  4.  static const char *const currencies[] = {
  5.      "Altarian Dollar",       /* The Hitchhiker's Guide to the Galaxy */
  6.      "Ankh-Morpork Dollar",   /* Discworld */
  7.      "auric",                 /* The Domination of Draka */
  8.      "buckazoid",             /* Space Quest */
  9.      "cirbozoid",             /* Starslip */
  10.      "credit chit",           /* Deus Ex */
  11.      "cubit",                 /* Battlestar Galactica */
  12.      "Flanian Pobble Bead",   /* The Hitchhiker's Guide to the Galaxy */
  13.      "fretzer",               /* Jules Verne */
  14.      "imperial credit",       /* Star Wars */
  15.      "Hong Kong Luna Dollar", /* The Moon is a Harsh Mistress */
  16.      "kongbuck",              /* Snow Crash */
  17.      "nanite",                /* System Shock 2 */
  18.      "quatloo",               /* Star Trek, Sim City */
  19.      "simoleon",              /* Sim City */
  20.      "solari",                /* Spaceballs */
  21.      "spacebuck",             /* Spaceballs */
  22.      "sporebuck",             /* Spore */
  23.      "Triganic Pu",           /* The Hitchhiker's Guide to the Galaxy */
  24.      "woolong",               /* Cowboy Bebop */
  25.      "zorkmid",               /* Zork, NetHack */
  26.  };
  27.  
  28.  const char *
  29.  currency(amount)
  30.  long amount;
  31.  {
  32.      const char *res;
  33.  
  34.      res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
  35.      if (amount != 1L)
  36.          res = makeplural(res);
  37.      return res;
  38.  }
  39.  

have_lizard

  1.  boolean
  2.  have_lizard()
  3.  {
  4.      register struct obj *otmp;
  5.  
  6.      for (otmp = invent; otmp; otmp = otmp->nobj)
  7.          if (otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
  8.              return  TRUE;
  9.      return FALSE;
  10.  }
  11.  

u_have_novel

  1.  /* 3.6.0 tribute */
  2.  struct obj *
  3.  u_have_novel()
  4.  {
  5.      register struct obj *otmp;
  6.  
  7.      for (otmp = invent; otmp; otmp = otmp->nobj)
  8.          if (otmp->otyp == SPE_NOVEL)
  9.              return otmp;
  10.      return (struct obj *) 0;
  11.  }
  12.  

o_on

  1.  struct obj *
  2.  o_on(id, objchn)
  3.  unsigned int id;
  4.  register struct obj *objchn;
  5.  {
  6.      struct obj *temp;
  7.  
  8.      while (objchn) {
  9.          if (objchn->o_id == id)
  10.              return objchn;
  11.          if (Has_contents(objchn) && (temp = o_on(id, objchn->cobj)))
  12.              return temp;
  13.          objchn = objchn->nobj;
  14.      }
  15.      return (struct obj *) 0;
  16.  }
  17.  

obj_here

  1.  boolean
  2.  obj_here(obj, x, y)
  3.  register struct obj *obj;
  4.  int x, y;
  5.  {
  6.      register struct obj *otmp;
  7.  
  8.      for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  9.          if (obj == otmp)
  10.              return TRUE;
  11.      return FALSE;
  12.  }
  13.  

g_at

  1.  struct obj *
  2.  g_at(x, y)
  3.  register int x, y;
  4.  {
  5.      register struct obj *obj = level.objects[x][y];
  6.  
  7.      while (obj) {
  8.          if (obj->oclass == COIN_CLASS)
  9.              return obj;
  10.          obj = obj->nexthere;
  11.      }
  12.      return (struct obj *) 0;
  13.  }
  14.  

compactify

  1.  /* compact a string of inventory letters by dashing runs of letters */
  2.  STATIC_OVL void
  3.  compactify(buf)
  4.  register char *buf;
  5.  {
  6.      register int i1 = 1, i2 = 1;
  7.      register char ilet, ilet1, ilet2;
  8.  
  9.      ilet2 = buf[0];
  10.      ilet1 = buf[1];
  11.      buf[++i2] = buf[++i1];
  12.      ilet = buf[i1];
  13.      while (ilet) {
  14.          if (ilet == ilet1 + 1) {
  15.              if (ilet1 == ilet2 + 1)
  16.                  buf[i2 - 1] = ilet1 = '-';
  17.              else if (ilet2 == '-') {
  18.                  buf[i2 - 1] = ++ilet1;
  19.                  buf[i2] = buf[++i1];
  20.                  ilet = buf[i1];
  21.                  continue;
  22.              }
  23.          } else if (ilet == NOINVSYM) {
  24.              /* compact three or more consecutive '#'
  25.                 characters into "#-#" */
  26.              if (i2 >= 2 && buf[i2 - 2] == NOINVSYM && buf[i2 - 1] == NOINVSYM)
  27.                  buf[i2 - 1] = '-';
  28.              else if (i2 >= 3 && buf[i2 - 3] == NOINVSYM && buf[i2 - 2] == '-'
  29.                       && buf[i2 - 1] == NOINVSYM)
  30.                  --i2;
  31.          }
  32.          ilet2 = ilet1;
  33.          ilet1 = ilet;
  34.          buf[++i2] = buf[++i1];
  35.          ilet = buf[i1];
  36.      }
  37.  }
  38.  

splittable

  1.  /* some objects shouldn't be split when count given to getobj or askchain */
  2.  STATIC_OVL boolean
  3.  splittable(obj)
  4.  struct obj *obj;
  5.  {
  6.      return !((obj->otyp == LOADSTONE && obj->cursed)
  7.               || (obj == uwep && welded(uwep)));
  8.  }
  9.  

taking_off

  1.  /* match the prompt for either 'T' or 'R' command */
  2.  STATIC_OVL boolean
  3.  taking_off(action)
  4.  const char *action;
  5.  {
  6.      return !strcmp(action, "take off") || !strcmp(action, "remove");
  7.  }
  8.  

putting_on

  1.  /* match the prompt for either 'W' or 'P' command */
  2.  STATIC_OVL boolean
  3.  putting_on(action)
  4.  const char *action;
  5.  {
  6.      return !strcmp(action, "wear") || !strcmp(action, "put on");
  7.  }
  8.  

getobj

  1.  /*
  2.   * getobj returns:
  3.   *      struct obj *xxx:        object to do something with.
  4.   *      (struct obj *) 0        error return: no object.
  5.   *      &zeroobj                explicitly no object (as in w-).
  6.  !!!! test if gold can be used in unusual ways (eaten etc.)
  7.  !!!! may be able to remove "usegold"
  8.   */
  9.  struct obj *
  10.  getobj(let, word)
  11.  register const char *let, *word;
  12.  {
  13.      register struct obj *otmp;
  14.      register char ilet;
  15.      char buf[BUFSZ], qbuf[QBUFSZ];
  16.      char lets[BUFSZ], altlets[BUFSZ], *ap;
  17.      register int foo = 0;
  18.      register char *bp = buf;
  19.      xchar allowcnt = 0; /* 0, 1 or 2 */
  20.      struct obj *firstobj = invent;
  21.      boolean usegold = FALSE; /* can't use gold because its illegal */
  22.      boolean allowall = FALSE;
  23.      boolean allownone = FALSE;
  24.      boolean useboulder = FALSE;
  25.      xchar foox = 0;
  26.      long cnt, prevcnt;
  27.      boolean prezero;
  28.      long dummymask;
  29.  
  30.      if (*let == ALLOW_COUNT)
  31.          let++, allowcnt = 1;
  32.      if (*let == COIN_CLASS)
  33.          let++, usegold = TRUE;
  34.  
  35.      /* Equivalent of an "ugly check" for gold */
  36.      if (usegold && !strcmp(word, "eat")
  37.          && (!metallivorous(youmonst.data)
  38.              || youmonst.data == &mons[PM_RUST_MONSTER]))
  39.          usegold = FALSE;
  40.  
  41.      if (*let == ALL_CLASSES)
  42.          let++, allowall = TRUE;
  43.      if (*let == ALLOW_NONE)
  44.          let++, allownone = TRUE;
  45.      /* "ugly check" for reading fortune cookies, part 1.
  46.       * The normal 'ugly check' keeps the object on the inventory list.
  47.       * We don't want to do that for shirts/cookies, so the check for
  48.       * them is handled a bit differently (and also requires that we set
  49.       * allowall in the caller).
  50.       */
  51.      if (allowall && !strcmp(word, "read"))
  52.          allowall = FALSE;
  53.  
  54.      /* another ugly check: show boulders (not statues) */
  55.      if (*let == WEAPON_CLASS && !strcmp(word, "throw")
  56.          && throws_rocks(youmonst.data))
  57.          useboulder = TRUE;
  58.  
  59.      if (allownone)
  60.          *bp++ = '-';
  61.      if (bp > buf && bp[-1] == '-')
  62.          *bp++ = ' ';
  63.      ap = altlets;
  64.  
  65.      if (!flags.invlet_constant)
  66.          reassign();
  67.  
  68.      for (otmp = firstobj; otmp; otmp = otmp->nobj) {
  69.          if (&bp[foo] == &buf[sizeof buf - 1]
  70.              || ap == &altlets[sizeof altlets - 1]) {
  71.              /* we must have a huge number of NOINVSYM items somehow */
  72.              impossible("getobj: inventory overflow");
  73.              break;
  74.          }
  75.  
  76.          if (!*let || index(let, otmp->oclass)
  77.              || (usegold && otmp->invlet == GOLD_SYM)
  78.              || (useboulder && otmp->otyp == BOULDER)) {
  79.              register int otyp = otmp->otyp;
  80.              bp[foo++] = otmp->invlet;
  81.  
  82.  /* clang-format off */
  83.  /* *INDENT-OFF* */
  84.              /* ugly check: remove inappropriate things */
  85.              if (
  86.                  (taking_off(word) /* exclude if not worn */
  87.                   && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
  88.               || (putting_on(word) /* exclude if already worn */
  89.                   && (otmp->owornmask & (W_ARMOR | W_ACCESSORY)))
  90.  #if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */
  91.               || (!strcmp(word, "wield")
  92.                   && (otmp->owornmask & W_WEP))
  93.  #endif
  94.               || (!strcmp(word, "ready") /* exclude if wielded */
  95.                   && (otmp == uwep || (otmp == uswapwep && u.twoweap)))
  96.               || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
  97.                   && inaccessible_equipment(otmp, (const char *) 0, FALSE))
  98.               ) {
  99.                  foo--;
  100.                  foox++;
  101.              }
  102.              /* Second ugly check; unlike the first it won't trigger an
  103.               * "else" in "you don't have anything else to ___".
  104.               */
  105.              else if (
  106.                  (putting_on(word)
  107.                   && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING)
  108.                       || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD
  109.                           && otyp != TOWEL && otyp != LENSES)))
  110.               || (!strcmp(word, "wield")
  111.                   && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
  112.               || (!strcmp(word, "eat") && !is_edible(otmp))
  113.               || (!strcmp(word, "sacrifice")
  114.                   && (otyp != CORPSE && otyp != AMULET_OF_YENDOR
  115.                       && otyp != FAKE_AMULET_OF_YENDOR))
  116.               || (!strcmp(word, "write with")
  117.                   && (otmp->oclass == TOOL_CLASS
  118.                       && otyp != MAGIC_MARKER && otyp != TOWEL))
  119.               || (!strcmp(word, "tin")
  120.                   && (otyp != CORPSE || !tinnable(otmp)))
  121.               || (!strcmp(word, "rub")
  122.                   && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP
  123.                        && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN)
  124.                       || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
  125.               || (!strcmp(word, "use or apply")
  126.                   /* Picks, axes, pole-weapons, bullwhips */
  127.                   && ((otmp->oclass == WEAPON_CLASS
  128.                        && !is_pick(otmp) && !is_axe(otmp)
  129.                        && !is_pole(otmp) && otyp != BULLWHIP)
  130.                       || (otmp->oclass == POTION_CLASS
  131.                           /* only applicable potion is oil, and it will only
  132.                              be offered as a choice when already discovered */
  133.                           && (otyp != POT_OIL || !otmp->dknown
  134.                               || !objects[POT_OIL].oc_name_known))
  135.                       || (otmp->oclass == FOOD_CLASS
  136.                           && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF)
  137.                       || (otmp->oclass == GEM_CLASS && !is_graystone(otmp))))
  138.               || (!strcmp(word, "invoke")
  139.                   && !otmp->oartifact
  140.                   && !objects[otyp].oc_unique
  141.                   && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known)
  142.                   && otyp != CRYSTAL_BALL /* synonym for apply */
  143.                   /* note: presenting the possibility of invoking non-artifact
  144.                      mirrors and/or lamps is simply a cruel deception... */
  145.                   && otyp != MIRROR
  146.                   && otyp != MAGIC_LAMP
  147.                   && (otyp != OIL_LAMP /* don't list known oil lamp */
  148.                       || (otmp->dknown && objects[OIL_LAMP].oc_name_known)))
  149.               || (!strcmp(word, "untrap with")
  150.                   && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)
  151.                       || (otmp->oclass == POTION_CLASS
  152.                           /* only applicable potion is oil, and it will only
  153.                              be offered as a choice when already discovered */
  154.                           && (otyp != POT_OIL || !otmp->dknown
  155.                               || !objects[POT_OIL].oc_name_known))))
  156.               || (!strcmp(word, "tip") && !Is_container(otmp)
  157.                   /* include horn of plenty if sufficiently discovered */
  158.                   && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
  159.                       || !objects[HORN_OF_PLENTY].oc_name_known))
  160.               || (!strcmp(word, "charge") && !is_chargeable(otmp))
  161.               || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
  162.               ) {
  163.                  foo--;
  164.              }
  165.              /* Third ugly check:  acceptable but not listed as likely
  166.               * candidates in the prompt or in the inventory subset if
  167.               * player responds with '?'.
  168.               */
  169.              else if (
  170.               /* ugly check for unworn armor that can't be worn */
  171.                  (putting_on(word) && *let == ARMOR_CLASS
  172.                   && !canwearobj(otmp, &dummymask, FALSE))
  173.               /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */
  174.               || ((putting_on(word) || taking_off(word))
  175.                   && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS)))
  176.               /* or unsuitable items rubbed on known touchstone */
  177.               || (!strncmp(word, "rub on the stone", 16)
  178.                   && *let == GEM_CLASS && otmp->dknown
  179.                   && objects[otyp].oc_name_known)
  180.               /* suppress corpses on astral, amulets elsewhere */
  181.               || (!strcmp(word, "sacrifice")
  182.                   /* (!astral && amulet) || (astral && !amulet) */
  183.                   && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
  184.               /* suppress container being stashed into */
  185.               || (!strcmp(word, "stash") && !ck_bag(otmp))
  186.               /* worn armor or accessory covered by cursed worn armor */
  187.               || (taking_off(word)
  188.                   && inaccessible_equipment(otmp, (const char *) 0, TRUE))
  189.               ) {
  190.                  /* acceptable but not listed as likely candidate */
  191.                  foo--;
  192.                  allowall = TRUE;
  193.                  *ap++ = otmp->invlet;
  194.              }
  195.  /* *INDENT-ON* */
  196.  /* clang-format on */
  197.          } else {
  198.              /* "ugly check" for reading fortune cookies, part 2 */
  199.              if ((!strcmp(word, "read") && is_readable(otmp)))
  200.                  allowall = usegold = TRUE;
  201.          }
  202.      }
  203.  
  204.      bp[foo] = 0;
  205.      if (foo == 0 && bp > buf && bp[-1] == ' ')
  206.          *--bp = 0;
  207.      Strcpy(lets, bp); /* necessary since we destroy buf */
  208.      if (foo > 5)      /* compactify string */
  209.          compactify(bp);
  210.      *ap = '\0';
  211.  
  212.      if (!foo && !allowall && !allownone) {
  213.          You("don't have anything %sto %s.", foox ? "else " : "", word);
  214.          return (struct obj *) 0;
  215.      }
  216.      for (;;) {
  217.          cnt = 0;
  218.          if (allowcnt == 2)
  219.              allowcnt = 1; /* abort previous count */
  220.          prezero = FALSE;
  221.          if (!buf[0]) {
  222.              Sprintf(qbuf, "What do you want to %s? [*]", word);
  223.          } else {
  224.              Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
  225.          }
  226.          if (in_doagain)
  227.              ilet = readchar();
  228.          else
  229.              ilet = yn_function(qbuf, (char *) 0, '\0');
  230.          if (digit(ilet) && !allowcnt) {
  231.              pline("No count allowed with this command.");
  232.              continue;
  233.          }
  234.          if (ilet == '0')
  235.              prezero = TRUE;
  236.          while (digit(ilet)) {
  237.              if (ilet != '?' && ilet != '*')
  238.                  savech(ilet);
  239.              /* accumulate unless cnt has overflowed */
  240.              if (allowcnt < 3) {
  241.                  prevcnt = cnt;
  242.                  cnt = 10L * cnt + (long) (ilet - '0');
  243.                  /* signal presence of cnt */
  244.                  allowcnt = (cnt >= prevcnt) ? 2 : 3;
  245.              }
  246.              ilet = readchar();
  247.          }
  248.          if (allowcnt == 3) {
  249.              /* overflow detected; force cnt to be invalid */
  250.              cnt = -1L;
  251.              allowcnt = 2;
  252.          }
  253.          if (index(quitchars, ilet)) {
  254.              if (flags.verbose)
  255.                  pline1(Never_mind);
  256.              return (struct obj *) 0;
  257.          }
  258.          if (ilet == '-') {
  259.              if (!allownone) {
  260.                  char *suf = (char *) 0;
  261.  
  262.                  strcpy(buf, word);
  263.                  if ((bp = strstr(buf, " on the ")) != 0) {
  264.                      /* rub on the stone[s] */
  265.                      *bp = '\0';
  266.                      suf = (bp + 1);
  267.                  }
  268.                  if ((bp = strstr(buf, " or ")) != 0) {
  269.                      *bp = '\0';
  270.                      bp = (rn2(2) ? buf : (bp + 4));
  271.                  } else
  272.                      bp = buf;
  273.                  You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
  274.                      suf ? suf : "");
  275.              }
  276.              return (allownone ? &zeroobj : (struct obj *) 0);
  277.          }
  278.          /* since gold is now kept in inventory, we need to do processing for
  279.             select-from-invent before checking whether gold has been picked */
  280.          if (ilet == '?' || ilet == '*') {
  281.              char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
  282.              long ctmp = 0;
  283.  
  284.              if (ilet == '?' && !*lets && *altlets)
  285.                  allowed_choices = altlets;
  286.              ilet = display_pickinv(allowed_choices, TRUE,
  287.                                     allowcnt ? &ctmp : (long *) 0);
  288.              if (!ilet)
  289.                  continue;
  290.              if (allowcnt && ctmp >= 0) {
  291.                  cnt = ctmp;
  292.                  if (!cnt)
  293.                      prezero = TRUE;
  294.                  allowcnt = 2;
  295.              }
  296.              if (ilet == '\033') {
  297.                  if (flags.verbose)
  298.                      pline1(Never_mind);
  299.                  return (struct obj *) 0;
  300.              }
  301.              /* they typed a letter (not a space) at the prompt */
  302.          }
  303.          /* find the item which was picked */
  304.          for (otmp = invent; otmp; otmp = otmp->nobj)
  305.              if (otmp->invlet == ilet)
  306.                  break;
  307.          /* some items have restrictions */
  308.          if (ilet == def_oc_syms[COIN_CLASS].sym
  309.              /* guard against the [hypothetical] chace of having more
  310.                 than one invent slot of gold and picking the non-'$' one */
  311.              || (otmp && otmp->oclass == COIN_CLASS)) {
  312.              if (!usegold) {
  313.                  You("cannot %s gold.", word);
  314.                  return (struct obj *) 0;
  315.              }
  316.              /* Historic note: early Nethack had a bug which was
  317.               * first reported for Larn, where trying to drop 2^32-n
  318.               * gold pieces was allowed, and did interesting things
  319.               * to your money supply.  The LRS is the tax bureau
  320.               * from Larn.
  321.               */
  322.              if (allowcnt == 2 && cnt <= 0) {
  323.                  if (cnt < 0 || !prezero)
  324.                      pline_The(
  325.                    "LRS would be very interested to know you have that much.");
  326.                  return (struct obj *) 0;
  327.              }
  328.          }
  329.          if (allowcnt == 2 && !strcmp(word, "throw")) {
  330.              /* permit counts for throwing gold, but don't accept
  331.               * counts for other things since the throw code will
  332.               * split off a single item anyway */
  333.              if (ilet != def_oc_syms[COIN_CLASS].sym
  334.                  && !(otmp && otmp->oclass == COIN_CLASS))
  335.                  allowcnt = 1;
  336.              if (cnt == 0 && prezero)
  337.                  return (struct obj *) 0;
  338.              if (cnt > 1) {
  339.                  You("can only throw one item at a time.");
  340.                  continue;
  341.              }
  342.          }
  343.          context.botl = 1; /* May have changed the amount of money */
  344.          savech(ilet);
  345.          /* [we used to set otmp (by finding ilet in invent) here, but
  346.             that's been moved above so that otmp can be checked earlier] */
  347.          /* verify the chosen object */
  348.          if (!otmp) {
  349.              You("don't have that object.");
  350.              if (in_doagain)
  351.                  return (struct obj *) 0;
  352.              continue;
  353.          } else if (cnt < 0 || otmp->quan < cnt) {
  354.              You("don't have that many!  You have only %ld.", otmp->quan);
  355.              if (in_doagain)
  356.                  return (struct obj *) 0;
  357.              continue;
  358.          }
  359.          break;
  360.      }
  361.      if (!allowall && let && !index(let, otmp->oclass)
  362.          && !(usegold && otmp->oclass == COIN_CLASS)) {
  363.          silly_thing(word, otmp);
  364.          return (struct obj *) 0;
  365.      }
  366.      if (allowcnt == 2) { /* cnt given */
  367.          if (cnt == 0)
  368.              return (struct obj *) 0;
  369.          if (cnt != otmp->quan) {
  370.              /* don't split a stack of cursed loadstones */
  371.              if (splittable(otmp))
  372.                  otmp = splitobj(otmp, cnt);
  373.              else if (otmp->otyp == LOADSTONE && otmp->cursed)
  374.                  /* kludge for canletgo()'s can't-drop-this message */
  375.                  otmp->corpsenm = (int) cnt;
  376.          }
  377.      }
  378.      return otmp;
  379.  }
  380.  

silly_thing

  1.  void
  2.  silly_thing(word, otmp)
  3.  const char *word;
  4.  struct obj *otmp;
  5.  {
  6.  #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
  7.      nhUse(otmp);
  8.  #else
  9.      const char *s1, *s2, *s3, *what;
  10.      int ocls = otmp->oclass, otyp = otmp->otyp;
  11.  
  12.      s1 = s2 = s3 = 0;
  13.      /* check for attempted use of accessory commands ('P','R') on armor
  14.         and for corresponding armor commands ('W','T') on accessories */
  15.      if (ocls == ARMOR_CLASS) {
  16.          if (!strcmp(word, "put on"))
  17.              s1 = "W", s2 = "wear", s3 = "";
  18.          else if (!strcmp(word, "remove"))
  19.              s1 = "T", s2 = "take", s3 = " off";
  20.      } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
  21.                 || ocls == AMULET_CLASS
  22.                 || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
  23.          if (!strcmp(word, "wear"))
  24.              s1 = "P", s2 = "put", s3 = " on";
  25.          else if (!strcmp(word, "take off"))
  26.              s1 = "R", s2 = "remove", s3 = "";
  27.      }
  28.      if (s1) {
  29.          what = "that";
  30.          /* quantity for armor and accessory objects is always 1,
  31.             but some things should be referred to as plural */
  32.          if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
  33.              what = "those";
  34.          pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
  35.      } else
  36.  #endif
  37.          pline(silly_thing_to, word);
  38.  }
  39.  

ckvalidcat

  1.  STATIC_PTR int
  2.  ckvalidcat(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      /* use allow_category() from pickup.c */
  6.      return (int) allow_category(otmp);
  7.  }
  8.  

ckunpaid

  1.  STATIC_PTR int
  2.  ckunpaid(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      return (otmp->unpaid || (Has_contents(otmp) && count_unpaid(otmp->cobj)));
  6.  }
  7.  

wearing_armor

  1.  boolean
  2.  wearing_armor()
  3.  {
  4.      return (boolean) (uarm || uarmc || uarmf || uarmg
  5.                        || uarmh || uarms || uarmu);
  6.  }
  7.  

is_worn

  1.  boolean
  2.  is_worn(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      return (otmp->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE | W_WEAPON))
  6.              ? TRUE
  7.              : FALSE;
  8.  }
  9.  

safeq_xprname

  1.  /* extra xprname() input that askchain() can't pass through safe_qbuf() */
  2.  STATIC_VAR struct xprnctx {
  3.      char let;
  4.      boolean dot;
  5.  } safeq_xprn_ctx;
  6.  
  7.  /* safe_qbuf() -> short_oname() callback */
  8.  STATIC_PTR char *
  9.  safeq_xprname(obj)
  10.  struct obj *obj;
  11.  {
  12.      return xprname(obj, (char *) 0, safeq_xprn_ctx.let, safeq_xprn_ctx.dot,
  13.                     0L, 0L);
  14.  }
  15.  

safeq_shortxprname

  1.  /* alternate safe_qbuf() -> short_oname() callback */
  2.  STATIC_PTR char *
  3.  safeq_shortxprname(obj)
  4.  struct obj *obj;
  5.  {
  6.      return xprname(obj, ansimpleoname(obj), safeq_xprn_ctx.let,
  7.                     safeq_xprn_ctx.dot, 0L, 0L);
  8.  }
  9.  

ggetobj

  1.  static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
  2.                                               RING_CLASS,  AMULET_CLASS,
  3.                                               TOOL_CLASS,  0 };
  4.  
  5.  /* interactive version of getobj - used for Drop, Identify and */
  6.  /* Takeoff (A). Return the number of times fn was called successfully */
  7.  /* If combo is TRUE, we just use this to get a category list */
  8.  int
  9.  ggetobj(word, fn, mx, combo, resultflags)
  10.  const char *word;
  11.  int FDECL((*fn), (OBJ_P)), mx;
  12.  boolean combo; /* combination menu flag */
  13.  unsigned *resultflags;
  14.  {
  15.      int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
  16.      boolean FDECL((*filter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
  17.      boolean takeoff, ident, allflag, m_seen;
  18.      int itemcount;
  19.      int oletct, iletct, unpaid, oc_of_sym;
  20.      char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
  21.      char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
  22.      char buf[BUFSZ], qbuf[QBUFSZ];
  23.  
  24.      if (resultflags)
  25.          *resultflags = 0;
  26.      takeoff = ident = allflag = m_seen = FALSE;
  27.      if (!invent) {
  28.          You("have nothing to %s.", word);
  29.          return 0;
  30.      }
  31.      add_valid_menu_class(0); /* reset */
  32.      if (taking_off(word)) {
  33.          takeoff = TRUE;
  34.          filter = is_worn;
  35.      } else if (!strcmp(word, "identify")) {
  36.          ident = TRUE;
  37.          filter = not_fully_identified;
  38.      }
  39.  
  40.      iletct = collect_obj_classes(ilets, invent, FALSE, filter, &itemcount);
  41.      unpaid = count_unpaid(invent);
  42.  
  43.      if (ident && !iletct) {
  44.          return -1; /* no further identifications */
  45.      } else if (!takeoff && (unpaid || invent)) {
  46.          ilets[iletct++] = ' ';
  47.          if (unpaid)
  48.              ilets[iletct++] = 'u';
  49.          if (count_buc(invent, BUC_BLESSED))
  50.              ilets[iletct++] = 'B';
  51.          if (count_buc(invent, BUC_UNCURSED))
  52.              ilets[iletct++] = 'U';
  53.          if (count_buc(invent, BUC_CURSED))
  54.              ilets[iletct++] = 'C';
  55.          if (count_buc(invent, BUC_UNKNOWN))
  56.              ilets[iletct++] = 'X';
  57.          if (invent)
  58.              ilets[iletct++] = 'a';
  59.      } else if (takeoff && invent) {
  60.          ilets[iletct++] = ' ';
  61.      }
  62.      ilets[iletct++] = 'i';
  63.      if (!combo)
  64.          ilets[iletct++] = 'm'; /* allow menu presentation on request */
  65.      ilets[iletct] = '\0';
  66.  
  67.      for (;;) {
  68.          Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word,
  69.                  ilets);
  70.          getlin(qbuf, buf);
  71.          if (buf[0] == '\033')
  72.              return 0;
  73.          if (index(buf, 'i')) {
  74.              if (display_inventory((char *) 0, TRUE) == '\033')
  75.                  return 0;
  76.          } else
  77.              break;
  78.      }
  79.  
  80.      extra_removeables[0] = '\0';
  81.      if (takeoff) {
  82.          /* arbitrary types of items can be placed in the weapon slots
  83.             [any duplicate entries in extra_removeables[] won't matter] */
  84.          if (uwep)
  85.              (void) strkitten(extra_removeables, uwep->oclass);
  86.          if (uswapwep)
  87.              (void) strkitten(extra_removeables, uswapwep->oclass);
  88.          if (uquiver)
  89.              (void) strkitten(extra_removeables, uquiver->oclass);
  90.      }
  91.  
  92.      ip = buf;
  93.      olets[oletct = 0] = '\0';
  94.      while ((sym = *ip++) != '\0') {
  95.          if (sym == ' ')
  96.              continue;
  97.          oc_of_sym = def_char_to_objclass(sym);
  98.          if (takeoff && oc_of_sym != MAXOCLASSES) {
  99.              if (index(extra_removeables, oc_of_sym)) {
  100.                  ; /* skip rest of takeoff checks */
  101.              } else if (!index(removeables, oc_of_sym)) {
  102.                  pline("Not applicable.");
  103.                  return 0;
  104.              } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
  105.                  noarmor(FALSE);
  106.                  return 0;
  107.              } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
  108.                         && !uquiver) {
  109.                  You("are not wielding anything.");
  110.                  return 0;
  111.              } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
  112.                  You("are not wearing rings.");
  113.                  return 0;
  114.              } else if (oc_of_sym == AMULET_CLASS && !uamul) {
  115.                  You("are not wearing an amulet.");
  116.                  return 0;
  117.              } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
  118.                  You("are not wearing a blindfold.");
  119.                  return 0;
  120.              }
  121.          }
  122.  
  123.          if (oc_of_sym == COIN_CLASS && !combo) {
  124.              context.botl = 1;
  125.          } else if (sym == 'a') {
  126.              allflag = TRUE;
  127.          } else if (sym == 'A') {
  128.              /* same as the default */;
  129.          } else if (sym == 'u') {
  130.              add_valid_menu_class('u');
  131.              ckfn = ckunpaid;
  132.          } else if (sym == 'B') {
  133.              add_valid_menu_class('B');
  134.              ckfn = ckvalidcat;
  135.          } else if (sym == 'U') {
  136.              add_valid_menu_class('U');
  137.              ckfn = ckvalidcat;
  138.          } else if (sym == 'C') {
  139.              add_valid_menu_class('C');
  140.              ckfn = ckvalidcat;
  141.          } else if (sym == 'X') {
  142.              add_valid_menu_class('X');
  143.              ckfn = ckvalidcat;
  144.          } else if (sym == 'm') {
  145.              m_seen = TRUE;
  146.          } else if (oc_of_sym == MAXOCLASSES) {
  147.              You("don't have any %c's.", sym);
  148.          } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
  149.              if (!index(olets, oc_of_sym)) {
  150.                  add_valid_menu_class(oc_of_sym);
  151.                  olets[oletct++] = oc_of_sym;
  152.                  olets[oletct] = 0;
  153.              }
  154.          }
  155.      }
  156.  
  157.      if (m_seen) {
  158.          return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
  159.      } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
  160.          return 0;
  161.  #if 0
  162.      /* !!!! test gold dropping */
  163.      } else if (allowgold == 2 && !oletct) {
  164.          return 1; /* you dropped gold (or at least tried to)  */
  165.  #endif
  166.      } else {
  167.          int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
  168.          /*
  169.           * askchain() has already finished the job in this case
  170.           * so set a special flag to convey that back to the caller
  171.           * so that it won't continue processing.
  172.           * Fix for bug C331-1 reported by Irina Rempt-Drijfhout.
  173.           */
  174.          if (combo && allflag && resultflags)
  175.              *resultflags |= ALL_FINISHED;
  176.          return cnt;
  177.      }
  178.  }
  179.  

askchain

  1.  /*
  2.   * Walk through the chain starting at objchn and ask for all objects
  3.   * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
  4.   * whether the action in question (i.e., fn) has to be performed.
  5.   * If allflag then no questions are asked. Max gives the max nr of
  6.   * objects to be treated. Return the number of objects treated.
  7.   */
  8.  int
  9.  askchain(objchn, olets, allflag, fn, ckfn, mx, word)
  10.  struct obj **objchn;
  11.  register int allflag, mx;
  12.  register const char *olets, *word; /* olets is an Obj Class char array */
  13.  register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
  14.  {
  15.      struct obj *otmp, *otmpo;
  16.      register char sym, ilet;
  17.      register int cnt = 0, dud = 0, tmp;
  18.      boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
  19.      char qbuf[QBUFSZ], qpfx[QBUFSZ];
  20.  
  21.      takeoff = taking_off(word);
  22.      ident = !strcmp(word, "identify");
  23.      take_out = !strcmp(word, "take out");
  24.      put_in = !strcmp(word, "put in");
  25.      nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
  26.               || takeoff || take_out || put_in);
  27.      ininv = (*objchn == invent);
  28.      first = TRUE;
  29.  /* Changed so the askchain is interrogated in the order specified.
  30.   * For example, if a person specifies =/ then first all rings will be
  31.   * asked about followed by all wands -dgk
  32.   */
  33.  nextclass:
  34.      ilet = 'a' - 1;
  35.      if (*objchn && (*objchn)->oclass == COIN_CLASS)
  36.          ilet--;                     /* extra iteration */
  37.      /*
  38.       * Multiple Drop can change the invent chain while it operates
  39.       * (dropping a burning potion of oil while levitating creates
  40.       * an explosion which can destroy inventory items), so simple
  41.       * list traversal
  42.       *  for (otmp = *objchn; otmp; otmp = otmp2) {
  43.       *      otmp2 = otmp->nobj;
  44.       *      ...
  45.       *  }
  46.       * is inadequate here.  Use each object's bypass bit to keep
  47.       * track of which list elements have already been processed.
  48.       */
  49.      bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
  50.      while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
  51.          if (ilet == 'z')
  52.              ilet = 'A';
  53.          else
  54.              ilet++;
  55.          if (olets && *olets && otmp->oclass != *olets)
  56.              continue;
  57.          if (takeoff && !is_worn(otmp))
  58.              continue;
  59.          if (ident && !not_fully_identified(otmp))
  60.              continue;
  61.          if (ckfn && !(*ckfn)(otmp))
  62.              continue;
  63.          if (!allflag) {
  64.              safeq_xprn_ctx.let = ilet;
  65.              safeq_xprn_ctx.dot = !nodot;
  66.              *qpfx = '\0';
  67.              if (first) {
  68.                  /* traditional_loot() skips prompting when only one
  69.                     class of objects is involved, so prefix the first
  70.                     object being queried here with an explanation why */
  71.                  if (take_out || put_in)
  72.                      Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
  73.                  first = FALSE;
  74.              }
  75.              (void) safe_qbuf(
  76.                  qbuf, qpfx, "?", otmp, ininv ? safeq_xprname : doname,
  77.                  ininv ? safeq_shortxprname : ansimpleoname, "item");
  78.              sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
  79.                                                          : nyNaq(qbuf);
  80.          } else
  81.              sym = 'y';
  82.  
  83.          otmpo = otmp;
  84.          if (sym == '#') {
  85.              /* Number was entered; split the object unless it corresponds
  86.                 to 'none' or 'all'.  2 special cases: cursed loadstones and
  87.                 welded weapons (eg, multiple daggers) will remain as merged
  88.                 unit; done to avoid splitting an object that won't be
  89.                 droppable (even if we're picking up rather than dropping).
  90.               */
  91.              if (!yn_number)
  92.                  sym = 'n';
  93.              else {
  94.                  sym = 'y';
  95.                  if (yn_number < otmp->quan && splittable(otmp))
  96.                      otmp = splitobj(otmp, yn_number);
  97.              }
  98.          }
  99.          switch (sym) {
  100.          case 'a':
  101.              allflag = 1;
  102.          case 'y':
  103.              tmp = (*fn)(otmp);
  104.              if (tmp < 0) {
  105.                  if (container_gone(fn)) {
  106.                      /* otmp caused magic bag to explode;
  107.                         both are now gone */
  108.                      otmp = 0; /* and return */
  109.                  } else if (otmp && otmp != otmpo) {
  110.                      /* split occurred, merge again */
  111.                      (void) merged(&otmpo, &otmp);
  112.                  }
  113.                  goto ret;
  114.              }
  115.              cnt += tmp;
  116.              if (--mx == 0)
  117.                  goto ret;
  118.          case 'n':
  119.              if (nodot)
  120.                  dud++;
  121.          default:
  122.              break;
  123.          case 'q':
  124.              /* special case for seffects() */
  125.              if (ident)
  126.                  cnt = -1;
  127.              goto ret;
  128.          }
  129.      }
  130.      if (olets && *olets && *++olets)
  131.          goto nextclass;
  132.      if (!takeoff && (dud || cnt))
  133.          pline("That was all.");
  134.      else if (!dud && !cnt)
  135.          pline("No applicable objects.");
  136.  ret:
  137.      bypass_objlist(*objchn, FALSE);
  138.      return cnt;
  139.  }
  140.  

fully_identify_obj

  1.  /*
  2.   *      Object identification routines:
  3.   */
  4.  
  5.  /* make an object actually be identified; no display updating */
  6.  void
  7.  fully_identify_obj(otmp)
  8.  struct obj *otmp;
  9.  {
  10.      makeknown(otmp->otyp);
  11.      if (otmp->oartifact)
  12.          discover_artifact((xchar) otmp->oartifact);
  13.      otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
  14.      if (Is_container(otmp) || otmp->otyp == STATUE)
  15.          otmp->cknown = otmp->lknown = 1;
  16.      if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
  17.          learn_egg_type(otmp->corpsenm);
  18.  }
  19.  

identify

  1.  /* ggetobj callback routine; identify an object and give immediate feedback */
  2.  int
  3.  identify(otmp)
  4.  struct obj *otmp;
  5.  {
  6.      fully_identify_obj(otmp);
  7.      prinv((char *) 0, otmp, 0L);
  8.      return 1;
  9.  }
  10.  

menu_identify

  1.  /* menu of unidentified objects; select and identify up to id_limit of them */
  2.  STATIC_OVL void
  3.  menu_identify(id_limit)
  4.  int id_limit;
  5.  {
  6.      menu_item *pick_list;
  7.      int n, i, first = 1, tryct = 5;
  8.      char buf[BUFSZ];
  9.      /* assumptions:  id_limit > 0 and at least one unID'd item is present */
  10.  
  11.      while (id_limit) {
  12.          Sprintf(buf, "What would you like to identify %s?",
  13.                  first ? "first" : "next");
  14.          n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE
  15.                                             | USE_INVLET | INVORDER_SORT,
  16.                            &pick_list, PICK_ANY, not_fully_identified);
  17.  
  18.          if (n > 0) {
  19.              if (n > id_limit)
  20.                  n = id_limit;
  21.              for (i = 0; i < n; i++, id_limit--)
  22.                  (void) identify(pick_list[i].item.a_obj);
  23.              free((genericptr_t) pick_list);
  24.              mark_synch(); /* Before we loop to pop open another menu */
  25.              first = 0;
  26.          } else if (n == -2) { /* player used ESC to quit menu */
  27.              break;
  28.          } else if (n == -1) { /* no eligible items found */
  29.              pline("That was all.");
  30.              break;
  31.          } else if (!--tryct) { /* stop re-prompting */
  32.              pline1(thats_enough_tries);
  33.              break;
  34.          } else { /* try again */
  35.              pline("Choose an item; use ESC to decline.");
  36.          }
  37.      }
  38.  }
  39.  

identify_pack

  1.  /* dialog with user to identify a given number of items; 0 means all */
  2.  void
  3.  identify_pack(id_limit, learning_id)
  4.  int id_limit;
  5.  boolean learning_id; /* true if we just read unknown identify scroll */
  6.  {
  7.      struct obj *obj, *the_obj;
  8.      int n, unid_cnt;
  9.  
  10.      unid_cnt = 0;
  11.      the_obj = 0; /* if unid_cnt ends up 1, this will be it */
  12.      for (obj = invent; obj; obj = obj->nobj)
  13.          if (not_fully_identified(obj))
  14.              ++unid_cnt, the_obj = obj;
  15.  
  16.      if (!unid_cnt) {
  17.          You("have already identified all %sof your possessions.",
  18.              learning_id ? "the rest " : "");
  19.      } else if (!id_limit || id_limit >= unid_cnt) {
  20.          /* identify everything */
  21.          if (unid_cnt == 1) {
  22.              (void) identify(the_obj);
  23.          } else {
  24.              /* TODO:  use fully_identify_obj and cornline/menu/whatever here
  25.               */
  26.              for (obj = invent; obj; obj = obj->nobj)
  27.                  if (not_fully_identified(obj))
  28.                      (void) identify(obj);
  29.          }
  30.      } else {
  31.          /* identify up to `id_limit' items */
  32.          n = 0;
  33.          if (flags.menu_style == MENU_TRADITIONAL)
  34.              do {
  35.                  n = ggetobj("identify", identify, id_limit, FALSE,
  36.                              (unsigned *) 0);
  37.                  if (n < 0)
  38.                      break; /* quit or no eligible items */
  39.              } while ((id_limit -= n) > 0);
  40.          if (n == 0 || n < -1)
  41.              menu_identify(id_limit);
  42.      }
  43.      update_inventory();
  44.  }
  45.  

learn_unseen_invent

  1.  /* called when regaining sight; mark inventory objects which were picked
  2.     up while blind as now having been seen */
  3.  void
  4.  learn_unseen_invent()
  5.  {
  6.      struct obj *otmp;
  7.  
  8.      if (Blind)
  9.          return; /* sanity check */
  10.  
  11.      for (otmp = invent; otmp; otmp = otmp->nobj) {
  12.          if (otmp->dknown)
  13.              continue; /* already seen */
  14.          /* set dknown, perhaps bknown (for priest[ess]) */
  15.          (void) xname(otmp);
  16.          /*
  17.           * If object->eknown gets implemented (see learnwand(zap.c)),
  18.           * handle deferred discovery here.
  19.           */
  20.      }
  21.      update_inventory();
  22.  }
  23.  

obj_to_let

  1.  /* should of course only be called for things in invent */
  2.  STATIC_OVL char
  3.  obj_to_let(obj)
  4.  struct obj *obj;
  5.  {
  6.      if (!flags.invlet_constant) {
  7.          obj->invlet = NOINVSYM;
  8.          reassign();
  9.      }
  10.      return obj->invlet;
  11.  }
  12.  

prinv

  1.  /*
  2.   * Print the indicated quantity of the given object.  If quan == 0L then use
  3.   * the current quantity.
  4.   */
  5.  void
  6.  prinv(prefix, obj, quan)
  7.  const char *prefix;
  8.  struct obj *obj;
  9.  long quan;
  10.  {
  11.      if (!prefix)
  12.          prefix = "";
  13.      pline("%s%s%s", prefix, *prefix ? " " : "",
  14.            xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
  15.  }
  16.  

xprname

  1.  char *
  2.  xprname(obj, txt, let, dot, cost, quan)
  3.  struct obj *obj;
  4.  const char *txt; /* text to print instead of obj */
  5.  char let;        /* inventory letter */
  6.  boolean dot;     /* append period; (dot && cost => Iu) */
  7.  long cost;       /* cost (for inventory of unpaid or expended items) */
  8.  long quan;       /* if non-0, print this quantity, not obj->quan */
  9.  {
  10.  #ifdef LINT /* handle static char li[BUFSZ]; */
  11.      char li[BUFSZ];
  12.  #else
  13.      static char li[BUFSZ];
  14.  #endif
  15.      boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
  16.      long savequan = 0;
  17.  
  18.      if (quan && obj) {
  19.          savequan = obj->quan;
  20.          obj->quan = quan;
  21.      }
  22.  
  23.      /*
  24.       * If let is:
  25.       *  *  Then obj == null and we are printing a total amount.
  26.       *  >  Then the object is contained and doesn't have an inventory letter.
  27.       */
  28.      if (cost != 0 || let == '*') {
  29.          /* if dot is true, we're doing Iu, otherwise Ix */
  30.          Sprintf(li, "%c - %-45s %6ld %s",
  31.                  (dot && use_invlet ? obj->invlet : let),
  32.                  (txt ? txt : doname(obj)), cost, currency(cost));
  33.      } else {
  34.          /* ordinary inventory display or pickup message */
  35.          Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
  36.                  (txt ? txt : doname(obj)), (dot ? "." : ""));
  37.      }
  38.      if (savequan)
  39.          obj->quan = savequan;
  40.  
  41.      return li;
  42.  }
  43.  

ddoinv

  1.  /* the 'i' command */
  2.  int
  3.  ddoinv()
  4.  {
  5.      (void) display_inventory((char *) 0, FALSE);
  6.      return 0;
  7.  }
  8.  

find_unpaid

  1.  /*
  2.   * find_unpaid()
  3.   *
  4.   * Scan the given list of objects.  If last_found is NULL, return the first
  5.   * unpaid object found.  If last_found is not NULL, then skip over unpaid
  6.   * objects until last_found is reached, then set last_found to NULL so the
  7.   * next unpaid object is returned.  This routine recursively follows
  8.   * containers.
  9.   */
  10.  STATIC_OVL struct obj *
  11.  find_unpaid(list, last_found)
  12.  struct obj *list, **last_found;
  13.  {
  14.      struct obj *obj;
  15.  
  16.      while (list) {
  17.          if (list->unpaid) {
  18.              if (*last_found) {
  19.                  /* still looking for previous unpaid object */
  20.                  if (list == *last_found)
  21.                      *last_found = (struct obj *) 0;
  22.              } else
  23.                  return ((*last_found = list));
  24.          }
  25.          if (Has_contents(list)) {
  26.              if ((obj = find_unpaid(list->cobj, last_found)) != 0)
  27.                  return obj;
  28.          }
  29.          list = list->nobj;
  30.      }
  31.      return (struct obj *) 0;
  32.  }
  33.  

free_pickinv_cache

  1.  /* for perm_invent when operating on a partial inventory display, so that
  2.     the persistent one doesn't get shrunk during filtering for item selection
  3.     then regrown to full inventory, possibly being resized in the process */
  4.  static winid cached_pickinv_win = WIN_ERR;
  5.  
  6.  void
  7.  free_pickinv_cache()
  8.  {
  9.      if (cached_pickinv_win != WIN_ERR) {
  10.          destroy_nhwindow(cached_pickinv_win);
  11.          cached_pickinv_win = WIN_ERR;
  12.      }
  13.  }
  14.  

display_pickinv

  1.  /*
  2.   * Internal function used by display_inventory and getobj that can display
  3.   * inventory and return a count as well as a letter. If out_cnt is not null,
  4.   * any count returned from the menu selection is placed here.
  5.   */
  6.  STATIC_OVL char
  7.  display_pickinv(lets, want_reply, out_cnt)
  8.  register const char *lets;
  9.  boolean want_reply;
  10.  long *out_cnt;
  11.  {
  12.      struct obj *otmp;
  13.      char ilet, ret;
  14.      char *invlet = flags.inv_order;
  15.      int i, n, classcount;
  16.      winid win;                        /* windows being used */
  17.      anything any;
  18.      menu_item *selected;
  19.      struct obj **oarray;
  20.  
  21.      if (flags.perm_invent && lets && *lets) {
  22.          /* partial inventory in perm_invent setting; don't operate on
  23.             full inventory window, use an alternate one instead; create
  24.             the first time needed and keep it for re-use as needed later */
  25.          if (cached_pickinv_win == WIN_ERR)
  26.              cached_pickinv_win = create_nhwindow(NHW_MENU);
  27.          win = cached_pickinv_win;
  28.      } else
  29.          win = WIN_INVEN;
  30.  
  31.      /*
  32.       * Exit early if no inventory -- but keep going if we are doing
  33.       * a permanent inventory update.  We need to keep going so the
  34.       * permanent inventory window updates itself to remove the last
  35.       * item(s) dropped.  One down side:  the addition of the exception
  36.       * for permanent inventory window updates _can_ pop the window
  37.       * up when it's not displayed -- even if it's empty -- because we
  38.       * don't know at this level if its up or not.  This may not be
  39.       * an issue if empty checks are done before hand and the call
  40.       * to here is short circuited away.
  41.       */
  42.      if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
  43.          pline("Not carrying anything.");
  44.          return 0;
  45.      }
  46.  
  47.      /* oxymoron? temporarily assign permanent inventory letters */
  48.      if (!flags.invlet_constant)
  49.          reassign();
  50.  
  51.      if (lets && strlen(lets) == 1 && !iflags.override_ID) {
  52.          /* when only one item of interest, use pline instead of menus;
  53.             we actually use a fake message-line menu in order to allow
  54.             the user to perform selection at the --More-- prompt for tty */
  55.          ret = '\0';
  56.          for (otmp = invent; otmp; otmp = otmp->nobj) {
  57.              if (otmp->invlet == lets[0]) {
  58.                  ret = message_menu(
  59.                      lets[0], want_reply ? PICK_ONE : PICK_NONE,
  60.                      xprname(otmp, (char *) 0, lets[0], TRUE, 0L, 0L));
  61.                  if (out_cnt)
  62.                      *out_cnt = -1L; /* select all */
  63.                  break;
  64.              }
  65.          }
  66.          return ret;
  67.      }
  68.  
  69.      /* count the number of items */
  70.      for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
  71.          if (!lets || !*lets || index(lets, otmp->invlet))
  72.              n++;
  73.  
  74.      oarray = objarr_init(n);
  75.  
  76.      /* Add objects to the array */
  77.      i = 0;
  78.      for (otmp = invent; otmp; otmp = otmp->nobj)
  79.          if (!lets || !*lets || index(lets, otmp->invlet)) {
  80.              objarr_set(otmp, i++, oarray, (flags.sortloot == 'f'));
  81.          }
  82.  
  83.      start_menu(win);
  84.      any = zeroany;
  85.      if (wizard && iflags.override_ID) {
  86.          char prompt[BUFSZ];
  87.          any.a_char = -1;
  88.          /* wiz_identify stuffed the wiz_identify cmd character
  89.             into iflags.override_ID */
  90.          Sprintf(prompt, "Debug Identify (%s to permanently identify)",
  91.                  visctrl(iflags.override_ID));
  92.          add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
  93.                   prompt, MENU_UNSELECTED);
  94.      }
  95.  nextclass:
  96.      classcount = 0;
  97.      any = zeroany; /* set all bits to zero */
  98.      for (i = 0; i < n; i++) {
  99.          otmp = oarray[i];
  100.          ilet = otmp->invlet;
  101.          any = zeroany; /* zero */
  102.          if (!flags.sortpack || otmp->oclass == *invlet) {
  103.              if (flags.sortpack && !classcount) {
  104.                  add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
  105.                           let_to_name(*invlet, FALSE,
  106.                                       (want_reply && iflags.menu_head_objsym)),
  107.                           MENU_UNSELECTED);
  108.                  classcount++;
  109.              }
  110.              any.a_char = ilet;
  111.              add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
  112.                       doname(otmp), MENU_UNSELECTED);
  113.          }
  114.      }
  115.      if (flags.sortpack) {
  116.          if (*++invlet)
  117.              goto nextclass;
  118.          if (--invlet != venom_inv) {
  119.              invlet = venom_inv;
  120.              goto nextclass;
  121.          }
  122.      }
  123.      free(oarray);
  124.      end_menu(win, (char *) 0);
  125.  
  126.      n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
  127.      if (n > 0) {
  128.          ret = selected[0].item.a_char;
  129.          if (out_cnt)
  130.              *out_cnt = selected[0].count;
  131.          free((genericptr_t) selected);
  132.      } else
  133.          ret = !n ? '\0' : '\033'; /* cancelled */
  134.  
  135.      return ret;
  136.  }
  137.  

display_inventory

  1.  /*
  2.   * If lets == NULL or "", list all objects in the inventory.  Otherwise,
  3.   * list all objects with object classes that match the order in lets.
  4.   *
  5.   * Returns the letter identifier of a selected item, or 0 if nothing
  6.   * was selected.
  7.   */
  8.  char
  9.  display_inventory(lets, want_reply)
  10.  const char *lets;
  11.  boolean want_reply;
  12.  {
  13.      return display_pickinv(lets, want_reply, (long *) 0);
  14.  }
  15.  

display_used_invlets

  1.  /*
  2.   * Show what is current using inventory letters.
  3.   *
  4.   */
  5.  STATIC_OVL char
  6.  display_used_invlets(avoidlet)
  7.  char avoidlet;
  8.  {
  9.      struct obj *otmp;
  10.      char ilet, ret = 0;
  11.      char *invlet = flags.inv_order;
  12.      int n, classcount, invdone = 0;
  13.      winid win;
  14.      anything any;
  15.      menu_item *selected;
  16.  
  17.      if (invent) {
  18.          win = create_nhwindow(NHW_MENU);
  19.          start_menu(win);
  20.          while (!invdone) {
  21.              any = zeroany; /* set all bits to zero */
  22.              classcount = 0;
  23.              for (otmp = invent; otmp; otmp = otmp->nobj) {
  24.                  ilet = otmp->invlet;
  25.                  if (ilet == avoidlet)
  26.                      continue;
  27.                  if (!flags.sortpack || otmp->oclass == *invlet) {
  28.                      if (flags.sortpack && !classcount) {
  29.                          any = zeroany; /* zero */
  30.                          add_menu(win, NO_GLYPH, &any, 0, 0,
  31.                                   iflags.menu_headings,
  32.                                   let_to_name(*invlet, FALSE, FALSE),
  33.                                   MENU_UNSELECTED);
  34.                          classcount++;
  35.                      }
  36.                      any.a_char = ilet;
  37.                      add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
  38.                               doname(otmp), MENU_UNSELECTED);
  39.                  }
  40.              }
  41.              if (flags.sortpack && *++invlet)
  42.                  continue;
  43.              invdone = 1;
  44.          }
  45.          end_menu(win, "Inventory letters used:");
  46.  
  47.          n = select_menu(win, PICK_NONE, &selected);
  48.          if (n > 0) {
  49.              ret = selected[0].item.a_char;
  50.              free((genericptr_t) selected);
  51.          } else
  52.              ret = !n ? '\0' : '\033'; /* cancelled */
  53.          destroy_nhwindow(win);
  54.      }
  55.      return ret;
  56.  }
  57.  

count_unpaid

  1.  /*
  2.   * Returns the number of unpaid items within the given list.  This includes
  3.   * contained objects.
  4.   */
  5.  int
  6.  count_unpaid(list)
  7.  struct obj *list;
  8.  {
  9.      int count = 0;
  10.  
  11.      while (list) {
  12.          if (list->unpaid)
  13.              count++;
  14.          if (Has_contents(list))
  15.              count += count_unpaid(list->cobj);
  16.          list = list->nobj;
  17.      }
  18.      return count;
  19.  }
  20.  

count_buc

  1.  /*
  2.   * Returns the number of items with b/u/c/unknown within the given list.
  3.   * This does NOT include contained objects.
  4.   *
  5.   * Assumes that the hero sees or touches or otherwise senses the objects
  6.   * at some point:  bknown is forced for priest[ess], like in xname().
  7.   */
  8.  int
  9.  count_buc(list, type)
  10.  struct obj *list;
  11.  int type;
  12.  {
  13.      int count = 0;
  14.  
  15.      for (; list; list = list->nobj) {
  16.          /* coins are "none of the above" as far as BUCX filtering goes */
  17.          if (list->oclass == COIN_CLASS)
  18.              continue;
  19.          /* priests always know bless/curse state */
  20.          if (Role_if(PM_PRIEST))
  21.              list->bknown = 1;
  22.  
  23.          /* check whether this object matches the requested type */
  24.          if (!list->bknown
  25.                  ? (type == BUC_UNKNOWN)
  26.                  : list->blessed ? (type == BUC_BLESSED)
  27.                                  : list->cursed ? (type == BUC_CURSED)
  28.                                                 : (type == BUC_UNCURSED))
  29.              ++count;
  30.      }
  31.      return count;
  32.  }
  33.  

tally_BUCX

  1.  /* similar to count_buc(), but tallies all states at once
  2.     rather than looking for a specific type */
  3.  STATIC_OVL void
  4.  tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
  5.  struct obj *list;
  6.  int *bcp, *ucp, *ccp, *xcp, *ocp;
  7.  {
  8.      *bcp = *ucp = *ccp = *xcp = *ocp = 0;
  9.      for (; list; list = list->nobj) {
  10.          if (list->oclass == COIN_CLASS) {
  11.              ++(*ocp); /* "other" */
  12.              continue;
  13.          }
  14.          /* priests always know bless/curse state */
  15.          if (Role_if(PM_PRIEST))
  16.              list->bknown = 1;
  17.  
  18.          if (!list->bknown)
  19.              ++(*xcp);
  20.          else if (list->blessed)
  21.              ++(*bcp);
  22.          else if (list->cursed)
  23.              ++(*ccp);
  24.          else /* neither blessed nor cursed => uncursed */
  25.              ++(*ucp);
  26.      }
  27.  }
  28.  

count_contents

  1.  long
  2.  count_contents(container, nested, quantity, everything)
  3.  struct obj *container;
  4.  boolean nested, /* include contents of any nested containers */
  5.      quantity,   /* count all vs count separate stacks */
  6.      everything; /* all objects vs only unpaid objects */
  7.  {
  8.      struct obj *otmp;
  9.      long count = 0L;
  10.  
  11.      for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
  12.          if (nested && Has_contents(otmp))
  13.              count += count_contents(otmp, nested, quantity, everything);
  14.          if (everything || otmp->unpaid)
  15.              count += quantity ? otmp->quan : 1L;
  16.      }
  17.      return count;
  18.  }
  19.  

dounpaid

  1.  STATIC_OVL void
  2.  dounpaid()
  3.  {
  4.      winid win;
  5.      struct obj *otmp, *marker;
  6.      register char ilet;
  7.      char *invlet = flags.inv_order;
  8.      int classcount, count, num_so_far;
  9.      long cost, totcost;
  10.  
  11.      count = count_unpaid(invent);
  12.  
  13.      if (count == 1) {
  14.          marker = (struct obj *) 0;
  15.          otmp = find_unpaid(invent, &marker);
  16.          cost = unpaid_cost(otmp, FALSE);
  17.          iflags.suppress_price++; /* suppress "(unpaid)" suffix */
  18.          pline1(xprname(otmp, distant_name(otmp, doname),
  19.                         carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
  20.                         cost, 0L));
  21.          iflags.suppress_price--;
  22.          return;
  23.      }
  24.  
  25.      win = create_nhwindow(NHW_MENU);
  26.      cost = totcost = 0;
  27.      num_so_far = 0; /* count of # printed so far */
  28.      if (!flags.invlet_constant)
  29.          reassign();
  30.  
  31.      do {
  32.          classcount = 0;
  33.          for (otmp = invent; otmp; otmp = otmp->nobj) {
  34.              ilet = otmp->invlet;
  35.              if (otmp->unpaid) {
  36.                  if (!flags.sortpack || otmp->oclass == *invlet) {
  37.                      if (flags.sortpack && !classcount) {
  38.                          putstr(win, 0, let_to_name(*invlet, TRUE, FALSE));
  39.                          classcount++;
  40.                      }
  41.  
  42.                      totcost += cost = unpaid_cost(otmp, FALSE);
  43.                      iflags.suppress_price++; /* suppress "(unpaid)" suffix */
  44.                      putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
  45.                                             ilet, TRUE, cost, 0L));
  46.                      iflags.suppress_price--;
  47.                      num_so_far++;
  48.                  }
  49.              }
  50.          }
  51.      } while (flags.sortpack && (*++invlet));
  52.  
  53.      if (count > num_so_far) {
  54.          /* something unpaid is contained */
  55.          if (flags.sortpack)
  56.              putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE, FALSE));
  57.          /*
  58.           * Search through the container objects in the inventory for
  59.           * unpaid items.  The top level inventory items have already
  60.           * been listed.
  61.           */
  62.          for (otmp = invent; otmp; otmp = otmp->nobj) {
  63.              if (Has_contents(otmp)) {
  64.                  long contcost = 0L;
  65.  
  66.                  marker = (struct obj *) 0; /* haven't found any */
  67.                  while (find_unpaid(otmp->cobj, &marker)) {
  68.                      totcost += cost = unpaid_cost(marker, FALSE);
  69.                      contcost += cost;
  70.                      if (otmp->cknown) {
  71.                          iflags.suppress_price++; /* suppress "(unpaid)" sfx */
  72.                          putstr(win, 0,
  73.                                 xprname(marker, distant_name(marker, doname),
  74.                                         CONTAINED_SYM, TRUE, cost, 0L));
  75.                          iflags.suppress_price--;
  76.                      }
  77.                  }
  78.                  if (!otmp->cknown) {
  79.                      char contbuf[BUFSZ];
  80.  
  81.                      /* Shopkeeper knows what to charge for contents */
  82.                      Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
  83.                      putstr(win, 0,
  84.                             xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
  85.                                     TRUE, contcost, 0L));
  86.                  }
  87.              }
  88.          }
  89.      }
  90.  
  91.      putstr(win, 0, "");
  92.      putstr(win, 0,
  93.             xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
  94.      display_nhwindow(win, FALSE);
  95.      destroy_nhwindow(win);
  96.  }
  97.  

this_type_only

  1.  /* query objlist callback: return TRUE if obj type matches "this_type" */
  2.  static int this_type;
  3.  
  4.  STATIC_OVL boolean
  5.  this_type_only(obj)
  6.  struct obj *obj;
  7.  {
  8.      boolean res = (obj->oclass == this_type);
  9.  
  10.      if (obj->oclass != COIN_CLASS) {
  11.          switch (this_type) {
  12.          case 'B':
  13.              res = (obj->bknown && obj->blessed);
  14.              break;
  15.          case 'U':
  16.              res = (obj->bknown && !(obj->blessed || obj->cursed));
  17.              break;
  18.          case 'C':
  19.              res = (obj->bknown && obj->cursed);
  20.              break;
  21.          case 'X':
  22.              res = !obj->bknown;
  23.              break;
  24.          default:
  25.              break; /* use 'res' as-is */
  26.          }
  27.      }
  28.      return res;
  29.  }
  30.  

dotypeinv

  1.  /* the 'I' command */
  2.  int
  3.  dotypeinv()
  4.  {
  5.      char c = '\0';
  6.      int n, i = 0;
  7.      char *extra_types, types[BUFSZ];
  8.      int class_count, oclass, unpaid_count, itemcount;
  9.      int bcnt, ccnt, ucnt, xcnt, ocnt;
  10.      boolean billx = *u.ushops && doinvbill(0);
  11.      menu_item *pick_list;
  12.      boolean traditional = TRUE;
  13.      const char *prompt = "What type of object do you want an inventory of?";
  14.  
  15.      if (!invent && !billx) {
  16.          You("aren't carrying anything.");
  17.          return 0;
  18.      }
  19.      unpaid_count = count_unpaid(invent);
  20.      tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
  21.  
  22.      if (flags.menu_style != MENU_TRADITIONAL) {
  23.          if (flags.menu_style == MENU_FULL
  24.              || flags.menu_style == MENU_PARTIAL) {
  25.              traditional = FALSE;
  26.              i = UNPAID_TYPES;
  27.              if (billx)
  28.                  i |= BILLED_TYPES;
  29.              if (bcnt)
  30.                  i |= BUC_BLESSED;
  31.              if (ucnt)
  32.                  i |= BUC_UNCURSED;
  33.              if (ccnt)
  34.                  i |= BUC_CURSED;
  35.              if (xcnt)
  36.                  i |= BUC_UNKNOWN;
  37.              n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
  38.              if (!n)
  39.                  return 0;
  40.              this_type = c = pick_list[0].item.a_int;
  41.              free((genericptr_t) pick_list);
  42.          }
  43.      }
  44.      if (traditional) {
  45.          /* collect a list of classes of objects carried, for use as a prompt
  46.           */
  47.          types[0] = 0;
  48.          class_count =
  49.              collect_obj_classes(types, invent, FALSE,
  50.                                  (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
  51.          if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
  52.              types[class_count++] = ' ';
  53.          if (unpaid_count)
  54.              types[class_count++] = 'u';
  55.          if (billx)
  56.              types[class_count++] = 'x';
  57.          if (bcnt)
  58.              types[class_count++] = 'B';
  59.          if (ucnt)
  60.              types[class_count++] = 'U';
  61.          if (ccnt)
  62.              types[class_count++] = 'C';
  63.          if (xcnt)
  64.              types[class_count++] = 'X';
  65.          types[class_count] = '\0';
  66.          /* add everything not already included; user won't see these */
  67.          extra_types = eos(types);
  68.          *extra_types++ = '\033';
  69.          if (!unpaid_count)
  70.              *extra_types++ = 'u';
  71.          if (!billx)
  72.              *extra_types++ = 'x';
  73.          if (!bcnt)
  74.              *extra_types++ = 'B';
  75.          if (!ucnt)
  76.              *extra_types++ = 'U';
  77.          if (!ccnt)
  78.              *extra_types++ = 'C';
  79.          if (!xcnt)
  80.              *extra_types++ = 'X';
  81.          *extra_types = '\0'; /* for index() */
  82.          for (i = 0; i < MAXOCLASSES; i++)
  83.              if (!index(types, def_oc_syms[i].sym)) {
  84.                  *extra_types++ = def_oc_syms[i].sym;
  85.                  *extra_types = '\0';
  86.              }
  87.  
  88.          if (class_count > 1) {
  89.              c = yn_function(prompt, types, '\0');
  90.              savech(c);
  91.              if (c == '\0') {
  92.                  clear_nhwindow(WIN_MESSAGE);
  93.                  return 0;
  94.              }
  95.          } else {
  96.              /* only one thing to itemize */
  97.              if (unpaid_count)
  98.                  c = 'u';
  99.              else if (billx)
  100.                  c = 'x';
  101.              else
  102.                  c = types[0];
  103.          }
  104.      }
  105.      if (c == 'x' || (c == 'X' && billx && !xcnt)) {
  106.          if (billx)
  107.              (void) doinvbill(1);
  108.          else
  109.              pline("No used-up objects%s.",
  110.                    unpaid_count ? " on your shopping bill" : "");
  111.          return 0;
  112.      }
  113.      if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
  114.          if (unpaid_count)
  115.              dounpaid();
  116.          else
  117.              You("are not carrying any unpaid objects.");
  118.          return 0;
  119.      }
  120.      if (traditional) {
  121.          if (index("BUCX", c))
  122.              oclass = c; /* not a class but understood by this_type_only() */
  123.          else
  124.              oclass = def_char_to_objclass(c); /* change to object class */
  125.  
  126.          if (oclass == COIN_CLASS)
  127.              return doprgold();
  128.          if (index(types, c) > index(types, '\033')) {
  129.              /* '> ESC' => hidden choice, something known not to be carried */
  130.              const char *which = 0;
  131.  
  132.              switch (c) {
  133.              case 'B':
  134.                  which = "known to be blessed";
  135.                  break;
  136.              case 'U':
  137.                  which = "known to be uncursed";
  138.                  break;
  139.              case 'C':
  140.                  which = "known to be cursed";
  141.                  break;
  142.              case 'X':
  143.                  You(
  144.            "have no objects whose blessed/uncursed/cursed status is unknown.");
  145.                  break; /* better phrasing is desirable */
  146.              default:
  147.                  which = "such";
  148.                  break;
  149.              }
  150.              if (which)
  151.                  You("have no %s objects.", which);
  152.              return 0;
  153.          }
  154.          this_type = oclass;
  155.      }
  156.      if (query_objlist((char *) 0, invent,
  157.                        (flags.invlet_constant ? USE_INVLET : 0)
  158.                            | INVORDER_SORT,
  159.                        &pick_list, PICK_NONE, this_type_only) > 0)
  160.          free((genericptr_t) pick_list);
  161.      return 0;
  162.  }
  163.  

dfeature_at

  1.  /* return a string describing the dungeon feature at <x,y> if there
  2.     is one worth mentioning at that location; otherwise null */
  3.  const char *
  4.  dfeature_at(x, y, buf)
  5.  int x, y;
  6.  char *buf;
  7.  {
  8.      struct rm *lev = &levl[x][y];
  9.      int ltyp = lev->typ, cmap = -1;
  10.      const char *dfeature = 0;
  11.      static char altbuf[BUFSZ];
  12.  
  13.      if (IS_DOOR(ltyp)) {
  14.          switch (lev->doormask) {
  15.          case D_NODOOR:
  16.              cmap = S_ndoor;
  17.              break; /* "doorway" */
  18.          case D_ISOPEN:
  19.              cmap = S_vodoor;
  20.              break; /* "open door" */
  21.          case D_BROKEN:
  22.              dfeature = "broken door";
  23.              break;
  24.          default:
  25.              cmap = S_vcdoor;
  26.              break; /* "closed door" */
  27.          }
  28.          /* override door description for open drawbridge */
  29.          if (is_drawbridge_wall(x, y) >= 0)
  30.              dfeature = "open drawbridge portcullis", cmap = -1;
  31.      } else if (IS_FOUNTAIN(ltyp))
  32.          cmap = S_fountain; /* "fountain" */
  33.      else if (IS_THRONE(ltyp))
  34.          cmap = S_throne; /* "opulent throne" */
  35.      else if (is_lava(x, y))
  36.          cmap = S_lava; /* "molten lava" */
  37.      else if (is_ice(x, y))
  38.          cmap = S_ice; /* "ice" */
  39.      else if (is_pool(x, y))
  40.          dfeature = "pool of water";
  41.      else if (IS_SINK(ltyp))
  42.          cmap = S_sink; /* "sink" */
  43.      else if (IS_ALTAR(ltyp)) {
  44.          Sprintf(altbuf, "%saltar to %s (%s)",
  45.                  ((lev->altarmask & AM_SHRINE)
  46.                   && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
  47.                      ? "high "
  48.                      : "",
  49.                  a_gname(),
  50.                  align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
  51.          dfeature = altbuf;
  52.      } else if ((x == xupstair && y == yupstair)
  53.                 || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
  54.          cmap = S_upstair; /* "staircase up" */
  55.      else if ((x == xdnstair && y == ydnstair)
  56.               || (x == sstairs.sx && y == sstairs.sy && !sstairs.up))
  57.          cmap = S_dnstair; /* "staircase down" */
  58.      else if (x == xupladder && y == yupladder)
  59.          cmap = S_upladder; /* "ladder up" */
  60.      else if (x == xdnladder && y == ydnladder)
  61.          cmap = S_dnladder; /* "ladder down" */
  62.      else if (ltyp == DRAWBRIDGE_DOWN)
  63.          cmap = S_vodbridge; /* "lowered drawbridge" */
  64.      else if (ltyp == DBWALL)
  65.          cmap = S_vcdbridge; /* "raised drawbridge" */
  66.      else if (IS_GRAVE(ltyp))
  67.          cmap = S_grave; /* "grave" */
  68.      else if (ltyp == TREE)
  69.          cmap = S_tree; /* "tree" */
  70.      else if (ltyp == IRONBARS)
  71.          dfeature = "set of iron bars";
  72.  
  73.      if (cmap >= 0)
  74.          dfeature = defsyms[cmap].explanation;
  75.      if (dfeature)
  76.          Strcpy(buf, dfeature);
  77.      return dfeature;
  78.  }
  79.  

look_here

  1.  /* look at what is here; if there are many objects (pile_limit or more),
  2.     don't show them unless obj_cnt is 0 */
  3.  int
  4.  look_here(obj_cnt, picked_some)
  5.  int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
  6.  boolean picked_some;
  7.  {
  8.      struct obj *otmp;
  9.      struct trap *trap;
  10.      const char *verb = Blind ? "feel" : "see";
  11.      const char *dfeature = (char *) 0;
  12.      char fbuf[BUFSZ], fbuf2[BUFSZ];
  13.      winid tmpwin;
  14.      boolean skip_objects, felt_cockatrice = FALSE;
  15.  
  16.      /* default pile_limit is 5; a value of 0 means "never skip"
  17.         (and 1 effectively forces "always skip") */
  18.      skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
  19.      if (u.uswallow && u.ustuck) {
  20.          struct monst *mtmp = u.ustuck;
  21.          Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
  22.                  mbodypart(mtmp, STOMACH));
  23.          /* Skip "Contents of " by using fbuf index 12 */
  24.          You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
  25.              verb, &fbuf[12]);
  26.          otmp = mtmp->minvent;
  27.          if (otmp) {
  28.              for (; otmp; otmp = otmp->nobj) {
  29.                  /* If swallower is an animal, it should have become stone
  30.                   * but... */
  31.                  if (otmp->otyp == CORPSE)
  32.                      feel_cockatrice(otmp, FALSE);
  33.              }
  34.              if (Blind)
  35.                  Strcpy(fbuf, "You feel");
  36.              Strcat(fbuf, ":");
  37.              (void) display_minventory(mtmp, MINV_ALL, fbuf);
  38.          } else {
  39.              You("%s no objects here.", verb);
  40.          }
  41.          return !!Blind;
  42.      }
  43.      if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
  44.          There("is %s here.",
  45.                an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
  46.  
  47.      otmp = level.objects[u.ux][u.uy];
  48.      dfeature = dfeature_at(u.ux, u.uy, fbuf2);
  49.      if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
  50.          dfeature = 0;
  51.  
  52.      if (Blind) {
  53.          boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
  54.  
  55.          if (dfeature && !strncmp(dfeature, "altar ", 6)) {
  56.              /* don't say "altar" twice, dfeature has more info */
  57.              You("try to feel what is here.");
  58.          } else {
  59.              const char *where = (Blind && !can_reach_floor(TRUE))
  60.                                      ? "lying beneath you"
  61.                                      : "lying here on the ",
  62.                         *onwhat = (Blind && !can_reach_floor(TRUE))
  63.                                       ? ""
  64.                                       : surface(u.ux, u.uy);
  65.  
  66.              You("try to feel what is %s%s.", drift ? "floating here" : where,
  67.                  drift ? "" : onwhat);
  68.          }
  69.          if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
  70.              dfeature = 0; /* ice already identified */
  71.          if (!can_reach_floor(TRUE)) {
  72.              pline("But you can't reach it!");
  73.              return 0;
  74.          }
  75.      }
  76.  
  77.      if (dfeature)
  78.          Sprintf(fbuf, "There is %s here.", an(dfeature));
  79.  
  80.      if (!otmp || is_lava(u.ux, u.uy)
  81.          || (is_pool(u.ux, u.uy) && !Underwater)) {
  82.          if (dfeature)
  83.              pline1(fbuf);
  84.          read_engr_at(u.ux, u.uy); /* Eric Backus */
  85.          if (!skip_objects && (Blind || !dfeature))
  86.              You("%s no objects here.", verb);
  87.          return !!Blind;
  88.      }
  89.      /* we know there is something here */
  90.  
  91.      if (skip_objects) {
  92.          if (dfeature)
  93.              pline1(fbuf);
  94.          read_engr_at(u.ux, u.uy); /* Eric Backus */
  95.          if (obj_cnt == 1 && otmp->quan == 1L)
  96.              There("is %s object here.", picked_some ? "another" : "an");
  97.          else
  98.              There("are %s%s objects here.",
  99.                    (obj_cnt < 5)
  100.                        ? "a few"
  101.                        : (obj_cnt < 10)
  102.                            ? "several"
  103.                            : "many",
  104.                    picked_some ? " more" : "");
  105.          for (; otmp; otmp = otmp->nexthere)
  106.              if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
  107.                  pline("%s %s%s.",
  108.                        (obj_cnt > 1)
  109.                            ? "Including"
  110.                            : (otmp->quan > 1L)
  111.                                ? "They're"
  112.                                : "It's",
  113.                        corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
  114.                        poly_when_stoned(youmonst.data)
  115.                            ? ""
  116.                            : ", unfortunately");
  117.                  feel_cockatrice(otmp, FALSE);
  118.                  break;
  119.              }
  120.      } else if (!otmp->nexthere) {
  121.          /* only one object */
  122.          if (dfeature)
  123.              pline1(fbuf);
  124.          read_engr_at(u.ux, u.uy); /* Eric Backus */
  125.          You("%s here %s.", verb, doname_with_price(otmp));
  126.          iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
  127.          if (otmp->otyp == CORPSE)
  128.              feel_cockatrice(otmp, FALSE);
  129.      } else {
  130.          char buf[BUFSZ];
  131.  
  132.          display_nhwindow(WIN_MESSAGE, FALSE);
  133.          tmpwin = create_nhwindow(NHW_MENU);
  134.          if (dfeature) {
  135.              putstr(tmpwin, 0, fbuf);
  136.              putstr(tmpwin, 0, "");
  137.          }
  138.          Sprintf(buf, "%s that %s here:",
  139.                  picked_some ? "Other things" : "Things",
  140.                  Blind ? "you feel" : "are");
  141.          putstr(tmpwin, 0, buf);
  142.          for (; otmp; otmp = otmp->nexthere) {
  143.              if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
  144.                  felt_cockatrice = TRUE;
  145.                  Sprintf(buf, "%s...", doname(otmp));
  146.                  putstr(tmpwin, 0, buf);
  147.                  break;
  148.              }
  149.              putstr(tmpwin, 0, doname_with_price(otmp));
  150.          }
  151.          display_nhwindow(tmpwin, TRUE);
  152.          destroy_nhwindow(tmpwin);
  153.          if (felt_cockatrice)
  154.              feel_cockatrice(otmp, FALSE);
  155.          read_engr_at(u.ux, u.uy); /* Eric Backus */
  156.      }
  157.      return !!Blind;
  158.  }
  159.  

dolook

  1.  /* the ':' command - explicitly look at what is here, including all objects */
  2.  int
  3.  dolook()
  4.  {
  5.      return look_here(0, FALSE);
  6.  }
  7.  

will_feel_cockatrice

  1.  boolean
  2.  will_feel_cockatrice(otmp, force_touch)
  3.  struct obj *otmp;
  4.  boolean force_touch;
  5.  {
  6.      if ((Blind || force_touch) && !uarmg && !Stone_resistance
  7.          && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])))
  8.          return TRUE;
  9.      return FALSE;
  10.  }
  11.  

feel_cockatrice

  1.  void
  2.  feel_cockatrice(otmp, force_touch)
  3.  struct obj *otmp;
  4.  boolean force_touch;
  5.  {
  6.      char kbuf[BUFSZ];
  7.  
  8.      if (will_feel_cockatrice(otmp, force_touch)) {
  9.          /* "the <cockatrice> corpse" */
  10.          Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
  11.  
  12.          if (poly_when_stoned(youmonst.data))
  13.              You("touched %s with your bare %s.", kbuf,
  14.                  makeplural(body_part(HAND)));
  15.          else
  16.              pline("Touching %s is a fatal mistake...", kbuf);
  17.          /* normalize body shape here; hand, not body_part(HAND) */
  18.          Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
  19.          /* will call polymon() for the poly_when_stoned() case */
  20.          instapetrify(kbuf);
  21.      }
  22.  }
  23.  

stackobj

  1.  void
  2.  stackobj(obj)
  3.  struct obj *obj;
  4.  {
  5.      struct obj *otmp;
  6.  
  7.      for (otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
  8.          if (otmp != obj && merged(&obj, &otmp))
  9.              break;
  10.      return;
  11.  }
  12.  

mergable

  1.  /* returns TRUE if obj  & otmp can be merged */
  2.  STATIC_OVL boolean
  3.  mergable(otmp, obj)
  4.  register struct obj *otmp, *obj;
  5.  {
  6.      int objnamelth = 0, otmpnamelth = 0;
  7.      if (obj == otmp)
  8.          return FALSE; /* already the same object */
  9.      if (obj->otyp != otmp->otyp)
  10.          return FALSE;
  11.      /* coins of the same kind will always merge */
  12.      if (obj->oclass == COIN_CLASS)
  13.          return TRUE;
  14.      if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
  15.          || obj->dknown != otmp->dknown
  16.          || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
  17.          || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
  18.          || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
  19.          || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
  20.          || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded
  21.          || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass)
  22.          return FALSE;
  23.  
  24.      if (obj->nomerge) /* explicitly marked to prevent merge */
  25.          return FALSE;
  26.  
  27.      if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
  28.          && (obj->oerodeproof != otmp->oerodeproof
  29.              || obj->rknown != otmp->rknown))
  30.          return FALSE;
  31.  
  32.      if (obj->oclass == FOOD_CLASS
  33.          && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
  34.          return FALSE;
  35.  
  36.      if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
  37.          if (obj->corpsenm != otmp->corpsenm)
  38.              return FALSE;
  39.      }
  40.  
  41.      /* hatching eggs don't merge; ditto for revivable corpses */
  42.      if ((obj->otyp == EGG && (obj->timed || otmp->timed))
  43.          || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM
  44.              && is_reviver(&mons[otmp->corpsenm])))
  45.          return FALSE;
  46.  
  47.      /* allow candle merging only if their ages are close */
  48.      /* see begin_burn() for a reference for the magic "25" */
  49.      if (Is_candle(obj) && obj->age / 25 != otmp->age / 25)
  50.          return FALSE;
  51.  
  52.      /* burning potions of oil never merge */
  53.      if (obj->otyp == POT_OIL && obj->lamplit)
  54.          return FALSE;
  55.  
  56.      /* don't merge surcharged item with base-cost item */
  57.      if (obj->unpaid && !same_price(obj, otmp))
  58.          return FALSE;
  59.  
  60.      /* if they have names, make sure they're the same */
  61.      objnamelth = strlen(safe_oname(obj));
  62.      otmpnamelth = strlen(safe_oname(otmp));
  63.      if ((objnamelth != otmpnamelth
  64.           && ((objnamelth && otmpnamelth) || obj->otyp == CORPSE))
  65.          || (objnamelth && otmpnamelth
  66.              && strncmp(ONAME(obj), ONAME(otmp), objnamelth)))
  67.          return FALSE;
  68.  
  69.      /* for the moment, any additional information is incompatible */
  70.      if (has_omonst(obj) || has_omid(obj) || has_olong(obj) || has_omonst(otmp)
  71.          || has_omid(otmp) || has_olong(otmp))
  72.          return FALSE;
  73.  
  74.      if (obj->oartifact != otmp->oartifact)
  75.          return FALSE;
  76.  
  77.      if (obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) {
  78.          return (boolean) objects[obj->otyp].oc_merge;
  79.      } else
  80.          return FALSE;
  81.  }
  82.  

doprgold

  1.  /* the '$' command */
  2.  int
  3.  doprgold()
  4.  {
  5.      /* the messages used to refer to "carrying gold", but that didn't
  6.         take containers into account */
  7.      long umoney = money_cnt(invent);
  8.      if (!umoney)
  9.          Your("wallet is empty.");
  10.      else
  11.          Your("wallet contains %ld %s.", umoney, currency(umoney));
  12.      shopper_financial_report();
  13.      return 0;
  14.  }
  15.  

doprwep

  1.  /* the ')' command */
  2.  int
  3.  doprwep()
  4.  {
  5.      if (!uwep) {
  6.          You("are empty %s.", body_part(HANDED));
  7.      } else {
  8.          prinv((char *) 0, uwep, 0L);
  9.          if (u.twoweap)
  10.              prinv((char *) 0, uswapwep, 0L);
  11.      }
  12.      return 0;
  13.  }
  14.  

noarmor

  1.  /* caller is responsible for checking !wearing_armor() */
  2.  STATIC_OVL void
  3.  noarmor(report_uskin)
  4.  boolean report_uskin;
  5.  {
  6.      if (!uskin || !report_uskin) {
  7.          You("are not wearing any armor.");
  8.      } else {
  9.          char *p, *uskinname, buf[BUFSZ];
  10.  
  11.          uskinname = strcpy(buf, simpleonames(uskin));
  12.          /* shorten "set of <color> dragon scales" to "<color> scales"
  13.             and "<color> dragon scale mail" to "<color> scale mail" */
  14.          if (!strncmpi(uskinname, "set of ", 7))
  15.              uskinname += 7;
  16.          if ((p = strstri(uskinname, " dragon ")) != 0)
  17.              while ((p[1] = p[8]) != '\0')
  18.                  ++p;
  19.  
  20.          You("are not wearing armor but have %s embedded in your skin.",
  21.              uskinname);
  22.      }
  23.  }
  24.  

doprarm

  1.  /* the '[' command */
  2.  int
  3.  doprarm()
  4.  {
  5.      char lets[8];
  6.      register int ct = 0;
  7.      /*
  8.       * Note:  players sometimes get here by pressing a function key which
  9.       * transmits ''ESC [ <something>'' rather than by pressing '[';
  10.       * there's nothing we can--or should-do about that here.
  11.       */
  12.  
  13.      if (!wearing_armor()) {
  14.          noarmor(TRUE);
  15.      } else {
  16.          if (uarmu)
  17.              lets[ct++] = obj_to_let(uarmu);
  18.          if (uarm)
  19.              lets[ct++] = obj_to_let(uarm);
  20.          if (uarmc)
  21.              lets[ct++] = obj_to_let(uarmc);
  22.          if (uarmh)
  23.              lets[ct++] = obj_to_let(uarmh);
  24.          if (uarms)
  25.              lets[ct++] = obj_to_let(uarms);
  26.          if (uarmg)
  27.              lets[ct++] = obj_to_let(uarmg);
  28.          if (uarmf)
  29.              lets[ct++] = obj_to_let(uarmf);
  30.          lets[ct] = 0;
  31.          (void) display_inventory(lets, FALSE);
  32.      }
  33.      return 0;
  34.  }
  35.  

doprring

  1.  /* the '=' command */
  2.  int
  3.  doprring()
  4.  {
  5.      if (!uleft && !uright)
  6.          You("are not wearing any rings.");
  7.      else {
  8.          char lets[3];
  9.          register int ct = 0;
  10.  
  11.          if (uleft)
  12.              lets[ct++] = obj_to_let(uleft);
  13.          if (uright)
  14.              lets[ct++] = obj_to_let(uright);
  15.          lets[ct] = 0;
  16.          (void) display_inventory(lets, FALSE);
  17.      }
  18.      return 0;
  19.  }
  20.  

dopramulet

  1.  /* the '"' command */
  2.  int
  3.  dopramulet()
  4.  {
  5.      if (!uamul)
  6.          You("are not wearing an amulet.");
  7.      else
  8.          prinv((char *) 0, uamul, 0L);
  9.      return 0;
  10.  }
  11.  

tool_in_use

  1.  STATIC_OVL boolean
  2.  tool_in_use(obj)
  3.  struct obj *obj;
  4.  {
  5.      if ((obj->owornmask & (W_TOOL | W_SADDLE)) != 0L)
  6.          return TRUE;
  7.      if (obj->oclass != TOOL_CLASS)
  8.          return FALSE;
  9.      return (boolean) (obj == uwep || obj->lamplit
  10.                        || (obj->otyp == LEASH && obj->leashmon));
  11.  }
  12.  

doprtool

  1.  /* the '(' command */
  2.  int
  3.  doprtool()
  4.  {
  5.      struct obj *otmp;
  6.      int ct = 0;
  7.      char lets[52 + 1];
  8.  
  9.      for (otmp = invent; otmp; otmp = otmp->nobj)
  10.          if (tool_in_use(otmp))
  11.              lets[ct++] = obj_to_let(otmp);
  12.      lets[ct] = '\0';
  13.      if (!ct)
  14.          You("are not using any tools.");
  15.      else
  16.          (void) display_inventory(lets, FALSE);
  17.      return 0;
  18.  }
  19.  

doprinuse

  1.  /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands;
  2.     show inventory of all currently wielded, worn, or used objects */
  3.  int
  4.  doprinuse()
  5.  {
  6.      struct obj *otmp;
  7.      int ct = 0;
  8.      char lets[52 + 1];
  9.  
  10.      for (otmp = invent; otmp; otmp = otmp->nobj)
  11.          if (is_worn(otmp) || tool_in_use(otmp))
  12.              lets[ct++] = obj_to_let(otmp);
  13.      lets[ct] = '\0';
  14.      if (!ct)
  15.          You("are not wearing or wielding anything.");
  16.      else
  17.          (void) display_inventory(lets, FALSE);
  18.      return 0;
  19.  }
  20.  

useupf

  1.  /*
  2.   * uses up an object that's on the floor, charging for it as necessary
  3.   */
  4.  void
  5.  useupf(obj, numused)
  6.  register struct obj *obj;
  7.  long numused;
  8.  {
  9.      register struct obj *otmp;
  10.      boolean at_u = (obj->ox == u.ux && obj->oy == u.uy);
  11.  
  12.      /* burn_floor_objects() keeps an object pointer that it tries to
  13.       * useupf() multiple times, so obj must survive if plural */
  14.      if (obj->quan > numused)
  15.          otmp = splitobj(obj, numused);
  16.      else
  17.          otmp = obj;
  18.      if (costly_spot(otmp->ox, otmp->oy)) {
  19.          if (index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
  20.              addtobill(otmp, FALSE, FALSE, FALSE);
  21.          else
  22.              (void) stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
  23.      }
  24.      delobj(otmp);
  25.      if (at_u && u.uundetected && hides_under(youmonst.data))
  26.          (void) hideunder(&youmonst);
  27.  }
  28.  

let_to_name

  1.  /*
  2.   * Conversion from a class to a string for printing.
  3.   * This must match the object class order.
  4.   */
  5.  STATIC_VAR NEARDATA const char *names[] = {
  6.      0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
  7.      "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
  8.      "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
  9.  };
  10.  
  11.  static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
  12.  
  13.  static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
  14.  
  15.  static NEARDATA char *invbuf = (char *) 0;
  16.  static NEARDATA unsigned invbufsiz = 0;
  17.  
  18.  char *
  19.  let_to_name(let, unpaid, showsym)
  20.  char let;
  21.  boolean unpaid, showsym;
  22.  {
  23.      const char *ocsymfmt = "  ('%c')";
  24.      const int invbuf_sympadding = 8; /* arbitrary */
  25.      const char *class_name;
  26.      const char *pos;
  27.      int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
  28.      unsigned len;
  29.  
  30.      if (oclass)
  31.          class_name = names[oclass];
  32.      else if ((pos = index(oth_symbols, let)) != 0)
  33.          class_name = oth_names[pos - oth_symbols];
  34.      else
  35.          class_name = names[0];
  36.  
  37.      len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
  38.            + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
  39.      if (len > invbufsiz) {
  40.          if (invbuf)
  41.              free((genericptr_t) invbuf);
  42.          invbufsiz = len + 10; /* add slop to reduce incremental realloc */
  43.          invbuf = (char *) alloc(invbufsiz);
  44.      }
  45.      if (unpaid)
  46.          Strcat(strcpy(invbuf, "Unpaid "), class_name);
  47.      else
  48.          Strcpy(invbuf, class_name);
  49.      if ((oclass != 0) && showsym) {
  50.          char *bp = eos(invbuf);
  51.          int mlen = invbuf_sympadding - strlen(class_name);
  52.          while (--mlen > 0) {
  53.              *bp = ' ';
  54.              bp++;
  55.          }
  56.          *bp = '\0';
  57.          Sprintf(eos(invbuf), ocsymfmt, def_oc_syms[oclass].sym);
  58.      }
  59.      return invbuf;
  60.  }
  61.  

free_invbuf

  1.  /* release the static buffer used by let_to_name() */
  2.  void
  3.  free_invbuf()
  4.  {
  5.      if (invbuf)
  6.          free((genericptr_t) invbuf), invbuf = (char *) 0;
  7.      invbufsiz = 0;
  8.  }
  9.  

reassign

  1.  /* give consecutive letters to every item in inventory (for !fixinv mode);
  2.     gold is always forced to '$' slot at head of list */
  3.  void
  4.  reassign()
  5.  {
  6.      int i;
  7.      struct obj *obj, *prevobj, *goldobj;
  8.  
  9.      /* first, remove [first instance of] gold from invent, if present */
  10.      prevobj = goldobj = 0;
  11.      for (obj = invent; obj; prevobj = obj, obj = obj->nobj)
  12.          if (obj->oclass == COIN_CLASS) {
  13.              goldobj = obj;
  14.              if (prevobj)
  15.                  prevobj->nobj = goldobj->nobj;
  16.              else
  17.                  invent = goldobj->nobj;
  18.              break;
  19.          }
  20.      /* second, re-letter the rest of the list */
  21.      for (obj = invent, i = 0; obj; obj = obj->nobj, i++)
  22.          obj->invlet =
  23.              (i < 26) ? ('a' + i) : (i < 52) ? ('A' + i - 26) : NOINVSYM;
  24.      /* third, assign gold the "letter" '$' and re-insert it at head */
  25.      if (goldobj) {
  26.          goldobj->invlet = GOLD_SYM;
  27.          goldobj->nobj = invent;
  28.          invent = goldobj;
  29.      }
  30.      if (i >= 52)
  31.          i = 52 - 1;
  32.      lastinvnr = i;
  33.  }
  34.  

doorganize

  1.  /* #adjust command
  2.   *
  3.   *      User specifies a 'from' slot for inventory stack to move,
  4.   *      then a 'to' slot for its destination.  Open slots and those
  5.   *      filled by compatible stacks are listed as likely candidates
  6.   *      but user can pick any inventory letter (including 'from').
  7.   *      All compatible items found are gathered into the 'from'
  8.   *      stack as it is moved.  If the 'to' slot isn't empty and
  9.   *      doesn't merge, then its stack is swapped to the 'from' slot.
  10.   *
  11.   *      If the user specifies a count when choosing the 'from' slot,
  12.   *      and that count is less than the full size of the stack,
  13.   *      then the stack will be split.  The 'count' portion is moved
  14.   *      to the destination, and the only candidate for merging with
  15.   *      it is the stack already at the 'to' slot, if any.  When the
  16.   *      destination is non-empty but won't merge, whatever is there
  17.   *      will be moved to an open slot; if there isn't any open slot
  18.   *      available, the adjustment attempt fails.
  19.   *
  20.   *      Splitting has one special case:  if 'to' slot is non-empty
  21.   *      and is compatible with 'from' in all respects except for
  22.   *      user-assigned names, the 'count' portion being moved is
  23.   *      effectively renamed so that it will merge with 'to' stack.
  24.   */
  25.  int
  26.  doorganize() /* inventory organizer by Del Lamb */
  27.  {
  28.      struct obj *obj, *otmp, *splitting, *bumped;
  29.      int ix, cur, trycnt;
  30.      char let;
  31.      char alphabet[52 + 1], buf[52 + 1];
  32.      char qbuf[QBUFSZ];
  33.      char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
  34.      const char *adj_type;
  35.  
  36.      if (!invent) {
  37.          You("aren't carrying anything to adjust.");
  38.          return 0;
  39.      }
  40.  
  41.      if (!flags.invlet_constant)
  42.          reassign();
  43.      /* get object the user wants to organize (the 'from' slot) */
  44.      allowall[0] = ALLOW_COUNT;
  45.      allowall[1] = ALL_CLASSES;
  46.      allowall[2] = '\0';
  47.      if (!(obj = getobj(allowall, "adjust")))
  48.          return 0;
  49.  
  50.      /* figure out whether user gave a split count to getobj() */
  51.      splitting = bumped = 0;
  52.      for (otmp = invent; otmp; otmp = otmp->nobj)
  53.          if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
  54.              if (otmp->invlet == obj->invlet)
  55.                  splitting = otmp;
  56.              break;
  57.          }
  58.  
  59.      /* initialize the list with all lower and upper case letters */
  60.      for (ix = 0, let = 'a'; let <= 'z';)
  61.          alphabet[ix++] = let++;
  62.      for (let = 'A'; let <= 'Z';)
  63.          alphabet[ix++] = let++;
  64.      alphabet[ix] = '\0';
  65.      /* for floating inv letters, truncate list after the first open slot */
  66.      if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
  67.          alphabet[ix + (splitting ? 0 : 1)] = '\0';
  68.  
  69.      /* blank out all the letters currently in use in the inventory */
  70.      /* except those that will be merged with the selected object   */
  71.      for (otmp = invent; otmp; otmp = otmp->nobj)
  72.          if (otmp != obj && !mergable(otmp, obj)) {
  73.              let = otmp->invlet;
  74.              if (let >= 'a' && let <= 'z')
  75.                  alphabet[let - 'a'] = ' ';
  76.              else if (let >= 'A' && let <= 'Z')
  77.                  alphabet[let - 'A' + 26] = ' ';
  78.          }
  79.  
  80.      /* compact the list by removing all the blanks */
  81.      for (ix = cur = 0; alphabet[ix]; ix++)
  82.          if (alphabet[ix] != ' ')
  83.              buf[cur++] = alphabet[ix];
  84.      if (!cur && obj->invlet == NOINVSYM)
  85.          buf[cur++] = NOINVSYM;
  86.      buf[cur] = '\0';
  87.      /* and by dashing runs of letters */
  88.      if (cur > 5)
  89.          compactify(buf);
  90.  
  91.      /* get 'to' slot to use as destination */
  92.      Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
  93.              invent ? " (? see used letters)" : "");
  94.      for (trycnt = 1; ; ++trycnt) {
  95.          let = yn_function(qbuf, (char *) 0, '\0');
  96.          if (let == '?' || let == '*') {
  97.              let = display_used_invlets(splitting ? obj->invlet : 0);
  98.              if (!let)
  99.                  continue;
  100.              if (let == '\033')
  101.                  goto noadjust;
  102.          }
  103.          if (index(quitchars, let)
  104.              /* adjusting to same slot is meaningful since all
  105.                 compatible stacks get collected along the way,
  106.                 but splitting to same slot is not */
  107.              || (splitting && let == obj->invlet)) {
  108.          noadjust:
  109.              if (splitting)
  110.                  (void) merged(&splitting, &obj);
  111.              pline1(Never_mind);
  112.              return 0;
  113.          }
  114.          if ((letter(let) && let != '@') || index(buf, let))
  115.              break; /* got one */
  116.          if (trycnt == 5)
  117.              goto noadjust;
  118.          pline("Select an inventory slot letter."); /* else try again */
  119.      }
  120.  
  121.      /* change the inventory and print the resulting item */
  122.      adj_type = !splitting ? "Moving:" : "Splitting:";
  123.  
  124.      /*
  125.       * don't use freeinv/addinv to avoid double-touching artifacts,
  126.       * dousing lamps, losing luck, cursing loadstone, etc.
  127.       */
  128.      extract_nobj(obj, &invent);
  129.  
  130.      for (otmp = invent; otmp;) {
  131.          if (!splitting) {
  132.              if (merged(&otmp, &obj)) {
  133.                  adj_type = "Merging:";
  134.                  obj = otmp;
  135.                  otmp = otmp->nobj;
  136.                  extract_nobj(obj, &invent);
  137.                  continue; /* otmp has already been updated */
  138.              } else if (otmp->invlet == let) {
  139.                  adj_type = "Swapping:";
  140.                  otmp->invlet = obj->invlet;
  141.              }
  142.          } else {
  143.              /* splitting: don't merge extra compatible stacks;
  144.                 if destination is compatible, do merge with it,
  145.                 otherwise bump whatever is there to an open slot */
  146.              if (otmp->invlet == let) {
  147.                  int olth = 0;
  148.  
  149.                  if (has_oname(obj))
  150.                      olth = strlen(ONAME(obj));
  151.                  /* ugly hack:  if these objects aren't going to merge
  152.                     solely because they have conflicting user-assigned
  153.                     names, strip off the name of the one being moved */
  154.                  if (olth && !obj->oartifact && !mergable(otmp, obj)) {
  155.                      char *holdname = ONAME(obj);
  156.                      ONAME(obj) = (char *) 0;
  157.                      /* restore name iff merging is still not possible */
  158.                      if (!mergable(otmp, obj)) {
  159.                          ONAME(obj) = holdname;
  160.                          holdname = (char *) 0;
  161.                      } else
  162.                          free((genericptr_t) holdname);
  163.                  }
  164.  
  165.                  if (merged(&otmp, &obj)) {
  166.                      obj = otmp;
  167.                      extract_nobj(obj, &invent);
  168.                  } else if (inv_cnt(FALSE) >= 52) {
  169.                      (void) merged(&splitting, &obj); /* undo split */
  170.                      /* "knapsack cannot accommodate any more items" */
  171.                      Your("pack is too full.");
  172.                      return 0;
  173.                  } else {
  174.                      bumped = otmp;
  175.                      extract_nobj(bumped, &invent);
  176.                  }
  177.                  break;
  178.              } /* found 'to' slot */
  179.          }     /* splitting */
  180.          otmp = otmp->nobj;
  181.      }
  182.  
  183.      /* inline addinv; insert loose object at beginning of inventory */
  184.      obj->invlet = let;
  185.      obj->nobj = invent;
  186.      obj->where = OBJ_INVENT;
  187.      invent = obj;
  188.      reorder_invent();
  189.      if (bumped) {
  190.          /* splitting the 'from' stack is causing an incompatible
  191.             stack in the 'to' slot to be moved into an open one;
  192.             we need to do another inline insertion to inventory */
  193.          assigninvlet(bumped);
  194.          bumped->nobj = invent;
  195.          bumped->where = OBJ_INVENT;
  196.          invent = bumped;
  197.          reorder_invent();
  198.      }
  199.  
  200.      /* messages deferred until inventory has been fully reestablished */
  201.      prinv(adj_type, obj, 0L);
  202.      if (bumped)
  203.          prinv("Moving:", bumped, 0L);
  204.      if (splitting)
  205.          clear_splitobjs(); /* reset splitobj context */
  206.      update_inventory();
  207.      return 0;
  208.  }
  209.  

invdisp_nothing

  1.  /* common to display_minventory and display_cinventory */
  2.  STATIC_OVL void
  3.  invdisp_nothing(hdr, txt)
  4.  const char *hdr, *txt;
  5.  {
  6.      winid win;
  7.      anything any;
  8.      menu_item *selected;
  9.  
  10.      any = zeroany;
  11.      win = create_nhwindow(NHW_MENU);
  12.      start_menu(win);
  13.      add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr,
  14.               MENU_UNSELECTED);
  15.      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
  16.      add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
  17.      end_menu(win, (char *) 0);
  18.      if (select_menu(win, PICK_NONE, &selected) > 0)
  19.          free((genericptr_t) selected);
  20.      destroy_nhwindow(win);
  21.      return;
  22.  }
  23.  

worn_wield_only

  1.  /* query_objlist callback: return things that are worn or wielded */
  2.  STATIC_OVL boolean
  3.  worn_wield_only(obj)
  4.  struct obj *obj;
  5.  {
  6.  #if 1
  7.      /* check for things that *are* worn or wielded (only used for monsters,
  8.         so we don't worry about excluding W_CHAIN, W_ARTI and the like) */
  9.      return (boolean) (obj->owornmask != 0L);
  10.  #else
  11.      /* this used to check for things that *might* be worn or wielded,
  12.         but that's not particularly interesting */
  13.      if (is_weptool(obj) || is_wet_towel(obj) || obj->otyp == MEAT_RING)
  14.          return TRUE;
  15.      return (boolean) (obj->oclass == WEAPON_CLASS
  16.                        || obj->oclass == ARMOR_CLASS
  17.                        || obj->oclass == AMULET_CLASS
  18.                        || obj->oclass == RING_CLASS);
  19.  #endif
  20.  }
  21.  

display_minventory

  1.  /*
  2.   * Display a monster's inventory.
  3.   * Returns a pointer to the object from the monster's inventory selected
  4.   * or NULL if nothing was selected.
  5.   *
  6.   * By default, only worn and wielded items are displayed.  The caller
  7.   * can pick one.  Modifier flags are:
  8.   *
  9.   *      MINV_NOLET      - nothing selectable
  10.   *      MINV_ALL        - display all inventory
  11.   */
  12.  struct obj *
  13.  display_minventory(mon, dflags, title)
  14.  register struct monst *mon;
  15.  int dflags;
  16.  char *title;
  17.  {
  18.      struct obj *ret;
  19.      char tmp[QBUFSZ];
  20.      int n;
  21.      menu_item *selected = 0;
  22.      int do_all = (dflags & MINV_ALL) != 0,
  23.          incl_hero = (do_all && u.uswallow && mon == u.ustuck),
  24.          have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero);
  25.  
  26.      Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
  27.              do_all ? "possessions" : "armament");
  28.  
  29.      if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
  30.          /* Fool the 'weapon in hand' routine into
  31.           * displaying 'weapon in claw', etc. properly.
  32.           */
  33.          youmonst.data = mon->data;
  34.  
  35.          n = query_objlist(title ? title : tmp, mon->minvent,
  36.                            INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0),
  37.                            &selected,
  38.                            (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
  39.                            do_all ? allow_all : worn_wield_only);
  40.  
  41.          set_uasmon();
  42.      } else {
  43.          invdisp_nothing(title ? title : tmp, "(none)");
  44.          n = 0;
  45.      }
  46.  
  47.      if (n > 0) {
  48.          ret = selected[0].item.a_obj;
  49.          free((genericptr_t) selected);
  50.      } else
  51.          ret = (struct obj *) 0;
  52.      return ret;
  53.  }
  54.  

display_cinventory

  1.  /*
  2.   * Display the contents of a container in inventory style.
  3.   * Currently, this is only used for statues, via wand of probing.
  4.   */
  5.  struct obj *
  6.  display_cinventory(obj)
  7.  register struct obj *obj;
  8.  {
  9.      struct obj *ret;
  10.      char qbuf[QBUFSZ];
  11.      int n;
  12.      menu_item *selected = 0;
  13.  
  14.      (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
  15.                       "that");
  16.  
  17.      if (obj->cobj) {
  18.          n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected,
  19.                            PICK_NONE, allow_all);
  20.      } else {
  21.          invdisp_nothing(qbuf, "(empty)");
  22.          n = 0;
  23.      }
  24.      if (n > 0) {
  25.          ret = selected[0].item.a_obj;
  26.          free((genericptr_t) selected);
  27.      } else
  28.          ret = (struct obj *) 0;
  29.      obj->cknown = 1;
  30.      return ret;
  31.  }
  32.  

only_here

  1.  /* query objlist callback: return TRUE if obj is at given location */
  2.  static coord only;
  3.  
  4.  STATIC_OVL boolean
  5.  only_here(obj)
  6.  struct obj *obj;
  7.  {
  8.      return (obj->ox == only.x && obj->oy == only.y);
  9.  }
  10.  

display_binventory

  1.  /*
  2.   * Display a list of buried items in inventory style.  Return a non-zero
  3.   * value if there were items at that spot.
  4.   *
  5.   * Currently, this is only used with a wand of probing zapped downwards.
  6.   */
  7.  int
  8.  display_binventory(x, y, as_if_seen)
  9.  int x, y;
  10.  boolean as_if_seen;
  11.  {
  12.      struct obj *obj;
  13.      menu_item *selected = 0;
  14.      int n;
  15.  
  16.      /* count # of objects here */
  17.      for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
  18.          if (obj->ox == x && obj->oy == y) {
  19.              if (as_if_seen)
  20.                  obj->dknown = 1;
  21.              n++;
  22.          }
  23.  
  24.      if (n) {
  25.          only.x = x;
  26.          only.y = y;
  27.          if (query_objlist("Things that are buried here:", level.buriedobjlist,
  28.                            INVORDER_SORT, &selected, PICK_NONE, only_here) > 0)
  29.              free((genericptr_t) selected);
  30.          only.x = only.y = 0;
  31.      }
  32.      return n;
  33.  }
  34.  
  35.  /*invent.c*/