Source:NetHack 3.6.0/src/detect.c

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

Below is the full text to detect.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/detect.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	detect.c	$NHDT-Date: 1446369464 2015/11/01 09:17:44 $  $NHDT-Branch: master $:$NHDT-Revision: 1.61 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  /*
  6.   * Detection routines, including crystal ball, magic mapping, and search
  7.   * command.
  8.   */
  9.  
  10.  #include "hack.h"
  11.  #include "artifact.h"
  12.  
  13.  extern boolean known; /* from read.c */
  14.  
  15.  STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
  16.  STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned));
  17.  STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned));
  18.  STATIC_DCL void FDECL(sense_trap, (struct trap *, XCHAR_P, XCHAR_P, int));
  19.  STATIC_DCL int FDECL(detect_obj_traps, (struct obj *, BOOLEAN_P, int));
  20.  STATIC_DCL void FDECL(show_map_spot, (int, int));
  21.  STATIC_PTR void FDECL(findone, (int, int, genericptr_t));
  22.  STATIC_PTR void FDECL(openone, (int, int, genericptr_t));
  23.  

o_in

  1.  /* Recursively search obj for an object in class oclass and return 1st found
  2.   */
  3.  struct obj *
  4.  o_in(obj, oclass)
  5.  struct obj *obj;
  6.  char oclass;
  7.  {
  8.      register struct obj *otmp;
  9.      struct obj *temp;
  10.  
  11.      if (obj->oclass == oclass)
  12.          return obj;
  13.  
  14.      if (Has_contents(obj)) {
  15.          for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  16.              if (otmp->oclass == oclass)
  17.                  return otmp;
  18.              else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
  19.                  return temp;
  20.      }
  21.      return (struct obj *) 0;
  22.  }
  23.  

o_material

  1.  /* Recursively search obj for an object made of specified material.
  2.   * Return first found.
  3.   */
  4.  struct obj *
  5.  o_material(obj, material)
  6.  struct obj *obj;
  7.  unsigned material;
  8.  {
  9.      register struct obj *otmp;
  10.      struct obj *temp;
  11.  
  12.      if (objects[obj->otyp].oc_material == material)
  13.          return obj;
  14.  
  15.      if (Has_contents(obj)) {
  16.          for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  17.              if (objects[otmp->otyp].oc_material == material)
  18.                  return otmp;
  19.              else if (Has_contents(otmp)
  20.                       && (temp = o_material(otmp, material)))
  21.                  return temp;
  22.      }
  23.      return (struct obj *) 0;
  24.  }
  25.  

do_dknown_of

  1.  STATIC_OVL void
  2.  do_dknown_of(obj)
  3.  struct obj *obj;
  4.  {
  5.      struct obj *otmp;
  6.  
  7.      obj->dknown = 1;
  8.      if (Has_contents(obj)) {
  9.          for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  10.              do_dknown_of(otmp);
  11.      }
  12.  }
  13.  

check_map_spot

  1.  /* Check whether the location has an outdated object displayed on it. */
  2.  STATIC_OVL boolean
  3.  check_map_spot(x, y, oclass, material)
  4.  int x, y;
  5.  char oclass;
  6.  unsigned material;
  7.  {
  8.      int glyph;
  9.      register struct obj *otmp;
  10.      register struct monst *mtmp;
  11.  
  12.      glyph = glyph_at(x, y);
  13.      if (glyph_is_object(glyph)) {
  14.          /* there's some object shown here */
  15.          if (oclass == ALL_CLASSES) {
  16.              return (boolean) !(level.objects[x][y] /* stale if nothing here */
  17.                                 || ((mtmp = m_at(x, y)) != 0 && mtmp->minvent));
  18.          } else {
  19.              if (material
  20.                  && objects[glyph_to_obj(glyph)].oc_material == material) {
  21.                  /* object shown here is of interest because material matches */
  22.                  for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  23.                      if (o_material(otmp, GOLD))
  24.                          return FALSE;
  25.                  /* didn't find it; perhaps a monster is carrying it */
  26.                  if ((mtmp = m_at(x, y)) != 0) {
  27.                      for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
  28.                          if (o_material(otmp, GOLD))
  29.                              return FALSE;
  30.                  }
  31.                  /* detection indicates removal of this object from the map */
  32.                  return TRUE;
  33.              }
  34.              if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) {
  35.                  /* obj shown here is of interest because its class matches */
  36.                  for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  37.                      if (o_in(otmp, oclass))
  38.                          return FALSE;
  39.                  /* didn't find it; perhaps a monster is carrying it */
  40.                  if ((mtmp = m_at(x, y)) != 0) {
  41.                      for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
  42.                          if (o_in(otmp, oclass))
  43.                              return FALSE;
  44.                  }
  45.                  /* detection indicates removal of this object from the map */
  46.                  return TRUE;
  47.              }
  48.          }
  49.      }
  50.      return FALSE;
  51.  }
  52.  

clear_stale_map

  1.  /*
  2.   * When doing detection, remove stale data from the map display (corpses
  3.   * rotted away, objects carried away by monsters, etc) so that it won't
  4.   * reappear after the detection has completed.  Return true if noticeable
  5.   * change occurs.
  6.   */
  7.  STATIC_OVL boolean
  8.  clear_stale_map(oclass, material)
  9.  char oclass;
  10.  unsigned material;
  11.  {
  12.      register int zx, zy;
  13.      boolean change_made = FALSE;
  14.  
  15.      for (zx = 1; zx < COLNO; zx++)
  16.          for (zy = 0; zy < ROWNO; zy++)
  17.              if (check_map_spot(zx, zy, oclass, material)) {
  18.                  unmap_object(zx, zy);
  19.                  change_made = TRUE;
  20.              }
  21.  
  22.      return change_made;
  23.  }
  24.  

