home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / display.c < prev    next >
Encoding:
Text File  |  1993-08-01  |  34.5 KB  |  1,235 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)display.c    3.1    93/05/15    */
  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. */
  5.  
  6. /*
  7.  *            THE NEW DISPLAY CODE
  8.  *
  9.  * The old display code has been broken up into three parts: vision, display,
  10.  * and drawing.  Vision decides what locations can and cannot be physically
  11.  * seen by the hero.  Display decides _what_ is displayed at a given location.
  12.  * Drawing decides _how_ to draw a monster, fountain, sword, etc.
  13.  *
  14.  * The display system uses information from the vision system to decide
  15.  * what to draw at a given location.  The routines for the vision system
  16.  * can be found in vision.c and vision.h.  The routines for display can
  17.  * be found in this file (display.c) and display.h.  The drawing routines
  18.  * are part of the window port.  See doc/window.doc for the drawing
  19.  * interface.
  20.  *
  21.  * The display system deals with an abstraction called a glyph.  Anything
  22.  * that could possibly be displayed has a unique glyph identifier.
  23.  *
  24.  * What is seen on the screen is a combination of what the hero remembers
  25.  * and what the hero currently sees.  Objects and dungeon features (walls
  26.  * doors, etc) are remembered when out of sight.  Monsters and temporary
  27.  * effects are not remembered.  Each location on the level has an
  28.  * associated glyph.  This is the hero's _memory_ of what he or she has
  29.  * seen there before.
  30.  *
  31.  * Display rules:
  32.  *
  33.  *    If the location is in sight, display in order:
  34.  *        visible monsters
  35.  *        visible objects
  36.  *        known traps
  37.  *        background
  38.  *
  39.  *    If the location is out of sight, display in order:
  40.  *        sensed monsters (telepathy)
  41.  *        memory
  42.  *
  43.  *
  44.  *
  45.  * Here is a list of the major routines in this file to be used externally:
  46.  *
  47.  * newsym
  48.  *
  49.  * Possibly update the screen location (x,y).  This is the workhorse routine.
  50.  * It is always correct --- where correct means following the in-sight/out-
  51.  * of-sight rules.  **Most of the code should use this routine.**  This
  52.  * routine updates the map and displays monsters.
  53.  *
  54.  *
  55.  * map_background
  56.  * map_object
  57.  * map_trap
  58.  * unmap_object
  59.  *
  60.  * If you absolutely must override the in-sight/out-of-sight rules, there
  61.  * are two possibilities.  First, you can mess with vision to force the
  62.  * location in sight then use newsym(), or you can  use the map_* routines.
  63.  * The first has not been tried [no need] and the second is used in the
  64.  * detect routines --- detect object, magic mapping, etc.  The map_*
  65.  * routines *change* what the hero remembers.  All changes made by these
  66.  * routines will be sticky --- they will survive screen redraws.  Do *not*
  67.  * use these for things that only temporarily change the screen.  These
  68.  * routines are also used directly by newsym().  unmap_object is used to
  69.  * clear a remembered object when/if detection reveals it isn't there.
  70.  *
  71.  *
  72.  * show_glyph
  73.  *
  74.  * This is direct (no processing in between) buffered access to the screen.
  75.  * Temporary screen effects are run through this and its companion,
  76.  * flush_screen().  There is yet a lower level routine, print_glyph(),
  77.  * but this is unbuffered and graphic dependent (i.e. it must be surrounded
  78.  * by graphic set-up and tear-down routines).  Do not use print_glyph().
  79.  *
  80.  *
  81.  * see_monsters
  82.  * see_objects
  83.  *
  84.  * These are only used when something affects all of the monsters or
  85.  * objects.  For objects, the only thing is hallucination.  For monsters,
  86.  * there are hallucination and changing from/to blindness, etc.
  87.  *
  88.  *
  89.  * tmp_at
  90.  *
  91.  * This is a useful interface for displaying temporary items on the screen.
  92.  * Its interface is different than previously, so look at it carefully.
  93.  *
  94.  *
  95.  *
  96.  * Parts of the rm structure that are used:
  97.  *
  98.  *    typ    - What is really there.
  99.  *    glyph    - What the hero remembers.  This will never be a monster.
  100.  *          Monsters "float" above this.
  101.  *    lit    - True if the position is lit.  An optimization for
  102.  *          lit/unlit rooms.
  103.  *    waslit    - True if the position was *remembered* as lit.
  104.  *    seen    - Set to true when the location is seen or felt as it really
  105.  *          is.  This is used primarily for walls, which look like stone
  106.  *          if seen from the outside of a room.  However, this is
  107.  *          also used as a guide for blind heros.  If the hero has
  108.  *          seen or felt a room feature underneath a boulder, when the
  109.  *          boulder is moved, the hero should see it again.  This is
  110.  *          also used as an indicator for unmapping detected objects.
  111.  *
  112.  *    doormask   - Additional information for the typ field.
  113.  *    horizontal - Indicates whether the wall or door is horizontal or
  114.  *             vertical.
  115.  */
  116. #include "hack.h"
  117.  
  118. static void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
  119. static int FDECL(swallow_to_glyph, (int, int));
  120.  
  121. #ifdef INVISIBLE_OBJECTS
  122. /*
  123.  * vobj_at()
  124.  *
  125.  * Returns a pointer to an object if the hero can see an object at the
  126.  * given location.  This takes care of invisible objects.  NOTE, this
  127.  * assumes that the hero is not blind and on top of the object pile.
  128.  * It does NOT take into account that the location is out of sight, or,
  129.  * say, one can see blessed, etc.
  130.  */
  131. struct obj *
  132. vobj_at(x,y)
  133.     xchar x,y;
  134. {
  135.     register struct obj *obj = level.objects[x][y];
  136.  
  137.     while (obj) {
  138.     if (!obj->oinvis || See_invisible) return obj;
  139.     obj = obj->nexthere;
  140.     }
  141.     return ((struct obj *) 0);
  142. }
  143. #endif    /* else vobj_at() is defined in display.h */
  144.  
  145. /*
  146.  * The routines map_background(), map_object(), and map_trap() could just
  147.  * as easily be:
  148.  *
  149.  *    map_glyph(x,y,glyph,show)
  150.  *
  151.  * Which is called with the xx_to_glyph() in the call.  Then I can get
  152.  * rid of 3 routines that don't do very much anyway.  And then stop
  153.  * having to create fake objects and traps.  However, I am reluctant to
  154.  * make this change.
  155.  */
  156.  
  157. /*
  158.  * map_background()
  159.  *
  160.  * Make the real background part of our map.  This routine assumes that
  161.  * the hero can physically see the location.  Update the screen if directed.
  162.  */
  163. void
  164. map_background(x, y, show)
  165.     register xchar x,y;
  166.     register int  show;
  167. {
  168.     register int glyph = back_to_glyph(x,y);
  169.  
  170.     if (level.flags.hero_memory)
  171.     levl[x][y].glyph = glyph;
  172.     if (show) show_glyph(x,y, glyph);
  173. }
  174.  
  175. /*
  176.  * map_trap()
  177.  *
  178.  * Map the trap and print it out if directed.  This routine assumes that the
  179.  * hero can physically see the location.
  180.  */
  181. void
  182. map_trap(trap, show)
  183.     register struct trap *trap;
  184.     register int     show;
  185. {
  186.     register int x = trap->tx, y = trap->ty;
  187.     register int glyph = trap_to_glyph(trap);
  188.  
  189.     if (level.flags.hero_memory)
  190.     levl[x][y].glyph = glyph;
  191.     if (show) show_glyph(x, y, glyph);
  192. }
  193.  
  194. /*
  195.  * map_object()
  196.  *
  197.  * Map the given object.  This routine assumes that the hero can physically
  198.  * see the location of the object.  Update the screen if directed.
  199.  */
  200. void
  201. map_object(obj, show)
  202.     register struct obj *obj;
  203.     register int    show;
  204. {
  205.     register int x = obj->ox, y = obj->oy;
  206.     register int glyph = obj_to_glyph(obj);
  207.  
  208.     if (level.flags.hero_memory)
  209.     levl[x][y].glyph = glyph;
  210.     if (show) show_glyph(x, y, glyph);
  211. }
  212.  
  213. /*
  214.  * unmap_object()
  215.  *
  216.  * Remove something from the map when detection reveals that it isn't
  217.  * there any more.  Replace it with background or known trap, but not
  218.  * with any other remembered object.  No need to update the display;
  219.  * a full update is imminent.
  220.  *
  221.  * This isn't quite correct due to overloading of the seen bit.  But
  222.  * it works well enough for now.
  223.  */
  224. void
  225. unmap_object(x, y)
  226.     register int x, y;
  227. {
  228.     register struct trap *trap;
  229.  
  230.     if (!level.flags.hero_memory) return;
  231.  
  232.     if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
  233.     map_trap(trap, 0);
  234.     else if (levl[x][y].seen) {
  235.     struct rm *lev = &levl[x][y];
  236.  
  237.     map_background(x, y, 0);
  238.  
  239.     /* turn remembered dark room squares dark */
  240.     if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
  241.                                 lev->typ == ROOM)
  242.         lev->glyph = cmap_to_glyph(S_stone);
  243.     } else 
  244.     levl[x][y].glyph = cmap_to_glyph(S_stone);    /* default val */
  245. }
  246.  
  247.  
  248. /*
  249.  * map_location()
  250.  *
  251.  * Make whatever at this location show up.  This is only for non-living
  252.  * things.  This will not handle feeling invisible objects correctly.
  253.  *
  254.  * Internal to display.c, this is a #define for speed.
  255.  */
  256. #define _map_location(x,y,show)                        \
  257. {                                    \
  258.     register struct obj   *obj;                        \
  259.     register struct trap  *trap;                    \
  260.                                     \
  261.     if ((obj = vobj_at(x,y)) && !covers_objects(x,y))            \
  262.     map_object(obj,show);                        \
  263.     else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))    \
  264.     map_trap(trap,show);                        \
  265.     else                                \
  266.     map_background(x,y,show);                    \
  267. }
  268.  
  269. void map_location(x,y,show)
  270.     int x, y, show;
  271. {
  272.     _map_location(x,y,show);
  273. }
  274.  
  275.  
  276. /*
  277.  * display_monster()
  278.  *
  279.  * Note that this is *not* a map_XXXX() function!  Monsters sort of float
  280.  * above everything.
  281.  *
  282.  * Yuck.  Display body parts by recognizing that the display position is
  283.  * not the same as the monster position.  Currently the only body part is
  284.  * a worm tail.
  285.  *  
  286.  */
  287. static void
  288. display_monster(x, y, mon, in_sight, worm_tail)
  289.     register xchar x, y;    /* display position */
  290.     register struct monst *mon;    /* monster to display */
  291.     int in_sight;        /* TRUE if the monster is physically seen */
  292.     register xchar worm_tail;    /* mon is actually a worm tail */
  293. {
  294.     register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
  295.     register int sensed = mon_mimic &&
  296.     (Protection_from_shape_changers || sensemon(mon));
  297.  
  298.     /*
  299.      * We must do the mimic check first.  If the mimic is mimicing something,
  300.      * and the location is in sight, we have to change the hero's memory
  301.      * so that when the position is out of sight, the hero remembers what
  302.      * the mimic was mimicing.
  303.      */
  304.  
  305.     if (mon_mimic && in_sight) {
  306.     switch (mon->m_ap_type) {
  307.         default:
  308.         impossible("display_monster:  bad m_ap_type value [ = %d ]",
  309.                             (int) mon->m_ap_type);
  310.         case M_AP_NOTHING:
  311.         show_glyph(x, y, mon_to_glyph(mon));
  312.         break;
  313.  
  314.         case M_AP_FURNITURE: {
  315.         /*
  316.          * This is a poor man's version of map_background().  I can't
  317.          * use map_background() because we are overriding what is in
  318.          * the 'typ' field.  Maybe have map_background()'s parameters
  319.          * be (x,y,glyph) instead of just (x,y).
  320.          *
  321.          * mappearance is currently set to an S_ index value in
  322.          * makemon.c.
  323.          */
  324.         register int glyph = cmap_to_glyph(mon->mappearance);
  325.         levl[x][y].glyph = glyph;
  326.         if (!sensed) show_glyph(x,y, glyph);
  327.         break;
  328.         }
  329.  
  330.         case M_AP_OBJECT: {
  331.         struct obj obj;    /* Make a fake object to send    */
  332.                 /* to map_object().        */
  333.         obj.ox = x;
  334.         obj.oy = y;
  335.         obj.otyp = mon->mappearance;
  336.         obj.corpsenm = PM_TENGU;    /* if mimicing a corpse */
  337.         map_object(&obj,!sensed);
  338.         break;
  339.         }
  340.  
  341.         case M_AP_MONSTER:
  342.         show_glyph(x,y, monnum_to_glyph(what_mon(mon->mappearance)));
  343.         break;
  344.     }
  345.     
  346.     }
  347.  
  348.     /* If the mimic is unsucessfully mimicing something, display the monster */
  349.     if (!mon_mimic || sensed) {
  350.     if (mon->mtame) {
  351.         if (worm_tail)
  352.         show_glyph(x,y, petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
  353.         else    
  354.         show_glyph(x,y, pet_to_glyph(mon));
  355.     } else {
  356.         if (worm_tail)
  357.         show_glyph(x,y, monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
  358.         else    
  359.         show_glyph(x,y, mon_to_glyph(mon));
  360.     }
  361.     }
  362. }
  363.  
  364. /*
  365.  * feel_location()
  366.  *
  367.  * Feel the given location.  This assumes that the hero is blind and that
  368.  * the given position is either the hero's or one of the eight squares
  369.  * adjacent to the hero (except for a boulder push).
  370.  */
  371. void
  372. feel_location(x, y)
  373.     xchar x, y;
  374. {
  375.     struct rm *lev = &(levl[x][y]);
  376.     struct obj *boulder;
  377.     register struct monst *mon;
  378.  
  379.     /* The hero can't feel non pool locations while under water. */
  380.     if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
  381.     return;
  382.  
  383.     /* If the hero is not in a corridor, then she will feel the wall as a */
  384.     /* wall.  It doesn't matter if the hero is levitating or not.      */
  385.     if ((IS_WALL(lev->typ) || lev->typ == SDOOR) &&
  386.                         levl[u.ux][u.uy].typ != CORR)
  387.     lev->seen = 1;
  388.  
  389.     if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  390.     /*
  391.      * Levitation Rules.  It is assumed that the hero can feel the state
  392.      * of the walls around herself and can tell if she is in a corridor,
  393.      * room, or doorway.  Boulders are felt because they are large enough.
  394.      * Anything else is unknown because the hero can't reach the ground.
  395.      * This makes things difficult.
  396.      *
  397.      * Check (and display) in order:
  398.      *
  399.      *    + Stone, walls, and closed doors.
  400.      *    + Boulders.  [see a boulder before a doorway]
  401.      *    + Doors.
  402.      *    + Room/water positions
  403.      *    + Everything else (hallways!)
  404.      */
  405.     if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
  406.                 (lev->doormask & (D_LOCKED | D_CLOSED)))) {
  407.         map_background(x, y, 1);
  408.     } else if ((boulder = sobj_at(BOULDER,x,y)) != 0) {
  409.         map_object(boulder, 1);
  410.     } else if (IS_DOOR(lev->typ)) {
  411.         map_background(x, y, 1);
  412.     } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
  413.         /*
  414.          * An open room or water location.  Normally we wouldn't touch
  415.          * this, but we have to get rid of remembered boulder symbols.
  416.          * This will only occur in rare occations when the hero goes
  417.          * blind and doesn't find a boulder where expected (something
  418.          * came along and picked it up).  We know that there is not a
  419.          * boulder at this location.  Show fountains, pools, etc.
  420.          * underneath if already seen.  Otherwise, show the appropriate
  421.          * floor symbol.
  422.          *
  423.          * This isn't quite correct.  If the boulder was on top of some
  424.          * other objects they should be seen once the boulder is removed.
  425.          * However, we have no way of knowing that what is there now
  426.          * was there then.  So we let the hero have a lapse of memory.
  427.          * We could also just display what is currently on the top of the
  428.          * object stack (if anything).
  429.          */
  430.         if (lev->glyph == objnum_to_glyph(BOULDER)) {
  431.         if (lev->typ != ROOM && lev->seen) {
  432.             map_background(x, y, 1);
  433.         } else {
  434.             lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
  435.                            cmap_to_glyph(S_stone);
  436.             show_glyph(x,y,lev->glyph);
  437.         }
  438.         }
  439.     } else {
  440.         /* We feel it (I think hallways are the only things left). */
  441.         map_background(x, y, 1);
  442.         /* Corridors are never felt as lit (unless remembered that way) */
  443.         /* (lit_corridor only).                        */
  444.         if (lev->typ == CORR &&
  445.             lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
  446.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  447.     }
  448.     } else {
  449.     _map_location(x, y, 1);
  450.  
  451.     if (Punished) {
  452.         /*
  453.          * A ball or chain is only felt if it is first on the object
  454.          * location list.  Otherwise, we need to clear the felt bit ---
  455.          * something has been dropped on the ball/chain.  If the bit is
  456.          * not cleared, then when the ball/chain is moved it will drop
  457.          * the wrong glyph.
  458.          */
  459.         if (uchain->ox == x && uchain->oy == y) {
  460.         if (level.objects[x][y] == uchain)
  461.             u.bc_felt |= BC_CHAIN;
  462.         else
  463.             u.bc_felt &= ~BC_CHAIN;    /* do not feel the chain */
  464.         }
  465.         if (!carried(uball) && uball->ox == x && uball->oy == y) {
  466.         if (level.objects[x][y] == uball)
  467.             u.bc_felt |= BC_BALL;
  468.         else
  469.             u.bc_felt &= ~BC_BALL;    /* do not feel the ball */
  470.         }
  471.     }
  472.  
  473.     /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
  474.     if (lev->typ == ROOM &&
  475.             lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
  476.         show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
  477.     else if (lev->typ == CORR &&
  478.             lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
  479.         show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
  480.     }
  481.     /* draw monster on top if we can sense it */
  482.     if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
  483.     display_monster(x,y,mon,1,((x != mon->mx)  || (y != mon->my)));
  484. }
  485.  
  486. /*
  487.  * newsym()
  488.  *
  489.  * Possibly put a new glyph at the given location.
  490.  */
  491. void
  492. newsym(x,y)
  493.     register xchar x,y;
  494. {
  495.     register struct monst *mon;
  496.     register struct rm *lev = &(levl[x][y]);
  497.     register int see_it;
  498.     register xchar worm_tail;
  499.  
  500.     /* only permit updating the hero when swallowed */
  501.     if (u.uswallow) {
  502.     if (x == u.ux && y == u.uy) display_self();
  503.     return;
  504.     }
  505.     if (Underwater && !Is_waterlevel(&u.uz)) {
  506.     /* don't do anything unless (x,y) is an adjacent underwater position */
  507.     int dx, dy;
  508.     if (!is_pool(x,y)) return;
  509.     dx = x - u.ux;    if (dx < 0) dx = -dx;
  510.     dy = y - u.uy;    if (dy < 0) dy = -dy;
  511.     if (dx > 1 || dy > 1) return;
  512.     }
  513.  
  514.     /* Can physically see the location. */
  515.     if (cansee(x,y)) {
  516.     lev->waslit = (lev->lit!=0);    /* remember lit condition */
  517.  
  518.     if (x == u.ux && y == u.uy) {
  519.         if (canseeself()) {
  520.         _map_location(x,y,0);    /* map *under* self */
  521.         display_self();
  522.         } else
  523.         /* we can see what is there */
  524.         _map_location(x,y,1);
  525.     }
  526.     else if ((mon = m_at(x,y)) &&
  527.          ((see_it = mon_visible(mon)) || sensemon(mon))) {
  528.         _map_location(x,y,0);     /* map under the monster */
  529.             worm_tail = ((x != mon->mx)  || (y != mon->my));
  530.         display_monster(x,y,mon,see_it,worm_tail);
  531.     }
  532.     else
  533.         _map_location(x,y,1);    /* map the location */
  534.     }
  535.  
  536.     /* Can't see the location. */
  537.     else {
  538.     if (x == u.ux && y == u.uy) {
  539.         feel_location(u.ux, u.uy);        /* forces an update */
  540.  
  541.         if (canseeself()) display_self();
  542.     }
  543.     else if ((mon = m_at(x,y)) && sensemon(mon) &&
  544.                      !((x != mon->mx)  || (y != mon->my))) {
  545.         /* Monsters are printed every time. */
  546.         display_monster(x,y,mon,0,0);
  547.     }
  548.     /*
  549.      * If the location is remembered as being both dark (waslit is false)
  550.      * and lit (glyph is a lit room or lit corridor) then it was either:
  551.      *
  552.      *    (1) A dark location that the hero could see through night
  553.      *        vision.
  554.      *
  555.      *    (2) Darkened while out of the hero's sight.  This can happen
  556.      *        when cursed scroll of light is read.
  557.      *
  558.      * In either case, we have to manually correct the hero's memory to
  559.      * match waslit.  Deciding when to change waslit is non-trivial.
  560.      *
  561.      *  Note:  If flags.lit_corridor is set, then corridors act like room
  562.      *       squares.  That is, they light up if in night vision range.
  563.      *       If flags.lit_corridor is not set, then corridors will
  564.      *       remain dark unless lit by a light spell.
  565.      *
  566.      * These checks and changes must be here and not in back_to_glyph().
  567.      * They are dependent on the position being out of sight.
  568.      */
  569.     else if (!lev->waslit) {
  570.         if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&
  571.                                 lev->typ == CORR)
  572.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  573.         else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
  574.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
  575.         else
  576.         goto show_mem;
  577.     } else {
  578. show_mem:
  579.         show_glyph(x, y, lev->glyph);
  580.     }
  581.     }
  582. }
  583.  
  584.  
  585. /*
  586.  * shieldeff()
  587.  *
  588.  * Put magic shield pyrotechnics at the given location.  This *could* be
  589.  * pulled into a platform dependent routine for fancier graphics if desired.
  590.  */
  591. void
  592. shieldeff(x,y)
  593.     xchar x,y;
  594. {
  595.     register int i;
  596.  
  597.     if (cansee(x,y)) {    /* Don't see anything if can't see the location */
  598.     for (i = 0; i < SHIELD_COUNT; i++) {
  599.         show_glyph(x, y, cmap_to_glyph(shield_static[i]));
  600.         flush_screen(1);    /* make sure the glyph shows up */
  601.         delay_output();
  602.     }
  603.     newsym(x,y);        /* restore the old information */
  604.     }
  605. }
  606.  
  607.  
  608. /*
  609.  * tmp_at()
  610.  *
  611.  * Temporarily place glyphs on the screen.  Do not call delay_output().  It
  612.  * is up to the caller to decide if it wants to wait [presently, everyone
  613.  * but explode() wants to delay].
  614.  *
  615.  * Call:
  616.  *    (DISP_BEAM,   glyph)    open, initialize glyph
  617.  *    (DISP_FLASH,  glyph)    open, initialize glyph
  618.  *    (DISP_CHANGE, glyph)    change glyph
  619.  *    (DISP_END,    0)    close & clean up (second argument doesn't
  620.  *                matter)
  621.  *    (x, y)            display the glyph at the location
  622.  *
  623.  * DISP_BEAM  - Display the given glyph at each location, but do not erase
  624.  *        any until the close call.
  625.  * DISP_FLASH - Display the given glyph at each location, but erase the
  626.  *        previous location's glyph.
  627.  */
  628. void
  629. tmp_at(x, y)
  630.     int x, y;
  631. {
  632.     static coord saved[COLNO];    /* prev positions, only for DISP_BEAM */
  633.     static int sidx = 0;    /* index of saved previous positions */
  634.     static int sx = -1, sy;    /* previous position, only for DISP_FLASH */
  635.     static int status;        /* either DISP_BEAM or DISP_FLASH */
  636.     static int glyph;        /* glyph to use when printing */
  637.  
  638.     switch (x) {
  639.     case DISP_BEAM:
  640.     case DISP_FLASH:
  641.         status = x;
  642.         glyph  = y;
  643.         flush_screen(0);    /* flush buffered glyphs */
  644.         break;
  645.  
  646.     case DISP_CHANGE:
  647.         glyph = y;
  648.         break;
  649.  
  650.     case DISP_END:
  651.         if (status == DISP_BEAM) {
  652.         register int i;
  653.  
  654.         /* Erase (reset) from source to end */
  655.         for (i = 0; i < sidx; i++)
  656.             newsym(saved[i].x,saved[i].y);
  657.         sidx = 0;
  658.         
  659.         } else if (sx >= 0) {    /* DISP_FLASH (called at least once) */
  660.         newsym(sx,sy);    /* reset the location */
  661.         sx = -1;    /* reset sx to an illegal pos for next time */
  662.         }
  663.         break;
  664.  
  665.     default:    /* do it */
  666.         if (!cansee(x,y)) break;
  667.  
  668.         if (status == DISP_BEAM) {
  669.         saved[sidx  ].x = x;    /* save pos for later erasing */
  670.         saved[sidx++].y = y;
  671.         }
  672.  
  673.         else {    /* DISP_FLASH */
  674.         if (sx >= 0)        /* not first call */
  675.             newsym(sx,sy);    /* update the old position */
  676.  
  677.         sx = x;        /* save previous pos for next call */
  678.         sy = y;
  679.         }
  680.  
  681.         show_glyph(x,y,glyph);    /* show it */
  682.         flush_screen(0);        /* make sure it shows up */
  683.         break;
  684.     } /* end case */
  685. }
  686.  
  687.  
  688. /*
  689.  * swallowed()
  690.  *
  691.  * The hero is swallowed.  Show a special graphics sequence for this.  This
  692.  * bypasses all of the display routines and messes with buffered screen
  693.  * directly.  This method works because both vision and display check for
  694.  * being swallowed.
  695.  */
  696. void
  697. swallowed(first)
  698.     int first;
  699. {
  700.     static xchar lastx, lasty;    /* last swallowed position */
  701.     int swallower;
  702.  
  703.     if (first)
  704.     cls();
  705.     else {
  706.     register int x, y;
  707.  
  708.     /* Clear old location */
  709.     for (y = lasty-1; y <= lasty+1; y++)
  710.         if(isok(lastx,y)) {
  711.         for (x = lastx-1; x <= lastx+1; x++)
  712.             show_glyph(x,y,cmap_to_glyph(S_stone));
  713.         }
  714.     }
  715.  
  716.     swallower = monsndx(u.ustuck->data);
  717.     /*
  718.      *  Display the hero surrounded by the monster's stomach.
  719.      */
  720.     if(isok(u.ux, u.uy-1)) {
  721.     show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
  722.     show_glyph(u.ux  , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
  723.     show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
  724.     }
  725.  
  726.     show_glyph(u.ux-1, u.uy  , swallow_to_glyph(swallower, S_sw_ml));
  727.     display_self();
  728.     show_glyph(u.ux+1, u.uy  , swallow_to_glyph(swallower, S_sw_mr));
  729.  
  730.     if(isok(u.ux, u.uy+1)) {
  731.     show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
  732.     show_glyph(u.ux  , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
  733.     show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
  734.     }
  735.  
  736.     /* Update the swallowed position. */
  737.     lastx = u.ux;
  738.     lasty = u.uy;
  739. }
  740.  
  741. /*
  742.  * under_water()
  743.  *
  744.  * Similar to swallowed() in operation.  Shows hero when underwater
  745.  * except when in water level.  Special routines exist for that.
  746.  */
  747. void
  748. under_water(mode)
  749.     int mode;
  750. {
  751.     static xchar lastx, lasty;
  752.     static boolean dela;
  753.     register int x, y;
  754.  
  755.     /* swallowing has a higher precedence than under water */
  756.     if (Is_waterlevel(&u.uz) || u.uswallow) return;
  757.  
  758.     /* full update */
  759.     if (mode == 1 || dela) {
  760.     cls();
  761.     dela = FALSE;
  762.     }   
  763.     /* delayed full update */
  764.     else if (mode == 2) {
  765.     dela = TRUE;
  766.     return;
  767.     }
  768.     /* limited update */
  769.     else {
  770.     for (y = lasty-1; y <= lasty+1; y++)
  771.         for (x = lastx-1; x <= lastx+1; x++)
  772.         if (isok(x,y)) 
  773.             show_glyph(x,y,cmap_to_glyph(S_stone));
  774.     }
  775.     for (x = u.ux-1; x <= u.ux+1; x++)
  776.     for (y = u.uy-1; y <= u.uy+1; y++)
  777.         if (isok(x,y) && is_pool(x,y)) {
  778.         if (Blind && !(x == u.ux && y == u.uy))
  779.             show_glyph(x,y,cmap_to_glyph(S_stone));
  780.         else    
  781.             newsym(x,y);
  782.         }
  783.     lastx = u.ux;
  784.     lasty = u.uy;
  785. }
  786.  
  787.  
  788. /* ========================================================================= */
  789.  
  790. /*
  791.  * Loop through all of the monsters and update them.  Called when:
  792.  *    + going blind & telepathic
  793.  *    + regaining sight & telepathic
  794.  *    + hallucinating
  795.  *    + doing a full screen redraw
  796.  *    + see invisible times out or a ring of see invisible is taken off
  797.  *    + when a potion of see invisible is quaffed or a ring of see
  798.  *      invisible is put on
  799.  *    + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
  800.  *    + losing telepathy while blind [xkilled() in mon.c, attrcurse() in
  801.  *      sit.c]
  802.  */
  803. void
  804. see_monsters()
  805. {
  806.     register struct monst *mon;
  807.     for (mon = fmon; mon; mon = mon->nmon) {
  808.     newsym(mon->mx,mon->my);
  809.     if (mon->wormno) see_wsegs(mon);
  810.     }
  811. }
  812.  
  813. /*
  814.  * Block/unblock light depending on what a mimic is mimicing and if it's
  815.  * invisible or not.  Should be called only when the state of See_invisible
  816.  * changes.
  817.  */
  818. void
  819. set_mimic_blocking()
  820. {
  821.     register struct monst *mon;
  822.     for (mon = fmon; mon; mon = mon->nmon)
  823.     if(mon->minvis &&
  824.        ((mon->m_ap_type == M_AP_FURNITURE &&
  825.           (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))||
  826.         (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
  827.         if(See_invisible)
  828.         block_point(mon->mx, mon->my);
  829.         else
  830.         unblock_point(mon->mx, mon->my);
  831.     }
  832. }
  833.  
  834. /*
  835.  * Loop through all of the object *locations* and update them.  Called when
  836.  *    + hallucinating.
  837.  */
  838. void
  839. see_objects()
  840. {
  841.     register struct obj *obj;
  842.     for(obj = fobj; obj; obj = obj->nobj)
  843.     if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
  844. }
  845.  
  846. /*
  847.  * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
  848.  */
  849. void
  850. curs_on_u()
  851. {
  852.     flush_screen(1);    /* Flush waiting glyphs & put cursor on hero */
  853. }
  854.  
  855. int
  856. doredraw()
  857. {
  858.     docrt();
  859.     return 0;
  860. }
  861.  
  862. void
  863. docrt()
  864. {
  865.     register int x,y;
  866.     register struct rm *lev;
  867.  
  868.     if (!u.ux) return; /* display isn't ready yet */
  869.  
  870.     if (u.uswallow) {
  871.     swallowed(1);
  872.     return;
  873.     }
  874.     if (Underwater && !Is_waterlevel(&u.uz)) {
  875.     under_water(1);
  876.     return;
  877.     }
  878.  
  879.     /* shut down vision */
  880.     vision_recalc(2);
  881.  
  882.     /*
  883.      * This routine assumes that cls() does the following:
  884.      *      + fills the physical screen with the symbol for rock
  885.      *      + clears the glyph buffer
  886.      */
  887.     cls();
  888.  
  889.     /* display memory */
  890.     for (x = 1; x < COLNO; x++) {
  891.     lev = &levl[x][0];
  892.     for (y = 0; y < ROWNO; y++, lev++)
  893.         if (lev->glyph != cmap_to_glyph(S_stone))
  894.         show_glyph(x,y,lev->glyph);
  895.     }
  896.  
  897.     /* see what is to be seen */
  898.     vision_recalc(0);
  899.  
  900.     /* overlay with monsters */
  901.     see_monsters();
  902.  
  903.     flags.botlx = 1;    /* force a redraw of the bottom line */
  904. }
  905.  
  906.  
  907. /* ========================================================================= */
  908. /* Glyph Buffering (3rd screen) ============================================ */
  909.  
  910. typedef struct {
  911.     xchar new;        /* perhaps move this bit into the rm strucure. */
  912.     int   glyph;
  913. } gbuf_entry;
  914.  
  915. static gbuf_entry gbuf[ROWNO][COLNO];
  916. static char gbuf_start[ROWNO];
  917. static char gbuf_stop[ROWNO];
  918.  
  919. /*
  920.  * Store the glyph in the 3rd screen for later flushing.
  921.  */
  922. void
  923. show_glyph(x,y,glyph)
  924.     xchar x,y;
  925.     int   glyph;
  926. {
  927.     /*
  928.      * Check for bad positions and glyphs.
  929.      */
  930.     if (x <= 0 || x >= COLNO || y < 0 || y >= ROWNO) {
  931.     const char *text;
  932.     int  offset;
  933.  
  934.     /* column 0 is invalid, but it's often used as a flag, so ignore it */
  935.     if (x == 0) return;
  936.  
  937.     /*
  938.      *  This assumes an ordering of the offsets.  See display.h for
  939.      *  the definition.
  940.      */
  941.     if (glyph >= GLYPH_SWALLOW_OFF) {        /* swallow border */
  942.         text = "swallow border";    offset = glyph - GLYPH_SWALLOW_OFF;
  943.     }else if (glyph >= GLYPH_ZAP_OFF) {        /* zap beam */
  944.         text = "zap beam";        offset = glyph - GLYPH_ZAP_OFF;
  945.     } else if (glyph >= GLYPH_CMAP_OFF) {        /* cmap */
  946.         text = "cmap_index";    offset = glyph - GLYPH_CMAP_OFF;
  947.     } else if (glyph >= GLYPH_TRAP_OFF) {        /* trap */
  948.         text = "trap";        offset = glyph - GLYPH_TRAP_OFF;
  949.     } else if (glyph >= GLYPH_OBJ_OFF) {        /* object */
  950.         text = "object";        offset = glyph - GLYPH_OBJ_OFF;
  951.     } else if (glyph >= GLYPH_BODY_OFF) {        /* a corpse */
  952.         text = "corpse";        offset = glyph - GLYPH_BODY_OFF;
  953.     } else {                    /* a monster */
  954.         text = "monster";        offset = glyph;
  955.     }
  956.  
  957.     impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",
  958.                         x, y, glyph, text, offset);
  959.     return;
  960.     }
  961.  
  962.     if (glyph >= MAX_GLYPH) {
  963.     impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",
  964.                     glyph, MAX_GLYPH, x, y);
  965.     return;
  966.     }
  967.  
  968.     if (gbuf[y][x].glyph != glyph) {
  969.     gbuf[y][x].glyph = glyph;
  970.     gbuf[y][x].new   = 1;
  971.     if (gbuf_start[y] > x) gbuf_start[y] = x;
  972.     if (gbuf_stop[y]  < x) gbuf_stop[y]  = x;
  973.     }
  974. }
  975.  
  976.  
  977. /*
  978.  * Reset the changed glyph borders so that none of the 3rd screen has
  979.  * changed.
  980.  */
  981. #define reset_glyph_bbox()            \
  982.     {                        \
  983.     int i;                    \
  984.                         \
  985.     for (i = 0; i < ROWNO; i++) {        \
  986.         gbuf_start[i] = COLNO-1;        \
  987.         gbuf_stop[i]  = 0;            \
  988.     }                    \
  989.     }
  990.  
  991.  
  992. static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
  993. /*
  994.  * Turn the 3rd screen into stone.
  995.  */
  996. void
  997. clear_glyph_buffer()
  998. {
  999.     register int x, y;
  1000.     register gbuf_entry *gptr;
  1001.  
  1002.     for (y = 0; y < ROWNO; y++) {
  1003.     gptr = &gbuf[y][0];
  1004.     for (x = COLNO; x; x--) {
  1005.         *gptr++ = nul_gbuf;
  1006.     }
  1007.     }
  1008.     reset_glyph_bbox();
  1009. }
  1010.  
  1011. /*
  1012.  * Assumes that the indicated positions are filled with S_stone glyphs.
  1013.  */
  1014. void
  1015. row_refresh(start,stop,y)
  1016.     int start,stop,y;
  1017. {
  1018.     register int x;
  1019.  
  1020.     for (x = start; x <= stop; x++)
  1021.     if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
  1022.         print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
  1023. }
  1024.  
  1025. void
  1026. cls()
  1027. {
  1028.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
  1029.     flags.botlx = 1;        /* force update of botl window */
  1030.     clear_nhwindow(WIN_MAP);    /* clear physical screen */
  1031.  
  1032.     clear_glyph_buffer();    /* this is sort of an extra effort, but OK */
  1033. }
  1034.  
  1035. /*
  1036.  * Synch the third screen with the display.
  1037.  */
  1038. void
  1039. flush_screen(cursor_on_u)
  1040.     int cursor_on_u;
  1041. {
  1042.     /* Prevent infinite loops on errors:
  1043.      *        flush_screen->print_glyph->impossible->pline->flush_screen
  1044.      */
  1045.     static   boolean flushing = 0;
  1046.     register int x,y;
  1047.  
  1048.     if (flushing) return;    /* if already flushing then return */
  1049.     flushing = 1;
  1050.  
  1051.     for (y = 0; y < ROWNO; y++) {
  1052.     register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
  1053.     for (; x <= gbuf_stop[y]; gptr++, x++)
  1054.         if (gptr->new) {
  1055.         print_glyph(WIN_MAP,x,y,gptr->glyph);
  1056.         gptr->new = 0;
  1057.         }
  1058.     }
  1059.  
  1060.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
  1061.     display_nhwindow(WIN_MAP, FALSE);
  1062.     reset_glyph_bbox();
  1063.     flushing = 0;
  1064.     if(flags.botl || flags.botlx) bot();
  1065. }
  1066.  
  1067. /* ========================================================================= */
  1068.  
  1069. /*
  1070.  * back_to_glyph()
  1071.  *
  1072.  * Use the information in the rm structure at the given position to create
  1073.  * a glyph of a background.
  1074.  *
  1075.  * I had to add a field in the rm structure (horizontal) so that we knew
  1076.  * if open doors and secret doors were horizontal or vertical.  Previously,
  1077.  * the screen symbol had the horizontal/vertical information set at
  1078.  * level generation time.
  1079.  *
  1080.  * I used the 'ladder' field (really doormask) for deciding if stairwells
  1081.  * were up or down.  I didn't want to check the upstairs and dnstairs
  1082.  * variables.
  1083.  */
  1084. int
  1085. back_to_glyph(x,y)
  1086.     xchar x,y;
  1087. {
  1088.     int idx;
  1089.     struct rm *ptr = &(levl[x][y]);
  1090.  
  1091.     switch (ptr->typ) {
  1092.     case SCORR:
  1093.     case STONE:        idx = S_stone;      break;
  1094.     case ROOM:        idx = S_room;      break;
  1095.     case CORR:
  1096.         idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
  1097.         break;
  1098.     case HWALL:    idx = ptr->seen ? S_hwall  : S_stone;   break;
  1099.     case VWALL:    idx = ptr->seen ? S_vwall  : S_stone;   break;
  1100.     case TLCORNER:    idx = ptr->seen ? S_tlcorn : S_stone;    break;
  1101.     case TRCORNER:    idx = ptr->seen ? S_trcorn : S_stone;    break;
  1102.     case BLCORNER:    idx = ptr->seen ? S_blcorn : S_stone;    break;
  1103.     case BRCORNER:    idx = ptr->seen ? S_brcorn : S_stone;    break;
  1104.     case CROSSWALL:    idx = ptr->seen ? S_crwall : S_stone;    break;
  1105.     case TUWALL:    idx = ptr->seen ? S_tuwall : S_stone;    break;
  1106.     case TDWALL:    idx = ptr->seen ? S_tdwall : S_stone;    break;
  1107.     case TLWALL:    idx = ptr->seen ? S_tlwall : S_stone;    break;
  1108.     case TRWALL:    idx = ptr->seen ? S_trwall : S_stone;    break;
  1109.     case SDOOR:
  1110.         if (ptr->seen)
  1111.         idx = (ptr->horizontal) ? S_hwall : S_vwall;
  1112.         else
  1113.         idx = S_stone;
  1114.         break;
  1115.     case DOOR:
  1116.         if (ptr->doormask) {
  1117.         if (ptr->doormask & D_BROKEN)
  1118.             idx = S_ndoor;
  1119.         else if (ptr->doormask & D_ISOPEN)
  1120.             idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
  1121.         else            /* else is closed */
  1122.             idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
  1123.         } else
  1124.         idx = S_ndoor;
  1125.         break;
  1126.     case POOL:
  1127.     case MOAT:        idx = S_pool;      break;
  1128.     case STAIRS:
  1129.         idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
  1130.         break;
  1131.     case LADDER:
  1132.         idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
  1133.         break;
  1134.     case FOUNTAIN:        idx = S_fountain; break;
  1135.     case SINK:        idx = S_sink;     break;
  1136.     case ALTAR:        idx = S_altar;    break;
  1137.     case THRONE:        idx = S_throne;   break;
  1138.     case LAVAPOOL:        idx = S_lava;      break;
  1139.     case ICE:        idx = S_ice;      break;
  1140.     case AIR:        idx = S_air;      break;
  1141.     case CLOUD:        idx = S_cloud;      break;
  1142.     case WATER:        idx = S_water;      break;
  1143.     case DBWALL:
  1144.         idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
  1145.         break;
  1146.     case DRAWBRIDGE_UP:
  1147.         switch(ptr->drawbridgemask & DB_UNDER) {
  1148.         case DB_MOAT:  idx = S_pool; break;
  1149.         case DB_LAVA:  idx = S_lava; break;
  1150.         case DB_ICE:   idx = S_ice;  break;
  1151.         case DB_FLOOR: idx = S_room; break;
  1152.         default:
  1153.         impossible("Strange db-under: %d",
  1154.                ptr->drawbridgemask & DB_UNDER);
  1155.         idx = S_room; /* something is better than nothing */
  1156.         break;
  1157.         }
  1158.         break;
  1159.     case DRAWBRIDGE_DOWN:
  1160.         idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
  1161.         break;
  1162.     default:
  1163.         impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ);
  1164.         idx = S_room;
  1165.         break;
  1166.     }
  1167.  
  1168.     return cmap_to_glyph(idx);
  1169. }
  1170.  
  1171.  
  1172. /*
  1173.  * swallow_to_glyph()
  1174.  *
  1175.  * Convert a monster number and a swallow location into the correct glyph.
  1176.  * If you don't want a patchwork monster while hallucinating, decide on
  1177.  * a random monster in swallowed() and don't use what_mon() here.
  1178.  */
  1179. static int
  1180. swallow_to_glyph(mnum, loc)
  1181.     int mnum;
  1182.     int loc;
  1183. {
  1184.     if (loc < S_sw_tl || S_sw_br < loc) {
  1185.     impossible("swallow_to_glyph: bad swallow location");
  1186.     loc = S_sw_br;
  1187.     }
  1188.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
  1189. }
  1190.  
  1191.  
  1192.  
  1193. /*
  1194.  * zapdir_to_glyph()
  1195.  *
  1196.  * Change the given zap direction and beam type into a glyph.  Each beam
  1197.  * type has four glyphs, one for each of the symbols below.  The order of
  1198.  * the zap symbols [0-3] as defined in rm.h are:
  1199.  *
  1200.  *    |  S_vbeam    ( 0, 1) or ( 0,-1)
  1201.  *    -  S_hbeam    ( 1, 0) or (-1,    0)
  1202.  *    \  S_lslant    ( 1, 1) or (-1,-1)
  1203.  *    /  S_rslant    (-1, 1) or ( 1,-1)
  1204.  */
  1205. int
  1206. zapdir_to_glyph(dx, dy, beam_type)
  1207.     register int dx, dy;
  1208.     int beam_type;
  1209. {
  1210.     if (beam_type >= NUM_ZAP) {
  1211.     impossible("zapdir_to_glyph:  illegal beam type");
  1212.     beam_type = 0;
  1213.     }
  1214.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
  1215.  
  1216.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
  1217. }
  1218.  
  1219.  
  1220. /*
  1221.  * Utility routine for dowhatis() used to find out the glyph displayed at
  1222.  * the location.  This isn't necessarily the same as the glyph in the levl
  1223.  * structure, so we must check the "third screen".
  1224.  */
  1225. int
  1226. glyph_at(x, y)
  1227.     xchar x,y;
  1228. {
  1229.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
  1230.     return cmap_to_glyph(S_room);            /* XXX */
  1231.     return gbuf[y][x].glyph;
  1232. }
  1233.  
  1234. /*display.c*/
  1235.