Source:NetHack 3.6.1/src/do name.c

From NetHackWiki
(Redirected from Source:Do name.c)
Jump to: navigation, search

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

Top of file

  1.  /* NetHack 3.6	do_name.c	$NHDT-Date: 1519420054 2018/02/23 21:07:34 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.128 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Pasi Kallinen, 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.  #include "hack.h"
  3.  
  4.  STATIC_DCL char *NDECL(nextmbuf);
  5.  STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *));
  6.  STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *));
  7.  STATIC_DCL boolean FDECL(gather_locs_interesting, (int, int, int));
  8.  STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
  9.  STATIC_DCL int FDECL(gloc_filter_floodfill_matcharea, (int, int));
  10.  STATIC_DCL void FDECL(auto_describe, (int, int));
  11.  STATIC_DCL void NDECL(do_mname);
  12.  STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *));
  13.  STATIC_DCL void FDECL(do_oname, (struct obj *));
  14.  STATIC_PTR char *FDECL(docall_xname, (struct obj *));
  15.  STATIC_DCL void NDECL(namefloorobj);
  16.  STATIC_DCL char *FDECL(bogusmon, (char *,char *));
  17.  
  18.  extern const char what_is_an_unknown_object[]; /* from pager.c */
  19.  
  20.  #define NUMMBUF 5
  21.  
  22.  /* manage a pool of BUFSZ buffers, so callers don't have to */
  23.  STATIC_OVL char *
  24.  nextmbuf()
  25.  {
  26.      static char NEARDATA bufs[NUMMBUF][BUFSZ];
  27.      static int bufidx = 0;
  28.  
  29.      bufidx = (bufidx + 1) % NUMMBUF;
  30.      return bufs[bufidx];
  31.  }
  32.  
  33.  /* function for getpos() to highlight desired map locations.
  34.   * parameter value 0 = initialize, 1 = highlight, 2 = done
  35.   */
  36.  static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0;
  37.  static boolean FDECL((*getpos_getvalid), (int, int)) =
  38.                                             (boolean FDECL((*), (int, int))) 0;
  39.  

getpos_sethilite

  1.  void
  2.  getpos_sethilite(gp_hilitef, gp_getvalidf)
  3.  void FDECL((*gp_hilitef), (int));
  4.  boolean FDECL((*gp_getvalidf), (int, int));
  5.  {
  6.      getpos_hilitefunc = gp_hilitef;
  7.      getpos_getvalid = gp_getvalidf;
  8.  }
  9.  
  10.  const char *const gloc_descr[NUM_GLOCS][4] = {
  11.      { "any monsters", "monster", "next monster", "monsters" },
  12.      { "any items", "item", "next object", "objects" },
  13.      { "any doors", "door", "next door or doorway", "doors or doorways" },
  14.      { "any unexplored areas", "unexplored area", "unexplored location",
  15.        "unexplored locations" },
  16.      { "anything interesting", "interesting thing", "anything interesting",
  17.        "anything interesting" }
  18.  };
  19.  
  20.  const char *const gloc_filtertxt[NUM_GFILTER] = {
  21.      "",
  22.      " in view",
  23.      " in this area"
  24.  };
  25.  

getpos_help_keyxhelp

  1.  void
  2.  getpos_help_keyxhelp(tmpwin, k1, k2, gloc)
  3.  winid tmpwin;
  4.  const char *k1;
  5.  const char *k2;
  6.  int gloc;
  7.  {
  8.      char sbuf[BUFSZ];
  9.  
  10.      Sprintf(sbuf, "Use '%s' or '%s' to %s%s%s.",
  11.              k1, k2,
  12.              iflags.getloc_usemenu ? "get a menu of "
  13.                                    : "move the cursor to ",
  14.              gloc_descr[gloc][2 + iflags.getloc_usemenu],
  15.              gloc_filtertxt[iflags.getloc_filter]);
  16.      putstr(tmpwin, 0, sbuf);
  17.  }
  18.  

