Source:NetHack 3.6.0/src/mkobj.c

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

Below is the full text to mkobj.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/mkobj.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	mkobj.c	$NHDT-Date: 1447475943 2015/11/14 04:39:03 $  $NHDT-Branch: master $:$NHDT-Revision: 1.113 $ */
  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.  STATIC_DCL void FDECL(mkbox_cnts, (struct obj *));
  8.  STATIC_DCL void FDECL(maybe_adjust_light, (struct obj *, int));
  9.  STATIC_DCL void FDECL(obj_timer_checks, (struct obj *,
  10.                                           XCHAR_P, XCHAR_P, int));
  11.  STATIC_DCL void FDECL(container_weight, (struct obj *));
  12.  STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *));
  13.  STATIC_DCL void FDECL(objlist_sanity, (struct obj *, int, const char *));
  14.  STATIC_DCL void FDECL(mon_obj_sanity, (struct monst *, const char *));
  15.  STATIC_DCL const char *FDECL(where_name, (struct obj *));
  16.  STATIC_DCL void FDECL(insane_object, (struct obj *, const char *,
  17.                                        const char *, struct monst *));
  18.  STATIC_DCL void FDECL(check_contained, (struct obj *, const char *));
  19.  STATIC_DCL void FDECL(sanity_check_worn, (struct obj *));
  20.  
  21.  struct icp {
  22.      int iprob;   /* probability of an item type */
  23.      char iclass; /* item class */
  24.  };
  25.  
  26.  static const struct icp mkobjprobs[] = { { 10, WEAPON_CLASS },
  27.                                           { 10, ARMOR_CLASS },
  28.                                           { 20, FOOD_CLASS },
  29.                                           { 8, TOOL_CLASS },
  30.                                           { 8, GEM_CLASS },
  31.                                           { 16, POTION_CLASS },
  32.                                           { 16, SCROLL_CLASS },
  33.                                           { 4, SPBOOK_CLASS },
  34.                                           { 4, WAND_CLASS },
  35.                                           { 3, RING_CLASS },
  36.                                           { 1, AMULET_CLASS } };
  37.  
  38.  static const struct icp boxiprobs[] = { { 18, GEM_CLASS },
  39.                                          { 15, FOOD_CLASS },
  40.                                          { 18, POTION_CLASS },
  41.                                          { 18, SCROLL_CLASS },
  42.                                          { 12, SPBOOK_CLASS },
  43.                                          { 7, COIN_CLASS },
  44.                                          { 6, WAND_CLASS },
  45.                                          { 5, RING_CLASS },
  46.                                          { 1, AMULET_CLASS } };
  47.  
  48.  static const struct icp rogueprobs[] = { { 12, WEAPON_CLASS },
  49.                                           { 12, ARMOR_CLASS },
  50.                                           { 22, FOOD_CLASS },
  51.                                           { 22, POTION_CLASS },
  52.                                           { 22, SCROLL_CLASS },
  53.                                           { 5, WAND_CLASS },
  54.                                           { 5, RING_CLASS } };
  55.  
  56.  static const struct icp hellprobs[] = { { 20, WEAPON_CLASS },
  57.                                          { 20, ARMOR_CLASS },
  58.                                          { 16, FOOD_CLASS },
  59.                                          { 12, TOOL_CLASS },
  60.                                          { 10, GEM_CLASS },
  61.                                          { 1, POTION_CLASS },
  62.                                          { 1, SCROLL_CLASS },
  63.                                          { 8, WAND_CLASS },
  64.                                          { 8, RING_CLASS },
  65.                                          { 4, AMULET_CLASS } };
  66.  

newoextra

  1.  struct oextra *
  2.  newoextra()
  3.  {
  4.      struct oextra *oextra;
  5.  
  6.      oextra = (struct oextra *) alloc(sizeof(struct oextra));
  7.      oextra->oname = 0;
  8.      oextra->omonst = 0;
  9.      oextra->omid = 0;
  10.      oextra->olong = 0;
  11.      oextra->omailcmd = 0;
  12.      return oextra;
  13.  }
  14.  

dealloc_oextra

  1.  void
  2.  dealloc_oextra(o)
  3.  struct obj *o;
  4.  {
  5.      struct oextra *x = o->oextra;
  6.  
  7.      if (x) {
  8.          if (x->oname)
  9.              free((genericptr_t) x->oname);
  10.          if (x->omonst)
  11.              free_omonst(o);     /* 'o' rather than 'x' */
  12.          if (x->omid)
  13.              free((genericptr_t) x->omid);
  14.          if (x->olong)
  15.              free((genericptr_t) x->olong);
  16.          if (x->omailcmd)
  17.              free((genericptr_t) x->omailcmd);
  18.  
  19.          free((genericptr_t) x);
  20.          o->oextra = (struct oextra *) 0;
  21.      }
  22.  }
  23.  

newomonst

  1.  void
  2.  newomonst(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (!otmp->oextra)
  6.          otmp->oextra = newoextra();
  7.      if (!OMONST(otmp)) {
  8.          struct monst *m = newmonst();
  9.  
  10.          /* newmonst() allocates memory but doesn't initialize anything */
  11.          (void) memset((genericptr_t) m, 0, sizeof (struct monst));
  12.          m->mextra = (struct mextra *) 0;
  13.          m->nmon = (struct monst *) 0;
  14.          OMONST(otmp) = m;
  15.      }
  16.  }
  17.  

free_omonst

  1.  void
  2.  free_omonst(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (otmp->oextra) {
  6.          struct monst *m = OMONST(otmp);
  7.  
  8.          if (m) {
  9.              if (m->mextra)
  10.                  dealloc_mextra(m);
  11.              free((genericptr_t) m);
  12.              OMONST(otmp) = (struct monst *) 0;
  13.          }
  14.      }
  15.  }
  16.  

newomid

  1.  void
  2.  newomid(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (!otmp->oextra)
  6.          otmp->oextra = newoextra();
  7.      if (!OMID(otmp)) {
  8.          OMID(otmp) = (unsigned *) alloc(sizeof (unsigned));
  9.          (void) memset((genericptr_t) OMID(otmp), 0, sizeof (unsigned));
  10.      }
  11.  }
  12.  

free_omid

  1.  void
  2.  free_omid(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (otmp->oextra && OMID(otmp)) {
  6.          free((genericptr_t) OMID(otmp));
  7.          OMID(otmp) = (unsigned *) 0;
  8.      }
  9.  }
  10.  

newolong

  1.  void
  2.  newolong(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (!otmp->oextra)
  6.          otmp->oextra = newoextra();
  7.      if (!OLONG(otmp)) {
  8.          OLONG(otmp) = (long *) alloc(sizeof (long));
  9.          (void) memset((genericptr_t) OLONG(otmp), 0, sizeof (long));
  10.      }
  11.  }
  12.  

free_olong

  1.  void
  2.  free_olong(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (otmp->oextra && OLONG(otmp)) {
  6.          free((genericptr_t) OLONG(otmp));
  7.          OLONG(otmp) = (long *) 0;
  8.      }
  9.  }
  10.  

new_omailcmd

  1.  void
  2.  new_omailcmd(otmp, response_cmd)
  3.  struct obj *otmp;
  4.  const char *response_cmd;
  5.  {
  6.      if (!otmp->oextra)
  7.          otmp->oextra = newoextra();
  8.      if (OMAILCMD(otmp))
  9.          free_omailcmd(otmp);
  10.      OMAILCMD(otmp) = dupstr(response_cmd);
  11.  }
  12.  

free_omailcmd

  1.  void
  2.  free_omailcmd(otmp)
  3.  struct obj *otmp;
  4.  {
  5.      if (otmp->oextra && OMAILCMD(otmp)) {
  6.          free((genericptr_t) OMAILCMD(otmp));
  7.          OMAILCMD(otmp) = (char *) 0;
  8.      }
  9.  }
  10.  

mkobj_at

  1.  struct obj *
  2.  mkobj_at(let, x, y, artif)
  3.  char let;
  4.  int x, y;
  5.  boolean artif;
  6.  {
  7.      struct obj *otmp;
  8.  
  9.      otmp = mkobj(let, artif);
  10.      place_object(otmp, x, y);
  11.      return otmp;
  12.  }
  13.  

mksobj_at

  1.  struct obj *
  2.  mksobj_at(otyp, x, y, init, artif)
  3.  int otyp, x, y;
  4.  boolean init, artif;
  5.  {
  6.      struct obj *otmp;
  7.  
  8.      otmp = mksobj(otyp, init, artif);
  9.      place_object(otmp, x, y);
  10.      return otmp;
  11.  }
  12.  

mkobj

  1.  struct obj *
  2.  mkobj(oclass, artif)
  3.  char oclass;
  4.  boolean artif;
  5.  {
  6.      int tprob, i, prob = rnd(1000);
  7.  
  8.      if (oclass == RANDOM_CLASS) {
  9.          const struct icp *iprobs = Is_rogue_level(&u.uz)
  10.                                     ? (const struct icp *) rogueprobs
  11.                                     : Inhell ? (const struct icp *) hellprobs
  12.                                              : (const struct icp *) mkobjprobs;
  13.  
  14.          for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
  15.              ;
  16.          oclass = iprobs->iclass;
  17.      }
  18.  
  19.      i = bases[(int) oclass];
  20.      while ((prob -= objects[i].oc_prob) > 0)
  21.          i++;
  22.  
  23.      if (objects[i].oc_class != oclass || !OBJ_NAME(objects[i]))
  24.          panic("probtype error, oclass=%d i=%d", (int) oclass, i);
  25.  
  26.      return mksobj(i, TRUE, artif);
  27.  }
  28.  

mkbox_cnts

  1.  STATIC_OVL void
  2.  mkbox_cnts(box)
  3.  struct obj *box;
  4.  {
  5.      register int n;
  6.      register struct obj *otmp;
  7.  
  8.      box->cobj = (struct obj *) 0;
  9.  
  10.      switch (box->otyp) {
  11.      case ICE_BOX:
  12.          n = 20;
  13.          break;
  14.      case CHEST:
  15.          n = 5;
  16.          break;
  17.      case LARGE_BOX:
  18.          n = 3;
  19.          break;
  20.      case SACK:
  21.      case OILSKIN_SACK:
  22.          /* initial inventory: sack starts out empty */
  23.          if (moves <= 1 && !in_mklev) {
  24.              n = 0;
  25.              break;
  26.          }
  27.      /*else FALLTHRU*/
  28.      case BAG_OF_HOLDING:
  29.          n = 1;
  30.          break;
  31.      default:
  32.          n = 0;
  33.          break;
  34.      }
  35.  
  36.      for (n = rn2(n + 1); n > 0; n--) {
  37.          if (box->otyp == ICE_BOX) {
  38.              if (!(otmp = mksobj(CORPSE, TRUE, TRUE)))
  39.                  continue;
  40.              /* Note: setting age to 0 is correct.  Age has a different
  41.               * from usual meaning for objects stored in ice boxes. -KAA
  42.               */
  43.              otmp->age = 0L;
  44.              if (otmp->timed) {
  45.                  (void) stop_timer(ROT_CORPSE, obj_to_any(otmp));
  46.                  (void) stop_timer(REVIVE_MON, obj_to_any(otmp));
  47.              }
  48.          } else {
  49.              register int tprob;
  50.              const struct icp *iprobs = boxiprobs;
  51.  
  52.              for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++)
  53.                  ;
  54.              if (!(otmp = mkobj(iprobs->iclass, TRUE)))
  55.                  continue;
  56.  
  57.              /* handle a couple of special cases */
  58.              if (otmp->oclass == COIN_CLASS) {
  59.                  /* 2.5 x level's usual amount; weight adjusted below */
  60.                  otmp->quan = (long) (rnd(level_difficulty() + 2) * rnd(75));
  61.                  otmp->owt = weight(otmp);
  62.              } else
  63.                  while (otmp->otyp == ROCK) {
  64.                      otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE);
  65.                      if (otmp->quan > 2L)
  66.                          otmp->quan = 1L;
  67.                      otmp->owt = weight(otmp);
  68.                  }
  69.              if (box->otyp == BAG_OF_HOLDING) {
  70.                  if (Is_mbag(otmp)) {
  71.                      otmp->otyp = SACK;
  72.                      otmp->spe = 0;
  73.                      otmp->owt = weight(otmp);
  74.                  } else
  75.                      while (otmp->otyp == WAN_CANCELLATION)
  76.                          otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
  77.              }
  78.          }
  79.          (void) add_to_container(box, otmp);
  80.      }
  81.  }
  82.  

rndmonnum

  1.  /* select a random, common monster type */
  2.  int
  3.  rndmonnum()
  4.  {
  5.      register struct permonst *ptr;
  6.      register int i;
  7.      unsigned short excludeflags;
  8.  
  9.      /* Plan A: get a level-appropriate common monster */
  10.      ptr = rndmonst();
  11.      if (ptr)
  12.          return monsndx(ptr);
  13.  
  14.      /* Plan B: get any common monster */
  15.      excludeflags = G_UNIQ | G_NOGEN | (Inhell ? G_NOHELL : G_HELL);
  16.      do {
  17.          i = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
  18.          ptr = &mons[i];
  19.      } while ((ptr->geno & excludeflags) != 0);
  20.  
  21.      return i;
  22.  }
  23.  

