Source:NetHack 3.6.0/src/engrave.c

From NetHackWiki
Jump to: navigation, search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

Top of file

  1.  /* NetHack 3.6	engrave.c	$NHDT-Date: 1445388915 2015/10/21 00:55:15 $  $NHDT-Branch: master $:$NHDT-Revision: 1.59 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  #include "lev.h"
  7.  
  8.  STATIC_VAR NEARDATA struct engr *head_engr;
  9.  

random_engraving

  1.  char *
  2.  random_engraving(outbuf)
  3.  char *outbuf;
  4.  {
  5.      const char *rumor;
  6.  
  7.      /* a random engraving may come from the "rumors" file,
  8.         or from the "engrave" file (formerly in an array here) */
  9.      if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor)
  10.          (void) get_rnd_text(ENGRAVEFILE, outbuf);
  11.  
  12.      wipeout_text(outbuf, (int) (strlen(outbuf) / 4), 0);
  13.      return outbuf;
  14.  }
  15.  

wipeout_text

  1.  /* Partial rubouts for engraving characters. -3. */
  2.  static const struct {
  3.      char wipefrom;
  4.      const char *wipeto;
  5.  } rubouts[] = { { 'A', "^" },
  6.                  { 'B', "Pb[" },
  7.                  { 'C', "(" },
  8.                  { 'D', "|)[" },
  9.                  { 'E', "|FL[_" },
  10.                  { 'F', "|-" },
  11.                  { 'G', "C(" },
  12.                  { 'H', "|-" },
  13.                  { 'I', "|" },
  14.                  { 'K', "|<" },
  15.                  { 'L', "|_" },
  16.                  { 'M', "|" },
  17.                  { 'N', "|\\" },
  18.                  { 'O', "C(" },
  19.                  { 'P', "F" },
  20.                  { 'Q', "C(" },
  21.                  { 'R', "PF" },
  22.                  { 'T', "|" },
  23.                  { 'U', "J" },
  24.                  { 'V', "/\\" },
  25.                  { 'W', "V/\\" },
  26.                  { 'Z', "/" },
  27.                  { 'b', "|" },
  28.                  { 'd', "c|" },
  29.                  { 'e', "c" },
  30.                  { 'g', "c" },
  31.                  { 'h', "n" },
  32.                  { 'j', "i" },
  33.                  { 'k', "|" },
  34.                  { 'l', "|" },
  35.                  { 'm', "nr" },
  36.                  { 'n', "r" },
  37.                  { 'o', "c" },
  38.                  { 'q', "c" },
  39.                  { 'w', "v" },
  40.                  { 'y', "v" },
  41.                  { ':', "." },
  42.                  { ';', ",:" },
  43.                  { ',', "." },
  44.                  { '=', "-" },
  45.                  { '+', "-|" },
  46.                  { '*', "+" },
  47.                  { '@', "0" },
  48.                  { '0', "C(" },
  49.                  { '1', "|" },
  50.                  { '6', "o" },
  51.                  { '7', "/" },
  52.                  { '8', "3o" } };
  53.  
  54.  /* degrade some of the characters in a string */
  55.  void
  56.  wipeout_text(engr, cnt, seed)
  57.  char *engr;
  58.  int cnt;
  59.  unsigned seed; /* for semi-controlled randomization */
  60.  {
  61.      char *s;
  62.      int i, j, nxt, use_rubout, lth = (int) strlen(engr);
  63.  
  64.      if (lth && cnt > 0) {
  65.          while (cnt--) {
  66.              /* pick next character */
  67.              if (!seed) {
  68.                  /* random */
  69.                  nxt = rn2(lth);
  70.                  use_rubout = rn2(4);
  71.              } else {
  72.                  /* predictable; caller can reproduce the same sequence by
  73.                     supplying the same arguments later, or a pseudo-random
  74.                     sequence by varying any of them */
  75.                  nxt = seed % lth;
  76.                  seed *= 31, seed %= (BUFSZ - 1);
  77.                  use_rubout = seed & 3;
  78.              }
  79.              s = &engr[nxt];
  80.              if (*s == ' ')
  81.                  continue;
  82.  
  83.              /* rub out unreadable & small punctuation marks */
  84.              if (index("?.,'`-|_", *s)) {
  85.                  *s = ' ';
  86.                  continue;
  87.              }
  88.  
  89.              if (!use_rubout)
  90.                  i = SIZE(rubouts);
  91.              else
  92.                  for (i = 0; i < SIZE(rubouts); i++)
  93.                      if (*s == rubouts[i].wipefrom) {
  94.                          /*
  95.                           * Pick one of the substitutes at random.
  96.                           */
  97.                          if (!seed)
  98.                              j = rn2(strlen(rubouts[i].wipeto));
  99.                          else {
  100.                              seed *= 31, seed %= (BUFSZ - 1);
  101.                              j = seed % (strlen(rubouts[i].wipeto));
  102.                          }
  103.                          *s = rubouts[i].wipeto[j];
  104.                          break;
  105.                      }
  106.  
  107.              /* didn't pick rubout; use '?' for unreadable character */
  108.              if (i == SIZE(rubouts))
  109.                  *s = '?';
  110.          }
  111.      }
  112.  
  113.      /* trim trailing spaces */
  114.      while (lth && engr[lth - 1] == ' ')
  115.          engr[--lth] = '\0';
  116.  }
  117.  

can_reach_floor

  1.  /* check whether hero can reach something at ground level */
  2.  boolean
  3.  can_reach_floor(check_pit)
  4.  boolean check_pit;
  5.  {
  6.      struct trap *t;
  7.  
  8.      if (u.uswallow)
  9.          return FALSE;
  10.      /* Restricted/unskilled riders can't reach the floor */
  11.      if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
  12.          return FALSE;
  13.      if (check_pit && !Flying
  14.          && (t = t_at(u.ux, u.uy)) != 0 && uteetering_at_seen_pit(t))
  15.          return FALSE;
  16.  
  17.      return (boolean) ((!Levitation || Is_airlevel(&u.uz)
  18.                         || Is_waterlevel(&u.uz))
  19.                        && (!u.uundetected || !is_hider(youmonst.data)
  20.                            || u.umonnum == PM_TRAPPER));
  21.  }
  22.  