getpos_help

  1.  /* the response for '?' help request in getpos() */
  2.  STATIC_OVL void
  3.  getpos_help(force, goal)
  4.  boolean force;
  5.  const char *goal;
  6.  {
  7.      char sbuf[BUFSZ];
  8.      boolean doing_what_is;
  9.      winid tmpwin = create_nhwindow(NHW_MENU);
  10.      const char *const fastmovemode[2] = { "8 units at a time",
  11.                                            "skipping same glyphs" };
  12.  
  13.      Sprintf(sbuf,
  14.              "Use '%c', '%c', '%c', '%c' to move the cursor to %s.", /* hjkl */
  15.              Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
  16.      putstr(tmpwin, 0, sbuf);
  17.      Sprintf(sbuf,
  18.              "Use 'H', 'J', 'K', 'L' to fast-move the cursor, %s.",
  19.              fastmovemode[iflags.getloc_moveskip]);
  20.      putstr(tmpwin, 0, sbuf);
  21.      putstr(tmpwin, 0, "Or enter a background symbol (ex. '<').");
  22.      Sprintf(sbuf, "Use '%s' to move the cursor on yourself.",
  23.             visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
  24.      putstr(tmpwin, 0, sbuf);
  25.      if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
  26.          getpos_help_keyxhelp(tmpwin,
  27.                               visctrl(Cmd.spkeys[NHKF_GETPOS_MON_NEXT]),
  28.                               visctrl(Cmd.spkeys[NHKF_GETPOS_MON_PREV]),
  29.                               GLOC_MONS);
  30.      }
  31.      if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
  32.          getpos_help_keyxhelp(tmpwin,
  33.                               visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_NEXT]),
  34.                               visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_PREV]),
  35.                               GLOC_OBJS);
  36.      }
  37.      if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
  38.          /* these are primarily useful when choosing a travel
  39.             destination for the '_' command */
  40.          getpos_help_keyxhelp(tmpwin,
  41.                               visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_NEXT]),
  42.                               visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_PREV]),
  43.                               GLOC_DOOR);
  44.          getpos_help_keyxhelp(tmpwin,
  45.                               visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_NEXT]),
  46.                               visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]),
  47.                               GLOC_EXPLORE);
  48.          getpos_help_keyxhelp(tmpwin,
  49.                               visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_NEXT]),
  50.                               visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_PREV]),
  51.                               GLOC_INTERESTING);
  52.      }
  53.      Sprintf(sbuf, "Use '%s' to change fast-move mode to %s.",
  54.              visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]),
  55.              fastmovemode[!iflags.getloc_moveskip]);
  56.      putstr(tmpwin, 0, sbuf);
  57.      if (!iflags.terrainmode || (iflags.terrainmode & TER_DETECT) == 0) {
  58.          Sprintf(sbuf, "Use '%s' to toggle menu listing for possible targets.",
  59.                  visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
  60.          putstr(tmpwin, 0, sbuf);
  61.          Sprintf(sbuf,
  62.                  "Use '%s' to change the mode of limiting possible targets.",
  63.                  visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
  64.          putstr(tmpwin, 0, sbuf);
  65.      }
  66.      if (!iflags.terrainmode) {
  67.          char kbuf[BUFSZ];
  68.  
  69.          if (getpos_getvalid) {
  70.              Sprintf(sbuf, "Use '%s' or '%s' to move to valid locations.",
  71.                      visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]),
  72.                      visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_PREV]));
  73.              putstr(tmpwin, 0, sbuf);
  74.          }
  75.          if (getpos_hilitefunc) {
  76.              Sprintf(sbuf, "Use '%s' to display valid locations.",
  77.                      visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
  78.              putstr(tmpwin, 0, sbuf);
  79.          }
  80.          Sprintf(sbuf, "Use '%s' to toggle automatic description.",
  81.                  visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
  82.          putstr(tmpwin, 0, sbuf);
  83.          if (iflags.cmdassist) { /* assisting the '/' command, I suppose... */
  84.              Sprintf(sbuf,
  85.                      (iflags.getpos_coords == GPCOORDS_NONE)
  86.           ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
  87.           : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
  88.                      visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
  89.          }
  90.          /* disgusting hack; the alternate selection characters work for any
  91.             getpos call, but only matter for dowhatis (and doquickwhatis) */
  92.  	doing_what_is = (goal == what_is_an_unknown_object);
  93.          if (doing_what_is) {
  94.              Sprintf(kbuf, "'%s' or '%s' or '%s' or '%s'",
  95.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
  96.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
  97.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
  98.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
  99.          } else {
  100.              Sprintf(kbuf, "'%s'", visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
  101.          }
  102.          Sprintf(sbuf, "Type a %s when you are at the right place.", kbuf);
  103.          putstr(tmpwin, 0, sbuf);
  104.          if (doing_what_is) {
  105.              Sprintf(sbuf,
  106.         "  '%s' describe current spot, show 'more info', move to another spot.",
  107.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
  108.              putstr(tmpwin, 0, sbuf);
  109.              Sprintf(sbuf,
  110.                      "  '%s' describe current spot,%s move to another spot;",
  111.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
  112.                      flags.help ? " prompt if 'more info'," : "");
  113.              putstr(tmpwin, 0, sbuf);
  114.              Sprintf(sbuf,
  115.                      "  '%s' describe current spot, move to another spot;",
  116.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
  117.              putstr(tmpwin, 0, sbuf);
  118.              Sprintf(sbuf,
  119.                      "  '%s' describe current spot, stop looking at things;",
  120.                      visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
  121.              putstr(tmpwin, 0, sbuf);
  122.          }
  123.      }
  124.      if (!force)
  125.          putstr(tmpwin, 0, "Type Space or Escape when you're done.");
  126.      putstr(tmpwin, 0, "");
  127.      display_nhwindow(tmpwin, TRUE);
  128.      destroy_nhwindow(tmpwin);
  129.  }
  130.  

cmp_coord_distu

  1.  STATIC_OVL int
  2.  cmp_coord_distu(a, b)
  3.  const void *a;
  4.  const void *b;
  5.  {
  6.      const coord *c1 = a;
  7.      const coord *c2 = b;
  8.      int dx, dy, dist_1, dist_2;
  9.  
  10.      dx = u.ux - c1->x;
  11.      dy = u.uy - c1->y;
  12.      dist_1 = max(abs(dx), abs(dy));
  13.      dx = u.ux - c2->x;
  14.      dy = u.uy - c2->y;
  15.      dist_2 = max(abs(dx), abs(dy));
  16.  
  17.      if (dist_1 == dist_2)
  18.          return (c1->y != c2->y) ? (c1->y - c2->y) : (c1->x - c2->x);
  19.  
  20.      return dist_1 - dist_2;
  21.  }
  22.  
  23.  #define IS_UNEXPLORED_LOC(x,y) \
  24.      (isok((x), (y))                                     \
  25.       && glyph_is_cmap(levl[(x)][(y)].glyph)             \
  26.       && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone  \
  27.       && !levl[(x)][(y)].seenv)
  28.  
  29.  static struct opvar *gloc_filter_map = (struct opvar *) 0;
  30.  
  31.  #define GLOC_SAME_AREA(x,y)                                     \
  32.      (isok((x), (y))                                             \
  33.       && (selection_getpoint((x),(y), gloc_filter_map)))
  34.  
  35.  static int gloc_filter_floodfill_match_glyph;
  36.  

gloc_filter_classify_glyph

  1.  int
  2.  gloc_filter_classify_glyph(glyph)
  3.  int glyph;
  4.  {
  5.      int c;
  6.  
  7.      if (!glyph_is_cmap(glyph))
  8.          return 0;
  9.  
  10.      c = glyph_to_cmap(glyph);
  11.  
  12.      if (is_cmap_room(c) || is_cmap_furniture(c))
  13.          return 1;
  14.      else if (is_cmap_wall(c) || c == S_tree)
  15.          return 2;
  16.      else if (is_cmap_corr(c))
  17.          return 3;
  18.      else if (is_cmap_water(c))
  19.          return 4;
  20.      else if (is_cmap_lava(c))
  21.          return 5;
  22.      return 0;
  23.  }
  24.  

gloc_filter_flood

  1.  STATIC_OVL int
  2.  gloc_filter_floodfill_matcharea(x,y)
  3.  int x,y;
  4.  {
  5.      int glyph = back_to_glyph(x, y);
  6.  
  7.      if (!levl[x][y].seenv)
  8.          return FALSE;
  9.  
  10.      if (glyph == gloc_filter_floodfill_match_glyph)
  11.          return TRUE;
  12.  
  13.      if (gloc_filter_classify_glyph(glyph)
  14.          == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph))
  15.          return TRUE;
  16.  
  17.      return FALSE;
  18.  }
  19.  

gloc_filter_floodfill

  1.  void
  2.  gloc_filter_floodfill(x, y)
  3.  int x, y;
  4.  {
  5.      gloc_filter_floodfill_match_glyph = back_to_glyph(x, y);
  6.  
  7.      set_selection_floodfillchk(gloc_filter_floodfill_matcharea);
  8.      selection_floodfill(gloc_filter_map, x, y, FALSE);
  9.  }
  10.  

gloc_filter_init

  1.  void
  2.  gloc_filter_init()
  3.  {
  4.      if (iflags.getloc_filter == GFILTER_AREA) {
  5.          if (!gloc_filter_map) {
  6.              gloc_filter_map = selection_opvar(NULL);
  7.          }
  8.          /* special case: if we're in a doorway, try to figure out which
  9.             direction we're moving, and use that side of the doorway */
  10.          if (IS_DOOR(levl[u.ux][u.uy].typ)) {
  11.              if (u.dx || u.dy) {
  12.                  gloc_filter_floodfill(u.ux + u.dx, u.uy + u.dy);
  13.              } else {
  14.                  /* TODO: maybe add both sides of the doorway? */
  15.              }
  16.          } else {
  17.              gloc_filter_floodfill(u.ux, u.uy);
  18.          }
  19.  
  20.  
  21.      }
  22.  }
  23.  

gloc_filter_done

  1.  void
  2.  gloc_filter_done()
  3.  {
  4.      if (gloc_filter_map) {
  5.          opvar_free_x(gloc_filter_map);
  6.          gloc_filter_map = NULL;
  7.      }
  8.  }
  9.  

gather_locs_interesting

  1.  STATIC_OVL boolean
  2.  gather_locs_interesting(x, y, gloc)
  3.  int x, y, gloc;
  4.  {
  5.      /* TODO: if glyph is a pile glyph, convert to ordinary one
  6.       *       in order to keep tail/boulder/rock check simple.
  7.       */
  8.      int glyph = glyph_at(x, y);
  9.  
  10.      if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x, y))
  11.          return FALSE;
  12.      if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x, y)
  13.          && !GLOC_SAME_AREA(x - 1, y) && !GLOC_SAME_AREA(x, y - 1)
  14.          && !GLOC_SAME_AREA(x + 1, y) && !GLOC_SAME_AREA(x, y + 1))
  15.          return FALSE;
  16.  
  17.      switch (gloc) {
  18.      default:
  19.      case GLOC_MONS:
  20.          /* unlike '/M', this skips monsters revealed by
  21.             warning glyphs and remembered unseen ones */
  22.          return (glyph_is_monster(glyph)
  23.                  && glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
  24.      case GLOC_OBJS:
  25.          return (glyph_is_object(glyph)
  26.                  && glyph != objnum_to_glyph(BOULDER)
  27.                  && glyph != objnum_to_glyph(ROCK));
  28.      case GLOC_DOOR:
  29.          return (glyph_is_cmap(glyph)
  30.                  && (is_cmap_door(glyph_to_cmap(glyph))
  31.                      || is_cmap_drawbridge(glyph_to_cmap(glyph))
  32.                      || glyph_to_cmap(glyph) == S_ndoor));
  33.      case GLOC_EXPLORE:
  34.          return (glyph_is_cmap(glyph)
  35.                  && (is_cmap_door(glyph_to_cmap(glyph))
  36.                      || is_cmap_drawbridge(glyph_to_cmap(glyph))
  37.                      || glyph_to_cmap(glyph) == S_ndoor
  38.                      || glyph_to_cmap(glyph) == S_room
  39.                      || glyph_to_cmap(glyph) == S_darkroom
  40.                      || glyph_to_cmap(glyph) == S_corr
  41.                      || glyph_to_cmap(glyph) == S_litcorr)
  42.                  && (IS_UNEXPLORED_LOC(x + 1, y)
  43.                      || IS_UNEXPLORED_LOC(x - 1, y)
  44.                      || IS_UNEXPLORED_LOC(x, y + 1)
  45.                      || IS_UNEXPLORED_LOC(x, y - 1)));
  46.      case GLOC_INTERESTING:
  47.          return gather_locs_interesting(x,y, GLOC_DOOR)
  48.              || !(glyph_is_cmap(glyph)
  49.                   && (is_cmap_wall(glyph_to_cmap(glyph))
  50.                       || glyph_to_cmap(glyph) == S_tree
  51.                       || glyph_to_cmap(glyph) == S_bars
  52.                       || glyph_to_cmap(glyph) == S_ice
  53.                       || glyph_to_cmap(glyph) == S_air
  54.                       || glyph_to_cmap(glyph) == S_cloud
  55.                       || glyph_to_cmap(glyph) == S_lava
  56.                       || glyph_to_cmap(glyph) == S_water
  57.                       || glyph_to_cmap(glyph) == S_pool
  58.                       || glyph_to_cmap(glyph) == S_ndoor
  59.                       || glyph_to_cmap(glyph) == S_room
  60.                       || glyph_to_cmap(glyph) == S_darkroom
  61.                       || glyph_to_cmap(glyph) == S_corr
  62.                       || glyph_to_cmap(glyph) == S_litcorr));
  63.      case GLOC_VALID:
  64.          return (getpos_getvalid && getpos_getvalid(x,y));
  65.      }
  66.      /*NOTREACHED*/
  67.      return FALSE;
  68.  }
  69.  

gather_locs

  1.  /* gather locations for monsters or objects shown on the map */
  2.  STATIC_OVL void
  3.  gather_locs(arr_p, cnt_p, gloc)
  4.  coord **arr_p;
  5.  int *cnt_p;
  6.  int gloc;
  7.  {
  8.      int x, y, pass, idx;
  9.  
  10.      /*
  11.       * We always include the hero's location even if there is no monster
  12.       * (invisible hero without see invisible) or object (usual case)
  13.       * displayed there.  That way, the count will always be at least 1,
  14.       * and player has a visual indicator (cursor returns to hero's spot)
  15.       * highlighting when successive 'm's or 'o's have cycled all the way
  16.       * through all monsters or objects.
  17.       *
  18.       * Hero's spot will always sort to array[0] because it will always
  19.       * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
  20.       */
  21.  
  22.      gloc_filter_init();
  23.  
  24.      *cnt_p = idx = 0;
  25.      for (pass = 0; pass < 2; pass++) {
  26.          for (x = 1; x < COLNO; x++)
  27.              for (y = 0; y < ROWNO; y++) {
  28.                  if ((x == u.ux && y == u.uy)
  29.                      || gather_locs_interesting(x, y, gloc)) {
  30.                      if (!pass) {
  31.                          ++*cnt_p;
  32.                      } else {
  33.                          (*arr_p)[idx].x = x;
  34.                          (*arr_p)[idx].y = y;
  35.                          ++idx;
  36.                      }
  37.                  }
  38.              }
  39.  
  40.          if (!pass) /* end of first pass */
  41.              *arr_p = (coord *) alloc(*cnt_p * sizeof (coord));
  42.          else /* end of second pass */
  43.              qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu);
  44.      } /* pass */
  45.  
  46.      gloc_filter_done();
  47.  }
  48.  

dxdy_to_dist_descr

  1.  char *
  2.  dxdy_to_dist_descr(dx, dy, fulldir)
  3.  int dx, dy;
  4.  boolean fulldir;
  5.  {
  6.      static char buf[30];
  7.      int dst;
  8.  
  9.      if (!dx && !dy) {
  10.          Sprintf(buf, "here");
  11.      } else if ((dst = xytod(dx, dy)) != -1) {
  12.          /* explicit direction; 'one step' is implicit */
  13.          Sprintf(buf, "%s", directionname(dst));
  14.      } else {
  15.          const char *dirnames[4][2] = {
  16.              { "n", "north" },
  17.              { "s", "south" },
  18.              { "w", "west" },
  19.              { "e", "east" } };
  20.          buf[0] = '\0';
  21.          /* 9999: protect buf[] against overflow caused by invalid values */
  22.          if (dy) {
  23.              if (abs(dy) > 9999)
  24.                  dy = sgn(dy) * 9999;
  25.              Sprintf(eos(buf), "%d%s%s", abs(dy), dirnames[(dy > 0)][fulldir],
  26.                      dx ? "," : "");
  27.          }
  28.          if (dx) {
  29.              if (abs(dx) > 9999)
  30.                  dx = sgn(dx) * 9999;
  31.              Sprintf(eos(buf), "%d%s", abs(dx),
  32.                      dirnames[2 + (dx > 0)][fulldir]);
  33.          }
  34.      }
  35.      return buf;
  36.  }
  37.  

coord_desc

  1.  /* coordinate formatting for 'whatis_coord' option */
  2.  char *
  3.  coord_desc(x, y, outbuf, cmode)
  4.  int x, y;
  5.  char *outbuf, cmode;
  6.  {
  7.      static char screen_fmt[16]; /* [12] suffices: "[%02d,%02d]" */
  8.      int dx, dy;
  9.  
  10.      outbuf[0] = '\0';
  11.      switch (cmode) {
  12.      default:
  13.          break;
  14.      case GPCOORDS_COMFULL:
  15.      case GPCOORDS_COMPASS:
  16.          /* "east", "3s", "2n,4w" */
  17.          dx = x - u.ux;
  18.          dy = y - u.uy;
  19.          Sprintf(outbuf, "(%s)",
  20.                  dxdy_to_dist_descr(dx, dy, cmode == GPCOORDS_COMFULL));
  21.          break;
  22.      case GPCOORDS_MAP: /* x,y */
  23.          /* upper left corner of map is <1,0>;
  24.             with default COLNO,ROWNO lower right corner is <79,20> */
  25.          Sprintf(outbuf, "<%d,%d>", x, y);
  26.          break;
  27.      case GPCOORDS_SCREEN: /* y+2,x */
  28.          /* for normal map sizes, force a fixed-width formatting so that
  29.             /m, /M, /o, and /O output lines up cleanly; map sizes bigger
  30.             than Nx999 or 999xM will still work, but not line up like normal
  31.             when displayed in a column setting */
  32.          if (!*screen_fmt)
  33.              Sprintf(screen_fmt, "[%%%sd,%%%sd]",
  34.                      (ROWNO - 1 + 2 < 100) ? "02" :  "03",
  35.                      (COLNO - 1 < 100) ? "02" : "03");
  36.          /* map line 0 is screen row 2;
  37.             map column 0 isn't used, map column 1 is screen column 1 */
  38.          Sprintf(outbuf, screen_fmt, y + 2, x);
  39.          break;
  40.      }
  41.      return outbuf;
  42.  }
  43.  

auto_describe

  1.  STATIC_OVL void
  2.  auto_describe(cx, cy)
  3.  int cx, cy;
  4.  {
  5.      coord cc;
  6.      int sym = 0;
  7.      char tmpbuf[BUFSZ];
  8.      const char *firstmatch = "unknown";
  9.  
  10.      cc.x = cx;
  11.      cc.y = cy;
  12.      if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) {
  13.          (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords);
  14.          custompline(SUPPRESS_HISTORY,
  15.                      "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf,
  16.                      (iflags.autodescribe
  17.                       && getpos_getvalid && !getpos_getvalid(cx, cy))
  18.                        ? " (illegal)" : "",
  19.                      (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy))
  20.                        ? " (no travel path)" : "");
  21.          curs(WIN_MAP, cx, cy);
  22.          flush_screen(0);
  23.      }
  24.  }
  25.  

