Source:NetHack 3.6.1/src/pager.c

From NetHackWiki
(Redirected from Source:Ref/is swallow sym)
Jump to: navigation, search

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

Top of file

  1.  /* NetHack 3.6	pager.c	$NHDT-Date: 1523142395 2018/04/07 23:06:35 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Robert Patrick Rankin, 2018. */
  4.  /* NetHack may be freely redistributed.  See license for details. */

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.

  1.  
  2.  /* This file contains the command routines dowhatis() and dohelp() and */
  3.  /* a few other help related facilities */
  4.  
  5.  #include "hack.h"
  6.  #include "dlb.h"
  7.  
  8.  STATIC_DCL boolean FDECL(is_swallow_sym, (int));
  9.  STATIC_DCL int FDECL(append_str, (char *, const char *));
  10.  STATIC_DCL void FDECL(look_at_object, (char *, int, int, int));
  11.  STATIC_DCL void FDECL(look_at_monster, (char *, char *,
  12.                                          struct monst *, int, int));
  13.  STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
  14.  STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
  15.                                    BOOLEAN_P, BOOLEAN_P));
  16.  STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
  17.  STATIC_DCL void NDECL(whatdoes_help);
  18.  STATIC_DCL void NDECL(docontact);
  19.  STATIC_DCL void NDECL(dispfile_help);
  20.  STATIC_DCL void NDECL(dispfile_shelp);
  21.  STATIC_DCL void NDECL(dispfile_optionfile);
  22.  STATIC_DCL void NDECL(dispfile_license);
  23.  STATIC_DCL void NDECL(dispfile_debughelp);
  24.  STATIC_DCL void NDECL(hmenu_doextversion);
  25.  STATIC_DCL void NDECL(hmenu_dohistory);
  26.  STATIC_DCL void NDECL(hmenu_dowhatis);
  27.  STATIC_DCL void NDECL(hmenu_dowhatdoes);
  28.  STATIC_DCL void NDECL(hmenu_doextlist);
  29.  #ifdef PORT_HELP
  30.  extern void NDECL(port_help);
  31.  #endif
  32.  

is_swallow_sym

  1.  /* Returns "true" for characters that could represent a monster's stomach. */
  2.  STATIC_OVL boolean
  3.  is_swallow_sym(c)
  4.  int c;
  5.  {
  6.      int i;
  7.  
  8.      for (i = S_sw_tl; i <= S_sw_br; i++)
  9.          if ((int) showsyms[i] == c)
  10.              return TRUE;
  11.      return FALSE;
  12.  }
  13.  

append_str

  1.  /*
  2.   * Append new_str to the end of buf if new_str doesn't already exist as
  3.   * a substring of buf.  Return 1 if the string was appended, 0 otherwise.
  4.   * It is expected that buf is of size BUFSZ.
  5.   */
  6.  STATIC_OVL int
  7.  append_str(buf, new_str)
  8.  char *buf;
  9.  const char *new_str;
  10.  {
  11.      int space_left; /* space remaining in buf */
  12.  
  13.      if (strstri(buf, new_str))
  14.          return 0;
  15.  
  16.      space_left = BUFSZ - strlen(buf) - 1;
  17.      if (space_left < 1)
  18.          return 0;
  19.      (void) strncat(buf, " or ", space_left);
  20.      (void) strncat(buf, new_str, space_left - 4);
  21.      return 1;
  22.  }
  23.  

self_lookat

  1.  /* shared by monster probing (via query_objlist!) as well as lookat() */
  2.  char *
  3.  self_lookat(outbuf)
  4.  char *outbuf;
  5.  {
  6.      char race[QBUFSZ];
  7.  
  8.      /* include race with role unless polymorphed */
  9.      race[0] = '\0';
  10.      if (!Upolyd)
  11.          Sprintf(race, "%s ", urace.adj);
  12.      Sprintf(outbuf, "%s%s%s called %s",
  13.              /* being blinded may hide invisibility from self */
  14.              (Invis && (senseself() || !Blind)) ? "invisible " : "", race,
  15.              mons[u.umonnum].mname, plname);
  16.      if (u.usteed)
  17.          Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
  18.      if (u.uundetected || (Upolyd && youmonst.m_ap_type))
  19.          mhidden_description(&youmonst, FALSE, eos(outbuf));
  20.      return outbuf;
  21.  }
  22.  

mhidden_description

  1.  /* describe a hidden monster; used for look_at during extended monster
  2.     detection and for probing; also when looking at self */
  3.  void
  4.  mhidden_description(mon, altmon, outbuf)
  5.  struct monst *mon;
  6.  boolean altmon; /* for probing: if mimicking a monster, say so */
  7.  char *outbuf;
  8.  {
  9.      struct obj *otmp;
  10.      boolean fakeobj, isyou = (mon == &youmonst);
  11.      int x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my,
  12.          glyph = (level.flags.hero_memory && !isyou) ? levl[x][y].glyph
  13.                                                      : glyph_at(x, y);
  14.  
  15.      *outbuf = '\0';
  16.      if (mon->m_ap_type == M_AP_FURNITURE
  17.          || mon->m_ap_type == M_AP_OBJECT) {
  18.          Strcpy(outbuf, ", mimicking ");
  19.          if (mon->m_ap_type == M_AP_FURNITURE) {
  20.              Strcat(outbuf, an(defsyms[mon->mappearance].explanation));
  21.          } else if (mon->m_ap_type == M_AP_OBJECT
  22.                     /* remembered glyph, not glyph_at() which is 'mon' */
  23.                     && glyph_is_object(glyph)) {
  24.          objfrommap:
  25.              otmp = (struct obj *) 0;
  26.              fakeobj = object_from_map(glyph, x, y, &otmp);
  27.              Strcat(outbuf, (otmp && otmp->otyp != STRANGE_OBJECT)
  28.                                ? ansimpleoname(otmp)
  29.                                : an(obj_descr[STRANGE_OBJECT].oc_name));
  30.              if (fakeobj)
  31.                  dealloc_obj(otmp);
  32.          } else {
  33.              Strcat(outbuf, something);
  34.          }
  35.      } else if (mon->m_ap_type == M_AP_MONSTER) {
  36.          if (altmon)
  37.              Sprintf(outbuf, ", masquerading as %s",
  38.                      an(mons[mon->mappearance].mname));
  39.      } else if (isyou ? u.uundetected : mon->mundetected) {
  40.          Strcpy(outbuf, ", hiding");
  41.          if (hides_under(mon->data)) {
  42.              Strcat(outbuf, " under ");
  43.              /* remembered glyph, not glyph_at() which is 'mon' */
  44.              if (glyph_is_object(glyph))
  45.                  goto objfrommap;
  46.              Strcat(outbuf, something);
  47.          } else if (is_hider(mon->data)) {
  48.              Sprintf(eos(outbuf), " on the %s",
  49.                      (is_flyer(mon->data) || mon->data->mlet == S_PIERCER)
  50.                         ? "ceiling"
  51.                         : surface(x, y)); /* trapper */
  52.          } else {
  53.              if (mon->data->mlet == S_EEL && is_pool(x, y))
  54.                  Strcat(outbuf, " in murky water");
  55.          }
  56.      }
  57.  }
  58.  

object_from_map

  1.  /* extracted from lookat(); also used by namefloorobj() */
  2.  boolean
  3.  object_from_map(glyph, x, y, obj_p)
  4.  int glyph, x, y;
  5.  struct obj **obj_p;
  6.  {
  7.      boolean fakeobj = FALSE;
  8.      struct monst *mtmp;
  9.      struct obj *otmp;
  10.      int glyphotyp = glyph_to_obj(glyph);
  11.  
  12.      *obj_p = (struct obj *) 0;
  13.      /* TODO: check inside containers in case glyph came from detection */
  14.      if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
  15.          for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
  16.              if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
  17.                  break;
  18.  
  19.      /* there might be a mimic here posing as an object */
  20.      mtmp = m_at(x, y);
  21.      if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp))
  22.          otmp = 0;
  23.      else
  24.          mtmp = 0;
  25.  
  26.      if (!otmp || otmp->otyp != glyphotyp) {
  27.          /* this used to exclude STRANGE_OBJECT; now caller deals with it */
  28.          otmp = mksobj(glyphotyp, FALSE, FALSE);
  29.          if (!otmp)
  30.              return FALSE;
  31.          fakeobj = TRUE;
  32.          if (otmp->oclass == COIN_CLASS)
  33.              otmp->quan = 2L; /* to force pluralization */
  34.          else if (otmp->otyp == SLIME_MOLD)
  35.              otmp->spe = context.current_fruit; /* give it a type */
  36.          if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */
  37.              otmp->corpsenm = MCORPSENM(mtmp);
  38.      }
  39.      /* if located at adjacent spot, mark it as having been seen up close
  40.         (corpse type will be known even if dknown is 0, so we don't need a
  41.         touch check for cockatrice corpse--we're looking without touching) */
  42.      if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
  43.          /* redundant: we only look for an object which matches current
  44.             glyph among floor and buried objects; when !Blind, any buried
  45.             object's glyph will have been replaced by whatever is present
  46.             on the surface as soon as we moved next to its spot */
  47.          && (fakeobj || otmp->where == OBJ_FLOOR) /* not buried */
  48.          /* terrain mode views what's already known, doesn't learn new stuff */
  49.          && !iflags.terrainmode) /* so don't set dknown when in terrain mode */
  50.          otmp->dknown = 1; /* if a pile, clearly see the top item only */
  51.  
  52.      *obj_p = otmp;
  53.      return fakeobj; /* when True, caller needs to dealloc *obj_p */
  54.  }
  55.  