cant_reach_floor

  1.  /* give a message after caller has determined that hero can't reach */
  2.  void
  3.  cant_reach_floor(x, y, up, check_pit)
  4.  int x, y;
  5.  boolean up, check_pit;
  6.  {
  7.      You("can't reach the %s.",
  8.          up ? ceiling(x, y)
  9.             : (check_pit && can_reach_floor(FALSE))
  10.                 ? "bottom of the pit"
  11.                 : surface(x, y));
  12.  }
  13.  

surface

  1.  const char *
  2.  surface(x, y)
  3.  register int x, y;
  4.  {
  5.      register struct rm *lev = &levl[x][y];
  6.  
  7.      if (x == u.ux && y == u.uy && u.uswallow && is_animal(u.ustuck->data))
  8.          return "maw";
  9.      else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
  10.          return "air";
  11.      else if (is_pool(x, y))
  12.          return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
  13.      else if (is_ice(x, y))
  14.          return "ice";
  15.      else if (is_lava(x, y))
  16.          return "lava";
  17.      else if (lev->typ == DRAWBRIDGE_DOWN)
  18.          return "bridge";
  19.      else if (IS_ALTAR(levl[x][y].typ))
  20.          return "altar";
  21.      else if (IS_GRAVE(levl[x][y].typ))
  22.          return "headstone";
  23.      else if (IS_FOUNTAIN(levl[x][y].typ))
  24.          return "fountain";
  25.      else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz))
  26.               || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
  27.          return "floor";
  28.      else
  29.          return "ground";
  30.  }
  31.  

ceiling

  1.  const char *
  2.  ceiling(x, y)
  3.  register int x, y;
  4.  {
  5.      register struct rm *lev = &levl[x][y];
  6.      const char *what;
  7.  
  8.      /* other room types will no longer exist when we're interested --
  9.       * see check_special_room()
  10.       */
  11.      if (*in_rooms(x, y, VAULT))
  12.          what = "vault's ceiling";
  13.      else if (*in_rooms(x, y, TEMPLE))
  14.          what = "temple's ceiling";
  15.      else if (*in_rooms(x, y, SHOPBASE))
  16.          what = "shop's ceiling";
  17.      else if (Is_waterlevel(&u.uz))
  18.          /* water plane has no surface; its air bubbles aren't below sky */
  19.          what = "water above";
  20.      else if (IS_AIR(lev->typ))
  21.          what = "sky";
  22.      else if (Underwater)
  23.          what = "water's surface";
  24.      else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz))
  25.               || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
  26.          what = "ceiling";
  27.      else
  28.          what = "rock cavern";
  29.  
  30.      return what;
  31.  }
  32.  

engr_at

  1.  struct engr *
  2.  engr_at(x, y)
  3.  xchar x, y;
  4.  {
  5.      register struct engr *ep = head_engr;
  6.  
  7.      while (ep) {
  8.          if (x == ep->engr_x && y == ep->engr_y)
  9.              return ep;
  10.          ep = ep->nxt_engr;
  11.      }
  12.      return (struct engr *) 0;
  13.  }
  14.  

sengr_at

  1.  /* Decide whether a particular string is engraved at a specified
  2.   * location; a case-insensitive substring match is used.
  3.   * Ignore headstones, in case the player names herself "Elbereth".
  4.   *
  5.   * If strict checking is requested, the word is only considered to be
  6.   * present if it is intact and is the first word in the engraving.
  7.   * ("Elbereth burrito" matches; "o Elbereth" does not.)
  8.   */
  9.  int
  10.  sengr_at(s, x, y, strict)
  11.  const char *s;
  12.  xchar x, y;
  13.  boolean strict;
  14.  {
  15.      register struct engr *ep = engr_at(x, y);
  16.  
  17.      if (ep && ep->engr_type != HEADSTONE && ep->engr_time <= moves) {
  18.          return strict ? (strncmpi(ep->engr_txt, s, strlen(s)) == 0)
  19.                        : (strstri(ep->engr_txt, s) != 0);
  20.      }
  21.      return FALSE;
  22.  }
  23.  

u_wipe_engr

  1.  void
  2.  u_wipe_engr(cnt)
  3.  int cnt;
  4.  {
  5.      if (can_reach_floor(TRUE))
  6.          wipe_engr_at(u.ux, u.uy, cnt, FALSE);
  7.  }
  8.  

wipe_engr_at

  1.  void
  2.  wipe_engr_at(x, y, cnt, magical)
  3.  xchar x, y, cnt, magical;
  4.  {
  5.      register struct engr *ep = engr_at(x, y);
  6.  
  7.      /* Headstones are indelible */
  8.      if (ep && ep->engr_type != HEADSTONE) {
  9.          debugpline1("asked to erode %d characters", cnt);
  10.          if (ep->engr_type != BURN || is_ice(x, y) || (magical && !rn2(2))) {
  11.              if (ep->engr_type != DUST && ep->engr_type != ENGR_BLOOD) {
  12.                  cnt = rn2(1 + 50 / (cnt + 1)) ? 0 : 1;
  13.                  debugpline1("actually eroding %d characters", cnt);
  14.              }
  15.              wipeout_text(ep->engr_txt, (int) cnt, 0);
  16.              while (ep->engr_txt[0] == ' ')
  17.                  ep->engr_txt++;
  18.              if (!ep->engr_txt[0])
  19.                  del_engr(ep);
  20.          }
  21.      }
  22.  }
  23.  