getpos_menu

  1.  boolean
  2.  getpos_menu(ccp, gloc)
  3.  coord *ccp;
  4.  int gloc;
  5.  {
  6.      coord *garr = DUMMY;
  7.      int gcount = 0;
  8.      winid tmpwin;
  9.      anything any;
  10.      int i, pick_cnt;
  11.      menu_item *picks = (menu_item *) 0;
  12.      char tmpbuf[BUFSZ];
  13.  
  14.      gather_locs(&garr, &gcount, gloc);
  15.  
  16.      if (gcount < 2) { /* gcount always includes the hero */
  17.          free((genericptr_t) garr);
  18.          You("cannot %s %s.",
  19.              iflags.getloc_filter == GFILTER_VIEW ? "see" : "detect",
  20.              gloc_descr[gloc][0]);
  21.          return FALSE;
  22.      }
  23.  
  24.      tmpwin = create_nhwindow(NHW_MENU);
  25.      start_menu(tmpwin);
  26.      any = zeroany;
  27.  
  28.      /* gather_locs returns array[0] == you. skip it. */
  29.      for (i = 1; i < gcount; i++) {
  30.          char fullbuf[BUFSZ];
  31.          coord tmpcc;
  32.          const char *firstmatch = "unknown";
  33.          int sym = 0;
  34.          any.a_int = i + 1;
  35.          tmpcc.x = garr[i].x;
  36.          tmpcc.y = garr[i].y;
  37.          if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) {
  38.              (void) coord_desc(garr[i].x, garr[i].y, tmpbuf,
  39.                                iflags.getpos_coords);
  40.              Sprintf(fullbuf, "%s%s%s", firstmatch,
  41.                      (*tmpbuf ? " " : ""), tmpbuf);
  42.              add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf,
  43.                       MENU_UNSELECTED);
  44.          }
  45.      }
  46.  
  47.      Sprintf(tmpbuf, "Pick a target %s%s%s",
  48.              gloc_descr[gloc][1],
  49.              gloc_filtertxt[iflags.getloc_filter],
  50.              iflags.getloc_travelmode ? " for travel" : "");
  51.      end_menu(tmpwin, tmpbuf);
  52.      pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
  53.      destroy_nhwindow(tmpwin);
  54.      if (pick_cnt > 0) {
  55.          ccp->x = garr[picks->item.a_int - 1].x;
  56.          ccp->y = garr[picks->item.a_int - 1].y;
  57.          free((genericptr_t) picks);
  58.      }
  59.      free((genericptr_t) garr);
  60.      return (pick_cnt > 0);
  61.  }
  62.  