gold_detect

  1.  /* look for gold, on the floor or in monsters' possession */
  2.  int
  3.  gold_detect(sobj)
  4.  register struct obj *sobj;
  5.  {
  6.      register struct obj *obj;
  7.      register struct monst *mtmp;
  8.      struct obj *temp;
  9.      boolean stale;
  10.  
  11.      known = stale =
  12.          clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0));
  13.  
  14.      /* look for gold carried by monsters (might be in a container) */
  15.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  16.          if (DEADMONSTER(mtmp))
  17.              continue; /* probably not needed in this case but... */
  18.          if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
  19.              known = TRUE;
  20.              goto outgoldmap; /* skip further searching */
  21.          } else
  22.              for (obj = mtmp->minvent; obj; obj = obj->nobj)
  23.                  if (sobj->blessed && o_material(obj, GOLD)) {
  24.                      known = TRUE;
  25.                      goto outgoldmap;
  26.                  } else if (o_in(obj, COIN_CLASS)) {
  27.                      known = TRUE;
  28.                      goto outgoldmap; /* skip further searching */
  29.                  }
  30.      }
  31.  
  32.      /* look for gold objects */
  33.      for (obj = fobj; obj; obj = obj->nobj) {
  34.          if (sobj->blessed && o_material(obj, GOLD)) {
  35.              known = TRUE;
  36.              if (obj->ox != u.ux || obj->oy != u.uy)
  37.                  goto outgoldmap;
  38.          } else if (o_in(obj, COIN_CLASS)) {
  39.              known = TRUE;
  40.              if (obj->ox != u.ux || obj->oy != u.uy)
  41.                  goto outgoldmap;
  42.          }
  43.      }
  44.  
  45.      if (!known) {
  46.          /* no gold found on floor or monster's inventory.
  47.             adjust message if you have gold in your inventory */
  48.          if (sobj) {
  49.              char buf[BUFSZ];
  50.              if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
  51.                  Sprintf(buf, "You feel like a million %s!", currency(2L));
  52.              } else if (hidden_gold() || money_cnt(invent))
  53.                  Strcpy(buf,
  54.                     "You feel worried about your future financial situation.");
  55.              else
  56.                  Strcpy(buf, "You feel materially poor.");
  57.              strange_feeling(sobj, buf);
  58.          }
  59.          return 1;
  60.      }
  61.      /* only under me - no separate display required */
  62.      if (stale)
  63.          docrt();
  64.      You("notice some gold between your %s.", makeplural(body_part(FOOT)));
  65.      return 0;
  66.  
  67.  outgoldmap:
  68.      cls();
  69.  
  70.      iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  71.      u.uinwater = u.uburied = 0;
  72.      /* Discover gold locations. */
  73.      for (obj = fobj; obj; obj = obj->nobj) {
  74.          if (sobj->blessed && (temp = o_material(obj, GOLD))) {
  75.              if (temp != obj) {
  76.                  temp->ox = obj->ox;
  77.                  temp->oy = obj->oy;
  78.              }
  79.              map_object(temp, 1);
  80.          } else if ((temp = o_in(obj, COIN_CLASS))) {
  81.              if (temp != obj) {
  82.                  temp->ox = obj->ox;
  83.                  temp->oy = obj->oy;
  84.              }
  85.              map_object(temp, 1);
  86.          }
  87.      }
  88.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  89.          if (DEADMONSTER(mtmp))
  90.              continue; /* probably overkill here */
  91.          if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
  92.              struct obj gold;
  93.              gold = zeroobj; /* ensure oextra is cleared too */
  94.              gold.otyp = GOLD_PIECE;
  95.              gold.ox = mtmp->mx;
  96.              gold.oy = mtmp->my;
  97.              map_object(&gold, 1);
  98.          } else
  99.              for (obj = mtmp->minvent; obj; obj = obj->nobj)
  100.                  if (sobj->blessed && (temp = o_material(obj, GOLD))) {
  101.                      temp->ox = mtmp->mx;
  102.                      temp->oy = mtmp->my;
  103.                      map_object(temp, 1);
  104.                      break;
  105.                  } else if ((temp = o_in(obj, COIN_CLASS))) {
  106.                      temp->ox = mtmp->mx;
  107.                      temp->oy = mtmp->my;
  108.                      map_object(temp, 1);
  109.                      break;
  110.                  }
  111.      }
  112.      newsym(u.ux, u.uy);
  113.      u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  114.      You_feel("very greedy, and sense gold!");
  115.      exercise(A_WIS, TRUE);
  116.      display_nhwindow(WIN_MAP, TRUE);
  117.      docrt();
  118.      if (Underwater)
  119.          under_water(2);
  120.      if (u.uburied)
  121.          under_ground(2);
  122.      return 0;
  123.  }
  124.  

food_detect

  1.  /* returns 1 if nothing was detected   */
  2.  /* returns 0 if something was detected */
  3.  int
  4.  food_detect(sobj)
  5.  register struct obj *sobj;
  6.  {
  7.      register struct obj *obj;
  8.      register struct monst *mtmp;
  9.      register int ct = 0, ctu = 0;
  10.      boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
  11.      char oclass = confused ? POTION_CLASS : FOOD_CLASS;
  12.      const char *what = confused ? something : "food";
  13.  
  14.      stale = clear_stale_map(oclass, 0);
  15.  
  16.      for (obj = fobj; obj; obj = obj->nobj)
  17.          if (o_in(obj, oclass)) {
  18.              if (obj->ox == u.ux && obj->oy == u.uy)
  19.                  ctu++;
  20.              else
  21.                  ct++;
  22.          }
  23.      for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
  24.          /* no DEADMONSTER(mtmp) check needed since dmons never have inventory
  25.           */
  26.          for (obj = mtmp->minvent; obj; obj = obj->nobj)
  27.              if (o_in(obj, oclass)) {
  28.                  ct++;
  29.                  break;
  30.              }
  31.      }
  32.  
  33.      if (!ct && !ctu) {
  34.          known = stale && !confused;
  35.          if (stale) {
  36.              docrt();
  37.              You("sense a lack of %s nearby.", what);
  38.              if (sobj && sobj->blessed) {
  39.                  if (!u.uedibility)
  40.                      Your("%s starts to tingle.", body_part(NOSE));
  41.                  u.uedibility = 1;
  42.              }
  43.          } else if (sobj) {
  44.              char buf[BUFSZ];
  45.              Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
  46.                      (sobj->blessed && !u.uedibility)
  47.                          ? " then starts to tingle"
  48.                          : "");
  49.              if (sobj->blessed && !u.uedibility) {
  50.                  boolean savebeginner = flags.beginner;
  51.  
  52.                  flags.beginner = FALSE; /* prevent non-delivery of message */
  53.                  strange_feeling(sobj, buf);
  54.                  flags.beginner = savebeginner;
  55.                  u.uedibility = 1;
  56.              } else
  57.                  strange_feeling(sobj, buf);
  58.          }
  59.          return !stale;
  60.      } else if (!ct) {
  61.          known = TRUE;
  62.          You("%s %s nearby.", sobj ? "smell" : "sense", what);
  63.          if (sobj && sobj->blessed) {
  64.              if (!u.uedibility)
  65.                  pline("Your %s starts to tingle.", body_part(NOSE));
  66.              u.uedibility = 1;
  67.          }
  68.      } else {
  69.          struct obj *temp;
  70.          known = TRUE;
  71.          cls();
  72.          iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  73.          u.uinwater = u.uburied = 0;
  74.          for (obj = fobj; obj; obj = obj->nobj)
  75.              if ((temp = o_in(obj, oclass)) != 0) {
  76.                  if (temp != obj) {
  77.                      temp->ox = obj->ox;
  78.                      temp->oy = obj->oy;
  79.                  }
  80.                  map_object(temp, 1);
  81.              }
  82.          for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  83.              /* no DEADMONSTER(mtmp) check needed since dmons never have
  84.               * inventory */
  85.              for (obj = mtmp->minvent; obj; obj = obj->nobj)
  86.                  if ((temp = o_in(obj, oclass)) != 0) {
  87.                      temp->ox = mtmp->mx;
  88.                      temp->oy = mtmp->my;
  89.                      map_object(temp, 1);
  90.                      break; /* skip rest of this monster's inventory */
  91.                  }
  92.          newsym(u.ux, u.uy);
  93.          u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  94.          if (sobj) {
  95.              if (sobj->blessed) {
  96.                  Your("%s %s to tingle and you smell %s.", body_part(NOSE),
  97.                       u.uedibility ? "continues" : "starts", what);
  98.                  u.uedibility = 1;
  99.              } else
  100.                  Your("%s tingles and you smell %s.", body_part(NOSE), what);
  101.          } else
  102.              You("sense %s.", what);
  103.          display_nhwindow(WIN_MAP, TRUE);
  104.          exercise(A_WIS, TRUE);
  105.          docrt();
  106.          if (Underwater)
  107.              under_water(2);
  108.          if (u.uburied)
  109.              under_ground(2);
  110.      }
  111.      return 0;
  112.  }
  113.  