look_at_object

  1.  STATIC_OVL void
  2.  look_at_object(buf, x, y, glyph)
  3.  char *buf; /* output buffer */
  4.  int x, y, glyph;
  5.  {
  6.      struct obj *otmp = 0;
  7.      boolean fakeobj = object_from_map(glyph, x, y, &otmp);
  8.  
  9.      if (otmp) {
  10.          Strcpy(buf, (otmp->otyp != STRANGE_OBJECT)
  11.                       ? distant_name(otmp, doname_vague_quan)
  12.                       : obj_descr[STRANGE_OBJECT].oc_name);
  13.          if (fakeobj)
  14.              dealloc_obj(otmp), otmp = 0;
  15.      } else
  16.          Strcpy(buf, something); /* sanity precaution */
  17.  
  18.      if (otmp && otmp->where == OBJ_BURIED)
  19.          Strcat(buf, " (buried)");
  20.      else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
  21.          Strcat(buf, " embedded in stone");
  22.      else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
  23.          Strcat(buf, " embedded in a wall");
  24.      else if (closed_door(x, y))
  25.          Strcat(buf, " embedded in a door");
  26.      else if (is_pool(x, y))
  27.          Strcat(buf, " in water");
  28.      else if (is_lava(x, y))
  29.          Strcat(buf, " in molten lava"); /* [can this ever happen?] */
  30.      return;
  31.  }
  32.  

look_at_monster

  1.  STATIC_OVL void
  2.  look_at_monster(buf, monbuf, mtmp, x, y)
  3.  char *buf, *monbuf; /* buf: output, monbuf: optional output */
  4.  struct monst *mtmp;
  5.  int x, y;
  6.  {
  7.      char *name, monnambuf[BUFSZ];
  8.      boolean accurate = !Hallucination;
  9.  
  10.      name = (mtmp->data == &mons[PM_COYOTE] && accurate)
  11.                ? coyotename(mtmp, monnambuf)
  12.                : distant_monnam(mtmp, ARTICLE_NONE, monnambuf);
  13.      Sprintf(buf, "%s%s%s",
  14.              (mtmp->mx != x || mtmp->my != y)
  15.                  ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ")
  16.                  : "",
  17.              (mtmp->mtame && accurate)
  18.                  ? "tame "
  19.                  : (mtmp->mpeaceful && accurate)
  20.                      ? "peaceful "
  21.                      : "",
  22.              name);
  23.      if (u.ustuck == mtmp) {
  24.          if (u.uswallow || iflags.save_uswallow) /* monster detection */
  25.              Strcat(buf, is_animal(mtmp->data)
  26.                            ? ", swallowing you" : ", engulfing you");
  27.          else
  28.              Strcat(buf, (Upolyd && sticks(youmonst.data))
  29.                            ? ", being held" : ", holding you");
  30.      }
  31.      if (mtmp->mleashed)
  32.          Strcat(buf, ", leashed to you");
  33.  
  34.      if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) {
  35.          struct trap *t = t_at(mtmp->mx, mtmp->my);
  36.          int tt = t ? t->ttyp : NO_TRAP;
  37.  
  38.          /* newsym lets you know of the trap, so mention it here */
  39.          if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB)
  40.              Sprintf(eos(buf), ", trapped in %s",
  41.                      an(defsyms[trap_to_defsym(tt)].explanation));
  42.      }
  43.  
  44.      /* we know the hero sees a monster at this location, but if it's shown
  45.         due to persistant monster detection he might remember something else */
  46.      if (mtmp->mundetected || mtmp->m_ap_type)
  47.          mhidden_description(mtmp, FALSE, eos(buf));
  48.  
  49.      if (monbuf) {
  50.          unsigned how_seen = howmonseen(mtmp);
  51.  
  52.          monbuf[0] = '\0';
  53.          if (how_seen != 0 && how_seen != MONSEEN_NORMAL) {
  54.              if (how_seen & MONSEEN_NORMAL) {
  55.                  Strcat(monbuf, "normal vision");
  56.                  how_seen &= ~MONSEEN_NORMAL;
  57.                  /* how_seen can't be 0 yet... */
  58.                  if (how_seen)
  59.                      Strcat(monbuf, ", ");
  60.              }
  61.              if (how_seen & MONSEEN_SEEINVIS) {
  62.                  Strcat(monbuf, "see invisible");
  63.                  how_seen &= ~MONSEEN_SEEINVIS;
  64.                  if (how_seen)
  65.                      Strcat(monbuf, ", ");
  66.              }
  67.              if (how_seen & MONSEEN_INFRAVIS) {
  68.                  Strcat(monbuf, "infravision");
  69.                  how_seen &= ~MONSEEN_INFRAVIS;
  70.                  if (how_seen)
  71.                      Strcat(monbuf, ", ");
  72.              }
  73.              if (how_seen & MONSEEN_TELEPAT) {
  74.                  Strcat(monbuf, "telepathy");
  75.                  how_seen &= ~MONSEEN_TELEPAT;
  76.                  if (how_seen)
  77.                      Strcat(monbuf, ", ");
  78.              }
  79.              if (how_seen & MONSEEN_XRAYVIS) {
  80.                  /* Eyes of the Overworld */
  81.                  Strcat(monbuf, "astral vision");
  82.                  how_seen &= ~MONSEEN_XRAYVIS;
  83.                  if (how_seen)
  84.                      Strcat(monbuf, ", ");
  85.              }
  86.              if (how_seen & MONSEEN_DETECT) {
  87.                  Strcat(monbuf, "monster detection");
  88.                  how_seen &= ~MONSEEN_DETECT;
  89.                  if (how_seen)
  90.                      Strcat(monbuf, ", ");
  91.              }
  92.              if (how_seen & MONSEEN_WARNMON) {
  93.                  if (Hallucination) {
  94.                      Strcat(monbuf, "paranoid delusion");
  95.                  } else {
  96.                      unsigned long mW = (context.warntype.obj
  97.                                          | context.warntype.polyd),
  98.                                    m2 = mtmp->data->mflags2;
  99.                      const char *whom = ((mW & M2_HUMAN & m2) ? "human"
  100.                                          : (mW & M2_ELF & m2) ? "elf"
  101.                                            : (mW & M2_ORC & m2) ? "orc"
  102.                                              : (mW & M2_DEMON & m2) ? "demon"
  103.                                                : mtmp->data->mname);
  104.  
  105.                      Sprintf(eos(monbuf), "warned of %s", makeplural(whom));
  106.                  }
  107.                  how_seen &= ~MONSEEN_WARNMON;
  108.                  if (how_seen)
  109.                      Strcat(monbuf, ", ");
  110.              }
  111.              /* should have used up all the how_seen bits by now */
  112.              if (how_seen) {
  113.                  impossible("lookat: unknown method of seeing monster");
  114.                  Sprintf(eos(monbuf), "(%u)", how_seen);
  115.              }
  116.          } /* seen by something other than normal vision */
  117.      } /* monbuf is non-null */
  118.  }
  119.  

lookat

  1.  /*
  2.   * Return the name of the glyph found at (x,y).
  3.   * If not hallucinating and the glyph is a monster, also monster data.
  4.   */
  5.  STATIC_OVL struct permonst *
  6.  lookat(x, y, buf, monbuf)
  7.  int x, y;
  8.  char *buf, *monbuf;
  9.  {
  10.      struct monst *mtmp = (struct monst *) 0;
  11.      struct permonst *pm = (struct permonst *) 0;
  12.      int glyph;
  13.  
  14.      buf[0] = monbuf[0] = '\0';
  15.      glyph = glyph_at(x, y);
  16.      if (u.ux == x && u.uy == y && canspotself()
  17.          && !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck))
  18.          && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
  19.          /* fill in buf[] */
  20.          (void) self_lookat(buf);
  21.  
  22.          /* file lookup can't distinguish between "gnomish wizard" monster
  23.             and correspondingly named player character, always picking the
  24.             former; force it to find the general "wizard" entry instead */
  25.          if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd)
  26.              pm = &mons[PM_WIZARD];
  27.  
  28.          /* When you see yourself normally, no explanation is appended
  29.             (even if you could also see yourself via other means).
  30.             Sensing self while blind or swallowed is treated as if it
  31.             were by normal vision (cf canseeself()). */
  32.          if ((Invisible || u.uundetected) && !Blind
  33.              && !(u.uswallow || iflags.save_uswallow)) {
  34.              unsigned how = 0;
  35.  
  36.              if (Infravision)
  37.                  how |= 1;
  38.              if (Unblind_telepat)
  39.                  how |= 2;
  40.              if (Detect_monsters)
  41.                  how |= 4;
  42.  
  43.              if (how)
  44.                  Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
  45.                          (how & 1) ? "infravision" : "",
  46.                          /* add comma if telep and infrav */
  47.                          ((how & 3) > 2) ? ", " : "",
  48.                          (how & 2) ? "telepathy" : "",
  49.                          /* add comma if detect and (infrav or telep or both) */
  50.                          ((how & 7) > 4) ? ", " : "",
  51.                          (how & 4) ? "monster detection" : "");
  52.          }
  53.      } else if (u.uswallow) {
  54.          /* when swallowed, we're only called for spots adjacent to hero,
  55.             and blindness doesn't prevent hero from feeling what holds him */
  56.          Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
  57.          pm = u.ustuck->data;
  58.      } else if (glyph_is_monster(glyph)) {
  59.          bhitpos.x = x;
  60.          bhitpos.y = y;
  61.          if ((mtmp = m_at(x, y)) != 0) {
  62.              look_at_monster(buf, monbuf, mtmp, x, y);
  63.              pm = mtmp->data;
  64.          } else if (Hallucination) {
  65.              /* 'monster' must actually be a statue */
  66.              Strcpy(buf, rndmonnam((char *) 0));
  67.          }
  68.      } else if (glyph_is_object(glyph)) {
  69.          look_at_object(buf, x, y, glyph); /* fill in buf[] */
  70.      } else if (glyph_is_trap(glyph)) {
  71.          int tnum = what_trap(glyph_to_trap(glyph));
  72.  
  73.          /* Trap detection displays a bear trap at locations having
  74.           * a trapped door or trapped container or both.
  75.           * TODO: we should create actual trap types for doors and
  76.           * chests so that they can have their own glyphs and tiles.
  77.           */
  78.          if (trapped_chest_at(tnum, x, y))
  79.              Strcpy(buf, "trapped chest"); /* might actually be a large box */
  80.          else if (trapped_door_at(tnum, x, y))
  81.              Strcpy(buf, "trapped door"); /* not "trap door"... */
  82.          else
  83.              Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
  84.      } else if (glyph_is_warning(glyph)) {
  85.          int warnindx = glyph_to_warning(glyph);
  86.  
  87.          Strcpy(buf, def_warnsyms[warnindx].explanation);
  88.      } else if (!glyph_is_cmap(glyph)) {
  89.          Strcpy(buf, "unexplored area");
  90.      } else
  91.          switch (glyph_to_cmap(glyph)) {
  92.          case S_altar:
  93.              Sprintf(buf, "%s %saltar",
  94.                      /* like endgame high priests, endgame high altars
  95.                         are only recognizable when immediately adjacent */
  96.                      (Is_astralevel(&u.uz) && distu(x, y) > 2)
  97.                          ? "aligned"
  98.                          : align_str(
  99.                                Amask2align(levl[x][y].altarmask & ~AM_SHRINE)),
  100.                      ((levl[x][y].altarmask & AM_SHRINE)
  101.                       && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
  102.                          ? "high "
  103.                          : "");
  104.              break;
  105.          case S_ndoor:
  106.              if (is_drawbridge_wall(x, y) >= 0)
  107.                  Strcpy(buf, "open drawbridge portcullis");
  108.              else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
  109.                  Strcpy(buf, "broken door");
  110.              else
  111.                  Strcpy(buf, "doorway");
  112.              break;
  113.          case S_cloud:
  114.              Strcpy(buf,
  115.                     Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud");
  116.              break;
  117.          case S_stone:
  118.              if (!levl[x][y].seenv) {
  119.                  Strcpy(buf, "unexplored");
  120.                  break;
  121.              } else if (Underwater && !Is_waterlevel(&u.uz)) {
  122.                  /* "unknown" == previously mapped but not visible when
  123.                     submerged; better terminology appreciated... */
  124.                  Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
  125.                  break;
  126.              } else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
  127.                  Strcpy(buf, "stone");
  128.                  break;
  129.              }
  130.              /*FALLTHRU*/
  131.          default:
  132.              Strcpy(buf, defsyms[glyph_to_cmap(glyph)].explanation);
  133.              break;
  134.          }
  135.  
  136.      return (pm && !Hallucination) ? pm : (struct permonst *) 0;
  137.  }
  138.  