getpos

  1.  int
  2.  getpos(ccp, force, goal)
  3.  coord *ccp;
  4.  boolean force;
  5.  const char *goal;
  6.  {
  7.      const char *cp;
  8.      struct {
  9.          int nhkf, ret;
  10.      } const pick_chars_def[] = {
  11.          { NHKF_GETPOS_PICK, LOOK_TRADITIONAL },
  12.          { NHKF_GETPOS_PICK_Q, LOOK_QUICK },
  13.          { NHKF_GETPOS_PICK_O, LOOK_ONCE },
  14.          { NHKF_GETPOS_PICK_V, LOOK_VERBOSE }
  15.      };
  16.      const int mMoOdDxX_def[] = {
  17.          NHKF_GETPOS_MON_NEXT,
  18.          NHKF_GETPOS_MON_PREV,
  19.          NHKF_GETPOS_OBJ_NEXT,
  20.          NHKF_GETPOS_OBJ_PREV,
  21.          NHKF_GETPOS_DOOR_NEXT,
  22.          NHKF_GETPOS_DOOR_PREV,
  23.          NHKF_GETPOS_UNEX_NEXT,
  24.          NHKF_GETPOS_UNEX_PREV,
  25.          NHKF_GETPOS_INTERESTING_NEXT,
  26.          NHKF_GETPOS_INTERESTING_PREV,
  27.          NHKF_GETPOS_VALID_NEXT,
  28.          NHKF_GETPOS_VALID_PREV
  29.      };
  30.      char pick_chars[6];
  31.      char mMoOdDxX[13];
  32.      int result = 0;
  33.      int cx, cy, i, c;
  34.      int sidx, tx, ty;
  35.      boolean msg_given = TRUE; /* clear message window by default */
  36.      boolean show_goal_msg = FALSE;
  37.      boolean hilite_state = FALSE;
  38.      coord *garr[NUM_GLOCS] = DUMMY;
  39.      int gcount[NUM_GLOCS] = DUMMY;
  40.      int gidx[NUM_GLOCS] = DUMMY;
  41.  
  42.      for (i = 0; i < SIZE(pick_chars_def); i++)
  43.          pick_chars[i] = Cmd.spkeys[pick_chars_def[i].nhkf];
  44.      pick_chars[SIZE(pick_chars_def)] = '\0';
  45.  
  46.      for (i = 0; i < SIZE(mMoOdDxX_def); i++)
  47.          mMoOdDxX[i] = Cmd.spkeys[mMoOdDxX_def[i]];
  48.      mMoOdDxX[SIZE(mMoOdDxX_def)] = '\0';
  49.  
  50.      if (!goal)
  51.          goal = "desired location";
  52.      if (flags.verbose) {
  53.          pline("(For instructions type a '%s')",
  54.                visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
  55.          msg_given = TRUE;
  56.      }
  57.      cx = ccp->x;
  58.      cy = ccp->y;
  59.  #ifdef CLIPPING
  60.      cliparound(cx, cy);
  61.  #endif
  62.      curs(WIN_MAP, cx, cy);
  63.      flush_screen(0);
  64.  #ifdef MAC
  65.      lock_mouse_cursor(TRUE);
  66.  #endif
  67.      for (;;) {
  68.          if (show_goal_msg) {
  69.              pline("Move cursor to %s:", goal);
  70.              curs(WIN_MAP, cx, cy);
  71.              flush_screen(0);
  72.              show_goal_msg = FALSE;
  73.          } else if (iflags.autodescribe && !msg_given && !hilite_state) {
  74.              auto_describe(cx, cy);
  75.          }
  76.  
  77.          c = nh_poskey(&tx, &ty, &sidx);
  78.  
  79.          if (hilite_state) {
  80.              (*getpos_hilitefunc)(2);
  81.              hilite_state = FALSE;
  82.              curs(WIN_MAP, cx, cy);
  83.              flush_screen(0);
  84.          }
  85.  
  86.          if (iflags.autodescribe)
  87.              msg_given = FALSE;
  88.  
  89.          if (c == Cmd.spkeys[NHKF_ESC]) {
  90.              cx = cy = -10;
  91.              msg_given = TRUE; /* force clear */
  92.              result = -1;
  93.              break;
  94.          }
  95.          if (c == 0) {
  96.              if (!isok(tx, ty))
  97.                  continue;
  98.              /* a mouse click event, just assign and return */
  99.              cx = tx;
  100.              cy = ty;
  101.              break;
  102.          }
  103.          if ((cp = index(pick_chars, c)) != 0) {
  104.              /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
  105.              result = pick_chars_def[(int) (cp - pick_chars)].ret;
  106.              break;
  107.          }
  108.          for (i = 0; i < 8; i++) {
  109.              int dx, dy;
  110.  
  111.              if (Cmd.dirchars[i] == c) {
  112.                  /* a normal movement letter or digit */
  113.                  dx = xdir[i];
  114.                  dy = ydir[i];
  115.              } else if (Cmd.alphadirchars[i] == lowc((char) c)
  116.                         || (Cmd.num_pad && Cmd.dirchars[i] == (c & 0177))) {
  117.                  /* a shifted movement letter or Meta-digit */
  118.                  if (iflags.getloc_moveskip) {
  119.                      /* skip same glyphs */
  120.                      int glyph = glyph_at(cx, cy);
  121.  
  122.                      dx = xdir[i];
  123.                      dy = ydir[i];
  124.                      while (isok(cx + dx, cy + dy)
  125.                             && glyph == glyph_at(cx + dx, cy + dy)
  126.                             && isok(cx + dx + xdir[i], cy + dy + ydir[i])
  127.                             && glyph == glyph_at(cx + dx + xdir[i],
  128.                                                  cy + dy + ydir[i])) {
  129.                          dx += xdir[i];
  130.                          dy += ydir[i];
  131.                      }
  132.                  } else {
  133.                      dx = 8 * xdir[i];
  134.                      dy = 8 * ydir[i];
  135.                  }
  136.              } else
  137.                  continue;
  138.  
  139.              /* truncate at map edge; diagonal moves complicate this... */
  140.              if (cx + dx < 1) {
  141.                  dy -= sgn(dy) * (1 - (cx + dx));
  142.                  dx = 1 - cx; /* so that (cx+dx == 1) */
  143.              } else if (cx + dx > COLNO - 1) {
  144.                  dy += sgn(dy) * ((COLNO - 1) - (cx + dx));
  145.                  dx = (COLNO - 1) - cx;
  146.              }
  147.              if (cy + dy < 0) {
  148.                  dx -= sgn(dx) * (0 - (cy + dy));
  149.                  dy = 0 - cy; /* so that (cy+dy == 0) */
  150.              } else if (cy + dy > ROWNO - 1) {
  151.                  dx += sgn(dx) * ((ROWNO - 1) - (cy + dy));
  152.                  dy = (ROWNO - 1) - cy;
  153.              }
  154.              cx += dx;
  155.              cy += dy;
  156.              goto nxtc;
  157.          }
  158.  
  159.          if (c == Cmd.spkeys[NHKF_GETPOS_HELP] || redraw_cmd(c)) {
  160.              if (c == Cmd.spkeys[NHKF_GETPOS_HELP])
  161.                  getpos_help(force, goal);
  162.              else /* ^R */
  163.                  docrt(); /* redraw */
  164.              /* update message window to reflect that we're still targetting */
  165.              show_goal_msg = TRUE;
  166.              msg_given = TRUE;
  167.          } else if (c == Cmd.spkeys[NHKF_GETPOS_SHOWVALID]
  168.                     && getpos_hilitefunc) {
  169.              if (!hilite_state) {
  170.                  (*getpos_hilitefunc)(0);
  171.                  (*getpos_hilitefunc)(1);
  172.                  hilite_state = TRUE;
  173.              }
  174.              goto nxtc;
  175.          } else if (c == Cmd.spkeys[NHKF_GETPOS_AUTODESC]) {
  176.              iflags.autodescribe = !iflags.autodescribe;
  177.              pline("Automatic description %sis %s.",
  178.                    flags.verbose ? "of features under cursor " : "",
  179.                    iflags.autodescribe ? "on" : "off");
  180.              if (!iflags.autodescribe)
  181.                  show_goal_msg = TRUE;
  182.              msg_given = TRUE;
  183.              goto nxtc;
  184.          } else if (c == Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]) {
  185.              const char *const view_filters[NUM_GFILTER] = {
  186.                  "Not limiting targets",
  187.                  "Limiting targets to in sight",
  188.                  "Limiting targets to in same area"
  189.              };
  190.              iflags.getloc_filter = (iflags.getloc_filter + 1) % NUM_GFILTER;
  191.              for (i = 0; i < NUM_GLOCS; i++) {
  192.                  if (garr[i]) {
  193.                      free((genericptr_t) garr[i]);
  194.                      garr[i] = NULL;
  195.                  }
  196.                  gidx[i] = gcount[i] = 0;
  197.              }
  198.              pline("%s.", view_filters[iflags.getloc_filter]);
  199.              msg_given = TRUE;
  200.              goto nxtc;
  201.          } else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]) {
  202.              iflags.getloc_usemenu = !iflags.getloc_usemenu;
  203.              pline("%s a menu to show possible targets.",
  204.                    iflags.getloc_usemenu ? "Using" : "Not using");
  205.              msg_given = TRUE;
  206.              goto nxtc;
  207.          } else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
  208.              /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
  209.                 to achieve that except by manually cycling through all spots */
  210.              for (i = 0; i < NUM_GLOCS; i++)
  211.                  gidx[i] = 0;
  212.              cx = u.ux;
  213.              cy = u.uy;
  214.              goto nxtc;
  215.          } else if (c == Cmd.spkeys[NHKF_GETPOS_MOVESKIP]) {
  216.              iflags.getloc_moveskip = !iflags.getloc_moveskip;
  217.              pline("%skipping over similar terrain when fastmoving the cursor.",
  218.                    iflags.getloc_moveskip ? "S" : "Not s");
  219.          } else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */
  220.              /* nearest or farthest monster or object or door or unexplored */
  221.              int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */
  222.                  gloc = gtmp >> 1;             /* 0..3 */
  223.  
  224.              if (iflags.getloc_usemenu) {
  225.                  coord tmpcrd;
  226.                  if (getpos_menu(&tmpcrd, gloc)) {
  227.                      cx = tmpcrd.x;
  228.                      cy = tmpcrd.y;
  229.                  }
  230.                  goto nxtc;
  231.              }
  232.  
  233.              if (!garr[gloc]) {
  234.                  gather_locs(&garr[gloc], &gcount[gloc], gloc);
  235.                  gidx[gloc] = 0; /* garr[][0] is hero's spot */
  236.              }
  237.              if (!(gtmp & 1)) {  /* c=='m' || c=='o' || c=='d' || c=='x') */
  238.                  gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc];
  239.              } else {            /* c=='M' || c=='O' || c=='D' || c=='X') */
  240.                  if (--gidx[gloc] < 0)
  241.                      gidx[gloc] = gcount[gloc] - 1;
  242.              }
  243.              cx = garr[gloc][gidx[gloc]].x;
  244.              cy = garr[gloc][gidx[gloc]].y;
  245.              goto nxtc;
  246.          } else {
  247.              if (!index(quitchars, c)) {
  248.                  char matching[MAXPCHARS];
  249.                  int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
  250.  
  251.                  (void) memset((genericptr_t) matching, 0, sizeof matching);
  252.                  for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */
  253.                      if (IS_DOOR(sidx) || IS_WALL(sidx)
  254.                          || sidx == SDOOR || sidx == SCORR
  255.                          || glyph_to_cmap(k) == S_room
  256.                          || glyph_to_cmap(k) == S_darkroom
  257.                          || glyph_to_cmap(k) == S_corr
  258.                          || glyph_to_cmap(k) == S_litcorr)
  259.                          continue;
  260.                      if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
  261.                          matching[sidx] = (char) ++k;
  262.                  }
  263.                  if (k) {
  264.                      for (pass = 0; pass <= 1; pass++) {
  265.                          /* pass 0: just past current pos to lower right;
  266.                             pass 1: upper left corner to current pos */
  267.                          lo_y = (pass == 0) ? cy : 0;
  268.                          hi_y = (pass == 0) ? ROWNO - 1 : cy;
  269.                          for (ty = lo_y; ty <= hi_y; ty++) {
  270.                              lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
  271.                              hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
  272.                              for (tx = lo_x; tx <= hi_x; tx++) {
  273.                                  /* first, look at what is currently visible
  274.                                     (might be monster) */
  275.                                  k = glyph_at(tx, ty);
  276.                                  if (glyph_is_cmap(k)
  277.                                      && matching[glyph_to_cmap(k)])
  278.                                      goto foundc;
  279.                                  /* next, try glyph that's remembered here
  280.                                     (might be trap or object) */
  281.                                  if (level.flags.hero_memory
  282.                                      /* !terrainmode: don't move to remembered
  283.                                         trap or object if not currently shown */
  284.                                      && !iflags.terrainmode) {
  285.                                      k = levl[tx][ty].glyph;
  286.                                      if (glyph_is_cmap(k)
  287.                                          && matching[glyph_to_cmap(k)])
  288.                                          goto foundc;
  289.                                  }
  290.                                  /* last, try actual terrain here (shouldn't
  291.                                     we be using lastseentyp[][] instead?) */
  292.                                  if (levl[tx][ty].seenv) {
  293.                                      k = back_to_glyph(tx, ty);
  294.                                      if (glyph_is_cmap(k)
  295.                                          && matching[glyph_to_cmap(k)])
  296.                                          goto foundc;
  297.                                  }
  298.                                  continue;
  299.                              foundc:
  300.                                  cx = tx, cy = ty;
  301.                                  if (msg_given) {
  302.                                      clear_nhwindow(WIN_MESSAGE);
  303.                                      msg_given = FALSE;
  304.                                  }
  305.                                  goto nxtc;
  306.                              } /* column */
  307.                          }     /* row */
  308.                      }         /* pass */
  309.                      pline("Can't find dungeon feature '%c'.", c);
  310.                      msg_given = TRUE;
  311.                      goto nxtc;
  312.                  } else {
  313.                      char note[QBUFSZ];
  314.  
  315.                      if (!force)
  316.                          Strcpy(note, "aborted");
  317.                      else /* hjkl */
  318.                          Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'",
  319.                                  Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E,
  320.                                  visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
  321.                      pline("Unknown direction: '%s' (%s).", visctrl((char) c),
  322.                            note);
  323.                      msg_given = TRUE;
  324.                  } /* k => matching */
  325.              }     /* !quitchars */
  326.              if (force)
  327.                  goto nxtc;
  328.              pline("Done.");
  329.              msg_given = FALSE; /* suppress clear */
  330.              cx = -1;
  331.              cy = 0;
  332.              result = 0; /* not -1 */
  333.              break;
  334.          }
  335.      nxtc:
  336.          ;
  337.  #ifdef CLIPPING
  338.          cliparound(cx, cy);
  339.  #endif
  340.          curs(WIN_MAP, cx, cy);
  341.          flush_screen(0);
  342.      }
  343.  #ifdef MAC
  344.      lock_mouse_cursor(FALSE);
  345.  #endif
  346.      if (msg_given)
  347.          clear_nhwindow(WIN_MESSAGE);
  348.      ccp->x = cx;
  349.      ccp->y = cy;
  350.      for (i = 0; i < NUM_GLOCS; i++)
  351.          if (garr[i])
  352.              free((genericptr_t) garr[i]);
  353.      getpos_hilitefunc = (void FDECL((*), (int))) 0;
  354.      getpos_getvalid = (boolean FDECL((*), (int, int))) 0;
  355.      return result;
  356.  }
  357.  

new_mname

  1.  /* allocate space for a monster's name; removes old name if there is one */
  2.  void
  3.  new_mname(mon, lth)
  4.  struct monst *mon;
  5.  int lth; /* desired length (caller handles adding 1 for terminator) */
  6.  {
  7.      if (lth) {
  8.          /* allocate mextra if necessary; otherwise get rid of old name */
  9.          if (!mon->mextra)
  10.              mon->mextra = newmextra();
  11.          else
  12.              free_mname(mon); /* already has mextra, might also have name */
  13.          MNAME(mon) = (char *) alloc((unsigned) lth);
  14.      } else {
  15.          /* zero length: the new name is empty; get rid of the old name */
  16.          if (has_mname(mon))
  17.              free_mname(mon);
  18.      }
  19.  }
  20.  

free_mname

  1.  /* release a monster's name; retains mextra even if all fields are now null */
  2.  void
  3.  free_mname(mon)
  4.  struct monst *mon;
  5.  {
  6.      if (has_mname(mon)) {
  7.          free((genericptr_t) MNAME(mon));
  8.          MNAME(mon) = (char *) 0;
  9.      }
  10.  }
  11.  

