OSDN Git Service

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