object_detect

  1.  /*
  2.   * Used for scrolls, potions, spells, and crystal balls.  Returns:
  3.   *
  4.   *      1 - nothing was detected
  5.   *      0 - something was detected
  6.   */
  7.  int
  8.  object_detect(detector, class)
  9.  struct obj *detector; /* object doing the detecting */
  10.  int class;            /* an object class, 0 for all */
  11.  {
  12.      register int x, y;
  13.      char stuff[BUFSZ];
  14.      int is_cursed = (detector && detector->cursed);
  15.      int do_dknown = (detector && (detector->oclass == POTION_CLASS
  16.                                    || detector->oclass == SPBOOK_CLASS)
  17.                       && detector->blessed);
  18.      int ct = 0, ctu = 0;
  19.      register struct obj *obj, *otmp = (struct obj *) 0;
  20.      register struct monst *mtmp;
  21.      int sym, boulder = 0;
  22.  
  23.      if (class < 0 || class >= MAXOCLASSES) {
  24.          impossible("object_detect:  illegal class %d", class);
  25.          class = 0;
  26.      }
  27.  
  28.      /* Special boulder symbol check - does the class symbol happen
  29.       * to match iflags.bouldersym which is a user-defined?
  30.       * If so, that means we aren't sure what they really wanted to
  31.       * detect. Rather than trump anything, show both possibilities.
  32.       * We can exclude checking the buried obj chain for boulders below.
  33.       */
  34.      sym = class ? def_oc_syms[class].sym : 0;
  35.      if (sym && iflags.bouldersym && sym == iflags.bouldersym)
  36.          boulder = ROCK_CLASS;
  37.  
  38.      if (Hallucination || (Confusion && class == SCROLL_CLASS))
  39.          Strcpy(stuff, something);
  40.      else
  41.          Strcpy(stuff, class ? def_oc_syms[class].name : "objects");
  42.      if (boulder && class != ROCK_CLASS)
  43.          Strcat(stuff, " and/or large stones");
  44.  
  45.      if (do_dknown)
  46.          for (obj = invent; obj; obj = obj->nobj)
  47.              do_dknown_of(obj);
  48.  
  49.      for (obj = fobj; obj; obj = obj->nobj) {
  50.          if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
  51.              if (obj->ox == u.ux && obj->oy == u.uy)
  52.                  ctu++;
  53.              else
  54.                  ct++;
  55.          }
  56.          if (do_dknown)
  57.              do_dknown_of(obj);
  58.      }
  59.  
  60.      for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
  61.          if (!class || o_in(obj, class)) {
  62.              if (obj->ox == u.ux && obj->oy == u.uy)
  63.                  ctu++;
  64.              else
  65.                  ct++;
  66.          }
  67.          if (do_dknown)
  68.              do_dknown_of(obj);
  69.      }
  70.  
  71.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  72.          if (DEADMONSTER(mtmp))
  73.              continue;
  74.          for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  75.              if ((!class && !boulder) || o_in(obj, class)
  76.                  || o_in(obj, boulder))
  77.                  ct++;
  78.              if (do_dknown)
  79.                  do_dknown_of(obj);
  80.          }
  81.          if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT
  82.               && (!class || class == objects[mtmp->mappearance].oc_class))
  83.              || (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
  84.              ct++;
  85.              break;
  86.          }
  87.      }
  88.  
  89.      if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
  90.          if (!ctu) {
  91.              if (detector)
  92.                  strange_feeling(detector, "You feel a lack of something.");
  93.              return 1;
  94.          }
  95.  
  96.          You("sense %s nearby.", stuff);
  97.          return 0;
  98.      }
  99.  
  100.      cls();
  101.  
  102.      iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  103.      u.uinwater = u.uburied = 0;
  104.      /*
  105.       *  Map all buried objects first.
  106.       */
  107.      for (obj = level.buriedobjlist; obj; obj = obj->nobj)
  108.          if (!class || (otmp = o_in(obj, class))) {
  109.              if (class) {
  110.                  if (otmp != obj) {
  111.                      otmp->ox = obj->ox;
  112.                      otmp->oy = obj->oy;
  113.                  }
  114.                  map_object(otmp, 1);
  115.              } else
  116.                  map_object(obj, 1);
  117.          }
  118.      /*
  119.       * If we are mapping all objects, map only the top object of a pile or
  120.       * the first object in a monster's inventory.  Otherwise, go looking
  121.       * for a matching object class and display the first one encountered
  122.       * at each location.
  123.       *
  124.       * Objects on the floor override buried objects.
  125.       */
  126.      for (x = 1; x < COLNO; x++)
  127.          for (y = 0; y < ROWNO; y++)
  128.              for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
  129.                  if ((!class && !boulder) || (otmp = o_in(obj, class))
  130.                      || (otmp = o_in(obj, boulder))) {
  131.                      if (class || boulder) {
  132.                          if (otmp != obj) {
  133.                              otmp->ox = obj->ox;
  134.                              otmp->oy = obj->oy;
  135.                          }
  136.                          map_object(otmp, 1);
  137.                      } else
  138.                          map_object(obj, 1);
  139.                      break;
  140.                  }
  141.  
  142.      /* Objects in the monster's inventory override floor objects. */
  143.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  144.          if (DEADMONSTER(mtmp))
  145.              continue;
  146.          for (obj = mtmp->minvent; obj; obj = obj->nobj)
  147.              if ((!class && !boulder) || (otmp = o_in(obj, class))
  148.                  || (otmp = o_in(obj, boulder))) {
  149.                  if (!class && !boulder)
  150.                      otmp = obj;
  151.                  otmp->ox = mtmp->mx; /* at monster location */
  152.                  otmp->oy = mtmp->my;
  153.                  map_object(otmp, 1);
  154.                  break;
  155.              }
  156.          /* Allow a mimic to override the detected objects it is carrying. */
  157.          if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT
  158.              && (!class || class == objects[mtmp->mappearance].oc_class)) {
  159.              struct obj temp;
  160.  
  161.              temp.oextra = (struct oextra *) 0;
  162.              temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
  163.              temp.ox = mtmp->mx;
  164.              temp.oy = mtmp->my;
  165.              temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
  166.              map_object(&temp, 1);
  167.          } else if (findgold(mtmp->minvent)
  168.                     && (!class || class == COIN_CLASS)) {
  169.              struct obj gold;
  170.              gold = zeroobj; /* ensure oextra is cleared too */
  171.              gold.otyp = GOLD_PIECE;
  172.              gold.ox = mtmp->mx;
  173.              gold.oy = mtmp->my;
  174.              map_object(&gold, 1);
  175.          }
  176.      }
  177.  
  178.      newsym(u.ux, u.uy);
  179.      u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  180.      You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
  181.      display_nhwindow(WIN_MAP, TRUE);
  182.      /*
  183.       * What are we going to do when the hero does an object detect while blind
  184.       * and the detected object covers a known pool?
  185.       */
  186.      docrt(); /* this will correctly reset vision */
  187.  
  188.      if (Underwater)
  189.          under_water(2);
  190.      if (u.uburied)
  191.          under_ground(2);
  192.      return 0;
  193.  }
  194.  

