Source:NetHack 3.6.1/src/display.c

From NetHackWiki
(Redirected from Source:Ref/feel location)
Jump to: navigation, search

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

Top of file

  1.  /* NetHack 3.6	display.c	$NHDT-Date: 1524780381 2018/04/26 22:06:21 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */
  2.  /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
  3.  /* and Dave Cohrs, 1990.                                          */
  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.  /*
  3.   *                      THE NEW DISPLAY CODE
  4.   *
  5.   * The old display code has been broken up into three parts: vision, display,
  6.   * and drawing.  Vision decides what locations can and cannot be physically
  7.   * seen by the hero.  Display decides _what_ is displayed at a given location.
  8.   * Drawing decides _how_ to draw a monster, fountain, sword, etc.
  9.   *
  10.   * The display system uses information from the vision system to decide
  11.   * what to draw at a given location.  The routines for the vision system
  12.   * can be found in vision.c and vision.h.  The routines for display can
  13.   * be found in this file (display.c) and display.h.  The drawing routines
  14.   * are part of the window port.  See doc/window.doc for the drawing
  15.   * interface.
  16.   *
  17.   * The display system deals with an abstraction called a glyph.  Anything
  18.   * that could possibly be displayed has a unique glyph identifier.
  19.   *
  20.   * What is seen on the screen is a combination of what the hero remembers
  21.   * and what the hero currently sees.  Objects and dungeon features (walls
  22.   * doors, etc) are remembered when out of sight.  Monsters and temporary
  23.   * effects are not remembered.  Each location on the level has an
  24.   * associated glyph.  This is the hero's _memory_ of what he or she has
  25.   * seen there before.
  26.   *
  27.   * Display rules:
  28.   *
  29.   *      If the location is in sight, display in order:
  30.   *              visible (or sensed) monsters
  31.   *              visible objects
  32.   *              known traps
  33.   *              background
  34.   *
  35.   *      If the location is out of sight, display in order:
  36.   *              sensed monsters (telepathy)
  37.   *              memory
  38.   *
  39.   *
  40.   *
  41.   * Here is a list of the major routines in this file to be used externally:
  42.   *
  43.   * newsym
  44.   *
  45.   * Possibly update the screen location (x,y).  This is the workhorse routine.
  46.   * It is always correct --- where correct means following the in-sight/out-
  47.   * of-sight rules.  **Most of the code should use this routine.**  This
  48.   * routine updates the map and displays monsters.
  49.   *
  50.   *
  51.   * map_background
  52.   * map_object
  53.   * map_trap
  54.   * map_invisible
  55.   * unmap_object
  56.   *
  57.   * If you absolutely must override the in-sight/out-of-sight rules, there
  58.   * are two possibilities.  First, you can mess with vision to force the
  59.   * location in sight then use newsym(), or you can  use the map_* routines.
  60.   * The first has not been tried [no need] and the second is used in the
  61.   * detect routines --- detect object, magic mapping, etc.  The map_*
  62.   * routines *change* what the hero remembers.  All changes made by these
  63.   * routines will be sticky --- they will survive screen redraws.  Do *not*
  64.   * use these for things that only temporarily change the screen.  These
  65.   * routines are also used directly by newsym().  unmap_object is used to
  66.   * clear a remembered object when/if detection reveals it isn't there.
  67.   *
  68.   *
  69.   * show_glyph
  70.   *
  71.   * This is direct (no processing in between) buffered access to the screen.
  72.   * Temporary screen effects are run through this and its companion,
  73.   * flush_screen().  There is yet a lower level routine, print_glyph(),
  74.   * but this is unbuffered and graphic dependent (i.e. it must be surrounded
  75.   * by graphic set-up and tear-down routines).  Do not use print_glyph().
  76.   *
  77.   *
  78.   * see_monsters
  79.   * see_objects
  80.   * see_traps
  81.   *
  82.   * These are only used when something affects all of the monsters or
  83.   * objects or traps.  For objects and traps, the only thing is hallucination.
  84.   * For monsters, there are hallucination and changing from/to blindness, etc.
  85.   *
  86.   *
  87.   * tmp_at
  88.   *
  89.   * This is a useful interface for displaying temporary items on the screen.
  90.   * Its interface is different than previously, so look at it carefully.
  91.   *
  92.   *
  93.   *
  94.   * Parts of the rm structure that are used:
  95.   *
  96.   *      typ     - What is really there.
  97.   *      glyph   - What the hero remembers.  This will never be a monster.
  98.   *                Monsters "float" above this.
  99.   *      lit     - True if the position is lit.  An optimization for
  100.   *                lit/unlit rooms.
  101.   *      waslit  - True if the position was *remembered* as lit.
  102.   *      seenv   - A vector of bits representing the directions from which the
  103.   *                hero has seen this position.  The vector's primary use is
  104.   *                determining how walls are seen.  E.g. a wall sometimes looks
  105.   *                like stone on one side, but is seen as wall from the other.
  106.   *                Other uses are for unmapping detected objects and felt
  107.   *                locations, where we need to know if the hero has ever
  108.   *                seen the location.
  109.   *      flags   - Additional information for the typ field.  Different for
  110.   *                each typ.
  111.   *      horizontal - Indicates whether the wall or door is horizontal or
  112.   *                vertical.
  113.   */
  114.  #include "hack.h"
  115.  
  116.  STATIC_DCL void FDECL(display_monster,
  117.                        (XCHAR_P, XCHAR_P, struct monst *, int, XCHAR_P));
  118.  STATIC_DCL int FDECL(swallow_to_glyph, (int, int));
  119.  STATIC_DCL void FDECL(display_warning, (struct monst *));
  120.  
  121.  STATIC_DCL int FDECL(check_pos, (int, int, int));
  122.  STATIC_DCL int FDECL(get_bk_glyph, (XCHAR_P, XCHAR_P));
  123.  
  124.  /*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */
  125.  #ifdef WA_VERBOSE
  126.  STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int));
  127.  #endif
  128.  
  129.  STATIC_DCL int FDECL(set_twall, (int, int, int, int, int, int, int, int));
  130.  STATIC_DCL int FDECL(set_wall, (int, int, int));
  131.  STATIC_DCL int FDECL(set_corn, (int, int, int, int, int, int, int, int));
  132.  STATIC_DCL int FDECL(set_crosswall, (int, int));
  133.  STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int));
  134.  STATIC_DCL void FDECL(t_warn, (struct rm *));
  135.  STATIC_DCL int FDECL(wall_angle, (struct rm *));
  136.  
  137.  #define remember_topology(x, y) (lastseentyp[x][y] = levl[x][y].typ)
  138.  

magic_map_background

  1.  /*
  2.   * magic_map_background()
  3.   *
  4.   * This function is similar to map_background (see below) except we pay
  5.   * attention to and correct unexplored, lit ROOM and CORR spots.
  6.   */
  7.  void
  8.  magic_map_background(x, y, show)
  9.  xchar x, y;
  10.  int show;
  11.  {
  12.      int glyph = back_to_glyph(x, y); /* assumes hero can see x,y */
  13.      struct rm *lev = &levl[x][y];
  14.  
  15.      /*
  16.       * Correct for out of sight lit corridors and rooms that the hero
  17.       * doesn't remember as lit.
  18.       */
  19.      if (!cansee(x, y) && !lev->waslit) {
  20.          /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
  21.          if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room))
  22.              glyph = cmap_to_glyph((flags.dark_room && iflags.use_color)
  23.                                        ? (DARKROOMSYM)
  24.                                        : S_stone);
  25.          else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr))
  26.              glyph = cmap_to_glyph(S_corr);
  27.      }
  28.      if (level.flags.hero_memory)
  29.          lev->glyph = glyph;
  30.      if (show)
  31.          show_glyph(x, y, glyph);
  32.  
  33.      remember_topology(x, y);
  34.  }
  35.  
  36.  /*
  37.   * The routines map_background(), map_object(), and map_trap() could just
  38.   * as easily be:
  39.   *
  40.   *      map_glyph(x,y,glyph,show)
  41.   *
  42.   * Which is called with the xx_to_glyph() in the call.  Then I can get
  43.   * rid of 3 routines that don't do very much anyway.  And then stop
  44.   * having to create fake objects and traps.  However, I am reluctant to
  45.   * make this change.
  46.   */
  47.  /* FIXME: some of these use xchars for x and y, and some use ints.  Make
  48.   * this consistent.
  49.   */
  50.  

map_background

  1.  /*
  2.   * map_background()
  3.   *
  4.   * Make the real background part of our map.  This routine assumes that
  5.   * the hero can physically see the location.  Update the screen if directed.
  6.   */
  7.  void
  8.  map_background(x, y, show)
  9.  register xchar x, y;
  10.  register int show;
  11.  {
  12.      register int glyph = back_to_glyph(x, y);
  13.  
  14.      if (level.flags.hero_memory)
  15.          levl[x][y].glyph = glyph;
  16.      if (show)
  17.          show_glyph(x, y, glyph);
  18.  }
  19.  

map_trap

  1.  /*
  2.   * map_trap()
  3.   *
  4.   * Map the trap and print it out if directed.  This routine assumes that the
  5.   * hero can physically see the location.
  6.   */
  7.  void
  8.  map_trap(trap, show)
  9.  register struct trap *trap;
  10.  register int show;
  11.  {
  12.      register int x = trap->tx, y = trap->ty;
  13.      register int glyph = trap_to_glyph(trap);
  14.  
  15.      if (level.flags.hero_memory)
  16.          levl[x][y].glyph = glyph;
  17.      if (show)
  18.          show_glyph(x, y, glyph);
  19.  }
  20.  

map_object

  1.  /*
  2.   * map_object()
  3.   *
  4.   * Map the given object.  This routine assumes that the hero can physically
  5.   * see the location of the object.  Update the screen if directed.
  6.   */
  7.  void
  8.  map_object(obj, show)
  9.  register struct obj *obj;
  10.  register int show;
  11.  {
  12.      register int x = obj->ox, y = obj->oy;
  13.      register int glyph = obj_to_glyph(obj);
  14.  
  15.      if (level.flags.hero_memory) {
  16.          /* MRKR: While hallucinating, statues are seen as random monsters */
  17.          /*       but remembered as random objects.                        */
  18.  
  19.          if (Hallucination && obj->otyp == STATUE) {
  20.              levl[x][y].glyph = random_obj_to_glyph();
  21.          } else {
  22.              levl[x][y].glyph = glyph;
  23.          }
  24.      }
  25.      if (show)
  26.          show_glyph(x, y, glyph);
  27.  }
  28.  

map_invisible

  1.  /*
  2.   * map_invisible()
  3.   *
  4.   * Make the hero remember that a square contains an invisible monster.
  5.   * This is a special case in that the square will continue to be displayed
  6.   * this way even when the hero is close enough to see it.  To get rid of
  7.   * this and display the square's actual contents, use unmap_object() followed
  8.   * by newsym() if necessary.
  9.   */
  10.  void
  11.  map_invisible(x, y)
  12.  register xchar x, y;
  13.  {
  14.      if (x != u.ux || y != u.uy) { /* don't display I at hero's location */
  15.          if (level.flags.hero_memory)
  16.              levl[x][y].glyph = GLYPH_INVISIBLE;
  17.          show_glyph(x, y, GLYPH_INVISIBLE);
  18.      }
  19.  }
  20.  

unmap_invisible

  1.  boolean
  2.  unmap_invisible(x, y)
  3.  int x, y;
  4.  {
  5.      if (isok(x,y) && glyph_is_invisible(levl[x][y].glyph)) {
  6.          unmap_object(x, y);
  7.          newsym(x, y);
  8.          return TRUE;
  9.      }
  10.      return FALSE;
  11.  }
  12.  
  13.  