copy_oextra

  1.  void
  2.  copy_oextra(obj2, obj1)
  3.  struct obj *obj2, *obj1;
  4.  {
  5.      if (!obj2 || !obj1 || !obj1->oextra)
  6.          return;
  7.  
  8.      if (!obj2->oextra)
  9.          obj2->oextra = newoextra();
  10.      if (has_oname(obj1))
  11.          oname(obj2, ONAME(obj1));
  12.      if (has_omonst(obj1)) {
  13.          if (!OMONST(obj2))
  14.              newomonst(obj2);
  15.          (void) memcpy((genericptr_t) OMONST(obj2),
  16.                        (genericptr_t) OMONST(obj1), sizeof(struct monst));
  17.          OMONST(obj2)->mextra = (struct mextra *) 0;
  18.          OMONST(obj2)->nmon = (struct monst *) 0;
  19.  #if 0
  20.          OMONST(obj2)->m_id = context.ident++;
  21.          if (OMONST(obj2)->m_id) /* ident overflowed */
  22.              OMONST(obj2)->m_id = context.ident++;
  23.  #endif
  24.          if (OMONST(obj1)->mextra)
  25.              copy_mextra(OMONST(obj2), OMONST(obj1));
  26.      }
  27.      if (has_omid(obj1)) {
  28.          if (!OMID(obj2))
  29.              newomid(obj2);
  30.          (void) memcpy((genericptr_t) OMID(obj2), (genericptr_t) OMID(obj1),
  31.                        sizeof(unsigned));
  32.      }
  33.      if (has_olong(obj1)) {
  34.          if (!OLONG(obj2))
  35.              newolong(obj2);
  36.          (void) memcpy((genericptr_t) OLONG(obj2), (genericptr_t) OLONG(obj1),
  37.                        sizeof(long));
  38.      }
  39.      if (has_omailcmd(obj1)) {
  40.          new_omailcmd(obj2, OMAILCMD(obj1));
  41.      }
  42.  }
  43.  

splitobj

  1.  /*
  2.   * Split obj so that it gets size gets reduced by num. The quantity num is
  3.   * put in the object structure delivered by this call.  The returned object
  4.   * has its wornmask cleared and is positioned just following the original
  5.   * in the nobj chain (and nexthere chain when on the floor).
  6.   */
  7.  struct obj *
  8.  splitobj(obj, num)
  9.  struct obj *obj;
  10.  long num;
  11.  {
  12.      struct obj *otmp;
  13.  
  14.      if (obj->cobj || num <= 0L || obj->quan <= num)
  15.          panic("splitobj"); /* can't split containers */
  16.      otmp = newobj();
  17.      *otmp = *obj; /* copies whole structure */
  18.      otmp->oextra = (struct oextra *) 0;
  19.      otmp->o_id = context.ident++;
  20.      if (!otmp->o_id)
  21.          otmp->o_id = context.ident++; /* ident overflowed */
  22.      otmp->timed = 0;                  /* not timed, yet */
  23.      otmp->lamplit = 0;                /* ditto */
  24.      otmp->owornmask = 0L;             /* new object isn't worn */
  25.      obj->quan -= num;
  26.      obj->owt = weight(obj);
  27.      otmp->quan = num;
  28.      otmp->owt = weight(otmp); /* -= obj->owt ? */
  29.  
  30.      context.objsplit.parent_oid = obj->o_id;
  31.      context.objsplit.child_oid = otmp->o_id;
  32.      obj->nobj = otmp;
  33.      /* Only set nexthere when on the floor, nexthere is also used */
  34.      /* as a back pointer to the container object when contained. */
  35.      if (obj->where == OBJ_FLOOR)
  36.          obj->nexthere = otmp;
  37.      copy_oextra(otmp, obj);
  38.      if (has_omid(otmp))
  39.          free_omid(otmp); /* only one association with m_id*/
  40.      if (obj->unpaid)
  41.          splitbill(obj, otmp);
  42.      if (obj->timed)
  43.          obj_split_timers(obj, otmp);
  44.      if (obj_sheds_light(obj))
  45.          obj_split_light_source(obj, otmp);
  46.      return otmp;
  47.  }
  48.  

unsplitobj

  1.  /* try to find the stack obj was split from, then merge them back together;
  2.     returns the combined object if unsplit is successful, null otherwise */
  3.  struct obj *
  4.  unsplitobj(obj)
  5.  struct obj *obj;
  6.  {
  7.      unsigned target_oid = 0;
  8.      struct obj *oparent = 0, *ochild = 0, *list = 0;
  9.  
  10.      /*
  11.       * We don't operate on floor objects (we're following o->nobj rather
  12.       * than o->nexthere), on free objects (don't know which list to use when
  13.       * looking for obj's parent or child), on bill objects (too complicated,
  14.       * not needed), or on buried or migrating objects (not needed).
  15.       * [This could be improved, but at present additional generality isn't
  16.       * necessary.]
  17.       */
  18.      switch (obj->where) {
  19.      case OBJ_FREE:
  20.      case OBJ_FLOOR:
  21.      case OBJ_ONBILL:
  22.      case OBJ_MIGRATING:
  23.      case OBJ_BURIED:
  24.      default:
  25.          return (struct obj *) 0;
  26.      case OBJ_INVENT:
  27.          list = invent;
  28.          break;
  29.      case OBJ_MINVENT:
  30.          list = obj->ocarry->minvent;
  31.          break;
  32.      case OBJ_CONTAINED:
  33.          list = obj->ocontainer->cobj;
  34.          break;
  35.      }
  36.  
  37.      /* first try the expected case; obj is split from another stack */
  38.      if (obj->o_id == context.objsplit.child_oid) {
  39.          /* parent probably precedes child and will require list traversal */
  40.          ochild = obj;
  41.          target_oid = context.objsplit.parent_oid;
  42.          if (obj->nobj && obj->nobj->o_id == target_oid)
  43.              oparent = obj->nobj;
  44.      } else if (obj->o_id == context.objsplit.parent_oid) {
  45.          /* alternate scenario: another stack was split from obj;
  46.             child probably follows parent and will be found here */
  47.          oparent = obj;
  48.          target_oid = context.objsplit.child_oid;
  49.          if (obj->nobj && obj->nobj->o_id == target_oid)
  50.              ochild = obj->nobj;
  51.      }
  52.      /* if we have only half the split, scan obj's list to find other half */
  53.      if (ochild && !oparent) {
  54.          /* expected case */
  55.          for (obj = list; obj; obj = obj->nobj)
  56.              if (obj->o_id == target_oid) {
  57.                  oparent = obj;
  58.                  break;
  59.              }
  60.      } else if (oparent && !ochild) {
  61.          /* alternate scenario */
  62.          for (obj = list; obj; obj = obj->nobj)
  63.              if (obj->o_id == target_oid) {
  64.                  ochild = obj;
  65.                  break;
  66.              }
  67.      }
  68.      /* if we have both parent and child, try to merge them;
  69.         if successful, return the combined stack, otherwise return null */
  70.      return (oparent && ochild && merged(&oparent, &ochild)) ? oparent : 0;
  71.  }
  72.  

clear_splitobjs

  1.  /* reset splitobj()/unsplitobj() context */
  2.  void
  3.  clear_splitobjs()
  4.  {
  5.      context.objsplit.parent_oid = context.objsplit.child_oid = 0;
  6.  }
  7.  

replace_object

  1.  /*
  2.   * Insert otmp right after obj in whatever chain(s) it is on.  Then extract
  3.   * obj from the chain(s).  This function does a literal swap.  It is up to
  4.   * the caller to provide a valid context for the swap.  When done, obj will
  5.   * still exist, but not on any chain.
  6.   *
  7.   * Note:  Don't use use obj_extract_self() -- we are doing an in-place swap,
  8.   * not actually moving something.
  9.   */
  10.  void
  11.  replace_object(obj, otmp)
  12.  struct obj *obj;
  13.  struct obj *otmp;
  14.  {
  15.      otmp->where = obj->where;
  16.      switch (obj->where) {
  17.      case OBJ_FREE:
  18.          /* do nothing */
  19.          break;
  20.      case OBJ_INVENT:
  21.          otmp->nobj = obj->nobj;
  22.          obj->nobj = otmp;
  23.          extract_nobj(obj, &invent);
  24.          break;
  25.      case OBJ_CONTAINED:
  26.          otmp->nobj = obj->nobj;
  27.          otmp->ocontainer = obj->ocontainer;
  28.          obj->nobj = otmp;
  29.          extract_nobj(obj, &obj->ocontainer->cobj);
  30.          break;
  31.      case OBJ_MINVENT:
  32.          otmp->nobj = obj->nobj;
  33.          otmp->ocarry = obj->ocarry;
  34.          obj->nobj = otmp;
  35.          extract_nobj(obj, &obj->ocarry->minvent);
  36.          break;
  37.      case OBJ_FLOOR:
  38.          otmp->nobj = obj->nobj;
  39.          otmp->nexthere = obj->nexthere;
  40.          otmp->ox = obj->ox;
  41.          otmp->oy = obj->oy;
  42.          obj->nobj = otmp;
  43.          obj->nexthere = otmp;
  44.          extract_nobj(obj, &fobj);
  45.          extract_nexthere(obj, &level.objects[obj->ox][obj->oy]);
  46.          break;
  47.      default:
  48.          panic("replace_object: obj position");
  49.          break;
  50.      }
  51.  }
  52.  

bill_dummy_object

  1.  /*
  2.   * Create a dummy duplicate to put on shop bill.  The duplicate exists
  3.   * only in the billobjs chain.  This function is used when a shop object
  4.   * is being altered, and a copy of the original is needed for billing
  5.   * purposes.  For example, when eating, where an interruption will yield
  6.   * an object which is different from what it started out as; the "I x"
  7.   * command needs to display the original object.
  8.   *
  9.   * The caller is responsible for checking otmp->unpaid and
  10.   * costly_spot(u.ux, u.uy).  This function will make otmp no charge.
  11.   *
  12.   * Note that check_unpaid_usage() should be used instead for partial
  13.   * usage of an object.
  14.   */
  15.  void
  16.  bill_dummy_object(otmp)
  17.  register struct obj *otmp;
  18.  {
  19.      register struct obj *dummy;
  20.      long cost = 0L;
  21.  
  22.      if (otmp->unpaid) {
  23.          cost = unpaid_cost(otmp, FALSE);
  24.          subfrombill(otmp, shop_keeper(*u.ushops));
  25.      }
  26.      dummy = newobj();
  27.      *dummy = *otmp;
  28.      dummy->oextra = (struct oextra *) 0;
  29.      dummy->where = OBJ_FREE;
  30.      dummy->o_id = context.ident++;
  31.      if (!dummy->o_id)
  32.          dummy->o_id = context.ident++; /* ident overflowed */
  33.      dummy->timed = 0;
  34.      copy_oextra(dummy, otmp);
  35.      if (has_omid(dummy))
  36.          free_omid(dummy); /* only one association with m_id*/
  37.      if (Is_candle(dummy))
  38.          dummy->lamplit = 0;
  39.      dummy->owornmask = 0L; /* dummy object is not worn */
  40.      addtobill(dummy, FALSE, TRUE, TRUE);
  41.      if (cost)
  42.          alter_cost(dummy, -cost);
  43.      /* no_charge is only valid for some locations */
  44.      otmp->no_charge =
  45.          (otmp->where == OBJ_FLOOR || otmp->where == OBJ_CONTAINED) ? 1 : 0;
  46.      otmp->unpaid = 0;
  47.      return;
  48.  }
  49.  

costly_alteration

  1.  /* alteration types; must match COST_xxx macros in hack.h */
  2.  static const char *const alteration_verbs[] = {
  3.      "cancel", "drain", "uncharge", "unbless", "uncurse", "disenchant",
  4.      "degrade", "dilute", "erase", "burn", "neutralize", "destroy", "splatter",
  5.      "bite", "open", "break the lock on", "rust", "rot", "tarnish"
  6.  };
  7.  
  8.  /* possibly bill for an object which the player has just modified */
  9.  void
  10.  costly_alteration(obj, alter_type)
  11.  struct obj *obj;
  12.  int alter_type;
  13.  {
  14.      xchar ox, oy;
  15.      char objroom;
  16.      boolean set_bknown;
  17.      const char *those, *them;
  18.      struct monst *shkp = 0;
  19.  
  20.      if (alter_type < 0 || alter_type >= SIZE(alteration_verbs)) {
  21.          impossible("invalid alteration type (%d)", alter_type);
  22.          alter_type = 0;
  23.      }
  24.  
  25.      ox = oy = 0;    /* lint suppression */
  26.      objroom = '\0'; /* ditto */
  27.      if (carried(obj) || obj->where == OBJ_FREE) {
  28.          /* OBJ_FREE catches obj_no_longer_held()'s transformation
  29.             of crysknife back into worm tooth; the object has been
  30.             removed from inventory but not necessarily placed at
  31.             its new location yet--the unpaid flag will still be set
  32.             if this item is owned by a shop */
  33.          if (!obj->unpaid)
  34.              return;
  35.      } else {
  36.          /* this get_obj_location shouldn't fail, but if it does,
  37.             use hero's location */
  38.          if (!get_obj_location(obj, &ox, &oy, CONTAINED_TOO))
  39.              ox = u.ux, oy = u.uy;
  40.          if (!costly_spot(ox, oy))
  41.              return;
  42.          objroom = *in_rooms(ox, oy, SHOPBASE);
  43.          /* if no shop cares about it, we're done */
  44.          if (!billable(&shkp, obj, objroom, FALSE))
  45.              return;
  46.      }
  47.  
  48.      if (obj->quan == 1L)
  49.          those = "that", them = "it";
  50.      else
  51.          those = "those", them = "them";
  52.  
  53.      /* when shopkeeper describes the object as being uncursed or unblessed
  54.         hero will know that it is now uncursed; will also make the feedback
  55.         from `I x' after bill_dummy_object() be more specific for this item */
  56.      set_bknown = (alter_type == COST_UNCURS || alter_type == COST_UNBLSS);
  57.  
  58.      switch (obj->where) {
  59.      case OBJ_FREE: /* obj_no_longer_held() */
  60.      case OBJ_INVENT:
  61.          if (set_bknown)
  62.              obj->bknown = 1;
  63.          verbalize("You %s %s %s, you pay for %s!",
  64.                    alteration_verbs[alter_type], those, simpleonames(obj),
  65.                    them);
  66.          bill_dummy_object(obj);
  67.          break;
  68.      case OBJ_FLOOR:
  69.          if (set_bknown)
  70.              obj->bknown = 1;
  71.          if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
  72.              verbalize("You %s %s, you pay for %s!",
  73.                        alteration_verbs[alter_type], those, them);
  74.              bill_dummy_object(obj);
  75.          } else {
  76.              (void) stolen_value(obj, ox, oy, FALSE, FALSE);
  77.          }
  78.          break;
  79.      }
  80.  }
  81.  