monster_detect

  1.  /*
  2.   * Used by: crystal balls, potions, fountains
  3.   *
  4.   * Returns 1 if nothing was detected.
  5.   * Returns 0 if something was detected.
  6.   */
  7.  int
  8.  monster_detect(otmp, mclass)
  9.  register struct obj *otmp; /* detecting object (if any) */
  10.  int mclass;                /* monster class, 0 for all */
  11.  {
  12.      register struct monst *mtmp;
  13.      int mcnt = 0;
  14.  
  15.      /* Note: This used to just check fmon for a non-zero value
  16.       * but in versions since 3.3.0 fmon can test TRUE due to the
  17.       * presence of dmons, so we have to find at least one
  18.       * with positive hit-points to know for sure.
  19.       */
  20.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  21.          if (!DEADMONSTER(mtmp)) {
  22.              mcnt++;
  23.              break;
  24.          }
  25.  
  26.      if (!mcnt) {
  27.          if (otmp)
  28.              strange_feeling(otmp, Hallucination
  29.                                        ? "You get the heebie jeebies."
  30.                                        : "You feel threatened.");
  31.          return 1;
  32.      } else {
  33.          boolean woken = FALSE;
  34.  
  35.          cls();
  36.          for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  37.              if (DEADMONSTER(mtmp))
  38.                  continue;
  39.              if (!mclass || mtmp->data->mlet == mclass
  40.                  || (mtmp->data == &mons[PM_LONG_WORM]
  41.                      && mclass == S_WORM_TAIL))
  42.                  if (mtmp->mx > 0) {
  43.                      if (mclass && def_monsyms[mclass].sym == ' ')
  44.                          show_glyph(mtmp->mx, mtmp->my,
  45.                                     detected_mon_to_glyph(mtmp));
  46.                      else
  47.                          show_glyph(mtmp->mx, mtmp->my,
  48.                                     mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
  49.                      /* don't be stingy - display entire worm */
  50.                      if (mtmp->data == &mons[PM_LONG_WORM])
  51.                          detect_wsegs(mtmp, 0);
  52.                  }
  53.              if (otmp && otmp->cursed
  54.                  && (mtmp->msleeping || !mtmp->mcanmove)) {
  55.                  mtmp->msleeping = mtmp->mfrozen = 0;
  56.                  mtmp->mcanmove = 1;
  57.                  woken = TRUE;
  58.              }
  59.          }
  60.          display_self();
  61.          You("sense the presence of monsters.");
  62.          if (woken)
  63.              pline("Monsters sense the presence of you.");
  64.          display_nhwindow(WIN_MAP, TRUE);
  65.          docrt();
  66.          if (Underwater)
  67.              under_water(2);
  68.          if (u.uburied)
  69.              under_ground(2);
  70.      }
  71.      return 0;
  72.  }
  73.  

sense_trap

  1.  STATIC_OVL void
  2.  sense_trap(trap, x, y, src_cursed)
  3.  struct trap *trap;
  4.  xchar x, y;
  5.  int src_cursed;
  6.  {
  7.      if (Hallucination || src_cursed) {
  8.          struct obj obj; /* fake object */
  9.  
  10.          obj.oextra = (struct oextra *) 0;
  11.          if (trap) {
  12.              obj.ox = trap->tx;
  13.              obj.oy = trap->ty;
  14.          } else {
  15.              obj.ox = x;
  16.              obj.oy = y;
  17.          }
  18.          obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
  19.          obj.corpsenm = random_monster(); /* if otyp == CORPSE */
  20.          map_object(&obj, 1);
  21.      } else if (trap) {
  22.          map_trap(trap, 1);
  23.          trap->tseen = 1;
  24.      } else {
  25.          struct trap temp_trap; /* fake trap */
  26.          temp_trap.tx = x;
  27.          temp_trap.ty = y;
  28.          temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
  29.          map_trap(&temp_trap, 1);
  30.      }
  31.  }
  32.  

detect_obj_traps

  1.  #define OTRAP_NONE 0  /* nothing found */
  2.  #define OTRAP_HERE 1  /* found at hero's location */
  3.  #define OTRAP_THERE 2 /* found at any other location */
  4.  
  5.  /* check a list of objects for chest traps; return 1 if found at <ux,uy>,
  6.     2 if found at some other spot, 3 if both, 0 otherwise; optionally
  7.     update the map to show where such traps were found */
  8.  STATIC_OVL int
  9.  detect_obj_traps(objlist, show_them, how)
  10.  struct obj *objlist;
  11.  boolean show_them;
  12.  int how; /* 1 for misleading map feedback */
  13.  {
  14.      struct obj *otmp;
  15.      xchar x, y;
  16.      int result = OTRAP_NONE;
  17.  
  18.      for (otmp = objlist; otmp; otmp = otmp->nobj) {
  19.          if (Is_box(otmp) && otmp->otrapped
  20.              && get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
  21.              result |= (x == u.ux && y == u.uy) ? OTRAP_HERE : OTRAP_THERE;
  22.              if (show_them)
  23.                  sense_trap((struct trap *) 0, x, y, how);
  24.          }
  25.          if (Has_contents(otmp))
  26.              result |= detect_obj_traps(otmp->cobj, show_them, how);
  27.      }
  28.      return result;
  29.  }
  30.  

trap_detect

  1.  /* the detections are pulled out so they can
  2.   * also be used in the crystal ball routine
  3.   * returns 1 if nothing was detected
  4.   * returns 0 if something was detected
  5.   */
  6.  int
  7.  trap_detect(sobj)
  8.  register struct obj *sobj;
  9.  /* sobj is null if crystal ball, *scroll if gold detection scroll */
  10.  {
  11.      register struct trap *ttmp;
  12.      struct monst *mon;
  13.      int door, glyph, tr;
  14.      int cursed_src = sobj && sobj->cursed;
  15.      boolean found = FALSE;
  16.      coord cc;
  17.  
  18.      /* floor/ceiling traps */
  19.      for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
  20.          if (ttmp->tx != u.ux || ttmp->ty != u.uy)
  21.              goto outtrapmap;
  22.          else
  23.              found = TRUE;
  24.      }
  25.      /* chest traps (might be buried or carried) */
  26.      if ((tr = detect_obj_traps(fobj, FALSE, 0)) != OTRAP_NONE) {
  27.          if (tr & OTRAP_THERE)
  28.              goto outtrapmap;
  29.          else
  30.              found = TRUE;
  31.      }
  32.      if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0))
  33.          != OTRAP_NONE) {
  34.          if (tr & OTRAP_THERE)
  35.              goto outtrapmap;
  36.          else
  37.              found = TRUE;
  38.      }
  39.      for (mon = fmon; mon; mon = mon->nmon) {
  40.          if (DEADMONSTER(mon))
  41.              continue;
  42.          if ((tr = detect_obj_traps(mon->minvent, FALSE, 0)) != OTRAP_NONE) {
  43.              if (tr & OTRAP_THERE)
  44.                  goto outtrapmap;
  45.              else
  46.                  found = TRUE;
  47.          }
  48.      }
  49.      if (detect_obj_traps(invent, FALSE, 0) != OTRAP_NONE)
  50.          found = TRUE;
  51.      /* door traps */
  52.      for (door = 0; door < doorindex; door++) {
  53.          cc = doors[door];
  54.          if (levl[cc.x][cc.y].doormask & D_TRAPPED) {
  55.              if (cc.x != u.ux || cc.y != u.uy)
  56.                  goto outtrapmap;
  57.              else
  58.                  found = TRUE;
  59.          }
  60.      }
  61.      if (!found) {
  62.          char buf[BUFSZ];
  63.  
  64.          Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
  65.          strange_feeling(sobj, buf);
  66.          return 1;
  67.      }
  68.      /* traps exist, but only under me - no separate display required */
  69.      Your("%s itch.", makeplural(body_part(TOE)));
  70.      return 0;
  71.  outtrapmap:
  72.      cls();
  73.  
  74.      iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  75.      u.uinwater = u.uburied = 0;
  76.  
  77.      /* show chest traps first, so that subsequent floor trap display
  78.         will override if both types are present at the same location */
  79.      (void) detect_obj_traps(fobj, TRUE, cursed_src);
  80.      (void) detect_obj_traps(level.buriedobjlist, TRUE, cursed_src);
  81.      for (mon = fmon; mon; mon = mon->nmon) {
  82.          if (DEADMONSTER(mon))
  83.              continue;
  84.          (void) detect_obj_traps(mon->minvent, TRUE, cursed_src);
  85.      }
  86.      (void) detect_obj_traps(invent, TRUE, cursed_src);
  87.  
  88.      for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
  89.          sense_trap(ttmp, 0, 0, cursed_src);
  90.  
  91.      for (door = 0; door < doorindex; door++) {
  92.          cc = doors[door];
  93.          if (levl[cc.x][cc.y].doormask & D_TRAPPED)
  94.              sense_trap((struct trap *) 0, cc.x, cc.y, cursed_src);
  95.      }
  96.  
  97.      /* redisplay hero unless sense_trap() revealed something at <ux,uy> */
  98.      glyph = glyph_at(u.ux, u.uy);
  99.      if (!(glyph_is_trap(glyph) || glyph_is_object(glyph)))
  100.          newsym(u.ux, u.uy);
  101.      u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  102.  
  103.      You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
  104.      /* wait for user to respond, then reset map display to normal */
  105.      display_nhwindow(WIN_MAP, TRUE);
  106.      docrt();
  107.      if (Underwater)
  108.          under_water(2);
  109.      if (u.uburied)
  110.          under_ground(2);
  111.      return 0;
  112.  }
  113.  