unmap_object

  1.  /*
  2.   * unmap_object()
  3.   *
  4.   * Remove something from the map when the hero realizes it's not there any
  5.   * more.  Replace it with background or known trap, but not with any other
  6.   * If this is used for detection, a full screen update is imminent anyway;
  7.   * if this is used to get rid of an invisible monster notation, we might have
  8.   * to call newsym().
  9.   */
  10.  void
  11.  unmap_object(x, y)
  12.  register int x, y;
  13.  {
  14.      register struct trap *trap;
  15.  
  16.      if (!level.flags.hero_memory)
  17.          return;
  18.  
  19.      if ((trap = t_at(x, y)) != 0 && trap->tseen && !covers_traps(x, y))
  20.          map_trap(trap, 0);
  21.      else if (levl[x][y].seenv) {
  22.          struct rm *lev = &levl[x][y];
  23.  
  24.          map_background(x, y, 0);
  25.  
  26.          /* turn remembered dark room squares dark */
  27.          if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room)
  28.              && lev->typ == ROOM)
  29.              lev->glyph = cmap_to_glyph(S_stone);
  30.      } else
  31.          levl[x][y].glyph = cmap_to_glyph(S_stone); /* default val */
  32.  }
  33.  

map_location

  1.  /*
  2.   * map_location()
  3.   *
  4.   * Make whatever at this location show up.  This is only for non-living
  5.   * things.  This will not handle feeling invisible objects correctly.
  6.   *
  7.   * Internal to display.c, this is a #define for speed.
  8.   */
  9.  #define _map_location(x, y, show)                                           \
  10.      {                                                                       \
  11.          register struct obj *obj;                                           \
  12.          register struct trap *trap;                                         \
  13.                                                                              \
  14.          if ((obj = vobj_at(x, y)) && !covers_objects(x, y))                 \
  15.              map_object(obj, show);                                          \
  16.          else if ((trap = t_at(x, y)) && trap->tseen && !covers_traps(x, y)) \
  17.              map_trap(trap, show);                                           \
  18.          else                                                                \
  19.              map_background(x, y, show);                                     \
  20.                                                                              \
  21.          remember_topology(x, y);                                            \
  22.      }
  23.  
  24.  void
  25.  map_location(x, y, show)
  26.  int x, y, show;
  27.  {
  28.      _map_location(x, y, show);
  29.  }
  30.  
  31.  #define DETECTED 2
  32.  #define PHYSICALLY_SEEN 1
  33.  #define is_worm_tail(mon) ((mon) && ((x != (mon)->mx) || (y != (mon)->my)))
  34.  

display_monster

  1.  /*
  2.   * display_monster()
  3.   *
  4.   * Note that this is *not* a map_XXXX() function!  Monsters sort of float
  5.   * above everything.
  6.   *
  7.   * Yuck.  Display body parts by recognizing that the display position is
  8.   * not the same as the monster position.  Currently the only body part is
  9.   * a worm tail.
  10.   *
  11.   */
  12.  STATIC_OVL void
  13.  display_monster(x, y, mon, sightflags, worm_tail)
  14.  register xchar x, y;        /* display position */
  15.  register struct monst *mon; /* monster to display */
  16.  int sightflags;             /* 1 if the monster is physically seen;
  17.                                 2 if detected using Detect_monsters */
  18.  xchar worm_tail;            /* mon is actually a worm tail */
  19.  {
  20.      boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
  21.      int sensed = (mon_mimic && (Protection_from_shape_changers
  22.                                  || sensemon(mon)));
  23.      /*
  24.       * We must do the mimic check first.  If the mimic is mimicing something,
  25.       * and the location is in sight, we have to change the hero's memory
  26.       * so that when the position is out of sight, the hero remembers what
  27.       * the mimic was mimicing.
  28.       */
  29.  
  30.      if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) {
  31.          switch (mon->m_ap_type) {
  32.          default:
  33.              impossible("display_monster:  bad m_ap_type value [ = %d ]",
  34.                         (int) mon->m_ap_type);
  35.              /*FALLTHRU*/
  36.          case M_AP_NOTHING:
  37.              show_glyph(x, y, mon_to_glyph(mon));
  38.              break;
  39.  
  40.          case M_AP_FURNITURE: {
  41.              /*
  42.               * This is a poor man's version of map_background().  I can't
  43.               * use map_background() because we are overriding what is in
  44.               * the 'typ' field.  Maybe have map_background()'s parameters
  45.               * be (x,y,glyph) instead of just (x,y).
  46.               *
  47.               * mappearance is currently set to an S_ index value in
  48.               * makemon.c.
  49.               */
  50.              int sym = mon->mappearance, glyph = cmap_to_glyph(sym);
  51.  
  52.              levl[x][y].glyph = glyph;
  53.              if (!sensed) {
  54.                  show_glyph(x, y, glyph);
  55.                  /* override real topology with mimic's fake one */
  56.                  lastseentyp[x][y] = cmap_to_type(sym);
  57.              }
  58.              break;
  59.          }
  60.  
  61.          case M_AP_OBJECT: {
  62.              /* Make a fake object to send to map_object(). */
  63.              struct obj obj;
  64.  
  65.              obj = zeroobj;
  66.              obj.ox = x;
  67.              obj.oy = y;
  68.              obj.otyp = mon->mappearance;
  69.              /* might be mimicing a corpse or statue */
  70.              obj.corpsenm = has_mcorpsenm(mon) ? MCORPSENM(mon) : PM_TENGU;
  71.              map_object(&obj, !sensed);
  72.              break;
  73.          }
  74.  
  75.          case M_AP_MONSTER:
  76.              show_glyph(x, y,
  77.                         monnum_to_glyph(what_mon((int) mon->mappearance)));
  78.              break;
  79.          }
  80.      }
  81.  
  82.      /* If the mimic is unsuccessfully mimicing something, display the monster.
  83.       */
  84.      if (!mon_mimic || sensed) {
  85.          int num;
  86.  
  87.          /* [ALI] Only use detected glyphs when monster wouldn't be
  88.           * visible by any other means.
  89.           *
  90.           * There are no glyphs for "detected pets" so we have to
  91.           * decide whether to display such things as detected or as tame.
  92.           * If both are being highlighted in the same way, it doesn't
  93.           * matter, but if not, showing them as pets is preferrable.
  94.           */
  95.          if (mon->mtame && !Hallucination) {
  96.              if (worm_tail)
  97.                  num = petnum_to_glyph(PM_LONG_WORM_TAIL);
  98.              else
  99.                  num = pet_to_glyph(mon);
  100.          } else if (sightflags == DETECTED) {
  101.              if (worm_tail)
  102.                  num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
  103.              else
  104.                  num = detected_mon_to_glyph(mon);
  105.          } else {
  106.              if (worm_tail)
  107.                  num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL));
  108.              else
  109.                  num = mon_to_glyph(mon);
  110.          }
  111.          show_glyph(x, y, num);
  112.      }
  113.  }
  114.  

display_warning

  1.  /*
  2.   * display_warning()
  3.   *
  4.   * This is also *not* a map_XXXX() function!  Monster warnings float
  5.   * above everything just like monsters do, but only if the monster
  6.   * is not showing.
  7.   *
  8.   * Do not call for worm tails.
  9.   */
  10.  STATIC_OVL void
  11.  display_warning(mon)
  12.  register struct monst *mon;
  13.  {
  14.      int x = mon->mx, y = mon->my;
  15.      int glyph;
  16.  
  17.      if (mon_warning(mon)) {
  18.          int wl = Hallucination ? rn1(WARNCOUNT - 1, 1) : warning_of(mon);
  19.          glyph = warning_to_glyph(wl);
  20.      } else if (MATCH_WARN_OF_MON(mon)) {
  21.          glyph = mon_to_glyph(mon);
  22.      } else {
  23.          impossible("display_warning did not match warning type?");
  24.          return;
  25.      }
  26.      /* warning glyph is drawn on the monster layer; unseen
  27.         monster glyph is drawn on the object/trap/floor layer;
  28.         if we see a 'warning' move onto 'remembered, unseen' we
  29.         need to explicitly remove that in order for it to not
  30.         reappear when the warned-of monster moves off that spot */
  31.      if (glyph_is_invisible(levl[x][y].glyph))
  32.          unmap_object(x, y);
  33.      show_glyph(x, y, glyph);
  34.  }
  35.  

warning_of

  1.  int
  2.  warning_of(mon)
  3.  struct monst *mon;
  4.  {
  5.      int wl = 0, tmp = 0;
  6.      if (mon_warning(mon)) {
  7.          tmp = (int) (mon->m_lev / 4);    /* match display.h */
  8.          wl = (tmp > WARNCOUNT - 1) ? WARNCOUNT - 1 : tmp;
  9.      }
  10.      return wl;
  11.  }
  12.  
  13.  

feel_newsym

  1.  /*
  2.   * feel_newsym()
  3.   *
  4.   * When hero knows what happened to location, even when blind.
  5.   */
  6.  void
  7.  feel_newsym(x, y)
  8.  xchar x, y;
  9.  {
  10.      if (Blind)
  11.          feel_location(x, y);
  12.      else
  13.          newsym(x, y);
  14.  }
  15.  
  16.  