mksobj

  1.  static const char dknowns[] = { WAND_CLASS,   RING_CLASS, POTION_CLASS,
  2.                                  SCROLL_CLASS, GEM_CLASS,  SPBOOK_CLASS,
  3.                                  WEAPON_CLASS, TOOL_CLASS, 0 };
  4.  
  5.  struct obj *
  6.  mksobj(otyp, init, artif)
  7.  int otyp;
  8.  boolean init;
  9.  boolean artif;
  10.  {
  11.      int mndx, tryct;
  12.      struct obj *otmp;
  13.      char let = objects[otyp].oc_class;
  14.  
  15.      otmp = newobj();
  16.      *otmp = zeroobj;
  17.      otmp->age = monstermoves;
  18.      otmp->o_id = context.ident++;
  19.      if (!otmp->o_id)
  20.          otmp->o_id = context.ident++; /* ident overflowed */
  21.      otmp->quan = 1L;
  22.      otmp->oclass = let;
  23.      otmp->otyp = otyp;
  24.      otmp->where = OBJ_FREE;
  25.      otmp->dknown = index(dknowns, let) ? 0 : 1;
  26.      if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD)
  27.          || otmp->otyp == SHIELD_OF_REFLECTION)
  28.          otmp->dknown = 0;
  29.      if (!objects[otmp->otyp].oc_uses_known)
  30.          otmp->known = 1;
  31.      otmp->lknown = 0;
  32.      otmp->cknown = 0;
  33.      otmp->corpsenm = NON_PM;
  34.  
  35.      if (init)
  36.          switch (let) {
  37.          case WEAPON_CLASS:
  38.              otmp->quan = is_multigen(otmp) ? (long) rn1(6, 6) : 1L;
  39.              if (!rn2(11)) {
  40.                  otmp->spe = rne(3);
  41.                  otmp->blessed = rn2(2);
  42.              } else if (!rn2(10)) {
  43.                  curse(otmp);
  44.                  otmp->spe = -rne(3);
  45.              } else
  46.                  blessorcurse(otmp, 10);
  47.              if (is_poisonable(otmp) && !rn2(100))
  48.                  otmp->opoisoned = 1;
  49.  
  50.              if (artif && !rn2(20))
  51.                  otmp = mk_artifact(otmp, (aligntyp) A_NONE);
  52.              break;
  53.          case FOOD_CLASS:
  54.              otmp->oeaten = 0;
  55.              switch (otmp->otyp) {
  56.              case CORPSE:
  57.                  /* possibly overridden by mkcorpstat() */
  58.                  tryct = 50;
  59.                  do
  60.                      otmp->corpsenm = undead_to_corpse(rndmonnum());
  61.                  while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE)
  62.                         && (--tryct > 0));
  63.                  if (tryct == 0) {
  64.                      /* perhaps rndmonnum() only wants to make G_NOCORPSE
  65.                         monsters on
  66.                         this level; let's create an adventurer's corpse
  67.                         instead, then */
  68.                      otmp->corpsenm = PM_HUMAN;
  69.                  }
  70.                  /* timer set below */
  71.                  break;
  72.              case EGG:
  73.                  otmp->corpsenm = NON_PM; /* generic egg */
  74.                  if (!rn2(3))
  75.                      for (tryct = 200; tryct > 0; --tryct) {
  76.                          mndx = can_be_hatched(rndmonnum());
  77.                          if (mndx != NON_PM && !dead_species(mndx, TRUE)) {
  78.                              otmp->corpsenm = mndx; /* typed egg */
  79.                              break;
  80.                          }
  81.                      }
  82.                  /* timer set below */
  83.                  break;
  84.              case TIN:
  85.                  otmp->corpsenm = NON_PM; /* empty (so far) */
  86.                  if (!rn2(6))
  87.                      set_tin_variety(otmp, SPINACH_TIN);
  88.                  else
  89.                      for (tryct = 200; tryct > 0; --tryct) {
  90.                          mndx = undead_to_corpse(rndmonnum());
  91.                          if (mons[mndx].cnutrit
  92.                              && !(mvitals[mndx].mvflags & G_NOCORPSE)) {
  93.                              otmp->corpsenm = mndx;
  94.                              set_tin_variety(otmp, RANDOM_TIN);
  95.                              break;
  96.                          }
  97.                      }
  98.                  blessorcurse(otmp, 10);
  99.                  break;
  100.              case SLIME_MOLD:
  101.                  otmp->spe = context.current_fruit;
  102.                  flags.made_fruit = TRUE;
  103.                  break;
  104.              case KELP_FROND:
  105.                  otmp->quan = (long) rnd(2);
  106.                  break;
  107.              }
  108.              if (Is_pudding(otmp)) {
  109.                  otmp->globby = 1;
  110.                  otmp->known = otmp->bknown = otmp->rknown = otmp->dknown = 1;
  111.                  otmp->corpsenm =
  112.                      PM_GRAY_OOZE + (otmp->otyp - GLOB_OF_GRAY_OOZE);
  113.                  /* this ensures that they don't fail merging because of
  114.                   * BUC status or other irrelevancies */
  115.              } else {
  116.                  if (otmp->otyp != CORPSE && otmp->otyp != MEAT_RING
  117.                      && otmp->otyp != KELP_FROND && !rn2(6)) {
  118.                      otmp->quan = 2L;
  119.                  }
  120.              }
  121.              break;
  122.          case GEM_CLASS:
  123.              otmp->corpsenm = 0; /* LOADSTONE hack */
  124.              if (otmp->otyp == LOADSTONE)
  125.                  curse(otmp);
  126.              else if (otmp->otyp == ROCK)
  127.                  otmp->quan = (long) rn1(6, 6);
  128.              else if (otmp->otyp != LUCKSTONE && !rn2(6))
  129.                  otmp->quan = 2L;
  130.              else
  131.                  otmp->quan = 1L;
  132.              break;
  133.          case TOOL_CLASS:
  134.              switch (otmp->otyp) {
  135.              case TALLOW_CANDLE:
  136.              case WAX_CANDLE:
  137.                  otmp->spe = 1;
  138.                  otmp->age = 20L * /* 400 or 200 */
  139.                              (long) objects[otmp->otyp].oc_cost;
  140.                  otmp->lamplit = 0;
  141.                  otmp->quan = 1L + (long) (rn2(2) ? rn2(7) : 0);
  142.                  blessorcurse(otmp, 5);
  143.                  break;
  144.              case BRASS_LANTERN:
  145.              case OIL_LAMP:
  146.                  otmp->spe = 1;
  147.                  otmp->age = (long) rn1(500, 1000);
  148.                  otmp->lamplit = 0;
  149.                  blessorcurse(otmp, 5);
  150.                  break;
  151.              case MAGIC_LAMP:
  152.                  otmp->spe = 1;
  153.                  otmp->lamplit = 0;
  154.                  blessorcurse(otmp, 2);
  155.                  break;
  156.              case CHEST:
  157.              case LARGE_BOX:
  158.                  otmp->olocked = !!(rn2(5));
  159.                  otmp->otrapped = !(rn2(10));
  160.              case ICE_BOX:
  161.              case SACK:
  162.              case OILSKIN_SACK:
  163.              case BAG_OF_HOLDING:
  164.                  mkbox_cnts(otmp);
  165.                  break;
  166.              case LEASH:
  167.                  otmp->leashmon = 0;
  168.                  break;
  169.              case EXPENSIVE_CAMERA:
  170.              case TINNING_KIT:
  171.              case MAGIC_MARKER:
  172.                  otmp->spe = rn1(70, 30);
  173.                  break;
  174.              case CAN_OF_GREASE:
  175.                  otmp->spe = rnd(25);
  176.                  blessorcurse(otmp, 10);
  177.                  break;
  178.              case CRYSTAL_BALL:
  179.                  otmp->spe = rnd(5);
  180.                  blessorcurse(otmp, 2);
  181.                  break;
  182.              case HORN_OF_PLENTY:
  183.              case BAG_OF_TRICKS:
  184.                  otmp->spe = rnd(20);
  185.                  break;
  186.              case FIGURINE: {
  187.                  int tryct2 = 0;
  188.                  do
  189.                      otmp->corpsenm = rndmonnum();
  190.                  while (is_human(&mons[otmp->corpsenm]) && tryct2++ < 30);
  191.                  blessorcurse(otmp, 4);
  192.                  break;
  193.              }
  194.              case BELL_OF_OPENING:
  195.                  otmp->spe = 3;
  196.                  break;
  197.              case MAGIC_FLUTE:
  198.              case MAGIC_HARP:
  199.              case FROST_HORN:
  200.              case FIRE_HORN:
  201.              case DRUM_OF_EARTHQUAKE:
  202.                  otmp->spe = rn1(5, 4);
  203.                  break;
  204.              }
  205.              break;
  206.          case AMULET_CLASS:
  207.              if (otmp->otyp == AMULET_OF_YENDOR)
  208.                  context.made_amulet = TRUE;
  209.              if (rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION
  210.                              || otmp->otyp == AMULET_OF_CHANGE
  211.                              || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) {
  212.                  curse(otmp);
  213.              } else
  214.                  blessorcurse(otmp, 10);
  215.          case VENOM_CLASS:
  216.          case CHAIN_CLASS:
  217.          case BALL_CLASS:
  218.              break;
  219.          case POTION_CLASS:
  220.              otmp->fromsink = 0;
  221.              if (otmp->otyp == POT_OIL)
  222.                  otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */
  223.          /* fall through */
  224.          case SCROLL_CLASS:
  225.  #ifdef MAIL
  226.              if (otmp->otyp != SCR_MAIL)
  227.  #endif
  228.                  blessorcurse(otmp, 4);
  229.              break;
  230.          case SPBOOK_CLASS:
  231.              otmp->spestudied = 0;
  232.              blessorcurse(otmp, 17);
  233.              break;
  234.          case ARMOR_CLASS:
  235.              if (rn2(10)
  236.                  && (otmp->otyp == FUMBLE_BOOTS
  237.                      || otmp->otyp == LEVITATION_BOOTS
  238.                      || otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT
  239.                      || otmp->otyp == GAUNTLETS_OF_FUMBLING || !rn2(11))) {
  240.                  curse(otmp);
  241.                  otmp->spe = -rne(3);
  242.              } else if (!rn2(10)) {
  243.                  otmp->blessed = rn2(2);
  244.                  otmp->spe = rne(3);
  245.              } else
  246.                  blessorcurse(otmp, 10);
  247.              if (artif && !rn2(40))
  248.                  otmp = mk_artifact(otmp, (aligntyp) A_NONE);
  249.              /* simulate lacquered armor for samurai */
  250.              if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL
  251.                  && (moves <= 1 || In_quest(&u.uz))) {
  252.  #ifdef UNIXPC
  253.                  /* optimizer bitfield bug */
  254.                  otmp->oerodeproof = 1;
  255.                  otmp->rknown = 1;
  256.  #else
  257.                  otmp->oerodeproof = otmp->rknown = 1;
  258.  #endif
  259.              }
  260.              break;
  261.          case WAND_CLASS:
  262.              if (otmp->otyp == WAN_WISHING)
  263.                  otmp->spe = rnd(3);
  264.              else
  265.                  otmp->spe =
  266.                      rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4);
  267.              blessorcurse(otmp, 17);
  268.              otmp->recharged = 0; /* used to control recharging */
  269.              break;
  270.          case RING_CLASS:
  271.              if (objects[otmp->otyp].oc_charged) {
  272.                  blessorcurse(otmp, 3);
  273.                  if (rn2(10)) {
  274.                      if (rn2(10) && bcsign(otmp))
  275.                          otmp->spe = bcsign(otmp) * rne(3);
  276.                      else
  277.                          otmp->spe = rn2(2) ? rne(3) : -rne(3);
  278.                  }
  279.                  /* make useless +0 rings much less common */
  280.                  if (otmp->spe == 0)
  281.                      otmp->spe = rn2(4) - rn2(3);
  282.                  /* negative rings are usually cursed */
  283.                  if (otmp->spe < 0 && rn2(5))
  284.                      curse(otmp);
  285.              } else if (rn2(10) && (otmp->otyp == RIN_TELEPORTATION
  286.                                     || otmp->otyp == RIN_POLYMORPH
  287.                                     || otmp->otyp == RIN_AGGRAVATE_MONSTER
  288.                                     || otmp->otyp == RIN_HUNGER || !rn2(9))) {
  289.                  curse(otmp);
  290.              }
  291.              break;
  292.          case ROCK_CLASS:
  293.              switch (otmp->otyp) {
  294.              case STATUE:
  295.                  /* possibly overridden by mkcorpstat() */
  296.                  otmp->corpsenm = rndmonnum();
  297.                  if (!verysmall(&mons[otmp->corpsenm])
  298.                      && rn2(level_difficulty() / 2 + 10) > 10)
  299.                      (void) add_to_container(otmp, mkobj(SPBOOK_CLASS, FALSE));
  300.              }
  301.              break;
  302.          case COIN_CLASS:
  303.              break; /* do nothing */
  304.          default:
  305.              impossible("impossible mkobj %d, sym '%c'.", otmp->otyp,
  306.                         objects[otmp->otyp].oc_class);
  307.              return (struct obj *) 0;
  308.          }
  309.  
  310.      /* some things must get done (corpsenm, timers) even if init = 0 */
  311.      switch (otmp->otyp) {
  312.      case CORPSE:
  313.          if (otmp->corpsenm == NON_PM) {
  314.              otmp->corpsenm = undead_to_corpse(rndmonnum());
  315.              if (mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE))
  316.                  otmp->corpsenm = urole.malenum;
  317.          }
  318.      /*FALLTHRU*/
  319.      case STATUE:
  320.      case FIGURINE:
  321.          if (otmp->corpsenm == NON_PM)
  322.              otmp->corpsenm = rndmonnum();
  323.      /*FALLTHRU*/
  324.      case EGG:
  325.          /* case TIN: */
  326.          set_corpsenm(otmp, otmp->corpsenm);
  327.          break;
  328.      case SPE_NOVEL:
  329.          otmp->novelidx = -1; /* "none of the above"; will be changed */
  330.          otmp = oname(otmp, noveltitle(&otmp->novelidx));
  331.          break;
  332.      }
  333.  
  334.      /* unique objects may have an associated artifact entry */
  335.      if (objects[otyp].oc_unique && !otmp->oartifact)
  336.          otmp = mk_artifact(otmp, (aligntyp) A_NONE);
  337.      otmp->owt = weight(otmp);
  338.      return otmp;
  339.  }
  340.  