level_distance

  1.  const char *
  2.  level_distance(where)
  3.  d_level *where;
  4.  {
  5.      register schar ll = depth(&u.uz) - depth(where);
  6.      register boolean indun = (u.uz.dnum == where->dnum);
  7.  
  8.      if (ll < 0) {
  9.          if (ll < (-8 - rn2(3)))
  10.              if (!indun)
  11.                  return "far away";
  12.              else
  13.                  return "far below";
  14.          else if (ll < -1)
  15.              if (!indun)
  16.                  return "away below you";
  17.              else
  18.                  return "below you";
  19.          else if (!indun)
  20.              return "in the distance";
  21.          else
  22.              return "just below";
  23.      } else if (ll > 0) {
  24.          if (ll > (8 + rn2(3)))
  25.              if (!indun)
  26.                  return "far away";
  27.              else
  28.                  return "far above";
  29.          else if (ll > 1)
  30.              if (!indun)
  31.                  return "away above you";
  32.              else
  33.                  return "above you";
  34.          else if (!indun)
  35.              return "in the distance";
  36.          else
  37.              return "just above";
  38.      } else if (!indun)
  39.          return "in the distance";
  40.      else
  41.          return "near you";
  42.  }
  43.  

use_crystal_ball

  1.  static const struct {
  2.      const char *what;
  3.      d_level *where;
  4.  } level_detects[] = {
  5.      { "Delphi", &oracle_level },
  6.      { "Medusa's lair", &medusa_level },
  7.      { "a castle", &stronghold_level },
  8.      { "the Wizard of Yendor's tower", &wiz1_level },
  9.  };
  10.  
  11.  void
  12.  use_crystal_ball(optr)
  13.  struct obj **optr;
  14.  {
  15.      char ch;
  16.      int oops;
  17.      struct obj *obj = *optr;
  18.  
  19.      if (Blind) {
  20.          pline("Too bad you can't see %s.", the(xname(obj)));
  21.          return;
  22.      }
  23.      oops = (rnd(20) > ACURR(A_INT) || obj->cursed);
  24.      if (oops && (obj->spe > 0)) {
  25.          switch (rnd(obj->oartifact ? 4 : 5)) {
  26.          case 1:
  27.              pline("%s too much to comprehend!", Tobjnam(obj, "are"));
  28.              break;
  29.          case 2:
  30.              pline("%s you!", Tobjnam(obj, "confuse"));
  31.              make_confused((HConfusion & TIMEOUT) + (long) rnd(100), FALSE);
  32.              break;
  33.          case 3:
  34.              if (!resists_blnd(&youmonst)) {
  35.                  pline("%s your vision!", Tobjnam(obj, "damage"));
  36.                  make_blinded((Blinded & TIMEOUT) + (long) rnd(100), FALSE);
  37.                  if (!Blind)
  38.                      Your1(vision_clears);
  39.              } else {
  40.                  pline("%s your vision.", Tobjnam(obj, "assault"));
  41.                  You("are unaffected!");
  42.              }
  43.              break;
  44.          case 4:
  45.              pline("%s your mind!", Tobjnam(obj, "zap"));
  46.              (void) make_hallucinated(
  47.                  (HHallucination & TIMEOUT) + (long) rnd(100), FALSE, 0L);
  48.              break;
  49.          case 5:
  50.              pline("%s!", Tobjnam(obj, "explode"));
  51.              useup(obj);
  52.              *optr = obj = 0; /* it's gone */
  53.              /* physical damage cause by the shards and force */
  54.              losehp(Maybe_Half_Phys(rnd(30)), "exploding crystal ball",
  55.                     KILLED_BY_AN);
  56.              break;
  57.          }
  58.          if (obj)
  59.              consume_obj_charge(obj, TRUE);
  60.          return;
  61.      }
  62.  
  63.      if (Hallucination) {
  64.          if (!obj->spe) {
  65.              pline("All you see is funky %s haze.", hcolor((char *) 0));
  66.          } else {
  67.              switch (rnd(6)) {
  68.              case 1:
  69.                  You("grok some groovy globs of incandescent lava.");
  70.                  break;
  71.              case 2:
  72.                  pline("Whoa!  Psychedelic colors, %s!",
  73.                        poly_gender() == 1 ? "babe" : "dude");
  74.                  break;
  75.              case 3:
  76.                  pline_The("crystal pulses with sinister %s light!",
  77.                            hcolor((char *) 0));
  78.                  break;
  79.              case 4:
  80.                  You_see("goldfish swimming above fluorescent rocks.");
  81.                  break;
  82.              case 5:
  83.                  You_see(
  84.                      "tiny snowflakes spinning around a miniature farmhouse.");
  85.                  break;
  86.              default:
  87.                  pline("Oh wow... like a kaleidoscope!");
  88.                  break;
  89.              }
  90.              consume_obj_charge(obj, TRUE);
  91.          }
  92.          return;
  93.      }
  94.  
  95.      /* read a single character */
  96.      if (flags.verbose)
  97.          You("may look for an object or monster symbol.");
  98.      ch = yn_function("What do you look for?", (char *) 0, '\0');
  99.      /* Don't filter out ' ' here; it has a use */
  100.      if ((ch != def_monsyms[S_GHOST].sym) && index(quitchars, ch)) {
  101.          if (flags.verbose)
  102.              pline1(Never_mind);
  103.          return;
  104.      }
  105.      You("peer into %s...", the(xname(obj)));
  106.      nomul(-rnd(10));
  107.      multi_reason = "gazing into a crystal ball";
  108.      nomovemsg = "";
  109.      if (obj->spe <= 0)
  110.          pline_The("vision is unclear.");
  111.      else {
  112.          int class;
  113.          int ret = 0;
  114.  
  115.          makeknown(CRYSTAL_BALL);
  116.          consume_obj_charge(obj, TRUE);
  117.  
  118.          /* special case: accept ']' as synonym for mimic
  119.           * we have to do this before the def_char_to_objclass check
  120.           */
  121.          if (ch == DEF_MIMIC_DEF)
  122.              ch = DEF_MIMIC;
  123.  
  124.          if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
  125.              ret = object_detect((struct obj *) 0, class);
  126.          else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
  127.              ret = monster_detect((struct obj *) 0, class);
  128.          else if (iflags.bouldersym && (ch == iflags.bouldersym))
  129.              ret = object_detect((struct obj *) 0, ROCK_CLASS);
  130.          else
  131.              switch (ch) {
  132.              case '^':
  133.                  ret = trap_detect((struct obj *) 0);
  134.                  break;
  135.              default: {
  136.                  int i = rn2(SIZE(level_detects));
  137.                  You_see("%s, %s.", level_detects[i].what,
  138.                          level_distance(level_detects[i].where));
  139.              }
  140.                  ret = 0;
  141.                  break;
  142.              }
  143.  
  144.          if (ret) {
  145.              if (!rn2(100)) /* make them nervous */
  146.                  You_see("the Wizard of Yendor gazing out at you.");
  147.              else
  148.                  pline_The("vision is unclear.");
  149.          }
  150.      }
  151.      return;
  152.  }
  153.  