checkfile

  1.  /*
  2.   * Look in the "data" file for more info.  Called if the user typed in the
  3.   * whole name (user_typed_name == TRUE), or we've found a possible match
  4.   * with a character/glyph and flags.help is TRUE.
  5.   *
  6.   * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
  7.   *       must not be changed directly, e.g. via lcase(). We want to force
  8.   *       lcase() for data.base lookup so that we can have a clean key.
  9.   *       Therefore, we create a copy of inp _just_ for data.base lookup.
  10.   */
  11.  STATIC_OVL void
  12.  checkfile(inp, pm, user_typed_name, without_asking)
  13.  char *inp;
  14.  struct permonst *pm;
  15.  boolean user_typed_name, without_asking;
  16.  {
  17.      dlb *fp;
  18.      char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ];
  19.      char *ep, *dbase_str;
  20.      unsigned long txt_offset = 0L;
  21.      winid datawin = WIN_ERR;
  22.  
  23.      fp = dlb_fopen(DATAFILE, "r");
  24.      if (!fp) {
  25.          pline("Cannot open data file!");
  26.          return;
  27.      }
  28.      /* If someone passed us garbage, prevent fault. */
  29.      if (!inp || strlen(inp) > (BUFSZ - 1)) {
  30.          impossible("bad do_look buffer passed (%s)!",
  31.                     !inp ? "null" : "too long");
  32.          return;
  33.      }
  34.  
  35.      /* To prevent the need for entries in data.base like *ngel to account
  36.       * for Angel and angel, make the lookup string the same for both
  37.       * user_typed_name and picked name.
  38.       */
  39.      if (pm != (struct permonst *) 0 && !user_typed_name)
  40.          dbase_str = strcpy(newstr, pm->mname);
  41.      else
  42.          dbase_str = strcpy(newstr, inp);
  43.      (void) lcase(dbase_str);
  44.  
  45.      /*
  46.       * TODO:
  47.       * The switch from xname() to doname_vague_quan() in look_at_obj()
  48.       * had the unintendded side-effect of making names picked from
  49.       * pointing at map objects become harder to simplify for lookup.
  50.       * We should split the prefix and suffix handling used by wish
  51.       * parsing and also wizmode monster generation out into separate
  52.       * routines and use those routines here.  This currently lacks
  53.       * erosion handling and probably lots of other bits and pieces
  54.       * that wishing already understands and most of this duplicates
  55.       * stuff already done for wish handling or monster generation.
  56.       */
  57.      if (!strncmp(dbase_str, "interior of ", 12))
  58.          dbase_str += 12;
  59.      if (!strncmp(dbase_str, "a ", 2))
  60.          dbase_str += 2;
  61.      else if (!strncmp(dbase_str, "an ", 3))
  62.          dbase_str += 3;
  63.      else if (!strncmp(dbase_str, "the ", 4))
  64.          dbase_str += 4;
  65.      else if (!strncmp(dbase_str, "some ", 5))
  66.          dbase_str += 5;
  67.      else if (digit(*dbase_str)) {
  68.          /* remove count prefix ("2 ya") which can come from looking at map */
  69.          while (digit(*dbase_str))
  70.              ++dbase_str;
  71.          if (*dbase_str == ' ')
  72.              ++dbase_str;
  73.      }
  74.      if (!strncmp(dbase_str, "tame ", 5))
  75.          dbase_str += 5;
  76.      else if (!strncmp(dbase_str, "peaceful ", 9))
  77.          dbase_str += 9;
  78.      if (!strncmp(dbase_str, "invisible ", 10))
  79.          dbase_str += 10;
  80.      if (!strncmp(dbase_str, "saddled ", 8))
  81.          dbase_str += 8;
  82.      if (!strncmp(dbase_str, "blessed ", 8))
  83.          dbase_str += 8;
  84.      else if (!strncmp(dbase_str, "uncursed ", 9))
  85.          dbase_str += 9;
  86.      else if (!strncmp(dbase_str, "cursed ", 7))
  87.          dbase_str += 7;
  88.      if (!strncmp(dbase_str, "empty ", 6))
  89.          dbase_str += 6;
  90.      if (!strncmp(dbase_str, "partly used ", 12))
  91.          dbase_str += 12;
  92.      else if (!strncmp(dbase_str, "partly eaten ", 13))
  93.          dbase_str += 13;
  94.      if (!strncmp(dbase_str, "statue of ", 10))
  95.          dbase_str[6] = '\0';
  96.      else if (!strncmp(dbase_str, "figurine of ", 12))
  97.          dbase_str[8] = '\0';
  98.      /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't
  99.         needed because looking at items on the map used xname() rather than
  100.         doname() hence known enchantment was implicitly suppressed] */
  101.      if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) {
  102.          ++dbase_str; /* skip sign */
  103.          while (digit(*dbase_str))
  104.              ++dbase_str;
  105.          if (*dbase_str == ' ')
  106.              ++dbase_str;
  107.      }
  108.      /* "towel", "wet towel", and "moist towel" share one data.base entry;
  109.         for "wet towel", we keep prefix so that the prompt will ask about
  110.         "wet towel"; for "moist towel", we also want to ask about "wet towel".
  111.         (note: strncpy() only terminates output string if the specified
  112.         count is bigger than the length of the substring being copied) */
  113.      if (!strncmp(dbase_str, "moist towel", 11))
  114.          (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */
  115.  
  116.      /* Make sure the name is non-empty. */
  117.      if (*dbase_str) {
  118.          long pass1offset = -1L;
  119.          int chk_skip, pass = 1;
  120.          boolean yes_to_moreinfo, found_in_file, pass1found_in_file,
  121.                  skipping_entry;
  122.          char *ap, *alt = 0; /* alternate description */
  123.  
  124.          /* adjust the input to remove "named " and "called " */
  125.          if ((ep = strstri(dbase_str, " named ")) != 0) {
  126.              alt = ep + 7;
  127.              if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep)
  128.                  ep = ap; /* "named" is alt but truncate at "called" */
  129.          } else if ((ep = strstri(dbase_str, " called ")) != 0) {
  130.              copynchars(givenname, ep + 8, BUFSZ - 1);
  131.              alt = givenname;
  132.          } else
  133.              ep = strstri(dbase_str, ", ");
  134.          if (ep && ep > dbase_str)
  135.              *ep = '\0';
  136.          /* remove charges or "(lit)" or wizmode "(N aum)" */
  137.          if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str)
  138.              *ep = '\0';
  139.          if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt)
  140.              *ap = '\0';
  141.  
  142.          /*
  143.           * If the object is named, then the name is the alternate description;
  144.           * otherwise, the result of makesingular() applied to the name is.
  145.           * This isn't strictly optimal, but named objects of interest to the
  146.           * user will usually be found under their name, rather than under
  147.           * their object type, so looking for a singular form is pointless.
  148.           */
  149.          if (!alt)
  150.              alt = makesingular(dbase_str);
  151.  
  152.          pass1found_in_file = FALSE;
  153.          for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) {
  154.              found_in_file = skipping_entry = FALSE;
  155.              txt_offset = 0L;
  156.              if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) {
  157.                  impossible("can't get to start of 'data' file");
  158.                  goto checkfile_done;
  159.              }
  160.              /* skip first record; read second */
  161.              if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) {
  162.                  impossible("can't read 'data' file");
  163.                  goto checkfile_done;
  164.              } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1
  165.                         || txt_offset == 0L)
  166.                  goto bad_data_file;
  167.  
  168.              /* look for the appropriate entry */
  169.              while (dlb_fgets(buf, BUFSZ, fp)) {
  170.                  if (*buf == '.')
  171.                      break; /* we passed last entry without success */
  172.  
  173.                  if (digit(*buf)) {
  174.                      /* a number indicates the end of current entry */
  175.                      skipping_entry = FALSE;
  176.                  } else if (!skipping_entry) {
  177.                      if (!(ep = index(buf, '\n')))
  178.                          goto bad_data_file;
  179.                      (void) strip_newline((ep > buf) ? ep - 1 : ep);
  180.                      /* if we match a key that begins with "~", skip
  181.                         this entry */
  182.                      chk_skip = (*buf == '~') ? 1 : 0;
  183.                      if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
  184.                          || (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
  185.                          if (chk_skip) {
  186.                              skipping_entry = TRUE;
  187.                              continue;
  188.                          } else {
  189.                              found_in_file = TRUE;
  190.                              if (pass == 1)
  191.                                  pass1found_in_file = TRUE;
  192.                              break;
  193.                          }
  194.                      }
  195.                  }
  196.              }
  197.              if (found_in_file) {
  198.                  long entry_offset, fseekoffset;
  199.                  int entry_count;
  200.                  int i;
  201.  
  202.                  /* skip over other possible matches for the info */
  203.                  do {
  204.                      if (!dlb_fgets(buf, BUFSZ, fp))
  205.                          goto bad_data_file;
  206.                  } while (!digit(*buf));
  207.                  if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2)
  208.                      goto bad_data_file;
  209.                  fseekoffset = (long) txt_offset + entry_offset;
  210.                  if (pass == 1)
  211.                      pass1offset = fseekoffset;
  212.                  else if (fseekoffset == pass1offset)
  213.                      goto checkfile_done;
  214.  
  215.                  yes_to_moreinfo = FALSE;
  216.                  if (!user_typed_name && !without_asking) {
  217.                      char *entrytext = pass ? alt : dbase_str;
  218.                      char question[QBUFSZ];
  219.  
  220.                      Strcpy(question, "More info about \"");
  221.                      /* +2 => length of "\"?" */
  222.                      copynchars(eos(question), entrytext,
  223.                                 (int) (sizeof question - 1
  224.                                        - (strlen(question) + 2)));
  225.                      Strcat(question, "\"?");
  226.                      if (yn(question) == 'y')
  227.                          yes_to_moreinfo = TRUE;
  228.                  }
  229.  
  230.                  if (user_typed_name || without_asking || yes_to_moreinfo) {
  231.                      if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) {
  232.                          pline("? Seek error on 'data' file!");
  233.                          goto checkfile_done;
  234.                      }
  235.                      datawin = create_nhwindow(NHW_MENU);
  236.                      for (i = 0; i < entry_count; i++) {
  237.                          if (!dlb_fgets(buf, BUFSZ, fp))
  238.                              goto bad_data_file;
  239.                          (void) strip_newline(buf);
  240.                          if (index(buf + 1, '\t') != 0)
  241.                              (void) tabexpand(buf + 1);
  242.                          putstr(datawin, 0, buf + 1);
  243.                      }
  244.                      display_nhwindow(datawin, FALSE);
  245.                      destroy_nhwindow(datawin), datawin = WIN_ERR;
  246.                  }
  247.              } else if (user_typed_name && pass == 0 && !pass1found_in_file)
  248.                  pline("I don't have any information on those things.");
  249.          }
  250.      }
  251.      goto checkfile_done; /* skip error feedback */
  252.  
  253.   bad_data_file:
  254.      impossible("'data' file in wrong format or corrupted");
  255.   checkfile_done:
  256.      if (datawin != WIN_ERR)
  257.          destroy_nhwindow(datawin);
  258.      (void) dlb_fclose(fp);
  259.      return;
  260.  }
  261.  