read_engr_at

  1.  void
  2.  read_engr_at(x, y)
  3.  int x, y;
  4.  {
  5.      register struct engr *ep = engr_at(x, y);
  6.      int sensed = 0;
  7.      char buf[BUFSZ];
  8.  
  9.      /* Sensing an engraving does not require sight,
  10.       * nor does it necessarily imply comprehension (literacy).
  11.       */
  12.      if (ep && ep->engr_txt[0]) {
  13.          switch (ep->engr_type) {
  14.          case DUST:
  15.              if (!Blind) {
  16.                  sensed = 1;
  17.                  pline("%s is written here in the %s.", Something,
  18.                        is_ice(x, y) ? "frost" : "dust");
  19.              }
  20.              break;
  21.          case ENGRAVE:
  22.          case HEADSTONE:
  23.              if (!Blind || can_reach_floor(TRUE)) {
  24.                  sensed = 1;
  25.                  pline("%s is engraved here on the %s.", Something,
  26.                        surface(x, y));
  27.              }
  28.              break;
  29.          case BURN:
  30.              if (!Blind || can_reach_floor(TRUE)) {
  31.                  sensed = 1;
  32.                  pline("Some text has been %s into the %s here.",
  33.                        is_ice(x, y) ? "melted" : "burned", surface(x, y));
  34.              }
  35.              break;
  36.          case MARK:
  37.              if (!Blind) {
  38.                  sensed = 1;
  39.                  pline("There's some graffiti on the %s here.", surface(x, y));
  40.              }
  41.              break;
  42.          case ENGR_BLOOD:
  43.              /* "It's a message!  Scrawled in blood!"
  44.               * "What's it say?"
  45.               * "It says... `See you next Wednesday.'" -- Thriller
  46.               */
  47.              if (!Blind) {
  48.                  sensed = 1;
  49.                  You_see("a message scrawled in blood here.");
  50.              }
  51.              break;
  52.          default:
  53.              impossible("%s is written in a very strange way.", Something);
  54.              sensed = 1;
  55.          }
  56.          if (sensed) {
  57.              char *et;
  58.              unsigned maxelen = BUFSZ - sizeof("You feel the words: \"\". ");
  59.              if (strlen(ep->engr_txt) > maxelen) {
  60.                  (void) strncpy(buf, ep->engr_txt, (int) maxelen);
  61.                  buf[maxelen] = '\0';
  62.                  et = buf;
  63.              } else
  64.                  et = ep->engr_txt;
  65.              You("%s: \"%s\".", (Blind) ? "feel the words" : "read", et);
  66.              if (context.run > 1)
  67.                  nomul(0);
  68.          }
  69.      }
  70.  }
  71.  

make_engr_at

  1.  void
  2.  make_engr_at(x, y, s, e_time, e_type)
  3.  int x, y;
  4.  const char *s;
  5.  long e_time;
  6.  xchar e_type;
  7.  {
  8.      struct engr *ep;
  9.  
  10.      if ((ep = engr_at(x, y)) != 0)
  11.          del_engr(ep);
  12.      ep = newengr(strlen(s) + 1);
  13.      ep->nxt_engr = head_engr;
  14.      head_engr = ep;
  15.      ep->engr_x = x;
  16.      ep->engr_y = y;
  17.      ep->engr_txt = (char *) (ep + 1);
  18.      Strcpy(ep->engr_txt, s);
  19.      /* engraving Elbereth shows wisdom */
  20.      if (!in_mklev && !strcmp(s, "Elbereth"))
  21.          exercise(A_WIS, TRUE);
  22.      ep->engr_time = e_time;
  23.      ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE - 1);
  24.      ep->engr_lth = strlen(s) + 1;
  25.  }
  26.  

del_engr_at

  1.  /* delete any engraving at location <x,y> */
  2.  void
  3.  del_engr_at(x, y)
  4.  int x, y;
  5.  {
  6.      register struct engr *ep = engr_at(x, y);
  7.  
  8.      if (ep)
  9.          del_engr(ep);
  10.  }
  11.  

freehand

  1.  /*
  2.   *	freehand - returns true if player has a free hand
  3.   */
  4.  int
  5.  freehand()
  6.  {
  7.      return (!uwep || !welded(uwep)
  8.              || (!bimanual(uwep) && (!uarms || !uarms->cursed)));
  9.  }
  10.  