show_map_spot

  1.  STATIC_OVL void
  2.  show_map_spot(x, y)
  3.  register int x, y;
  4.  {
  5.      struct rm *lev;
  6.      struct trap *t;
  7.      int oldglyph;
  8.  
  9.      if (Confusion && rn2(7))
  10.          return;
  11.      lev = &levl[x][y];
  12.  
  13.      lev->seenv = SVALL;
  14.  
  15.      /* Secret corridors are found, but not secret doors. */
  16.      if (lev->typ == SCORR) {
  17.          lev->typ = CORR;
  18.          unblock_point(x, y);
  19.      }
  20.  
  21.      /*
  22.       * Force the real background, then if it's not furniture and there's
  23.       * a known trap there, display the trap, else if there was an object
  24.       * shown there, redisplay the object.  So during mapping, furniture
  25.       * takes precedence over traps, which take precedence over objects,
  26.       * opposite to how normal vision behaves.
  27.       */
  28.      oldglyph = glyph_at(x, y);
  29.      if (level.flags.hero_memory) {
  30.          magic_map_background(x, y, 0);
  31.          newsym(x, y); /* show it, if not blocked */
  32.      } else {
  33.          magic_map_background(x, y, 1); /* display it */
  34.      }
  35.      if (!IS_FURNITURE(lev->typ)) {
  36.          if ((t = t_at(x, y)) != 0 && t->tseen) {
  37.              map_trap(t, 1);
  38.          } else if (glyph_is_trap(oldglyph) || glyph_is_object(oldglyph)) {
  39.              show_glyph(x, y, oldglyph);
  40.              if (level.flags.hero_memory)
  41.                  lev->glyph = oldglyph;
  42.          }
  43.      }
  44.  }
  45.  

do_mapping

  1.  void
  2.  do_mapping()
  3.  {
  4.      register int zx, zy;
  5.  
  6.      iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  7.      u.uinwater = u.uburied = 0;
  8.      for (zx = 1; zx < COLNO; zx++)
  9.          for (zy = 0; zy < ROWNO; zy++)
  10.              show_map_spot(zx, zy);
  11.      u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  12.      if (!level.flags.hero_memory || Underwater) {
  13.          flush_screen(1);                 /* flush temp screen */
  14.          display_nhwindow(WIN_MAP, TRUE); /* wait */
  15.          docrt();
  16.      }
  17.      exercise(A_WIS, TRUE);
  18.  }
  19.  

do_vicinity_map

  1.  void
  2.  do_vicinity_map()
  3.  {
  4.      register int zx, zy;
  5.      int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5),
  6.          hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6),
  7.          lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */
  8.          hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10);
  9.  
  10.      for (zx = lo_x; zx < hi_x; zx++)
  11.          for (zy = lo_y; zy < hi_y; zy++)
  12.              show_map_spot(zx, zy);
  13.  
  14.      if (!level.flags.hero_memory || Underwater) {
  15.          flush_screen(1);                 /* flush temp screen */
  16.          display_nhwindow(WIN_MAP, TRUE); /* wait */
  17.          docrt();
  18.      }
  19.  }
  20.  

cvt_sdoor_to_door

  1.  /* convert a secret door into a normal door */
  2.  void
  3.  cvt_sdoor_to_door(lev)
  4.  struct rm *lev;
  5.  {
  6.      int newmask = lev->doormask & ~WM_MASK;
  7.  
  8.      if (Is_rogue_level(&u.uz))
  9.          /* rogue didn't have doors, only doorways */
  10.          newmask = D_NODOOR;
  11.      else
  12.          /* newly exposed door is closed */
  13.          if (!(newmask & D_LOCKED))
  14.          newmask |= D_CLOSED;
  15.  
  16.      lev->typ = DOOR;
  17.      lev->doormask = newmask;
  18.  }
  19.  

findone

  1.  STATIC_PTR void
  2.  findone(zx, zy, num)
  3.  int zx, zy;
  4.  genericptr_t num;
  5.  {
  6.      register struct trap *ttmp;
  7.      register struct monst *mtmp;
  8.  
  9.      if (levl[zx][zy].typ == SDOOR) {
  10.          cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
  11.          magic_map_background(zx, zy, 0);
  12.          newsym(zx, zy);
  13.          (*(int *) num)++;
  14.      } else if (levl[zx][zy].typ == SCORR) {
  15.          levl[zx][zy].typ = CORR;
  16.          unblock_point(zx, zy);
  17.          magic_map_background(zx, zy, 0);
  18.          newsym(zx, zy);
  19.          (*(int *) num)++;
  20.      } else if ((ttmp = t_at(zx, zy)) != 0) {
  21.          if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
  22.              ttmp->tseen = 1;
  23.              newsym(zx, zy);
  24.              (*(int *) num)++;
  25.          }
  26.      } else if ((mtmp = m_at(zx, zy)) != 0) {
  27.          if (mtmp->m_ap_type) {
  28.              seemimic(mtmp);
  29.              (*(int *) num)++;
  30.          }
  31.          if (mtmp->mundetected
  32.              && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) {
  33.              mtmp->mundetected = 0;
  34.              newsym(zx, zy);
  35.              (*(int *) num)++;
  36.          }
  37.          if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph))
  38.              map_invisible(zx, zy);
  39.      } else if (glyph_is_invisible(levl[zx][zy].glyph)) {
  40.          unmap_object(zx, zy);
  41.          newsym(zx, zy);
  42.          (*(int *) num)++;
  43.      }
  44.  }
  45.  