set_corpsenm

  1.  /*
  2.   * Several areas of the code made direct reassignments
  3.   * to obj->corpsenm. Because some special handling is
  4.   * required in certain cases, place that handling here
  5.   * and call this routine in place of the direct assignment.
  6.   *
  7.   * If the object was a lizard or lichen corpse:
  8.   *     - ensure that you don't end up with some
  9.   *       other corpse type which has no rot-away timer.
  10.   *
  11.   * If the object was a troll corpse:
  12.   *     - ensure that you don't end up with some other
  13.   *       corpse type which resurrects from the dead.
  14.   *
  15.   * Re-calculates the weight of figurines and corpses to suit the
  16.   * new species.
  17.   *
  18.   * Existing timeout value for egg hatch is preserved.
  19.   *
  20.   */
  21.  void
  22.  set_corpsenm(obj, id)
  23.  struct obj *obj;
  24.  int id;
  25.  {
  26.      long when = 0L;
  27.  
  28.      if (obj->timed) {
  29.          if (obj->otyp == EGG)
  30.              when = stop_timer(HATCH_EGG, obj_to_any(obj));
  31.          else {
  32.              when = 0L;
  33.              obj_stop_timers(obj); /* corpse or figurine */
  34.          }
  35.      }
  36.      obj->corpsenm = id;
  37.      switch (obj->otyp) {
  38.      case CORPSE:
  39.          start_corpse_timeout(obj);
  40.          obj->owt = weight(obj);
  41.          break;
  42.      case FIGURINE:
  43.          if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)
  44.              && (carried(obj) || mcarried(obj)))
  45.              attach_fig_transform_timeout(obj);
  46.          obj->owt = weight(obj);
  47.          break;
  48.      case EGG:
  49.          if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
  50.              attach_egg_hatch_timeout(obj, when);
  51.          break;
  52.      default: /* tin, etc. */
  53.          obj->owt = weight(obj);
  54.          break;
  55.      }
  56.  }
  57.  

start_corpse_timeout

  1.  /*
  2.   * Start a corpse decay or revive timer.
  3.   * This takes the age of the corpse into consideration as of 3.4.0.
  4.   */
  5.  void
  6.  start_corpse_timeout(body)
  7.  struct obj *body;
  8.  {
  9.      long when;       /* rot away when this old */
  10.      long corpse_age; /* age of corpse          */
  11.      int rot_adjust;
  12.      short action;
  13.  
  14.  #define TAINT_AGE (50L)        /* age when corpses go bad */
  15.  #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */
  16.  #define ROT_AGE (250L)         /* age when corpses rot away */
  17.  
  18.      /* lizards and lichen don't rot or revive */
  19.      if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN)
  20.          return;
  21.  
  22.      action = ROT_CORPSE;             /* default action: rot away */
  23.      rot_adjust = in_mklev ? 25 : 10; /* give some variation */
  24.      corpse_age = monstermoves - body->age;
  25.      if (corpse_age > ROT_AGE)
  26.          when = rot_adjust;
  27.      else
  28.          when = ROT_AGE - corpse_age;
  29.      when += (long) (rnz(rot_adjust) - rot_adjust);
  30.  
  31.      if (is_rider(&mons[body->corpsenm])) {
  32.          /*
  33.           * Riders always revive.  They have a 1/3 chance per turn
  34.           * of reviving after 12 turns.  Always revive by 500.
  35.           */
  36.          action = REVIVE_MON;
  37.          for (when = 12L; when < 500L; when++)
  38.              if (!rn2(3))
  39.                  break;
  40.  
  41.      } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) {
  42.          long age;
  43.          for (age = 2; age <= TAINT_AGE; age++)
  44.              if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */
  45.                  action = REVIVE_MON;
  46.                  when = age;
  47.                  break;
  48.              }
  49.      }
  50.  
  51.      if (body->norevive)
  52.          body->norevive = 0;
  53.      (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body));
  54.  }
  55.  

maybe_adjust_light

  1.  STATIC_OVL void
  2.  maybe_adjust_light(obj, old_range)
  3.  struct obj *obj;
  4.  int old_range;
  5.  {
  6.      char buf[BUFSZ];
  7.      xchar ox, oy;
  8.      int new_range = arti_light_radius(obj), delta = new_range - old_range;
  9.  
  10.      /* radius of light emitting artifact varies by curse/bless state
  11.         so will change after blessing or cursing */
  12.      if (delta) {
  13.          obj_adjust_light_radius(obj, new_range);
  14.          /* simplifying assumptions:  hero is wielding this object;
  15.             artifacts have to be in use to emit light and monsters'
  16.             gear won't change bless or curse state */
  17.          if (!Blind && get_obj_location(obj, &ox, &oy, 0)) {
  18.              *buf = '\0';
  19.              if (iflags.last_msg == PLNMSG_OBJ_GLOWS)
  20.                  /* we just saw "The <obj> glows <color>." from dipping */
  21.                  Strcpy(buf, (obj->quan == 1L) ? "It" : "They");
  22.              else if (carried(obj) || cansee(ox, oy))
  23.                  Strcpy(buf, Yname2(obj));
  24.              if (*buf) {
  25.                  /* initial activation says "dimly" if cursed,
  26.                     "brightly" if uncursed, and "brilliantly" if blessed;
  27.                     when changing intensity, using "less brightly" is
  28.                     straightforward for dimming, but we need "brighter"
  29.                     rather than "more brightly" for brightening; ugh */
  30.                  pline("%s %s %s%s.", buf, otense(obj, "shine"),
  31.                        (abs(delta) > 1) ? "much " : "",
  32.                        (delta > 0) ? "brighter" : "less brightly");
  33.              }
  34.          }
  35.      }
  36.  }
  37.  

bless

  1.  /*
  2.   *      bless(), curse(), unbless(), uncurse() -- any relevant message
  3.   *      about glowing amber/black/&c should be delivered prior to calling
  4.   *      these routines to make the actual curse/bless state change.
  5.   */
  6.  
  7.  void
  8.  bless(otmp)
  9.  register struct obj *otmp;
  10.  {
  11.      int old_light = 0;
  12.  
  13.      if (otmp->oclass == COIN_CLASS)
  14.          return;
  15.      if (otmp->lamplit)
  16.          old_light = arti_light_radius(otmp);
  17.      otmp->cursed = 0;
  18.      otmp->blessed = 1;
  19.      if (carried(otmp) && confers_luck(otmp))
  20.          set_moreluck();
  21.      else if (otmp->otyp == BAG_OF_HOLDING)
  22.          otmp->owt = weight(otmp);
  23.      else if (otmp->otyp == FIGURINE && otmp->timed)
  24.          (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp));
  25.      if (otmp->lamplit)
  26.          maybe_adjust_light(otmp, old_light);
  27.      return;
  28.  }
  29.  

unbless

  1.  void
  2.  unbless(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      int old_light = 0;
  6.  
  7.      if (otmp->lamplit)
  8.          old_light = arti_light_radius(otmp);
  9.      otmp->blessed = 0;
  10.      if (carried(otmp) && confers_luck(otmp))
  11.          set_moreluck();
  12.      else if (otmp->otyp == BAG_OF_HOLDING)
  13.          otmp->owt = weight(otmp);
  14.      if (otmp->lamplit)
  15.          maybe_adjust_light(otmp, old_light);
  16.  }
  17.  

curse

  1.  void
  2.  curse(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      int old_light = 0;
  6.  
  7.      if (otmp->oclass == COIN_CLASS)
  8.          return;
  9.      if (otmp->lamplit)
  10.          old_light = arti_light_radius(otmp);
  11.      otmp->blessed = 0;
  12.      otmp->cursed = 1;
  13.      /* welded two-handed weapon interferes with some armor removal */
  14.      if (otmp == uwep && bimanual(uwep))
  15.          reset_remarm();
  16.      /* rules at top of wield.c state that twoweapon cannot be done
  17.         with cursed alternate weapon */
  18.      if (otmp == uswapwep && u.twoweap)
  19.          drop_uswapwep();
  20.      /* some cursed items need immediate updating */
  21.      if (carried(otmp) && confers_luck(otmp))
  22.          set_moreluck();
  23.      else if (otmp->otyp == BAG_OF_HOLDING)
  24.          otmp->owt = weight(otmp);
  25.      else if (otmp->otyp == FIGURINE) {
  26.          if (otmp->corpsenm != NON_PM && !dead_species(otmp->corpsenm, TRUE)
  27.              && (carried(otmp) || mcarried(otmp)))
  28.              attach_fig_transform_timeout(otmp);
  29.      }
  30.      if (otmp->lamplit)
  31.          maybe_adjust_light(otmp, old_light);
  32.      return;
  33.  }
  34.  

uncurse

  1.  void
  2.  uncurse(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      int old_light = 0;
  6.  
  7.      if (otmp->lamplit)
  8.          old_light = arti_light_radius(otmp);
  9.      otmp->cursed = 0;
  10.      if (carried(otmp) && confers_luck(otmp))
  11.          set_moreluck();
  12.      else if (otmp->otyp == BAG_OF_HOLDING)
  13.          otmp->owt = weight(otmp);
  14.      else if (otmp->otyp == FIGURINE && otmp->timed)
  15.          (void) stop_timer(FIG_TRANSFORM, obj_to_any(otmp));
  16.      if (otmp->lamplit)
  17.          maybe_adjust_light(otmp, old_light);
  18.      return;
  19.  }
  20.  

blessorcurse

  1.  void
  2.  blessorcurse(otmp, chance)
  3.  register struct obj *otmp;
  4.  register int chance;
  5.  {
  6.      if (otmp->blessed || otmp->cursed)
  7.          return;
  8.  
  9.      if (!rn2(chance)) {
  10.          if (!rn2(2)) {
  11.              curse(otmp);
  12.          } else {
  13.              bless(otmp);
  14.          }
  15.      }
  16.      return;
  17.  }
  18.  

bcsign

  1.  int
  2.  bcsign(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      return (!!otmp->blessed - !!otmp->cursed);
  6.  }
  7.  
  8.  /*
  9.   *  Calculate the weight of the given object.  This will recursively follow
  10.   *  and calculate the weight of any containers.
  11.   *
  12.   *  Note:  It is possible to end up with an incorrect weight if some part
  13.   *         of the code messes with a contained object and doesn't update the
  14.   *         container's weight.
  15.   */
  16.  int
  17.  weight(obj)
  18.  register struct obj *obj;
  19.  {
  20.      int wt = objects[obj->otyp].oc_weight;
  21.  
  22.      if (SchroedingersBox(obj))
  23.          wt += mons[PM_HOUSECAT].cwt;
  24.      if (Is_container(obj) || obj->otyp == STATUE) {
  25.          struct obj *contents;
  26.          register int cwt = 0;
  27.  
  28.          if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM)
  29.              wt = (int) obj->quan * ((int) mons[obj->corpsenm].cwt * 3 / 2);
  30.  
  31.          for (contents = obj->cobj; contents; contents = contents->nobj)
  32.              cwt += weight(contents);
  33.          /*
  34.           *  The weight of bags of holding is calculated as the weight
  35.           *  of the bag plus the weight of the bag's contents modified
  36.           *  as follows:
  37.           *
  38.           *      Bag status      Weight of contents
  39.           *      ----------      ------------------
  40.           *      cursed                  2x
  41.           *      blessed                 x/4 [rounded up: (x+3)/4]
  42.           *      otherwise               x/2 [rounded up: (x+1)/2]
  43.           *
  44.           *  The macro DELTA_CWT in pickup.c also implements these
  45.           *  weight equations.
  46.           */
  47.          if (obj->otyp == BAG_OF_HOLDING)
  48.              cwt = obj->cursed ? (cwt * 2) : obj->blessed ? ((cwt + 3) / 4)
  49.                                                           : ((cwt + 1) / 2);
  50.  
  51.          return wt + cwt;
  52.      }
  53.      if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) {
  54.          long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt;
  55.  
  56.          wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int) long_wt;
  57.          if (obj->oeaten)
  58.              wt = eaten_stat(wt, obj);
  59.          return wt;
  60.      } else if (obj->oclass == FOOD_CLASS && obj->oeaten) {
  61.          return eaten_stat((int) obj->quan * wt, obj);
  62.      } else if (obj->oclass == COIN_CLASS) {
  63.          return (int) ((obj->quan + 50L) / 100L);
  64.      } else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) {
  65.          return (int) obj->owt; /* kludge for "very" heavy iron ball */
  66.      }
  67.      return (wt ? wt * (int) obj->quan : ((int) obj->quan + 1) >> 1);
  68.  }
  69.  