do_screen_description

  1.  int
  2.  do_screen_description(cc, looked, sym, out_str, firstmatch)
  3.  coord cc;
  4.  boolean looked;
  5.  int sym;
  6.  char *out_str;
  7.  const char **firstmatch;
  8.  {
  9.      static const char mon_interior[] = "the interior of a monster",
  10.                        unreconnoitered[] = "unreconnoitered";
  11.      static char look_buf[BUFSZ];
  12.      char prefix[BUFSZ];
  13.      int i, alt_i, glyph = NO_GLYPH,
  14.          skipped_venom = 0, found = 0; /* count of matching syms found */
  15.      boolean hit_trap, need_to_look = FALSE,
  16.              submerged = (Underwater && !Is_waterlevel(&u.uz));
  17.      const char *x_str;
  18.  
  19.      if (looked) {
  20.          int oc;
  21.          unsigned os;
  22.  
  23.          glyph = glyph_at(cc.x, cc.y);
  24.          /* Convert glyph at selected position to a symbol for use below. */
  25.          (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y);
  26.  
  27.          Sprintf(prefix, "%s        ", encglyph(glyph));
  28.      } else
  29.          Sprintf(prefix, "%c        ", sym);
  30.  
  31.      /*
  32.       * Check all the possibilities, saving all explanations in a buffer.
  33.       * When all have been checked then the string is printed.
  34.       */
  35.  
  36.      /*
  37.       * Handle restricted vision range (limited to adjacent spots when
  38.       * swallowed or underwater) cases first.
  39.       *
  40.       * 3.6.0 listed anywhere on map, other than self, as "interior
  41.       * of a monster" when swallowed, and non-adjacent water or
  42.       * non-water anywhere as "dark part of a room" when underwater.
  43.       * "unreconnoitered" is an attempt to convey "even if you knew
  44.       * what was there earlier, you don't know what is there in the
  45.       * current circumstance".
  46.       *
  47.       * (Note: 'self' will always be visible when swallowed so we don't
  48.       * need special swallow handling for <ux,uy>.
  49.       * Another note: for '#terrain' without monsters, u.uswallow and
  50.       * submerged will always both be False and skip this code.)
  51.       */
  52.      x_str = 0;
  53.      if (!looked) {
  54.          ; /* skip special handling */
  55.      } else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
  56.                 /* detection showing some category, so mostly background */
  57.                 || ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
  58.                     && glyph == cmap_to_glyph(S_stone))) {
  59.          x_str = unreconnoitered;
  60.          need_to_look = FALSE;
  61.      } else if (is_swallow_sym(sym)) {
  62.          x_str = mon_interior;
  63.          need_to_look = TRUE; /* for specific monster type */
  64.      }
  65.      if (x_str) {
  66.          /* we know 'found' is zero here, but guard against some other
  67.             special case being inserted ahead of us someday */
  68.          if (!found) {
  69.              Sprintf(out_str, "%s%s", prefix, x_str);
  70.              *firstmatch = x_str;
  71.              found++;
  72.          } else {
  73.              found += append_str(out_str, x_str); /* not 'an(x_str)' */
  74.          }
  75.          /* for is_swallow_sym(), we want to list the current symbol's
  76.             other possibilities (wand for '/', throne for '\\', &c) so
  77.             don't jump to the end for the x_str==mon_interior case */
  78.          if (x_str == unreconnoitered)
  79.              goto didlook;
  80.      }
  81.  
  82.      /* Check for monsters */
  83.      if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
  84.          for (i = 0; i < MAXMCLASSES; i++) {
  85.              if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
  86.                  && def_monsyms[i].explain) {
  87.                  need_to_look = TRUE;
  88.                  if (!found) {
  89.                      Sprintf(out_str, "%s%s",
  90.                              prefix, an(def_monsyms[i].explain));
  91.                      *firstmatch = def_monsyms[i].explain;
  92.                      found++;
  93.                  } else {
  94.                      found += append_str(out_str, an(def_monsyms[i].explain));
  95.                  }
  96.              }
  97.          }
  98.          /* handle '@' as a special case if it refers to you and you're
  99.             playing a character which isn't normally displayed by that
  100.             symbol; firstmatch is assumed to already be set for '@' */
  101.          if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
  102.                         && cc.x == u.ux && cc.y == u.uy)
  103.                      : (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
  104.              && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
  105.              found += append_str(out_str, "you"); /* tack on "or you" */
  106.      }
  107.  
  108.      /* Now check for objects */
  109.      if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
  110.          for (i = 1; i < MAXOCLASSES; i++) {
  111.              if (sym == (looked ? showsyms[i + SYM_OFF_O]
  112.                                 : def_oc_syms[i].sym)
  113.                  || (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
  114.                  need_to_look = TRUE;
  115.                  if (looked && i == VENOM_CLASS) {
  116.                      skipped_venom++;
  117.                      continue;
  118.                  }
  119.                  if (!found) {
  120.                      Sprintf(out_str, "%s%s",
  121.                              prefix, an(def_oc_syms[i].explain));
  122.                      *firstmatch = def_oc_syms[i].explain;
  123.                      found++;
  124.                  } else {
  125.                      found += append_str(out_str, an(def_oc_syms[i].explain));
  126.                  }
  127.              }
  128.          }
  129.      }
  130.  
  131.      if (sym == DEF_INVISIBLE) {
  132.          if (!found) {
  133.              Sprintf(out_str, "%s%s", prefix, an(invisexplain));
  134.              *firstmatch = invisexplain;
  135.              found++;
  136.          } else {
  137.              found += append_str(out_str, an(invisexplain));
  138.          }
  139.      }
  140.  
  141.      /* Now check for graphics symbols */
  142.      alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
  143.      for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
  144.          /* when sym is the default background character, we process
  145.             i == 0 three times: unexplored, stone, dark part of a room */
  146.          if (alt_i < 2) {
  147.              x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
  148.              i = 0; /* for second iteration, undo loop increment */
  149.              /* alt_i is now 1 or 2 */
  150.          } else {
  151.              if (alt_i++ == 2)
  152.                  i = 0; /* undo loop increment */
  153.              x_str = defsyms[i].explanation;
  154.              if (submerged && !strcmp(x_str, defsyms[0].explanation))
  155.                  x_str = "land"; /* replace "dark part of a room" */
  156.              /* alt_i is now 3 or more and no longer of interest */
  157.          }
  158.          if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
  159.              /* avoid "an unexplored", "an stone", "an air", "a water",
  160.                 "a floor of a room", "a dark part of a room";
  161.                 article==2 => "the", 1 => "an", 0 => (none) */
  162.              int article = strstri(x_str, " of a room") ? 2
  163.                            : !(alt_i <= 2
  164.                                || strcmp(x_str, "air") == 0
  165.                                || strcmp(x_str, "land") == 0
  166.                                || strcmp(x_str, "water") == 0);
  167.  
  168.              if (!found) {
  169.                  if (is_cmap_trap(i)) {
  170.                      Sprintf(out_str, "%sa trap", prefix);
  171.                      hit_trap = TRUE;
  172.                  } else {
  173.                      Sprintf(out_str, "%s%s", prefix,
  174.                              article == 2 ? the(x_str)
  175.                              : article == 1 ? an(x_str) : x_str);
  176.                  }
  177.                  *firstmatch = x_str;
  178.                  found++;
  179.              } else if (!(hit_trap && is_cmap_trap(i))
  180.                         && !(found >= 3 && is_cmap_drawbridge(i))
  181.                         /* don't mention vibrating square outside of Gehennom
  182.                            unless this happens to be one (hallucination?) */
  183.                         && (i != S_vibrating_square || Inhell
  184.                             || (looked && glyph_is_trap(glyph)
  185.                                 && glyph_to_trap(glyph) == VIBRATING_SQUARE))) {
  186.                  found += append_str(out_str, (article == 2) ? the(x_str)
  187.                                               : (article == 1) ? an(x_str)
  188.                                                 : x_str);
  189.                  if (is_cmap_trap(i))
  190.                      hit_trap = TRUE;
  191.              }
  192.  
  193.              if (i == S_altar || is_cmap_trap(i))
  194.                  need_to_look = TRUE;
  195.          }
  196.      }
  197.  
  198.      /* Now check for warning symbols */
  199.      for (i = 1; i < WARNCOUNT; i++) {
  200.          x_str = def_warnsyms[i].explanation;
  201.          if (sym == (looked ? warnsyms[i] : def_warnsyms[i].sym)) {
  202.              if (!found) {
  203.                  Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation);
  204.                  *firstmatch = def_warnsyms[i].explanation;
  205.                  found++;
  206.              } else {
  207.                  found += append_str(out_str, def_warnsyms[i].explanation);
  208.              }
  209.              /* Kludge: warning trumps boulders on the display.
  210.                 Reveal the boulder too or player can get confused */
  211.              if (looked && sobj_at(BOULDER, cc.x, cc.y))
  212.                  Strcat(out_str, " co-located with a boulder");
  213.              break; /* out of for loop*/
  214.          }
  215.      }
  216.  
  217.      /* if we ignored venom and list turned out to be short, put it back */
  218.      if (skipped_venom && found < 2) {
  219.          x_str = def_oc_syms[VENOM_CLASS].explain;
  220.          if (!found) {
  221.              Sprintf(out_str, "%s%s", prefix, an(x_str));
  222.              *firstmatch = x_str;
  223.              found++;
  224.          } else {
  225.              found += append_str(out_str, an(x_str));
  226.          }
  227.      }
  228.  
  229.      /* handle optional boulder symbol as a special case */
  230.      if (iflags.bouldersym && sym == iflags.bouldersym) {
  231.          if (!found) {
  232.              *firstmatch = "boulder";
  233.              Sprintf(out_str, "%s%s", prefix, an(*firstmatch));
  234.              found++;
  235.          } else {
  236.              found += append_str(out_str, "boulder");
  237.          }
  238.      }
  239.  
  240.      /*
  241.       * If we are looking at the screen, follow multiple possibilities or
  242.       * an ambiguous explanation by something more detailed.
  243.       */
  244.  
  245.      if (found > 4)
  246.          Sprintf(out_str, "%s", "That can be many things");
  247.  
  248.   didlook:
  249.      if (looked) {
  250.          if (found > 1 || need_to_look) {
  251.              char monbuf[BUFSZ];
  252.              char temp_buf[BUFSZ];
  253.  
  254.              (void) lookat(cc.x, cc.y, look_buf, monbuf);
  255.              *firstmatch = look_buf;
  256.              if (*(*firstmatch)) {
  257.                  Sprintf(temp_buf, " (%s)", *firstmatch);
  258.                  (void) strncat(out_str, temp_buf,
  259.                                 BUFSZ - strlen(out_str) - 1);
  260.                  found = 1; /* we have something to look up */
  261.              }
  262.              if (monbuf[0]) {
  263.                  Sprintf(temp_buf, " [seen: %s]", monbuf);
  264.                  (void) strncat(out_str, temp_buf,
  265.                                 BUFSZ - strlen(out_str) - 1);
  266.              }
  267.          }
  268.      }
  269.  
  270.      return found;
  271.  }
  272.  
  273.  /* also used by getpos hack in do_name.c */
  274.  const char what_is_an_unknown_object[] = "an unknown object";
  275.  

