make rank() static again
[NetHack.git] / src / vision.c
blob3f33d726c1a713167a5291f900c76c85ecb6db0c
1 /* NetHack 3.7 vision.c $NHDT-Date: 1724939600 2024/08/29 13:53:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */
2 /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 /* Circles
8 * ==================================================================*/
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:
19 * XXX +2
20 * ...X +3
21 * ....X +4
22 * ....X +4
23 * @...X +4
25 * Externally referenced from light.c
27 const coordxy circle_data[] = {
28 /* 0*/ 0,
29 /* 1*/ 1, 1,
30 /* 3*/ 2, 2, 1,
31 /* 6*/ 3, 3, 2, 1,
32 /* 10*/ 4, 4, 4, 3, 2,
33 /* 15*/ 5, 5, 5, 4, 3, 2,
34 /* 21*/ 6, 6, 6, 5, 5, 4, 2,
35 /* 28*/ 7, 7, 7, 6, 6, 5, 4, 2,
36 /* 36*/ 8, 8, 8, 7, 7, 6, 6, 4, 2,
37 /* 45*/ 9, 9, 9, 9, 8, 8, 7, 6, 5, 3,
38 /* 55*/ 10, 10, 10, 10, 9, 9, 8, 7, 6, 5, 3,
39 /* 66*/ 11, 11, 11, 11, 10, 10, 9, 9, 8, 7, 5, 3,
40 /* 78*/ 12, 12, 12, 12, 11, 11, 10, 10, 9, 8, 7, 5, 3,
41 /* 91*/ 13, 13, 13, 13, 12, 12, 12, 11, 10, 10, 9, 7, 6, 3,
42 /*105*/ 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 10, 9, 8, 6, 3,
43 /*120*/ 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, 11, 10, 9, 8, 6, 3,
44 /*136*/ 16 /* MAX_RADIUS+1; used to terminate range loops -dlc */
48 * These are the starting indexes into the circle_data[] array for a
49 * circle of a given radius. Radius 0 used to be unused, but is now
50 * used for a single point: temporary light source of a camera flash
51 * as it traverses its path.
53 const coordxy circle_start[] = {
54 /* 0*/ 0,
55 /* 1*/ 1,
56 /* 2*/ 3,
57 /* 3*/ 6,
58 /* 4*/ 10,
59 /* 5*/ 15,
60 /* 6*/ 21,
61 /* 7*/ 38,
62 /* 8*/ 36,
63 /* 9*/ 45,
64 /*10*/ 55,
65 /*11*/ 66,
66 /*12*/ 78,
67 /*13*/ 91,
68 /*14*/ 105,
69 /*15*/ 120,
72 /*==========================================================================*/
73 /* Vision (arbitrary line of sight)
74 * =========================================*/
76 /*------ local variables ------*/
78 static seenV could_see[2][ROWNO][COLNO]; /* vision work space */
79 static seenV *cs_rows0[ROWNO], *cs_rows1[ROWNO];
80 static coordxy cs_rmin0[ROWNO], cs_rmax0[ROWNO];
81 static coordxy cs_rmin1[ROWNO], cs_rmax1[ROWNO];
83 static char viz_clear[ROWNO][COLNO]; /* vision clear/blocked map */
84 static char *viz_clear_rows[ROWNO];
86 static coordxy left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */
87 static coordxy right_ptrs[ROWNO][COLNO];
89 /* Forward declarations. */
90 staticfn void fill_point(int, int);
91 staticfn void dig_point(int, int);
92 staticfn void view_init(void);
93 staticfn void view_from(coordxy, coordxy, seenV **, coordxy *, coordxy *, int,
94 void (*)(coordxy, coordxy, genericptr_t),
95 genericptr_t);
96 staticfn void get_unused_cs(seenV ***, coordxy **, coordxy **);
97 staticfn void rogue_vision(seenV **, coordxy *, coordxy *);
99 /* Macro definitions that I can't find anywhere. */
100 #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0))
101 #define v_abs(z) ((z) < 0 ? -(z) : (z)) /* don't use abs -- it may exist */
103 /* expose viz_clear[][] for sanity checking */
104 boolean
105 get_viz_clear(int x, int y)
107 if (isok(x,y) && !viz_clear[y][x])
108 return TRUE;
109 return FALSE;
113 * vision_init()
115 * The one-time vision initialization routine.
117 * This must be called before mklev() is called in newgame() [allmain.c],
118 * or before a game restore. Else we die a horrible death.
120 void
121 vision_init(void)
123 int i;
125 /* Set up the pointers. */
126 for (i = 0; i < ROWNO; i++) {
127 cs_rows0[i] = could_see[0][i];
128 cs_rows1[i] = could_see[1][i];
129 viz_clear_rows[i] = viz_clear[i];
132 /* Start out with cs0 as our current array */
133 gv.viz_array = cs_rows0;
134 gv.viz_rmin = cs_rmin0;
135 gv.viz_rmax = cs_rmax0;
137 gv.vision_full_recalc = 0;
138 (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
140 /* Initialize the vision algorithm (currently C). */
141 view_init();
145 * does_block()
147 * Returns 0 if nothing at (x,y) blocks sight, 1 if anything other than
148 * an opaque region (gas cloud rather than CLOUD terrain) blocks sight,
149 * or 2 if an opaque region blocks sight. [At present, the rest of the
150 * code makes no distinction between 1 and 2, just between 0 and non-0.]
153 does_block(int x, int y, struct rm *lev)
155 struct obj *obj;
156 struct monst *mon;
158 #ifdef DEBUG
159 /* set DEBUGFILES=seethru in environment to see through bubbles */
160 if (gs.seethru == 0) { /* init once */
161 gs.seethru = (wizard && explicitdebug("seethru")) ? 1 : -1;
163 #endif
165 /* Features that block . . */
166 if (IS_OBSTRUCTED(lev->typ) || lev->typ == TREE
167 || (IS_DOOR(lev->typ)
168 && (lev->doormask & (D_CLOSED | D_LOCKED | D_TRAPPED))))
169 return 1;
171 #ifdef DEBUG
172 if (gs.seethru != 1) {
173 #endif
174 if (lev->typ == CLOUD || IS_WATERWALL(lev->typ) || lev->typ == LAVAWALL
175 || (Underwater && is_moat(x, y)))
176 return 1;
177 #ifdef DEBUG
178 } /* gs.seethru */
179 #endif
181 /* Boulders block light. */
182 for (obj = svl.level.objects[x][y]; obj; obj = obj->nexthere)
183 if (obj->otyp == BOULDER)
184 return 1;
186 /* Mimics mimicking a door or boulder or ... block light. */
187 if ((mon = m_at(x, y)) && (!mon->minvis || See_invisible)
188 && is_lightblocker_mappear(mon))
189 return 1;
191 #ifdef DEBUG
192 if (gs.seethru != 1) {
193 #endif
194 /* Clouds (poisonous or not) block light. */
195 if (visible_region_at(x, y))
196 return 2;
197 #ifdef DEBUG
198 } /* gs.seethru */
199 #endif
201 return 0;
205 * vision_reset()
207 * This must be called *after* the levl[][] structure is set with the new
208 * level and the level monsters and objects are in place.
210 void
211 vision_reset(void)
213 int y;
214 int x, i, dig_left, block;
215 struct rm *lev;
217 /* Start out with cs0 as our current array */
218 gv.viz_array = cs_rows0;
219 gv.viz_rmin = cs_rmin0;
220 gv.viz_rmax = cs_rmax0;
222 (void) memset((genericptr_t) could_see, 0, sizeof(could_see));
224 /* Reset the pointers and clear so that we have a "full" dungeon. */
225 (void) memset((genericptr_t) viz_clear, 0, sizeof(viz_clear));
227 /* Dig the level */
228 for (y = 0; y < ROWNO; y++) {
229 dig_left = 0;
230 block = TRUE; /* location (0,y) is always stone; it's !isok() */
231 lev = &levl[1][y];
232 for (x = 1; x < COLNO; x++, lev += ROWNO)
233 if (block != (IS_OBSTRUCTED(lev->typ) || does_block(x, y, lev))) {
234 if (block) {
235 for (i = dig_left; i < x; i++) {
236 left_ptrs[y][i] = dig_left;
237 right_ptrs[y][i] = x - 1;
239 } else {
240 i = dig_left;
241 if (dig_left)
242 dig_left--; /* point at first blocked point */
243 for (; i < x; i++) {
244 left_ptrs[y][i] = dig_left;
245 right_ptrs[y][i] = x;
246 viz_clear[y][i] = 1;
249 dig_left = x;
250 block = !block;
252 /* handle right boundary; almost identical for blocked/unblocked */
253 i = dig_left;
254 if (!block && dig_left)
255 dig_left--; /* point at first blocked point */
256 for (; i < COLNO; i++) {
257 left_ptrs[y][i] = dig_left;
258 right_ptrs[y][i] = (COLNO - 1);
259 viz_clear[y][i] = !block;
263 iflags.vision_inited = TRUE; /* vision is ready */
264 gv.vision_full_recalc = 1; /* we want to run vision_recalc() */
268 * get_unused_cs()
270 * Called from vision_recalc() and at least one light routine. Get pointers
271 * to the unused vision work area.
273 staticfn void
274 get_unused_cs(seenV ***rows, coordxy **rmin, coordxy **rmax)
276 int row;
277 coordxy *nrmin, *nrmax;
279 if (gv.viz_array == cs_rows0) {
280 *rows = cs_rows1;
281 *rmin = cs_rmin1;
282 *rmax = cs_rmax1;
283 } else {
284 *rows = cs_rows0;
285 *rmin = cs_rmin0;
286 *rmax = cs_rmax0;
289 /* return an initialized, unused work area */
290 nrmin = *rmin;
291 nrmax = *rmax;
293 (void) memset((genericptr_t) **rows, 0,
294 ROWNO * COLNO * sizeof (seenV)); /* see nothing */
295 for (row = 0; row < ROWNO; row++) { /* set row min & max */
296 *nrmin++ = COLNO - 1;
297 *nrmax++ = 1;
302 * rogue_vision()
304 * Set the "could see" and in sight bits so vision acts just like the old
305 * rogue game:
307 * + If in a room, the hero can see to the room boundaries.
308 * + The hero can always see adjacent squares.
310 * We set the in_sight bit here as well to escape a bug that shows up
311 * due to the one-sided lit wall hack.
313 staticfn void
314 rogue_vision(seenV **next, coordxy *rmin, coordxy *rmax)
316 int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */
317 int start, stop, in_door, xhi, xlo, yhi, ylo;
318 int zx, zy;
320 /* If in a lit room, we are able to see to its boundaries. */
321 /* If dark, set COULD_SEE so various spells work -dlc */
322 if (rnum >= 0) {
323 for (zy = svr.rooms[rnum].ly - 1; zy <= svr.rooms[rnum].hy + 1; zy++) {
324 rmin[zy] = start = svr.rooms[rnum].lx - 1;
325 rmax[zy] = stop = svr.rooms[rnum].hx + 1;
327 for (zx = start; zx <= stop; zx++) {
328 if (svr.rooms[rnum].rlit) {
329 next[zy][zx] = COULD_SEE | IN_SIGHT;
330 levl[zx][zy].seenv = SVALL; /* see the walls */
331 } else
332 next[zy][zx] = COULD_SEE;
337 in_door = levl[u.ux][u.uy].typ == DOOR;
339 /* Can always see adjacent. */
340 ylo = max(u.uy - 1, 0);
341 yhi = min(u.uy + 1, ROWNO - 1);
342 xlo = max(u.ux - 1, 1);
343 xhi = min(u.ux + 1, COLNO - 1);
344 for (zy = ylo; zy <= yhi; zy++) {
345 if (xlo < rmin[zy])
346 rmin[zy] = xlo;
347 if (xhi > rmax[zy])
348 rmax[zy] = xhi;
350 for (zx = xlo; zx <= xhi; zx++) {
351 next[zy][zx] = COULD_SEE | IN_SIGHT;
353 * Yuck, update adjacent non-diagonal positions when in a doorway.
354 * We need to do this to catch the case when we first step into
355 * a room. The room's walls were not seen from the outside, but
356 * now are seen (the seen bits are set just above). However, the
357 * positions are not updated because they were already in sight.
358 * So, we have to do it here.
360 if (in_door && (zx == u.ux || zy == u.uy))
361 newsym(zx, zy);
366 /*#define EXTEND_SPINE*/ /* possibly better looking wall-angle */
368 #ifdef EXTEND_SPINE
370 staticfn int new_angle(struct rm *, unsigned char *, int, int);
372 * new_angle()
374 * Return the new angle seen by the hero for this location. The angle
375 * bit is given in the value pointed at by sv.
377 * For T walls and crosswall, just setting the angle bit, even though
378 * it is technically correct, doesn't look good. If we can see the
379 * next position beyond the current one and it is a wall that we can
380 * see, then we want to extend a spine of the T to connect with the wall
381 * that is beyond. Example:
383 * Correct, but ugly Extend T spine
385 * | ... | ...
386 * | ... <-- wall beyond & floor --> | ...
387 * | ... | ...
388 * Unseen --> ... | ...
389 * spine +-... <-- trwall & doorway --> +-...
390 * | ... | ...
393 * @ <-- hero --> @
396 * We fake the above check by only checking if the horizontal
397 * & vertical positions adjacent to the crosswall and T wall are
398 * unblocked. Then, _in general_ we can see beyond. Generally,
399 * this is good enough.
401 * + When this function is called we don't have all of the seen
402 * information (we're doing a top down scan in vision_recalc).
403 * We would need to scan once to set all IN_SIGHT and COULD_SEE
404 * bits, then again to correctly set the seenv bits.
405 * + I'm trying to make this as cheap as possible. The display
406 * & vision eat up too much CPU time.
409 * Note: Even as I write this, I'm still not convinced. There are too
410 * many exceptions. I may have to bite the bullet and do more
411 * checks. - Dean 2/11/93
413 staticfn int
414 new_angle(struct rm *lev, unsigned char *sv, int row, int col)
416 int res = *sv;
419 * Do extra checks for crosswalls and T walls if we see them from
420 * an angle.
422 if (lev->typ >= CROSSWALL && lev->typ <= TRWALL) {
423 switch (res) {
424 case SV0:
425 if (col > 0 && viz_clear[row][col - 1])
426 res |= SV7;
427 if (row > 0 && viz_clear[row - 1][col])
428 res |= SV1;
429 break;
430 case SV2:
431 if (row > 0 && viz_clear[row - 1][col])
432 res |= SV1;
433 if (col < COLNO - 1 && viz_clear[row][col + 1])
434 res |= SV3;
435 break;
436 case SV4:
437 if (col < COLNO - 1 && viz_clear[row][col + 1])
438 res |= SV3;
439 if (row < ROWNO - 1 && viz_clear[row + 1][col])
440 res |= SV5;
441 break;
442 case SV6:
443 if (row < ROWNO - 1 && viz_clear[row + 1][col])
444 res |= SV5;
445 if (col > 0 && viz_clear[row][col - 1])
446 res |= SV7;
447 break;
450 return res;
452 #else
454 * new_angle()
456 * Return the new angle seen by the hero for this location. The angle
457 * bit is given in the value pointed at by sv.
459 * The other parameters are not used.
461 #define new_angle(lev, sv, row, col) (*sv)
463 #endif
466 * vision_recalc()
468 * Do all of the heavy vision work. Recalculate all locations that could
469 * possibly be seen by the hero --- if the location were lit, etc. Note
470 * which locations are actually seen because of lighting. Then add to
471 * this all locations that be seen by hero due to night vision and x-ray
472 * vision. Finally, compare with what the hero was able to see previously.
473 * Update the difference.
475 * This function is usually called only when the variable 'vision_full_recalc'
476 * is set. The following is a list of places where this function is called,
477 * with three valid values for the control flag parameter:
479 * Control flag = 0. A complete vision recalculation. Generate the vision
480 * tables from scratch. This is necessary to correctly set what the hero
481 * can see. (1) and (2) call this routine for synchronization purposes, (3)
482 * calls this routine so it can operate correctly.
484 * + After the monster move, before input from the player. [moveloop()]
485 * + At end of moveloop. [moveloop() ??? not sure why this is here]
486 * + Right before something is printed. [pline()]
487 * + Right before we do a vision-based operation. [do_clear_area()]
488 * + screen redraw, so we can renew all positions in sight. [docrt()]
489 * + When toggling temporary blindness, in case additional events
490 * impacted by vision occur during the same move [make_blinded()]
492 * Control flag = 1. An adjacent vision recalculation. The hero has moved
493 * one square. Knowing this, it might be possible to optimize the vision
494 * recalculation using the current knowledge. This is presently unimplemented
495 * and is treated as a control = 0 call.
497 * + Right after the hero moves. [domove()]
499 * Control flag = 2. Turn off the vision system. Nothing new will be
500 * displayed, since nothing is seen. This is usually done when you need
501 * a newsym() run on all locations in sight, or on some locations but you
502 * don't know which ones.
504 * + Before a screen redraw, so all positions are renewed. [docrt()]
505 * + Right before the hero arrives on a new level. [goto_level()]
506 * + Right after a scroll of light is read. [litroom()]
507 * + After an option has changed that affects vision [parseoptions()]
508 * + Right after the hero is swallowed. [gulpmu()]
509 * + Just before bubbles are moved. [movebubbles()]
511 void
512 vision_recalc(int control)
514 extern const seenV seenv_matrix[3][3]; /* from display.c */
515 static coordxy colbump[COLNO + 1]; /* cols to bump sv */
516 seenV **temp_array; /* points to the old vision array */
517 seenV **next_array; /* points to the new vision array */
518 seenV *next_row; /* row pointer for the new array */
519 seenV *old_row; /* row pointer for the old array */
520 coordxy *next_rmin; /* min pointer for the new array */
521 coordxy *next_rmax; /* max pointer for the new array */
522 const coordxy *ranges; /* circle ranges -- used for xray & night vision */
523 int row = 0; /* row counter (outer loop) */
524 int start, stop; /* inner loop starting/stopping index */
525 int dx, dy; /* one step from a lit door or lit wall (see below) */
526 int col; /* inner loop counter */
527 struct rm *lev; /* pointer to current pos */
528 struct rm *flev; /* pointer to position in "front" of current pos */
529 const seenV *sv; /* ptr to seen angle bits */
530 int oldseenv; /* previous seenv value */
532 gv.vision_full_recalc = 0; /* reset flag */
533 if (gi.in_mklev || program_state.in_getlev || !iflags.vision_inited)
534 return;
537 * Either the light sources have been taken care of, or we must
538 * recalculate them here.
541 /* Get the unused could see, row min, and row max arrays. */
542 get_unused_cs(&next_array, &next_rmin, &next_rmax);
544 /* You see nothing, nothing can see you --- if swallowed or refreshing. */
545 if (u.uswallow || control == 2) {
546 /* do nothing -- get_unused_cs() nulls out the new work area */
548 } else if (Blind) {
550 * Calculate the could_see array even when blind so that monsters
551 * can see you, even if you can't see them. Note that the current
552 * setup allows:
554 * + Monsters to see with the "new" vision, even on the rogue
555 * level.
556 * + Monsters can see you even when you're in a pit.
558 view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0,
559 (void (*)(coordxy, coordxy, genericptr_t)) 0,
560 (genericptr_t) 0);
563 * Our own version of the update loop below. We know we can't see
564 * anything, so we only need update positions we used to be able
565 * to see.
567 temp_array = gv.viz_array; /* set gv.viz_array so newsym() will work */
568 gv.viz_array = next_array;
570 for (row = 0; row < ROWNO; row++) {
571 old_row = temp_array[row];
573 /* Find the min and max positions on the row. */
574 start = min(gv.viz_rmin[row], next_rmin[row]);
575 stop = max(gv.viz_rmax[row], next_rmax[row]);
577 for (col = start; col <= stop; col++)
578 if (old_row[col] & IN_SIGHT)
579 newsym(col, row);
582 /* skip the normal update loop */
583 goto skip;
584 } else if (Is_rogue_level(&u.uz)) {
585 rogue_vision(next_array, next_rmin, next_rmax);
586 } else {
587 int lo_col, has_night_vision = 1; /* hero has night vision */
589 if (Underwater && !Is_waterlevel(&u.uz)) {
591 * The hero is under water. Only see surrounding locations if
592 * they are also underwater. This overrides night vision but
593 * does not override x-ray vision.
595 has_night_vision = 0;
597 lo_col = max(u.ux - 1, 1);
598 for (row = u.uy - 1; row <= u.uy + 1; row++)
599 for (col = lo_col; col <= u.ux + 1; col++) {
600 if (!isok(col, row) || !is_pool(col, row))
601 continue;
603 next_rmin[row] = min(next_rmin[row], col);
604 next_rmax[row] = max(next_rmax[row], col);
605 next_array[row][col] = IN_SIGHT | COULD_SEE;
608 /* if in a pit, just update for immediate locations */
609 } else if (u.utrap && u.utraptype == TT_PIT) {
610 for (row = u.uy - 1; row <= u.uy + 1; row++) {
611 if (row < 0)
612 continue;
613 if (row >= ROWNO)
614 break;
616 next_rmin[row] = max(1, u.ux - 1);
617 next_rmax[row] = min(COLNO - 1, u.ux + 1);
618 next_row = next_array[row];
620 for (col = next_rmin[row]; col <= next_rmax[row]; col++)
621 next_row[col] = IN_SIGHT | COULD_SEE;
623 } else
624 view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0,
625 (void (*)(coordxy, coordxy, genericptr_t)) 0,
626 (genericptr_t) 0);
629 * Set the IN_SIGHT bit for xray and night vision.
631 if (u.xray_range >= 0) {
632 if (u.xray_range) {
633 ranges = circle_ptr(u.xray_range);
635 for (row = u.uy - u.xray_range; row <= u.uy + u.xray_range;
636 row++) {
637 if (row < 0)
638 continue;
639 if (row >= ROWNO)
640 break;
641 dy = v_abs(u.uy - row);
642 next_row = next_array[row];
644 start = max(1, u.ux - ranges[dy]);
645 stop = min(COLNO - 1, u.ux + ranges[dy]);
647 for (col = start; col <= stop; col++) {
648 char old_row_val = next_row[col];
650 next_row[col] |= IN_SIGHT;
651 oldseenv = levl[col][row].seenv;
652 levl[col][row].seenv = SVALL; /* see all! */
653 /* Update if previously not in sight or new angle. */
654 if (!(old_row_val & IN_SIGHT) || oldseenv != SVALL)
655 newsym(col, row);
658 next_rmin[row] = min(start, next_rmin[row]);
659 next_rmax[row] = max(stop, next_rmax[row]);
662 } else { /* range is 0 */
663 next_array[u.uy][u.ux] |= IN_SIGHT;
664 levl[u.ux][u.uy].seenv = SVALL;
665 next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
666 next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
670 if (has_night_vision && u.xray_range < u.nv_range) {
671 if (!u.nv_range) { /* range is 0 */
672 next_array[u.uy][u.ux] |= IN_SIGHT;
673 levl[u.ux][u.uy].seenv = SVALL;
674 next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]);
675 next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]);
676 } else if (u.nv_range > 0) {
677 ranges = circle_ptr(u.nv_range);
679 for (row = u.uy - u.nv_range; row <= u.uy + u.nv_range;
680 row++) {
681 if (row < 0)
682 continue;
683 if (row >= ROWNO)
684 break;
685 dy = v_abs(u.uy - row);
686 next_row = next_array[row];
688 start = max(1, u.ux - ranges[dy]);
689 stop = min(COLNO - 1, u.ux + ranges[dy]);
691 for (col = start; col <= stop; col++)
692 if (next_row[col])
693 next_row[col] |= IN_SIGHT;
695 next_rmin[row] = min(start, next_rmin[row]);
696 next_rmax[row] = max(stop, next_rmax[row]);
702 /* Set the correct bits for all light sources. */
703 do_light_sources(next_array);
706 * Make the viz_array the new array so that cansee() will work correctly.
708 temp_array = gv.viz_array;
709 gv.viz_array = next_array;
712 * The main update loop. Here we do two things:
714 * + Set the IN_SIGHT bit for places that we could see and are lit.
715 * + Reset changed places.
717 * There is one thing that make deciding what the hero can see
718 * difficult:
720 * 1. Directional lighting. Items that block light create problems.
721 * The worst offenders are doors. Suppose a door to a lit room
722 * is closed. It is lit on one side, but not on the other. How
723 * do you know? You have to check the closest adjacent position.
724 * Even so, that is not entirely correct. But it seems close
725 * enough for now.
727 colbump[u.ux] = colbump[u.ux + 1] = 1;
728 for (row = 0; row < ROWNO; row++) {
729 dy = u.uy - row;
730 dy = sign(dy);
731 next_row = next_array[row];
732 old_row = temp_array[row];
734 /* Find the min and max positions on the row. */
735 start = min(gv.viz_rmin[row], next_rmin[row]);
736 stop = max(gv.viz_rmax[row], next_rmax[row]);
737 lev = &levl[start][row];
739 sv = &seenv_matrix[dy + 1][start < u.ux ? 0 : (start > u.ux ? 2 : 1)];
741 for (col = start; col <= stop;
742 lev += ROWNO, sv += (int) colbump[++col]) {
743 if (next_row[col] & IN_SIGHT) {
745 * We see this position because of night- or xray-vision.
747 oldseenv = lev->seenv;
748 lev->seenv |=
749 new_angle(lev, sv, row, col); /* update seen angle */
751 /* Update pos if previously not in sight or new angle. */
752 if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
753 newsym(col, row);
755 } else if ((next_row[col] & COULD_SEE)
756 && (lev->lit || (next_row[col] & TEMP_LIT))) {
758 * We see this position because it is lit.
760 if ((IS_DOOR(lev->typ) || lev->typ == SDOOR
761 || IS_WALL(lev->typ)) && !viz_clear[row][col]) {
763 * Make sure doors, walls, boulders or mimics don't show
764 * up
765 * at the end of dark hallways. We do this by checking
766 * the adjacent position. If it is lit, then we can see
767 * the door or wall, otherwise we can't.
769 dx = u.ux - col;
770 dx = sign(dx);
771 flev = &(levl[col + dx][row + dy]);
772 if (flev->lit
773 || next_array[row + dy][col + dx] & TEMP_LIT) {
774 next_row[col] |= IN_SIGHT; /* we see it */
776 oldseenv = lev->seenv;
777 lev->seenv |= new_angle(lev, sv, row, col);
779 /* Update pos if previously not in sight or new
780 * angle.*/
781 if (!(old_row[col] & IN_SIGHT)
782 || oldseenv != lev->seenv)
783 newsym(col, row);
784 } else
785 goto not_in_sight; /* we don't see it */
787 } else {
788 next_row[col] |= IN_SIGHT; /* we see it */
790 oldseenv = lev->seenv;
791 lev->seenv |= new_angle(lev, sv, row, col);
793 /* Update pos if previously not in sight or new angle. */
794 if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
795 newsym(col, row);
797 } else if ((next_row[col] & COULD_SEE) && lev->waslit) {
799 * If we make it here, the hero _could see_ the location,
800 * but doesn't see it (location is not lit).
801 * However, the hero _remembers_ it as lit (waslit is true).
802 * The hero can now see that it is not lit, so change waslit
803 * and update the location.
805 lev->waslit = 0; /* remember lit condition */
806 newsym(col, row);
809 * At this point we know that the row position is *not* in normal
810 * sight. That is, the position could be seen, but is dark
811 * or LOS is just plain blocked.
813 * Update the position if:
814 * o If the old one *was* in sight. We may need to clean up
815 * the glyph -- E.g. darken room spot, etc.
816 * o If we now could see the location (yet the location is not
817 * lit), but previously we couldn't see the location, or vice
818 * versa. Update the spot because there may be an
819 * infrared monster there.
821 } else {
822 not_in_sight:
823 if ((old_row[col] & IN_SIGHT)
824 || ((next_row[col] & COULD_SEE)
825 ^ (old_row[col] & COULD_SEE)))
826 newsym(col, row);
829 } /* end for col . . */
830 } /* end for row . . */
831 colbump[u.ux] = colbump[u.ux + 1] = 0;
833 skip:
834 /* This newsym() caused a crash delivering msg about failure to open
835 * dungeon file init_dungeons() -> panic() -> done(11) ->
836 * vision_recalc(2) -> newsym() -> crash! u.ux and u.uy are 0 and
837 * program_state.panicking == 1 under those circumstances
839 if (!program_state.panicking)
840 newsym(u.ux, u.uy); /* Make sure the hero shows up! */
842 /* Set the new min and max pointers. */
843 gv.viz_rmin = next_rmin;
844 gv.viz_rmax = next_rmax;
846 notice_all_mons(TRUE);
850 * block_point()
852 * Make the location opaque to light.
854 void
855 block_point(int x, int y)
857 #ifdef DEBUG
858 /* set DEBUGFILES=seethru in environment to see through clouds & water */
859 if (gs.seethru == 0) { /* init once */
860 gs.seethru = (wizard && explicitdebug("seethru")) ? 1 : -1;
862 if (gs.seethru == 1) {
863 if (!does_block(x, y, &levl[x][y]))
864 return;
866 #endif
868 fill_point(y, x);
870 /* recalc light sources here? */
873 * We have to do a full vision recalculation if we "could see" the
874 * location. Why? Suppose some monster opened a way so that the
875 * hero could see a lit room. However, the position of the opening
876 * was out of night-vision range of the hero. Suddenly the hero should
877 * see the lit room.
879 if (gv.viz_array[y][x])
880 gv.vision_full_recalc = 1;
884 * unblock_point()
886 * Make the location transparent to light.
888 void
889 unblock_point(int x, int y)
891 dig_point(y, x);
893 /* recalc light sources here? */
895 if (gv.viz_array[y][x])
896 gv.vision_full_recalc = 1;
899 /* recalc if point should be blocked or unblocked */
900 void
901 recalc_block_point(coordxy x, coordxy y)
903 if (does_block(x, y, &levl[x][y]))
904 block_point(x, y);
905 else
906 unblock_point(x, y);
909 /*==========================================================================* \
911 : Everything below this line uses (y,x) instead of (x,y) --- the :
912 : algorithms are faster if they are less recursive and can scan :
913 : on a row longer. :
915 \*==========================================================================*/
917 /* ======================================================================= *\
918 Left and Right Pointer Updates
919 \* ======================================================================= */
922 * LEFT and RIGHT pointer rules
925 * **NOTE** The rules changed on 4/4/90. This comment reflects the
926 * new rules. The change was so that the stone-wall optimization
927 * would work.
929 * OK, now the tough stuff. We must maintain our left and right
930 * row pointers. The rules are as follows:
932 * Left Pointers:
933 * ______________
935 * + If you are a clear spot, your left will point to the first
936 * stone to your left. If there is none, then point the first
937 * legal position in the row (0).
939 * + If you are a blocked spot, then your left will point to the
940 * left-most blocked spot to your left that is connected to you.
941 * This means that a left-edge (a blocked spot that has an open
942 * spot on its left) will point to itself.
945 * Right Pointers:
946 * ---------------
947 * + If you are a clear spot, your right will point to the first
948 * stone to your right. If there is none, then point the last
949 * legal position in the row (COLNO-1).
951 * + If you are a blocked spot, then your right will point to the
952 * right-most blocked spot to your right that is connected to you.
953 * This means that a right-edge (a blocked spot that has an open
954 * spot on its right) will point to itself.
956 staticfn void
957 dig_point(int row, int col)
959 int i;
961 if (viz_clear[row][col])
962 return; /* already done */
964 viz_clear[row][col] = 1;
967 * Boundary cases first.
969 if (col == 0) { /* left edge */
970 if (viz_clear[row][1]) {
971 right_ptrs[row][0] = right_ptrs[row][1];
972 } else {
973 right_ptrs[row][0] = 1;
974 for (i = 1; i <= right_ptrs[row][1]; i++)
975 left_ptrs[row][i] = 1;
977 } else if (col == (COLNO - 1)) { /* right edge */
979 if (viz_clear[row][COLNO - 2]) {
980 left_ptrs[row][COLNO - 1] = left_ptrs[row][COLNO - 2];
981 } else {
982 left_ptrs[row][COLNO - 1] = COLNO - 2;
983 for (i = left_ptrs[row][COLNO - 2]; i < COLNO - 1; i++)
984 right_ptrs[row][i] = COLNO - 2;
988 * At this point, we know we aren't on the boundaries.
990 } else if (viz_clear[row][col - 1] && viz_clear[row][col + 1]) {
991 /* Both sides clear */
992 for (i = left_ptrs[row][col - 1]; i <= col; i++) {
993 if (!viz_clear[row][i])
994 continue; /* catch non-end case */
995 right_ptrs[row][i] = right_ptrs[row][col + 1];
997 for (i = col; i <= right_ptrs[row][col + 1]; i++) {
998 if (!viz_clear[row][i])
999 continue; /* catch non-end case */
1000 left_ptrs[row][i] = left_ptrs[row][col - 1];
1003 } else if (viz_clear[row][col - 1]) {
1004 /* Left side clear, right side blocked. */
1005 for (i = col + 1; i <= right_ptrs[row][col + 1]; i++)
1006 left_ptrs[row][i] = col + 1;
1008 for (i = left_ptrs[row][col - 1]; i <= col; i++) {
1009 if (!viz_clear[row][i])
1010 continue; /* catch non-end case */
1011 right_ptrs[row][i] = col + 1;
1013 left_ptrs[row][col] = left_ptrs[row][col - 1];
1015 } else if (viz_clear[row][col + 1]) {
1016 /* Right side clear, left side blocked. */
1017 for (i = left_ptrs[row][col - 1]; i < col; i++)
1018 right_ptrs[row][i] = col - 1;
1020 for (i = col; i <= right_ptrs[row][col + 1]; i++) {
1021 if (!viz_clear[row][i])
1022 continue; /* catch non-end case */
1023 left_ptrs[row][i] = col - 1;
1025 right_ptrs[row][col] = right_ptrs[row][col + 1];
1027 } else {
1028 /* Both sides blocked */
1029 for (i = left_ptrs[row][col - 1]; i < col; i++)
1030 right_ptrs[row][i] = col - 1;
1032 for (i = col + 1; i <= right_ptrs[row][col + 1]; i++)
1033 left_ptrs[row][i] = col + 1;
1035 left_ptrs[row][col] = col - 1;
1036 right_ptrs[row][col] = col + 1;
1040 staticfn void
1041 fill_point(int row, int col)
1043 int i;
1045 if (!viz_clear[row][col])
1046 return;
1048 viz_clear[row][col] = 0;
1050 if (col == 0) {
1051 if (viz_clear[row][1]) { /* adjacent is clear */
1052 right_ptrs[row][0] = 0;
1053 } else {
1054 right_ptrs[row][0] = right_ptrs[row][1];
1055 for (i = 1; i <= right_ptrs[row][1]; i++)
1056 left_ptrs[row][i] = 0;
1058 } else if (col == COLNO - 1) {
1059 if (viz_clear[row][COLNO - 2]) { /* adjacent is clear */
1060 left_ptrs[row][COLNO - 1] = COLNO - 1;
1061 } else {
1062 left_ptrs[row][COLNO - 1] = left_ptrs[row][COLNO - 2];
1063 for (i = left_ptrs[row][COLNO - 2]; i < COLNO - 1; i++)
1064 right_ptrs[row][i] = COLNO - 1;
1068 * Else we know that we are not on an edge.
1070 } else if (viz_clear[row][col - 1] && viz_clear[row][col + 1]) {
1071 /* Both sides clear */
1072 for (i = left_ptrs[row][col - 1] + 1; i <= col; i++)
1073 right_ptrs[row][i] = col;
1075 if (!left_ptrs[row][col - 1]) /* catch the end case */
1076 right_ptrs[row][0] = col;
1078 for (i = col; i < right_ptrs[row][col + 1]; i++)
1079 left_ptrs[row][i] = col;
1081 if (right_ptrs[row][col + 1] == COLNO - 1) /* catch the end case */
1082 left_ptrs[row][COLNO - 1] = col;
1084 } else if (viz_clear[row][col - 1]) {
1085 /* Left side clear, right side blocked. */
1086 for (i = col; i <= right_ptrs[row][col + 1]; i++)
1087 left_ptrs[row][i] = col;
1089 for (i = left_ptrs[row][col - 1] + 1; i < col; i++)
1090 right_ptrs[row][i] = col;
1092 if (!left_ptrs[row][col - 1]) /* catch the end case */
1093 right_ptrs[row][i] = col;
1095 right_ptrs[row][col] = right_ptrs[row][col + 1];
1097 } else if (viz_clear[row][col + 1]) {
1098 /* Right side clear, left side blocked. */
1099 for (i = left_ptrs[row][col - 1]; i <= col; i++)
1100 right_ptrs[row][i] = col;
1102 for (i = col + 1; i < right_ptrs[row][col + 1]; i++)
1103 left_ptrs[row][i] = col;
1105 if (right_ptrs[row][col + 1] == COLNO - 1) /* catch the end case */
1106 left_ptrs[row][i] = col;
1108 left_ptrs[row][col] = left_ptrs[row][col - 1];
1110 } else {
1111 /* Both sides blocked */
1112 for (i = left_ptrs[row][col - 1]; i <= col; i++)
1113 right_ptrs[row][i] = right_ptrs[row][col + 1];
1115 for (i = col; i <= right_ptrs[row][col + 1]; i++)
1116 left_ptrs[row][i] = left_ptrs[row][col - 1];
1120 /*==========================================================================*/
1121 /*==========================================================================*/
1124 * Variables local to Algorithm C.
1126 static int start_row;
1127 static int start_col;
1128 static int step;
1129 static seenV **cs_rows;
1130 static coordxy *cs_left;
1131 static coordxy *cs_right;
1133 static void (*vis_func)(coordxy, coordxy, genericptr_t);
1134 static genericptr_t varg;
1137 * Algorithm C uses the following macros:
1139 * good_row(z) - Return TRUE if the argument is a legal row.
1140 * set_cs(rowp,col) - Set the local could see array.
1141 * set_min(z) - Save the min value of the argument and the current
1142 * row minimum.
1143 * set_max(z) - Save the max value of the argument and the current
1144 * row maximum.
1146 * The last three macros depend on having local pointers row_min, row_max,
1147 * and rowp being set correctly.
1149 * The assertions are included to pacify a static source code analyzer.
1150 * Compile with NDEBUG defined to suppress them.
1152 #define is_clear(row, col) viz_clear_rows[row][col]
1153 #define good_row(z) ((z) >= 0 && (z) < ROWNO)
1154 #define set_cs(rowp, col) \
1155 do { \
1156 assert(rowp != NULL); \
1157 rowp[col] = COULD_SEE; \
1158 } while (0)
1159 #define set_min(z) \
1160 do { \
1161 assert(row_min != NULL); \
1162 if (*row_min > (z)) \
1163 *row_min = (z); \
1164 } while (0)
1165 #define set_max(z) \
1166 do { \
1167 assert(row_max != NULL); \
1168 if (*row_max < (z)) \
1169 *row_max = (z); \
1170 } while (0)
1173 * clear_path() expanded into 4 macros/functions:
1175 * q1_path()
1176 * q2_path()
1177 * q3_path()
1178 * q4_path()
1180 * "Draw" a line from the start to the given location. Stop if we hit
1181 * something that blocks light. The start and finish points themselves are
1182 * not checked, just the points between them. These routines do _not_
1183 * expect to be called with the same starting and stopping point.
1185 * These routines use the generalized integer Bresenham's algorithm (fast
1186 * line drawing) for all quadrants. The algorithm was taken from _Procedural
1187 * Elements for Computer Graphics_, by David F. Rogers. McGraw-Hill, 1985.
1189 #ifdef MACRO_CPATH /* quadrant calls are macros */
1192 * When called, the result is in "result".
1193 * The first two arguments (srow,scol) are one end of the path. The next
1194 * two arguments (row,col) are the destination. The last argument is
1195 * used as a C language label. This means that it must be different
1196 * in each pair of calls.
1200 * Quadrant I (step < 0).
1202 #define q1_path(srow, scol, y2, x2, label) \
1204 int dx, dy; \
1205 int k, err, x, y, dxs, dys; \
1207 x = (scol); \
1208 y = (srow); \
1209 dx = (x2) -x; \
1210 dy = y - (y2); \
1212 result = 0; /* default to a blocked path */ \
1214 dxs = dx << 1; /* save the shifted values */ \
1215 dys = dy << 1; \
1216 if (dy > dx) { \
1217 err = dxs - dy; \
1219 for (k = dy - 1; k; k--) { \
1220 if (err >= 0) { \
1221 x++; \
1222 err -= dys; \
1224 y--; \
1225 err += dxs; \
1226 if (!is_clear(y, x)) \
1227 goto label; /* blocked */ \
1229 } else { \
1230 err = dys - dx; \
1232 for (k = dx - 1; k; k--) { \
1233 if (err >= 0) { \
1234 y--; \
1235 err -= dxs; \
1237 x++; \
1238 err += dys; \
1239 if (!is_clear(y, x)) \
1240 goto label; /* blocked */ \
1244 result = 1; \
1248 * Quadrant IV (step > 0).
1250 #define q4_path(srow, scol, y2, x2, label) \
1252 int dx, dy; \
1253 int k, err, x, y, dxs, dys; \
1255 x = (scol); \
1256 y = (srow); \
1257 dx = (x2) -x; \
1258 dy = (y2) -y; \
1260 result = 0; /* default to a blocked path */ \
1262 dxs = dx << 1; /* save the shifted values */ \
1263 dys = dy << 1; \
1264 if (dy > dx) { \
1265 err = dxs - dy; \
1267 for (k = dy - 1; k; k--) { \
1268 if (err >= 0) { \
1269 x++; \
1270 err -= dys; \
1272 y++; \
1273 err += dxs; \
1274 if (!is_clear(y, x)) \
1275 goto label; /* blocked */ \
1278 } else { \
1279 err = dys - dx; \
1281 for (k = dx - 1; k; k--) { \
1282 if (err >= 0) { \
1283 y++; \
1284 err -= dxs; \
1286 x++; \
1287 err += dys; \
1288 if (!is_clear(y, x)) \
1289 goto label; /* blocked */ \
1293 result = 1; \
1297 * Quadrant II (step < 0).
1299 #define q2_path(srow, scol, y2, x2, label) \
1301 int dx, dy; \
1302 int k, err, x, y, dxs, dys; \
1304 x = (scol); \
1305 y = (srow); \
1306 dx = x - (x2); \
1307 dy = y - (y2); \
1309 result = 0; /* default to a blocked path */ \
1311 dxs = dx << 1; /* save the shifted values */ \
1312 dys = dy << 1; \
1313 if (dy > dx) { \
1314 err = dxs - dy; \
1316 for (k = dy - 1; k; k--) { \
1317 if (err >= 0) { \
1318 x--; \
1319 err -= dys; \
1321 y--; \
1322 err += dxs; \
1323 if (!is_clear(y, x)) \
1324 goto label; /* blocked */ \
1326 } else { \
1327 err = dys - dx; \
1329 for (k = dx - 1; k; k--) { \
1330 if (err >= 0) { \
1331 y--; \
1332 err -= dxs; \
1334 x--; \
1335 err += dys; \
1336 if (!is_clear(y, x)) \
1337 goto label; /* blocked */ \
1341 result = 1; \
1345 * Quadrant III (step > 0).
1347 #define q3_path(srow, scol, y2, x2, label) \
1349 int dx, dy; \
1350 int k, err, x, y, dxs, dys; \
1352 x = (scol); \
1353 y = (srow); \
1354 dx = x - (x2); \
1355 dy = (y2) -y; \
1357 result = 0; /* default to a blocked path */ \
1359 dxs = dx << 1; /* save the shifted values */ \
1360 dys = dy << 1; \
1361 if (dy > dx) { \
1362 err = dxs - dy; \
1364 for (k = dy - 1; k; k--) { \
1365 if (err >= 0) { \
1366 x--; \
1367 err -= dys; \
1369 y++; \
1370 err += dxs; \
1371 if (!is_clear(y, x)) \
1372 goto label; /* blocked */ \
1375 } else { \
1376 err = dys - dx; \
1378 for (k = dx - 1; k; k--) { \
1379 if (err >= 0) { \
1380 y++; \
1381 err -= dxs; \
1383 x--; \
1384 err += dys; \
1385 if (!is_clear(y, x)) \
1386 goto label; /* blocked */ \
1390 result = 1; \
1393 #else /* !MACRO_CPATH -- quadrants are really functions */
1395 staticfn int _q1_path(int, int, int, int);
1396 staticfn int _q2_path(int, int, int, int);
1397 staticfn int _q3_path(int, int, int, int);
1398 staticfn int _q4_path(int, int, int, int);
1400 #define q1_path(sy, sx, y, x, dummy) result = _q1_path(sy, sx, y, x)
1401 #define q2_path(sy, sx, y, x, dummy) result = _q2_path(sy, sx, y, x)
1402 #define q3_path(sy, sx, y, x, dummy) result = _q3_path(sy, sx, y, x)
1403 #define q4_path(sy, sx, y, x, dummy) result = _q4_path(sy, sx, y, x)
1406 * Quadrant I (step < 0).
1408 staticfn int
1409 _q1_path(int scol, int srow, int y2, int x2)
1411 int dx, dy;
1412 int k, err, x, y, dxs, dys;
1414 x = scol;
1415 y = srow;
1416 dx = x2 - x;
1417 dy = y - y2;
1419 dxs = dx << 1; /* save the shifted values */
1420 dys = dy << 1;
1421 if (dy > dx) {
1422 err = dxs - dy;
1424 for (k = dy - 1; k; k--) {
1425 if (err >= 0) {
1426 x++;
1427 err -= dys;
1429 y--;
1430 err += dxs;
1431 if (!is_clear(y, x))
1432 return 0; /* blocked */
1434 } else {
1435 err = dys - dx;
1437 for (k = dx - 1; k; k--) {
1438 if (err >= 0) {
1439 y--;
1440 err -= dxs;
1442 x++;
1443 err += dys;
1444 if (!is_clear(y, x))
1445 return 0; /* blocked */
1449 return 1;
1453 * Quadrant IV (step > 0).
1455 staticfn int
1456 _q4_path(int scol, int srow, int y2, int x2)
1458 int dx, dy;
1459 int k, err, x, y, dxs, dys;
1461 x = scol;
1462 y = srow;
1463 dx = x2 - x;
1464 dy = y2 - y;
1466 dxs = dx << 1; /* save the shifted values */
1467 dys = dy << 1;
1468 if (dy > dx) {
1469 err = dxs - dy;
1471 for (k = dy - 1; k; k--) {
1472 if (err >= 0) {
1473 x++;
1474 err -= dys;
1476 y++;
1477 err += dxs;
1478 if (!is_clear(y, x))
1479 return 0; /* blocked */
1481 } else {
1482 err = dys - dx;
1484 for (k = dx - 1; k; k--) {
1485 if (err >= 0) {
1486 y++;
1487 err -= dxs;
1489 x++;
1490 err += dys;
1491 if (!is_clear(y, x))
1492 return 0; /* blocked */
1496 return 1;
1500 * Quadrant II (step < 0).
1502 staticfn int
1503 _q2_path(int scol, int srow, int y2, int x2)
1505 int dx, dy;
1506 int k, err, x, y, dxs, dys;
1508 x = scol;
1509 y = srow;
1510 dx = x - x2;
1511 dy = y - y2;
1513 dxs = dx << 1; /* save the shifted values */
1514 dys = dy << 1;
1515 if (dy > dx) {
1516 err = dxs - dy;
1518 for (k = dy - 1; k; k--) {
1519 if (err >= 0) {
1520 x--;
1521 err -= dys;
1523 y--;
1524 err += dxs;
1525 if (!is_clear(y, x))
1526 return 0; /* blocked */
1528 } else {
1529 err = dys - dx;
1531 for (k = dx - 1; k; k--) {
1532 if (err >= 0) {
1533 y--;
1534 err -= dxs;
1536 x--;
1537 err += dys;
1538 if (!is_clear(y, x))
1539 return 0; /* blocked */
1543 return 1;
1547 * Quadrant III (step > 0).
1549 staticfn int
1550 _q3_path(int scol, int srow, int y2, int x2)
1552 int dx, dy;
1553 int k, err, x, y, dxs, dys;
1555 x = scol;
1556 y = srow;
1557 dx = x - x2;
1558 dy = y2 - y;
1560 dxs = dx << 1; /* save the shifted values */
1561 dys = dy << 1;
1562 if (dy > dx) {
1563 err = dxs - dy;
1565 for (k = dy - 1; k; k--) {
1566 if (err >= 0) {
1567 x--;
1568 err -= dys;
1570 y++;
1571 err += dxs;
1572 if (!is_clear(y, x))
1573 return 0; /* blocked */
1575 } else {
1576 err = dys - dx;
1578 for (k = dx - 1; k; k--) {
1579 if (err >= 0) {
1580 y++;
1581 err -= dxs;
1583 x--;
1584 err += dys;
1585 if (!is_clear(y, x))
1586 return 0; /* blocked */
1590 return 1;
1593 #endif /* ?MACRO_CPATH */
1596 * Use vision tables to determine if there is a clear path from
1597 * (col1,row1) to (col2,row2). This is used by:
1598 * m_cansee()
1599 * m_canseeu()
1600 * do_light_sources()
1602 boolean
1603 clear_path(int col1, int row1, int col2, int row2)
1605 int result;
1607 if (col1 < col2) {
1608 if (row1 > row2) {
1609 q1_path(row1, col1, row2, col2, cleardone);
1610 } else {
1611 q4_path(row1, col1, row2, col2, cleardone);
1613 } else {
1614 if (row1 > row2) {
1615 q2_path(row1, col1, row2, col2, cleardone);
1616 } else if (row1 == row2 && col1 == col2) {
1617 result = 1;
1618 } else {
1619 q3_path(row1, col1, row2, col2, cleardone);
1622 #ifdef MACRO_CPATH
1623 cleardone:
1624 #endif
1625 return (boolean) result;
1628 /*==========================================================================*\
1629 GENERAL LINE OF SIGHT
1630 Algorithm C
1631 \*==========================================================================*/
1634 * Defines local to Algorithm C.
1636 staticfn void right_side(int, int, int, const coordxy *);
1637 staticfn void left_side(int, int, int, const coordxy *);
1639 /* Initialize algorithm C (nothing). */
1640 staticfn void
1641 view_init(void)
1646 * Mark positions as visible on one quadrant of the right side. The
1647 * quadrant is determined by the value of the global variable step.
1649 * Arguments:
1650 * row current row
1651 * left first (left side) visible spot on prev row
1652 * right_mark last (right side) visible spot on prev row
1653 * limits points at range limit for current row, or NULL
1655 staticfn void
1656 right_side(
1657 int row,
1658 int left,
1659 int right_mark,
1660 const coordxy *limits)
1662 int right; /* right limit of "could see" */
1663 int right_edge; /* right edge of an opening */
1664 int nrow; /* new row (calculate once) */
1665 int deeper; /* if TRUE, call self as needed */
1666 int result; /* set by q?_path() */
1667 int i; /* loop counter */
1668 seenV *rowp = NULL; /* row optimization */
1669 coordxy *row_min = NULL; /* left most [used by macro set_min()] */
1670 coordxy *row_max = NULL; /* right most [used by macro set_max()] */
1671 int lim_max; /* right most limit of circle */
1673 nrow = row + step;
1675 * Can go deeper if the row is in bounds and the next row is within
1676 * the circle's limit. We tell the latter by checking to see if the next
1677 * limit value is the start of a new circle radius (meaning we depend
1678 * on the structure of circle_data[]).
1680 deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1)));
1681 if (!vis_func) {
1682 rowp = cs_rows[row]; /* optimization */
1683 row_min = &cs_left[row];
1684 row_max = &cs_right[row];
1686 if (limits) {
1687 lim_max = start_col + *limits;
1688 if (lim_max > COLNO - 1)
1689 lim_max = COLNO - 1;
1690 if (right_mark > lim_max)
1691 right_mark = lim_max;
1692 limits++; /* prepare for next row */
1693 } else
1694 lim_max = COLNO - 1;
1696 while (left <= right_mark) {
1697 right_edge = right_ptrs[row][left];
1698 if (right_edge > lim_max)
1699 right_edge = lim_max;
1701 if (!is_clear(row, left)) {
1703 * Jump to the far side of a stone wall. We can set all
1704 * the points in between as seen.
1706 * If the right edge goes beyond the right mark, check to see
1707 * how much we can see.
1709 if (right_edge > right_mark) {
1711 * If the mark on the previous row was a clear position,
1712 * the odds are that we can actually see part of the wall
1713 * beyond the mark on this row. If so, then see one beyond
1714 * the mark. Otherwise don't. This is a kludge so corners
1715 * with an adjacent doorway show up in nethack.
1717 right_edge = is_clear(row - step, right_mark) ? right_mark + 1
1718 : right_mark;
1720 if (vis_func) {
1721 for (i = left; i <= right_edge; i++)
1722 (*vis_func)(i, row, varg);
1723 } else {
1724 for (i = left; i <= right_edge; i++)
1725 set_cs(rowp, i);
1726 set_min(left);
1727 set_max(right_edge);
1729 left = right_edge + 1; /* no limit check necessary */
1730 continue;
1733 /* No checking needed if our left side is the start column. */
1734 if (left != start_col) {
1736 * Find the left side. Move right until we can see it or we run
1737 * into a wall.
1739 for (; left <= right_edge; left++) {
1740 if (step < 0) {
1741 q1_path(start_row, start_col, row, left, rside1);
1742 } else {
1743 q4_path(start_row, start_col, row, left, rside1);
1745 rside1: /* used if q?_path() is a macro */
1746 if (result)
1747 break;
1751 * Check for boundary conditions. We *need* check (2) to break
1752 * an infinite loop where:
1754 * left == right_edge == right_mark == lim_max.
1757 if (left > lim_max)
1758 return; /* check (1) */
1759 if (left == lim_max) { /* check (2) */
1760 if (vis_func) {
1761 (*vis_func)(lim_max, row, varg);
1762 } else {
1763 set_cs(rowp, lim_max);
1764 set_max(lim_max);
1766 return;
1769 * Check if we can see any spots in the opening. We might
1770 * (left == right_edge) or might not (left == right_edge+1) have
1771 * been able to see the far wall. Make sure we *can* see the
1772 * wall (remember, we can see the spot above/below this one)
1773 * by backing up.
1775 if (left >= right_edge) {
1776 left = right_edge; /* for the case left == right_edge+1 */
1777 continue;
1782 * Find the right side. If the marker from the previous row is
1783 * closer than the edge on this row, then we have to check
1784 * how far we can see around the corner (under the overhang). Stop
1785 * at the first non-visible spot or we actually hit the far wall.
1787 * Otherwise, we know we can see the right edge of the current row.
1789 * This must be a strict less than so that we can always see a
1790 * horizontal wall, even if it is adjacent to us.
1792 if (right_mark < right_edge) {
1793 for (right = right_mark; right <= right_edge; right++) {
1794 if (step < 0) {
1795 q1_path(start_row, start_col, row, right, rside2);
1796 } else {
1797 q4_path(start_row, start_col, row, right, rside2);
1799 rside2: /* used if q?_path() is a macro */
1800 if (!result)
1801 break;
1803 --right; /* get rid of the last increment */
1804 } else
1805 right = right_edge;
1808 * We have the range that we want. Set the bits. Note that
1809 * there is no else --- we no longer handle splinters.
1811 if (left <= right) {
1813 * An ugly special case. If you are adjacent to a vertical wall
1814 * and it has a break in it, then the right mark is set to be
1815 * start_col. We *want* to be able to see adjacent vertical
1816 * walls, so we have to set it back.
1818 if (left == right && left == start_col && start_col < (COLNO - 1)
1819 && !is_clear(row, start_col + 1))
1820 right = start_col + 1;
1822 if (right > lim_max)
1823 right = lim_max;
1824 /* set the bits */
1825 if (vis_func) {
1826 for (i = left; i <= right; i++)
1827 (*vis_func)(i, row, varg);
1828 } else {
1829 for (i = left; i <= right; i++)
1830 set_cs(rowp, i);
1831 set_min(left);
1832 set_max(right);
1835 /* recursive call for next finger of light */
1836 if (deeper)
1837 right_side(nrow, left, right, limits);
1838 left = right + 1; /* no limit check necessary */
1844 * This routine is the mirror image of right_side(). See right_side() for
1845 * extensive comments.
1847 staticfn void
1848 left_side(
1849 int row,
1850 int left_mark,
1851 int right,
1852 const coordxy *limits)
1854 int left, left_edge, nrow, deeper, result;
1855 int i;
1856 seenV *rowp = NULL;
1857 coordxy *row_min = NULL;
1858 coordxy *row_max = NULL;
1859 int lim_min;
1861 nrow = row + step;
1862 deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1)));
1863 if (!vis_func) {
1864 rowp = cs_rows[row];
1865 row_min = &cs_left[row];
1866 row_max = &cs_right[row];
1868 if (limits) {
1869 lim_min = start_col - *limits;
1870 if (lim_min < 0)
1871 lim_min = 0;
1872 if (left_mark < lim_min)
1873 left_mark = lim_min;
1874 limits++; /* prepare for next row */
1875 } else
1876 lim_min = 0;
1878 while (right >= left_mark) {
1879 left_edge = left_ptrs[row][right];
1880 if (left_edge < lim_min)
1881 left_edge = lim_min;
1883 if (!is_clear(row, right)) {
1884 /* Jump to the far side of a stone wall. */
1885 if (left_edge < left_mark) {
1886 /* Maybe see more (kludge). */
1887 left_edge = is_clear(row - step, left_mark) ? left_mark - 1
1888 : left_mark;
1890 if (vis_func) {
1891 for (i = left_edge; i <= right; i++)
1892 (*vis_func)(i, row, varg);
1893 } else {
1894 for (i = left_edge; i <= right; i++)
1895 set_cs(rowp, i);
1896 set_min(left_edge);
1897 set_max(right);
1899 right = left_edge - 1; /* no limit check necessary */
1900 continue;
1903 if (right != start_col) {
1904 /* Find the right side. */
1905 for (; right >= left_edge; right--) {
1906 if (step < 0) {
1907 q2_path(start_row, start_col, row, right, lside1);
1908 } else {
1909 q3_path(start_row, start_col, row, right, lside1);
1911 lside1: /* used if q?_path() is a macro */
1912 if (result)
1913 break;
1916 /* Check for boundary conditions. */
1917 if (right < lim_min)
1918 return;
1919 if (right == lim_min) {
1920 if (vis_func) {
1921 (*vis_func)(lim_min, row, varg);
1922 } else {
1923 set_cs(rowp, lim_min);
1924 set_min(lim_min);
1926 return;
1928 /* Check if we can see any spots in the opening. */
1929 if (right <= left_edge) {
1930 right = left_edge;
1931 continue;
1935 /* Find the left side. */
1936 if (left_mark > left_edge) {
1937 for (left = left_mark; left >= left_edge; --left) {
1938 if (step < 0) {
1939 q2_path(start_row, start_col, row, left, lside2);
1940 } else {
1941 q3_path(start_row, start_col, row, left, lside2);
1943 lside2: /* used if q?_path() is a macro */
1944 if (!result)
1945 break;
1947 left++; /* get rid of the last decrement */
1948 } else
1949 left = left_edge;
1951 if (left <= right) {
1952 /* An ugly special case. */
1953 if (left == right && right == start_col && start_col > 0
1954 && !is_clear(row, start_col - 1))
1955 left = start_col - 1;
1957 if (left < lim_min)
1958 left = lim_min;
1959 if (vis_func) {
1960 for (i = left; i <= right; i++)
1961 (*vis_func)(i, row, varg);
1962 } else {
1963 for (i = left; i <= right; i++)
1964 set_cs(rowp, i);
1965 set_min(left);
1966 set_max(right);
1969 /* Recurse */
1970 if (deeper)
1971 left_side(nrow, left, right, limits);
1972 right = left - 1; /* no limit check necessary */
1978 * Calculate all possible visible locations from the given location
1979 * (srow,scol). NOTE this is (y,x)! Mark the visible locations in the
1980 * array provided.
1982 * Arguments
1983 * srow, scol starting row and column
1984 * loc_cs_rows pointers to the rows of the could_see array
1985 * left_most min mark on each row
1986 * right_most max mark on each row
1987 * range 0 if unlimited
1988 * func function to call on each spot
1989 * arg argument for func
1991 staticfn void
1992 view_from(
1993 coordxy srow, coordxy scol,
1994 seenV **loc_cs_rows,
1995 coordxy *left_most, coordxy *right_most,
1996 int range,
1997 void (*func)(coordxy, coordxy, genericptr_t),
1998 genericptr_t arg)
2000 int i; /* loop counter */
2001 seenV *rowp; /* optimization for setting could_see */
2002 int nrow; /* the next row */
2003 int left; /* the left-most visible column */
2004 int right; /* the right-most visible column */
2005 const coordxy *limits; /* range limit for next row */
2007 /* Set globals for q?_path(), left_side(), and right_side() to use. */
2008 start_col = scol;
2009 start_row = srow;
2010 cs_rows = loc_cs_rows; /* 'could see' rows */
2011 cs_left = left_most;
2012 cs_right = right_most;
2013 vis_func = func;
2014 varg = arg;
2017 * Determine extent of sight on the starting row.
2019 if (is_clear(srow, scol)) {
2020 left = left_ptrs[srow][scol];
2021 right = right_ptrs[srow][scol];
2022 } else {
2024 * When in stone, you can only see your adjacent squares, unless
2025 * you are on an array boundary or a stone/clear boundary.
2027 left = (!scol) ? 0
2028 : (is_clear(srow, scol - 1) ? left_ptrs[srow][scol - 1]
2029 : scol - 1);
2030 right = (scol == COLNO - 1)
2031 ? COLNO - 1
2032 : (is_clear(srow, scol + 1) ? right_ptrs[srow][scol + 1]
2033 : scol + 1);
2036 if (range) {
2037 if (range > MAX_RADIUS || range < 1)
2038 panic("view_from called with range %d", range);
2039 limits = circle_ptr(range) + 1; /* start at next row */
2040 if (left < scol - range)
2041 left = scol - range;
2042 if (right > scol + range)
2043 right = scol + range;
2044 } else
2045 limits = (coordxy *) 0;
2047 if (func) {
2048 for (i = left; i <= right; i++)
2049 (*func)(i, srow, arg);
2050 } else {
2051 /* Row pointer optimization. */
2052 rowp = cs_rows[srow];
2054 /* We know that we can see our row. */
2055 for (i = left; i <= right; i++)
2056 set_cs(rowp, i);
2057 cs_left[srow] = left;
2058 cs_right[srow] = right;
2062 * Check what could be seen in quadrants. We need to check for valid
2063 * rows here, since we don't do it in the routines right_side() and
2064 * left_side() [ugliness to remove extra routine calls].
2066 if ((nrow = srow + 1) < ROWNO) { /* move down */
2067 step = 1;
2068 if (scol < COLNO - 1)
2069 right_side(nrow, scol, right, limits);
2070 if (scol)
2071 left_side(nrow, left, scol, limits);
2074 if ((nrow = srow - 1) >= 0) { /* move up */
2075 step = -1;
2076 if (scol < COLNO - 1)
2077 right_side(nrow, scol, right, limits);
2078 if (scol)
2079 left_side(nrow, left, scol, limits);
2083 /*===== End of algorithm C =====*/
2086 * AREA OF EFFECT "ENGINE"
2088 * Calculate all possible visible locations as viewed from the given location
2089 * (srow,scol) within the range specified. Perform "func" with (x, y) args and
2090 * additional argument "arg" for each square.
2092 * If not centered on the hero, just forward arguments to view_from(); it
2093 * will call "func" when necessary. If the hero is the center, use the
2094 * vision matrix and reduce extra work.
2096 void
2097 do_clear_area(
2098 coordxy scol, coordxy srow,
2099 int range,
2100 void (*func)(coordxy, coordxy, genericptr_t),
2101 genericptr_t arg)
2103 /* If not centered on hero, do the hard work of figuring the area */
2104 if (scol != u.ux || srow != u.uy) {
2105 view_from(srow, scol, (seenV **) 0, (coordxy *) 0, (coordxy *) 0,
2106 range, func, arg);
2107 } else {
2108 int x;
2109 int y, min_x, max_x, max_y, offset;
2110 const coordxy *limits;
2111 boolean override_vision;
2113 /* vision doesn't pass through water or clouds, detection should
2114 [this probably ought to be an arg supplied by our caller...] */
2115 override_vision = (detecting(func)
2116 && (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)));
2118 if (range > MAX_RADIUS || range < 1)
2119 panic("do_clear_area: illegal range %d", range);
2120 if (gv.vision_full_recalc)
2121 vision_recalc(0); /* recalc vision if dirty */
2122 limits = circle_ptr(range);
2123 if ((max_y = (srow + range)) >= ROWNO)
2124 max_y = ROWNO - 1;
2125 if ((y = (srow - range)) < 0)
2126 y = 0;
2127 for (; y <= max_y; y++) {
2128 offset = limits[v_abs(y - srow)];
2129 if ((min_x = (scol - offset)) < 1)
2130 min_x = 1;
2131 if ((max_x = (scol + offset)) >= COLNO)
2132 max_x = COLNO - 1;
2133 for (x = min_x; x <= max_x; x++)
2134 if (couldsee(x, y) || override_vision)
2135 (*func)(x, y, arg);
2140 /* bitmask indicating ways mon is seen; extracted from lookat(pager.c) */
2141 unsigned
2142 howmonseen(struct monst *mon)
2144 boolean useemon = (boolean) canseemon(mon);
2145 int xraydist = (u.xray_range < 0) ? -1 : (u.xray_range * u.xray_range);
2146 unsigned how_seen = 0; /* result */
2148 /* assert(mon != NULL) */
2149 /* normal vision;
2150 cansee is true for both normal and astral vision,
2151 but couldsee it not true for astral vision */
2152 if ((mon->wormno ? worm_known(mon) : (cansee(mon->mx, mon->my)
2153 && couldsee(mon->mx, mon->my)))
2154 && mon_visible(mon) && !mon->minvis)
2155 how_seen |= MONSEEN_NORMAL;
2156 /* see invisible */
2157 if (useemon && mon->minvis)
2158 how_seen |= MONSEEN_SEEINVIS;
2159 /* infravision */
2160 if ((!mon->minvis || See_invisible) && see_with_infrared(mon))
2161 how_seen |= MONSEEN_INFRAVIS;
2162 /* telepathy */
2163 if (tp_sensemon(mon))
2164 how_seen |= MONSEEN_TELEPAT;
2165 /* xray */
2166 if (useemon && xraydist > 0 && mdistu(mon) <= xraydist)
2167 how_seen |= MONSEEN_XRAYVIS;
2168 /* extended detection */
2169 if (Detect_monsters)
2170 how_seen |= MONSEEN_DETECT;
2171 /* class-/type-specific warning */
2172 if (MATCH_WARN_OF_MON(mon))
2173 how_seen |= MONSEEN_WARNMON;
2175 return how_seen;
2178 /*vision.c*/