rnd_treefruit_at

  1.  static int treefruits[] = { APPLE, ORANGE, PEAR, BANANA, EUCALYPTUS_LEAF };
  2.  
  3.  struct obj *
  4.  rnd_treefruit_at(x, y)
  5.  int x, y;
  6.  {
  7.      return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE);
  8.  }
  9.  

mkgold

  1.  struct obj *
  2.  mkgold(amount, x, y)
  3.  long amount;
  4.  int x, y;
  5.  {
  6.      register struct obj *gold = g_at(x, y);
  7.  
  8.      if (amount <= 0L)
  9.          amount = (long) (1 + rnd(level_difficulty() + 2) * rnd(30));
  10.      if (gold) {
  11.          gold->quan += amount;
  12.      } else {
  13.          gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE);
  14.          gold->quan = amount;
  15.      }
  16.      gold->owt = weight(gold);
  17.      return gold;
  18.  }
  19.  

mkcorpstat

  1.  /* return TRUE if the corpse has special timing */
  2.  #define special_corpse(num)                                                 \
  3.      (((num) == PM_LIZARD) || ((num) == PM_LICHEN) || (is_rider(&mons[num])) \
  4.       || (mons[num].mlet == S_TROLL))
  5.  
  6.  /*
  7.   * OEXTRA note: Passing mtmp causes mtraits to be saved
  8.   * even if ptr passed as well, but ptr is always used for
  9.   * the corpse type (corpsenm). That allows the corpse type
  10.   * to be different from the original monster,
  11.   *      i.e.  vampire -> human corpse
  12.   * yet still allow restoration of the original monster upon
  13.   * resurrection.
  14.   */
  15.  struct obj *
  16.  mkcorpstat(objtype, mtmp, ptr, x, y, corpstatflags)
  17.  int objtype; /* CORPSE or STATUE */
  18.  struct monst *mtmp;
  19.  struct permonst *ptr;
  20.  int x, y;
  21.  unsigned corpstatflags;
  22.  {
  23.      register struct obj *otmp;
  24.      boolean init = ((corpstatflags & CORPSTAT_INIT) != 0);
  25.  
  26.      if (objtype != CORPSE && objtype != STATUE)
  27.          impossible("making corpstat type %d", objtype);
  28.      if (x == 0 && y == 0) { /* special case - random placement */
  29.          otmp = mksobj(objtype, init, FALSE);
  30.          if (otmp)
  31.              (void) rloco(otmp);
  32.      } else
  33.          otmp = mksobj_at(objtype, x, y, init, FALSE);
  34.      if (otmp) {
  35.          if (mtmp) {
  36.              struct obj *otmp2;
  37.  
  38.              if (!ptr)
  39.                  ptr = mtmp->data;
  40.              /* save_mtraits frees original data pointed to by otmp */
  41.              otmp2 = save_mtraits(otmp, mtmp);
  42.              if (otmp2)
  43.                  otmp = otmp2;
  44.          }
  45.          /* use the corpse or statue produced by mksobj() as-is
  46.             unless `ptr' is non-null */
  47.          if (ptr) {
  48.              int old_corpsenm = otmp->corpsenm;
  49.  
  50.              otmp->corpsenm = monsndx(ptr);
  51.              otmp->owt = weight(otmp);
  52.              if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm)
  53.                                           || special_corpse(otmp->corpsenm))) {
  54.                  obj_stop_timers(otmp);
  55.                  start_corpse_timeout(otmp);
  56.              }
  57.          }
  58.      }
  59.      return otmp;
  60.  }
  61.  

corpse_revive_type

  1.  /*
  2.   * Return the type of monster that this corpse will
  3.   * revive as, even if it has a monster structure
  4.   * attached to it. In that case, you can't just
  5.   * use obj->corpsenm, because the stored monster
  6.   * type can, and often is, different.
  7.   * The return value is an index into mons[].
  8.   */
  9.  int
  10.  corpse_revive_type(obj)
  11.  struct obj *obj;
  12.  {
  13.      int revivetype;
  14.      struct monst *mtmp;
  15.      if (has_omonst(obj)
  16.          && ((mtmp = get_mtraits(obj, FALSE)) != (struct monst *) 0)) {
  17.          /* mtmp is a temporary pointer to a monster's stored
  18.          attributes, not a real monster */
  19.          revivetype = mtmp->mnum;
  20.      } else
  21.          revivetype = obj->corpsenm;
  22.      return revivetype;
  23.  }
  24.  

obj_attach_mid

  1.  /*
  2.   * Attach a monster id to an object, to provide
  3.   * a lasting association between the two.
  4.   */
  5.  struct obj *
  6.  obj_attach_mid(obj, mid)
  7.  struct obj *obj;
  8.  unsigned mid;
  9.  {
  10.      if (!mid || !obj)
  11.          return (struct obj *) 0;
  12.      newomid(obj);
  13.      *OMID(obj) = mid;
  14.      return obj;
  15.  }
  16.  

save_mtraits

  1.  static struct obj *
  2.  save_mtraits(obj, mtmp)
  3.  struct obj *obj;
  4.  struct monst *mtmp;
  5.  {
  6.      if (mtmp->ispriest)
  7.          forget_temple_entry(mtmp); /* EPRI() */
  8.      if (!has_omonst(obj))
  9.          newomonst(obj);
  10.      if (has_omonst(obj)) {
  11.          struct monst *mtmp2 = OMONST(obj);
  12.  
  13.          *mtmp2 = *mtmp;
  14.          mtmp2->mextra = (struct mextra *) 0;
  15.          if (mtmp->data)
  16.              mtmp2->mnum = monsndx(mtmp->data);
  17.          /* invalidate pointers */
  18.          /* m_id is needed to know if this is a revived quest leader */
  19.          /* but m_id must be cleared when loading bones */
  20.          mtmp2->nmon = (struct monst *) 0;
  21.          mtmp2->data = (struct permonst *) 0;
  22.          mtmp2->minvent = (struct obj *) 0;
  23.          if (mtmp->mextra)
  24.              copy_mextra(mtmp2, mtmp);
  25.      }
  26.      return obj;
  27.  }
  28.  

get_mtraits

  1.  /* returns a pointer to a new monst structure based on
  2.   * the one contained within the obj.
  3.   */
  4.  struct monst *
  5.  get_mtraits(obj, copyof)
  6.  struct obj *obj;
  7.  boolean copyof;
  8.  {
  9.      struct monst *mtmp = (struct monst *) 0;
  10.      struct monst *mnew = (struct monst *) 0;
  11.  
  12.      if (has_omonst(obj))
  13.          mtmp = OMONST(obj);
  14.      if (mtmp) {
  15.          if (copyof) {
  16.              mnew = newmonst();
  17.              *mnew = *mtmp;
  18.              mnew->mextra = (struct mextra *) 0;
  19.              if (mtmp->mextra)
  20.                  copy_mextra(mnew, mtmp);
  21.          } else {
  22.              /* Never insert this returned pointer into mon chains! */
  23.              mnew = mtmp;
  24.          }
  25.      }
  26.      return mnew;
  27.  }
  28.  

mk_tt_object

  1.  /* make an object named after someone listed in the scoreboard file */
  2.  struct obj *
  3.  mk_tt_object(objtype, x, y)
  4.  int objtype; /* CORPSE or STATUE */
  5.  register int x, y;
  6.  {
  7.      register struct obj *otmp, *otmp2;
  8.      boolean initialize_it;
  9.  
  10.      /* player statues never contain books */
  11.      initialize_it = (objtype != STATUE);
  12.      if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) {
  13.          /* tt_oname will return null if the scoreboard is empty */
  14.          if ((otmp2 = tt_oname(otmp)) != 0)
  15.              otmp = otmp2;
  16.      }
  17.      return otmp;
  18.  }
  19.  

mk_named_object

  1.  /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */
  2.  struct obj *
  3.  mk_named_object(objtype, ptr, x, y, nm)
  4.  int objtype; /* CORPSE or STATUE */
  5.  struct permonst *ptr;
  6.  int x, y;
  7.  const char *nm;
  8.  {
  9.      struct obj *otmp;
  10.      unsigned corpstatflags =
  11.          (objtype != STATUE) ? CORPSTAT_INIT : CORPSTAT_NONE;
  12.  
  13.      otmp = mkcorpstat(objtype, (struct monst *) 0, ptr, x, y, corpstatflags);
  14.      if (nm)
  15.          otmp = oname(otmp, nm);
  16.      return otmp;
  17.  }
  18.  

is_flammable

  1.  boolean
  2.  is_flammable(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      int otyp = otmp->otyp;
  6.      int omat = objects[otyp].oc_material;
  7.  
  8.      /* Candles can be burned, but they're not flammable in the sense that
  9.       * they can't get fire damage and it makes no sense for them to be
  10.       * fireproofed.
  11.       */
  12.      if (Is_candle(otmp))
  13.          return FALSE;
  14.  
  15.      if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE)
  16.          return FALSE;
  17.  
  18.      return (boolean) ((omat <= WOOD && omat != LIQUID) || omat == PLASTIC);
  19.  }
  20.  

is_rottable

  1.  boolean
  2.  is_rottable(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      int otyp = otmp->otyp;
  6.  
  7.      return (boolean) (objects[otyp].oc_material <= WOOD
  8.                        && objects[otyp].oc_material != LIQUID);
  9.  }
  10.  

place_object

  1.  /*
  2.   * These routines maintain the single-linked lists headed in level.objects[][]
  3.   * and threaded through the nexthere fields in the object-instance structure.
  4.   */
  5.  
  6.  /* put the object at the given location */
  7.  void
  8.  place_object(otmp, x, y)
  9.  register struct obj *otmp;
  10.  int x, y;
  11.  {
  12.      register struct obj *otmp2 = level.objects[x][y];
  13.  
  14.      if (otmp->where != OBJ_FREE)
  15.          panic("place_object: obj not free");
  16.  
  17.      obj_no_longer_held(otmp);
  18.      /* (could bypass this vision update if there is already a boulder here) */
  19.      if (otmp->otyp == BOULDER)
  20.          block_point(x, y); /* vision */
  21.  
  22.      /* obj goes under boulders */
  23.      if (otmp2 && (otmp2->otyp == BOULDER)) {
  24.          otmp->nexthere = otmp2->nexthere;
  25.          otmp2->nexthere = otmp;
  26.      } else {
  27.          otmp->nexthere = otmp2;
  28.          level.objects[x][y] = otmp;
  29.      }
  30.  
  31.      /* set the new object's location */
  32.      otmp->ox = x;
  33.      otmp->oy = y;
  34.  
  35.      otmp->where = OBJ_FLOOR;
  36.  
  37.      /* add to floor chain */
  38.      otmp->nobj = fobj;
  39.      fobj = otmp;
  40.      if (otmp->timed)
  41.          obj_timer_checks(otmp, x, y, 0);
  42.  }
  43.  

obj_ice_effects

  1.  #define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */
  2.  
  3.  /* If ice was affecting any objects correct that now
  4.   * Also used for starting ice effects too. [zap.c]
  5.   */
  6.  void
  7.  obj_ice_effects(x, y, do_buried)
  8.  int x, y;
  9.  boolean do_buried;
  10.  {
  11.      struct obj *otmp;
  12.  
  13.      for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) {
  14.          if (otmp->timed)
  15.              obj_timer_checks(otmp, x, y, 0);
  16.      }
  17.      if (do_buried) {
  18.          for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) {
  19.              if (otmp->ox == x && otmp->oy == y) {
  20.                  if (otmp->timed)
  21.                      obj_timer_checks(otmp, x, y, 0);
  22.              }
  23.          }
  24.      }
  25.  }
  26.  