openone

  1.  STATIC_PTR void
  2.  openone(zx, zy, num)
  3.  int zx, zy;
  4.  genericptr_t num;
  5.  {
  6.      register struct trap *ttmp;
  7.      register struct obj *otmp;
  8.      int *num_p = (int *) num;
  9.  
  10.      if (OBJ_AT(zx, zy)) {
  11.          for (otmp = level.objects[zx][zy]; otmp; otmp = otmp->nexthere) {
  12.              if (Is_box(otmp) && otmp->olocked) {
  13.                  otmp->olocked = 0;
  14.                  (*num_p)++;
  15.              }
  16.          }
  17.          /* let it fall to the next cases. could be on trap. */
  18.      }
  19.      if (levl[zx][zy].typ == SDOOR
  20.          || (levl[zx][zy].typ == DOOR
  21.              && (levl[zx][zy].doormask & (D_CLOSED | D_LOCKED)))) {
  22.          if (levl[zx][zy].typ == SDOOR)
  23.              cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
  24.          if (levl[zx][zy].doormask & D_TRAPPED) {
  25.              if (distu(zx, zy) < 3)
  26.                  b_trapped("door", 0);
  27.              else
  28.                  Norep("You %s an explosion!",
  29.                        cansee(zx, zy) ? "see" : (!Deaf ? "hear"
  30.                                                        : "feel the shock of"));
  31.              wake_nearto(zx, zy, 11 * 11);
  32.              levl[zx][zy].doormask = D_NODOOR;
  33.          } else
  34.              levl[zx][zy].doormask = D_ISOPEN;
  35.          unblock_point(zx, zy);
  36.          newsym(zx, zy);
  37.          (*num_p)++;
  38.      } else if (levl[zx][zy].typ == SCORR) {
  39.          levl[zx][zy].typ = CORR;
  40.          unblock_point(zx, zy);
  41.          newsym(zx, zy);
  42.          (*num_p)++;
  43.      } else if ((ttmp = t_at(zx, zy)) != 0) {
  44.          struct monst *mon;
  45.          boolean dummy; /* unneeded "you notice it arg" */
  46.  
  47.          if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
  48.              ttmp->tseen = 1;
  49.              newsym(zx, zy);
  50.              (*num_p)++;
  51.          }
  52.          mon = (zx == u.ux && zy == u.uy) ? &youmonst : m_at(zx, zy);
  53.          if (openholdingtrap(mon, &dummy)
  54.              || openfallingtrap(mon, TRUE, &dummy))
  55.              (*num_p)++;
  56.      } else if (find_drawbridge(&zx, &zy)) {
  57.          /* make sure it isn't an open drawbridge */
  58.          open_drawbridge(zx, zy);
  59.          (*num_p)++;
  60.      }
  61.  }
  62.  

findit

  1.  /* returns number of things found */
  2.  int
  3.  findit()
  4.  {
  5.      int num = 0;
  6.  
  7.      if (u.uswallow)
  8.          return 0;
  9.      do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num);
  10.      return num;
  11.  }
  12.  

openit

  1.  /* returns number of things found and opened */
  2.  int
  3.  openit()
  4.  {
  5.      int num = 0;
  6.  
  7.      if (u.uswallow) {
  8.          if (is_animal(u.ustuck->data)) {
  9.              if (Blind)
  10.                  pline("Its mouth opens!");
  11.              else
  12.                  pline("%s opens its mouth!", Monnam(u.ustuck));
  13.          }
  14.          expels(u.ustuck, u.ustuck->data, TRUE);
  15.          return -1;
  16.      }
  17.  
  18.      do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num);
  19.      return num;
  20.  }
  21.  

detecting

  1.  /* callback hack for overriding vision in do_clear_area() */
  2.  boolean
  3.  detecting(func)
  4.  void FDECL((*func), (int, int, genericptr_t));
  5.  {
  6.      return (func == findone || func == openone);
  7.  }
  8.  

find_trap

  1.  void
  2.  find_trap(trap)
  3.  struct trap *trap;
  4.  {
  5.      int tt = what_trap(trap->ttyp);
  6.      boolean cleared = FALSE;
  7.  
  8.      trap->tseen = 1;
  9.      exercise(A_WIS, TRUE);
  10.      feel_newsym(trap->tx, trap->ty);
  11.  
  12.      if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
  13.          /* There's too much clutter to see your find otherwise */
  14.          cls();
  15.          map_trap(trap, 1);
  16.          display_self();
  17.          cleared = TRUE;
  18.      }
  19.  
  20.      You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
  21.  
  22.      if (cleared) {
  23.          display_nhwindow(WIN_MAP, TRUE); /* wait */
  24.          docrt();
  25.      }
  26.  }
  27.  

dosearch0

  1.  int
  2.  dosearch0(aflag)
  3.  register int aflag; /* intrinsic autosearch vs explicit searching */
  4.  {
  5.  #ifdef GCC_BUG
  6.      /* some versions of gcc seriously muck up nested loops. if you get strange
  7.         crashes while searching in a version compiled with gcc, try putting
  8.         #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
  9.         makefile).
  10.       */
  11.      volatile xchar x, y;
  12.  #else
  13.      register xchar x, y;
  14.  #endif
  15.      register struct trap *trap;
  16.      register struct monst *mtmp;
  17.  
  18.      if (u.uswallow) {
  19.          if (!aflag)
  20.              pline("What are you looking for?  The exit?");
  21.      } else {
  22.          int fund = (uwep && uwep->oartifact
  23.                      && spec_ability(uwep, SPFX_SEARCH)) ? uwep->spe : 0;
  24.  
  25.          if (ublindf && ublindf->otyp == LENSES && !Blind)
  26.              fund += 2; /* JDS: lenses help searching */
  27.          if (fund > 5)
  28.              fund = 5;
  29.          for (x = u.ux - 1; x < u.ux + 2; x++)
  30.              for (y = u.uy - 1; y < u.uy + 2; y++) {
  31.                  if (!isok(x, y))
  32.                      continue;
  33.                  if (x == u.ux && y == u.uy)
  34.                      continue;
  35.  
  36.                  if (Blind && !aflag)
  37.                      feel_location(x, y);
  38.                  if (levl[x][y].typ == SDOOR) {
  39.                      if (rnl(7 - fund))
  40.                          continue;
  41.                      cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
  42.                      exercise(A_WIS, TRUE);
  43.                      nomul(0);
  44.                      feel_location(x, y); /* make sure it shows up */
  45.                      You("find a hidden door.");
  46.                  } else if (levl[x][y].typ == SCORR) {
  47.                      if (rnl(7 - fund))
  48.                          continue;
  49.                      levl[x][y].typ = CORR;
  50.                      unblock_point(x, y); /* vision */
  51.                      exercise(A_WIS, TRUE);
  52.                      nomul(0);
  53.                      feel_location(x, y); /* make sure it shows up */
  54.                      You("find a hidden passage.");
  55.                  } else {
  56.                      /* Be careful not to find anything in an SCORR or SDOOR */
  57.                      if ((mtmp = m_at(x, y)) != 0 && !aflag) {
  58.                          if (mtmp->m_ap_type) {
  59.                              seemimic(mtmp);
  60.                          find:
  61.                              exercise(A_WIS, TRUE);
  62.                              if (!canspotmon(mtmp)) {
  63.                                  if (glyph_is_invisible(levl[x][y].glyph)) {
  64.                                      /* found invisible monster in a square
  65.                                       * which already has an 'I' in it.
  66.                                       * Logically, this should still take
  67.                                       * time and lead to a return(1), but
  68.                                       * if we did that the player would keep
  69.                                       * finding the same monster every turn.
  70.                                       */
  71.                                      continue;
  72.                                  } else {
  73.                                      You_feel("an unseen monster!");
  74.                                      map_invisible(x, y);
  75.                                  }
  76.                              } else if (!sensemon(mtmp))
  77.                                  You("find %s.", mtmp->mtame
  78.                                                     ? y_monnam(mtmp)
  79.                                                     : a_monnam(mtmp));
  80.                              return 1;
  81.                          }
  82.                          if (!canspotmon(mtmp)) {
  83.                              if (mtmp->mundetected
  84.                                  && (is_hider(mtmp->data)
  85.                                      || mtmp->data->mlet == S_EEL))
  86.                                  mtmp->mundetected = 0;
  87.                              newsym(x, y);
  88.                              goto find;
  89.                          }
  90.                      }
  91.  
  92.                      /* see if an invisible monster has moved--if Blind,
  93.                       * feel_location() already did it
  94.                       */
  95.                      if (!aflag && !mtmp && !Blind
  96.                          && glyph_is_invisible(levl[x][y].glyph)) {
  97.                          unmap_object(x, y);
  98.                          newsym(x, y);
  99.                      }
  100.  
  101.                      if ((trap = t_at(x, y)) && !trap->tseen && !rnl(8)) {
  102.                          nomul(0);
  103.                          if (trap->ttyp == STATUE_TRAP) {
  104.                              if (activate_statue_trap(trap, x, y, FALSE))
  105.                                  exercise(A_WIS, TRUE);
  106.                              return 1;
  107.                          } else {
  108.                              find_trap(trap);
  109.                          }
  110.                      }
  111.                  }
  112.              }
  113.      }
  114.      return 1;
  115.  }
  116.  