feel_location

  1.  /*
  2.   * feel_location()
  3.   *
  4.   * Feel the given location.  This assumes that the hero is blind and that
  5.   * the given position is either the hero's or one of the eight squares
  6.   * adjacent to the hero (except for a boulder push).
  7.   * If an invisible monster has gone away, that will be discovered.  If an
  8.   * invisible monster has appeared, this will _not_ be discovered since
  9.   * searching only finds one monster per turn so we must check that separately.
  10.   */
  11.  void
  12.  feel_location(x, y)
  13.  xchar x, y;
  14.  {
  15.      struct rm *lev;
  16.      struct obj *boulder;
  17.      register struct monst *mon;
  18.  
  19.      if (!isok(x, y))
  20.          return;
  21.      lev = &(levl[x][y]);
  22.      /* If hero's memory of an invisible monster is accurate, we want to keep
  23.       * him from detecting the same monster over and over again on each turn.
  24.       * We must return (so we don't erase the monster).  (We must also, in the
  25.       * search function, be sure to skip over previously detected 'I's.)
  26.       */
  27.      if (glyph_is_invisible(lev->glyph) && m_at(x, y))
  28.          return;
  29.  
  30.      /* The hero can't feel non pool locations while under water
  31.         except for lava and ice. */
  32.      if (Underwater && !Is_waterlevel(&u.uz)
  33.          && !is_pool_or_lava(x, y) && !is_ice(x, y))
  34.          return;
  35.  
  36.      /* Set the seen vector as if the hero had seen it.
  37.         It doesn't matter if the hero is levitating or not. */
  38.      set_seenv(lev, u.ux, u.uy, x, y);
  39.  
  40.      if (!can_reach_floor(FALSE)) {
  41.          /*
  42.           * Levitation Rules.  It is assumed that the hero can feel the state
  43.           * of the walls around herself and can tell if she is in a corridor,
  44.           * room, or doorway.  Boulders are felt because they are large enough.
  45.           * Anything else is unknown because the hero can't reach the ground.
  46.           * This makes things difficult.
  47.           *
  48.           * Check (and display) in order:
  49.           *
  50.           *      + Stone, walls, and closed doors.
  51.           *      + Boulders.  [see a boulder before a doorway]
  52.           *      + Doors.
  53.           *      + Room/water positions
  54.           *      + Everything else (hallways!)
  55.           */
  56.          if (IS_ROCK(lev->typ)
  57.              || (IS_DOOR(lev->typ)
  58.                  && (lev->doormask & (D_LOCKED | D_CLOSED)))) {
  59.              map_background(x, y, 1);
  60.          } else if ((boulder = sobj_at(BOULDER, x, y)) != 0) {
  61.              map_object(boulder, 1);
  62.          } else if (IS_DOOR(lev->typ)) {
  63.              map_background(x, y, 1);
  64.          } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
  65.              boolean do_room_glyph;
  66.  
  67.              /*
  68.               * An open room or water location.  Normally we wouldn't touch
  69.               * this, but we have to get rid of remembered boulder symbols.
  70.               * This will only occur in rare occasions when the hero goes
  71.               * blind and doesn't find a boulder where expected (something
  72.               * came along and picked it up).  We know that there is not a
  73.               * boulder at this location.  Show fountains, pools, etc.
  74.               * underneath if already seen.  Otherwise, show the appropriate
  75.               * floor symbol.
  76.               *
  77.               * Similarly, if the hero digs a hole in a wall or feels a
  78.               * location
  79.               * that used to contain an unseen monster.  In these cases,
  80.               * there's no reason to assume anything was underneath, so
  81.               * just show the appropriate floor symbol.  If something was
  82.               * embedded in the wall, the glyph will probably already
  83.               * reflect that.  Don't change the symbol in this case.
  84.               *
  85.               * This isn't quite correct.  If the boulder was on top of some
  86.               * other objects they should be seen once the boulder is removed.
  87.               * However, we have no way of knowing that what is there now
  88.               * was there then.  So we let the hero have a lapse of memory.
  89.               * We could also just display what is currently on the top of the
  90.               * object stack (if anything).
  91.               */
  92.              do_room_glyph = FALSE;
  93.              if (lev->glyph == objnum_to_glyph(BOULDER)
  94.                  || glyph_is_invisible(lev->glyph)) {
  95.                  if (lev->typ != ROOM && lev->seenv)
  96.                      map_background(x, y, 1);
  97.                  else
  98.                      do_room_glyph = TRUE;
  99.              } else if (lev->glyph >= cmap_to_glyph(S_stone)
  100.                         && lev->glyph < cmap_to_glyph(S_darkroom)) {
  101.                  do_room_glyph = TRUE;
  102.              }
  103.              if (do_room_glyph) {
  104.                  lev->glyph = (flags.dark_room && iflags.use_color
  105.                                && !Is_rogue_level(&u.uz))
  106.                                   ? cmap_to_glyph(S_darkroom)
  107.                                   : (lev->waslit ? cmap_to_glyph(S_room)
  108.                                                  : cmap_to_glyph(S_stone));
  109.                  show_glyph(x, y, lev->glyph);
  110.              }
  111.          } else {
  112.              /* We feel it (I think hallways are the only things left). */
  113.              map_background(x, y, 1);
  114.              /* Corridors are never felt as lit (unless remembered that way) */
  115.              /* (lit_corridor only).                                         */
  116.              if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr)
  117.                  && !lev->waslit)
  118.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  119.              else if (lev->typ == ROOM && flags.dark_room && iflags.use_color
  120.                       && lev->glyph == cmap_to_glyph(S_room))
  121.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(S_darkroom));
  122.          }
  123.      } else {
  124.          _map_location(x, y, 1);
  125.  
  126.          if (Punished) {
  127.              /*
  128.               * A ball or chain is only felt if it is first on the object
  129.               * location list.  Otherwise, we need to clear the felt bit ---
  130.               * something has been dropped on the ball/chain.  If the bit is
  131.               * not cleared, then when the ball/chain is moved it will drop
  132.               * the wrong glyph.
  133.               */
  134.              if (uchain->ox == x && uchain->oy == y) {
  135.                  if (level.objects[x][y] == uchain)
  136.                      u.bc_felt |= BC_CHAIN;
  137.                  else
  138.                      u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */
  139.              }
  140.              if (!carried(uball) && uball->ox == x && uball->oy == y) {
  141.                  if (level.objects[x][y] == uball)
  142.                      u.bc_felt |= BC_BALL;
  143.                  else
  144.                      u.bc_felt &= ~BC_BALL; /* do not feel the ball */
  145.              }
  146.          }
  147.  
  148.          /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
  149.          if (lev->typ == ROOM && lev->glyph == cmap_to_glyph(S_room)
  150.              && (!lev->waslit || (flags.dark_room && iflags.use_color)))
  151.              show_glyph(x, y, lev->glyph = cmap_to_glyph(
  152.                                   flags.dark_room ? S_darkroom : S_stone));
  153.          else if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr)
  154.                   && !lev->waslit)
  155.              show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  156.      }
  157.      /* draw monster on top if we can sense it */
  158.      if ((x != u.ux || y != u.uy) && (mon = m_at(x, y)) != 0 && sensemon(mon))
  159.          display_monster(x, y, mon,
  160.                          (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon))
  161.                              ? PHYSICALLY_SEEN
  162.                              : DETECTED,
  163.                          is_worm_tail(mon));
  164.  }
  165.  

newsym

  1.  /*
  2.   * newsym()
  3.   *
  4.   * Possibly put a new glyph at the given location.
  5.   */
  6.  void
  7.  newsym(x, y)
  8.  register int x, y;
  9.  {
  10.      register struct monst *mon;
  11.      register struct rm *lev = &(levl[x][y]);
  12.      register int see_it;
  13.      register xchar worm_tail;
  14.  
  15.      if (in_mklev)
  16.          return;
  17.  #ifdef HANGUPHANDLING
  18.      if (program_state.done_hup)
  19.          return;
  20.  #endif
  21.  
  22.      /* only permit updating the hero when swallowed */
  23.      if (u.uswallow) {
  24.          if (x == u.ux && y == u.uy)
  25.              display_self();
  26.          return;
  27.      }
  28.      if (Underwater && !Is_waterlevel(&u.uz)) {
  29.          /* when underwater, don't do anything unless <x,y> is an
  30.             adjacent water or lava or ice position */
  31.          if (!(is_pool_or_lava(x, y) || is_ice(x, y)) || distu(x, y) > 2)
  32.              return;
  33.      }
  34.  
  35.      /* Can physically see the location. */
  36.      if (cansee(x, y)) {
  37.          NhRegion *reg = visible_region_at(x, y);
  38.          /*
  39.           * Don't use templit here:  E.g.
  40.           *
  41.           *      lev->waslit = !!(lev->lit || templit(x,y));
  42.           *
  43.           * Otherwise we have the "light pool" problem, where non-permanently
  44.           * lit areas just out of sight stay remembered as lit.  They should
  45.           * re-darken.
  46.           *
  47.           * Perhaps ALL areas should revert to their "unlit" look when
  48.           * out of sight.
  49.           */
  50.          lev->waslit = (lev->lit != 0); /* remember lit condition */
  51.  
  52.          /* normal region shown only on accessible positions, but poison clouds
  53.           * also shown above lava, pools and moats.
  54.           */
  55.          if (reg != NULL && (ACCESSIBLE(lev->typ)
  56.                              || (reg->glyph == cmap_to_glyph(S_poisoncloud)
  57.                                  && (lev->typ == LAVAPOOL || lev->typ == POOL
  58.                                      || lev->typ == MOAT)))) {
  59.              show_region(reg, x, y);
  60.              return;
  61.          }
  62.          if (x == u.ux && y == u.uy) {
  63.              if (canspotself()) {
  64.                  _map_location(x, y, 0); /* map *under* self */
  65.                  display_self();
  66.              } else
  67.                  /* we can see what is there */
  68.                  _map_location(x, y, 1);
  69.          } else {
  70.              mon = m_at(x, y);
  71.              worm_tail = is_worm_tail(mon);
  72.              see_it =
  73.                  mon && (worm_tail ? (!mon->minvis || See_invisible)
  74.                                    : (mon_visible(mon)) || tp_sensemon(mon)
  75.                                          || MATCH_WARN_OF_MON(mon));
  76.              if (mon && (see_it || (!worm_tail && Detect_monsters))) {
  77.                  if (mon->mtrapped) {
  78.                      struct trap *trap = t_at(x, y);
  79.                      int tt = trap ? trap->ttyp : NO_TRAP;
  80.  
  81.                      /* if monster is in a physical trap, you see the trap too
  82.                       */
  83.                      if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT
  84.                          || tt == WEB) {
  85.                          trap->tseen = TRUE;
  86.                      }
  87.                  }
  88.                  _map_location(x, y, 0); /* map under the monster */
  89.                  /* also gets rid of any invisibility glyph */
  90.                  display_monster(x, y, mon,
  91.                                  see_it ? PHYSICALLY_SEEN : DETECTED,
  92.                                  worm_tail);
  93.              } else if (mon && mon_warning(mon) && !is_worm_tail(mon)) {
  94.                  display_warning(mon);
  95.              } else if (glyph_is_invisible(levl[x][y].glyph)) {
  96.                  map_invisible(x, y);
  97.              } else
  98.                  _map_location(x, y, 1); /* map the location */\
  99.          }
  100.  
  101.      /* Can't see the location. */
  102.      } else {
  103.          if (x == u.ux && y == u.uy) {
  104.              feel_location(u.ux, u.uy); /* forces an update */
  105.  
  106.              if (canspotself())
  107.                  display_self();
  108.          } else if ((mon = m_at(x, y))
  109.                     && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)
  110.                                    || (see_with_infrared(mon)
  111.                                        && mon_visible(mon))))
  112.                         || Detect_monsters)) {
  113.              /* Monsters are printed every time. */
  114.              /* This also gets rid of any invisibility glyph */
  115.              display_monster(x, y, mon, see_it ? 0 : DETECTED,
  116.                              is_worm_tail(mon) ? TRUE : FALSE);
  117.          } else if ((mon = m_at(x, y)) && mon_warning(mon)
  118.                     && !is_worm_tail(mon)) {
  119.              display_warning(mon);
  120.          }
  121.  
  122.          /*
  123.           * If the location is remembered as being both dark (waslit is false)
  124.           * and lit (glyph is a lit room or lit corridor) then it was either:
  125.           *
  126.           *      (1) A dark location that the hero could see through night
  127.           *          vision.
  128.           *
  129.           *      (2) Darkened while out of the hero's sight.  This can happen
  130.           *          when cursed scroll of light is read.
  131.           *
  132.           * In either case, we have to manually correct the hero's memory to
  133.           * match waslit.  Deciding when to change waslit is non-trivial.
  134.           *
  135.           *  Note:  If flags.lit_corridor is set, then corridors act like room
  136.           *         squares.  That is, they light up if in night vision range.
  137.           *         If flags.lit_corridor is not set, then corridors will
  138.           *         remain dark unless lit by a light spell and may darken
  139.           *         again, as discussed above.
  140.           *
  141.           * These checks and changes must be here and not in back_to_glyph().
  142.           * They are dependent on the position being out of sight.
  143.           */
  144.          else if (Is_rogue_level(&u.uz)) {
  145.              if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR)
  146.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  147.              else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM
  148.                       && !lev->waslit)
  149.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
  150.              else
  151.                  goto show_mem;
  152.          }
  153.          else if (!lev->waslit || (flags.dark_room && iflags.use_color)) {
  154.              if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR)
  155.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  156.              else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
  157.                  show_glyph(x, y, lev->glyph = cmap_to_glyph(DARKROOMSYM));
  158.              else
  159.                  goto show_mem;
  160.          } else {
  161.          show_mem:
  162.              show_glyph(x, y, lev->glyph);
  163.          }
  164.      }
  165.  }
  166.  
  167.  #undef is_worm_tail
  168.  

shieldeff

  1.  /*
  2.   * shieldeff()
  3.   *
  4.   * Put magic shield pyrotechnics at the given location.  This *could* be
  5.   * pulled into a platform dependent routine for fancier graphics if desired.
  6.   */
  7.  void
  8.  shieldeff(x, y)
  9.  xchar x, y;
  10.  {
  11.      register int i;
  12.  
  13.      if (!flags.sparkle)
  14.          return;
  15.      if (cansee(x, y)) { /* Don't see anything if can't see the location */
  16.          for (i = 0; i < SHIELD_COUNT; i++) {
  17.              show_glyph(x, y, cmap_to_glyph(shield_static[i]));
  18.              flush_screen(1); /* make sure the glyph shows up */
  19.              delay_output();
  20.          }
  21.          newsym(x, y); /* restore the old information */
  22.      }
  23.  }
  24.  