peek_at_iced_corpse_age

  1.  /*
  2.   * Returns an obj->age for a corpse object on ice, that would be the
  3.   * actual obj->age if the corpse had just been lifted from the ice.
  4.   * This is useful when just using obj->age in a check or calculation because
  5.   * rot timers pertaining to the object don't have to be stopped and
  6.   * restarted etc.
  7.   */
  8.  long
  9.  peek_at_iced_corpse_age(otmp)
  10.  struct obj *otmp;
  11.  {
  12.      long age, retval = otmp->age;
  13.  
  14.      if (otmp->otyp == CORPSE && otmp->on_ice) {
  15.          /* Adjust the age; must be same as obj_timer_checks() for off ice*/
  16.          age = monstermoves - otmp->age;
  17.          retval += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT;
  18.          debugpline3(
  19.            "The %s age has ice modifications: otmp->age = %ld, returning %ld.",
  20.                      s_suffix(doname(otmp)), otmp->age, retval);
  21.          debugpline1("Effective age of corpse: %ld.", monstermoves - retval);
  22.      }
  23.      return retval;
  24.  }
  25.  

obj_timer_checks

  1.  STATIC_OVL void
  2.  obj_timer_checks(otmp, x, y, force)
  3.  struct obj *otmp;
  4.  xchar x, y;
  5.  int force; /* 0 = no force so do checks, <0 = force off, >0 force on */
  6.  {
  7.      long tleft = 0L;
  8.      short action = ROT_CORPSE;
  9.      boolean restart_timer = FALSE;
  10.      boolean on_floor = (otmp->where == OBJ_FLOOR);
  11.      boolean buried = (otmp->where == OBJ_BURIED);
  12.  
  13.      /* Check for corpses just placed on or in ice */
  14.      if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x, y)) {
  15.          tleft = stop_timer(action, obj_to_any(otmp));
  16.          if (tleft == 0L) {
  17.              action = REVIVE_MON;
  18.              tleft = stop_timer(action, obj_to_any(otmp));
  19.          }
  20.          if (tleft != 0L) {
  21.              long age;
  22.  
  23.              /* mark the corpse as being on ice */
  24.              otmp->on_ice = 1;
  25.              debugpline3("%s is now on ice at <%d,%d>.", The(xname(otmp)), x,
  26.                          y);
  27.              /* Adjust the time remaining */
  28.              tleft *= ROT_ICE_ADJUSTMENT;
  29.              restart_timer = TRUE;
  30.              /* Adjust the age; time spent off ice needs to be multiplied
  31.                 by the ice adjustment and subtracted from the age so that
  32.                 later calculations behave as if it had been on ice during
  33.                 that time (longwinded way of saying this is the inverse
  34.                 of removing it from the ice and of peeking at its age). */
  35.              age = monstermoves - otmp->age;
  36.              otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT);
  37.          }
  38.  
  39.      /* Check for corpses coming off ice */
  40.      } else if (force < 0 || (otmp->otyp == CORPSE && otmp->on_ice
  41.                               && !((on_floor || buried) && is_ice(x, y)))) {
  42.          tleft = stop_timer(action, obj_to_any(otmp));
  43.          if (tleft == 0L) {
  44.              action = REVIVE_MON;
  45.              tleft = stop_timer(action, obj_to_any(otmp));
  46.          }
  47.          if (tleft != 0L) {
  48.              long age;
  49.  
  50.              otmp->on_ice = 0;
  51.              debugpline3("%s is no longer on ice at <%d,%d>.",
  52.                          The(xname(otmp)), x, y);
  53.              /* Adjust the remaining time */
  54.              tleft /= ROT_ICE_ADJUSTMENT;
  55.              restart_timer = TRUE;
  56.              /* Adjust the age */
  57.              age = monstermoves - otmp->age;
  58.              otmp->age += age * (ROT_ICE_ADJUSTMENT - 1) / ROT_ICE_ADJUSTMENT;
  59.          }
  60.      }
  61.  
  62.      /* now re-start the timer with the appropriate modifications */
  63.      if (restart_timer)
  64.          (void) start_timer(tleft, TIMER_OBJECT, action, obj_to_any(otmp));
  65.  }
  66.  
  67.  #undef ROT_ICE_ADJUSTMENT
  68.  

remove_object

  1.  void
  2.  remove_object(otmp)
  3.  register struct obj *otmp;
  4.  {
  5.      xchar x = otmp->ox;
  6.      xchar y = otmp->oy;
  7.  
  8.      if (otmp->where != OBJ_FLOOR)
  9.          panic("remove_object: obj not on floor");
  10.      extract_nexthere(otmp, &level.objects[x][y]);
  11.      extract_nobj(otmp, &fobj);
  12.      /* update vision iff this was the only boulder at its spot */
  13.      if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y))
  14.          unblock_point(x, y); /* vision */
  15.      if (otmp->timed)
  16.          obj_timer_checks(otmp, x, y, 0);
  17.  }
  18.  

discard_minvent

  1.  /* throw away all of a monster's inventory */
  2.  void
  3.  discard_minvent(mtmp)
  4.  struct monst *mtmp;
  5.  {
  6.      struct obj *otmp, *mwep = MON_WEP(mtmp);
  7.      boolean keeping_mon = (mtmp->mhp > 0);
  8.  
  9.      while ((otmp = mtmp->minvent) != 0) {
  10.          /* this has now become very similar to m_useupall()... */
  11.          obj_extract_self(otmp);
  12.          if (otmp->owornmask) {
  13.              if (keeping_mon) {
  14.                  if (otmp == mwep)
  15.                      mwepgone(mtmp), mwep = 0;
  16.                  mtmp->misc_worn_check &= ~otmp->owornmask;
  17.                  update_mon_intrinsics(mtmp, otmp, FALSE, TRUE);
  18.              }
  19.              otmp->owornmask = 0L; /* obfree() expects this */
  20.          }
  21.          obfree(otmp, (struct obj *) 0); /* dealloc_obj() isn't sufficient */
  22.      }
  23.  }
  24.  

obj_extract_self

  1.  /*
  2.   * Free obj from whatever list it is on in preparation for deleting it
  3.   * or moving it elsewhere; obj->where will end up set to OBJ_FREE.
  4.   * Doesn't handle unwearing of objects in hero's or monsters' inventories.
  5.   *
  6.   * Object positions:
  7.   *      OBJ_FREE        not on any list
  8.   *      OBJ_FLOOR       fobj, level.locations[][] chains (use remove_object)
  9.   *      OBJ_CONTAINED   cobj chain of container object
  10.   *      OBJ_INVENT      hero's invent chain (use freeinv)
  11.   *      OBJ_MINVENT     monster's invent chain
  12.   *      OBJ_MIGRATING   migrating chain
  13.   *      OBJ_BURIED      level.buriedobjs chain
  14.   *      OBJ_ONBILL      on billobjs chain
  15.   */
  16.  void
  17.  obj_extract_self(obj)
  18.  struct obj *obj;
  19.  {
  20.      switch (obj->where) {
  21.      case OBJ_FREE:
  22.          break;
  23.      case OBJ_FLOOR:
  24.          remove_object(obj);
  25.          break;
  26.      case OBJ_CONTAINED:
  27.          extract_nobj(obj, &obj->ocontainer->cobj);
  28.          container_weight(obj->ocontainer);
  29.          break;
  30.      case OBJ_INVENT:
  31.          freeinv(obj);
  32.          break;
  33.      case OBJ_MINVENT:
  34.          extract_nobj(obj, &obj->ocarry->minvent);
  35.          break;
  36.      case OBJ_MIGRATING:
  37.          extract_nobj(obj, &migrating_objs);
  38.          break;
  39.      case OBJ_BURIED:
  40.          extract_nobj(obj, &level.buriedobjlist);
  41.          break;
  42.      case OBJ_ONBILL:
  43.          extract_nobj(obj, &billobjs);
  44.          break;
  45.      default:
  46.          panic("obj_extract_self");
  47.          break;
  48.      }
  49.  }
  50.  

extract_nobj

  1.  /* Extract the given object from the chain, following nobj chain. */
  2.  void
  3.  extract_nobj(obj, head_ptr)
  4.  struct obj *obj, **head_ptr;
  5.  {
  6.      struct obj *curr, *prev;
  7.  
  8.      curr = *head_ptr;
  9.      for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) {
  10.          if (curr == obj) {
  11.              if (prev)
  12.                  prev->nobj = curr->nobj;
  13.              else
  14.                  *head_ptr = curr->nobj;
  15.              break;
  16.          }
  17.      }
  18.      if (!curr)
  19.          panic("extract_nobj: object lost");
  20.      obj->where = OBJ_FREE;
  21.      obj->nobj = NULL;
  22.  }
  23.  

extract_nexthere

  1.  /*
  2.   * Extract the given object from the chain, following nexthere chain.
  3.   *
  4.   * This does not set obj->where, this function is expected to be called
  5.   * in tandem with extract_nobj, which does set it.
  6.   */
  7.  void
  8.  extract_nexthere(obj, head_ptr)
  9.  struct obj *obj, **head_ptr;
  10.  {
  11.      struct obj *curr, *prev;
  12.  
  13.      curr = *head_ptr;
  14.      for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) {
  15.          if (curr == obj) {
  16.              if (prev)
  17.                  prev->nexthere = curr->nexthere;
  18.              else
  19.                  *head_ptr = curr->nexthere;
  20.              break;
  21.          }
  22.      }
  23.      if (!curr)
  24.          panic("extract_nexthere: object lost");
  25.  }
  26.  

add_to_minv

  1.  /*
  2.   * Add obj to mon's inventory.  If obj is able to merge with something already
  3.   * in the inventory, then the passed obj is deleted and 1 is returned.
  4.   * Otherwise 0 is returned.
  5.   */
  6.  int
  7.  add_to_minv(mon, obj)
  8.  struct monst *mon;
  9.  struct obj *obj;
  10.  {
  11.      struct obj *otmp;
  12.  
  13.      if (obj->where != OBJ_FREE)
  14.          panic("add_to_minv: obj not free");
  15.  
  16.      /* merge if possible */
  17.      for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
  18.          if (merged(&otmp, &obj))
  19.              return 1; /* obj merged and then free'd */
  20.      /* else insert; don't bother forcing it to end of chain */
  21.      obj->where = OBJ_MINVENT;
  22.      obj->ocarry = mon;
  23.      obj->nobj = mon->minvent;
  24.      mon->minvent = obj;
  25.      return 0; /* obj on mon's inventory chain */
  26.  }
  27.  

add_to_container

  1.  /*
  2.   * Add obj to container, make sure obj is "free".  Returns (merged) obj.
  3.   * The input obj may be deleted in the process.
  4.   */
  5.  struct obj *
  6.  add_to_container(container, obj)
  7.  struct obj *container, *obj;
  8.  {
  9.      struct obj *otmp;
  10.  
  11.      if (obj->where != OBJ_FREE)
  12.          panic("add_to_container: obj not free");
  13.      if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT)
  14.          obj_no_longer_held(obj);
  15.  
  16.      /* merge if possible */
  17.      for (otmp = container->cobj; otmp; otmp = otmp->nobj)
  18.          if (merged(&otmp, &obj))
  19.              return otmp;
  20.  
  21.      obj->where = OBJ_CONTAINED;
  22.      obj->ocontainer = container;
  23.      obj->nobj = container->cobj;
  24.      container->cobj = obj;
  25.      return obj;
  26.  }
  27.  

add_to_migration

  1.  void
  2.  add_to_migration(obj)
  3.  struct obj *obj;
  4.  {
  5.      if (obj->where != OBJ_FREE)
  6.          panic("add_to_migration: obj not free");
  7.  
  8.      obj->where = OBJ_MIGRATING;
  9.      obj->nobj = migrating_objs;
  10.      migrating_objs = obj;
  11.  }
  12.  

add_to_buried

  1.  void
  2.  add_to_buried(obj)
  3.  struct obj *obj;
  4.  {
  5.      if (obj->where != OBJ_FREE)
  6.          panic("add_to_buried: obj not free");
  7.  
  8.      obj->where = OBJ_BURIED;
  9.      obj->nobj = level.buriedobjlist;
  10.      level.buriedobjlist = obj;
  11.  }
  12.  

container_weight

  1.  /* Recalculate the weight of this container and all of _its_ containers. */
  2.  STATIC_OVL void
  3.  container_weight(container)
  4.  struct obj *container;
  5.  {
  6.      container->owt = weight(container);
  7.      if (container->where == OBJ_CONTAINED)
  8.          container_weight(container->ocontainer);
  9.      /*
  10.          else if (container->where == OBJ_INVENT)
  11.          recalculate load delay here ???
  12.      */
  13.  }
  14.  

dealloc_obj

  1.  /*
  2.   * Deallocate the object.  _All_ objects should be run through here for
  3.   * them to be deallocated.
  4.   */
  5.  void
  6.  dealloc_obj(obj)
  7.  struct obj *obj;
  8.  {
  9.      if (obj->where != OBJ_FREE)
  10.          panic("dealloc_obj: obj not free");
  11.      if (obj->nobj)
  12.          panic("dealloc_obj with nobj");
  13.      if (obj->cobj)
  14.          panic("dealloc_obj with cobj");
  15.  
  16.      /* free up any timers attached to the object */
  17.      if (obj->timed)
  18.          obj_stop_timers(obj);
  19.  
  20.      /*
  21.       * Free up any light sources attached to the object.
  22.       *
  23.       * We may want to just call del_light_source() without any
  24.       * checks (requires a code change there).  Otherwise this
  25.       * list must track all objects that can have a light source
  26.       * attached to it (and also requires lamplit to be set).
  27.       */
  28.      if (obj_sheds_light(obj))
  29.          del_light_source(LS_OBJECT, obj_to_any(obj));
  30.  
  31.      if (obj == thrownobj)
  32.          thrownobj = 0;
  33.      if (obj == kickedobj)
  34.          kickedobj = 0;
  35.  
  36.      if (obj->oextra)
  37.          dealloc_oextra(obj);
  38.      free((genericptr_t) obj);
  39.  }
  40.  