do_look

  1.  int
  2.  do_look(mode, click_cc)
  3.  int mode;
  4.  coord *click_cc;
  5.  {
  6.      boolean quick = (mode == 1); /* use cursor; don't search for "more info" */
  7.      boolean clicklook = (mode == 2); /* right mouse-click method */
  8.      char out_str[BUFSZ] = DUMMY;
  9.      const char *firstmatch = 0;
  10.      struct permonst *pm = 0;
  11.      int i = '\0', ans = 0;
  12.      int sym;              /* typed symbol or converted glyph */
  13.      int found;            /* count of matching syms found */
  14.      coord cc;             /* screen pos of unknown glyph */
  15.      boolean save_verbose; /* saved value of flags.verbose */
  16.      boolean from_screen;  /* question from the screen */
  17.  
  18.      if (!clicklook) {
  19.          if (quick) {
  20.              from_screen = TRUE; /* yes, we want to use the cursor */
  21.              i = 'y';
  22.          } else {
  23.              menu_item *pick_list = (menu_item *) 0;
  24.              winid win;
  25.              anything any;
  26.  
  27.              any = zeroany;
  28.              win = create_nhwindow(NHW_MENU);
  29.              start_menu(win);
  30.              any.a_char = '/';
  31.              /* 'y' and 'n' to keep backwards compatibility with previous
  32.                 versions: "Specify unknown object by cursor?" */
  33.              add_menu(win, NO_GLYPH, &any,
  34.                       flags.lootabc ? 0 : any.a_char, 'y', ATR_NONE,
  35.                       "something on the map", MENU_UNSELECTED);
  36.              any.a_char = 'i';
  37.              add_menu(win, NO_GLYPH, &any,
  38.                       flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
  39.                       "something you're carrying", MENU_UNSELECTED);
  40.              any.a_char = '?';
  41.              add_menu(win, NO_GLYPH, &any,
  42.                       flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE,
  43.                       "something else (by symbol or name)", MENU_UNSELECTED);
  44.              if (!u.uswallow && !Hallucination) {
  45.                  any = zeroany;
  46.                  add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
  47.                           "", MENU_UNSELECTED);
  48.                  /* these options work sensibly for the swallowed case,
  49.                     but there's no reason for the player to use them then;
  50.                     objects work fine when hallucinating, but screen
  51.                     symbol/monster class letter doesn't match up with
  52.                     bogus monster type, so suppress when hallucinating */
  53.                  any.a_char = 'm';
  54.                  add_menu(win, NO_GLYPH, &any,
  55.                           flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
  56.                           "nearby monsters", MENU_UNSELECTED);
  57.                  any.a_char = 'M';
  58.                  add_menu(win, NO_GLYPH, &any,
  59.                           flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
  60.                           "all monsters shown on map", MENU_UNSELECTED);
  61.                  any.a_char = 'o';
  62.                  add_menu(win, NO_GLYPH, &any,
  63.                           flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
  64.                           "nearby objects", MENU_UNSELECTED);
  65.                  any.a_char = 'O';
  66.                  add_menu(win, NO_GLYPH, &any,
  67.                           flags.lootabc ? 0 : any.a_char, 0, ATR_NONE,
  68.                           "all objects shown on map", MENU_UNSELECTED);
  69.              }
  70.              end_menu(win, "What do you want to look at:");
  71.              if (select_menu(win, PICK_ONE, &pick_list) > 0) {
  72.                  i = pick_list->item.a_char;
  73.                  free((genericptr_t) pick_list);
  74.              }
  75.              destroy_nhwindow(win);
  76.          }
  77.  
  78.          switch (i) {
  79.          default:
  80.          case 'q':
  81.              return 0;
  82.          case 'y':
  83.          case '/':
  84.              from_screen = TRUE;
  85.              sym = 0;
  86.              cc.x = u.ux;
  87.              cc.y = u.uy;
  88.              break;
  89.          case 'i':
  90.            {
  91.              char invlet;
  92.              struct obj *invobj;
  93.  
  94.              invlet = display_inventory((const char *) 0, TRUE);
  95.              if (!invlet || invlet == '\033')
  96.                  return 0;
  97.              *out_str = '\0';
  98.              for (invobj = invent; invobj; invobj = invobj->nobj)
  99.                  if (invobj->invlet == invlet) {
  100.                      strcpy(out_str, singular(invobj, xname));
  101.                      break;
  102.                  }
  103.              if (*out_str)
  104.                  checkfile(out_str, pm, TRUE, TRUE);
  105.              return 0;
  106.            }
  107.          case '?':
  108.              from_screen = FALSE;
  109.              getlin("Specify what? (type the word)", out_str);
  110.              if (strcmp(out_str, " ")) /* keep single space as-is */
  111.                  /* remove leading and trailing whitespace and
  112.                     condense consecutive internal whitespace */
  113.                  mungspaces(out_str);
  114.              if (out_str[0] == '\0' || out_str[0] == '\033')
  115.                  return 0;
  116.  
  117.              if (out_str[1]) { /* user typed in a complete string */
  118.                  checkfile(out_str, pm, TRUE, TRUE);
  119.                  return 0;
  120.              }
  121.              sym = out_str[0];
  122.              break;
  123.          case 'm':
  124.              look_all(TRUE, TRUE); /* list nearby monsters */
  125.              return 0;
  126.          case 'M':
  127.              look_all(FALSE, TRUE); /* list all monsters */
  128.              return 0;
  129.          case 'o':
  130.              look_all(TRUE, FALSE); /* list nearby objects */
  131.              return 0;
  132.          case 'O':
  133.              look_all(FALSE, FALSE); /* list all objects */
  134.              return 0;
  135.          }
  136.      } else { /* clicklook */
  137.          cc.x = click_cc->x;
  138.          cc.y = click_cc->y;
  139.          sym = 0;
  140.          from_screen = FALSE;
  141.      }
  142.  
  143.      /* Save the verbose flag, we change it later. */
  144.      save_verbose = flags.verbose;
  145.      flags.verbose = flags.verbose && !quick;
  146.      /*
  147.       * The user typed one letter, or we're identifying from the screen.
  148.       */
  149.      do {
  150.          /* Reset some variables. */
  151.          pm = (struct permonst *) 0;
  152.          found = 0;
  153.          out_str[0] = '\0';
  154.  
  155.          if (from_screen || clicklook) {
  156.              if (from_screen) {
  157.                  if (flags.verbose)
  158.                      pline("Please move the cursor to %s.",
  159.                            what_is_an_unknown_object);
  160.                  else
  161.                      pline("Pick an object.");
  162.  
  163.                  ans = getpos(&cc, quick, what_is_an_unknown_object);
  164.                  if (ans < 0 || cc.x < 0)
  165.                      break; /* done */
  166.                  flags.verbose = FALSE; /* only print long question once */
  167.              }
  168.          }
  169.  
  170.          found = do_screen_description(cc, (from_screen || clicklook), sym,
  171.                                        out_str, &firstmatch);
  172.  
  173.          /* Finally, print out our explanation. */
  174.          if (found) {
  175.              /* use putmixed() because there may be an encoded glyph present */
  176.              putmixed(WIN_MESSAGE, 0, out_str);
  177.  
  178.              /* check the data file for information about this thing */
  179.              if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE
  180.                  && (ans == LOOK_VERBOSE || (flags.help && !quick))
  181.                  && !clicklook) {
  182.                  char temp_buf[BUFSZ];
  183.  
  184.                  Strcpy(temp_buf, firstmatch);
  185.                  checkfile(temp_buf, pm, FALSE,
  186.                            (boolean) (ans == LOOK_VERBOSE));
  187.              }
  188.          } else {
  189.              pline("I've never heard of such things.");
  190.          }
  191.  
  192.      } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook);
  193.  
  194.      flags.verbose = save_verbose;
  195.      return 0;
  196.  }
  197.  