doengrave

  1.  static NEARDATA const char styluses[] = { ALL_CLASSES, ALLOW_NONE,
  2.                                            TOOL_CLASS,  WEAPON_CLASS,
  3.                                            WAND_CLASS,  GEM_CLASS,
  4.                                            RING_CLASS,  0 };
  5.  
  6.  /* Mohs' Hardness Scale:
  7.   *  1 - Talc		 6 - Orthoclase
  8.   *  2 - Gypsum		 7 - Quartz
  9.   *  3 - Calcite		 8 - Topaz
  10.   *  4 - Fluorite	 9 - Corundum
  11.   *  5 - Apatite		10 - Diamond
  12.   *
  13.   * Since granite is an igneous rock hardness ~ 7, anything >= 8 should
  14.   * probably be able to scratch the rock.
  15.   * Devaluation of less hard gems is not easily possible because obj struct
  16.   * does not contain individual oc_cost currently. 7/91
  17.   *
  18.   * steel     -	5-8.5	(usu. weapon)
  19.   * diamond    - 10			* jade	     -	5-6	 (nephrite)
  20.   * ruby       -  9	(corundum)	* turquoise  -	5-6
  21.   * sapphire   -  9	(corundum)	* opal	     -	5-6
  22.   * topaz      -  8			* glass      - ~5.5
  23.   * emerald    -  7.5-8	(beryl)		* dilithium  -	4-5??
  24.   * aquamarine -  7.5-8	(beryl)		* iron	     -	4-5
  25.   * garnet     -  7.25	(var. 6.5-8)	* fluorite   -	4
  26.   * agate      -  7	(quartz)	* brass      -	3-4
  27.   * amethyst   -  7	(quartz)	* gold	     -	2.5-3
  28.   * jasper     -  7	(quartz)	* silver     -	2.5-3
  29.   * onyx       -  7	(quartz)	* copper     -	2.5-3
  30.   * moonstone  -  6	(orthoclase)	* amber      -	2-2.5
  31.   */
  32.  
  33.  /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
  34.  int
  35.  doengrave()
  36.  {
  37.      boolean dengr = FALSE;    /* TRUE if we wipe out the current engraving */
  38.      boolean doblind = FALSE;  /* TRUE if engraving blinds the player */
  39.      boolean doknown = FALSE;  /* TRUE if we identify the stylus */
  40.      boolean eow = FALSE;      /* TRUE if we are overwriting oep */
  41.      boolean jello = FALSE;    /* TRUE if we are engraving in slime */
  42.      boolean ptext = TRUE;     /* TRUE if we must prompt for engrave text */
  43.      boolean teleengr = FALSE; /* TRUE if we move the old engraving */
  44.      boolean zapwand = FALSE;  /* TRUE if we remove a wand charge */
  45.      xchar type = DUST;        /* Type of engraving made */
  46.      char buf[BUFSZ];          /* Buffer for final/poly engraving text */
  47.      char ebuf[BUFSZ];         /* Buffer for initial engraving text */
  48.      char fbuf[BUFSZ];         /* Buffer for "your fingers" */
  49.      char qbuf[QBUFSZ];        /* Buffer for query text */
  50.      char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */
  51.      const char *everb;          /* Present tense of engraving type */
  52.      const char *eloc; /* Where the engraving is (ie dust/floor/...) */
  53.      char *sp;         /* Place holder for space count of engr text */
  54.      int len;          /* # of nonspace chars of new engraving text */
  55.      int maxelen;      /* Max allowable length of engraving text */
  56.      struct engr *oep = engr_at(u.ux, u.uy);
  57.      /* The current engraving */
  58.      struct obj *otmp; /* Object selected with which to engrave */
  59.      char *writer;
  60.  
  61.      multi = 0;              /* moves consumed */
  62.      nomovemsg = (char *) 0; /* occupation end message */
  63.  
  64.      buf[0] = (char) 0;
  65.      ebuf[0] = (char) 0;
  66.      post_engr_text[0] = (char) 0;
  67.      maxelen = BUFSZ - 1;
  68.      if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
  69.          type = ENGR_BLOOD;
  70.  
  71.      /* Can the adventurer engrave at all? */
  72.  
  73.      if (u.uswallow) {
  74.          if (is_animal(u.ustuck->data)) {
  75.              pline("What would you write?  \"Jonah was here\"?");
  76.              return 0;
  77.          } else if (is_whirly(u.ustuck->data)) {
  78.              cant_reach_floor(u.ux, u.uy, FALSE, FALSE);
  79.              return 0;
  80.          } else
  81.              jello = TRUE;
  82.      } else if (is_lava(u.ux, u.uy)) {
  83.          You_cant("write on the %s!", surface(u.ux, u.uy));
  84.          return 0;
  85.      } else if (is_pool(u.ux, u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
  86.          You_cant("write on the %s!", surface(u.ux, u.uy));
  87.          return 0;
  88.      }
  89.      if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) /* in bubble */) {
  90.          You_cant("write in thin air!");
  91.          return 0;
  92.      } else if (!accessible(u.ux, u.uy)) {
  93.          /* stone, tree, wall, secret corridor, pool, lava, bars */
  94.          You_cant("write here.");
  95.          return 0;
  96.      }
  97.      if (cantwield(youmonst.data)) {
  98.          You_cant("even hold anything!");
  99.          return 0;
  100.      }
  101.      if (check_capacity((char *) 0))
  102.          return 0;
  103.  
  104.      /* One may write with finger, or weapon, or wand, or..., or...
  105.       * Edited by GAN 10/20/86 so as not to change weapon wielded.
  106.       */
  107.  
  108.      otmp = getobj(styluses, "write with");
  109.      if (!otmp) /* otmp == zeroobj if fingers */
  110.          return 0;
  111.  
  112.      if (otmp == &zeroobj) {
  113.          Strcat(strcpy(fbuf, "your "), makeplural(body_part(FINGER)));
  114.          writer = fbuf;
  115.      } else
  116.          writer = yname(otmp);
  117.  
  118.      /* There's no reason you should be able to write with a wand
  119.       * while both your hands are tied up.
  120.       */
  121.      if (!freehand() && otmp != uwep && !otmp->owornmask) {
  122.          You("have no free %s to write with!", body_part(HAND));
  123.          return 0;
  124.      }
  125.  
  126.      if (jello) {
  127.          You("tickle %s with %s.", mon_nam(u.ustuck), writer);
  128.          Your("message dissolves...");
  129.          return 0;
  130.      }
  131.      if (otmp->oclass != WAND_CLASS && !can_reach_floor(TRUE)) {
  132.          cant_reach_floor(u.ux, u.uy, FALSE, TRUE);
  133.          return 0;
  134.      }
  135.      if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
  136.          You("make a motion towards the altar with %s.", writer);
  137.          altar_wrath(u.ux, u.uy);
  138.          return 0;
  139.      }
  140.      if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
  141.          if (otmp == &zeroobj) { /* using only finger */
  142.              You("would only make a small smudge on the %s.",
  143.                  surface(u.ux, u.uy));
  144.              return 0;
  145.          } else if (!levl[u.ux][u.uy].disturbed) {
  146.              You("disturb the undead!");
  147.              levl[u.ux][u.uy].disturbed = 1;
  148.              (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
  149.              exercise(A_WIS, FALSE);
  150.              return 1;
  151.          }
  152.      }
  153.  
  154.      /* SPFX for items */
  155.  
  156.      switch (otmp->oclass) {
  157.      default:
  158.      case AMULET_CLASS:
  159.      case CHAIN_CLASS:
  160.      case POTION_CLASS:
  161.      case COIN_CLASS:
  162.          break;
  163.      case RING_CLASS:
  164.          /* "diamond" rings and others should work */
  165.      case GEM_CLASS:
  166.          /* diamonds & other hard gems should work */
  167.          if (objects[otmp->otyp].oc_tough) {
  168.              type = ENGRAVE;
  169.              break;
  170.          }
  171.          break;
  172.      case ARMOR_CLASS:
  173.          if (is_boots(otmp)) {
  174.              type = DUST;
  175.              break;
  176.          }
  177.          /*FALLTHRU*/
  178.      /* Objects too large to engrave with */
  179.      case BALL_CLASS:
  180.      case ROCK_CLASS:
  181.          You_cant("engrave with such a large object!");
  182.          ptext = FALSE;
  183.          break;
  184.      /* Objects too silly to engrave with */
  185.      case FOOD_CLASS:
  186.      case SCROLL_CLASS:
  187.      case SPBOOK_CLASS:
  188.          pline("%s would get %s.", Yname2(otmp),
  189.                is_ice(u.ux, u.uy) ? "all frosty" : "too dirty");
  190.          ptext = FALSE;
  191.          break;
  192.      case RANDOM_CLASS: /* This should mean fingers */
  193.          break;
  194.  
  195.      /* The charge is removed from the wand before prompting for
  196.       * the engraving text, because all kinds of setup decisions
  197.       * and pre-engraving messages are based upon knowing what type
  198.       * of engraving the wand is going to do.  Also, the player
  199.       * will have potentially seen "You wrest .." message, and
  200.       * therefore will know they are using a charge.
  201.       */
  202.      case WAND_CLASS:
  203.          if (zappable(otmp)) {
  204.              check_unpaid(otmp);
  205.              if (otmp->cursed && !rn2(WAND_BACKFIRE_CHANCE)) {
  206.                  wand_explode(otmp, 0);
  207.                  return 1;
  208.              }
  209.              zapwand = TRUE;
  210.              if (!can_reach_floor(TRUE))
  211.                  ptext = FALSE;
  212.  
  213.              switch (otmp->otyp) {
  214.              /* DUST wands */
  215.              default:
  216.                  break;
  217.              /* NODIR wands */
  218.              case WAN_LIGHT:
  219.              case WAN_SECRET_DOOR_DETECTION:
  220.              case WAN_CREATE_MONSTER:
  221.              case WAN_WISHING:
  222.              case WAN_ENLIGHTENMENT:
  223.                  zapnodir(otmp);
  224.                  break;
  225.              /* IMMEDIATE wands */
  226.              /* If wand is "IMMEDIATE", remember to affect the
  227.               * previous engraving even if turning to dust.
  228.               */
  229.              case WAN_STRIKING:
  230.                  Strcpy(post_engr_text,
  231.                      "The wand unsuccessfully fights your attempt to write!");
  232.                  break;
  233.              case WAN_SLOW_MONSTER:
  234.                  if (!Blind) {
  235.                      Sprintf(post_engr_text, "The bugs on the %s slow down!",
  236.                              surface(u.ux, u.uy));
  237.                  }
  238.                  break;
  239.              case WAN_SPEED_MONSTER:
  240.                  if (!Blind) {
  241.                      Sprintf(post_engr_text, "The bugs on the %s speed up!",
  242.                              surface(u.ux, u.uy));
  243.                  }
  244.                  break;
  245.              case WAN_POLYMORPH:
  246.                  if (oep) {
  247.                      if (!Blind) {
  248.                          type = (xchar) 0; /* random */
  249.                          (void) random_engraving(buf);
  250.                      }
  251.                      dengr = TRUE;
  252.                  }
  253.                  break;
  254.              case WAN_NOTHING:
  255.              case WAN_UNDEAD_TURNING:
  256.              case WAN_OPENING:
  257.              case WAN_LOCKING:
  258.              case WAN_PROBING:
  259.                  break;
  260.              /* RAY wands */
  261.              case WAN_MAGIC_MISSILE:
  262.                  ptext = TRUE;
  263.                  if (!Blind) {
  264.                      Sprintf(post_engr_text,
  265.                              "The %s is riddled by bullet holes!",
  266.                              surface(u.ux, u.uy));
  267.                  }
  268.                  break;
  269.              /* can't tell sleep from death - Eric Backus */
  270.              case WAN_SLEEP:
  271.              case WAN_DEATH:
  272.                  if (!Blind) {
  273.                      Sprintf(post_engr_text, "The bugs on the %s stop moving!",
  274.                              surface(u.ux, u.uy));
  275.                  }
  276.                  break;
  277.              case WAN_COLD:
  278.                  if (!Blind)
  279.                      Strcpy(post_engr_text,
  280.                             "A few ice cubes drop from the wand.");
  281.                  if (!oep || (oep->engr_type != BURN))
  282.                      break;
  283.              case WAN_CANCELLATION:
  284.              case WAN_MAKE_INVISIBLE:
  285.                  if (oep && oep->engr_type != HEADSTONE) {
  286.                      if (!Blind)
  287.                          pline_The("engraving on the %s vanishes!",
  288.                                    surface(u.ux, u.uy));
  289.                      dengr = TRUE;
  290.                  }
  291.                  break;
  292.              case WAN_TELEPORTATION:
  293.                  if (oep && oep->engr_type != HEADSTONE) {
  294.                      if (!Blind)
  295.                          pline_The("engraving on the %s vanishes!",
  296.                                    surface(u.ux, u.uy));
  297.                      teleengr = TRUE;
  298.                  }
  299.                  break;
  300.              /* type = ENGRAVE wands */
  301.              case WAN_DIGGING:
  302.                  ptext = TRUE;
  303.                  type = ENGRAVE;
  304.                  if (!objects[otmp->otyp].oc_name_known) {
  305.                      if (flags.verbose)
  306.                          pline("This %s is a wand of digging!", xname(otmp));
  307.                      doknown = TRUE;
  308.                  }
  309.                  Strcpy(post_engr_text,
  310.                         Blind
  311.                            ? "You hear drilling!"
  312.                            : IS_GRAVE(levl[u.ux][u.uy].typ)
  313.                               ? "Chips fly out from the headstone."
  314.                               : is_ice(u.ux, u.uy)
  315.                                  ? "Ice chips fly up from the ice surface!"
  316.                                  : (level.locations[u.ux][u.uy].typ
  317.                                     == DRAWBRIDGE_DOWN)
  318.                                     ? "Splinters fly up from the bridge."
  319.                                     : "Gravel flies up from the floor.");
  320.                  break;
  321.              /* type = BURN wands */
  322.              case WAN_FIRE:
  323.                  ptext = TRUE;
  324.                  type = BURN;
  325.                  if (!objects[otmp->otyp].oc_name_known) {
  326.                      if (flags.verbose)
  327.                          pline("This %s is a wand of fire!", xname(otmp));
  328.                      doknown = TRUE;
  329.                  }
  330.                  Strcpy(post_engr_text, Blind ? "You feel the wand heat up."
  331.                                               : "Flames fly from the wand.");
  332.                  break;
  333.              case WAN_LIGHTNING:
  334.                  ptext = TRUE;
  335.                  type = BURN;
  336.                  if (!objects[otmp->otyp].oc_name_known) {
  337.                      if (flags.verbose)
  338.                          pline("This %s is a wand of lightning!", xname(otmp));
  339.                      doknown = TRUE;
  340.                  }
  341.                  if (!Blind) {
  342.                      Strcpy(post_engr_text, "Lightning arcs from the wand.");
  343.                      doblind = TRUE;
  344.                  } else
  345.                      Strcpy(post_engr_text, "You hear crackling!");
  346.                  break;
  347.  
  348.              /* type = MARK wands */
  349.              /* type = ENGR_BLOOD wands */
  350.              }
  351.          } else { /* end if zappable */
  352.              /* failing to wrest one last charge takes time */
  353.              ptext = FALSE; /* use "early exit" below, return 1 */
  354.              /* give feedback here if we won't be getting the
  355.                 "can't reach floor" message below */
  356.              if (can_reach_floor(TRUE)) {
  357.                  /* cancelled wand turns to dust */
  358.                  if (otmp->spe < 0)
  359.                      zapwand = TRUE;
  360.                  /* empty wand just doesn't write */
  361.                  else
  362.                      pline_The("wand is too worn out to engrave.");
  363.              }
  364.          }
  365.          break;
  366.  
  367.      case WEAPON_CLASS:
  368.          if (is_blade(otmp)) {
  369.              if ((int) otmp->spe > -3)
  370.                  type = ENGRAVE;
  371.              else
  372.                  pline("%s too dull for engraving.", Yobjnam2(otmp, "are"));
  373.          }
  374.          break;
  375.  
  376.      case TOOL_CLASS:
  377.          if (otmp == ublindf) {
  378.              pline(
  379.                  "That is a bit difficult to engrave with, don't you think?");
  380.              return 0;
  381.          }
  382.          switch (otmp->otyp) {
  383.          case MAGIC_MARKER:
  384.              if (otmp->spe <= 0)
  385.                  Your("marker has dried out.");
  386.              else
  387.                  type = MARK;
  388.              break;
  389.          case TOWEL:
  390.              /* Can't really engrave with a towel */
  391.              ptext = FALSE;
  392.              if (oep)
  393.                  if (oep->engr_type == DUST
  394.                      || oep->engr_type == ENGR_BLOOD
  395.                      || oep->engr_type == MARK) {
  396.                      if (is_wet_towel(otmp))
  397.                          dry_a_towel(otmp, -1, TRUE);
  398.                      if (!Blind)
  399.                          You("wipe out the message here.");
  400.                      else
  401.                          pline("%s %s.", Yobjnam2(otmp, "get"),
  402.                                is_ice(u.ux, u.uy) ? "frosty" : "dusty");
  403.                      dengr = TRUE;
  404.                  } else
  405.                      pline("%s can't wipe out this engraving.", Yname2(otmp));
  406.              else
  407.                  pline("%s %s.", Yobjnam2(otmp, "get"),
  408.                        is_ice(u.ux, u.uy) ? "frosty" : "dusty");
  409.              break;
  410.          default:
  411.              break;
  412.          }
  413.          break;
  414.  
  415.      case VENOM_CLASS:
  416.          if (wizard) {
  417.              pline("Writing a poison pen letter??");
  418.              break;
  419.          }
  420.          /*FALLTHRU*/
  421.      case ILLOBJ_CLASS:
  422.          impossible("You're engraving with an illegal object!");
  423.          break;
  424.      }
  425.  
  426.      if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
  427.          if (type == ENGRAVE || type == 0) {
  428.              type = HEADSTONE;
  429.          } else {
  430.              /* ensures the "cannot wipe out" case */
  431.              type = DUST;
  432.              dengr = FALSE;
  433.              teleengr = FALSE;
  434.              buf[0] = '\0';
  435.          }
  436.      }
  437.  
  438.      /*
  439.       * End of implement setup
  440.       */
  441.  
  442.      /* Identify stylus */
  443.      if (doknown) {
  444.          learnwand(otmp);
  445.          if (objects[otmp->otyp].oc_name_known)
  446.              more_experienced(0, 10);
  447.      }
  448.      if (teleengr) {
  449.          rloc_engr(oep);
  450.          oep = (struct engr *) 0;
  451.      }
  452.      if (dengr) {
  453.          del_engr(oep);
  454.          oep = (struct engr *) 0;
  455.      }
  456.      /* Something has changed the engraving here */
  457.      if (*buf) {
  458.          make_engr_at(u.ux, u.uy, buf, moves, type);
  459.          pline_The("engraving now reads: \"%s\".", buf);
  460.          ptext = FALSE;
  461.      }
  462.      if (zapwand && (otmp->spe < 0)) {
  463.          pline("%s %sturns to dust.", The(xname(otmp)),
  464.                Blind ? "" : "glows violently, then ");
  465.          if (!IS_GRAVE(levl[u.ux][u.uy].typ))
  466.              You(
  467.      "are not going to get anywhere trying to write in the %s with your dust.",
  468.                  is_ice(u.ux, u.uy) ? "frost" : "dust");
  469.          useup(otmp);
  470.          otmp = 0; /* wand is now gone */
  471.          ptext = FALSE;
  472.      }
  473.      /* Early exit for some implements. */
  474.      if (!ptext) {
  475.          if (otmp && otmp->oclass == WAND_CLASS && !can_reach_floor(TRUE))
  476.              cant_reach_floor(u.ux, u.uy, FALSE, TRUE);
  477.          return 1;
  478.      }
  479.      /*
  480.       * Special effects should have deleted the current engraving (if
  481.       * possible) by now.
  482.       */
  483.      if (oep) {
  484.          register char c = 'n';
  485.  
  486.          /* Give player the choice to add to engraving. */
  487.          if (type == HEADSTONE) {
  488.              /* no choice, only append */
  489.              c = 'y';
  490.          } else if (type == oep->engr_type
  491.                     && (!Blind || oep->engr_type == BURN
  492.                         || oep->engr_type == ENGRAVE)) {
  493.              c = yn_function("Do you want to add to the current engraving?",
  494.                              ynqchars, 'y');
  495.              if (c == 'q') {
  496.                  pline1(Never_mind);
  497.                  return 0;
  498.              }
  499.          }
  500.  
  501.          if (c == 'n' || Blind) {
  502.              if (oep->engr_type == DUST
  503.                  || oep->engr_type == ENGR_BLOOD
  504.                  || oep->engr_type == MARK) {
  505.                  if (!Blind) {
  506.                      You("wipe out the message that was %s here.",
  507.                          (oep->engr_type == DUST)
  508.                              ? "written in the dust"
  509.                              : (oep->engr_type == ENGR_BLOOD)
  510.                                  ? "scrawled in blood"
  511.                                  : "written");
  512.                      del_engr(oep);
  513.                      oep = (struct engr *) 0;
  514.                  } else
  515.                      /* Don't delete engr until after we *know* we're engraving
  516.                       */
  517.                      eow = TRUE;
  518.              } else if (type == DUST || type == MARK || type == ENGR_BLOOD) {
  519.                  You("cannot wipe out the message that is %s the %s here.",
  520.                      oep->engr_type == BURN
  521.                          ? (is_ice(u.ux, u.uy) ? "melted into" : "burned into")
  522.                          : "engraved in",
  523.                      surface(u.ux, u.uy));
  524.                  return 1;
  525.              } else if (type != oep->engr_type || c == 'n') {
  526.                  if (!Blind || can_reach_floor(TRUE))
  527.                      You("will overwrite the current message.");
  528.                  eow = TRUE;
  529.              }
  530.          }
  531.      }
  532.  
  533.      eloc = surface(u.ux, u.uy);
  534.      switch (type) {
  535.      default:
  536.          everb = (oep && !eow ? "add to the weird writing on"
  537.                               : "write strangely on");
  538.          break;
  539.      case DUST:
  540.          everb = (oep && !eow ? "add to the writing in" : "write in");
  541.          eloc = is_ice(u.ux, u.uy) ? "frost" : "dust";
  542.          break;
  543.      case HEADSTONE:
  544.          everb = (oep && !eow ? "add to the epitaph on" : "engrave on");
  545.          break;
  546.      case ENGRAVE:
  547.          everb = (oep && !eow ? "add to the engraving in" : "engrave in");
  548.          break;
  549.      case BURN:
  550.          everb = (oep && !eow
  551.                       ? (is_ice(u.ux, u.uy) ? "add to the text melted into"
  552.                                             : "add to the text burned into")
  553.                       : (is_ice(u.ux, u.uy) ? "melt into" : "burn into"));
  554.          break;
  555.      case MARK:
  556.          everb = (oep && !eow ? "add to the graffiti on" : "scribble on");
  557.          break;
  558.      case ENGR_BLOOD:
  559.          everb = (oep && !eow ? "add to the scrawl on" : "scrawl on");
  560.          break;
  561.      }
  562.  
  563.      /* Tell adventurer what is going on */
  564.      if (otmp != &zeroobj)
  565.          You("%s the %s with %s.", everb, eloc, doname(otmp));
  566.      else
  567.          You("%s the %s with your %s.", everb, eloc,
  568.              makeplural(body_part(FINGER)));
  569.  
  570.      /* Prompt for engraving! */
  571.      Sprintf(qbuf, "What do you want to %s the %s here?", everb, eloc);
  572.      getlin(qbuf, ebuf);
  573.      /* convert tabs to spaces and condense consecutive spaces to one */
  574.      mungspaces(ebuf);
  575.  
  576.      /* Count the actual # of chars engraved not including spaces */
  577.      len = strlen(ebuf);
  578.      for (sp = ebuf; *sp; sp++)
  579.          if (*sp == ' ')
  580.              len -= 1;
  581.  
  582.      if (len == 0 || index(ebuf, '\033')) {
  583.          if (zapwand) {
  584.              if (!Blind)
  585.                  pline("%s, then %s.", Tobjnam(otmp, "glow"),
  586.                        otense(otmp, "fade"));
  587.              return 1;
  588.          } else {
  589.              pline1(Never_mind);
  590.              return 0;
  591.          }
  592.      }
  593.  
  594.      /* A single `x' is the traditional signature of an illiterate person */
  595.      if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X')))
  596.          u.uconduct.literate++;
  597.  
  598.      /* Mix up engraving if surface or state of mind is unsound.
  599.         Note: this won't add or remove any spaces. */
  600.      for (sp = ebuf; *sp; sp++) {
  601.          if (*sp == ' ')
  602.              continue;
  603.          if (((type == DUST || type == ENGR_BLOOD) && !rn2(25))
  604.              || (Blind && !rn2(11)) || (Confusion && !rn2(7))
  605.              || (Stunned && !rn2(4)) || (Hallucination && !rn2(2)))
  606.              *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~'
  607.                                          (excludes ' ' and DEL) */
  608.      }
  609.  
  610.      /* Previous engraving is overwritten */
  611.      if (eow) {
  612.          del_engr(oep);
  613.          oep = (struct engr *) 0;
  614.      }
  615.  
  616.      /* Figure out how long it took to engrave, and if player has
  617.       * engraved too much.
  618.       */
  619.      switch (type) {
  620.      default:
  621.          multi = -(len / 10);
  622.          if (multi)
  623.              nomovemsg = "You finish your weird engraving.";
  624.          break;
  625.      case DUST:
  626.          multi = -(len / 10);
  627.          if (multi)
  628.              nomovemsg = "You finish writing in the dust.";
  629.          break;
  630.      case HEADSTONE:
  631.      case ENGRAVE:
  632.          multi = -(len / 10);
  633.          if (otmp->oclass == WEAPON_CLASS
  634.              && (otmp->otyp != ATHAME || otmp->cursed)) {
  635.              multi = -len;
  636.              maxelen = ((otmp->spe + 3) * 2) + 1;
  637.              /* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
  638.               * Note: this does not allow a +0 anything (except an athame)
  639.               * to engrave "Elbereth" all at once.
  640.               * However, you can engrave "Elb", then "ere", then "th".
  641.               */
  642.              pline("%s dull.", Yobjnam2(otmp, "get"));
  643.              costly_alteration(otmp, COST_DEGRD);
  644.              if (len > maxelen) {
  645.                  multi = -maxelen;
  646.                  otmp->spe = -3;
  647.              } else if (len > 1)
  648.                  otmp->spe -= len >> 1;
  649.              else
  650.                  otmp->spe -= 1; /* Prevent infinite engraving */
  651.          } else if (otmp->oclass == RING_CLASS || otmp->oclass == GEM_CLASS) {
  652.              multi = -len;
  653.          }
  654.          if (multi)
  655.              nomovemsg = "You finish engraving.";
  656.          break;
  657.      case BURN:
  658.          multi = -(len / 10);
  659.          if (multi)
  660.              nomovemsg = is_ice(u.ux, u.uy)
  661.                            ? "You finish melting your message into the ice."
  662.                            : "You finish burning your message into the floor.";
  663.          break;
  664.      case MARK:
  665.          multi = -(len / 10);
  666.          if (otmp->otyp == MAGIC_MARKER) {
  667.              maxelen = otmp->spe * 2; /* one charge / 2 letters */
  668.              if (len > maxelen) {
  669.                  Your("marker dries out.");
  670.                  otmp->spe = 0;
  671.                  multi = -(maxelen / 10);
  672.              } else if (len > 1)
  673.                  otmp->spe -= len >> 1;
  674.              else
  675.                  otmp->spe -= 1; /* Prevent infinite graffiti */
  676.          }
  677.          if (multi)
  678.              nomovemsg = "You finish defacing the dungeon.";
  679.          break;
  680.      case ENGR_BLOOD:
  681.          multi = -(len / 10);
  682.          if (multi)
  683.              nomovemsg = "You finish scrawling.";
  684.          break;
  685.      }
  686.  
  687.      /* Chop engraving down to size if necessary */
  688.      if (len > maxelen) {
  689.          for (sp = ebuf; maxelen && *sp; sp++)
  690.              if (*sp == ' ')
  691.                  maxelen--;
  692.          if (!maxelen && *sp) {
  693.              *sp = '\0';
  694.              if (multi)
  695.                  nomovemsg = "You cannot write any more.";
  696.              You("are only able to write \"%s\".", ebuf);
  697.          }
  698.      }
  699.  
  700.      if (oep) /* add to existing engraving */
  701.          Strcpy(buf, oep->engr_txt);
  702.      (void) strncat(buf, ebuf, BUFSZ - (int) strlen(buf) - 1);
  703.      /* Put the engraving onto the map */
  704.      make_engr_at(u.ux, u.uy, buf, moves - multi, type);
  705.  
  706.      if (post_engr_text[0])
  707.          pline("%s", post_engr_text);
  708.      if (doblind && !resists_blnd(&youmonst)) {
  709.          You("are blinded by the flash!");
  710.          make_blinded((long) rnd(50), FALSE);
  711.          if (!Blind)
  712.              Your1(vision_clears);
  713.      }
  714.      return 1;
  715.  }
  716.  