dosearch

  1.  /* the 's' command -- explicit searching */
  2.  int
  3.  dosearch()
  4.  {
  5.      return dosearch0(0);
  6.  }
  7.  

sokoban_detect

  1.  /* Pre-map the sokoban levels */
  2.  void
  3.  sokoban_detect()
  4.  {
  5.      register int x, y;
  6.      register struct trap *ttmp;
  7.      register struct obj *obj;
  8.  
  9.      /* Map the background and boulders */
  10.      for (x = 1; x < COLNO; x++)
  11.          for (y = 0; y < ROWNO; y++) {
  12.              levl[x][y].seenv = SVALL;
  13.              levl[x][y].waslit = TRUE;
  14.              map_background(x, y, 1);
  15.              if ((obj = sobj_at(BOULDER, x, y)) != 0)
  16.                  map_object(obj, 1);
  17.          }
  18.  
  19.      /* Map the traps */
  20.      for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
  21.          ttmp->tseen = 1;
  22.          map_trap(ttmp, 1);
  23.          /* set sokoban_rules when there is at least one pit or hole */
  24.          if (ttmp->ttyp == PIT || ttmp->ttyp == HOLE)
  25.              Sokoban = 1;
  26.      }
  27.  }
  28.  

reveal_terrain

  1.  /* idea from crawl; show known portion of map without any monsters,
  2.     objects, or traps occluding the view of the underlying terrain */
  3.  void
  4.  reveal_terrain(full, which_subset)
  5.  int full; /* wizard|explore modes allow player to request full map */
  6.  int which_subset; /* when not full, whether to suppress objs and/or traps */
  7.  {
  8.      if ((Hallucination || Stunned || Confusion) && !full) {
  9.          You("are too disoriented for this.");
  10.      } else {
  11.          int x, y, glyph, levl_glyph, default_glyph;
  12.          uchar seenv;
  13.          unsigned save_swallowed;
  14.          struct monst *mtmp;
  15.          struct trap *t;
  16.          char buf[BUFSZ];
  17.          boolean keep_traps = (which_subset & 1) !=0,
  18.                  keep_objs = (which_subset & 2) != 0,
  19.                  keep_mons = (which_subset & 4) != 0; /* actually always 0 */
  20.  
  21.          save_swallowed = u.uswallow;
  22.          iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
  23.          u.uinwater = u.uburied = 0;
  24.          u.uswallow = 0;
  25.          default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
  26.          /* for 'full', show the actual terrain for the entire level,
  27.             otherwise what the hero remembers for seen locations with
  28.             monsters, objects, and/or traps removed as caller dictates */
  29.          for (x = 1; x < COLNO; x++)
  30.              for (y = 0; y < ROWNO; y++) {
  31.                  seenv = (full || level.flags.hero_memory)
  32.                             ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0;
  33.                  if (full) {
  34.                      levl[x][y].seenv = SVALL;
  35.                      glyph = back_to_glyph(x, y);
  36.                      levl[x][y].seenv = seenv;
  37.                  } else {
  38.                      levl_glyph = level.flags.hero_memory
  39.                                      ? levl[x][y].glyph
  40.                                      : seenv
  41.                                         ? back_to_glyph(x, y)
  42.                                         : default_glyph;
  43.                      /* glyph_at() returns the displayed glyph, which might
  44.                         be a monster.  levl[][].glyph contains the remembered
  45.                         glyph, which will never be a monster (unless it is
  46.                         the invisible monster glyph, which is handled like
  47.                         an object, replacing any object or trap at its spot) */
  48.                      glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph;
  49.                      if (keep_mons && x == u.ux && y == u.uy && save_swallowed)
  50.                          glyph = mon_to_glyph(u.ustuck);
  51.                      else if (((glyph_is_monster(glyph)
  52.                                 || glyph_is_warning(glyph)) && !keep_mons)
  53.                               || glyph_is_swallow(glyph))
  54.                          glyph = levl_glyph;
  55.                      if (((glyph_is_object(glyph) && !keep_objs)
  56.                           || glyph_is_invisible(glyph))
  57.                          && keep_traps && !covers_traps(x, y)) {
  58.                          if ((t = t_at(x, y)) != 0 && t->tseen)
  59.                              glyph = trap_to_glyph(t);
  60.                      }
  61.                      if ((glyph_is_object(glyph) && !keep_objs)
  62.                          || (glyph_is_trap(glyph) && !keep_traps)
  63.                          || glyph_is_invisible(glyph)) {
  64.                          if (!seenv) {
  65.                              glyph = default_glyph;
  66.                          } else if (lastseentyp[x][y] == levl[x][y].typ) {
  67.                              glyph = back_to_glyph(x, y);
  68.                          } else {
  69.                              /* look for a mimic here posing as furniture;
  70.                                 if we don't find one, we'll have to fake it */
  71.                              if ((mtmp = m_at(x, y)) != 0
  72.                                  && mtmp->m_ap_type == M_AP_FURNITURE) {
  73.                                  glyph = cmap_to_glyph(mtmp->mappearance);
  74.                              } else {
  75.                                  /* we have a topology type but we want a
  76.                                     screen symbol in order to derive a glyph;
  77.                                     some screen symbols need the flags field
  78.                                     of levl[][] in addition to the type
  79.                                     (to disambiguate STAIRS to S_upstair or
  80.                                     S_dnstair, for example; current flags
  81.                                     might not be intended for remembered
  82.                                     type, but we've got no other choice) */
  83.                                  schar save_typ = levl[x][y].typ;
  84.  
  85.                                  levl[x][y].typ = lastseentyp[x][y];
  86.                                  glyph = back_to_glyph(x, y);
  87.                                  levl[x][y].typ = save_typ;
  88.                              }
  89.                          }
  90.                      }
  91.                  }
  92.                  show_glyph(x, y, glyph);
  93.              }
  94.  
  95.          /* [TODO: highlight hero's location somehow] */
  96.          u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
  97.          if (save_swallowed)
  98.              u.uswallow = 1;
  99.          flush_screen(1);
  100.          if (full) {
  101.              Strcpy(buf, "underlying terrain");
  102.          } else {
  103.              Strcpy(buf, "known terrain");
  104.              if (keep_traps)
  105.                  Sprintf(eos(buf), "%s traps",
  106.                          (keep_objs || keep_mons) ? "," : " and");
  107.              if (keep_objs)
  108.                  Sprintf(eos(buf), "%s%s objects",
  109.                          (keep_traps || keep_mons) ? "," : "",
  110.                          keep_mons ? "" : " and");
  111.              if (keep_mons)
  112.                  Sprintf(eos(buf), "%s and monsters",
  113.                          (keep_traps || keep_objs) ? "," : "");
  114.          }
  115.          pline("Showing %s only...", buf);
  116.          display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */
  117.          docrt(); /* redraw the screen, restoring regular map */
  118.          if (Underwater)
  119.              under_water(2);
  120.          if (u.uburied)
  121.              under_ground(2);
  122.      }
  123.      return;
  124.  }
  125.  
  126.  /*detect.c*/