new_oname

  1.  /* allocate space for an object's name; removes old name if there is one */
  2.  void
  3.  new_oname(obj, lth)
  4.  struct obj *obj;
  5.  int lth; /* desired length (caller handles adding 1 for terminator) */
  6.  {
  7.      if (lth) {
  8.          /* allocate oextra if necessary; otherwise get rid of old name */
  9.          if (!obj->oextra)
  10.              obj->oextra = newoextra();
  11.          else
  12.              free_oname(obj); /* already has oextra, might also have name */
  13.          ONAME(obj) = (char *) alloc((unsigned) lth);
  14.      } else {
  15.          /* zero length: the new name is empty; get rid of the old name */
  16.          if (has_oname(obj))
  17.              free_oname(obj);
  18.      }
  19.  }
  20.  

free_oname

  1.  /* release an object's name; retains oextra even if all fields are now null */
  2.  void
  3.  free_oname(obj)
  4.  struct obj *obj;
  5.  {
  6.      if (has_oname(obj)) {
  7.          free((genericptr_t) ONAME(obj));
  8.          ONAME(obj) = (char *) 0;
  9.      }
  10.  }
  11.  

safe_oname

  1.  /*  safe_oname() always returns a valid pointer to
  2.   *  a string, either the pointer to an object's name
  3.   *  if it has one, or a pointer to an empty string
  4.   *  if it doesn't.
  5.   */
  6.  const char *
  7.  safe_oname(obj)
  8.  struct obj *obj;
  9.  {
  10.      if (has_oname(obj))
  11.          return ONAME(obj);
  12.      return "";
  13.  }
  14.  

christen_monst

  1.  /* historical note: this returns a monster pointer because it used to
  2.     allocate a new bigger block of memory to hold the monster and its name */
  3.  struct monst *
  4.  christen_monst(mtmp, name)
  5.  struct monst *mtmp;
  6.  const char *name;
  7.  {
  8.      int lth;
  9.      char buf[PL_PSIZ];
  10.  
  11.      /* dogname & catname are PL_PSIZ arrays; object names have same limit */
  12.      lth = (name && *name) ? ((int) strlen(name) + 1) : 0;
  13.      if (lth > PL_PSIZ) {
  14.          lth = PL_PSIZ;
  15.          name = strncpy(buf, name, PL_PSIZ - 1);
  16.          buf[PL_PSIZ - 1] = '\0';
  17.      }
  18.      new_mname(mtmp, lth); /* removes old name if one is present */
  19.      if (lth)
  20.          Strcpy(MNAME(mtmp), name);
  21.      return mtmp;
  22.  }
  23.  

alreadynamed

  1.  /* check whether user-supplied name matches or nearly matches an unnameable
  2.     monster's name; if so, give an alternate reject message for do_mname() */
  3.  STATIC_OVL boolean
  4.  alreadynamed(mtmp, monnambuf, usrbuf)
  5.  struct monst *mtmp;
  6.  char *monnambuf, *usrbuf;
  7.  {
  8.      char pronounbuf[10], *p;
  9.  
  10.      if (fuzzymatch(usrbuf, monnambuf, " -_", TRUE)
  11.          /* catch trying to name "the Oracle" as "Oracle" */
  12.          || (!strncmpi(monnambuf, "the ", 4)
  13.              && fuzzymatch(usrbuf, monnambuf + 4, " -_", TRUE))
  14.          /* catch trying to name "invisible Orcus" as "Orcus" */
  15.          || ((p = strstri(monnambuf, "invisible ")) != 0
  16.              && fuzzymatch(usrbuf, p + 10, " -_", TRUE))
  17.          /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
  18.          || ((p = strstri(monnambuf, " of ")) != 0
  19.              && fuzzymatch(usrbuf, p + 4, " -_", TRUE))) {
  20.          pline("%s is already called %s.",
  21.                upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
  22.          return TRUE;
  23.      } else if (mtmp->data == &mons[PM_JUIBLEX]
  24.                 && strstri(monnambuf, "Juiblex")
  25.                 && !strcmpi(usrbuf, "Jubilex")) {
  26.          pline("%s doesn't like being called %s.", upstart(monnambuf), usrbuf);
  27.          return TRUE;
  28.      }
  29.      return FALSE;
  30.  }
  31.  

do_mname

  1.  /* allow player to assign a name to some chosen monster */
  2.  STATIC_OVL void
  3.  do_mname()
  4.  {
  5.      char buf[BUFSZ] = DUMMY, monnambuf[BUFSZ], qbuf[QBUFSZ];
  6.      coord cc;
  7.      int cx, cy;
  8.      struct monst *mtmp = 0;
  9.  
  10.      if (Hallucination) {
  11.          You("would never recognize it anyway.");
  12.          return;
  13.      }
  14.      cc.x = u.ux;
  15.      cc.y = u.uy;
  16.      if (getpos(&cc, FALSE, "the monster you want to name") < 0
  17.          || (cx = cc.x) < 0)
  18.          return;
  19.      cy = cc.y;
  20.  
  21.      if (cx == u.ux && cy == u.uy) {
  22.          if (u.usteed && canspotmon(u.usteed)) {
  23.              mtmp = u.usteed;
  24.          } else {
  25.              pline("This %s creature is called %s and cannot be renamed.",
  26.                    beautiful(), plname);
  27.              return;
  28.          }
  29.      } else
  30.          mtmp = m_at(cx, cy);
  31.  
  32.      if (!mtmp
  33.          || (!sensemon(mtmp)
  34.              && (!(cansee(cx, cy) || see_with_infrared(mtmp))
  35.                  || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE
  36.                  || mtmp->m_ap_type == M_AP_OBJECT
  37.                  || (mtmp->minvis && !See_invisible)))) {
  38.          pline("I see no monster there.");
  39.          return;
  40.      }
  41.      /* special case similar to the one in lookat() */
  42.      Sprintf(qbuf, "What do you want to call %s?",
  43.              distant_monnam(mtmp, ARTICLE_THE, monnambuf));
  44.      getlin(qbuf, buf);
  45.      if (!*buf || *buf == '\033')
  46.          return;
  47.      /* strip leading and trailing spaces; unnames monster if all spaces */
  48.      (void) mungspaces(buf);
  49.  
  50.      /* Unique monsters have their own specific names or titles.
  51.       * Shopkeepers, temple priests and other minions use alternate
  52.       * name formatting routines which ignore any user-supplied name.
  53.       *
  54.       * Don't say the name is being rejected if it happens to match
  55.       * the existing name.
  56.       */
  57.      if ((mtmp->data->geno & G_UNIQ) && !mtmp->ispriest) {
  58.          if (!alreadynamed(mtmp, monnambuf, buf))
  59.              pline("%s doesn't like being called names!", upstart(monnambuf));
  60.      } else if (mtmp->isshk
  61.                 && !(Deaf || mtmp->msleeping || !mtmp->mcanmove
  62.                      || mtmp->data->msound <= MS_ANIMAL)) {
  63.          if (!alreadynamed(mtmp, monnambuf, buf))
  64.              verbalize("I'm %s, not %s.", shkname(mtmp), buf);
  65.      } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) {
  66.          if (!alreadynamed(mtmp, monnambuf, buf))
  67.              pline("%s will not accept the name %s.", upstart(monnambuf), buf);
  68.      } else
  69.          (void) christen_monst(mtmp, buf);
  70.  }
  71.  
  72.  STATIC_VAR int via_naming = 0;
  73.  

do_oname

  1.  /*
  2.   * This routine used to change the address of 'obj' so be unsafe if not
  3.   * used with extreme care.  Applying a name to an object no longer
  4.   * allocates a replacement object, so that old risk is gone.
  5.   */
  6.  STATIC_OVL
  7.  void
  8.  do_oname(obj)
  9.  register struct obj *obj;
  10.  {
  11.      char *bufp, buf[BUFSZ] = DUMMY, bufcpy[BUFSZ], qbuf[QBUFSZ];
  12.      const char *aname;
  13.      short objtyp;
  14.  
  15.      /* Do this now because there's no point in even asking for a name */
  16.      if (obj->otyp == SPE_NOVEL) {
  17.          pline("%s already has a published name.", Ysimple_name2(obj));
  18.          return;
  19.      }
  20.  
  21.      Sprintf(qbuf, "What do you want to name %s ",
  22.              is_plural(obj) ? "these" : "this");
  23.      (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item");
  24.      getlin(qbuf, buf);
  25.      if (!*buf || *buf == '\033')
  26.          return;
  27.      /* strip leading and trailing spaces; unnames item if all spaces */
  28.      (void) mungspaces(buf);
  29.  
  30.      /*
  31.       * We don't violate illiteracy conduct here, although it is
  32.       * arguable that we should for anything other than "X".  Doing so
  33.       * would make attaching player's notes to hero's inventory have an
  34.       * in-game effect, which may or may not be the correct thing to do.
  35.       *
  36.       * We do violate illiteracy in oname() if player creates Sting or
  37.       * Orcrist, clearly being literate (no pun intended...).
  38.       */
  39.  
  40.      /* relax restrictions over proper capitalization for artifacts */
  41.      if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
  42.          Strcpy(buf, aname);
  43.  
  44.      if (obj->oartifact) {
  45.          pline_The("artifact seems to resist the attempt.");
  46.          return;
  47.      } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
  48.          /* this used to change one letter, substituting a value
  49.             of 'a' through 'y' (due to an off by one error, 'z'
  50.             would never be selected) and then force that to
  51.             upper case if such was the case of the input;
  52.             now, the hand slip scuffs one or two letters as if
  53.             the text had been trodden upon, sometimes picking
  54.             punctuation instead of an arbitrary letter;
  55.             unfortunately, we have to cover the possibility of
  56.             it targetting spaces so failing to make any change
  57.             (we know that it must eventually target a nonspace
  58.             because buf[] matches a valid artifact name) */
  59.          Strcpy(bufcpy, buf);
  60.          /* for "the Foo of Bar", only scuff "Foo of Bar" part */
  61.          bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf;
  62.          do {
  63.              wipeout_text(bufp, rnd(2), (unsigned) 0);
  64.          } while (!strcmp(buf, bufcpy));
  65.          pline("While engraving, your %s slips.", body_part(HAND));
  66.          display_nhwindow(WIN_MESSAGE, FALSE);
  67.          You("engrave: \"%s\".", buf);
  68.          /* violate illiteracy conduct since hero attempted to write
  69.             a valid artifact name */
  70.          u.uconduct.literate++;
  71.      }
  72.      ++via_naming; /* This ought to be an argument rather than a static... */
  73.      obj = oname(obj, buf);
  74.      --via_naming; /* ...but oname() is used in a lot of places, so defer. */
  75.  }
  76.  