sanitize_engravings

  1.  /* while loading bones, clean up text which might accidentally
  2.     or maliciously disrupt player's terminal when displayed */
  3.  void
  4.  sanitize_engravings()
  5.  {
  6.      struct engr *ep;
  7.  
  8.      for (ep = head_engr; ep; ep = ep->nxt_engr) {
  9.          sanitize_name(ep->engr_txt);
  10.      }
  11.  }
  12.  

save_engravings

  1.  void
  2.  save_engravings(fd, mode)
  3.  int fd, mode;
  4.  {
  5.      struct engr *ep, *ep2;
  6.      unsigned no_more_engr = 0;
  7.  
  8.      for (ep = head_engr; ep; ep = ep2) {
  9.          ep2 = ep->nxt_engr;
  10.          if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) {
  11.              bwrite(fd, (genericptr_t) &ep->engr_lth, sizeof ep->engr_lth);
  12.              bwrite(fd, (genericptr_t) ep, sizeof (struct engr) + ep->engr_lth);
  13.          }
  14.          if (release_data(mode))
  15.              dealloc_engr(ep);
  16.      }
  17.      if (perform_bwrite(mode))
  18.          bwrite(fd, (genericptr_t) &no_more_engr, sizeof no_more_engr);
  19.      if (release_data(mode))
  20.          head_engr = 0;
  21.  }
  22.  