tmp_at

  1.  /*
  2.   * tmp_at()
  3.   *
  4.   * Temporarily place glyphs on the screen.  Do not call delay_output().  It
  5.   * is up to the caller to decide if it wants to wait [presently, everyone
  6.   * but explode() wants to delay].
  7.   *
  8.   * Call:
  9.   *      (DISP_BEAM,   glyph)    open, initialize glyph
  10.   *      (DISP_FLASH,  glyph)    open, initialize glyph
  11.   *      (DISP_ALWAYS, glyph)    open, initialize glyph
  12.   *      (DISP_CHANGE, glyph)    change glyph
  13.   *      (DISP_END,    0)        close & clean up (second argument doesn't
  14.   *                              matter)
  15.   *      (DISP_FREEMEM, 0)       only used to prevent memory leak during
  16.   *                              exit)
  17.   *      (x, y)                  display the glyph at the location
  18.   *
  19.   * DISP_BEAM  - Display the given glyph at each location, but do not erase
  20.   *              any until the close call.
  21.   * DISP_FLASH - Display the given glyph at each location, but erase the
  22.   *              previous location's glyph.
  23.   * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account.
  24.   */
  25.  
  26.  #define TMP_AT_MAX_GLYPHS (COLNO * 2)
  27.  
  28.  static struct tmp_glyph {
  29.      coord saved[TMP_AT_MAX_GLYPHS]; /* previously updated positions */
  30.      int sidx;                       /* index of next unused slot in saved[] */
  31.      int style; /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */
  32.      int glyph; /* glyph to use when printing */
  33.      struct tmp_glyph *prev;
  34.  } tgfirst;
  35.  
  36.  void
  37.  tmp_at(x, y)
  38.  int x, y;
  39.  {
  40.      static struct tmp_glyph *tglyph = (struct tmp_glyph *) 0;
  41.      struct tmp_glyph *tmp;
  42.  
  43.      switch (x) {
  44.      case DISP_BEAM:
  45.      case DISP_ALL:
  46.      case DISP_FLASH:
  47.      case DISP_ALWAYS:
  48.          if (!tglyph)
  49.              tmp = &tgfirst;
  50.          else /* nested effect; we need dynamic memory */
  51.              tmp = (struct tmp_glyph *) alloc(sizeof(struct tmp_glyph));
  52.          tmp->prev = tglyph;
  53.          tglyph = tmp;
  54.          tglyph->sidx = 0;
  55.          tglyph->style = x;
  56.          tglyph->glyph = y;
  57.          flush_screen(0); /* flush buffered glyphs */
  58.          return;
  59.  
  60.      case DISP_FREEMEM: /* in case game ends with tmp_at() in progress */
  61.          while (tglyph) {
  62.              tmp = tglyph->prev;
  63.              if (tglyph != &tgfirst)
  64.                  free((genericptr_t) tglyph);
  65.              tglyph = tmp;
  66.          }
  67.          return;
  68.  
  69.      default:
  70.          break;
  71.      }
  72.  
  73.      if (!tglyph)
  74.          panic("tmp_at: tglyph not initialized");
  75.  
  76.      switch (x) {
  77.      case DISP_CHANGE:
  78.          tglyph->glyph = y;
  79.          break;
  80.  
  81.      case DISP_END:
  82.          if (tglyph->style == DISP_BEAM || tglyph->style == DISP_ALL) {
  83.              register int i;
  84.  
  85.              /* Erase (reset) from source to end */
  86.              for (i = 0; i < tglyph->sidx; i++)
  87.                  newsym(tglyph->saved[i].x, tglyph->saved[i].y);
  88.          } else {              /* DISP_FLASH or DISP_ALWAYS */
  89.              if (tglyph->sidx) /* been called at least once */
  90.                  newsym(tglyph->saved[0].x, tglyph->saved[0].y);
  91.          }
  92.          /* tglyph->sidx = 0; -- about to be freed, so not necessary */
  93.          tmp = tglyph->prev;
  94.          if (tglyph != &tgfirst)
  95.              free((genericptr_t) tglyph);
  96.          tglyph = tmp;
  97.          break;
  98.  
  99.      default: /* do it */
  100.          if (!isok(x, y))
  101.              break;
  102.          if (tglyph->style == DISP_BEAM || tglyph->style == DISP_ALL) {
  103.              if (tglyph->style != DISP_ALL && !cansee(x, y))
  104.                  break;
  105.              if (tglyph->sidx >= TMP_AT_MAX_GLYPHS)
  106.                  break; /* too many locations */
  107.              /* save pos for later erasing */
  108.              tglyph->saved[tglyph->sidx].x = x;
  109.              tglyph->saved[tglyph->sidx].y = y;
  110.              tglyph->sidx += 1;
  111.          } else {                /* DISP_FLASH/ALWAYS */
  112.              if (tglyph->sidx) { /* not first call, so reset previous pos */
  113.                  newsym(tglyph->saved[0].x, tglyph->saved[0].y);
  114.                  tglyph->sidx = 0; /* display is presently up to date */
  115.              }
  116.              if (!cansee(x, y) && tglyph->style != DISP_ALWAYS)
  117.                  break;
  118.              tglyph->saved[0].x = x;
  119.              tglyph->saved[0].y = y;
  120.              tglyph->sidx = 1;
  121.          }
  122.  
  123.          show_glyph(x, y, tglyph->glyph); /* show it */
  124.          flush_screen(0);                 /* make sure it shows up */
  125.          break;
  126.      } /* end case */
  127.  }
  128.  

swallowed

  1.  /*
  2.   * swallowed()
  3.   *
  4.   * The hero is swallowed.  Show a special graphics sequence for this.  This
  5.   * bypasses all of the display routines and messes with buffered screen
  6.   * directly.  This method works because both vision and display check for
  7.   * being swallowed.
  8.   */
  9.  void
  10.  swallowed(first)
  11.  int first;
  12.  {
  13.      static xchar lastx, lasty; /* last swallowed position */
  14.      int swallower, left_ok, rght_ok;
  15.  
  16.      if (first) {
  17.          cls();
  18.          bot();
  19.      } else {
  20.          register int x, y;
  21.  
  22.          /* Clear old location */
  23.          for (y = lasty - 1; y <= lasty + 1; y++)
  24.              for (x = lastx - 1; x <= lastx + 1; x++)
  25.                  if (isok(x, y))
  26.                      show_glyph(x, y, cmap_to_glyph(S_stone));
  27.      }
  28.  
  29.      swallower = monsndx(u.ustuck->data);
  30.      /* assume isok(u.ux,u.uy) */
  31.      left_ok = isok(u.ux - 1, u.uy);
  32.      rght_ok = isok(u.ux + 1, u.uy);
  33.      /*
  34.       *  Display the hero surrounded by the monster's stomach.
  35.       */
  36.      if (isok(u.ux, u.uy - 1)) {
  37.          if (left_ok)
  38.              show_glyph(u.ux - 1, u.uy - 1,
  39.                         swallow_to_glyph(swallower, S_sw_tl));
  40.          show_glyph(u.ux, u.uy - 1, swallow_to_glyph(swallower, S_sw_tc));
  41.          if (rght_ok)
  42.              show_glyph(u.ux + 1, u.uy - 1,
  43.                         swallow_to_glyph(swallower, S_sw_tr));
  44.      }
  45.  
  46.      if (left_ok)
  47.          show_glyph(u.ux - 1, u.uy, swallow_to_glyph(swallower, S_sw_ml));
  48.      display_self();
  49.      if (rght_ok)
  50.          show_glyph(u.ux + 1, u.uy, swallow_to_glyph(swallower, S_sw_mr));
  51.  
  52.      if (isok(u.ux, u.uy + 1)) {
  53.          if (left_ok)
  54.              show_glyph(u.ux - 1, u.uy + 1,
  55.                         swallow_to_glyph(swallower, S_sw_bl));
  56.          show_glyph(u.ux, u.uy + 1, swallow_to_glyph(swallower, S_sw_bc));
  57.          if (rght_ok)
  58.              show_glyph(u.ux + 1, u.uy + 1,
  59.                         swallow_to_glyph(swallower, S_sw_br));
  60.      }
  61.  
  62.      /* Update the swallowed position. */
  63.      lastx = u.ux;
  64.      lasty = u.uy;
  65.  }
  66.  

under_water

  1.  /*
  2.   * under_water()
  3.   *
  4.   * Similar to swallowed() in operation.  Shows hero when underwater
  5.   * except when in water level.  Special routines exist for that.
  6.   */
  7.  void
  8.  under_water(mode)
  9.  int mode;
  10.  {
  11.      static xchar lastx, lasty;
  12.      static boolean dela;
  13.      register int x, y;
  14.  
  15.      /* swallowing has a higher precedence than under water */
  16.      if (Is_waterlevel(&u.uz) || u.uswallow)
  17.          return;
  18.  
  19.      /* full update */
  20.      if (mode == 1 || dela) {
  21.          cls();
  22.          dela = FALSE;
  23.  
  24.      /* delayed full update */
  25.      } else if (mode == 2) {
  26.          dela = TRUE;
  27.          return;
  28.  
  29.      /* limited update */
  30.      } else {
  31.          for (y = lasty - 1; y <= lasty + 1; y++)
  32.              for (x = lastx - 1; x <= lastx + 1; x++)
  33.                  if (isok(x, y))
  34.                      show_glyph(x, y, cmap_to_glyph(S_stone));
  35.      }
  36.  
  37.      /*
  38.       * TODO?  Should this honor Xray radius rather than force radius 1?
  39.       */
  40.  
  41.      for (x = u.ux - 1; x <= u.ux + 1; x++)
  42.          for (y = u.uy - 1; y <= u.uy + 1; y++)
  43.              if (isok(x, y) && (is_pool_or_lava(x, y) || is_ice(x, y))) {
  44.                  if (Blind && !(x == u.ux && y == u.uy))
  45.                      show_glyph(x, y, cmap_to_glyph(S_stone));
  46.                  else
  47.                      newsym(x, y);
  48.              }
  49.      lastx = u.ux;
  50.      lasty = u.uy;
  51.  }
  52.  

under_ground

  1.  /*
  2.   *      under_ground()
  3.   *
  4.   *      Very restricted display.  You can only see yourself.
  5.   */
  6.  void
  7.  under_ground(mode)
  8.  int mode;
  9.  {
  10.      static boolean dela;
  11.  
  12.      /* swallowing has a higher precedence than under ground */
  13.      if (u.uswallow)
  14.          return;
  15.  
  16.      /* full update */
  17.      if (mode == 1 || dela) {
  18.          cls();
  19.          dela = FALSE;
  20.  
  21.      /* delayed full update */
  22.      } else if (mode == 2) {
  23.          dela = TRUE;
  24.          return;
  25.  
  26.      /* limited update */
  27.      } else {
  28.          newsym(u.ux, u.uy);
  29.      }
  30.  }
  31.  
  32.  /* =========================================================================
  33.   */
  34.  

see_monsters

  1.  /*
  2.   * Loop through all of the monsters and update them.  Called when:
  3.   *      + going blind & telepathic
  4.   *      + regaining sight & telepathic
  5.   *      + getting and losing infravision
  6.   *      + hallucinating
  7.   *      + doing a full screen redraw
  8.   *      + see invisible times out or a ring of see invisible is taken off
  9.   *      + when a potion of see invisible is quaffed or a ring of see
  10.   *        invisible is put on
  11.   *      + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
  12.   *      + losing telepathy while blind [xkilled() in mon.c, attrcurse() in
  13.   *        sit.c]
  14.   */
  15.  void
  16.  see_monsters()
  17.  {
  18.      register struct monst *mon;
  19.      int new_warn_obj_cnt = 0;
  20.  
  21.      if (defer_see_monsters)
  22.          return;
  23.  
  24.      for (mon = fmon; mon; mon = mon->nmon) {
  25.          if (DEADMONSTER(mon))
  26.              continue;
  27.          newsym(mon->mx, mon->my);
  28.          if (mon->wormno)
  29.              see_wsegs(mon);
  30.          if (Warn_of_mon && (context.warntype.obj & mon->data->mflags2) != 0L)
  31.              new_warn_obj_cnt++;
  32.      }
  33.      /*
  34.       * Make Sting glow blue or stop glowing if required.
  35.       */
  36.      if (new_warn_obj_cnt != warn_obj_cnt) {
  37.          Sting_effects(new_warn_obj_cnt);
  38.          warn_obj_cnt = new_warn_obj_cnt;
  39.      }
  40.  
  41.      /* when mounted, hero's location gets caught by monster loop */
  42.      if (!u.usteed)
  43.          newsym(u.ux, u.uy);
  44.  }
  45.  