oname

  1.  struct obj *
  2.  oname(obj, name)
  3.  struct obj *obj;
  4.  const char *name;
  5.  {
  6.      int lth;
  7.      char buf[PL_PSIZ];
  8.  
  9.      lth = *name ? (int) (strlen(name) + 1) : 0;
  10.      if (lth > PL_PSIZ) {
  11.          lth = PL_PSIZ;
  12.          name = strncpy(buf, name, PL_PSIZ - 1);
  13.          buf[PL_PSIZ - 1] = '\0';
  14.      }
  15.      /* If named artifact exists in the game, do not create another.
  16.       * Also trying to create an artifact shouldn't de-artifact
  17.       * it (e.g. Excalibur from prayer). In this case the object
  18.       * will retain its current name. */
  19.      if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
  20.          return obj;
  21.  
  22.      new_oname(obj, lth); /* removes old name if one is present */
  23.      if (lth)
  24.          Strcpy(ONAME(obj), name);
  25.  
  26.      if (lth)
  27.          artifact_exists(obj, name, TRUE);
  28.      if (obj->oartifact) {
  29.          /* can't dual-wield with artifact as secondary weapon */
  30.          if (obj == uswapwep)
  31.              untwoweapon();
  32.          /* activate warning if you've just named your weapon "Sting" */
  33.          if (obj == uwep)
  34.              set_artifact_intrinsic(obj, TRUE, W_WEP);
  35.          /* if obj is owned by a shop, increase your bill */
  36.          if (obj->unpaid)
  37.              alter_cost(obj, 0L);
  38.          if (via_naming) {
  39.              /* violate illiteracy conduct since successfully wrote arti-name */
  40.              u.uconduct.literate++;
  41.          }
  42.      }
  43.      if (carried(obj))
  44.          update_inventory();
  45.      return obj;
  46.  }
  47.  
  48.  static NEARDATA const char callable[] = {
  49.      SCROLL_CLASS, POTION_CLASS, WAND_CLASS,  RING_CLASS, AMULET_CLASS,
  50.      GEM_CLASS,    SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0
  51.  };
  52.  

objtyp_is_callable

  1.  boolean
  2.  objtyp_is_callable(i)
  3.  int i;
  4.  {
  5.      return (boolean) (objects[i].oc_uname
  6.                        || (OBJ_DESCR(objects[i])
  7.                            && index(callable, objects[i].oc_class)));
  8.  }
  9.  

docallcmd

  1.  /* C and #name commands - player can name monster or object or type of obj */
  2.  int
  3.  docallcmd()
  4.  {
  5.      struct obj *obj;
  6.      winid win;
  7.      anything any;
  8.      menu_item *pick_list = 0;
  9.      char ch, allowall[2];
  10.      /* if player wants a,b,c instead of i,o when looting, do that here too */
  11.      boolean abc = flags.lootabc;
  12.  
  13.      win = create_nhwindow(NHW_MENU);
  14.      start_menu(win);
  15.      any = zeroany;
  16.      any.a_char = 'm'; /* group accelerator 'C' */
  17.      add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'C', ATR_NONE,
  18.               "a monster", MENU_UNSELECTED);
  19.      if (invent) {
  20.          /* we use y and n as accelerators so that we can accept user's
  21.             response keyed to old "name an individual object?" prompt */
  22.          any.a_char = 'i'; /* group accelerator 'y' */
  23.          add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'y', ATR_NONE,
  24.                   "a particular object in inventory", MENU_UNSELECTED);
  25.          any.a_char = 'o'; /* group accelerator 'n' */
  26.          add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'n', ATR_NONE,
  27.                   "the type of an object in inventory", MENU_UNSELECTED);
  28.      }
  29.      any.a_char = 'f'; /* group accelerator ',' (or ':' instead?) */
  30.      add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, ',', ATR_NONE,
  31.               "the type of an object upon the floor", MENU_UNSELECTED);
  32.      any.a_char = 'd'; /* group accelerator '\' */
  33.      add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, '\\', ATR_NONE,
  34.               "the type of an object on discoveries list", MENU_UNSELECTED);
  35.      any.a_char = 'a'; /* group accelerator 'l' */
  36.      add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'l', ATR_NONE,
  37.               "record an annotation for the current level", MENU_UNSELECTED);
  38.      end_menu(win, "What do you want to name?");
  39.      if (select_menu(win, PICK_ONE, &pick_list) > 0) {
  40.          ch = pick_list[0].item.a_char;
  41.          free((genericptr_t) pick_list);
  42.      } else
  43.          ch = 'q';
  44.      destroy_nhwindow(win);
  45.  
  46.      switch (ch) {
  47.      default:
  48.      case 'q':
  49.          break;
  50.      case 'm': /* name a visible monster */
  51.          do_mname();
  52.          break;
  53.      case 'i': /* name an individual object in inventory */
  54.          allowall[0] = ALL_CLASSES;
  55.          allowall[1] = '\0';
  56.          obj = getobj(allowall, "name");
  57.          if (obj)
  58.              do_oname(obj);
  59.          break;
  60.      case 'o': /* name a type of object in inventory */
  61.          obj = getobj(callable, "call");
  62.          if (obj) {
  63.              /* behave as if examining it in inventory;
  64.                 this might set dknown if it was picked up
  65.                 while blind and the hero can now see */
  66.              (void) xname(obj);
  67.  
  68.              if (!obj->dknown) {
  69.                  You("would never recognize another one.");
  70.  #if 0
  71.              } else if (!objtyp_is_callable(obj->otyp)) {
  72.                  You("know those as well as you ever will.");
  73.  #endif
  74.              } else {
  75.                  docall(obj);
  76.              }
  77.          }
  78.          break;
  79.      case 'f': /* name a type of object visible on the floor */
  80.          namefloorobj();
  81.          break;
  82.      case 'd': /* name a type of object on the discoveries list */
  83.          rename_disco();
  84.          break;
  85.      case 'a': /* annotate level */
  86.          donamelevel();
  87.          break;
  88.      }
  89.      return 0;
  90.  }
  91.  

docall_xname

  1.  /* for use by safe_qbuf() */
  2.  STATIC_PTR char *
  3.  docall_xname(obj)
  4.  struct obj *obj;
  5.  {
  6.      struct obj otemp;
  7.  
  8.      otemp = *obj;
  9.      otemp.oextra = (struct oextra *) 0;
  10.      otemp.quan = 1L;
  11.      /* in case water is already known, convert "[un]holy water" to "water" */
  12.      otemp.blessed = otemp.cursed = 0;
  13.      /* remove attributes that are doname() caliber but get formatted
  14.         by xname(); most of these fixups aren't really needed because the
  15.         relevant type of object isn't callable so won't reach this far */
  16.      if (otemp.oclass == WEAPON_CLASS)
  17.          otemp.opoisoned = 0; /* not poisoned */
  18.      else if (otemp.oclass == POTION_CLASS)
  19.          otemp.odiluted = 0; /* not diluted */
  20.      else if (otemp.otyp == TOWEL || otemp.otyp == STATUE)
  21.          otemp.spe = 0; /* not wet or historic */
  22.      else if (otemp.otyp == TIN)
  23.          otemp.known = 0; /* suppress tin type (homemade, &c) and mon type */
  24.      else if (otemp.otyp == FIGURINE)
  25.          otemp.corpsenm = NON_PM; /* suppress mon type */
  26.      else if (otemp.otyp == HEAVY_IRON_BALL)
  27.          otemp.owt = objects[HEAVY_IRON_BALL].oc_weight; /* not "very heavy" */
  28.      else if (otemp.oclass == FOOD_CLASS && otemp.globby)
  29.          otemp.owt = 120; /* 6*20, neither a small glob nor a large one */
  30.  
  31.      return an(xname(&otemp));
  32.  }
  33.  

docall

  1.  void
  2.  docall(obj)
  3.  struct obj *obj;
  4.  {
  5.      char buf[BUFSZ] = DUMMY, qbuf[QBUFSZ];
  6.      char **str1;
  7.  
  8.      if (!obj->dknown)
  9.          return; /* probably blind */
  10.  
  11.      if (obj->oclass == POTION_CLASS && obj->fromsink)
  12.          /* kludge, meaning it's sink water */
  13.          Sprintf(qbuf, "Call a stream of %s fluid:",
  14.                  OBJ_DESCR(objects[obj->otyp]));
  15.      else
  16.          (void) safe_qbuf(qbuf, "Call ", ":", obj,
  17.                           docall_xname, simpleonames, "thing");
  18.      getlin(qbuf, buf);
  19.      if (!*buf || *buf == '\033')
  20.          return;
  21.  
  22.      /* clear old name */
  23.      str1 = &(objects[obj->otyp].oc_uname);
  24.      if (*str1)
  25.          free((genericptr_t) *str1);
  26.  
  27.      /* strip leading and trailing spaces; uncalls item if all spaces */
  28.      (void) mungspaces(buf);
  29.      if (!*buf) {
  30.          if (*str1) { /* had name, so possibly remove from disco[] */
  31.              /* strip name first, for the update_inventory() call
  32.                 from undiscover_object() */
  33.              *str1 = (char *) 0;
  34.              undiscover_object(obj->otyp);
  35.          }
  36.      } else {
  37.          *str1 = dupstr(buf);
  38.          discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
  39.      }
  40.  }
  41.  