look_all

  1.  STATIC_OVL void
  2.  look_all(nearby, do_mons)
  3.  boolean nearby; /* True => within BOLTLIM, False => entire map */
  4.  boolean do_mons; /* True => monsters, False => objects */
  5.  {
  6.      winid win;
  7.      int x, y, lo_x, lo_y, hi_x, hi_y, glyph, count = 0;
  8.      char lookbuf[BUFSZ], outbuf[BUFSZ];
  9.  
  10.      win = create_nhwindow(NHW_TEXT);
  11.      lo_y = nearby ? max(u.uy - BOLT_LIM, 0) : 0;
  12.      lo_x = nearby ? max(u.ux - BOLT_LIM, 1) : 1;
  13.      hi_y = nearby ? min(u.uy + BOLT_LIM, ROWNO - 1) : ROWNO - 1;
  14.      hi_x = nearby ? min(u.ux + BOLT_LIM, COLNO - 1) : COLNO - 1;
  15.      for (y = lo_y; y <= hi_y; y++) {
  16.          for (x = lo_x; x <= hi_x; x++) {
  17.              lookbuf[0] = '\0';
  18.              glyph = glyph_at(x, y);
  19.              if (do_mons) {
  20.                  if (glyph_is_monster(glyph)) {
  21.                      struct monst *mtmp;
  22.  
  23.                      bhitpos.x = x; /* [is this actually necessary?] */
  24.                      bhitpos.y = y;
  25.                      if (x == u.ux && y == u.uy && canspotself()) {
  26.                          (void) self_lookat(lookbuf);
  27.                          ++count;
  28.                      } else if ((mtmp = m_at(x, y)) != 0) {
  29.                          look_at_monster(lookbuf, (char *) 0, mtmp, x, y);
  30.                          ++count;
  31.                      }
  32.                  } else if (glyph_is_invisible(glyph)) {
  33.                      /* remembered, unseen, creature */
  34.                      Strcpy(lookbuf, invisexplain);
  35.                      ++count;
  36.                  } else if (glyph_is_warning(glyph)) {
  37.                      int warnindx = glyph_to_warning(glyph);
  38.  
  39.                      Strcpy(lookbuf, def_warnsyms[warnindx].explanation);
  40.                      ++count;
  41.                  }
  42.              } else { /* !do_mons */
  43.                  if (glyph_is_object(glyph)) {
  44.                      look_at_object(lookbuf, x, y, glyph);
  45.                      ++count;
  46.                  }
  47.              }
  48.              if (*lookbuf) {
  49.                  char coordbuf[20], which[12], cmode;
  50.  
  51.                  cmode = (iflags.getpos_coords != GPCOORDS_NONE)
  52.                             ? iflags.getpos_coords : GPCOORDS_MAP;
  53.                  if (count == 1) {
  54.                      Strcpy(which, do_mons ? "monsters" : "objects");
  55.                      if (nearby)
  56.                          Sprintf(outbuf, "%s currently shown near %s:",
  57.                                  upstart(which),
  58.                                  (cmode != GPCOORDS_COMPASS)
  59.                                    ? coord_desc(u.ux, u.uy, coordbuf, cmode)
  60.                                    : !canspotself() ? "your position" : "you");
  61.                      else
  62.                          Sprintf(outbuf, "All %s currently shown on the map:",
  63.                                  which);
  64.                      putstr(win, 0, outbuf);
  65.                      putstr(win, 0, "");
  66.                  }
  67.                  /* prefix: "coords  C  " where 'C' is mon or obj symbol */
  68.                  Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s  "
  69.                                    : (cmode == GPCOORDS_MAP) ? "%8s  "
  70.                                        : "%12s  ",
  71.                          coord_desc(x, y, coordbuf, cmode));
  72.                  Sprintf(eos(outbuf), "%s  ", encglyph(glyph));
  73.                  /* guard against potential overflow */
  74.                  lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0';
  75.                  Strcat(outbuf, lookbuf);
  76.                  putmixed(win, 0, outbuf);
  77.              }
  78.          }
  79.      }
  80.      if (count)
  81.          display_nhwindow(win, TRUE);
  82.      else
  83.          pline("No %s are currently shown %s.",
  84.                do_mons ? "monsters" : "objects",
  85.                nearby ? "nearby" : "on the map");
  86.      destroy_nhwindow(win);
  87.  }
  88.  

dowhatis

  1.  /* the '/' command */
  2.  int
  3.  dowhatis()
  4.  {
  5.      return do_look(0, (coord *) 0);
  6.  }
  7.  

doquickwhatis

  1.  /* the ';' command */
  2.  int
  3.  doquickwhatis()
  4.  {
  5.      return do_look(1, (coord *) 0);
  6.  }
  7.  

doidtrap

  1.  /* the '^' command */
  2.  int
  3.  doidtrap()
  4.  {
  5.      register struct trap *trap;
  6.      int x, y, tt, glyph;
  7.  
  8.      if (!getdir("^"))
  9.          return 0;
  10.      x = u.ux + u.dx;
  11.      y = u.uy + u.dy;
  12.  
  13.      /* check fake bear trap from confused gold detection */
  14.      glyph = glyph_at(x, y);
  15.      if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
  16.          boolean chesttrap = trapped_chest_at(tt, x, y);
  17.  
  18.          if (chesttrap || trapped_door_at(tt, x, y)) {
  19.              pline("That is a trapped %s.", chesttrap ? "chest" : "door");
  20.              return 0; /* trap ID'd, but no time elapses */
  21.          }
  22.      }
  23.  
  24.      for (trap = ftrap; trap; trap = trap->ntrap)
  25.          if (trap->tx == x && trap->ty == y) {
  26.              if (!trap->tseen)
  27.                  break;
  28.              tt = trap->ttyp;
  29.              if (u.dz) {
  30.                  if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE)
  31.                               : tt == ROCKTRAP)
  32.                      break;
  33.              }
  34.              tt = what_trap(tt);
  35.              pline("That is %s%s%s.",
  36.                    an(defsyms[trap_to_defsym(tt)].explanation),
  37.                    !trap->madeby_u
  38.                       ? ""
  39.                       : (tt == WEB)
  40.                          ? " woven"
  41.                          /* trap doors & spiked pits can't be made by
  42.                             player, and should be considered at least
  43.                             as much "set" as "dug" anyway */
  44.                          : (tt == HOLE || tt == PIT)
  45.                             ? " dug"
  46.                             : " set",
  47.                    !trap->madeby_u ? "" : " by you");
  48.              return 0;
  49.          }
  50.      pline("I can't see a trap there.");
  51.      return 0;
  52.  }
  53.  