set_mimic_blocking

  1.  /*
  2.   * Block/unblock light depending on what a mimic is mimicing and if it's
  3.   * invisible or not.  Should be called only when the state of See_invisible
  4.   * changes.
  5.   */
  6.  void
  7.  set_mimic_blocking()
  8.  {
  9.      register struct monst *mon;
  10.  
  11.      for (mon = fmon; mon; mon = mon->nmon) {
  12.          if (DEADMONSTER(mon))
  13.              continue;
  14.          if (mon->minvis && is_lightblocker_mappear(mon)) {
  15.              if (See_invisible)
  16.                  block_point(mon->mx, mon->my);
  17.              else
  18.                  unblock_point(mon->mx, mon->my);
  19.          }
  20.      }
  21.  }
  22.  

see_objects

  1.  /*
  2.   * Loop through all of the object *locations* and update them.  Called when
  3.   *      + hallucinating.
  4.   */
  5.  void
  6.  see_objects()
  7.  {
  8.      register struct obj *obj;
  9.      for (obj = fobj; obj; obj = obj->nobj)
  10.          if (vobj_at(obj->ox, obj->oy) == obj)
  11.              newsym(obj->ox, obj->oy);
  12.  }
  13.  

see_traps

  1.  /*
  2.   * Update hallucinated traps.
  3.   */
  4.  void
  5.  see_traps()
  6.  {
  7.      struct trap *trap;
  8.      int glyph;
  9.  
  10.      for (trap = ftrap; trap; trap = trap->ntrap) {
  11.          glyph = glyph_at(trap->tx, trap->ty);
  12.          if (glyph_is_trap(glyph))
  13.              newsym(trap->tx, trap->ty);
  14.      }
  15.  }
  16.  

curs_on_u

  1.  /*
  2.   * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
  3.   */
  4.  void
  5.  curs_on_u()
  6.  {
  7.      flush_screen(1); /* Flush waiting glyphs & put cursor on hero */
  8.  }
  9.  

doredraw

  1.  int
  2.  doredraw()
  3.  {
  4.      docrt();
  5.      return 0;
  6.  }
  7.  

docrt

  1.  void
  2.  docrt()
  3.  {
  4.      register int x, y;
  5.      register struct rm *lev;
  6.  
  7.      if (!u.ux)
  8.          return; /* display isn't ready yet */
  9.  
  10.      if (u.uswallow) {
  11.          swallowed(1);
  12.          return;
  13.      }
  14.      if (Underwater && !Is_waterlevel(&u.uz)) {
  15.          under_water(1);
  16.          return;
  17.      }
  18.      if (u.uburied) {
  19.          under_ground(1);
  20.          return;
  21.      }
  22.  
  23.      /* shut down vision */
  24.      vision_recalc(2);
  25.  
  26.      /*
  27.       * This routine assumes that cls() does the following:
  28.       *      + fills the physical screen with the symbol for rock
  29.       *      + clears the glyph buffer
  30.       */
  31.      cls();
  32.  
  33.      /* display memory */
  34.      for (x = 1; x < COLNO; x++) {
  35.          lev = &levl[x][0];
  36.          for (y = 0; y < ROWNO; y++, lev++)
  37.              if (lev->glyph != cmap_to_glyph(S_stone))
  38.                  show_glyph(x, y, lev->glyph);
  39.      }
  40.  
  41.      /* see what is to be seen */
  42.      vision_recalc(0);
  43.  
  44.      /* overlay with monsters */
  45.      see_monsters();
  46.  
  47.      context.botlx = 1; /* force a redraw of the bottom line */
  48.  }
  49.  
  50.  /* =========================================================================
  51.   */
  52.  /* Glyph Buffering (3rd screen) ============================================
  53.   */
  54.  
  55.  typedef struct {
  56.      xchar new; /* perhaps move this bit into the rm structure. */
  57.      int glyph;
  58.  } gbuf_entry;
  59.  
  60.  static gbuf_entry gbuf[ROWNO][COLNO];
  61.  static char gbuf_start[ROWNO];
  62.  static char gbuf_stop[ROWNO];
  63.  

newsym_force

  1.  /* FIXME: This is a dirty hack, because newsym() doesn't distinguish
  2.   * between object piles and single objects, it doesn't mark the location
  3.   * for update. */
  4.  void
  5.  newsym_force(x, y)
  6.  register int x, y;
  7.  {
  8.      newsym(x,y);
  9.      gbuf[y][x].new = 1;
  10.      if (gbuf_start[y] > x)
  11.          gbuf_start[y] = x;
  12.      if (gbuf_stop[y] < x)
  13.          gbuf_stop[y] = x;
  14.  }
  15.  

show_glyph

  1.  /*
  2.   * Store the glyph in the 3rd screen for later flushing.
  3.   */
  4.  void
  5.  show_glyph(x, y, glyph)
  6.  int x, y, glyph;
  7.  {
  8.      /*
  9.       * Check for bad positions and glyphs.
  10.       */
  11.      if (!isok(x, y)) {
  12.          const char *text;
  13.          int offset;
  14.  
  15.          /* column 0 is invalid, but it's often used as a flag, so ignore it */
  16.          if (x == 0)
  17.              return;
  18.  
  19.          /*
  20.           *  This assumes an ordering of the offsets.  See display.h for
  21.           *  the definition.
  22.           */
  23.  
  24.          if (glyph >= GLYPH_WARNING_OFF
  25.              && glyph < GLYPH_STATUE_OFF) { /* a warning */
  26.              text = "warning";
  27.              offset = glyph - GLYPH_WARNING_OFF;
  28.          } else if (glyph >= GLYPH_SWALLOW_OFF) { /* swallow border */
  29.              text = "swallow border";
  30.              offset = glyph - GLYPH_SWALLOW_OFF;
  31.          } else if (glyph >= GLYPH_ZAP_OFF) { /* zap beam */
  32.              text = "zap beam";
  33.              offset = glyph - GLYPH_ZAP_OFF;
  34.          } else if (glyph >= GLYPH_EXPLODE_OFF) { /* explosion */
  35.              text = "explosion";
  36.              offset = glyph - GLYPH_EXPLODE_OFF;
  37.          } else if (glyph >= GLYPH_CMAP_OFF) { /* cmap */
  38.              text = "cmap_index";
  39.              offset = glyph - GLYPH_CMAP_OFF;
  40.          } else if (glyph >= GLYPH_OBJ_OFF) { /* object */
  41.              text = "object";
  42.              offset = glyph - GLYPH_OBJ_OFF;
  43.          } else if (glyph >= GLYPH_RIDDEN_OFF) { /* ridden mon */
  44.              text = "ridden mon";
  45.              offset = glyph - GLYPH_RIDDEN_OFF;
  46.          } else if (glyph >= GLYPH_BODY_OFF) { /* a corpse */
  47.              text = "corpse";
  48.              offset = glyph - GLYPH_BODY_OFF;
  49.          } else if (glyph >= GLYPH_DETECT_OFF) { /* detected mon */
  50.              text = "detected mon";
  51.              offset = glyph - GLYPH_DETECT_OFF;
  52.          } else if (glyph >= GLYPH_INVIS_OFF) { /* invisible mon */
  53.              text = "invisible mon";
  54.              offset = glyph - GLYPH_INVIS_OFF;
  55.          } else if (glyph >= GLYPH_PET_OFF) { /* a pet */
  56.              text = "pet";
  57.              offset = glyph - GLYPH_PET_OFF;
  58.          } else { /* a monster */
  59.              text = "monster";
  60.              offset = glyph;
  61.          }
  62.  
  63.          impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].", x, y,
  64.                     glyph, text, offset);
  65.          return;
  66.      }
  67.  
  68.      if (glyph >= MAX_GLYPH) {
  69.          impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).", glyph,
  70.                     MAX_GLYPH, x, y);
  71.          return;
  72.      }
  73.  
  74.      if (gbuf[y][x].glyph != glyph || iflags.use_background_glyph) {
  75.          gbuf[y][x].glyph = glyph;
  76.          gbuf[y][x].new = 1;
  77.          if (gbuf_start[y] > x)
  78.              gbuf_start[y] = x;
  79.          if (gbuf_stop[y] < x)
  80.              gbuf_stop[y] = x;
  81.      }
  82.  }
  83.  
  84.  /*
  85.   * Reset the changed glyph borders so that none of the 3rd screen has
  86.   * changed.
  87.   */
  88.  #define reset_glyph_bbox()             \
  89.      {                                  \
  90.          int i;                         \
  91.                                         \
  92.          for (i = 0; i < ROWNO; i++) {  \
  93.              gbuf_start[i] = COLNO - 1; \
  94.              gbuf_stop[i] = 0;          \
  95.          }                              \
  96.      }
  97.  
  98.  static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };

clear_glyph_buffer

  1.  /*
  2.   * Turn the 3rd screen into stone.
  3.   */
  4.  void
  5.  clear_glyph_buffer()
  6.  {
  7.      register int x, y;
  8.      register gbuf_entry *gptr;
  9.  
  10.      for (y = 0; y < ROWNO; y++) {
  11.          gptr = &gbuf[y][0];
  12.          for (x = COLNO; x; x--) {
  13.              *gptr++ = nul_gbuf;
  14.          }
  15.      }
  16.      reset_glyph_bbox();
  17.  }
  18.  

row_refresh

  1.  /*
  2.   * Assumes that the indicated positions are filled with S_stone glyphs.
  3.   */
  4.  void
  5.  row_refresh(start, stop, y)
  6.  int start, stop, y;
  7.  {
  8.      register int x;
  9.  
  10.      for (x = start; x <= stop; x++)
  11.          if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
  12.              print_glyph(WIN_MAP, x, y, gbuf[y][x].glyph, get_bk_glyph(x,y));
  13.  }
  14.  

cls

  1.  void
  2.  cls()
  3.  {
  4.      static boolean in_cls = 0;
  5.  
  6.      if (in_cls)
  7.          return;
  8.      in_cls = TRUE;
  9.      display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
  10.      context.botlx = 1;                    /* force update of botl window */
  11.      clear_nhwindow(WIN_MAP);              /* clear physical screen */
  12.  
  13.      clear_glyph_buffer(); /* this is sort of an extra effort, but OK */
  14.      in_cls = FALSE;
  15.  }
  16.  

flush_screen

  1.  /*
  2.   * Synch the third screen with the display.
  3.   */
  4.  void
  5.  flush_screen(cursor_on_u)
  6.  int cursor_on_u;
  7.  {
  8.      /* Prevent infinite loops on errors:
  9.       *      flush_screen->print_glyph->impossible->pline->flush_screen
  10.       */
  11.      static boolean flushing = 0;
  12.      static boolean delay_flushing = 0;
  13.      register int x, y;
  14.  
  15.      if (cursor_on_u == -1)
  16.          delay_flushing = !delay_flushing;
  17.      if (delay_flushing)
  18.          return;
  19.      if (flushing)
  20.          return; /* if already flushing then return */
  21.      flushing = 1;
  22.  #ifdef HANGUPHANDLING
  23.      if (program_state.done_hup)
  24.          return;
  25.  #endif
  26.  
  27.      for (y = 0; y < ROWNO; y++) {
  28.          register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
  29.          for (; x <= gbuf_stop[y]; gptr++, x++)
  30.              if (gptr->new) {
  31.                  print_glyph(WIN_MAP, x, y, gptr->glyph, get_bk_glyph(x, y));
  32.                  gptr->new = 0;
  33.              }
  34.      }
  35.  
  36.      if (cursor_on_u)
  37.          curs(WIN_MAP, u.ux, u.uy); /* move cursor to the hero */
  38.      display_nhwindow(WIN_MAP, FALSE);
  39.      reset_glyph_bbox();
  40.      flushing = 0;
  41.      if (context.botl || context.botlx)
  42.          bot();
  43.  }
  44.  
  45.  /* =========================================================================
  46.   */
  47.  