namefloorobj

  1.  STATIC_OVL void
  2.  namefloorobj()
  3.  {
  4.      coord cc;
  5.      int glyph;
  6.      char buf[BUFSZ];
  7.      struct obj *obj = 0;
  8.      boolean fakeobj = FALSE, use_plural;
  9.  
  10.      cc.x = u.ux, cc.y = u.uy;
  11.      /* "dot for under/over you" only makes sense when the cursor hasn't
  12.         been moved off the hero's '@' yet, but there's no way to adjust
  13.         the help text once getpos() has started */
  14.      Sprintf(buf, "object on map (or '.' for one %s you)",
  15.              (u.uundetected && hides_under(youmonst.data)) ? "over" : "under");
  16.      if (getpos(&cc, FALSE, buf) < 0 || cc.x <= 0)
  17.          return;
  18.      if (cc.x == u.ux && cc.y == u.uy) {
  19.          obj = vobj_at(u.ux, u.uy);
  20.      } else {
  21.          glyph = glyph_at(cc.x, cc.y);
  22.          if (glyph_is_object(glyph))
  23.              fakeobj = object_from_map(glyph, cc.x, cc.y, &obj);
  24.          /* else 'obj' stays null */
  25.      }
  26.      if (!obj) {
  27.          /* "under you" is safe here since there's no object to hide under */
  28.          pline("There doesn't seem to be any object %s.",
  29.                (cc.x == u.ux && cc.y == u.uy) ? "under you" : "there");
  30.          return;
  31.      }
  32.      /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
  33.         is a mimic; passing that to xname (directly or via simpleonames)
  34.         would yield "glorkum" so we need to handle it explicitly; it will
  35.         always fail the Hallucination test and pass the !callable test,
  36.         resulting in the "can't be assigned a type name" message */
  37.      Strcpy(buf, (obj->otyp != STRANGE_OBJECT)
  38.                   ? simpleonames(obj)
  39.                   : obj_descr[STRANGE_OBJECT].oc_name);
  40.      use_plural = (obj->quan > 1L);
  41.      if (Hallucination) {
  42.          const char *unames[6];
  43.          char tmpbuf[BUFSZ];
  44.  
  45.          /* straight role name */
  46.          unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
  47.                       ? urole.name.f
  48.                       : urole.name.m;
  49.          /* random rank title for hero's role */
  50.          unames[1] = rank_of(rnd(30), Role_switch, flags.female);
  51.          /* random fake monster */
  52.          unames[2] = bogusmon(tmpbuf, (char *) 0);
  53.          /* increased chance for fake monster */
  54.          unames[3] = unames[2];
  55.          /* traditional */
  56.          unames[4] = roguename();
  57.          /* silly */
  58.          unames[5] = "Wibbly Wobbly";
  59.          pline("%s %s to call you \"%s.\"",
  60.                The(buf), use_plural ? "decide" : "decides",
  61.                unames[rn2(SIZE(unames))]);
  62.      } else if (!objtyp_is_callable(obj->otyp)) {
  63.          pline("%s %s can't be assigned a type name.",
  64.                use_plural ? "Those" : "That", buf);
  65.      } else if (!obj->dknown) {
  66.          You("don't know %s %s well enough to name %s.",
  67.              use_plural ? "those" : "that", buf, use_plural ? "them" : "it");
  68.      } else {
  69.          docall(obj);
  70.      }
  71.      if (fakeobj)
  72.          dealloc_obj(obj);
  73.  }
  74.  
  75.  static const char *const ghostnames[] = {
  76.      /* these names should have length < PL_NSIZ */
  77.      /* Capitalize the names for aesthetics -dgk */
  78.      "Adri",    "Andries",       "Andreas",     "Bert",    "David",  "Dirk",
  79.      "Emile",   "Frans",         "Fred",        "Greg",    "Hether", "Jay",
  80.      "John",    "Jon",           "Karnov",      "Kay",     "Kenny",  "Kevin",
  81.      "Maud",    "Michiel",       "Mike",        "Peter",   "Robert", "Ron",
  82.      "Tom",     "Wilmar",        "Nick Danger", "Phoenix", "Jiro",   "Mizue",
  83.      "Stephan", "Lance Braccus", "Shadowhawk"
  84.  };
  85.  

rndghostname

  1.  /* ghost names formerly set by x_monnam(), now by makemon() instead */
  2.  const char *
  3.  rndghostname()
  4.  {
  5.      return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *) plname;
  6.  }
  7.  
  8.  /*
  9.   * Monster naming functions:
  10.   * x_monnam is the generic monster-naming function.
  11.   *                seen        unseen       detected               named
  12.   * mon_nam:     the newt        it      the invisible orc       Fido
  13.   * noit_mon_nam:the newt (as if detected) the invisible orc     Fido
  14.   * l_monnam:    newt            it      invisible orc           dog called Fido
  15.   * Monnam:      The newt        It      The invisible orc       Fido
  16.   * noit_Monnam: The newt (as if detected) The invisible orc     Fido
  17.   * Adjmonnam:   The poor newt   It      The poor invisible orc  The poor Fido
  18.   * Amonnam:     A newt          It      An invisible orc        Fido
  19.   * a_monnam:    a newt          it      an invisible orc        Fido
  20.   * m_monnam:    newt            xan     orc                     Fido
  21.   * y_monnam:    your newt     your xan  your invisible orc      Fido
  22.   * noname_monnam(mon,article):
  23.   *              article newt    art xan art invisible orc       art dog
  24.   */
  25.  
  26.  /* Bug: if the monster is a priest or shopkeeper, not every one of these
  27.   * options works, since those are special cases.
  28.   */

x_monnam

  1.  char *
  2.  x_monnam(mtmp, article, adjective, suppress, called)
  3.  register struct monst *mtmp;
  4.  int article;
  5.  /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
  6.   * ARTICLE_YOUR: "your" on pets, "the" on everything else
  7.   *
  8.   * If the monster would be referred to as "it" or if the monster has a name
  9.   * _and_ there is no adjective, "invisible", "saddled", etc., override this
  10.   * and always use no article.
  11.   */
  12.  const char *adjective;
  13.  int suppress;
  14.  /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
  15.   * EXACT_NAME: combination of all the above
  16.   * SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname).
  17.   */
  18.  boolean called;
  19.  {
  20.      char *buf = nextmbuf();
  21.      struct permonst *mdat = mtmp->data;
  22.      const char *pm_name = mdat->mname;
  23.      boolean do_hallu, do_invis, do_it, do_saddle, do_name;
  24.      boolean name_at_start, has_adjectives;
  25.      char *bp;
  26.  
  27.      if (program_state.gameover)
  28.          suppress |= SUPPRESS_HALLUCINATION;
  29.      if (article == ARTICLE_YOUR && !mtmp->mtame)
  30.          article = ARTICLE_THE;
  31.  
  32.      do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
  33.      do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
  34.      do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR
  35.              && !program_state.gameover && mtmp != u.usteed
  36.              && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT);
  37.      do_saddle = !(suppress & SUPPRESS_SADDLE);
  38.      do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat);
  39.  
  40.      buf[0] = '\0';
  41.  
  42.      /* unseen monsters, etc.  Use "it" */
  43.      if (do_it) {
  44.          Strcpy(buf, "it");
  45.          return buf;
  46.      }
  47.  
  48.      /* priests and minions: don't even use this function */
  49.      if (mtmp->ispriest || mtmp->isminion) {
  50.          char priestnambuf[BUFSZ];
  51.          char *name;
  52.          long save_prop = EHalluc_resistance;
  53.          unsigned save_invis = mtmp->minvis;
  54.  
  55.          /* when true name is wanted, explicitly block Hallucination */
  56.          if (!do_hallu)
  57.              EHalluc_resistance = 1L;
  58.          if (!do_invis)
  59.              mtmp->minvis = 0;
  60.          name = priestname(mtmp, priestnambuf);
  61.          EHalluc_resistance = save_prop;
  62.          mtmp->minvis = save_invis;
  63.          if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
  64.              name += 4;
  65.          return strcpy(buf, name);
  66.      }
  67.      /* an "aligned priest" not flagged as a priest or minion should be
  68.         "priest" or "priestess" (normally handled by priestname()) */
  69.      if (mdat == &mons[PM_ALIGNED_PRIEST])
  70.          pm_name = mtmp->female ? "priestess" : "priest";
  71.      else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female)
  72.          pm_name = "high priestess";
  73.  
  74.      /* Shopkeepers: use shopkeeper name.  For normal shopkeepers, just
  75.       * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
  76.       * shopkeeper" or "Asidonhopo the blue dragon".  If hallucinating,
  77.       * none of this applies.
  78.       */
  79.      if (mtmp->isshk && !do_hallu) {
  80.          if (adjective && article == ARTICLE_THE) {
  81.              /* pathological case: "the angry Asidonhopo the blue dragon"
  82.                 sounds silly */
  83.              Strcpy(buf, "the ");
  84.              Strcat(strcat(buf, adjective), " ");
  85.              Strcat(buf, shkname(mtmp));
  86.              return buf;
  87.          }
  88.          Strcat(buf, shkname(mtmp));
  89.          if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
  90.              return buf;
  91.          Strcat(buf, " the ");
  92.          if (do_invis)
  93.              Strcat(buf, "invisible ");
  94.          Strcat(buf, pm_name);
  95.          return buf;
  96.      }
  97.  
  98.      /* Put the adjectives in the buffer */
  99.      if (adjective)
  100.          Strcat(strcat(buf, adjective), " ");
  101.      if (do_invis)
  102.          Strcat(buf, "invisible ");
  103.      if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind
  104.          && !Hallucination)
  105.          Strcat(buf, "saddled ");
  106.      if (buf[0] != 0)
  107.          has_adjectives = TRUE;
  108.      else
  109.          has_adjectives = FALSE;
  110.  
  111.      /* Put the actual monster name or type into the buffer now */
  112.      /* Be sure to remember whether the buffer starts with a name */
  113.      if (do_hallu) {
  114.          char rnamecode;
  115.          char *rname = rndmonnam(&rnamecode);
  116.  
  117.          Strcat(buf, rname);
  118.          name_at_start = bogon_is_pname(rnamecode);
  119.      } else if (do_name && has_mname(mtmp)) {
  120.          char *name = MNAME(mtmp);
  121.  
  122.          if (mdat == &mons[PM_GHOST]) {
  123.              Sprintf(eos(buf), "%s ghost", s_suffix(name));
  124.              name_at_start = TRUE;
  125.          } else if (called) {
  126.              Sprintf(eos(buf), "%s called %s", pm_name, name);
  127.              name_at_start = (boolean) type_is_pname(mdat);
  128.          } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
  129.              /* <name> the <adjective> <invisible> <saddled> <rank> */
  130.              char pbuf[BUFSZ];
  131.  
  132.              Strcpy(pbuf, name);
  133.              pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
  134.              if (has_adjectives)
  135.                  Strcat(pbuf, buf);
  136.              Strcat(pbuf, bp + 5); /* append the rest of the name */
  137.              Strcpy(buf, pbuf);
  138.              article = ARTICLE_NONE;
  139.              name_at_start = TRUE;
  140.          } else {
  141.              Strcat(buf, name);
  142.              name_at_start = TRUE;
  143.          }
  144.      } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
  145.          char pbuf[BUFSZ];
  146.  
  147.          Strcpy(pbuf, rank_of((int) mtmp->m_lev, monsndx(mdat),
  148.                               (boolean) mtmp->female));
  149.          Strcat(buf, lcase(pbuf));
  150.          name_at_start = FALSE;
  151.      } else {
  152.          Strcat(buf, pm_name);
  153.          name_at_start = (boolean) type_is_pname(mdat);
  154.      }
  155.  
  156.      if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
  157.          if (mdat == &mons[PM_WIZARD_OF_YENDOR])
  158.              article = ARTICLE_THE;
  159.          else
  160.              article = ARTICLE_NONE;
  161.      } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
  162.          article = ARTICLE_THE;
  163.      }
  164.  
  165.      {
  166.          char buf2[BUFSZ];
  167.  
  168.          switch (article) {
  169.          case ARTICLE_YOUR:
  170.              Strcpy(buf2, "your ");
  171.              Strcat(buf2, buf);
  172.              Strcpy(buf, buf2);
  173.              return buf;
  174.          case ARTICLE_THE:
  175.              Strcpy(buf2, "the ");
  176.              Strcat(buf2, buf);
  177.              Strcpy(buf, buf2);
  178.              return buf;
  179.          case ARTICLE_A:
  180.              return an(buf);
  181.          case ARTICLE_NONE:
  182.          default:
  183.              return buf;
  184.          }
  185.      }
  186.  }
  187.  