rest_engravings

  1.  void
  2.  rest_engravings(fd)
  3.  int fd;
  4.  {
  5.      struct engr *ep;
  6.      unsigned lth;
  7.  
  8.      head_engr = 0;
  9.      while (1) {
  10.          mread(fd, (genericptr_t) &lth, sizeof lth);
  11.          if (lth == 0)
  12.              return;
  13.          ep = newengr(lth);
  14.          mread(fd, (genericptr_t) ep, sizeof (struct engr) + lth);
  15.          ep->nxt_engr = head_engr;
  16.          head_engr = ep;
  17.          ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */
  18.          /* Mark as finished for bones levels -- no problem for
  19.           * normal levels as the player must have finished engraving
  20.           * to be able to move again.
  21.           */
  22.          ep->engr_time = moves;
  23.      }
  24.  }
  25.  

del_engr

  1.  void
  2.  del_engr(ep)
  3.  register struct engr *ep;
  4.  {
  5.      if (ep == head_engr) {
  6.          head_engr = ep->nxt_engr;
  7.      } else {
  8.          register struct engr *ept;
  9.  
  10.          for (ept = head_engr; ept; ept = ept->nxt_engr)
  11.              if (ept->nxt_engr == ep) {
  12.                  ept->nxt_engr = ep->nxt_engr;
  13.                  break;
  14.              }
  15.          if (!ept) {
  16.              impossible("Error in del_engr?");
  17.              return;
  18.          }
  19.      }
  20.      dealloc_engr(ep);
  21.  }
  22.  