hornoplenty

  1.  /* create an object from a horn of plenty; mirrors bagotricks(makemon.c) */
  2.  int
  3.  hornoplenty(horn, tipping)
  4.  struct obj *horn;
  5.  boolean tipping; /* caller emptying entire contents; affects shop handling */
  6.  {
  7.      int objcount = 0;
  8.  
  9.      if (!horn || horn->otyp != HORN_OF_PLENTY) {
  10.          impossible("bad horn o' plenty");
  11.      } else if (horn->spe < 1) {
  12.          pline1(nothing_happens);
  13.      } else {
  14.          struct obj *obj;
  15.          const char *what;
  16.  
  17.          consume_obj_charge(horn, !tipping);
  18.          if (!rn2(13)) {
  19.              obj = mkobj(POTION_CLASS, FALSE);
  20.              if (objects[obj->otyp].oc_magic)
  21.                  do {
  22.                      obj->otyp = rnd_class(POT_BOOZE, POT_WATER);
  23.                  } while (obj->otyp == POT_SICKNESS);
  24.              what = (obj->quan > 1L) ? "Some potions" : "A potion";
  25.          } else {
  26.              obj = mkobj(FOOD_CLASS, FALSE);
  27.              if (obj->otyp == FOOD_RATION && !rn2(7))
  28.                  obj->otyp = LUMP_OF_ROYAL_JELLY;
  29.              what = "Some food";
  30.          }
  31.          ++objcount;
  32.          pline("%s %s out.", what, vtense(what, "spill"));
  33.          obj->blessed = horn->blessed;
  34.          obj->cursed = horn->cursed;
  35.          obj->owt = weight(obj);
  36.          /* using a shop's horn of plenty entails a usage fee and also
  37.             confers ownership of the created item to the shopkeeper */
  38.          if (horn->unpaid)
  39.              addtobill(obj, FALSE, FALSE, tipping);
  40.          /* if it ended up on bill, we don't want "(unpaid, N zorkids)"
  41.             being included in its formatted name during next message */
  42.          iflags.suppress_price++;
  43.          if (!tipping) {
  44.              obj = hold_another_object(
  45.                  obj, u.uswallow ? "Oops!  %s out of your reach!"
  46.                                  : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
  47.                                     || levl[u.ux][u.uy].typ < IRONBARS
  48.                                     || levl[u.ux][u.uy].typ >= ICE)
  49.                                        ? "Oops!  %s away from you!"
  50.                                        : "Oops!  %s to the floor!",
  51.                  The(aobjnam(obj, "slip")), (const char *) 0);
  52.          } else {
  53.              /* assumes this is taking place at hero's location */
  54.              if (!can_reach_floor(TRUE)) {
  55.                  hitfloor(obj); /* does altar check, message, drop */
  56.              } else {
  57.                  if (IS_ALTAR(levl[u.ux][u.uy].typ))
  58.                      doaltarobj(obj); /* does its own drop message */
  59.                  else
  60.                      pline("%s %s to the %s.", Doname2(obj),
  61.                            otense(obj, "drop"), surface(u.ux, u.uy));
  62.                  dropy(obj);
  63.              }
  64.          }
  65.          iflags.suppress_price--;
  66.          if (horn->dknown)
  67.              makeknown(HORN_OF_PLENTY);
  68.      }
  69.      return objcount;
  70.  }
  71.  

obj_sanity_check

  1.  /* support for wizard-mode's `sanity_check' option */
  2.  
  3.  static const char NEARDATA /* pline formats for insane_object() */
  4.      ofmt0[] = "%s obj %s %s: %s",
  5.      ofmt3[] = "%s [not null] %s %s: %s",
  6.      /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */
  7.      mfmt1[] = "%s obj %s %s (%s)", mfmt2[] = "%s obj %s %s (%s) *not*";
  8.  
  9.  /* Check all object lists for consistency. */
  10.  void
  11.  obj_sanity_check()
  12.  {
  13.      int x, y;
  14.      struct obj *obj;
  15.  
  16.      objlist_sanity(fobj, OBJ_FLOOR, "floor sanity");
  17.  
  18.      /* check that the map's record of floor objects is consistent;
  19.         those objects should have already been sanity checked via
  20.         the floor list so container contents are skipped here */
  21.      for (x = 0; x < COLNO; x++)
  22.          for (y = 0; y < ROWNO; y++)
  23.              for (obj = level.objects[x][y]; obj; obj = obj->nexthere) {
  24.                  /* <ox,oy> should match <x,y>; <0,*> should always be empty */
  25.                  if (obj->where != OBJ_FLOOR || x == 0 || obj->ox != x
  26.                      || obj->oy != y) {
  27.                      char at_fmt[BUFSZ];
  28.  
  29.                      Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", x,
  30.                              y, obj->ox, obj->oy);
  31.                      insane_object(obj, at_fmt, "location sanity",
  32.                                    (struct monst *) 0);
  33.                  }
  34.              }
  35.  
  36.      objlist_sanity(invent, OBJ_INVENT, "invent sanity");
  37.      objlist_sanity(migrating_objs, OBJ_MIGRATING, "migrating sanity");
  38.      objlist_sanity(level.buriedobjlist, OBJ_BURIED, "buried sanity");
  39.      objlist_sanity(billobjs, OBJ_ONBILL, "bill sanity");
  40.  
  41.      mon_obj_sanity(fmon, "minvent sanity");
  42.      mon_obj_sanity(migrating_mons, "migrating minvent sanity");
  43.      /* monsters temporarily in transit;
  44.         they should have arrived with hero by the time we get called */
  45.      if (mydogs) {
  46.          pline("mydogs sanity [not empty]");
  47.          mon_obj_sanity(mydogs, "mydogs minvent sanity");
  48.      }
  49.  
  50.      /* objects temporarily freed from invent/floor lists;
  51.         they should have arrived somewhere by the time we get called */
  52.      if (thrownobj)
  53.          insane_object(thrownobj, ofmt3, "thrownobj sanity",
  54.                        (struct monst *) 0);
  55.      if (kickedobj)
  56.          insane_object(kickedobj, ofmt3, "kickedobj sanity",
  57.                        (struct monst *) 0);
  58.      /* [how about current_wand too?] */
  59.  }
  60.  

objlist_sanity

  1.  /* sanity check for objects on specified list (fobj, &c) */
  2.  STATIC_OVL void
  3.  objlist_sanity(objlist, wheretype, mesg)
  4.  struct obj *objlist;
  5.  int wheretype;
  6.  const char *mesg;
  7.  {
  8.      struct obj *obj;
  9.  
  10.      for (obj = objlist; obj; obj = obj->nobj) {
  11.          if (obj->where != wheretype)
  12.              insane_object(obj, ofmt0, mesg, (struct monst *) 0);
  13.          if (Has_contents(obj)) {
  14.              if (wheretype == OBJ_ONBILL)
  15.                  /* containers on shop bill should always be empty */
  16.                  insane_object(obj, "%s obj contains something! %s %s: %s",
  17.                                mesg, (struct monst *) 0);
  18.              check_contained(obj, mesg);
  19.          }
  20.          if (obj->owornmask) {
  21.              char maskbuf[40];
  22.              boolean bc_ok = FALSE;
  23.  
  24.              switch (obj->where) {
  25.              case OBJ_INVENT:
  26.              case OBJ_MINVENT:
  27.                  sanity_check_worn(obj);
  28.                  break;
  29.              case OBJ_MIGRATING:
  30.                  /* migrating objects overload the owornmask field
  31.                     with a destination code; skip attempt to check it */
  32.                  break;
  33.              case OBJ_FLOOR:
  34.                  /* note: ball and chain can also be OBJ_FREE, but not across
  35.                     turns so this sanity check shouldn't encounter that */
  36.                  bc_ok = TRUE;
  37.              /*FALLTHRU*/
  38.              default:
  39.                  if ((obj != uchain && obj != uball) || !bc_ok) {
  40.                      /* discovered an object not in inventory which
  41.                         erroneously has worn mask set */
  42.                      Sprintf(maskbuf, "worn mask 0x%08lx", obj->owornmask);
  43.                      insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
  44.                  }
  45.                  break;
  46.              }
  47.          }
  48.      }
  49.  }
  50.  

mon_obj_sanity

  1.  /* sanity check for objects carried by all monsters in specified list */
  2.  STATIC_OVL void
  3.  mon_obj_sanity(monlist, mesg)
  4.  struct monst *monlist;
  5.  const char *mesg;
  6.  {
  7.      struct monst *mon;
  8.      struct obj *obj, *mwep;
  9.  
  10.      for (mon = monlist; mon; mon = mon->nmon) {
  11.          if (DEADMONSTER(mon)) continue;
  12.          mwep = MON_WEP(mon);
  13.          if (mwep) {
  14.              if (!mcarried(mwep))
  15.                  insane_object(mwep, mfmt1, mesg, mon);
  16.              if (mwep->ocarry != mon)
  17.                  insane_object(mwep, mfmt2, mesg, mon);
  18.          }
  19.          for (obj = mon->minvent; obj; obj = obj->nobj) {
  20.              if (obj->where != OBJ_MINVENT)
  21.                  insane_object(obj, mfmt1, mesg, mon);
  22.              if (obj->ocarry != mon)
  23.                  insane_object(obj, mfmt2, mesg, mon);
  24.              check_contained(obj, mesg);
  25.          }
  26.      }
  27.  }
  28.  

where_name

  1.  /* This must stay consistent with the defines in obj.h. */
  2.  static const char *obj_state_names[NOBJ_STATES] = { "free",      "floor",
  3.                                                      "contained", "invent",
  4.                                                      "minvent",   "migrating",
  5.                                                      "buried",    "onbill" };
  6.  
  7.  STATIC_OVL const char *
  8.  where_name(obj)
  9.  struct obj *obj;
  10.  {
  11.      static char unknown[32]; /* big enough to handle rogue 64-bit int */
  12.      int where;
  13.  
  14.      if (!obj)
  15.          return "nowhere";
  16.      where = obj->where;
  17.      if (where < 0 || where >= NOBJ_STATES || !obj_state_names[where]) {
  18.          Sprintf(unknown, "unknown[%d]", where);
  19.          return unknown;
  20.      }
  21.      return obj_state_names[where];
  22.  }
  23.  

insane_object

  1.  STATIC_OVL void
  2.  insane_object(obj, fmt, mesg, mon)
  3.  struct obj *obj;
  4.  const char *fmt, *mesg;
  5.  struct monst *mon;
  6.  {
  7.      const char *objnm, *monnm;
  8.      char altfmt[BUFSZ];
  9.  
  10.      objnm = monnm = "null!";
  11.      if (obj) {
  12.          iflags.override_ID++;
  13.          objnm = doname(obj);
  14.          iflags.override_ID--;
  15.      }
  16.      if (mon || (strstri(mesg, "minvent") && !strstri(mesg, "contained"))) {
  17.          Strcat(strcpy(altfmt, fmt), " held by mon %s (%s)");
  18.          if (mon)
  19.              monnm = x_monnam(mon, ARTICLE_A, (char *) 0, EXACT_NAME, TRUE);
  20.          pline(altfmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj),
  21.                objnm, fmt_ptr((genericptr_t) mon), monnm);
  22.      } else {
  23.          pline(fmt, mesg, fmt_ptr((genericptr_t) obj), where_name(obj), objnm);
  24.      }
  25.  }
  26.  

check_contained

  1.  /* obj sanity check: check objects inside container */
  2.  STATIC_OVL void
  3.  check_contained(container, mesg)
  4.  struct obj *container;
  5.  const char *mesg;
  6.  {
  7.      struct obj *obj;
  8.      /* big enough to work with, not too big to blow out stack in recursion */
  9.      char mesgbuf[40], nestedmesg[120];
  10.  
  11.      if (!Has_contents(container))
  12.          return;
  13.      /* change "invent sanity" to "contained invent sanity"
  14.         but leave "nested contained invent sanity" as is */
  15.      if (!strstri(mesg, "contained"))
  16.          mesg = strcat(strcpy(mesgbuf, "contained "), mesg);
  17.  
  18.      for (obj = container->cobj; obj; obj = obj->nobj) {
  19.          /* catch direct cycle to avoid unbounded recursion */
  20.          if (obj == container)
  21.              panic("failed sanity check: container holds itself");
  22.          if (obj->where != OBJ_CONTAINED)
  23.              insane_object(obj, "%s obj %s %s: %s", mesg, (struct monst *) 0);
  24.          else if (obj->ocontainer != container)
  25.              pline("%s obj %s in container %s, not %s", mesg,
  26.                    fmt_ptr((genericptr_t) obj),
  27.                    fmt_ptr((genericptr_t) obj->ocontainer),
  28.                    fmt_ptr((genericptr_t) container));
  29.  
  30.          if (Has_contents(obj)) {
  31.              /* catch most likely indirect cycle; we won't notice if
  32.                 parent is present when something comes before it, or
  33.                 notice more deeply embedded cycles (grandparent, &c) */
  34.              if (obj->cobj == container)
  35.                  panic("failed sanity check: container holds its parent");
  36.              /* change "contained... sanity" to "nested contained... sanity"
  37.                 and "nested contained..." to "nested nested contained..." */
  38.              Strcpy(nestedmesg, "nested ");
  39.              copynchars(eos(nestedmesg), mesg, (int) sizeof nestedmesg
  40.                                                    - (int) strlen(nestedmesg)
  41.                                                    - 1);
  42.              /* recursively check contents */
  43.              check_contained(obj, nestedmesg);
  44.          }
  45.      }
  46.  }
  47.  

