home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / vision.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  70.7 KB  |  2,540 lines  |  [TEXT/R*ch]

  1. /*    SCCS Id: @(#)vision.c    3.1    93/03/28    */
  2. /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990.    */
  3. /* NetHack may be freely redistributed.  See license for details.    */
  4. #include "hack.h"
  5.  
  6. /* Circles ==================================================================*/
  7.  
  8. /*
  9.  * These numbers are limit offsets for one quadrant of a circle of a given
  10.  * radius (the first number of each line) from the source.  The number in
  11.  * the comment is the element number (so pointers can be set up).  Each
  12.  * "circle" has as many elements as its radius+1.  The radius is the number
  13.  * of points away from the source that the limit exists.  The radius of the
  14.  * offset on the same row as the source *is* included so we don't have to
  15.  * make an extra check.  For example, a circle of radius 4 has offsets:
  16.  *
  17.  *                XXX    +2
  18.  *                ...X    +3
  19.  *                ....X    +4
  20.  *                ....X    +4
  21.  *                @...X   +4
  22.  *  
  23.  */
  24. static char circle_data[] = {
  25. /*  0*/     1, 1,
  26. /*  2*/     2, 2, 1,
  27. /*  5*/     3, 3, 2, 1,
  28. /*  9*/     4, 4, 4, 3, 2,
  29. /* 14*/     5, 5, 5, 4, 3, 2,
  30. /* 20*/     6, 6, 6, 5, 5, 4, 2,
  31. /* 27*/     7, 7, 7, 6, 6, 5, 4, 2,
  32. /* 35*/     8, 8, 8, 7, 7, 6, 6, 4, 2,
  33. /* 44*/     9, 9, 9, 9, 8, 8, 7, 6, 5, 3,
  34. /* 54*/    10,10,10,10, 9, 9, 8, 7, 6, 5, 3,
  35. /* 65*/    11,11,11,11,10,10, 9, 9, 8, 7, 5, 3,
  36. /* 77*/    12,12,12,12,11,11,10,10, 9, 8, 7, 5, 3,
  37. /* 90*/    13,13,13,13,12,12,12,11,10,10, 9, 7, 6, 3,
  38. /*104*/    14,14,14,14,13,13,13,12,12,11,10, 9, 8, 6, 3,
  39. /*119*/    15,15,15,15,14,14,14,13,13,12,11,10, 9, 8, 6, 3,
  40. /*135*/ 16 /* should be MAX_RADIUS+1; used to terminate range loops -dlc */
  41. };
  42.  
  43. /*
  44.  * These are the starting indexes into the circle_data[] array for a
  45.  * circle of a given radius.
  46.  */
  47. static char circle_start[] = {
  48. /*  */      0,    /* circles of radius zero are not used */
  49. /* 1*/    0,
  50. /* 2*/      2,
  51. /* 3*/      5,
  52. /* 4*/      9,
  53. /* 5*/     14,
  54. /* 6*/     20,
  55. /* 7*/     27,
  56. /* 8*/     35,
  57. /* 9*/     44,
  58. /*10*/     54,
  59. /*11*/     65,
  60. /*12*/     77,
  61. /*13*/     90,
  62. /*14*/    104,
  63. /*15*/    119,
  64. };
  65.  
  66.  
  67. /*===========================================================================*/
  68. /* Vision (arbitrary line of sight) =========================================*/
  69.  
  70. /*------ global variables ------*/
  71.  
  72. #if 0    /* (moved to decl.c) */
  73. /* True if we need to run a full vision recalculation. */
  74. boolean    vision_full_recalc = 0;
  75.  
  76. /* Pointers to the current vision array. */
  77. char    **viz_array;
  78. #endif
  79. char    *viz_rmin, *viz_rmax;        /* current vision cs bounds */
  80.  
  81.  
  82. /*------ local variables ------*/
  83.  
  84.  
  85. static char could_see[2][ROWNO][COLNO];        /* vision work space */
  86. static char *cs_rows0[ROWNO], *cs_rows1[ROWNO];
  87. static char  cs_rmin0[ROWNO],  cs_rmax0[ROWNO];
  88. static char  cs_rmin1[ROWNO],  cs_rmax1[ROWNO];
  89.  
  90. static char  viz_clear[ROWNO][COLNO];        /* vision clear/blocked map */
  91. static char *viz_clear_rows[ROWNO];
  92.  
  93. static char  left_ptrs[ROWNO][COLNO];        /* LOS algorithm helpers */
  94. static char right_ptrs[ROWNO][COLNO];
  95.  
  96. /* Forward declarations. */
  97. static void FDECL(fill_point, (int,int));
  98. static void FDECL(dig_point, (int,int));
  99. static void NDECL(view_init);
  100. static void FDECL(view_from,(int,int,char **,char *,char *,int,
  101.                  void (*)(int,int,genericptr_t),genericptr_t));
  102. static void FDECL(get_unused_cs, (char ***,char **,char **));
  103. #ifdef REINCARNATION
  104. static void FDECL(rogue_vision, (char **,char *,char *));
  105. #endif
  106.  
  107. /* Macro definitions that I can't find anywhere. */
  108. #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0 ))
  109. #define abs(z)  ((z) < 0 ? -(z) : (z))
  110.  
  111. /*
  112.  * vision_init()
  113.  *
  114.  * The one-time vision initialization routine.
  115.  *
  116.  * This must be called before mklev() is called in newgame() [allmain.c],
  117.  * or before a game restore.   Else we die a horrible death.
  118.  */
  119. void
  120. vision_init()
  121. {
  122.     int i;
  123.  
  124.     /* Set up the pointers. */
  125.     for (i = 0; i < ROWNO; i++) {
  126.     cs_rows0[i] = could_see[0][i];
  127.     cs_rows1[i] = could_see[1][i];
  128.     viz_clear_rows[i] = viz_clear[i];
  129.     }
  130.  
  131.     /* Start out with cs0 as our current array */
  132.     viz_array = cs_rows0;
  133.     viz_rmin  = cs_rmin0;
  134.     viz_rmax  = cs_rmax0;
  135.  
  136.     vision_full_recalc = 0;
  137.     (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
  138.  
  139.     /* Initialize the vision algorithm (currently C or D). */
  140.     view_init();
  141.  
  142. #ifdef VISION_TABLES
  143.     /* Note:  this initializer doesn't do anything except guarantee that
  144.           we're linked properly.
  145.     */
  146.     vis_tab_init();
  147. #endif
  148. }
  149.  
  150. /*
  151.  * does_block()
  152.  *
  153.  * Returns true if the level feature, object, or monster at (x,y) blocks
  154.  * sight.
  155.  */
  156. int
  157. does_block(x,y,lev)
  158.     int x, y;
  159.     register struct rm    *lev;
  160. {
  161.     struct obj   *obj;
  162.     struct monst *mon;
  163.  
  164.     /* Features that block . . */
  165.     if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
  166.                 (lev->doormask & (D_CLOSED|D_LOCKED|D_TRAPPED) )))
  167.     return 1;
  168.  
  169.     if (lev->typ == CLOUD || lev->typ == WATER ||
  170.             (lev->typ == MOAT && Underwater))
  171.     return 1;
  172.  
  173.     /* Boulders block light. */
  174.     for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
  175.     if (obj->otyp == BOULDER) return 1;
  176.  
  177.     /* Mimics mimicing a door or boulder block light. */
  178.     if ((mon = m_at(x,y)) && (!mon->minvis || See_invisible) &&
  179.       ((mon->m_ap_type == M_AP_FURNITURE &&
  180.       (mon->mappearance == S_hcdoor || mon->mappearance == S_vcdoor)) ||
  181.       (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER)))
  182.     return 1;
  183.  
  184.     return 0;
  185. }
  186.  
  187. /*
  188.  * vision_reset()
  189.  *
  190.  * This must be called *after* the levl[][] structure is set with the new
  191.  * level and the level monsters and objects are in place.
  192.  */
  193. void
  194. vision_reset()
  195. {
  196.     int y;
  197.     register int x, i, dig_left, block;
  198.     register struct rm    *lev;
  199.  
  200.     /* Start out with cs0 as our current array */
  201.     viz_array = cs_rows0;
  202.     viz_rmin  = cs_rmin0;
  203.     viz_rmax  = cs_rmax0;
  204.  
  205.     (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
  206.  
  207.     /* Reset the pointers and clear so that we have a "full" dungeon. */
  208.     (void) memset((genericptr_t) viz_clear,        0, sizeof(viz_clear));
  209.  
  210.     /* Dig the level */
  211.     for (y = 0; y < ROWNO; y++) {
  212.     dig_left = 0;
  213.     block = TRUE;    /* location (0,y) is always stone; it's !isok() */
  214.     lev = &levl[1][y];
  215.     for (x = 1; x < COLNO; x++, lev += ROWNO)
  216.         if (block != (IS_ROCK(lev->typ) || does_block(x,y,lev))) {
  217.         if(block) {
  218.             for(i=dig_left; i<x; i++) {
  219.             left_ptrs [y][i] = dig_left;
  220.             right_ptrs[y][i] = x-1;
  221.             }
  222.         } else {
  223.             i = dig_left;
  224.             if(dig_left) dig_left--; /* point at first blocked point */
  225.             for(; i<x; i++) {
  226.             left_ptrs [y][i] = dig_left;
  227.             right_ptrs[y][i] = x;
  228.             viz_clear[y][i] = 1;
  229.             }
  230.         }
  231.         dig_left = x;
  232.         block = !block;
  233.         }
  234.     /* handle right boundary; almost identical for blocked/unblocked */
  235.     i = dig_left;
  236.     if(!block && dig_left) dig_left--; /* point at first blocked point */
  237.     for(; i<COLNO; i++) {
  238.         left_ptrs [y][i] = dig_left;
  239.         right_ptrs[y][i] = (COLNO-1);
  240.         viz_clear[y][i] = !block;
  241.     }
  242.     }
  243.  
  244.     vision_full_recalc = 1;    /* we want to run vision_recalc() */
  245. }
  246.  
  247.  
  248. /*
  249.  * get_unused_cs()
  250.  *
  251.  * Called from vision_recalc() and at least one light routine.  Get pointers
  252.  * to the unused vision work area.
  253.  */
  254. static void
  255. get_unused_cs(rows, rmin, rmax)
  256.     char ***rows;
  257.     char **rmin, **rmax;
  258. {
  259.     register int  row;
  260.     register char *nrmin, *nrmax;
  261.  
  262.     if (viz_array == cs_rows0) {
  263.     *rows = cs_rows1;
  264.     *rmin = cs_rmin1;
  265.     *rmax = cs_rmax1;
  266.     } else {
  267.     *rows = cs_rows0;
  268.     *rmin = cs_rmin0;
  269.     *rmax = cs_rmax0;
  270.     }
  271.  
  272.     /* return an initialized, unused work area */
  273.     nrmin = *rmin;
  274.     nrmax = *rmax;
  275.  
  276.     (void) memset((genericptr_t)**rows, 0, ROWNO*COLNO);  /* we see nothing */
  277.     for (row = 0; row < ROWNO; row++) {        /* set row min & max */
  278.     *nrmin++ = COLNO-1;
  279.     *nrmax++ = 0;
  280.     }
  281. }
  282.  
  283.  
  284. #ifdef REINCARNATION
  285. /*
  286.  * rogue_vision()
  287.  *
  288.  * Set the "could see" and in sight bits so vision acts just like the old
  289.  * rogue game:
  290.  *
  291.  *    + If in a room, the hero can see to the room boundaries.
  292.  *    + The hero can always see adjacent squares.
  293.  *
  294.  * We set the in_sight bit here as well to escape a bug that shows up
  295.  * due to the one-sided lit wall hack.
  296.  */
  297. static void
  298. rogue_vision(next, rmin, rmax)
  299.     char **next;    /* could_see array pointers */
  300.     char *rmin, *rmax;
  301. {
  302.     int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */
  303.     int start, stop, in_door, xhi, xlo, yhi, ylo;
  304.     register int zx, zy;
  305.  
  306.     /* If in a lit room, we are able to see to its boundaries. */
  307.     /* If dark, set COULD_SEE so various spells work -dlc */
  308.     if (rnum >= 0) {
  309.     for (zy = rooms[rnum].ly-1; zy <= rooms[rnum].hy+1; zy++) {
  310.         rmin[zy] = start = rooms[rnum].lx-1;
  311.         rmax[zy] = stop  = rooms[rnum].hx+1;
  312.  
  313.         for (zx = start; zx <= stop; zx++) {
  314.         if (rooms[rnum].rlit) {
  315.             next[zy][zx] = COULD_SEE | IN_SIGHT;
  316.             levl[zx][zy].seen = 1;    /* see the walls */
  317.         } else
  318.             next[zy][zx] = COULD_SEE;
  319.         }
  320.     }
  321.     }
  322.  
  323.     in_door = levl[u.ux][u.uy].typ == DOOR;
  324.  
  325.     /* Can always see adjacent. */
  326.     ylo = max(u.uy - 1, 0);
  327.     yhi = min(u.uy + 1, ROWNO - 1);
  328.     xlo = max(u.ux - 1, 1);
  329.     xhi = min(u.ux + 1, COLNO - 1);
  330.     for (zy = ylo; zy <= yhi; zy++) {
  331.     if (xlo < rmin[zy]) rmin[zy] = xlo;
  332.     if (xhi > rmax[zy]) rmax[zy] = xhi;
  333.  
  334.     for (zx = xlo; zx <= xhi; zx++) {
  335.         next[zy][zx] = COULD_SEE | IN_SIGHT;
  336.         /*
  337.          * Yuck, update adjacent non-diagonal positions when in a doorway.
  338.          * We need to do this to catch the case when we first step into
  339.          * a room.  The room's walls were not seen from the outside, but
  340.          * now are seen (the seen bit is set just above).  However, the
  341.          * positions are not updated because they were already in sight.
  342.          * So, we have to do it here.
  343.          */
  344.         if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx,zy);
  345.     }
  346.     }
  347. }
  348. #endif /* REINCARNATION */
  349.  
  350.  
  351. /*
  352.  * vision_recalc()
  353.  *
  354.  * Do all of the heavy vision work.  Recalculate all locations that could
  355.  * possibly be seen by the hero --- if the location were lit, etc.  Note
  356.  * which locations are actually seen because of lighting.  Then add to
  357.  * this all locations that be seen by hero due to night vision and x-ray
  358.  * vision.  Finally, compare with what the hero was able to see previously.
  359.  * Update the difference.
  360.  *
  361.  * This function is usually called only when the variable 'vision_full_recalc'
  362.  * is set.  The following is a list of places where this function is called,
  363.  * with three valid values for the control flag parameter:
  364.  *
  365.  * Control flag = 0.  A complete vision recalculation.  Generate the vision
  366.  * tables from scratch.  This is necessary to correctly set what the hero
  367.  * can see.  (1) and (2) call this routine for synchronization purposes, (3)
  368.  * calls this routine so it can operate correctly.
  369.  *
  370.  *    + After the monster move, before input from the player. [moveloop()]
  371.  *    + At end of moveloop. [moveloop() ??? not sure why this is here]
  372.  *    + Right before something is printed. [pline()]
  373.  *    + Right before we do a vision based operation. [do_clear_area()]
  374.  *    + screen redraw, so we can renew all positions in sight. [docrt()]
  375.  *
  376.  * Control flag = 1.  An adjacent vision recalculation.  The hero has moved
  377.  * one square.  Knowing this, it might be possible to optimize the vision
  378.  * recalculation using the current knowledge.  This is presently unimplemented
  379.  * and is treated as a control = 0 call.
  380.  *
  381.  *    + Right after the hero moves. [domove()]
  382.  *
  383.  * Control flag = 2.  Turn off the vision system.  Nothing new will be
  384.  * displayed, since nothing is seen.  This is usually done when you need
  385.  * a newsym() run on all locations in sight, or on some locations but you
  386.  * don't know which ones.
  387.  *
  388.  *    + Before a screen redraw, so all positions are renewed. [docrt()]
  389.  *    + Right before the hero arrives on a new level. [goto_level()]
  390.  *    + Right after a scroll of light is read. [litroom()]
  391.  *    + After an option has changed that affects vision [parseoptions()]
  392.  *    + Right after the hero is swallowed. [gulpmu()]
  393.  *    + Just before bubbles are moved. [movebubbles()]
  394.  */
  395. void
  396. vision_recalc(control)
  397.     int control;
  398. {
  399.     char **temp_array;    /* points to the old vision array */
  400.     char **next_array;    /* points to the new vision array */
  401.     char *next_row;    /* row pointer for the new array */
  402.     char *old_row;    /* row pointer for the old array */
  403.     char *next_rmin;    /* min pointer for the new array */
  404.     char *next_rmax;    /* max pointer for the new array */
  405.     char *ranges;    /* circle ranges -- used for xray & night vision */
  406.     int row;        /* row counter (outer loop)  */
  407.     int start, stop;    /* inner loop starting/stopping index */
  408.     int dx, dy;        /* one step from a lit door or lit wall (see below) */
  409.     register int col;    /* inner loop counter */
  410.     register struct rm *lev;    /* pointer to current pos */
  411.     struct rm *flev;    /* pointer to position in "front" of current pos */
  412.  
  413.     vision_full_recalc = 0;            /* reset flag */
  414.  
  415. #ifdef GCC_WARN
  416.     row = 0;
  417. #endif
  418.  
  419.     /*
  420.      * Either the light sources have been taken care of, or we must
  421.      * recalculate them here.
  422.      */
  423.  
  424.     /* Get the unused could see, row min, and row max arrays. */
  425.     get_unused_cs(&next_array, &next_rmin, &next_rmax);
  426.  
  427.     /* You see nothing, nothing can see you --- if swallowed or refreshing. */
  428.     if (u.uswallow || control == 2) {
  429.     /* do nothing -- get_unused_cs() nulls out the new work area */
  430.  
  431.     } else if (Blind) {
  432.     /*
  433.      * Calculate the could_see array even when blind so that monsters
  434.      * can see you, even if you can't see them.  Note that the current
  435.      * setup allows:
  436.      *
  437.      *    + Monsters to see with the "new" vision, even on the rogue
  438.      *      level.
  439.      *
  440.      *    + Monsters to see you even when you're in a pit.
  441.      */
  442.     view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
  443.                     0,(void(*)())0,(genericptr_t)0);
  444.  
  445.     /*
  446.      * Our own version of the update loop below.  We know we can't see
  447.      * anything, so we only need update positions we used to be able
  448.      * to see.
  449.      */
  450.     temp_array = viz_array;    /* set viz_array so newsym() will work */
  451.     viz_array = next_array;
  452.  
  453.     for (row = 0; row < ROWNO; row++) {
  454.         old_row = temp_array[row];
  455.  
  456.         /* Find the min and max positions on the row. */
  457.         start = min(viz_rmin[row], next_rmin[row]);
  458.         stop  = max(viz_rmax[row], next_rmax[row]);
  459.  
  460.         for (col = start; col <= stop; col++)
  461.         if (old_row[col] & IN_SIGHT) newsym(col,row);
  462.     }
  463.  
  464.     /* skip the normal update loop */
  465.     goto skip;
  466.     }
  467. #ifdef REINCARNATION
  468.     else if (Is_rogue_level(&u.uz)) {
  469.     rogue_vision(next_array,next_rmin,next_rmax);
  470.     }
  471. #endif
  472.     else {
  473.     int has_night_vision = 1;    /* hero has night vision */
  474.  
  475.     if (Underwater && !Is_waterlevel(&u.uz)) {
  476.         /*
  477.          * The hero is under water.  Only see surrounding locations if
  478.          * they are also underwater.  This overrides night vision but
  479.          * does not override x-ray vision.
  480.          */
  481.         has_night_vision = 0;
  482.  
  483.         for (row = u.uy-1; row <= u.uy+1; row++)
  484.         for (col = u.ux-1; col <= u.ux+1; col++) {
  485.             if (!isok(col,row) || !is_pool(col,row)) continue;
  486.  
  487.             next_rmin[row] = min(next_rmin[row], col);
  488.             next_rmax[row] = max(next_rmax[row], col);
  489.             next_array[row][col] = IN_SIGHT;
  490.         }
  491.     }
  492.  
  493.     /* if in a pit, just update for immediate locations */
  494.     else if (u.utrap && u.utraptype == TT_PIT) {
  495.         for (row = u.uy-1; row <= u.uy+1; row++) {
  496.         if (row < 0) continue;    if (row >= ROWNO) break;
  497.  
  498.         next_rmin[row] = max(      0, u.ux - 1);
  499.         next_rmax[row] = min(COLNO-1, u.ux + 1);
  500.         next_row = next_array[row];
  501.  
  502.         for(col=next_rmin[row]; col <= next_rmax[row]; col++)
  503.             next_row[col] = IN_SIGHT;
  504.         }
  505.     } else
  506.         view_from(u.uy, u.ux, next_array, next_rmin, next_rmax,
  507.                     0,(void(*)())0,(genericptr_t)0);
  508.  
  509.     /*
  510.      * Set the IN_SIGHT bit for xray and night vision.
  511.      */
  512.     if (u.xray_range >= 0) {
  513.         if (u.xray_range) {
  514.         ranges = circle_ptr(u.xray_range);
  515.  
  516.         for (row = u.uy-u.xray_range; row <= u.uy+u.xray_range; row++) {
  517.             if (row < 0) continue;    if (row >= ROWNO) break;
  518.             dy = abs(u.uy-row);        next_row = next_array[row];
  519.  
  520.             start = max(      0, u.ux - ranges[dy]);
  521.             stop  = min(COLNO-1, u.ux + ranges[dy]);
  522.  
  523.             for (col = start; col <= stop; col++) {
  524.             next_row[col] |= IN_SIGHT;
  525.             levl[col][row].seen = 1;    /* we see walls */
  526.             }
  527.  
  528.             next_rmin[row] = min(start, next_rmin[row]);
  529.             next_rmax[row] = max(stop, next_rmax[row]);
  530.         }
  531.  
  532.         } else {    /* range is 0 */
  533.         next_array[u.uy][u.ux] |= IN_SIGHT;
  534.         levl[u.ux][u.uy].seen = 1;
  535.         next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
  536.         next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
  537.         }
  538.     }
  539.  
  540.     if (has_night_vision && u.xray_range < u.nv_range) {
  541.         if (!u.nv_range) {    /* range is 0 */
  542.         next_array[u.uy][u.ux] |= IN_SIGHT;
  543.         levl[u.ux][u.uy].seen = 1;
  544.         next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
  545.         next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
  546.         } else if (u.nv_range > 0) {
  547.         ranges = circle_ptr(u.nv_range);
  548.  
  549.         for (row = u.uy-u.nv_range; row <= u.uy+u.nv_range; row++) {
  550.             if (row < 0) continue;    if (row >= ROWNO) break;
  551.             dy = abs(u.uy-row);        next_row = next_array[row];
  552.  
  553.             start = max(      0, u.ux - ranges[dy]);
  554.             stop  = min(COLNO-1, u.ux + ranges[dy]);
  555.  
  556.             for (col = start; col <= stop; col++)
  557.             if (next_row[col]) next_row[col] |= IN_SIGHT;
  558.  
  559.             next_rmin[row] = min(start, next_rmin[row]);
  560.             next_rmax[row] = max(stop, next_rmax[row]);
  561.         }
  562.         }
  563.     }
  564.     }
  565.  
  566.  
  567.     /*
  568.      * Make the viz_array the new array so that cansee() will work correctly.
  569.      */
  570.     temp_array = viz_array;
  571.     viz_array = next_array;
  572.  
  573.     /*
  574.      * The main update loop.  Here we do two things:
  575.      *
  576.      *        + Set the IN_SIGHT bit for places that we could see and are lit.
  577.      *        + Reset changed places.
  578.      *
  579.      * There are two things that make deciding what the hero can see
  580.      * difficult:
  581.      *
  582.      *  1.  Walls.  Walls are only seen as walls from the inside of a room.
  583.      *        On the outside they look like stone.  The "seen" bit in the rm
  584.      *        structure is used in the display system to decide what to
  585.      *        display, but it is here where we decide to set the seen bit.
  586.      *        In this case the wall must already be in sight (either by night
  587.      *        vision or could be seen and lit) *and* we must see the wall
  588.      *        from across a room-typ square.
  589.      *
  590.      *  2.  Directional lighting.  Items that block light create problems.
  591.      *      The worst offenders are doors.  Suppose a door to a lit room
  592.      *      is closed.  It is lit on one side, but not on the other.  How
  593.      *      do you know?  You have to check the closest adjacent position.
  594.      *        Even so, that is not entirely correct.  But it seems close
  595.      *        enough for now.
  596.      */
  597.     for (row = 0; row < ROWNO; row++) {
  598.     dy = u.uy - row;                dy = sign(dy);
  599.     next_row = next_array[row];     old_row = temp_array[row];
  600.  
  601.     /* Find the min and max positions on the row. */
  602.     start = min(viz_rmin[row], next_rmin[row]);
  603.     stop  = max(viz_rmax[row], next_rmax[row]);
  604.     lev = &levl[start][row];
  605.  
  606.     for (col = start; col <= stop; col++, lev += ROWNO) {
  607.         if (next_row[col] & IN_SIGHT) {
  608.         /*
  609.          * We see this position because of night- or xray-vision.
  610.          *
  611.          * Check for "unseen" walls.
  612.          */
  613.         if ( (!lev->seen || (lev->diggable & W_REPAIRED)) && 
  614.              (IS_WALL(lev->typ) || lev->typ == SDOOR) ) {
  615.             /* Check the closest adjacent position. */
  616.             dx = u.ux - col;    dx = sign(dx);
  617.             flev = &(levl[col+dx][row+dy]);
  618.  
  619.             /* If it was a non-corridor "open" area, we see the wall */
  620.             if ((ZAP_POS(flev->typ) && (flev->typ != CORR)) ||
  621.             (lev->diggable & W_REPAIRED)) {
  622.             lev->seen = 1;    /* we've seen it */
  623.             lev->diggable &= ~W_REPAIRED;
  624.  
  625.             /* Make sure newly "seen" walls show up */
  626.             newsym(col,row);
  627.             }
  628.  
  629.             /* Update position if it was not in sight before. */
  630.             else if (!(old_row[col]&IN_SIGHT)) newsym(col,row);
  631.         }
  632.  
  633.         /* Update position if it was not in sight before. */
  634.         else if ( !(old_row[col] & IN_SIGHT) ) {
  635.             lev->seen = 1;
  636.             newsym(col,row);
  637.         }
  638.         }
  639.  
  640.         else if ( next_row[col] && lev->lit ) {
  641.         /*
  642.          * We see this position because it is lit.
  643.          *
  644.          * It is assumed here that lit walls are lit from the
  645.          * inside of the room,  Hence, walls are not "seen"
  646.          * unless we can see them from across a lit room square.
  647.          */
  648.         if (IS_WALL(lev->typ) || lev->typ == SDOOR) {
  649.  
  650.             /* Check the closest adjacent position. */
  651.             dx = u.ux - col;    dx = sign(dx);
  652.             flev = &(levl[col+dx][row+dy]);
  653.             /*
  654.              * If it is a non-corridor "open" area, and it is lit,
  655.              * then we see the wall as a wall.
  656.              *
  657.              * What happens when the hero is standing on this
  658.              * location (dx == dy == 0)?
  659.              */
  660.             if (ZAP_POS(flev->typ) && (flev->typ != CORR) &&
  661.                                 flev->lit) {
  662.             next_row[col] |= IN_SIGHT;    /* we see it */
  663.             if (!lev->seen || (lev->diggable & W_REPAIRED)) {
  664.                 lev->seen = 1;        /* see it as a wall */
  665.                 lev->diggable &= ~W_REPAIRED;
  666.                 /*
  667.                  * Force an update on the position, even if it
  668.                  * was previously in sight.  Reason:  the hero
  669.                  * could have been in a corridor or outside of
  670.                  * an undiscovered wall and then teleported into
  671.                  * the room.  The wall was in sight before, but
  672.                  * seen as stone.  Now we need to see it as a
  673.                  * wall.
  674.                  */
  675.                 newsym(col,row);
  676.             }
  677.             } else
  678.             goto not_in_sight;    /* we don't see it */
  679.  
  680.         } else if (IS_DOOR(lev->typ) && !viz_clear[row][col]) {
  681.             /*
  682.              * Make sure doors, boulders or mimics don't show up
  683.              * at the end of dark hallways.  We do this by checking
  684.              * the adjacent position.  If it is lit, then we can see
  685.              * the door, otherwise we can't.
  686.              */
  687.             dx = u.ux - col;    dx = sign(dx);
  688.             flev = &(levl[col+dx][row+dy]);
  689.             if (flev->lit) {
  690.             next_row[col] |= IN_SIGHT;    /* we see it */
  691.  
  692.             /* Update position if it was not in sight before. */
  693.             if (!(old_row[col] & IN_SIGHT)) newsym(col,row);
  694.             } else
  695.             goto not_in_sight;    /* we don't see it */
  696.  
  697.         } else {
  698.             next_row[col] |= IN_SIGHT;    /* we see it */
  699.  
  700.             /* Update position if it was not in sight before. */
  701.             if ( !(old_row[col] & IN_SIGHT) ) {
  702.             lev->seen = 1;
  703.             newsym(col,row);
  704.             }
  705.         }
  706.         } else if (next_row[col] && lev->waslit ) {
  707.         /*
  708.          * If we make it here, the hero _could see_ the location
  709.          * (next_row[col] is true), but doesn't see it (lit is false).
  710.          * However, the hero _remembers_ it as lit (waslit is true).
  711.          * The hero can now see that it is not lit, so change waslit
  712.          * and update the location.
  713.          */
  714.         lev->waslit = 0; /* remember lit condition */
  715.         newsym(col,row);
  716.         }
  717.         /*
  718.          * At this point we know that the row position is *not* in
  719.          * sight.  If the old one *was* in sight, then clean up the
  720.          * position.
  721.          */
  722.         else {
  723. not_in_sight:
  724.         if (old_row[col] & IN_SIGHT) newsym(col,row);
  725.         }
  726.  
  727.     } /* end for col . . */
  728.     }    /* end for row . .  */
  729.  
  730. skip:
  731.     newsym(u.ux,u.uy);        /* Make sure the hero shows up! */
  732.  
  733.     /* Set the new min and max pointers. */
  734.     viz_rmin  = next_rmin;
  735.     viz_rmax = next_rmax;
  736. }
  737.  
  738.  
  739. /*
  740.  * block_point()
  741.  *
  742.  * Make the location opaque to light.
  743.  */
  744. void
  745. block_point(x,y)
  746.     int x, y;
  747. {
  748.     fill_point(y,x);
  749.  
  750.     /* recalc light sources here? */
  751.  
  752.     /*
  753.      * We have to do a full vision recalculation if we "could see" the
  754.      * location.  Why? Suppose some monster opened a way so that the
  755.      * hero could see a lit room.  However, the position of the opening
  756.      * was out of night-vision range of the hero.  Suddenly the hero should
  757.      * see the lit room.
  758.      */
  759.     if (viz_array[y][x]) vision_full_recalc = 1;
  760. }
  761.  
  762. /*
  763.  * unblock_point()
  764.  *
  765.  * Make the location transparent to light.
  766.  */
  767. void
  768. unblock_point(x,y)
  769.     int x, y;
  770. {
  771.     dig_point(y,x);
  772.  
  773.     /* recalc light sources here? */
  774.  
  775.     if (viz_array[y][x]) vision_full_recalc = 1;
  776. }
  777.  
  778.  
  779. /*===========================================================================*\
  780.  |                                         |
  781.  |    Everything below this line uses (y,x) instead of (x,y) --- the         |
  782.  |    algorithms are faster if they are less recursive and can scan         |
  783.  |    on a row longer.                             |
  784.  |                                         |
  785. \*===========================================================================*/
  786.  
  787.  
  788. /* ========================================================================= *\
  789.             Left and Right Pointer Updates
  790. \* ========================================================================= */
  791.  
  792. /*
  793.  *            LEFT and RIGHT pointer rules
  794.  *
  795.  *
  796.  * **NOTE**  The rules changed on 4/4/90.  This comment reflects the
  797.  * new rules.  The change was so that the stone-wall optimization
  798.  * would work.
  799.  *
  800.  * OK, now the tough stuff.  We must maintain our left and right
  801.  * row pointers.  The rules are as follows:
  802.  *  
  803.  * Left Pointers:
  804.  * ______________
  805.  *
  806.  * + If you are a clear spot, your left will point to the first
  807.  *   stone to your left.  If there is none, then point the first
  808.  *   legal position in the row (0).
  809.  *
  810.  * + If you are a blocked spot, then your left will point to the
  811.  *   left-most blocked spot to your left that is connected to you.
  812.  *   This means that a left-edge (a blocked spot that has an open
  813.  *   spot on its left) will point to itself.
  814.  *
  815.  *
  816.  * Right Pointers:
  817.  * ---------------
  818.  * + If you are a clear spot, your right will point to the first
  819.  *   stone to your right.  If there is none, then point the last
  820.  *   legal position in the row (COLNO-1).
  821.  *
  822.  * + If you are a blocked spot, then your right will point to the
  823.  *   right-most blocked spot to your right that is connected to you.
  824.  *   This means that a right-edge (a blocked spot that has an open
  825.  *    spot on its right) will point to itself.
  826.  */
  827. static void
  828. dig_point(row,col)
  829.     int row,col;
  830. {
  831.     int i;
  832.  
  833.     if (viz_clear[row][col]) return;        /* already done */
  834.  
  835.     viz_clear[row][col] = 1;
  836.  
  837.     /*
  838.      * Boundary cases first.
  839.      */
  840.     if (col == 0) {                /* left edge */
  841.     if (viz_clear[row][1]) {
  842.         right_ptrs[row][0] = right_ptrs[row][1];
  843.     } else {
  844.         right_ptrs[row][0] = 1;
  845.         for (i = 1; i <= right_ptrs[row][1]; i++)
  846.         left_ptrs[row][i] = 1;
  847.     }
  848.     } else if (col == (COLNO-1)) {        /* right edge */
  849.  
  850.     if (viz_clear[row][COLNO-2]) {
  851.         left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
  852.     } else {
  853.         left_ptrs[row][COLNO-1] = COLNO-2;
  854.         for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
  855.         right_ptrs[row][i] = COLNO-2;
  856.     }
  857.     }
  858.      
  859.     /*
  860.      * At this point, we know we aren't on the boundaries.
  861.      */
  862.     else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
  863.     /* Both sides clear */
  864.     for (i = left_ptrs[row][col-1]; i <= col; i++) {
  865.         if (!viz_clear[row][i]) continue;    /* catch non-end case */
  866.         right_ptrs[row][i] = right_ptrs[row][col+1];
  867.     }
  868.     for (i = col; i <= right_ptrs[row][col+1]; i++) {
  869.         if (!viz_clear[row][i]) continue;    /* catch non-end case */
  870.         left_ptrs[row][i] = left_ptrs[row][col-1];
  871.     }
  872.  
  873.     } else if (viz_clear[row][col-1]) {
  874.     /* Left side clear, right side blocked. */
  875.     for (i = col+1; i <= right_ptrs[row][col+1]; i++)
  876.         left_ptrs[row][i] = col+1;
  877.  
  878.     for (i = left_ptrs[row][col-1]; i <= col; i++) {
  879.         if (!viz_clear[row][i]) continue;    /* catch non-end case */
  880.         right_ptrs[row][i] = col+1;
  881.     }
  882.     left_ptrs[row][col] = left_ptrs[row][col-1];
  883.  
  884.     } else if (viz_clear[row][col+1]) {
  885.     /* Right side clear, left side blocked. */
  886.     for (i = left_ptrs[row][col-1]; i < col; i++)
  887.         right_ptrs[row][i] = col-1;
  888.  
  889.     for (i = col; i <= right_ptrs[row][col+1]; i++) {
  890.         if (!viz_clear[row][i]) continue;    /* catch non-end case */
  891.         left_ptrs[row][i] = col-1;
  892.     }
  893.     right_ptrs[row][col] = right_ptrs[row][col+1];
  894.  
  895.     } else {
  896.     /* Both sides blocked */
  897.     for (i = left_ptrs[row][col-1]; i < col; i++)
  898.         right_ptrs[row][i] = col-1;
  899.  
  900.     for (i = col+1; i <= right_ptrs[row][col+1]; i++)
  901.         left_ptrs[row][i] = col+1;
  902.  
  903.     left_ptrs[row][col]  = col-1;
  904.     right_ptrs[row][col] = col+1;
  905.     }
  906. }
  907.  
  908. static void
  909. fill_point(row,col)
  910.     int row, col;
  911. {
  912.     int i;
  913.  
  914.     if (!viz_clear[row][col]) return;
  915.  
  916.     viz_clear[row][col] = 0;
  917.  
  918.     if (col == 0) {
  919.     if (viz_clear[row][1]) {            /* adjacent is clear */
  920.         right_ptrs[row][0] = 0;
  921.     } else {
  922.         right_ptrs[row][0] = right_ptrs[row][1];
  923.         for (i = 1; i <= right_ptrs[row][1]; i++)
  924.         left_ptrs[row][i] = 0;
  925.     }
  926.     } else if (col == COLNO-1) {
  927.     if (viz_clear[row][COLNO-2]) {        /* adjacent is clear */
  928.         left_ptrs[row][COLNO-1] = COLNO-1;
  929.     } else {
  930.         left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2];
  931.         for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++)
  932.         right_ptrs[row][i] = COLNO-1;
  933.     }
  934.     }
  935.  
  936.     /*
  937.      * Else we know that we are not on an edge.
  938.      */
  939.     else if (viz_clear[row][col-1] && viz_clear[row][col+1]) {
  940.     /* Both sides clear */
  941.     for (i = left_ptrs[row][col-1]+1; i <= col; i++)
  942.         right_ptrs[row][i] = col;
  943.  
  944.     if (!left_ptrs[row][col-1])        /* catch the end case */
  945.         right_ptrs[row][0] = col;
  946.  
  947.     for (i = col; i < right_ptrs[row][col+1]; i++)
  948.         left_ptrs[row][i] = col;
  949.  
  950.     if (right_ptrs[row][col+1] == COLNO-1)    /* catch the end case */
  951.         left_ptrs[row][COLNO-1] = col;
  952.  
  953.     } else if (viz_clear[row][col-1]) {
  954.     /* Left side clear, right side blocked. */
  955.     for (i = col; i <= right_ptrs[row][col+1]; i++)
  956.         left_ptrs[row][i] = col;
  957.  
  958.     for (i = left_ptrs[row][col-1]+1; i < col; i++)
  959.         right_ptrs[row][i] = col;
  960.  
  961.     if (!left_ptrs[row][col-1])        /* catch the end case */
  962.         right_ptrs[row][i] = col;
  963.  
  964.     right_ptrs[row][col] = right_ptrs[row][col+1];
  965.  
  966.     } else if (viz_clear[row][col+1]) {
  967.     /* Right side clear, left side blocked. */
  968.     for (i = left_ptrs[row][col-1]; i <= col; i++)
  969.         right_ptrs[row][i] = col;
  970.  
  971.     for (i = col+1; i < right_ptrs[row][col+1]; i++)
  972.         left_ptrs[row][i] = col;
  973.  
  974.     if (right_ptrs[row][col+1] == COLNO-1)    /* catch the end case */
  975.         left_ptrs[row][i] = col;
  976.  
  977.     left_ptrs[row][col] = left_ptrs[row][col-1];
  978.  
  979.     } else {
  980.     /* Both sides blocked */
  981.     for (i = left_ptrs[row][col-1]; i <= col; i++)
  982.         right_ptrs[row][i] = right_ptrs[row][col+1];
  983.  
  984.     for (i = col; i <= right_ptrs[row][col+1]; i++)
  985.         left_ptrs[row][i] = left_ptrs[row][col-1];
  986.     }
  987. }
  988.  
  989.  
  990. /*===========================================================================*/
  991. /*===========================================================================*/
  992. /* Use either algorithm C or D.  See the config.h for more details. =========*/
  993.  
  994. /*
  995.  * Variables local to both Algorithms C and D.
  996.  */
  997. static int  start_row;
  998. static int  start_col;
  999. static int  step;
  1000. static char **cs_rows;
  1001. static char *cs_left;
  1002. static char *cs_right;
  1003.  
  1004. static void FDECL((*vis_func), (int,int,genericptr_t));
  1005. static genericptr_t varg;
  1006.  
  1007. /*
  1008.  * Both Algorithms C and D use the following macros.
  1009.  *
  1010.  *      good_row(z)      - Return TRUE if the argument is a legal row.
  1011.  *      set_cs(rowp,col)  - Set the local could see array.
  1012.  *      set_min(z)      - Save the min value of the argument and the current
  1013.  *                    row minimum.
  1014.  *      set_max(z)      - Save the max value of the argument and the current
  1015.  *                    row maximum.
  1016.  *  
  1017.  * The last three macros depend on having local pointers row_min, row_max,
  1018.  * and rowp being set correctly.
  1019.  */
  1020. #define set_cs(rowp,col) (rowp[col] = COULD_SEE)
  1021. #define good_row(z) ((z) >= 0 && (z) < ROWNO)
  1022. #define set_min(z) if (*row_min > (z)) *row_min = (z)
  1023. #define set_max(z) if (*row_max < (z)) *row_max = (z)
  1024. #define is_clear(row,col) viz_clear_rows[row][col]
  1025.  
  1026. /*
  1027.  * clear_path()        expanded into 4 macros/functions:
  1028.  *
  1029.  *    q1_path()
  1030.  *    q2_path()
  1031.  *    q3_path()
  1032.  *    q4_path()
  1033.  *
  1034.  * "Draw" a line from the start to the given location.  Stop if we hit
  1035.  * something that blocks light.  The start and finish points themselves are
  1036.  * not checked, just the points between them.  These routines do _not_
  1037.  * expect to be called with the same starting and stopping point.
  1038.  *
  1039.  * These routines use the generalized integer Bresenham's algorithm (fast
  1040.  * line drawing) for all quadrants.  The algorithm was taken from _Procedural
  1041.  * Elements for Computer Graphics_, by David F. Rogers.  McGraw-Hill, 1985.
  1042.  */
  1043. #ifdef MACRO_CPATH    /* quadrant calls are macros */
  1044.  
  1045. /*
  1046.  * When called, the result is in "result".
  1047.  * The first two arguments (srow,scol) are one end of the path.  The next
  1048.  * two arguments (row,col) are the destination.  The last argument is
  1049.  * used as a C language label.  This means that it must be different
  1050.  * in each pair of calls.
  1051.  */
  1052.  
  1053. /*
  1054.  *  Quadrant I (step < 0).
  1055.  */
  1056. #define q1_path(srow,scol,y2,x2,label)                   \
  1057. {                            \
  1058.     int dx, dy;                        \
  1059.     register int k, err, x, y, dxs, dys;        \
  1060.                             \
  1061.     x  = (scol);    y  = (srow);            \
  1062.     dx = (x2) - x;    dy = y - (y2);            \
  1063.                             \
  1064.     result = 0;         /* default to a blocked path */\
  1065.                             \
  1066.     dxs = dx << 1;       /* save the shifted values */\
  1067.     dys = dy << 1;                    \
  1068.     if (dy > dx) {                    \
  1069.     err = dxs - dy;                    \
  1070.                             \
  1071.     for (k = dy-1; k; k--) {            \
  1072.         if (err >= 0) {                \
  1073.         x++;                    \
  1074.         err -= dys;                \
  1075.         }                        \
  1076.         y--;                    \
  1077.         err += dxs;                    \
  1078.         if (!is_clear(y,x)) goto label;/* blocked */\
  1079.     }                        \
  1080.     } else {                        \
  1081.     err = dys - dx;                    \
  1082.                             \
  1083.     for (k = dx-1; k; k--) {            \
  1084.         if (err >= 0) {                \
  1085.         y--;                    \
  1086.         err -= dxs;                \
  1087.         }                        \
  1088.         x++;                    \
  1089.         err += dys;                    \
  1090.         if (!is_clear(y,x)) goto label;/* blocked */\
  1091.     }                        \
  1092.     }                            \
  1093.                             \
  1094.     result = 1;                        \
  1095. }
  1096.  
  1097. /*
  1098.  * Quadrant IV (step > 0).
  1099.  */
  1100. #define q4_path(srow,scol,y2,x2,label)            \
  1101. {                            \
  1102.     int dx, dy;                        \
  1103.     register int k, err, x, y, dxs, dys;        \
  1104.                             \
  1105.     x  = (scol);    y  = (srow);            \
  1106.     dx = (x2) - x;    dy = (y2) - y;            \
  1107.                             \
  1108.     result = 0;         /* default to a blocked path */\
  1109.                             \
  1110.     dxs = dx << 1;       /* save the shifted values */\
  1111.     dys = dy << 1;                    \
  1112.     if (dy > dx) {                    \
  1113.     err = dxs - dy;                    \
  1114.                             \
  1115.     for (k = dy-1; k; k--) {            \
  1116.         if (err >= 0) {                \
  1117.         x++;                    \
  1118.         err -= dys;                \
  1119.         }                        \
  1120.         y++;                    \
  1121.         err += dxs;                    \
  1122.         if (!is_clear(y,x)) goto label;/* blocked */\
  1123.     }                        \
  1124.                             \
  1125.     } else {                        \
  1126.     err = dys - dx;                    \
  1127.                             \
  1128.     for (k = dx-1; k; k--) {            \
  1129.         if (err >= 0) {                \
  1130.         y++;                    \
  1131.         err -= dxs;                \
  1132.         }                        \
  1133.         x++;                    \
  1134.         err += dys;                    \
  1135.         if (!is_clear(y,x)) goto label;/* blocked */\
  1136.     }                        \
  1137.     }                            \
  1138.                             \
  1139.     result = 1;                        \
  1140. }
  1141.  
  1142. /*
  1143.  * Quadrant II (step < 0).
  1144.  */
  1145. #define q2_path(srow,scol,y2,x2,label)                   \
  1146. {                            \
  1147.     int dx, dy;                        \
  1148.     register int k, err, x, y, dxs, dys;        \
  1149.                             \
  1150.     x  = (scol);    y  = (srow);            \
  1151.     dx = x - (x2);    dy = y - (y2);            \
  1152.                             \
  1153.     result = 0;         /* default to a blocked path */\
  1154.                             \
  1155.     dxs = dx << 1;       /* save the shifted values */\
  1156.     dys = dy << 1;                    \
  1157.     if (dy > dx) {                    \
  1158.     err = dxs - dy;                    \
  1159.                             \
  1160.     for (k = dy-1; k; k--) {            \
  1161.         if (err >= 0) {                \
  1162.         x--;                    \
  1163.         err -= dys;                \
  1164.         }                        \
  1165.         y--;                    \
  1166.         err += dxs;                    \
  1167.         if (!is_clear(y,x)) goto label;/* blocked */\
  1168.     }                        \
  1169.     } else {                        \
  1170.     err = dys - dx;                    \
  1171.                             \
  1172.     for (k = dx-1; k; k--) {            \
  1173.         if (err >= 0) {                \
  1174.         y--;                    \
  1175.         err -= dxs;                \
  1176.         }                        \
  1177.         x--;                    \
  1178.         err += dys;                    \
  1179.         if (!is_clear(y,x)) goto label;/* blocked */\
  1180.     }                        \
  1181.     }                            \
  1182.                             \
  1183.     result = 1;                        \
  1184. }
  1185.  
  1186. /*
  1187.  * Quadrant III (step > 0).
  1188.  */
  1189. #define q3_path(srow,scol,y2,x2,label)            \
  1190. {                            \
  1191.     int dx, dy;                        \
  1192.     register int k, err, x, y, dxs, dys;        \
  1193.                             \
  1194.     x  = (scol);    y  = (srow);            \
  1195.     dx = x - (x2);    dy = (y2) - y;            \
  1196.                             \
  1197.     result = 0;         /* default to a blocked path */\
  1198.                             \
  1199.     dxs = dx << 1;       /* save the shifted values */\
  1200.     dys = dy << 1;                    \
  1201.     if (dy > dx) {                    \
  1202.     err = dxs - dy;                    \
  1203.                             \
  1204.     for (k = dy-1; k; k--) {            \
  1205.         if (err >= 0) {                \
  1206.         x--;                    \
  1207.         err -= dys;                \
  1208.         }                        \
  1209.         y++;                    \
  1210.         err += dxs;                    \
  1211.         if (!is_clear(y,x)) goto label;/* blocked */\
  1212.     }                        \
  1213.                             \
  1214.     } else {                        \
  1215.     err = dys - dx;                    \
  1216.                             \
  1217.     for (k = dx-1; k; k--) {            \
  1218.         if (err >= 0) {                \
  1219.         y++;                    \
  1220.         err -= dxs;                \
  1221.         }                        \
  1222.         x--;                    \
  1223.         err += dys;                    \
  1224.         if (!is_clear(y,x)) goto label;/* blocked */\
  1225.     }                        \
  1226.     }                            \
  1227.                             \
  1228.     result = 1;                        \
  1229. }
  1230.  
  1231. #else   /* quadrants are really functions */
  1232.  
  1233. static int FDECL(_q1_path, (int,int,int,int));
  1234. static int FDECL(_q2_path, (int,int,int,int));
  1235. static int FDECL(_q3_path, (int,int,int,int));
  1236. static int FDECL(_q4_path, (int,int,int,int));
  1237.  
  1238. #define q1_path(sy,sx,y,x,dummy) result = _q1_path(sy,sx,y,x)
  1239. #define q2_path(sy,sx,y,x,dummy) result = _q2_path(sy,sx,y,x)
  1240. #define q3_path(sy,sx,y,x,dummy) result = _q3_path(sy,sx,y,x)
  1241. #define q4_path(sy,sx,y,x,dummy) result = _q4_path(sy,sx,y,x)
  1242.  
  1243. /*
  1244.  * Quadrant I (step < 0).
  1245.  */
  1246. static int
  1247. _q1_path(srow,scol,y2,x2)
  1248.     int scol, srow, y2, x2;
  1249. {
  1250.     int dx, dy;
  1251.     register int k, err, x, y, dxs, dys;
  1252.  
  1253.     x  = scol;        y  = srow;
  1254.     dx = x2 - x;    dy = y - y2;
  1255.  
  1256.     dxs = dx << 1;       /* save the shifted values */
  1257.     dys = dy << 1;
  1258.     if (dy > dx) {
  1259.     err = dxs - dy;
  1260.  
  1261.     for (k = dy-1; k; k--) {
  1262.         if (err >= 0) {
  1263.         x++;
  1264.         err -= dys;
  1265.         }
  1266.         y--;
  1267.         err += dxs;
  1268.         if (!is_clear(y,x)) return 0; /* blocked */
  1269.     }
  1270.     } else {
  1271.     err = dys - dx;
  1272.  
  1273.     for (k = dx-1; k; k--) {
  1274.         if (err >= 0) {
  1275.         y--;
  1276.         err -= dxs;
  1277.         }
  1278.         x++;
  1279.         err += dys;
  1280.         if (!is_clear(y,x)) return 0;/* blocked */
  1281.     }
  1282.     }
  1283.  
  1284.     return 1;
  1285. }
  1286.  
  1287. /*
  1288.  * Quadrant IV (step > 0).
  1289.  */
  1290. static int
  1291. _q4_path(srow,scol,y2,x2)
  1292.     int scol, srow, y2, x2;
  1293. {
  1294.     int dx, dy;
  1295.     register int k, err, x, y, dxs, dys;
  1296.  
  1297.     x  = scol;        y  = srow;
  1298.     dx = x2 - x;    dy = y2 - y;
  1299.  
  1300.     dxs = dx << 1;       /* save the shifted values */
  1301.     dys = dy << 1;
  1302.     if (dy > dx) {
  1303.     err = dxs - dy;
  1304.  
  1305.     for (k = dy-1; k; k--) {
  1306.         if (err >= 0) {
  1307.         x++;
  1308.         err -= dys;
  1309.         }
  1310.         y++;
  1311.         err += dxs;
  1312.         if (!is_clear(y,x)) return 0; /* blocked */
  1313.     }
  1314.     } else {
  1315.     err = dys - dx;
  1316.  
  1317.     for (k = dx-1; k; k--) {
  1318.         if (err >= 0) {
  1319.         y++;
  1320.         err -= dxs;
  1321.         }
  1322.         x++;
  1323.         err += dys;
  1324.         if (!is_clear(y,x)) return 0;/* blocked */
  1325.     }
  1326.     }
  1327.  
  1328.     return 1;
  1329. }
  1330.  
  1331. /*
  1332.  * Quadrant II (step < 0).
  1333.  */
  1334. static int
  1335. _q2_path(srow,scol,y2,x2)
  1336.     int scol, srow, y2, x2;
  1337. {
  1338.     int dx, dy;
  1339.     register int k, err, x, y, dxs, dys;
  1340.  
  1341.     x  = scol;        y  = srow;
  1342.     dx = x - x2;    dy = y - y2;
  1343.  
  1344.     dxs = dx << 1;       /* save the shifted values */
  1345.     dys = dy << 1;
  1346.     if (dy > dx) {
  1347.     err = dxs - dy;
  1348.  
  1349.     for (k = dy-1; k; k--) {
  1350.         if (err >= 0) {
  1351.         x--;
  1352.         err -= dys;
  1353.         }
  1354.         y--;
  1355.         err += dxs;
  1356.         if (!is_clear(y,x)) return 0; /* blocked */
  1357.     }
  1358.     } else {
  1359.     err = dys - dx;
  1360.  
  1361.     for (k = dx-1; k; k--) {
  1362.         if (err >= 0) {
  1363.         y--;
  1364.         err -= dxs;
  1365.         }
  1366.         x--;
  1367.         err += dys;
  1368.         if (!is_clear(y,x)) return 0;/* blocked */
  1369.     }
  1370.     }
  1371.  
  1372.     return 1;
  1373. }
  1374.  
  1375. /*
  1376.  * Quadrant III (step > 0).
  1377.  */
  1378. static int
  1379. _q3_path(srow,scol,y2,x2)
  1380.     int scol, srow, y2, x2;
  1381. {
  1382.     int dx, dy;
  1383.     register int k, err, x, y, dxs, dys;
  1384.  
  1385.     x  = scol;        y  = srow;
  1386.     dx = x - x2;    dy = y2 - y;
  1387.  
  1388.     dxs = dx << 1;       /* save the shifted values */
  1389.     dys = dy << 1;
  1390.     if (dy > dx) {
  1391.     err = dxs - dy;
  1392.  
  1393.     for (k = dy-1; k; k--) {
  1394.         if (err >= 0) {
  1395.         x--;
  1396.         err -= dys;
  1397.         }
  1398.         y++;
  1399.         err += dxs;
  1400.         if (!is_clear(y,x)) return 0; /* blocked */
  1401.     }
  1402.     } else {
  1403.     err = dys - dx;
  1404.  
  1405.     for (k = dx-1; k; k--) {
  1406.         if (err >= 0) {
  1407.         y++;
  1408.         err -= dxs;
  1409.         }
  1410.         x--;
  1411.         err += dys;
  1412.         if (!is_clear(y,x)) return 0;/* blocked */
  1413.     }
  1414.     }
  1415.  
  1416.     return 1;
  1417. }
  1418.  
  1419. #endif    /* quadrants are functions */
  1420.  
  1421. /*
  1422.  * Use vision tables to determine if there is a clear path from
  1423.  * (col1,row1) to (col2,row2).  This is used by:
  1424.  *        m_cansee()
  1425.  *        m_canseeu()
  1426.  */
  1427. boolean
  1428. clear_path(col1,row1,col2,row2)
  1429.     int col1, row1, col2, row2;
  1430. {
  1431.     int result;
  1432.  
  1433.     if(col1 < col2) {
  1434.     if(row1 > row2) {
  1435.         q1_path(row1,col1,row2,col2,cleardone);
  1436.     } else {
  1437.         q4_path(row1,col1,row2,col2,cleardone);
  1438.     }
  1439.     } else {
  1440.     if(row1 > row2) {
  1441.         q2_path(row1,col1,row2,col2,cleardone);
  1442.     } else if(row1 == row2 && col1 == col2) {
  1443.         result = 1;
  1444.     } else {
  1445.         q3_path(row1,col1,row2,col2,cleardone);
  1446.     }
  1447.     }
  1448. cleardone:
  1449.     return((boolean)result);
  1450. }
  1451.  
  1452. #ifdef VISION_TABLES
  1453. /*===========================================================================*\
  1454.                 GENERAL LINE OF SIGHT
  1455.                 Algorithm D
  1456. \*===========================================================================*/
  1457.  
  1458.  
  1459. /*
  1460.  * Indicate caller for the shadow routines.
  1461.  */
  1462. #define FROM_RIGHT 0
  1463. #define FROM_LEFT  1
  1464.  
  1465.  
  1466. /*
  1467.  * Include the table definitions.
  1468.  */
  1469. #include "vis_tab.h"
  1470.  
  1471.  
  1472. /* 3D table pointers. */
  1473. static close2d *close_dy[CLOSE_MAX_BC_DY];
  1474. static far2d   *far_dy[FAR_MAX_BC_DY];
  1475.  
  1476. static void FDECL(right_side, (int,int,int,int,int,int,int,char*));
  1477. static void FDECL(left_side, (int,int,int,int,int,int,int,char*));
  1478. static int FDECL(close_shadow, (int,int,int,int));
  1479. static int FDECL(far_shadow, (int,int,int,int));
  1480.  
  1481. /*
  1482.  * Initialize algorithm D's table pointers.  If we don't have these,
  1483.  * then we do 3D table lookups.  Verrrry slow.
  1484.  */
  1485. static void
  1486. view_init()
  1487. {
  1488.     int i;
  1489.  
  1490.     for (i = 0; i < CLOSE_MAX_BC_DY; i++)
  1491.     close_dy[i] = &close_table[i];
  1492.  
  1493.     for (i = 0; i < FAR_MAX_BC_DY; i++)
  1494.     far_dy[i] = &far_table[i];
  1495. }
  1496.  
  1497.  
  1498. /*
  1499.  * If the far table has an entry of OFF_TABLE, then the far block prevents
  1500.  * us from seeing the location just above/below it.  I.e. the first visible
  1501.  * location is one *before* the block.
  1502.  */
  1503. #define OFF_TABLE 0xff
  1504.  
  1505. static int
  1506. close_shadow(side,this_row,block_row,block_col)
  1507.     int side,this_row,block_row,block_col;
  1508. {
  1509.     register int sdy, sdx, pdy, offset;
  1510.  
  1511.     /*
  1512.      * If on the same column (block_row = -1), then we can see it.
  1513.      */
  1514.     if (block_row < 0) return block_col;
  1515.  
  1516.     /* Take explicit absolute values.  Adjust. */
  1517.     if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy;    /* src   dy */
  1518.     if ((sdx = (start_col-block_col)) < 0) sdx = -sdx;        /* src   dx */
  1519.     if ((pdy = (block_row-this_row))  < 0) pdy = -pdy;        /* point dy */
  1520.  
  1521.     if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX ||
  1522.                             pdy >= CLOSE_MAX_BC_DY) {
  1523.     impossible("close_shadow:  bad value");
  1524.     return block_col;
  1525.     }
  1526.     offset = close_dy[sdy]->close[sdx][pdy];
  1527.     if (side == FROM_RIGHT)
  1528.     return block_col + offset;
  1529.  
  1530.     return block_col - offset;
  1531. }
  1532.  
  1533.  
  1534. static int
  1535. far_shadow(side,this_row,block_row,block_col)
  1536.     int side,this_row,block_row,block_col;
  1537. {
  1538.     register int sdy, sdx, pdy, offset;
  1539.  
  1540.     /*
  1541.      * Take care of a bug that shows up only on the borders.
  1542.      *
  1543.      * If the block is beyond the border, then the row is negative.  Return
  1544.      * the block's column number (should be 0 or COLNO-1).
  1545.      *
  1546.      * Could easily have the column be -1, but then wouldn't know if it was
  1547.      * the left or right border.
  1548.      */
  1549.     if (block_row < 0) return block_col;
  1550.  
  1551.     /* Take explicit absolute values.  Adjust. */
  1552.     if ((sdy = (start_row-block_row)) < 0) sdy = -sdy;        /* src   dy */
  1553.     if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx;    /* src   dx */
  1554.     if ((pdy = (block_row-this_row))  < 0) pdy = -pdy; --pdy;    /* point dy */
  1555.  
  1556.     if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX ||
  1557.                         pdy < 0 || pdy >= FAR_MAX_BC_DY) {
  1558.     impossible("far_shadow:  bad value");
  1559.     return block_col;
  1560.     }
  1561.     if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1;
  1562.     if (side == FROM_RIGHT)
  1563.     return block_col + offset;
  1564.  
  1565.     return block_col - offset;
  1566. }
  1567.  
  1568.  
  1569. /*
  1570.  * right_side()
  1571.  *
  1572.  * Figure out what could be seen on the right side of the source.
  1573.  */
  1574. static void
  1575. right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits)
  1576.     int row;        /* current row */
  1577.     int    cb_row, cb_col;    /* close block row and col */
  1578.     int    fb_row, fb_col;    /* far block row and col */
  1579.     int left;        /* left mark of the previous row */
  1580.     int    right_mark;    /* right mark of previous row */
  1581.     char *limits;    /* points at range limit for current row, or NULL */
  1582. {
  1583.     register int  i;
  1584.     register char *rowp;
  1585.     int  hit_stone = 0;
  1586.     int  left_shadow, right_shadow, loc_right;
  1587.     int  lblock_col;        /* local block column (current row) */
  1588.     int  nrow, deeper;
  1589.     char *row_min;        /* left most */
  1590.     char *row_max;        /* right most */
  1591.     int          lim_max;    /* right most limit of circle */
  1592.  
  1593.     nrow    = row + step;
  1594.     deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  1595.     if(!vis_func) {
  1596.     rowp    = cs_rows[row];
  1597.     row_min = &cs_left[row];
  1598.     row_max = &cs_right[row];
  1599.     }
  1600.     if(limits) {
  1601.     lim_max = start_col + *limits;
  1602.     if(lim_max > COLNO-1) lim_max = COLNO-1;
  1603.     if(right_mark > lim_max) right_mark = lim_max;
  1604.     limits++; /* prepare for next row */
  1605.     } else
  1606.     lim_max = COLNO-1;
  1607.  
  1608.     /*
  1609.      * Get the left shadow from the close block.  This value could be
  1610.      * illegal.
  1611.      */
  1612.     left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col);
  1613.  
  1614.     /*
  1615.      * Mark all stone walls as seen before the left shadow.  All this work
  1616.      * for a special case.
  1617.      *
  1618.      * NOTE.  With the addition of this code in here, it is now *required* 
  1619.      * for the algorithm to work correctly.  If this is commented out,
  1620.      * change the above assignment so that left and not left_shadow is the
  1621.      * variable that gets the shadow.
  1622.      */
  1623.     while (left <= right_mark) {
  1624.     loc_right = right_ptrs[row][left];
  1625.     if(loc_right > lim_max) loc_right = lim_max;
  1626.     if (viz_clear_rows[row][left]) {
  1627.         if (loc_right >= left_shadow) {
  1628.         left = left_shadow;    /* opening ends beyond shadow */
  1629.         break;
  1630.         }
  1631.         left = loc_right;
  1632.         loc_right = right_ptrs[row][left];
  1633.         if(loc_right > lim_max) loc_right = lim_max;
  1634.         if (left == loc_right) return;    /* boundary */
  1635.  
  1636.         /* Shadow covers opening, beyond right mark */
  1637.         if (left == right_mark && left_shadow > right_mark) return;
  1638.     }
  1639.  
  1640.     if (loc_right > right_mark)    /* can't see stone beyond the mark */
  1641.         loc_right = right_mark;
  1642.  
  1643.     if(vis_func) {
  1644.         for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  1645.     } else {
  1646.         for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  1647.         set_min(left);    set_max(loc_right);
  1648.     }
  1649.  
  1650.     if (loc_right == right_mark) return;    /* all stone */
  1651.     if (loc_right >= left_shadow) hit_stone = 1;
  1652.     left = loc_right + 1;
  1653.     }
  1654.  
  1655.     /*
  1656.      * At this point we are at the first visible clear spot on or beyond
  1657.      * the left shadow, unless the left shadow is an illegal value.  If we
  1658.      * have "hit stone" then we have a stone wall just to our left.
  1659.      */
  1660.  
  1661.     /*
  1662.      * Get the right shadow.  Make sure that it is a legal value.
  1663.      */
  1664.     if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO)
  1665.     right_shadow = COLNO-1;
  1666.     /*
  1667.      * Make vertical walls work the way we want them.  In this case, we
  1668.      * note when the close block blocks the column just above/beneath
  1669.      * it (right_shadow < fb_col [actually right_shadow == fb_col-1]).  If
  1670.      * the location is filled, then we want to see it, so we put the
  1671.      * right shadow back (same as fb_col).
  1672.      */
  1673.     if (right_shadow < fb_col && !viz_clear_rows[row][fb_col])
  1674.     right_shadow = fb_col;
  1675.     if(right_shadow > lim_max) right_shadow = lim_max;
  1676.  
  1677.     /*
  1678.      * Main loop.  Within the range of sight of the previous row, mark all
  1679.      * stone walls as seen.  Follow open areas recursively.
  1680.      */
  1681.     while (left <= right_mark) {
  1682.     /* Get the far right of the opening or wall */
  1683.     loc_right = right_ptrs[row][left];
  1684.     if(loc_right > lim_max) loc_right = lim_max;
  1685.  
  1686.     if (!viz_clear_rows[row][left]) {
  1687.         hit_stone = 1;    /* use stone on this row as close block */
  1688.         /*
  1689.          * We can see all of the wall until the next open spot or the
  1690.          * start of the shadow caused by the far block (right).
  1691.          *
  1692.          * Can't see stone beyond the right mark.
  1693.          */
  1694.         if (loc_right > right_mark) loc_right = right_mark;
  1695.  
  1696.         if(vis_func) {
  1697.         for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  1698.         } else {
  1699.         for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  1700.         set_min(left);    set_max(loc_right);
  1701.         }
  1702.  
  1703.         if (loc_right == right_mark) return;    /* hit the end */
  1704.         left = loc_right + 1;
  1705.         loc_right = right_ptrs[row][left];
  1706.         if(loc_right > lim_max) loc_right = lim_max;
  1707.         /* fall through... we know at least one position is visible */
  1708.     }
  1709.  
  1710.     /*
  1711.      * We are in an opening.
  1712.      *
  1713.      * If this is the first open spot since the could see area  (this is
  1714.      * true if we have hit stone), get the shadow generated by the wall
  1715.      * just to our left.
  1716.      */
  1717.     if (hit_stone) {
  1718.         lblock_col = left-1;    /* local block column */
  1719.         left = close_shadow(FROM_RIGHT,row,row,lblock_col);
  1720.         if (left > lim_max) break;        /* off the end */
  1721.     }
  1722.  
  1723.     /*
  1724.      * Check if the shadow covers the opening.  If it does, then
  1725.      * move to end of the opening.  A shadow generated on from a
  1726.      * wall on this row does *not* cover the wall on the right
  1727.      * of the opening.
  1728.      */
  1729.     if (left >= loc_right) {
  1730.         if (loc_right == lim_max) {        /* boundary */
  1731.         if (left == lim_max) {
  1732.             if(vis_func) (*vis_func)(lim_max, row, varg);
  1733.             else {
  1734.             set_cs(rowp,lim_max);    /* last pos */
  1735.             set_max(lim_max);
  1736.             }
  1737.         }
  1738.         return;                    /* done */
  1739.         }
  1740.         left = loc_right;
  1741.         continue;
  1742.     }
  1743.  
  1744.     /*
  1745.      * If the far wall of the opening (loc_right) is closer than the
  1746.      * shadow limit imposed by the far block (right) then use the far
  1747.      * wall as our new far block when we recurse.
  1748.      *
  1749.      * If the limits are the the same, and the far block really exists
  1750.      * (fb_row >= 0) then do the same as above.
  1751.      *
  1752.      * Normally, the check would be for the far wall being closer OR EQUAL
  1753.      * to the shadow limit.  However, there is a bug that arises from the
  1754.      * fact that the clear area pointers end in an open space (if it
  1755.      * exists) on a boundary.  This then makes a far block exist where it
  1756.      * shouldn't --- on a boundary.  To get around that, I had to
  1757.      * introduce the concept of a non-existent far block (when the
  1758.      * row < 0).  Next I have to check for it.  Here is where that check
  1759.      * exists.
  1760.      */
  1761.     if ((loc_right < right_shadow) ||
  1762.                 (fb_row >= 0 && loc_right == right_shadow)) {
  1763.         if(vis_func) {
  1764.         for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg);
  1765.         } else {
  1766.         for (i = left; i <= loc_right; i++) set_cs(rowp,i);
  1767.         set_min(left);    set_max(loc_right);
  1768.         }
  1769.  
  1770.         if (deeper) {
  1771.         if (hit_stone)
  1772.             right_side(nrow,row,lblock_col,row,loc_right,
  1773.                             left,loc_right,limits);
  1774.         else
  1775.             right_side(nrow,cb_row,cb_col,row,loc_right,
  1776.                             left,loc_right,limits);
  1777.         }
  1778.  
  1779.         /*
  1780.          * The following line, setting hit_stone, is needed for those
  1781.          * walls that are only 1 wide.  If hit stone is *not* set and
  1782.          * the stone is only one wide, then the close block is the old
  1783.          * one instead one on the current row.  A way around having to
  1784.          * set it here is to make left = loc_right (not loc_right+1) and
  1785.          * let the outer loop take care of it.  However, if we do that
  1786.          * then we then have to check for boundary conditions here as
  1787.          * well.
  1788.          */
  1789.         hit_stone = 1;
  1790.  
  1791.         left = loc_right+1;
  1792.     }
  1793.     /*
  1794.      * The opening extends beyond the right mark.  This means that
  1795.      * the next far block is the current far block.
  1796.      */
  1797.     else {
  1798.         if(vis_func) {
  1799.         for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg);
  1800.         } else {
  1801.         for (i = left; i <= right_shadow; i++) set_cs(rowp,i);
  1802.         set_min(left);    set_max(right_shadow);
  1803.         }
  1804.  
  1805.         if (deeper) {
  1806.         if (hit_stone)
  1807.             right_side(nrow,   row,lblock_col,fb_row,fb_col,
  1808.                              left,right_shadow,limits);
  1809.         else
  1810.             right_side(nrow,cb_row,    cb_col,fb_row,fb_col,
  1811.                              left,right_shadow,limits);
  1812.         }
  1813.  
  1814.         return;    /* we're outta here */
  1815.     }
  1816.     }
  1817. }
  1818.  
  1819.  
  1820. /*
  1821.  * left_side()
  1822.  *
  1823.  * This routine is the mirror image of right_side().  Please see right_side()
  1824.  * for blow by blow comments.
  1825.  */
  1826. static void
  1827. left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits)
  1828.     int row;        /* the current row */
  1829.     int    cb_row, cb_col;    /* close block row and col */
  1830.     int    fb_row, fb_col;    /* far block row and col */
  1831.     int    left_mark;    /* left mark of previous row */
  1832.     int right;        /* right mark of the previous row */
  1833.     char *limits;
  1834. {
  1835.     register int  i;
  1836.     register char *rowp;
  1837.     int  hit_stone = 0;
  1838.     int  left_shadow, right_shadow, loc_left;
  1839.     int  lblock_col;        /* local block column (current row) */
  1840.     int  nrow, deeper;
  1841.     char *row_min;        /* left most */
  1842.     char *row_max;        /* right most */
  1843.     int          lim_min;
  1844.  
  1845.     nrow    = row + step;
  1846.     deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  1847.     if(!vis_func) {
  1848.     rowp    = cs_rows[row];
  1849.     row_min = &cs_left[row];
  1850.     row_max = &cs_right[row];
  1851.     }
  1852.     if(limits) {
  1853.     lim_min = start_col - *limits;
  1854.     if(lim_min < 0) lim_min = 0;
  1855.     if(left_mark < lim_min) left_mark = lim_min;
  1856.     limits++; /* prepare for next row */
  1857.     } else
  1858.     lim_min = 0;
  1859.  
  1860.     /* This value could be illegal. */
  1861.     right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col);
  1862.  
  1863.     while ( right >= left_mark ) {
  1864.     loc_left = left_ptrs[row][right];
  1865.     if(loc_left < lim_min) loc_left = lim_min;
  1866.     if (viz_clear_rows[row][right]) {
  1867.         if (loc_left <= right_shadow) {
  1868.         right = right_shadow;    /* opening ends beyond shadow */
  1869.         break;
  1870.         }
  1871.         right = loc_left;
  1872.         loc_left = left_ptrs[row][right];
  1873.         if(loc_left < lim_min) loc_left = lim_min;
  1874.         if (right == loc_left) return;    /* boundary */
  1875.     }
  1876.  
  1877.     if (loc_left < left_mark)    /* can't see beyond the left mark */
  1878.         loc_left = left_mark;
  1879.  
  1880.     if(vis_func) {
  1881.         for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  1882.     } else {
  1883.         for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  1884.         set_min(loc_left);    set_max(right);
  1885.     }
  1886.  
  1887.     if (loc_left == left_mark) return;    /* all stone */
  1888.     if (loc_left <= right_shadow) hit_stone = 1;
  1889.     right = loc_left - 1;
  1890.     }
  1891.  
  1892.     /* At first visible clear spot on or beyond the right shadow. */
  1893.  
  1894.     if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0)
  1895.     left_shadow = 0;
  1896.     
  1897.     /* Do vertical walls as we want. */
  1898.     if (left_shadow > fb_col && !viz_clear_rows[row][fb_col])
  1899.     left_shadow = fb_col;
  1900.     if(left_shadow < lim_min) left_shadow = lim_min;
  1901.  
  1902.     while (right >= left_mark) {
  1903.     loc_left = left_ptrs[row][right];
  1904.  
  1905.     if (!viz_clear_rows[row][right]) {
  1906.         hit_stone = 1;    /* use stone on this row as close block */
  1907.  
  1908.         /* We can only see walls until the left mark */
  1909.         if (loc_left < left_mark) loc_left = left_mark;
  1910.  
  1911.         if(vis_func) {
  1912.         for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  1913.         } else {
  1914.         for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  1915.         set_min(loc_left);    set_max(right);
  1916.         }
  1917.  
  1918.         if (loc_left == left_mark) return;    /* hit end */
  1919.         right = loc_left - 1;
  1920.         loc_left = left_ptrs[row][right];
  1921.         if (loc_left < lim_min) loc_left = lim_min;
  1922.         /* fall through...*/
  1923.     }
  1924.  
  1925.     /* We are in an opening. */
  1926.     if (hit_stone) {
  1927.         lblock_col = right+1;    /* stone block (local) */
  1928.         right = close_shadow(FROM_LEFT,row,row,lblock_col);
  1929.         if (right < lim_min) return;    /* off the end */
  1930.     }
  1931.  
  1932.     /*  Check if the shadow covers the opening. */
  1933.     if (right <= loc_left) {
  1934.         /*  Make a boundary condition work. */
  1935.         if (loc_left == lim_min) {    /* at boundary */
  1936.         if (right == lim_min) {
  1937.             if(vis_func) (*vis_func)(lim_min, row, varg);
  1938.             else {
  1939.             set_cs(rowp,lim_min);    /* caught the last pos */
  1940.             set_min(lim_min);
  1941.             }
  1942.         }
  1943.         return;            /* and break out the loop */
  1944.         }
  1945.  
  1946.         right = loc_left;
  1947.         continue;
  1948.     }
  1949.  
  1950.     /* If the far wall of the opening is closer than the shadow limit. */
  1951.     if ((loc_left > left_shadow) ||
  1952.                     (fb_row >= 0 && loc_left == left_shadow)) {
  1953.         if(vis_func) {
  1954.         for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg);
  1955.         } else {
  1956.         for (i = loc_left; i <= right; i++) set_cs(rowp,i);
  1957.         set_min(loc_left);    set_max(right);
  1958.         }
  1959.  
  1960.         if (deeper) {
  1961.         if (hit_stone)
  1962.             left_side(nrow,row,lblock_col,row,loc_left,
  1963.                             loc_left,right,limits);
  1964.         else
  1965.             left_side(nrow,cb_row,cb_col,row,loc_left,
  1966.                             loc_left,right,limits);
  1967.         }
  1968.  
  1969.         hit_stone = 1;    /* needed for walls of width 1 */
  1970.         right = loc_left-1;
  1971.     }
  1972.     /*  The opening extends beyond the left mark. */
  1973.     else {
  1974.         if(vis_func) {
  1975.         for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg);
  1976.         } else {
  1977.         for (i = left_shadow; i <= right; i++) set_cs(rowp,i);
  1978.         set_min(left_shadow);    set_max(right);
  1979.         }
  1980.  
  1981.         if (deeper) {
  1982.         if (hit_stone)
  1983.             left_side(nrow,row,lblock_col,fb_row,fb_col,
  1984.                              left_shadow,right,limits);
  1985.         else
  1986.             left_side(nrow,cb_row,cb_col,fb_row,fb_col,
  1987.                              left_shadow,right,limits);
  1988.         }
  1989.  
  1990.         return;    /* we're outta here */
  1991.     }
  1992.  
  1993.     }
  1994. }
  1995.  
  1996. /*
  1997.  * view_from
  1998.  *  
  1999.  * Calculate a view from the given location.  Initialize and fill a
  2000.  * ROWNOxCOLNO array (could_see) with all the locations that could be
  2001.  * seen from the source location.  Initialize and fill the left most
  2002.  * and right most boundaries of what could be seen.
  2003.  */
  2004. static void
  2005. view_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg)
  2006.     int  srow, scol;            /* source row and column */
  2007.     char **loc_cs_rows;            /* could_see array (row pointers) */
  2008.     char *left_most, *right_most;    /* limits of what could be seen */
  2009.     int range;        /* 0 if unlimited */
  2010.     void FDECL((*func), (int,int,genericptr_t));
  2011.     genericptr_t arg;
  2012. {
  2013.     register int i;
  2014.     char     *rowp;
  2015.     int         nrow, left, right, left_row, right_row;
  2016.     char     *limits;
  2017.  
  2018.     /* Set globals for near_shadow(), far_shadow(), etc. to use. */
  2019.     start_col = scol;
  2020.     start_row = srow;
  2021.     cs_rows   = loc_cs_rows;
  2022.     cs_left   = left_most;
  2023.     cs_right  = right_most;
  2024.     vis_func = func;
  2025.     varg = arg;
  2026.  
  2027.     /*  Find the left and right limits of sight on the starting row. */
  2028.     if (viz_clear_rows[srow][scol]) {
  2029.     left  = left_ptrs[srow][scol];
  2030.     right = right_ptrs[srow][scol];
  2031.     } else {
  2032.     left  = (!scol) ? 0 :
  2033.         (viz_clear_rows[srow][scol-1] ?  left_ptrs[srow][scol-1] : scol-1);
  2034.     right = (scol == COLNO-1) ? COLNO-1 :
  2035.         (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1);
  2036.     }
  2037.  
  2038.     if(range) {
  2039.     if(range > MAX_RADIUS || range < 1)
  2040.         panic("view_from called with range %d", range);
  2041.     limits = circle_ptr(range) + 1; /* start at next row */
  2042.     if(left < scol - range) left = scol - range;
  2043.     if(right > scol + range) right = scol + range;
  2044.     } else
  2045.     limits = (char*) 0;
  2046.  
  2047.     if(func) {
  2048.     for (i = left; i <= right; i++) (*func)(i, srow, arg);
  2049.     } else {
  2050.     /* Row optimization */
  2051.     rowp = cs_rows[srow];
  2052.  
  2053.     /* We know that we can see our row. */
  2054.     for (i = left; i <= right; i++) set_cs(rowp,i);
  2055.     cs_left[srow]  = left;
  2056.     cs_right[srow] = right;
  2057.     }
  2058.  
  2059.     /* The far block has a row number of -1 if we are on an edge. */
  2060.     right_row = (right == COLNO-1) ? -1 : srow;
  2061.     left_row  = (!left)           ? -1 : srow;
  2062.  
  2063.     /*
  2064.      *  Check what could be seen in quadrants.
  2065.      */
  2066.     if ( (nrow = srow+1) < ROWNO ) {
  2067.     step =  1;    /* move down */
  2068.     if (scol<COLNO-1)
  2069.         right_side(nrow,-1,scol,right_row,right,scol,right,limits);
  2070.     if (scol)
  2071.         left_side(nrow,-1,scol,left_row, left, left, scol,limits);
  2072.     }
  2073.  
  2074.     if ( (nrow = srow-1) >= 0 ) {
  2075.     step = -1;    /* move up */
  2076.     if (scol<COLNO-1)
  2077.         right_side(nrow,-1,scol,right_row,right,scol,right,limits);
  2078.     if (scol)
  2079.         left_side(nrow,-1,scol,left_row, left, left, scol,limits);
  2080.     }
  2081. }
  2082.  
  2083.  
  2084. #else    /*===== End of algorithm D =====*/
  2085.  
  2086.  
  2087. /*===========================================================================*\
  2088.                 GENERAL LINE OF SIGHT
  2089.                 Algorithm C
  2090. \*===========================================================================*/
  2091.  
  2092. /*
  2093.  * Defines local to Algorithm C.  
  2094.  */
  2095. static void FDECL(right_side, (int,int,int,char*));
  2096. static void FDECL(left_side, (int,int,int,char*));
  2097.  
  2098. /* Initialize algorithm C (nothing). */
  2099. static void
  2100. view_init()
  2101. {
  2102. }
  2103.  
  2104. /*
  2105.  * Mark positions as visible on one quadrant of the right side.  The
  2106.  * quadrant is determined by the value of the global variable step.
  2107.  */
  2108. static void
  2109. right_side(row, left, right_mark, limits)
  2110.     int row;        /* current row */
  2111.     int left;        /* first (left side) visible spot on prev row */
  2112.     int right_mark;    /* last (right side) visible spot on prev row */
  2113.     char *limits;    /* points at range limit for current row, or NULL */
  2114. {
  2115.     int          right;    /* right limit of "could see" */
  2116.     int          right_edge;    /* right edge of an opening */
  2117.     int          nrow;        /* new row (calculate once) */
  2118.     int          deeper;    /* if TRUE, call self as needed */
  2119.     int          result;    /* set by q?_path() */
  2120.     register int  i;        /* loop counter */
  2121.     register char *rowp;    /* row optimization */
  2122.     char      *row_min;    /* left most  [used by macro set_min()] */
  2123.     char      *row_max;    /* right most [used by macro set_max()] */
  2124.     int          lim_max;    /* right most limit of circle */
  2125.  
  2126. #ifdef GCC_WARN
  2127.     rowp = row_min = row_max = 0;
  2128. #endif
  2129.     nrow    = row + step;
  2130.     /*
  2131.      * Can go deeper if the row is in bounds and the next row is within
  2132.      * the circle's limit.  We tell the latter by checking to see if the next
  2133.      * limit value is the start of a new circle radius (meaning we depend
  2134.      * on the structure of circle_data[]).
  2135.      */
  2136.     deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  2137.     if(!vis_func) {
  2138.     rowp    = cs_rows[row];    /* optimization */
  2139.     row_min = &cs_left[row];
  2140.     row_max = &cs_right[row];
  2141.     }
  2142.     if(limits) {
  2143.     lim_max = start_col + *limits;
  2144.     if(lim_max > COLNO-1) lim_max = COLNO-1;
  2145.     if(right_mark > lim_max) right_mark = lim_max;
  2146.     limits++; /* prepare for next row */
  2147.     } else
  2148.     lim_max = COLNO-1;
  2149.  
  2150.     while (left <= right_mark) {
  2151.     right_edge = right_ptrs[row][left];
  2152.     if(right_edge > lim_max) right_edge = lim_max;
  2153.  
  2154.     if (!is_clear(row,left)) {
  2155.         /*
  2156.          * Jump to the far side of a stone wall.  We can set all
  2157.          * the points in between as seen.
  2158.          *
  2159.          * If the right edge goes beyond the right mark, check to see
  2160.          * how much we can see.
  2161.          */
  2162.         if (right_edge > right_mark) {
  2163.         /*
  2164.          * If the mark on the previous row was a clear position, 
  2165.          * the odds are that we can actually see part of the wall
  2166.          * beyond the mark on this row.  If so, then see one beyond
  2167.          * the mark.  Otherwise don't.  This is a kludge so corners
  2168.          * with an adjacent doorway show up in nethack.
  2169.          */
  2170.         right_edge = is_clear(row-step,right_mark) ?
  2171.                             right_mark+1 : right_mark;
  2172.         }
  2173.         if(vis_func) {
  2174.         for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg);
  2175.         } else {
  2176.         for (i = left; i <= right_edge; i++) set_cs(rowp,i);
  2177.         set_min(left);      set_max(right_edge);
  2178.         }
  2179.         left = right_edge + 1; /* no limit check necessary */
  2180.         continue;
  2181.     }
  2182.  
  2183.     /* No checking needed if our left side is the start column. */
  2184.     if (left != start_col) { 
  2185.         /*
  2186.          * Find the left side.  Move right until we can see it or we run
  2187.          * into a wall.
  2188.          */
  2189.         for (; left <= right_edge; left++) {
  2190.         if (step < 0) {
  2191.             q1_path(start_row,start_col,row,left,rside1);
  2192.         } else {
  2193.             q4_path(start_row,start_col,row,left,rside1);
  2194.         }
  2195. rside1:                    /* used if q?_path() is a macro */
  2196.         if (result) break;
  2197.         }
  2198.  
  2199.         /*
  2200.          * Check for boundary conditions.  We *need* check (2) to break
  2201.          * an infinite loop where:
  2202.          *
  2203.          *        left == right_edge == right_mark == lim_max.
  2204.          * 
  2205.          */
  2206.         if (left > lim_max) return;    /* check (1) */
  2207.         if (left == lim_max) {    /* check (2) */
  2208.         if(vis_func) (*vis_func)(lim_max, row, varg);
  2209.         else {
  2210.             set_cs(rowp,lim_max);
  2211.             set_max(lim_max);
  2212.         }
  2213.         return;
  2214.         }
  2215.         /*
  2216.          * Check if we can see any spots in the opening.  We might
  2217.          * (left == right_edge) or might not (left == right_edge+1) have
  2218.          * been able to see the far wall.  Make sure we *can* see the
  2219.          * wall (remember, we can see the spot above/below this one)
  2220.          * by backing up.
  2221.          */
  2222.         if (left >= right_edge) {
  2223.         left = right_edge;    /* for the case left == right_edge+1 */
  2224.         continue;
  2225.         }
  2226.     }
  2227.  
  2228.     /*
  2229.      * Find the right side.  If the marker from the previous row is
  2230.      * closer than the edge on this row, then we have to check
  2231.      * how far we can see around the corner (under the overhang).  Stop
  2232.      * at the first non-visible spot or we actually hit the far wall.
  2233.      *
  2234.      * Otherwise, we know we can see the right edge of the current row.
  2235.      *
  2236.      * This must be a strict less than so that we can always see a
  2237.      * horizontal wall, even if it is adjacent to us.
  2238.      */
  2239.     if (right_mark < right_edge) {
  2240.         for (right = right_mark; right <= right_edge; right++) {
  2241.         if (step < 0) {
  2242.             q1_path(start_row,start_col,row,right,rside2);
  2243.         } else {
  2244.             q4_path(start_row,start_col,row,right,rside2);
  2245.         }
  2246. rside2:                    /* used if q?_path() is a macro */
  2247.         if (!result) break;
  2248.         }
  2249.         --right;    /* get rid of the last increment */
  2250.     }
  2251.     else
  2252.         right = right_edge;
  2253.  
  2254.     /*
  2255.      * We have the range that we want.  Set the bits.  Note that
  2256.      * there is no else --- we no longer handle splinters.
  2257.      */
  2258.     if (left <= right) {
  2259.         /*
  2260.          * An ugly special case.  If you are adjacent to a vertical wall
  2261.          * and it has a break in it, then the right mark is set to be
  2262.          * start_col.  We *want* to be able to see adjacent vertical
  2263.          * walls, so we have to set it back.
  2264.          */
  2265.         if (left == right && left == start_col &&
  2266.             start_col < (COLNO-1) && !is_clear(row,start_col+1))
  2267.         right = start_col+1;
  2268.  
  2269.         if(right > lim_max) right = lim_max;
  2270.         /* set the bits */
  2271.         if(vis_func)
  2272.         for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
  2273.         else {
  2274.         for (i = left; i <= right; i++) set_cs(rowp,i);
  2275.         set_min(left);      set_max(right);
  2276.         }
  2277.  
  2278.         /* recursive call for next finger of light */
  2279.         if (deeper) right_side(nrow,left,right,limits);
  2280.         left = right + 1; /* no limit check necessary */
  2281.     }
  2282.     }
  2283. }
  2284.  
  2285.  
  2286. /*
  2287.  * This routine is the mirror image of right_side().  See right_side() for
  2288.  * extensive comments.
  2289.  */
  2290. static void
  2291. left_side(row, left_mark, right, limits)
  2292.     int row, left_mark, right;
  2293.     char *limits;
  2294. {
  2295.     int          left, left_edge, nrow, deeper, result;
  2296.     register int  i;
  2297.     register char *rowp;
  2298.     char      *row_min, *row_max;
  2299.     int          lim_min;
  2300.  
  2301. #ifdef GCC_WARN
  2302.     rowp = row_min = row_max = 0;
  2303. #endif
  2304.     nrow    = row+step;
  2305.     deeper  = good_row(nrow) && (!limits || (*limits >= *(limits+1)));
  2306.     if(!vis_func) {
  2307.     rowp    = cs_rows[row];
  2308.     row_min = &cs_left[row];
  2309.     row_max = &cs_right[row];
  2310.     }
  2311.     if(limits) {
  2312.     lim_min = start_col - *limits;
  2313.     if(lim_min < 0) lim_min = 0;
  2314.     if(left_mark < lim_min) left_mark = lim_min;
  2315.     limits++; /* prepare for next row */
  2316.     } else
  2317.     lim_min = 0;
  2318.  
  2319.     while (right >= left_mark) {
  2320.     left_edge = left_ptrs[row][right];
  2321.     if(left_edge < lim_min) left_edge = lim_min;
  2322.  
  2323.     if (!is_clear(row,right)) {
  2324.         /* Jump to the far side of a stone wall. */
  2325.         if (left_edge < left_mark) {
  2326.         /* Maybe see more (kludge). */
  2327.         left_edge = is_clear(row-step,left_mark) ?
  2328.                             left_mark-1 : left_mark;
  2329.         }
  2330.         if(vis_func) {
  2331.         for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg);
  2332.         } else {
  2333.         for (i = left_edge; i <= right; i++) set_cs(rowp,i);
  2334.         set_min(left_edge); set_max(right);
  2335.         }
  2336.         right = left_edge - 1; /* no limit check necessary */
  2337.         continue;
  2338.     }
  2339.  
  2340.     if (right != start_col) {
  2341.         /* Find the right side. */
  2342.         for (; right >= left_edge; right--) {
  2343.         if (step < 0) {
  2344.             q2_path(start_row,start_col,row,right,lside1);
  2345.         } else {
  2346.             q3_path(start_row,start_col,row,right,lside1);
  2347.         }
  2348. lside1:                    /* used if q?_path() is a macro */
  2349.         if (result) break;
  2350.         }
  2351.  
  2352.         /* Check for boundary conditions. */
  2353.         if (right < lim_min) return;
  2354.         if (right == lim_min) {
  2355.         if(vis_func) (*vis_func)(lim_min, row, varg);
  2356.         else {
  2357.             set_cs(rowp,lim_min);
  2358.             set_min(lim_min);
  2359.         }
  2360.         return;
  2361.         }
  2362.         /* Check if we can see any spots in the opening. */
  2363.         if (right <= left_edge) {
  2364.         right = left_edge;
  2365.         continue;
  2366.         }
  2367.     }
  2368.  
  2369.     /* Find the left side. */
  2370.     if (left_mark > left_edge) {
  2371.         for (left = left_mark; left >= left_edge; --left) {
  2372.         if (step < 0) {
  2373.             q2_path(start_row,start_col,row,left,lside2);
  2374.         } else {
  2375.             q3_path(start_row,start_col,row,left,lside2);
  2376.         }
  2377. lside2:                    /* used if q?_path() is a macro */
  2378.         if (!result) break;
  2379.         }
  2380.         left++;    /* get rid of the last decrement */
  2381.     }
  2382.     else
  2383.         left = left_edge;
  2384.  
  2385.     if (left <= right) {
  2386.         /* An ugly special case. */
  2387.         if (left == right && right == start_col &&
  2388.                 start_col > 0 && !is_clear(row,start_col-1))
  2389.         left = start_col-1;
  2390.  
  2391.         if(left < lim_min) left = lim_min;
  2392.         if(vis_func)
  2393.         for (i = left; i <= right; i++) (*vis_func)(i, row, varg);
  2394.         else {
  2395.         for (i = left; i <= right; i++) set_cs(rowp,i);
  2396.         set_min(left);      set_max(right);
  2397.         }
  2398.  
  2399.         /* Recurse */
  2400.         if (deeper) left_side(nrow,left,right,limits);
  2401.         right = left - 1; /* no limit check necessary */
  2402.     }
  2403.     }
  2404. }
  2405.  
  2406.  
  2407. /*
  2408.  * Calculate all possible visible locations from the given location
  2409.  * (srow,scol).  NOTE this is (y,x)!  Mark the visible locations in the
  2410.  * array provided.
  2411.  */
  2412. static void
  2413. view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg)
  2414.     int  srow, scol;    /* starting row and column */
  2415.     char **loc_cs_rows;    /* pointers to the rows of the could_see array */
  2416.     char *left_most;    /* min mark on each row */
  2417.     char *right_most;    /* max mark on each row */
  2418.     int range;        /* 0 if unlimited */
  2419.     void FDECL((*func), (int,int,genericptr_t));
  2420.     genericptr_t arg;
  2421. {
  2422.     register int i;        /* loop counter */
  2423.     char         *rowp;        /* optimization for setting could_see */
  2424.     int         nrow;        /* the next row */
  2425.     int         left;        /* the left-most visible column */
  2426.     int         right;        /* the right-most visible column */
  2427.     char     *limits;    /* range limit for next row */
  2428.  
  2429.     /* Set globals for q?_path(), left_side(), and right_side() to use. */
  2430.     start_col = scol;
  2431.     start_row = srow;
  2432.     cs_rows   = loc_cs_rows;    /* 'could see' rows */
  2433.     cs_left   = left_most;
  2434.     cs_right  = right_most;
  2435.     vis_func = func;
  2436.     varg = arg;
  2437.  
  2438.     /*
  2439.      * Determine extent of sight on the starting row.
  2440.      */
  2441.     if (is_clear(srow,scol)) {
  2442.     left =  left_ptrs[srow][scol];
  2443.     right = right_ptrs[srow][scol];
  2444.     } else {
  2445.     /*
  2446.      * When in stone, you can only see your adjacent squares, unless
  2447.      * you are on an array boundary or a stone/clear boundary.
  2448.      */
  2449.     left  = (!scol) ? 0 :
  2450.         (is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1);
  2451.     right = (scol == COLNO-1) ? COLNO-1 :
  2452.         (is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1);
  2453.     }
  2454.  
  2455.     if(range) {
  2456.     if(range > MAX_RADIUS || range < 1)
  2457.         panic("view_from called with range %d", range);
  2458.     limits = circle_ptr(range) + 1; /* start at next row */
  2459.     if(left < scol - range) left = scol - range;
  2460.     if(right > scol + range) right = scol + range;
  2461.     } else
  2462.     limits = (char*) 0;
  2463.  
  2464.     if(func) {
  2465.     for (i = left; i <= right; i++) (*func)(i, srow, arg);
  2466.     } else {
  2467.     /* Row pointer optimization. */
  2468.     rowp = cs_rows[srow];
  2469.  
  2470.     /* We know that we can see our row. */
  2471.     for (i = left; i <= right; i++) set_cs(rowp,i);
  2472.     cs_left[srow]  = left;
  2473.     cs_right[srow] = right;
  2474.     }
  2475.  
  2476.     /*
  2477.      * Check what could be seen in quadrants.  We need to check for valid
  2478.      * rows here, since we don't do it in the routines right_side() and
  2479.      * left_side() [ugliness to remove extra routine calls].
  2480.      */
  2481.     if ( (nrow = srow+1) < ROWNO ) {    /* move down */
  2482.     step =  1;
  2483.     if (scol < COLNO-1) right_side(nrow, scol, right, limits);
  2484.     if (scol)        left_side (nrow, left,  scol, limits);
  2485.     }
  2486.  
  2487.     if ( (nrow = srow-1) >= 0 ) {    /* move up */
  2488.     step = -1;
  2489.     if (scol < COLNO-1) right_side(nrow, scol, right, limits);
  2490.     if (scol)        left_side (nrow, left,  scol, limits);
  2491.     }
  2492. }
  2493.  
  2494. #endif    /*===== End of algorithm C =====*/
  2495.  
  2496. /*
  2497.  * AREA OF EFFECT "ENGINE"
  2498.  *
  2499.  * Calculate all possible visible locations as viewed from the given location
  2500.  * (srow,scol) within the range specified. Perform "func" with (x, y) args and
  2501.  * additional argument "arg" for each square.
  2502.  *
  2503.  * If not centered on the hero, just forward arguments to view_from(); it
  2504.  * will call "func" when necessary.  If the hero is the center, use the
  2505.  * vision matrix and reduce extra work.
  2506.  */
  2507. void
  2508. do_clear_area(scol,srow,range,func,arg)
  2509.     int scol, srow, range;
  2510.     void FDECL((*func), (int,int,genericptr_t));
  2511.     genericptr_t arg;
  2512. {
  2513.     /* If not centered on hero, do the hard work of figuring the area */
  2514.     if (scol != u.ux || srow != u.uy)
  2515.         view_from(srow, scol, (char **)0, NULL, NULL, range, func, arg);
  2516.     else {
  2517.         register int x;
  2518.         int y, min_x, max_x, max_y, offset;
  2519.         char *limits;
  2520.  
  2521.         if (range > MAX_RADIUS || range < 1)
  2522.         panic("do_clear_area:  illegal range %d", range);
  2523.         if(vision_full_recalc)
  2524.         vision_recalc(0);    /* recalc vision if dirty */
  2525.         limits = circle_ptr(range);
  2526.         if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1;
  2527.         if ((y = (srow - range)) < 0) y = 0;
  2528.         for (; y <= max_y; y++) {
  2529.         offset = limits[abs(y-srow)];
  2530.         if((min_x = (scol - offset)) < 0) min_x = 0;
  2531.         if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1;
  2532.         for (x = min_x; x <= max_x; x++)
  2533.             if (couldsee(x, y))
  2534.             (*func)(x, y, arg);
  2535.         }
  2536.     }
  2537. }
  2538.  
  2539. /*vision.c*/
  2540.