back_to_glyph

  1.  /*
  2.   * back_to_glyph()
  3.   *
  4.   * Use the information in the rm structure at the given position to create
  5.   * a glyph of a background.
  6.   *
  7.   * I had to add a field in the rm structure (horizontal) so that we knew
  8.   * if open doors and secret doors were horizontal or vertical.  Previously,
  9.   * the screen symbol had the horizontal/vertical information set at
  10.   * level generation time.
  11.   *
  12.   * I used the 'ladder' field (really doormask) for deciding if stairwells
  13.   * were up or down.  I didn't want to check the upstairs and dnstairs
  14.   * variables.
  15.   */
  16.  int
  17.  back_to_glyph(x, y)
  18.  xchar x, y;
  19.  {
  20.      int idx;
  21.      struct rm *ptr = &(levl[x][y]);
  22.  
  23.      switch (ptr->typ) {
  24.      case SCORR:
  25.      case STONE:
  26.          idx = level.flags.arboreal ? S_tree : S_stone;
  27.          break;
  28.      case ROOM:
  29.          idx = S_room;
  30.          break;
  31.      case CORR:
  32.          idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
  33.          break;
  34.      case HWALL:
  35.      case VWALL:
  36.      case TLCORNER:
  37.      case TRCORNER:
  38.      case BLCORNER:
  39.      case BRCORNER:
  40.      case CROSSWALL:
  41.      case TUWALL:
  42.      case TDWALL:
  43.      case TLWALL:
  44.      case TRWALL:
  45.      case SDOOR:
  46.          idx = ptr->seenv ? wall_angle(ptr) : S_stone;
  47.          break;
  48.      case DOOR:
  49.          if (ptr->doormask) {
  50.              if (ptr->doormask & D_BROKEN)
  51.                  idx = S_ndoor;
  52.              else if (ptr->doormask & D_ISOPEN)
  53.                  idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
  54.              else /* else is closed */
  55.                  idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
  56.          } else
  57.              idx = S_ndoor;
  58.          break;
  59.      case IRONBARS:
  60.          idx = S_bars;
  61.          break;
  62.      case TREE:
  63.          idx = S_tree;
  64.          break;
  65.      case POOL:
  66.      case MOAT:
  67.          idx = S_pool;
  68.          break;
  69.      case STAIRS:
  70.          idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
  71.          break;
  72.      case LADDER:
  73.          idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
  74.          break;
  75.      case FOUNTAIN:
  76.          idx = S_fountain;
  77.          break;
  78.      case SINK:
  79.          idx = S_sink;
  80.          break;
  81.      case ALTAR:
  82.          idx = S_altar;
  83.          break;
  84.      case GRAVE:
  85.          idx = S_grave;
  86.          break;
  87.      case THRONE:
  88.          idx = S_throne;
  89.          break;
  90.      case LAVAPOOL:
  91.          idx = S_lava;
  92.          break;
  93.      case ICE:
  94.          idx = S_ice;
  95.          break;
  96.      case AIR:
  97.          idx = S_air;
  98.          break;
  99.      case CLOUD:
  100.          idx = S_cloud;
  101.          break;
  102.      case WATER:
  103.          idx = S_water;
  104.          break;
  105.      case DBWALL:
  106.          idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
  107.          break;
  108.      case DRAWBRIDGE_UP:
  109.          switch (ptr->drawbridgemask & DB_UNDER) {
  110.          case DB_MOAT:
  111.              idx = S_pool;
  112.              break;
  113.          case DB_LAVA:
  114.              idx = S_lava;
  115.              break;
  116.          case DB_ICE:
  117.              idx = S_ice;
  118.              break;
  119.          case DB_FLOOR:
  120.              idx = S_room;
  121.              break;
  122.          default:
  123.              impossible("Strange db-under: %d",
  124.                         ptr->drawbridgemask & DB_UNDER);
  125.              idx = S_room; /* something is better than nothing */
  126.              break;
  127.          }
  128.          break;
  129.      case DRAWBRIDGE_DOWN:
  130.          idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
  131.          break;
  132.      default:
  133.          impossible("back_to_glyph:  unknown level type [ = %d ]", ptr->typ);
  134.          idx = S_room;
  135.          break;
  136.      }
  137.  
  138.      return cmap_to_glyph(idx);
  139.  }
  140.  