whatdoes_help

  1.  /*
  2.      Implements a rudimentary if/elif/else/endif interpretor and use
  3.      conditionals in dat/cmdhelp to describe what command each keystroke
  4.      currently invokes, so that there isn't a lot of "(debug mode only)"
  5.      and "(if number_pad is off)" cluttering the feedback that the user
  6.      sees.  (The conditionals add quite a bit of clutter to the raw data
  7.      but users don't see that.  number_pad produces a lot of conditional
  8.      commands:  basic letters vs digits, 'g' vs 'G' for '5', phone
  9.      keypad vs normal layout of digits, and QWERTZ keyboard swap between
  10.      y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
  11.      
  12.      The interpretor understands
  13.       '&#' for comment,
  14.       '&? option' for 'if' (also '&? !option'
  15.                             or '&? option=value[,value2,...]'
  16.                             or '&? !option=value[,value2,...]'),
  17.       '&: option' for 'elif' (with argument variations same as 'if';
  18.                               any number of instances for each 'if'),
  19.       '&:' for 'else' (also '&: #comment';
  20.                        0 or 1 instance for a given 'if'), and
  21.       '&.' for 'endif' (also '&. #comment'; required for each 'if').
  22.      
  23.      The option handling is a bit of a mess, with no generality for
  24.      which options to deal with and only a comma separated list of
  25.      integer values for the '=value' part.  number_pad is the only
  26.      supported option that has a value; the few others (wizard/debug,
  27.      rest_on_space, #if SHELL, #if SUSPEND) are booleans.
  28.  */
  29.  
  30.  STATIC_DCL void
  31.  whatdoes_help()
  32.  {
  33.      dlb *fp;
  34.      char *p, buf[BUFSZ];
  35.      winid tmpwin = create_nhwindow(NHW_TEXT);
  36.  
  37.      fp = dlb_fopen(KEYHELP, "r");
  38.      if (!fp) {
  39.          pline("Cannot open \"%s\" data file!", KEYHELP);
  40.          display_nhwindow(WIN_MESSAGE, TRUE);
  41.          return;
  42.      }
  43.      while (dlb_fgets(buf, (int) sizeof buf, fp)) {
  44.          if (*buf == '#')
  45.              continue;
  46.          for (p = buf; *p; p++)
  47.              if (*p != ' ' && *p != '\t')
  48.                  break;
  49.          putstr(tmpwin, 0, p);
  50.      }
  51.      (void) dlb_fclose(fp);
  52.      display_nhwindow(tmpwin, TRUE);
  53.      destroy_nhwindow(tmpwin);
  54.  }
  55.  
  56.  #if 0
  57.  #define WD_STACKLIMIT 5
  58.  struct wd_stack_frame {
  59.      Bitfield(active, 1);
  60.      Bitfield(been_true, 1);
  61.      Bitfield(else_seen, 1);
  62.  };
  63.  
  64.  STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
  65.                                           int *, int));
  66.  

whatdoes_cond

  1.  STATIC_OVL boolean
  2.  whatdoes_cond(buf, stack, depth, lnum)
  3.  char *buf;
  4.  struct wd_stack_frame *stack;
  5.  int *depth, lnum;
  6.  {
  7.      const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
  8.      boolean newcond, neg, gotopt;
  9.      char *p, *q, act = buf[1];
  10.      int np = 0;
  11.  
  12.      newcond = (act == '?' || !stack[*depth].been_true);
  13.      buf += 2;
  14.      mungspaces(buf);
  15.      if (act == '#' || *buf == '#' || !*buf || !newcond) {
  16.          gotopt = (*buf && *buf != '#');
  17.          *buf = '\0';
  18.          neg = FALSE; /* lint suppression */
  19.          p = q = (char *) 0;
  20.      } else {
  21.          gotopt = TRUE;
  22.          if ((neg = (*buf == '!')) != 0)
  23.              if (*++buf == ' ')
  24.                  ++buf;
  25.          p = index(buf, '='), q = index(buf, ':');
  26.          if (!p || (q && q < p))
  27.              p = q;
  28.          if (p) { /* we have a value specified */
  29.              /* handle a space before or after (or both) '=' (or ':') */
  30.              if (p > buf && p[-1] == ' ')
  31.                  p[-1] = '\0'; /* end of keyword in buf[] */
  32.              *p++ = '\0'; /* terminate keyword, advance to start of value */
  33.              if (*p == ' ')
  34.                  p++;
  35.          }
  36.      }
  37.      if (*buf && (act == '?' || act == ':')) {
  38.          if (!strcmpi(buf, "number_pad")) {
  39.              if (!p) {
  40.                  newcond = iflags.num_pad;
  41.              } else {
  42.                  /* convert internal encoding (separate yes/no and 0..3)
  43.                     back to user-visible one (-1..4) */
  44.                  np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
  45.                                      : (-1 * iflags.num_pad_mode); /* -1..0 */
  46.                  newcond = FALSE;
  47.                  for (; p; p = q) {
  48.                      q = index(p, ',');
  49.                      if (q)
  50.                          *q++ = '\0';
  51.                      if (atoi(p) == np) {
  52.                          newcond = TRUE;
  53.                          break;
  54.                      }
  55.                  }
  56.              }
  57.          } else if (!strcmpi(buf, "rest_on_space")) {
  58.              newcond = flags.rest_on_space;
  59.          } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
  60.              newcond = flags.debug; /* == wizard */
  61.          } else if (!strcmpi(buf, "shell")) {
  62.  #ifdef SHELL
  63.              /* should we also check sysopt.shellers? */
  64.              newcond = TRUE;
  65.  #else
  66.              newcond = FALSE;
  67.  #endif
  68.          } else if (!strcmpi(buf, "suspend")) {
  69.  #ifdef SUSPEND
  70.              /* sysopt.shellers is also used for dosuspend()... */
  71.              newcond = TRUE;
  72.  #else
  73.              newcond = FALSE;
  74.  #endif
  75.          } else {
  76.              impossible(
  77.                  "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
  78.                         act, lnum, buf);
  79.              neg = FALSE;
  80.          }
  81.          /* this works for number_pad too: &? !number_pad:-1,0
  82.             would be true for 1..4 after negation */
  83.          if (neg)
  84.              newcond = !newcond;
  85.      }
  86.      switch (act) {
  87.      default:
  88.      case '#': /* comment */
  89.          break;
  90.      case '.': /* endif */
  91.          if (--*depth < 0) {
  92.              impossible(badstackfmt, '.', lnum);
  93.              *depth = 0;
  94.          }
  95.          break;
  96.      case ':': /* else or elif */
  97.          if (*depth == 0 || stack[*depth].else_seen) {
  98.              impossible(badstackfmt, ':', lnum);
  99.              *depth = 1; /* so that stack[*depth - 1] is a valid access */
  100.          }
  101.          if (stack[*depth].active || stack[*depth].been_true
  102.              || !stack[*depth - 1].active)
  103.              stack[*depth].active = 0;
  104.          else if (newcond)
  105.              stack[*depth].active = stack[*depth].been_true = 1;
  106.          if (!gotopt)
  107.              stack[*depth].else_seen = 1;
  108.          break;
  109.      case '?': /* if */
  110.          if (++*depth >= WD_STACKLIMIT) {
  111.              impossible(badstackfmt, '?', lnum);
  112.              *depth = WD_STACKLIMIT - 1;
  113.          }
  114.          stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
  115.          stack[*depth].been_true = stack[*depth].active;
  116.          stack[*depth].else_seen = 0;
  117.          break;
  118.      }
  119.      return stack[*depth].active ? TRUE : FALSE;
  120.  }
  121.  #endif /* 0 */
  122.  