l_monnam

  1.  char *
  2.  l_monnam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      return x_monnam(mtmp, ARTICLE_NONE, (char *) 0,
  6.                      (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE);
  7.  }
  8.  

mon_nam

  1.  char *
  2.  mon_nam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
  6.                      (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE);
  7.  }
  8.  

noit_mon_nam

  1.  /* print the name as if mon_nam() was called, but assume that the player
  2.   * can always see the monster--used for probing and for monsters aggravating
  3.   * the player with a cursed potion of invisibility
  4.   */
  5.  char *
  6.  noit_mon_nam(mtmp)
  7.  struct monst *mtmp;
  8.  {
  9.      return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
  10.                      (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT)
  11.                                        : SUPPRESS_IT,
  12.                      FALSE);
  13.  }
  14.  

Monnam

  1.  char *
  2.  Monnam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      register char *bp = mon_nam(mtmp);
  6.  
  7.      *bp = highc(*bp);
  8.      return  bp;
  9.  }
  10.  

noit_Monnam

  1.  char *
  2.  noit_Monnam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      register char *bp = noit_mon_nam(mtmp);
  6.  
  7.      *bp = highc(*bp);
  8.      return  bp;
  9.  }
  10.  

noname_monnam

  1.  /* return "a dog" rather than "Fido", honoring hallucination and visibility */
  2.  char *
  3.  noname_monnam(mtmp, article)
  4.  struct monst *mtmp;
  5.  int article;
  6.  {
  7.      return x_monnam(mtmp, article, (char *) 0, SUPPRESS_NAME, FALSE);
  8.  }
  9.  

m_monnam

  1.  /* monster's own name -- overrides hallucination and [in]visibility
  2.     so shouldn't be used in ordinary messages (mainly for disclosure) */
  3.  char *
  4.  m_monnam(mtmp)
  5.  struct monst *mtmp;
  6.  {
  7.      return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, EXACT_NAME, FALSE);
  8.  }
  9.  

y_monnam

  1.  /* pet name: "your little dog" */
  2.  char *
  3.  y_monnam(mtmp)
  4.  struct monst *mtmp;
  5.  {
  6.      int prefix, suppression_flag;
  7.  
  8.      prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
  9.      suppression_flag = (has_mname(mtmp)
  10.                          /* "saddled" is redundant when mounted */
  11.                          || mtmp == u.usteed)
  12.                             ? SUPPRESS_SADDLE
  13.                             : 0;
  14.  
  15.      return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE);
  16.  }
  17.  

Adjmonnam

  1.  char *
  2.  Adjmonnam(mtmp, adj)
  3.  struct monst *mtmp;
  4.  const char *adj;
  5.  {
  6.      char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
  7.                          has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
  8.  
  9.      *bp = highc(*bp);
  10.      return  bp;
  11.  }
  12.  

a_monnam

  1.  char *
  2.  a_monnam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      return x_monnam(mtmp, ARTICLE_A, (char *) 0,
  6.                      has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
  7.  }
  8.  

Amonnam

  1.  char *
  2.  Amonnam(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      char *bp = a_monnam(mtmp);
  6.  
  7.      *bp = highc(*bp);
  8.      return  bp;
  9.  }
  10.  

distant_monnam

  1.  /* used for monster ID by the '/', ';', and 'C' commands to block remote
  2.     identification of the endgame altars via their attending priests */
  3.  char *
  4.  distant_monnam(mon, article, outbuf)
  5.  struct monst *mon;
  6.  int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
  7.  char *outbuf;
  8.  {
  9.      /* high priest(ess)'s identity is concealed on the Astral Plane,
  10.         unless you're adjacent (overridden for hallucination which does
  11.         its own obfuscation) */
  12.      if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination
  13.          && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
  14.          Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
  15.          Strcat(outbuf, mon->female ? "high priestess" : "high priest");
  16.      } else {
  17.          Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE));
  18.      }
  19.      return outbuf;
  20.  }
  21.  

bogusmon

  1.  /* fake monsters used to be in a hard-coded array, now in a data file */
  2.  STATIC_OVL char *
  3.  bogusmon(buf, code)
  4.  char *buf, *code;
  5.  {
  6.      char *mname = buf;
  7.  
  8.      get_rnd_text(BOGUSMONFILE, buf);
  9.      /* strip prefix if present */
  10.      if (!letter(*mname)) {
  11.          if (code)
  12.              *code = *mname;
  13.          ++mname;
  14.      } else {
  15.          if (code)
  16.              *code = '\0';
  17.      }
  18.      return mname;
  19.  }
  20.  

rndmonnam

  1.  /* return a random monster name, for hallucination */
  2.  char *
  3.  rndmonnam(code)
  4.  char *code;
  5.  {
  6.      static char buf[BUFSZ];
  7.      char *mname;
  8.      int name;
  9.  #define BOGUSMONSIZE 100 /* arbitrary */
  10.  
  11.      if (code)
  12.          *code = '\0';
  13.  
  14.      do {
  15.          name = rn1(SPECIAL_PM + BOGUSMONSIZE - LOW_PM, LOW_PM);
  16.      } while (name < SPECIAL_PM
  17.               && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
  18.  
  19.      if (name >= SPECIAL_PM) {
  20.          mname = bogusmon(buf, code);
  21.      } else {
  22.          mname = strcpy(buf, mons[name].mname);
  23.      }
  24.      return mname;
  25.  #undef BOGUSMONSIZE
  26.  }
  27.  

bogon_is_pname

  1.  /* check bogusmon prefix to decide whether it's a personal name */
  2.  boolean
  3.  bogon_is_pname(code)
  4.  char code;
  5.  {
  6.      if (!code)
  7.          return FALSE;
  8.      return index("-+=", code) ? TRUE : FALSE;
  9.  }
  10.  

roguename

  1.  /* name of a Rogue player */
  2.  const char *
  3.  roguename()
  4.  {
  5.      char *i, *opts;
  6.  
  7.      if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
  8.          for (i = opts; *i; i++)
  9.              if (!strncmp("name=", i, 5)) {
  10.                  char *j;
  11.                  if ((j = index(i + 5, ',')) != 0)
  12.                      *j = (char) 0;
  13.                  return i + 5;
  14.              }
  15.      }
  16.      return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
  17.                    : "Glenn Wichman";
  18.  }
  19.  
  20.  static NEARDATA const char *const hcolors[] = {
  21.      "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
  22.      "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
  23.      "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
  24.      "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
  25.      "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
  26.      "strawberry-banana", "peppermint", "romantic", "incandescent",
  27.      "octarine", /* Discworld: the Colour of Magic */
  28.  };
  29.  

hcolor

  1.  const char *
  2.  hcolor(colorpref)
  3.  const char *colorpref;
  4.  {
  5.      return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))]
  6.                                           : colorpref;
  7.  }
  8.  

rndcolor

  1.  /* return a random real color unless hallucinating */
  2.  const char *
  3.  rndcolor()
  4.  {
  5.      int k = rn2(CLR_MAX);
  6.  
  7.      return Hallucination ? hcolor((char *) 0)
  8.                           : (k == NO_COLOR) ? "colorless"
  9.                                             : c_obj_colors[k];
  10.  }
  11.  
  12.  static NEARDATA const char *const hliquids[] = {
  13.      "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
  14.      "instant coffee", "tea", "herbal infusion", "liquid rainbow",
  15.      "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
  16.      "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
  17.      "caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
  18.      "glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
  19.      "sweet vitriol", "grey goo", "pink slime",
  20.  };
  21.  

hliquid

  1.  const char *
  2.  hliquid(liquidpref)
  3.  const char *liquidpref;
  4.  {
  5.      return (Hallucination || !liquidpref) ? hliquids[rn2(SIZE(hliquids))]
  6.                                           : liquidpref;
  7.  }
  8.  
  9.  /* Aliases for road-runner nemesis
  10.   */
  11.  static const char *const coynames[] = {
  12.      "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
  13.      "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
  14.      "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
  15.      "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
  16.      "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
  17.      "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
  18.      "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
  19.      "Canis latrans"
  20.  };
  21.  

coyotename

  1.  char *
  2.  coyotename(mtmp, buf)
  3.  struct monst *mtmp;
  4.  char *buf;
  5.  {
  6.      if (mtmp && buf) {
  7.          Sprintf(buf, "%s - %s",
  8.                  x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
  9.                  mtmp->mcan ? coynames[SIZE(coynames) - 1]
  10.                             : coynames[mtmp->m_id % (SIZE(coynames) - 1)]);
  11.      }
  12.      return buf;
  13.  }
  14.  
  15.  /* make sure "The Colour of Magic" remains the first entry in here */
  16.  static const char *const sir_Terry_novels[] = {
  17.      "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
  18.      "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
  19.      "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
  20.      "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
  21.      "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
  22.      "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
  23.      "The Last Hero", "The Amazing Maurice and His Educated Rodents",
  24.      "Night Watch", "The Wee Free Men", "Monstrous Regiment",
  25.      "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
  26.      "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
  27.      "Raising Steam", "The Shepherd's Crown"
  28.  };
  29.  

noveltitle

  1.  const char *
  2.  noveltitle(novidx)
  3.  int *novidx;
  4.  {
  5.      int j, k = SIZE(sir_Terry_novels);
  6.  
  7.      j = rn2(k);
  8.      if (novidx) {
  9.          if (*novidx == -1)
  10.              *novidx = j;
  11.          else if (*novidx >= 0 && *novidx < k)
  12.              j = *novidx;
  13.      }
  14.      return sir_Terry_novels[j];
  15.  }
  16.  

lookup_novel

  1.  const char *
  2.  lookup_novel(lookname, idx)
  3.  const char *lookname;
  4.  int *idx;
  5.  {
  6.      int k;
  7.  
  8.      /* Take American or U.K. spelling of this one */
  9.      if (!strcmpi(The(lookname), "The Color of Magic"))
  10.          lookname = sir_Terry_novels[0];
  11.  
  12.      for (k = 0; k < SIZE(sir_Terry_novels); ++k) {
  13.          if (!strcmpi(lookname, sir_Terry_novels[k])
  14.              || !strcmpi(The(lookname), sir_Terry_novels[k])) {
  15.              if (idx)
  16.                  *idx = k;
  17.              return sir_Terry_novels[k];
  18.          }
  19.      }
  20.      /* name not found; if novelidx is already set, override the name */
  21.      if (idx && *idx >= 0 && *idx < SIZE(sir_Terry_novels))
  22.          return sir_Terry_novels[*idx];
  23.  
  24.      return (const char *) 0;
  25.  }
  26.  
  27.  /*do_name.c*/