swallow_to_glyph

  1.  /*
  2.   * swallow_to_glyph()
  3.   *
  4.   * Convert a monster number and a swallow location into the correct glyph.
  5.   * If you don't want a patchwork monster while hallucinating, decide on
  6.   * a random monster in swallowed() and don't use what_mon() here.
  7.   */
  8.  STATIC_OVL int
  9.  swallow_to_glyph(mnum, loc)
  10.  int mnum;
  11.  int loc;
  12.  {
  13.      if (loc < S_sw_tl || S_sw_br < loc) {
  14.          impossible("swallow_to_glyph: bad swallow location");
  15.          loc = S_sw_br;
  16.      }
  17.      return ((int) (what_mon(mnum) << 3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
  18.  }
  19.  

zapdir_to_glyph

  1.  /*
  2.   * zapdir_to_glyph()
  3.   *
  4.   * Change the given zap direction and beam type into a glyph.  Each beam
  5.   * type has four glyphs, one for each of the symbols below.  The order of
  6.   * the zap symbols [0-3] as defined in rm.h are:
  7.   *
  8.   *      |  S_vbeam      ( 0, 1) or ( 0,-1)
  9.   *      -  S_hbeam      ( 1, 0) or (-1, 0)
  10.   *      \  S_lslant     ( 1, 1) or (-1,-1)
  11.   *      /  S_rslant     (-1, 1) or ( 1,-1)
  12.   */
  13.  int
  14.  zapdir_to_glyph(dx, dy, beam_type)
  15.  register int dx, dy;
  16.  int beam_type;
  17.  {
  18.      if (beam_type >= NUM_ZAP) {
  19.          impossible("zapdir_to_glyph:  illegal beam type");
  20.          beam_type = 0;
  21.      }
  22.      dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
  23.  
  24.      return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
  25.  }
  26.  

glyph_at

  1.  /*
  2.   * Utility routine for dowhatis() used to find out the glyph displayed at
  3.   * the location.  This isn't necessarily the same as the glyph in the levl
  4.   * structure, so we must check the "third screen".
  5.   */
  6.  int
  7.  glyph_at(x, y)
  8.  xchar x, y;
  9.  {
  10.      if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
  11.          return cmap_to_glyph(S_room); /* XXX */
  12.      return gbuf[y][x].glyph;
  13.  }
  14.  

get_bk_glyph

  1.  /*
  2.   * This will be used to get the glyph for the background so that
  3.   * it can potentially be merged into graphical window ports
  4.   * to improve the appearance of stuff on dark room
  5.   * squares and the plane of air etc.
  6.   *
  7.   * Until that is working correctly in the branch, however, for now
  8.   * we just return NO_GLYPH as an indicator to ignore it.
  9.   */
  10.  
  11.  STATIC_OVL int
  12.  get_bk_glyph(x,y)
  13.  xchar x, y;
  14.  {
  15.      int idx, bkglyph = NO_GLYPH;
  16.      struct rm *lev = &levl[x][y];
  17.  
  18.      if (iflags.use_background_glyph && lev->seenv != 0
  19.              && gbuf[y][x].glyph != cmap_to_glyph(S_stone)) {
  20.          switch (lev->typ) {
  21.          case SCORR:
  22.          case STONE:
  23.              idx = level.flags.arboreal ? S_tree : S_stone;
  24.              break;
  25.          case ROOM:
  26.             idx = S_room;
  27.             break;
  28.          case CORR:
  29.             idx = (lev->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
  30.             break;
  31.          case ICE:
  32.             idx = S_ice;
  33.             break;
  34.          case AIR:
  35.             idx = S_air;
  36.             break;
  37.          case CLOUD:
  38.             idx = S_cloud;
  39.             break;
  40.          case POOL:
  41.          case MOAT:
  42.             idx = S_pool;
  43.             break;
  44.          case WATER:
  45.             idx = S_water;
  46.             break;
  47.          case LAVAPOOL:
  48.             idx = S_lava;
  49.             break;
  50.          default:
  51.             idx = S_room;
  52.             break;
  53.          }
  54.  
  55.          if (!cansee(x, y) && (!lev->waslit || flags.dark_room)) {
  56.              /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
  57.              if (lev->typ == CORR && idx == S_litcorr)
  58.                  idx = S_corr;
  59.              else if (idx == S_room)
  60.                  idx = (flags.dark_room && iflags.use_color)
  61.                           ? DARKROOMSYM : S_stone;
  62.          }
  63.  
  64.          if (idx != S_room)
  65.              bkglyph = cmap_to_glyph(idx);
  66.      }
  67.      return bkglyph;
  68.  }
  69.  
  70.  /* -------------------------------------------------------------------------
  71.   */
  72.  /* Wall Angle --------------------------------------------------------------
  73.   */
  74.  
  75.  #ifdef WA_VERBOSE
  76.  
  77.  static const char *FDECL(type_to_name, (int));
  78.  static void FDECL(error4, (int, int, int, int, int, int));
  79.  
  80.  static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */
  81.  static const char *type_names[MAX_TYPE] = {
  82.      "STONE", "VWALL", "HWALL", "TLCORNER", "TRCORNER", "BLCORNER", "BRCORNER",
  83.      "CROSSWALL", "TUWALL", "TDWALL", "TLWALL", "TRWALL", "DBWALL", "TREE",
  84.      "SDOOR", "SCORR", "POOL", "MOAT", "WATER", "DRAWBRIDGE_UP", "LAVAPOOL",
  85.      "IRON_BARS", "DOOR", "CORR", "ROOM", "STAIRS", "LADDER", "FOUNTAIN",
  86.      "THRONE", "SINK", "GRAVE", "ALTAR", "ICE", "DRAWBRIDGE_DOWN", "AIR",
  87.      "CLOUD"
  88.  };
  89.  

type_to_name

  1.  static const char *
  2.  type_to_name(type)
  3.  int type;
  4.  {
  5.      return (type < 0 || type >= MAX_TYPE) ? "unknown" : type_names[type];
  6.  }
  7.  

error4

  1.  static void
  2.  error4(x, y, a, b, c, dd)
  3.  int x, y, a, b, c, dd;
  4.  {
  5.      pline("set_wall_state: %s @ (%d,%d) %s%s%s%s",
  6.            type_to_name(levl[x][y].typ), x, y,
  7.            a ? "1" : "", b ? "2" : "", c ? "3" : "", dd ? "4" : "");
  8.      bad_count[levl[x][y].typ]++;
  9.  }
  10.  #endif /* WA_VERBOSE */
  11.  

check_pos

  1.  /*
  2.   * Return 'which' if position is implies an unfinished exterior.  Return
  3.   * zero otherwise.  Unfinished implies outer area is rock or a corridor.
  4.   *
  5.   * Things that are ambiguous: lava
  6.   */
  7.  STATIC_OVL int
  8.  check_pos(x, y, which)
  9.  int x, y, which;
  10.  {
  11.      int type;
  12.      if (!isok(x, y))
  13.          return which;
  14.      type = levl[x][y].typ;
  15.      if (IS_ROCK(type) || type == CORR || type == SCORR)
  16.          return which;
  17.      return 0;
  18.  }
  19.  

more_than_one

  1.  /* Return TRUE if more than one is non-zero. */
  2.  /*ARGSUSED*/
  3.  #ifdef WA_VERBOSE
  4.  STATIC_OVL boolean
  5.  more_than_one(x, y, a, b, c)
  6.  int x, y, a, b, c;
  7.  {
  8.      if ((a && (b | c)) || (b && (a | c)) || (c && (a | b))) {
  9.          error4(x, y, a, b, c, 0);
  10.          return TRUE;
  11.      }
  12.      return FALSE;
  13.  }
  14.  #else
  15.  #define more_than_one(x, y, a, b, c) \
  16.      (((a) && ((b) | (c))) || ((b) && ((a) | (c))) || ((c) && ((a) | (b))))
  17.  #endif
  18.  

set_twall

  1.  /* Return the wall mode for a T wall. */
  2.  STATIC_OVL int
  3.  set_twall(x0, y0, x1, y1, x2, y2, x3, y3)
  4.  int x0, y0; /* used #if WA_VERBOSE */
  5.  int x1, y1, x2, y2, x3, y3;
  6.  {
  7.      int wmode, is_1, is_2, is_3;
  8.  
  9.      nhUse(x0);
  10.      nhUse(y0);
  11.  
  12.      is_1 = check_pos(x1, y1, WM_T_LONG);
  13.      is_2 = check_pos(x2, y2, WM_T_BL);
  14.      is_3 = check_pos(x3, y3, WM_T_BR);
  15.      if (more_than_one(x0, y0, is_1, is_2, is_3)) {
  16.          wmode = 0;
  17.      } else {
  18.          wmode = is_1 + is_2 + is_3;
  19.      }
  20.      return wmode;
  21.  }
  22.  

set_wall

  1.  /* Return wall mode for a horizontal or vertical wall. */
  2.  STATIC_OVL int
  3.  set_wall(x, y, horiz)
  4.  int x, y, horiz;
  5.  {
  6.      int wmode, is_1, is_2;
  7.  
  8.      if (horiz) {
  9.          is_1 = check_pos(x, y - 1, WM_W_TOP);
  10.          is_2 = check_pos(x, y + 1, WM_W_BOTTOM);
  11.      } else {
  12.          is_1 = check_pos(x - 1, y, WM_W_LEFT);
  13.          is_2 = check_pos(x + 1, y, WM_W_RIGHT);
  14.      }
  15.      if (more_than_one(x, y, is_1, is_2, 0)) {
  16.          wmode = 0;
  17.      } else {
  18.          wmode = is_1 + is_2;
  19.      }
  20.      return wmode;
  21.  }
  22.  

set_corn

  1.  /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */
  2.  STATIC_OVL int
  3.  set_corn(x1, y1, x2, y2, x3, y3, x4, y4)
  4.  int x1, y1, x2, y2, x3, y3, x4, y4;
  5.  {
  6.      int wmode, is_1, is_2, is_3, is_4;
  7.  
  8.      is_1 = check_pos(x1, y1, 1);
  9.      is_2 = check_pos(x2, y2, 1);
  10.      is_3 = check_pos(x3, y3, 1);
  11.      is_4 = check_pos(x4, y4, 1); /* inner location */
  12.  
  13.      /*
  14.       * All 4 should not be true.  So if the inner location is rock,
  15.       * use it.  If all of the outer 3 are true, use outer.  We currently
  16.       * can't cover the case where only part of the outer is rock, so
  17.       * we just say that all the walls are finished (if not overridden
  18.       * by the inner section).
  19.       */
  20.      if (is_4) {
  21.          wmode = WM_C_INNER;
  22.      } else if (is_1 && is_2 && is_3)
  23.          wmode = WM_C_OUTER;
  24.      else
  25.          wmode = 0; /* finished walls on all sides */
  26.  
  27.      return wmode;
  28.  }
  29.  

set_crosswall

  1.  /* Return mode for a crosswall. */
  2.  STATIC_OVL int
  3.  set_crosswall(x, y)
  4.  int x, y;
  5.  {
  6.      int wmode, is_1, is_2, is_3, is_4;
  7.  
  8.      is_1 = check_pos(x - 1, y - 1, 1);
  9.      is_2 = check_pos(x + 1, y - 1, 1);
  10.      is_3 = check_pos(x + 1, y + 1, 1);
  11.      is_4 = check_pos(x - 1, y + 1, 1);
  12.  
  13.      wmode = is_1 + is_2 + is_3 + is_4;
  14.      if (wmode > 1) {
  15.          if (is_1 && is_3 && (is_2 + is_4 == 0)) {
  16.              wmode = WM_X_TLBR;
  17.          } else if (is_2 && is_4 && (is_1 + is_3 == 0)) {
  18.              wmode = WM_X_BLTR;
  19.          } else {
  20.  #ifdef WA_VERBOSE
  21.              error4(x, y, is_1, is_2, is_3, is_4);
  22.  #endif
  23.              wmode = 0;
  24.          }
  25.      } else if (is_1)
  26.          wmode = WM_X_TL;
  27.      else if (is_2)
  28.          wmode = WM_X_TR;
  29.      else if (is_3)
  30.          wmode = WM_X_BR;
  31.      else if (is_4)
  32.          wmode = WM_X_BL;
  33.  
  34.      return wmode;
  35.  }
  36.  

set_wall_state

  1.  /* Called from mklev.  Scan the level and set the wall modes. */
  2.  void
  3.  set_wall_state()
  4.  {
  5.      int x, y;
  6.      int wmode;
  7.      struct rm *lev;
  8.  
  9.  #ifdef WA_VERBOSE
  10.      for (x = 0; x < MAX_TYPE; x++)
  11.          bad_count[x] = 0;
  12.  #endif
  13.  
  14.      for (x = 0; x < COLNO; x++)
  15.          for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) {
  16.              switch (lev->typ) {
  17.              case SDOOR:
  18.                  wmode = set_wall(x, y, (int) lev->horizontal);
  19.                  break;
  20.              case VWALL:
  21.                  wmode = set_wall(x, y, 0);
  22.                  break;
  23.              case HWALL:
  24.                  wmode = set_wall(x, y, 1);
  25.                  break;
  26.              case TDWALL:
  27.                  wmode = set_twall(x, y, x, y - 1, x - 1, y + 1, x + 1, y + 1);
  28.                  break;
  29.              case TUWALL:
  30.                  wmode = set_twall(x, y, x, y + 1, x + 1, y - 1, x - 1, y - 1);
  31.                  break;
  32.              case TLWALL:
  33.                  wmode = set_twall(x, y, x + 1, y, x - 1, y - 1, x - 1, y + 1);
  34.                  break;
  35.              case TRWALL:
  36.                  wmode = set_twall(x, y, x - 1, y, x + 1, y + 1, x + 1, y - 1);
  37.                  break;
  38.              case TLCORNER:
  39.                  wmode =
  40.                      set_corn(x - 1, y - 1, x, y - 1, x - 1, y, x + 1, y + 1);
  41.                  break;
  42.              case TRCORNER:
  43.                  wmode =
  44.                      set_corn(x, y - 1, x + 1, y - 1, x + 1, y, x - 1, y + 1);
  45.                  break;
  46.              case BLCORNER:
  47.                  wmode =
  48.                      set_corn(x, y + 1, x - 1, y + 1, x - 1, y, x + 1, y - 1);
  49.                  break;
  50.              case BRCORNER:
  51.                  wmode =
  52.                      set_corn(x + 1, y, x + 1, y + 1, x, y + 1, x - 1, y - 1);
  53.                  break;
  54.              case CROSSWALL:
  55.                  wmode = set_crosswall(x, y);
  56.                  break;
  57.  
  58.              default:
  59.                  wmode = -1; /* don't set wall info */
  60.                  break;
  61.              }
  62.  
  63.              if (wmode >= 0)
  64.                  lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode;
  65.          }
  66.  
  67.  #ifdef WA_VERBOSE
  68.      /* check if any bad positions found */
  69.      for (x = y = 0; x < MAX_TYPE; x++)
  70.          if (bad_count[x]) {
  71.              if (y == 0) {
  72.                  y = 1; /* only print once */
  73.                  pline("set_wall_type: wall mode problems with: ");
  74.              }
  75.              pline("%s %d;", type_names[x], bad_count[x]);
  76.          }
  77.  #endif /* WA_VERBOSE */
  78.  }
  79.  
  80.  /* -------------------------------------------------------------------------
  81.   */
  82.  /* This matrix is used here and in vision.c. */
  83.  unsigned char seenv_matrix[3][3] = { { SV2, SV1, SV0 },
  84.                                       { SV3, SVALL, SV7 },
  85.                                       { SV4, SV5, SV6 } };
  86.  
  87.  #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0))
  88.  

set_seenv

  1.  /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */
  2.  STATIC_OVL void
  3.  set_seenv(lev, x0, y0, x, y)
  4.  struct rm *lev;
  5.  int x0, y0, x, y; /* from, to */
  6.  {
  7.      int dx = x - x0, dy = y0 - y;
  8.  
  9.      lev->seenv |= seenv_matrix[sign(dy) + 1][sign(dx) + 1];
  10.  }
  11.  

unset_seenv

  1.  /* Called by blackout(vault.c) when vault guard removes temporary corridor,
  2.     turning spot <x0,y0> back into stone; <x1,y1> is an adjacent spot. */
  3.  void
  4.  unset_seenv(lev, x0, y0, x1, y1)
  5.  struct rm *lev;     /* &levl[x1][y1] */
  6.  int x0, y0, x1, y1; /* from, to; abs(x1-x0)==1 && abs(y0-y1)==1 */
  7.  {
  8.      int dx = x1 - x0, dy = y0 - y1;
  9.  
  10.      lev->seenv &= ~seenv_matrix[dy + 1][dx + 1];
  11.  }
  12.  
  13.  /* -------------------------------------------------------------------------
  14.   */
  15.  
  16.  /* T wall types, one for each row in wall_matrix[][]. */
  17.  #define T_d 0
  18.  #define T_l 1
  19.  #define T_u 2
  20.  #define T_r 3
  21.  
  22.  /*
  23.   * These are the column names of wall_matrix[][].  They are the "results"
  24.   * of a tdwall pattern match.  All T walls are rotated so they become
  25.   * a tdwall.  Then we do a single pattern match, but return the
  26.   * correct result for the original wall by using different rows for
  27.   * each of the wall types.
  28.   */
  29.  #define T_stone 0
  30.  #define T_tlcorn 1
  31.  #define T_trcorn 2
  32.  #define T_hwall 3
  33.  #define T_tdwall 4
  34.  
  35.  static const int wall_matrix[4][5] = {
  36.      { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall }, /* tdwall */
  37.      { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall }, /* tlwall */
  38.      { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall }, /* tuwall */
  39.      { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall }, /* trwall */
  40.  };
  41.  
  42.  /* Cross wall types, one for each "solid" quarter.  Rows of cross_matrix[][].
  43.   */
  44.  #define C_bl 0
  45.  #define C_tl 1
  46.  #define C_tr 2
  47.  #define C_br 3
  48.  
  49.  /*
  50.   * These are the column names for cross_matrix[][].  They express results
  51.   * in C_br (bottom right) terms.  All crosswalls with a single solid
  52.   * quarter are rotated so the solid section is at the bottom right.
  53.   * We pattern match on that, but return the correct result depending
  54.   * on which row we'ere looking at.
  55.   */
  56.  #define C_trcorn 0
  57.  #define C_brcorn 1
  58.  #define C_blcorn 2
  59.  #define C_tlwall 3
  60.  #define C_tuwall 4
  61.  #define C_crwall 5
  62.  
  63.  static const int cross_matrix[4][6] = {
  64.      { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall },
  65.      { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall },
  66.      { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall },
  67.      { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall },
  68.  };
  69.  

t_warn

  1.  /* Print out a T wall warning and all interesting info. */
  2.  STATIC_OVL void
  3.  t_warn(lev)
  4.  struct rm *lev;
  5.  {
  6.      static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x";
  7.      const char *wname;
  8.  
  9.      if (lev->typ == TUWALL)
  10.          wname = "tuwall";
  11.      else if (lev->typ == TLWALL)
  12.          wname = "tlwall";
  13.      else if (lev->typ == TRWALL)
  14.          wname = "trwall";
  15.      else if (lev->typ == TDWALL)
  16.          wname = "tdwall";
  17.      else
  18.          wname = "unknown";
  19.      impossible(warn_str, wname, lev->wall_info & WM_MASK,
  20.                 (unsigned int) lev->seenv);
  21.  }
  22.  

wall_angle

  1.  /*
  2.   * Return the correct graphics character index using wall type, wall mode,
  3.   * and the seen vector.  It is expected that seenv is non zero.
  4.   *
  5.   * All T-wall vectors are rotated to be TDWALL.  All single crosswall
  6.   * blocks are rotated to bottom right.  All double crosswall are rotated
  7.   * to W_X_BLTR.  All results are converted back.
  8.   *
  9.   * The only way to understand this is to take out pen and paper and
  10.   * draw diagrams.  See rm.h for more details on the wall modes and
  11.   * seen vector (SV).
  12.   */
  13.  STATIC_OVL int
  14.  wall_angle(lev)
  15.  struct rm *lev;
  16.  {
  17.      register unsigned int seenv = lev->seenv & 0xff;
  18.      const int *row;
  19.      int col, idx;
  20.  
  21.  #define only(sv, bits) (((sv) & (bits)) && !((sv) & ~(bits)))
  22.      switch (lev->typ) {
  23.      case TUWALL:
  24.          row = wall_matrix[T_u];
  25.          seenv = (seenv >> 4 | seenv << 4) & 0xff; /* rotate to tdwall */
  26.          goto do_twall;
  27.      case TLWALL:
  28.          row = wall_matrix[T_l];
  29.          seenv = (seenv >> 2 | seenv << 6) & 0xff; /* rotate to tdwall */
  30.          goto do_twall;
  31.      case TRWALL:
  32.          row = wall_matrix[T_r];
  33.          seenv = (seenv >> 6 | seenv << 2) & 0xff; /* rotate to tdwall */
  34.          goto do_twall;
  35.      case TDWALL:
  36.          row = wall_matrix[T_d];
  37.      do_twall:
  38.          switch (lev->wall_info & WM_MASK) {
  39.          case 0:
  40.              if (seenv == SV4) {
  41.                  col = T_tlcorn;
  42.              } else if (seenv == SV6) {
  43.                  col = T_trcorn;
  44.              } else if (seenv & (SV3 | SV5 | SV7)
  45.                         || ((seenv & SV4) && (seenv & SV6))) {
  46.                  col = T_tdwall;
  47.              } else if (seenv & (SV0 | SV1 | SV2)) {
  48.                  col = (seenv & (SV4 | SV6) ? T_tdwall : T_hwall);
  49.              } else {
  50.                  t_warn(lev);
  51.                  col = T_stone;
  52.              }
  53.              break;
  54.          case WM_T_LONG:
  55.              if (seenv & (SV3 | SV4) && !(seenv & (SV5 | SV6 | SV7))) {
  56.                  col = T_tlcorn;
  57.              } else if (seenv & (SV6 | SV7) && !(seenv & (SV3 | SV4 | SV5))) {
  58.                  col = T_trcorn;
  59.              } else if ((seenv & SV5)
  60.                         || ((seenv & (SV3 | SV4)) && (seenv & (SV6 | SV7)))) {
  61.                  col = T_tdwall;
  62.              } else {
  63.                  /* only SV0|SV1|SV2 */
  64.                  if (!only(seenv, SV0 | SV1 | SV2))
  65.                      t_warn(lev);
  66.                  col = T_stone;
  67.              }
  68.              break;
  69.          case WM_T_BL:
  70.  #if 0  /* older method, fixed */
  71.              if (only(seenv, SV4|SV5)) {
  72.                  col = T_tlcorn;
  73.              } else if ((seenv & (SV0|SV1|SV2))
  74.                         && only(seenv, SV0|SV1|SV2|SV6|SV7)) {
  75.                  col = T_hwall;
  76.              } else if ((seenv & SV3)
  77.                         || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) {
  78.                  col = T_tdwall;
  79.              } else {
  80.                  if (seenv != SV6)
  81.                      t_warn(lev);
  82.                  col = T_stone;
  83.              }
  84.  #endif /* 0 */
  85.              if (only(seenv, SV4 | SV5))
  86.                  col = T_tlcorn;
  87.              else if ((seenv & (SV0 | SV1 | SV2 | SV7))
  88.                       && !(seenv & (SV3 | SV4 | SV5)))
  89.                  col = T_hwall;
  90.              else if (only(seenv, SV6))
  91.                  col = T_stone;
  92.              else
  93.                  col = T_tdwall;
  94.              break;
  95.          case WM_T_BR:
  96.  #if 0  /* older method, fixed */
  97.              if (only(seenv, SV5|SV6)) {
  98.                  col = T_trcorn;
  99.              } else if ((seenv & (SV0|SV1|SV2))
  100.                         && only(seenv, SV0|SV1|SV2|SV3|SV4)) {
  101.                  col = T_hwall;
  102.              } else if ((seenv & SV7)
  103.                         || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) {
  104.                  col = T_tdwall;
  105.              } else {
  106.                  if (seenv != SV4)
  107.                      t_warn(lev);
  108.                  col = T_stone;
  109.              }
  110.  #endif /* 0 */
  111.              if (only(seenv, SV5 | SV6))
  112.                  col = T_trcorn;
  113.              else if ((seenv & (SV0 | SV1 | SV2 | SV3))
  114.                       && !(seenv & (SV5 | SV6 | SV7)))
  115.                  col = T_hwall;
  116.              else if (only(seenv, SV4))
  117.                  col = T_stone;
  118.              else
  119.                  col = T_tdwall;
  120.  
  121.              break;
  122.          default:
  123.              impossible("wall_angle: unknown T wall mode %d",
  124.                         lev->wall_info & WM_MASK);
  125.              col = T_stone;
  126.              break;
  127.          }
  128.          idx = row[col];
  129.          break;
  130.  
  131.      case SDOOR:
  132.          if (lev->horizontal)
  133.              goto horiz;
  134.      /* fall through */
  135.      case VWALL:
  136.          switch (lev->wall_info & WM_MASK) {
  137.          case 0:
  138.              idx = seenv ? S_vwall : S_stone;
  139.              break;
  140.          case 1:
  141.              idx = seenv & (SV1 | SV2 | SV3 | SV4 | SV5) ? S_vwall : S_stone;
  142.              break;
  143.          case 2:
  144.              idx = seenv & (SV0 | SV1 | SV5 | SV6 | SV7) ? S_vwall : S_stone;
  145.              break;
  146.          default:
  147.              impossible("wall_angle: unknown vwall mode %d",
  148.                         lev->wall_info & WM_MASK);
  149.              idx = S_stone;
  150.              break;
  151.          }
  152.          break;
  153.  
  154.      case HWALL:
  155.      horiz:
  156.          switch (lev->wall_info & WM_MASK) {
  157.          case 0:
  158.              idx = seenv ? S_hwall : S_stone;
  159.              break;
  160.          case 1:
  161.              idx = seenv & (SV3 | SV4 | SV5 | SV6 | SV7) ? S_hwall : S_stone;
  162.              break;
  163.          case 2:
  164.              idx = seenv & (SV0 | SV1 | SV2 | SV3 | SV7) ? S_hwall : S_stone;
  165.              break;
  166.          default:
  167.              impossible("wall_angle: unknown hwall mode %d",
  168.                         lev->wall_info & WM_MASK);
  169.              idx = S_stone;
  170.              break;
  171.          }
  172.          break;
  173.  
  174.  #define set_corner(idx, lev, which, outer, inner, name)    \
  175.      switch ((lev)->wall_info & WM_MASK) {                  \
  176.      case 0:                                                \
  177.          idx = which;                                       \
  178.          break;                                             \
  179.      case WM_C_OUTER:                                       \
  180.          idx = seenv & (outer) ? which : S_stone;           \
  181.          break;                                             \
  182.      case WM_C_INNER:                                       \
  183.          idx = seenv & ~(inner) ? which : S_stone;          \
  184.          break;                                             \
  185.      default:                                               \
  186.          impossible("wall_angle: unknown %s mode %d", name, \
  187.                     (lev)->wall_info &WM_MASK);             \
  188.          idx = S_stone;                                     \
  189.          break;                                             \
  190.      }
  191.  
  192.      case TLCORNER:
  193.          set_corner(idx, lev, S_tlcorn, (SV3 | SV4 | SV5), SV4, "tlcorn");
  194.          break;
  195.      case TRCORNER:
  196.          set_corner(idx, lev, S_trcorn, (SV5 | SV6 | SV7), SV6, "trcorn");
  197.          break;
  198.      case BLCORNER:
  199.          set_corner(idx, lev, S_blcorn, (SV1 | SV2 | SV3), SV2, "blcorn");
  200.          break;
  201.      case BRCORNER:
  202.          set_corner(idx, lev, S_brcorn, (SV7 | SV0 | SV1), SV0, "brcorn");
  203.          break;
  204.  
  205.      case CROSSWALL:
  206.          switch (lev->wall_info & WM_MASK) {
  207.          case 0:
  208.              if (seenv == SV0)
  209.                  idx = S_brcorn;
  210.              else if (seenv == SV2)
  211.                  idx = S_blcorn;
  212.              else if (seenv == SV4)
  213.                  idx = S_tlcorn;
  214.              else if (seenv == SV6)
  215.                  idx = S_trcorn;
  216.              else if (!(seenv & ~(SV0 | SV1 | SV2))
  217.                       && (seenv & SV1 || seenv == (SV0 | SV2)))
  218.                  idx = S_tuwall;
  219.              else if (!(seenv & ~(SV2 | SV3 | SV4))
  220.                       && (seenv & SV3 || seenv == (SV2 | SV4)))
  221.                  idx = S_trwall;
  222.              else if (!(seenv & ~(SV4 | SV5 | SV6))
  223.                       && (seenv & SV5 || seenv == (SV4 | SV6)))
  224.                  idx = S_tdwall;
  225.              else if (!(seenv & ~(SV0 | SV6 | SV7))
  226.                       && (seenv & SV7 || seenv == (SV0 | SV6)))
  227.                  idx = S_tlwall;
  228.              else
  229.                  idx = S_crwall;
  230.              break;
  231.  
  232.          case WM_X_TL:
  233.              row = cross_matrix[C_tl];
  234.              seenv = (seenv >> 4 | seenv << 4) & 0xff;
  235.              goto do_crwall;
  236.          case WM_X_TR:
  237.              row = cross_matrix[C_tr];
  238.              seenv = (seenv >> 6 | seenv << 2) & 0xff;
  239.              goto do_crwall;
  240.          case WM_X_BL:
  241.              row = cross_matrix[C_bl];
  242.              seenv = (seenv >> 2 | seenv << 6) & 0xff;
  243.              goto do_crwall;
  244.          case WM_X_BR:
  245.              row = cross_matrix[C_br];
  246.          do_crwall:
  247.              if (seenv == SV4)
  248.                  idx = S_stone;
  249.              else {
  250.                  seenv = seenv & ~SV4; /* strip SV4 */
  251.                  if (seenv == SV0) {
  252.                      col = C_brcorn;
  253.                  } else if (seenv & (SV2 | SV3)) {
  254.                      if (seenv & (SV5 | SV6 | SV7))
  255.                          col = C_crwall;
  256.                      else if (seenv & (SV0 | SV1))
  257.                          col = C_tuwall;
  258.                      else
  259.                          col = C_blcorn;
  260.                  } else if (seenv & (SV5 | SV6)) {
  261.                      if (seenv & (SV1 | SV2 | SV3))
  262.                          col = C_crwall;
  263.                      else if (seenv & (SV0 | SV7))
  264.                          col = C_tlwall;
  265.                      else
  266.                          col = C_trcorn;
  267.                  } else if (seenv & SV1) {
  268.                      col = seenv & SV7 ? C_crwall : C_tuwall;
  269.                  } else if (seenv & SV7) {
  270.                      col = seenv & SV1 ? C_crwall : C_tlwall;
  271.                  } else {
  272.                      impossible("wall_angle: bottom of crwall check");
  273.                      col = C_crwall;
  274.                  }
  275.  
  276.                  idx = row[col];
  277.              }
  278.              break;
  279.  
  280.          case WM_X_TLBR:
  281.              if (only(seenv, SV1 | SV2 | SV3))
  282.                  idx = S_blcorn;
  283.              else if (only(seenv, SV5 | SV6 | SV7))
  284.                  idx = S_trcorn;
  285.              else if (only(seenv, SV0 | SV4))
  286.                  idx = S_stone;
  287.              else
  288.                  idx = S_crwall;
  289.              break;
  290.  
  291.          case WM_X_BLTR:
  292.              if (only(seenv, SV0 | SV1 | SV7))
  293.                  idx = S_brcorn;
  294.              else if (only(seenv, SV3 | SV4 | SV5))
  295.                  idx = S_tlcorn;
  296.              else if (only(seenv, SV2 | SV6))
  297.                  idx = S_stone;
  298.              else
  299.                  idx = S_crwall;
  300.              break;
  301.  
  302.          default:
  303.              impossible("wall_angle: unknown crosswall mode");
  304.              idx = S_stone;
  305.              break;
  306.          }
  307.          break;
  308.  
  309.      default:
  310.          impossible("wall_angle: unexpected wall type %d", lev->typ);
  311.          idx = S_stone;
  312.      }
  313.      return idx;
  314.  }
  315.  
  316.  /*display.c*/