sanity_check_worn

  1.  /* check an object in hero's or monster's inventory which has worn mask set */
  2.  STATIC_OVL void
  3.  sanity_check_worn(obj)
  4.  struct obj *obj;
  5.  {
  6.  #if defined(BETA) || defined(DEBUG)
  7.      static unsigned long wearbits[] = {
  8.          W_ARM,    W_ARMC,   W_ARMH,    W_ARMS, W_ARMG,  W_ARMF,  W_ARMU,
  9.          W_WEP,    W_QUIVER, W_SWAPWEP, W_AMUL, W_RINGL, W_RINGR, W_TOOL,
  10.          W_SADDLE, W_BALL,   W_CHAIN,   0
  11.          /* [W_ART,W_ARTI are property bits for items which aren't worn] */
  12.      };
  13.      char maskbuf[60];
  14.      const char *what;
  15.      unsigned long owornmask, allmask = 0L;
  16.      boolean embedded = FALSE;
  17.      int i, n = 0;
  18.  
  19.      /* use owornmask for testing and bit twiddling, but use original
  20.         obj->owornmask for printing */
  21.      owornmask = obj->owornmask;
  22.      /* figure out how many bits are set, and also which are viable */
  23.      for (i = 0; wearbits[i]; ++i) {
  24.          if ((owornmask & wearbits[i]) != 0L)
  25.              ++n;
  26.          allmask |= wearbits[i];
  27.      }
  28.      if (obj == uskin) {
  29.          /* embedded dragon scales have an extra bit set;
  30.             make sure it's set, then suppress it */
  31.          embedded = TRUE;
  32.          if ((owornmask & (W_ARM | I_SPECIAL)) == (W_ARM | I_SPECIAL))
  33.              owornmask &= ~I_SPECIAL;
  34.          else
  35.              n = 0,  owornmask = ~0; /* force insane_object("bogus") below */
  36.      }
  37.      if (n == 2 && carried(obj)
  38.          && obj == uball && (owornmask & W_BALL) != 0L
  39.          && (owornmask & W_WEAPON) != 0L) {
  40.          /* chained ball can be wielded/alt-wielded/quivered; if so,
  41.            pretend it's not chained in order to check the weapon pointer
  42.            (we've already verified the ball pointer by successfully passing
  43.            the if-condition to get here...) */
  44.          owornmask &= ~W_BALL;
  45.          n = 1;
  46.      }
  47.      if (n > 1) {
  48.          /* multiple bits set */
  49.          Sprintf(maskbuf, "worn mask (multiple) 0x%08lx", obj->owornmask);
  50.          insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
  51.      }
  52.      if ((owornmask & ~allmask) != 0L
  53.          || (carried(obj) && (owornmask & W_SADDLE) != 0L)) {
  54.          /* non-wearable bit(s) set */
  55.          Sprintf(maskbuf, "worn mask (bogus)) 0x%08lx", obj->owornmask);
  56.          insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
  57.      }
  58.      if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L)) {
  59.          what = 0;
  60.          /* verify that obj in hero's invent (or ball/chain elsewhere)
  61.             with owornmask of W_foo is the object pointed to by ufoo */
  62.          switch (owornmask) {
  63.          case W_ARM:
  64.              if (obj != (embedded ? uskin : uarm))
  65.                  what = embedded ? "skin" : "suit";
  66.              break;
  67.          case W_ARMC:
  68.              if (obj != uarmc)
  69.                  what = "cloak";
  70.              break;
  71.          case W_ARMH:
  72.              if (obj != uarmh)
  73.                  what = "helm";
  74.              break;
  75.          case W_ARMS:
  76.              if (obj != uarms)
  77.                  what = "shield";
  78.              break;
  79.          case W_ARMG:
  80.              if (obj != uarmg)
  81.                  what = "gloves";
  82.              break;
  83.          case W_ARMF:
  84.              if (obj != uarmf)
  85.                  what = "boots";
  86.              break;
  87.          case W_ARMU:
  88.              if (obj != uarmu)
  89.                  what = "shirt";
  90.              break;
  91.          case W_WEP:
  92.              if (obj != uwep)
  93.                  what = "primary weapon";
  94.              break;
  95.          case W_QUIVER:
  96.              if (obj != uquiver)
  97.                  what = "quiver";
  98.              break;
  99.          case W_SWAPWEP:
  100.              if (obj != uswapwep)
  101.                  what = u.twoweap ? "secondary weapon" : "alternate weapon";
  102.              break;
  103.          case W_AMUL:
  104.              if (obj != uamul)
  105.                  what = "amulet";
  106.              break;
  107.          case W_RINGL:
  108.              if (obj != uleft)
  109.                  what = "left ring";
  110.              break;
  111.          case W_RINGR:
  112.              if (obj != uright)
  113.                  what = "right ring";
  114.              break;
  115.          case W_TOOL:
  116.              if (obj != ublindf)
  117.                  what = "blindfold";
  118.              break;
  119.          /* case W_SADDLE: */
  120.          case W_BALL:
  121.              if (obj != uball)
  122.                  what = "ball";
  123.              break;
  124.          case W_CHAIN:
  125.              if (obj != uchain)
  126.                  what = "chain";
  127.              break;
  128.          default:
  129.              break;
  130.          }
  131.          if (what) {
  132.              Sprintf(maskbuf, "worn mask 0x%08lx != %s", obj->owornmask, what);
  133.              insane_object(obj, ofmt0, maskbuf, (struct monst *) 0);
  134.          }
  135.      }
  136.      if (n == 1 && (carried(obj) || (owornmask & (W_BALL | W_CHAIN)) != 0L
  137.                     || mcarried(obj))) {
  138.          /* check for items worn in invalid slots; practically anything can
  139.             be wielded/alt-wielded/quivered, so tests on those are limited */
  140.          what = 0;
  141.          if (owornmask & W_ARMOR) {
  142.              if (obj->oclass != ARMOR_CLASS)
  143.                  what = "armor";
  144.              /* 3.6: dragon scale mail reverts to dragon scales when
  145.                 becoming embedded in poly'd hero's skin */
  146.              if (embedded && !Is_dragon_scales(obj))
  147.                  what = "skin";
  148.          } else if (owornmask & W_WEAPON) {
  149.              /* monsters don't maintain alternate weapon or quiver */
  150.              if (mcarried(obj) && (owornmask & (W_SWAPWEP | W_QUIVER)) != 0L)
  151.                  what = (owornmask & W_SWAPWEP) != 0L ? "monst alt weapon?"
  152.                                                       : "monst quiver?";
  153.              /* hero can quiver gold but not wield it (hence not alt-wield
  154.                 it either); also catches monster wielding gold */
  155.              else if (obj->oclass == COIN_CLASS
  156.                       && (owornmask & (W_WEP | W_SWAPWEP)) != 0L)
  157.                  what = (owornmask & W_WEP) != 0L ? "weapon" : "alt weapon";
  158.          } else if (owornmask & W_AMUL) {
  159.              if (obj->oclass != AMULET_CLASS)
  160.                  what = "amulet";
  161.          } else if (owornmask & W_RING) {
  162.              if (obj->oclass != RING_CLASS && obj->otyp != MEAT_RING)
  163.                  what = "ring";
  164.          } else if (owornmask & W_TOOL) {
  165.              if (obj->otyp != BLINDFOLD && obj->otyp != TOWEL
  166.                  && obj->otyp != LENSES)
  167.                  what = "blindfold";
  168.          } else if (owornmask & W_BALL) {
  169.              if (obj->oclass != BALL_CLASS)
  170.                  what = "chained ball";
  171.          } else if (owornmask & W_CHAIN) {
  172.              if (obj->oclass != CHAIN_CLASS)
  173.                  what = "chain";
  174.          } else if (owornmask & W_SADDLE) {
  175.              if (obj->otyp != SADDLE)
  176.                  what = "saddle";
  177.          }
  178.          if (what) {
  179.              char oclassname[30];
  180.              struct monst *mon = mcarried(obj) ? obj->ocarry : 0;
  181.  
  182.              /* if we've found a potion worn in the amulet slot,
  183.                 this yields "worn (potion amulet)" */
  184.              Strcpy(oclassname, def_oc_syms[(uchar) obj->oclass].name);
  185.              Sprintf(maskbuf, "worn (%s %s)", makesingular(oclassname), what);
  186.              insane_object(obj, ofmt0, maskbuf, mon);
  187.          }
  188.      }
  189.  #else /* not (BETA || DEBUG) */
  190.      /* dummy use of obj to avoid "arg not used" complaint */
  191.      if (!obj)
  192.          insane_object(obj, ofmt0, "<null>", (struct monst *) 0);
  193.  #endif
  194.  }
  195.  

obj_nexto

  1.  /*
  2.   * wrapper to make "near this object" convenient
  3.   */
  4.  struct obj *
  5.  obj_nexto(otmp)
  6.  struct obj *otmp;
  7.  {
  8.      struct obj *otmp2 = (struct obj *) 0;
  9.  
  10.      if (otmp) {
  11.          otmp2 = obj_nexto_xy(otmp->otyp, otmp->ox, otmp->oy, otmp->o_id);
  12.      } else {
  13.          impossible("obj_nexto: wasn't given an object to check");
  14.      }
  15.  
  16.      return otmp2;
  17.  }
  18.  

obj_nexto_xy

  1.  /*
  2.   * looks for objects of a particular type next to x, y
  3.   * skips over oid if found (lets us avoid ourselves if
  4.   * we're looking for a second type of an existing object)
  5.   *
  6.   * TODO: return a list of all objects near us so we can more
  7.   * reliably predict which one we want to 'find' first
  8.   */
  9.  struct obj *
  10.  obj_nexto_xy(otyp, x, y, oid)
  11.  int otyp, x, y;
  12.  unsigned oid;
  13.  {
  14.      struct obj *otmp;
  15.      int fx, fy, ex, ey;
  16.      short dx, dy;
  17.  
  18.      /* check under our "feet" first */
  19.      otmp = sobj_at(otyp, x, y);
  20.      while (otmp) {
  21.          /* don't be clever and find ourselves */
  22.          if (otmp->o_id != oid) {
  23.              return otmp;
  24.          }
  25.          otmp = nxtobj(otmp, otyp, TRUE);
  26.      }
  27.  
  28.      /* search in a random order */
  29.      dx = (rn2(2) ? -1 : 1);
  30.      dy = (rn2(2) ? -1 : 1);
  31.      ex = x - dx;
  32.      ey = y - dy;
  33.  
  34.      for (fx = ex; abs(fx - ex) < 3; fx += dx) {
  35.          for (fy = ey; abs(fy - ey) < 3; fy += dy) {
  36.              /* 0, 0 was checked above */
  37.              if (isok(fx, fy) && (fx != x || fy != y)) {
  38.                  if ((otmp = sobj_at(otyp, fx, fy)) != 0) {
  39.                      return otmp;
  40.                  }
  41.              }
  42.          }
  43.      }
  44.      return (struct obj *) 0;
  45.  }
  46.  

obj_absorb

  1.  /*
  2.   * Causes one object to absorb another, increasing
  3.   * weight accordingly. Frees obj2; obj1 remains and
  4.   * is returned.
  5.   */
  6.  struct obj *
  7.  obj_absorb(obj1, obj2)
  8.  struct obj **obj1, **obj2;
  9.  {
  10.      struct obj *otmp1 = (struct obj *) 0, *otmp2 = (struct obj *) 0;
  11.      int extrawt = 0;
  12.  
  13.      /* don't let people dumb it up */
  14.      if (obj1 && obj2) {
  15.          otmp1 = *obj1;
  16.          otmp2 = *obj2;
  17.          if (otmp1 && otmp2) {
  18.              extrawt = otmp2->oeaten ? otmp2->oeaten : otmp2->owt;
  19.              otmp1->owt += extrawt;
  20.              otmp1->oeaten += otmp1->oeaten ? extrawt : 0;
  21.              otmp1->quan = 1;
  22.              obj_extract_self(otmp2);
  23.              newsym(otmp2->ox, otmp2->oy); /* in case of floor */
  24.              dealloc_obj(otmp2);
  25.              *obj2 = (struct obj *) 0;
  26.              return otmp1;
  27.          }
  28.      }
  29.  
  30.      impossible("obj_absorb: not called with two actual objects");
  31.      return (struct obj *) 0;
  32.  }
  33.  

obj_meld

  1.  /*
  2.   * Causes the heavier object to absorb the lighter object;
  3.   * wrapper for obj_absorb so that floor_effects works more
  4.   * cleanly (since we don't know which we want to stay around)
  5.   */
  6.  struct obj *
  7.  obj_meld(obj1, obj2)
  8.  struct obj **obj1, **obj2;
  9.  {
  10.      struct obj *otmp1 = (struct obj *) 0, *otmp2 = (struct obj *) 0;
  11.  
  12.      if (obj1 && obj2) {
  13.          otmp1 = *obj1;
  14.          otmp2 = *obj2;
  15.          if (otmp1 && otmp2) {
  16.              if (otmp1->owt > otmp2->owt || rn2(2)) {
  17.                  return obj_absorb(obj1, obj2);
  18.              }
  19.              return obj_absorb(obj2, obj1);
  20.          }
  21.      }
  22.  
  23.      impossible("obj_meld: not called with two actual objects");
  24.      return (struct obj *) 0;
  25.  }
  26.  
  27.  /*mkobj.c*/