rloc_engr

  1.  /* randomly relocate an engraving */
  2.  void
  3.  rloc_engr(ep)
  4.  struct engr *ep;
  5.  {
  6.      int tx, ty, tryct = 200;
  7.  
  8.      do {
  9.          if (--tryct < 0)
  10.              return;
  11.          tx = rn1(COLNO - 3, 2);
  12.          ty = rn2(ROWNO);
  13.      } while (engr_at(tx, ty) || !goodpos(tx, ty, (struct monst *) 0, 0));
  14.  
  15.      ep->engr_x = tx;
  16.      ep->engr_y = ty;
  17.  }
  18.  

make_grave

  1.  /* Create a headstone at the given location.
  2.   * The caller is responsible for newsym(x, y).
  3.   */
  4.  void
  5.  make_grave(x, y, str)
  6.  int x, y;
  7.  const char *str;
  8.  {
  9.      char buf[BUFSZ];
  10.  
  11.      /* Can we put a grave here? */
  12.      if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x, y))
  13.          return;
  14.      /* Make the grave */
  15.      levl[x][y].typ = GRAVE;
  16.      /* Engrave the headstone */
  17.      del_engr_at(x, y);
  18.      if (!str)
  19.          str = get_rnd_text(EPITAPHFILE, buf);
  20.      make_engr_at(x, y, str, 0L, HEADSTONE);
  21.      return;
  22.  }
  23.  
  24.  /*engrave.c*/