dowhatdoes_core

  1.  char *
  2.  dowhatdoes_core(q, cbuf)
  3.  char q;
  4.  char *cbuf;
  5.  {
  6.      char buf[BUFSZ];
  7.  #if 0
  8.      dlb *fp;
  9.      struct wd_stack_frame stack[WD_STACKLIMIT];
  10.      boolean cond;
  11.      int ctrl, meta, depth = 0, lnum = 0;
  12.  #endif /* 0 */
  13.      const char *ec_desc;
  14.  
  15.      if ((ec_desc = key2extcmddesc(q)) != NULL) {
  16.          char keybuf[QBUFSZ];
  17.  
  18.          Sprintf(buf, "%-8s%s.", key2txt(q, keybuf), ec_desc);
  19.          Strcpy(cbuf, buf);
  20.          return cbuf;
  21.      }
  22.      return 0;
  23.  #if 0
  24.      fp = dlb_fopen(CMDHELPFILE, "r");
  25.      if (!fp) {
  26.          pline("Cannot open \"%s\" data file!", CMDHELPFILE);
  27.          return 0;
  28.      }
  29.  
  30.      meta = (0x80 & (uchar) q) != 0;
  31.      if (meta)
  32.          q &= 0x7f;
  33.      ctrl = (0x1f & (uchar) q) == (uchar) q;
  34.      if (ctrl)
  35.          q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
  36.      else if (q == 0x7f)
  37.          ctrl = 1, q = '?';
  38.  
  39.      (void) memset((genericptr_t) stack, 0, sizeof stack);
  40.      cond = stack[0].active = 1;
  41.      while (dlb_fgets(buf, sizeof buf, fp)) {
  42.          ++lnum;
  43.          if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
  44.              cond = whatdoes_cond(buf, stack, &depth, lnum);
  45.              continue;
  46.          }
  47.          if (!cond)
  48.              continue;
  49.          if (meta ? (buf[0] == 'M' && buf[1] == '-'
  50.                      && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
  51.                               : buf[2] == q))
  52.                   : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
  53.                           : buf[0] == q)) {
  54.              (void) strip_newline(buf);
  55.              if (index(buf, '\t'))
  56.                  (void) tabexpand(buf);
  57.              if (meta && ctrl && buf[4] == ' ') {
  58.                  (void) strncpy(buf, "M-^?    ", 8);
  59.                  buf[3] = q;
  60.              } else if (meta && buf[3] == ' ') {
  61.                  (void) strncpy(buf, "M-?     ", 8);
  62.                  buf[2] = q;
  63.              } else if (ctrl && buf[2] == ' ') {
  64.                  (void) strncpy(buf, "^?      ", 8);
  65.                  buf[1] = q;
  66.              } else if (buf[1] == ' ') {
  67.                  (void) strncpy(buf, "?       ", 8);
  68.                  buf[0] = q;
  69.              }
  70.              (void) dlb_fclose(fp);
  71.              Strcpy(cbuf, buf);
  72.              return cbuf;
  73.          }
  74.      }
  75.      (void) dlb_fclose(fp);
  76.      if (depth != 0)
  77.          impossible("cmdhelp: mismatched &? &: &. conditionals.");
  78.      return (char *) 0;
  79.  #endif /* 0 */
  80.  }
  81.  

dowhatdoes

  1.  int
  2.  dowhatdoes()
  3.  {
  4.      static boolean once = FALSE;
  5.      char bufr[BUFSZ];
  6.      char q, *reslt;
  7.  
  8.      if (!once) {
  9.          pline("Ask about '&' or '?' to get more info.%s",
  10.  #ifdef ALTMETA
  11.                iflags.altmeta ? "  (For ESC, type it twice.)" :
  12.  #endif
  13.                "");
  14.          once = TRUE;
  15.      }
  16.  #if defined(UNIX) || defined(VMS)
  17.      introff(); /* disables ^C but not ^\ */
  18.  #endif
  19.      q = yn_function("What command?", (char *) 0, '\0');
  20.  #ifdef ALTMETA
  21.      if (q == '\033' && iflags.altmeta) {
  22.          /* in an ideal world, we would know whether another keystroke
  23.             was already pending, but this is not an ideal world...
  24.             if user typed ESC, we'll essentially hang until another
  25.             character is typed */
  26.          q = yn_function("]", (char *) 0, '\0');
  27.          if (q != '\033')
  28.              q = (char) ((uchar) q | 0200);
  29.      }
  30.  #endif /*ALTMETA*/
  31.  #if defined(UNIX) || defined(VMS)
  32.      intron(); /* reenables ^C */
  33.  #endif
  34.      reslt = dowhatdoes_core(q, bufr);
  35.      if (reslt) {
  36.          if (q == '&' || q == '?')
  37.              whatdoes_help();
  38.          pline("%s", reslt);
  39.      } else {
  40.          pline("No such command '%s', char code %d (0%03o or 0x%02x).",
  41.                visctrl(q), (uchar) q, (uchar) q, (uchar) q);
  42.      }
  43.      return 0;
  44.  }
  45.  

docontact

  1.  STATIC_OVL void
  2.  docontact()
  3.  {
  4.      winid cwin = create_nhwindow(NHW_TEXT);
  5.      char buf[BUFSZ];
  6.  
  7.      if (sysopt.support) {
  8.          /*XXX overflow possibilities*/
  9.          Sprintf(buf, "To contact local support, %s", sysopt.support);
  10.          putstr(cwin, 0, buf);
  11.          putstr(cwin, 0, "");
  12.      } else if (sysopt.fmtd_wizard_list) { /* formatted SYSCF WIZARDS */
  13.          Sprintf(buf, "To contact local support, contact %s.",
  14.                  sysopt.fmtd_wizard_list);
  15.          putstr(cwin, 0, buf);
  16.          putstr(cwin, 0, "");
  17.      }
  18.      putstr(cwin, 0, "To contact the NetHack development team directly,");
  19.      /*XXX overflow possibilities*/
  20.      Sprintf(buf, "see the 'Contact' form on our website or email <%s>.",
  21.              DEVTEAM_EMAIL);
  22.      putstr(cwin, 0, buf);
  23.      putstr(cwin, 0, "");
  24.      putstr(cwin, 0, "For more information on NetHack, or to report a bug,");
  25.      Sprintf(buf, "visit our website \"%s\".", DEVTEAM_URL);
  26.      putstr(cwin, 0, buf);
  27.      display_nhwindow(cwin, FALSE);
  28.      destroy_nhwindow(cwin);
  29.  }
  30.  

dispfile_help

  1.  void
  2.  dispfile_help()
  3.  {
  4.      display_file(HELP, TRUE);
  5.  }
  6.  

dispfile_shelp

  1.  void
  2.  dispfile_shelp()
  3.  {
  4.      display_file(SHELP, TRUE);
  5.  }
  6.  

dispfile_optionfile

  1.  void
  2.  dispfile_optionfile()
  3.  {
  4.      display_file(OPTIONFILE, TRUE);
  5.  }
  6.  

dispfile_license

  1.  void
  2.  dispfile_license()
  3.  {
  4.      display_file(LICENSE, TRUE);
  5.  }
  6.  

dispfile_debughelp

  1.  void
  2.  dispfile_debughelp()
  3.  {
  4.      display_file(DEBUGHELP, TRUE);
  5.  }
  6.  

hmenu_doextversion

  1.  void
  2.  hmenu_doextversion()
  3.  {
  4.      (void) doextversion();
  5.  }
  6.  

hmenu_dohistory

  1.  void
  2.  hmenu_dohistory()
  3.  {
  4.      (void) dohistory();
  5.  }
  6.  

hmenu_dowhatis

  1.  void
  2.  hmenu_dowhatis()
  3.  {
  4.      (void) dowhatis();
  5.  }
  6.  

hmenu_dowhatdoes

  1.  void
  2.  hmenu_dowhatdoes()
  3.  {
  4.      (void) dowhatdoes();
  5.  }
  6.  

hmenu_doextlist

  1.  void
  2.  hmenu_doextlist()
  3.  {
  4.      (void) doextlist();
  5.  }
  6.  

domenucontrols

  1.  void
  2.  domenucontrols()
  3.  {
  4.      winid cwin = create_nhwindow(NHW_TEXT);
  5.      show_menu_controls(cwin, FALSE);
  6.      display_nhwindow(cwin, FALSE);
  7.      destroy_nhwindow(cwin);
  8.  }
  9.  
  10.  /* data for dohelp() */
  11.  static struct {
  12.      void (*f)();
  13.      const char *text;
  14.  } help_menu_items[] = {
  15.      { hmenu_doextversion, "About NetHack (version information)." },
  16.      { dispfile_help, "Long description of the game and commands." },
  17.      { dispfile_shelp, "List of game commands." },
  18.      { hmenu_dohistory, "Concise history of NetHack." },
  19.      { hmenu_dowhatis, "Info on a character in the game display." },
  20.      { hmenu_dowhatdoes, "Info on what a given key does." },
  21.      { option_help, "List of game options." },
  22.      { dispfile_optionfile, "Longer explanation of game options." },
  23.      { dokeylist, "Full list of keyboard commands" },
  24.      { hmenu_doextlist, "List of extended commands." },
  25.      { domenucontrols, "List menu control keys" },
  26.      { dispfile_license, "The NetHack license." },
  27.      { docontact, "Support information." },
  28.  #ifdef PORT_HELP
  29.      { port_help, "%s-specific help and commands." },
  30.  #endif
  31.      { dispfile_debughelp, "List of wizard-mode commands." },
  32.      { NULL, (char *) 0 }
  33.  };
  34.  

dohelp

  1.  /* the '?' command */
  2.  int
  3.  dohelp()
  4.  {
  5.      winid tmpwin = create_nhwindow(NHW_MENU);
  6.      char helpbuf[QBUFSZ];
  7.      int i, n;
  8.      menu_item *selected;
  9.      anything any;
  10.      int sel;
  11.      char *bufptr;
  12.  
  13.      any = zeroany; /* zero all bits */
  14.      start_menu(tmpwin);
  15.  
  16.      for (i = 0; help_menu_items[i].text; i++) {
  17.          if (!wizard && help_menu_items[i].f == dispfile_debughelp)
  18.              continue;
  19.          if (help_menu_items[i].text[0] == '%') {
  20.              Sprintf(helpbuf, help_menu_items[i].text, PORT_ID);
  21.              bufptr = helpbuf;
  22.          } else {
  23.              bufptr = (char *)help_menu_items[i].text;
  24.          }
  25.          any.a_int = i + 1;
  26.          add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
  27.                   bufptr, MENU_UNSELECTED);
  28.      }
  29.      end_menu(tmpwin, "Select one item:");
  30.      n = select_menu(tmpwin, PICK_ONE, &selected);
  31.      destroy_nhwindow(tmpwin);
  32.      if (n > 0) {
  33.          sel = selected[0].item.a_int - 1;
  34.          free((genericptr_t) selected);
  35.          (void)(*help_menu_items[sel].f)();
  36.      }
  37.      return 0;
  38.  }
  39.  

dohistory

  1.  /* the 'V' command; also a choice for '?' */
  2.  int
  3.  dohistory()
  4.  {
  5.      display_file(HISTORY, TRUE);
  6.      return 0;
  7.  }
  8.  
  9.  /*pager.c*/