1 /**
2  * \file cave-view.c
3  * \brief Line-of-sight and view calculations
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 
19 #include "angband.h"
20 #include "cave.h"
21 #include "cmds.h"
22 #include "init.h"
23 #include "monster.h"
24 #include "player-calcs.h"
25 #include "player-timed.h"
26 #include "trap.h"
27 
28 /**
29  * Approximate distance between two points.
30  *
31  * When either the X or Y component dwarfs the other component,
32  * this function is almost perfect, and otherwise, it tends to
33  * over-estimate about one grid per fifteen grids of distance.
34  *
35  * Algorithm: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2
36  */
distance(struct loc grid1,struct loc grid2)37 int distance(struct loc grid1, struct loc grid2)
38 {
39 	/* Find the absolute y/x distance components */
40 	int ay = abs(grid2.y - grid1.y);
41 	int ax = abs(grid2.x - grid1.x);
42 
43 	/* Approximate the distance */
44 	return ay > ax ? ay + (ax >> 1) : ax + (ay >> 1);
45 }
46 
47 
48 /**
49  * A simple, fast, integer-based line-of-sight algorithm.  By Joseph Hall,
50  * 4116 Brewster Drive, Raleigh NC 27606.  Email to jnh@ecemwl.ncsu.edu.
51  *
52  * This function returns true if a "line of sight" can be traced from the
53  * center of the grid (x1,y1) to the center of the grid (x2,y2), with all
54  * of the grids along this path (except for the endpoints) being non-wall
55  * grids.  Actually, the "chess knight move" situation is handled by some
56  * special case code which allows the grid diagonally next to the player
57  * to be obstructed, because this yields better gameplay semantics.  This
58  * algorithm is totally reflexive, except for "knight move" situations.
59  *
60  * Because this function uses (short) ints for all calculations, overflow
61  * may occur if dx and dy exceed 90.
62  *
63  * Once all the degenerate cases are eliminated, we determine the "slope"
64  * ("m"), and we use special "fixed point" mathematics in which we use a
65  * special "fractional component" for one of the two location components
66  * ("qy" or "qx"), which, along with the slope itself, are "scaled" by a
67  * scale factor equal to "abs(dy*dx*2)" to keep the math simple.  Then we
68  * simply travel from start to finish along the longer axis, starting at
69  * the border between the first and second tiles (where the y offset is
70  * thus half the slope), using slope and the fractional component to see
71  * when motion along the shorter axis is necessary.  Since we assume that
72  * vision is not blocked by "brushing" the corner of any grid, we must do
73  * some special checks to avoid testing grids which are "brushed" but not
74  * actually "entered".
75  *
76  * Angband three different "line of sight" type concepts, including this
77  * function (which is used almost nowhere), the "project()" method (which
78  * is used for determining the paths of projectables and spells and such),
79  * and the "update_view()" concept (which is used to determine which grids
80  * are "viewable" by the player, which is used for many things, such as
81  * determining which grids are illuminated by the player's torch, and which
82  * grids and monsters can be "seen" by the player, etc).
83  */
los(struct chunk * c,struct loc grid1,struct loc grid2)84 bool los(struct chunk *c, struct loc grid1, struct loc grid2)
85 {
86 	/* Delta */
87 	int dx, dy;
88 
89 	/* Absolute */
90 	int ax, ay;
91 
92 	/* Signs */
93 	int sx, sy;
94 
95 	/* Fractions */
96 	int qx, qy;
97 
98 	/* Scanners */
99 	int tx, ty;
100 
101 	/* Scale factors */
102 	int f1, f2;
103 
104 	/* Slope, or 1/Slope, of LOS */
105 	int m;
106 
107 	/* Extract the offset */
108 	dy = grid2.y - grid1.y;
109 	dx = grid2.x - grid1.x;
110 
111 	/* Extract the absolute offset */
112 	ay = ABS(dy);
113 	ax = ABS(dx);
114 
115 	/* Handle adjacent (or identical) grids */
116 	if ((ax < 2) && (ay < 2)) return (true);
117 
118 	/* Directly South/North */
119 	if (!dx) {
120 		/* South -- check for walls */
121 		if (dy > 0) {
122 			for (ty = grid1.y + 1; ty < grid2.y; ty++)
123 				if (!square_isprojectable(c, loc(grid1.x, ty))) return (false);
124 		} else { /* North -- check for walls */
125 			for (ty = grid1.y - 1; ty > grid2.y; ty--)
126 				if (!square_isprojectable(c, loc(grid1.x, ty))) return (false);
127 		}
128 
129 		/* Assume los */
130 		return (true);
131 	}
132 
133 	/* Directly East/West */
134 	if (!dy) {
135 		/* East -- check for walls */
136 		if (dx > 0) {
137 			for (tx = grid1.x + 1; tx < grid2.x; tx++)
138 				if (!square_isprojectable(c, loc(tx, grid1.y))) return (false);
139 		} else { /* West -- check for walls */
140 			for (tx = grid1.x - 1; tx > grid2.x; tx--)
141 				if (!square_isprojectable(c, loc(tx, grid1.y))) return (false);
142 		}
143 
144 		/* Assume los */
145 		return (true);
146 	}
147 
148 
149 	/* Extract some signs */
150 	sx = (dx < 0) ? -1 : 1;
151 	sy = (dy < 0) ? -1 : 1;
152 
153 	/* Vertical and horizontal "knights" */
154 	if ((ax == 1) && (ay == 2) &&
155 		square_isprojectable(c, loc(grid1.x, grid1.y + sy))) {
156 		return (true);
157 	} else if ((ay == 1) && (ax == 2) &&
158 			   square_isprojectable(c, loc(grid1.x + sx, grid1.y))) {
159 		return (true);
160 	}
161 
162 	/* Calculate scale factor div 2 */
163 	f2 = (ax * ay);
164 
165 	/* Calculate scale factor */
166 	f1 = f2 << 1;
167 
168 
169 	/* Travel horizontally */
170 	if (ax >= ay) {
171 		/* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
172 		qy = ay * ay;
173 		m = qy << 1;
174 
175 		tx = grid1.x + sx;
176 
177 		/* Consider the special case where slope == 1. */
178 		if (qy == f2) {
179 			ty = grid1.y + sy;
180 			qy -= f1;
181 		} else {
182 			ty = grid1.y;
183 		}
184 
185 		/* Note (below) the case (qy == f2), where */
186 		/* the LOS exactly meets the corner of a tile. */
187 		while (grid2.x - tx) {
188 			if (!square_isprojectable(c, loc(tx, ty)))
189 				return (false);
190 
191 			qy += m;
192 
193 			if (qy < f2) {
194 				tx += sx;
195 			} else if (qy > f2) {
196 				ty += sy;
197 				if (!square_isprojectable(c, loc(tx, ty)))
198 					return (false);
199 				qy -= f1;
200 				tx += sx;
201 			} else {
202 				ty += sy;
203 				qy -= f1;
204 				tx += sx;
205 			}
206 		}
207 	} else { /* Travel vertically */
208 		/* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
209 		qx = ax * ax;
210 		m = qx << 1;
211 
212 		ty = grid1.y + sy;
213 
214 		if (qx == f2) {
215 			tx = grid1.x + sx;
216 			qx -= f1;
217 		} else {
218 			tx = grid1.x;
219 		}
220 
221 		/* Note (below) the case (qx == f2), where */
222 		/* the LOS exactly meets the corner of a tile. */
223 		while (grid2.y - ty) {
224 			if (!square_isprojectable(c, loc(tx, ty)))
225 				return (false);
226 
227 			qx += m;
228 
229 			if (qx < f2) {
230 				ty += sy;
231 			} else if (qx > f2) {
232 				tx += sx;
233 				if (!square_isprojectable(c, loc(tx, ty)))
234 					return (false);
235 				qx -= f1;
236 				ty += sy;
237 			} else {
238 				tx += sx;
239 				qx -= f1;
240 				ty += sy;
241 			}
242 		}
243 	}
244 
245 	/* Assume los */
246 	return (true);
247 }
248 
249 /**
250  * The comments below are still predominantly true, and have been left
251  * (slightly modified for accuracy) for historical and nostalgic reasons.
252  *
253  * Some comments on the dungeon related data structures and functions...
254  *
255  * Angband is primarily a dungeon exploration game, and it should come as
256  * no surprise that the internal representation of the dungeon has evolved
257  * over time in much the same way as the game itself, to provide semantic
258  * changes to the game itself, to make the code simpler to understand, and
259  * to make the executable itself faster or more efficient in various ways.
260  *
261  * There are a variety of dungeon related data structures, and associated
262  * functions, which store information about the dungeon, and provide methods
263  * by which this information can be accessed or modified.
264  *
265  * Some of this information applies to the dungeon as a whole, such as the
266  * list of unique monsters which are still alive.  Some of this information
267  * only applies to the current dungeon level, such as the current depth, or
268  * the list of monsters currently inhabiting the level.  And some of the
269  * information only applies to a single grid of the current dungeon level,
270  * such as whether the grid is illuminated, or whether the grid contains a
271  * monster, or whether the grid can be seen by the player.  If Angband was
272  * to be turned into a multi-player game, some of the information currently
273  * associated with the dungeon should really be associated with the player,
274  * such as whether a given grid is viewable by a given player.
275  *
276  * Currently, a lot of the information about the dungeon is stored in ways
277  * that make it very efficient to access or modify the information, while
278  * still attempting to be relatively conservative about memory usage, even
279  * if this means that some information is stored in multiple places, or in
280  * ways which require the use of special code idioms.  For example, each
281  * monster record in the monster array contains the location of the monster,
282  * and each cave grid has an index into the monster array, or a zero if no
283  * monster is in the grid.  This allows the monster code to efficiently see
284  * where the monster is located, while allowing the dungeon code to quickly
285  * determine not only if a monster is present in a given grid, but also to
286  * find out which monster.  The extra space used to store the information
287  * twice is inconsequential compared to the speed increase.
288  *
289  * Several pieces of information about each cave grid are stored in the
290  * info field of the "cave->squares" array, which is a special array of
291  * bitflags.
292  *
293  * The "SQUARE_ROOM" flag is used to determine which grids are part of "rooms",
294  * and thus which grids are affected by "illumination" spells.
295  *
296  * The "SQUARE_VAULT" flag is used to determine which grids are part of
297  * "vaults", and thus which grids cannot serve as the destinations of player
298  * teleportation.
299  *
300  * The "SQUARE_GLOW" flag is used to determine which grids are "permanently
301  * illuminated".  This flag is used by the update_view() function to help
302  * determine which viewable flags may be "seen" by the player.  This flag
303  * is used by the "map_info" function to determine if a grid is only lit by
304  * the player's torch.  This flag has special semantics for wall grids
305  * (see "update_view()").
306  *
307  * The "SQUARE_VIEW" flag is used to determine which grids are currently in
308  * line of sight of the player.  This flag is set by (and used by) the
309  * "update_view()" function.  This flag is used by any code which needs to
310  * know if the player can "view" a given grid.  This flag is used by the
311  * "map_info()" function for some optional special lighting effects.  The
312  * "player_has_los_bold()" macro wraps an abstraction around this flag, but
313  * certain code idioms are much more efficient.  This flag is used to check
314  * if a modification to a terrain feature might affect the player's field of
315  * view.  This flag is used to see if certain monsters are "visible" to the
316  * player.  This flag is used to allow any monster in the player's field of
317  * view to "sense" the presence of the player.
318  *
319  * The "SQUARE_SEEN" flag is used to determine which grids are currently in
320  * line of sight of the player and also illuminated in some way.  This flag
321  * is set by the "update_view()" function, using computations based on the
322  * "SQUARE_VIEW" and "SQUARE_GLOW" flags and terrain of various grids.
323  * This flag is used by any code which needs to know if the player can "see" a
324  * given grid.  This flag is used by the "map_info()" function both to see
325  * if a given "boring" grid can be seen by the player, and for some optional
326  * special lighting effects.  The "player_can_see_bold()" macro wraps an
327  * abstraction around this flag, but certain code idioms are much more
328  * efficient.  This flag is used to see if certain monsters are "visible" to
329  * the player.  This flag is never set for a grid unless "SQUARE_VIEW" is also
330  * set for the grid.  Whenever the terrain or "SQUARE_GLOW" flag changes
331  * for a grid which has the "SQUARE_VIEW" flag set, the "SQUARE_SEEN" flag must
332  * be recalculated.  The simplest way to do this is to call "forget_view()"
333  * and "update_view()" whenever the terrain or "SQUARE_GLOW" flag changes
334  * for a grid which has "SQUARE_VIEW" set.
335  *
336  * The "SQUARE_WASSEEN" flag is used for a variety of temporary purposes.  This
337  * flag is used to determine if the "SQUARE_SEEN" flag for a grid has changed
338  * during the "update_view()" function.  This flag is used to "spread" light
339  * or darkness through a room.  This flag is used by the "monster flow code".
340  * This flag must always be cleared by any code which sets it.
341  *
342  * The "update_view()" function is an extremely important function.  It is
343  * called only when the player moves, significant terrain changes, or the
344  * player's blindness or torch radius changes.  Note that when the player
345  * is resting, or performing any repeated actions (like digging, disarming,
346  * farming, etc), there is no need to call the "update_view()" function, so
347  * even if it was not very efficient, this would really only matter when the
348  * player was "running" through the dungeon.  It sets the "SQUARE_VIEW" flag
349  * on every cave grid in the player's field of view.  It also checks the torch
350  * radius of the player, and sets the "SQUARE_SEEN" flag for every grid which
351  * is in the "field of view" of the player and which is also "illuminated",
352  * either by the players torch (if any) or by any permanent light source.
353  * It could use and help maintain information about multiple light sources,
354  * which would be helpful in a multi-player version of Angband.
355  *
356  * Note that the "update_view()" function allows, among other things, a room
357  * to be "partially" seen as the player approaches it, with a growing cone
358  * of floor appearing as the player gets closer to the door.  Also, by not
359  * turning on the "memorize perma-lit grids" option, the player will only
360  * "see" those floor grids which are actually in line of sight.  And best
361  * of all, you can now activate the special lighting effects to indicate
362  * which grids are actually in the player's field of view by using dimmer
363  * colors for grids which are not in the player's field of view, and/or to
364  * indicate which grids are illuminated only by the player's torch by using
365  * the color yellow for those grids.
366  *
367  * It seems as though slight modifications to the "update_view()" functions
368  * would allow us to determine "reverse" line-of-sight as well as "normal"
369  * line-of-sight", which would allow monsters to have a more "correct" way
370  * to determine if they can "see" the player, since right now, they "cheat"
371  * somewhat and assume that if the player has "line of sight" to them, then
372  * they can "pretend" that they have "line of sight" to the player.  But if
373  * such a change was attempted, the monsters would actually start to exhibit
374  * some undesirable behavior, such as "freezing" near the entrances to long
375  * hallways containing the player, and code would have to be added to make
376  * the monsters move around even if the player was not detectable, and to
377  * "remember" where the player was last seen, to avoid looking stupid.
378  *
379  * Note that the "SQUARE_GLOW" flag means that a grid is permanently lit in
380  * some way.  However, for the player to "see" the grid, as determined by
381  * the "SQUARE_SEEN" flag, the player must not be blind, the grid must have
382  * the "SQUARE_VIEW" flag set, and if the grid is a "wall" grid, and it is
383  * not lit by the player's torch, then it must touch a projectable grid
384  * which has both the "SQUARE_GLOW"
385  * and "SQUARE_VIEW" flags set.  This last part about wall grids is induced
386  * by the semantics of "SQUARE_GLOW" as applied to wall grids, and checking
387  * the technical requirements can be very expensive, especially since the
388  * grid may be touching some "illegal" grids.  Luckily, it is more or less
389  * correct to restrict the "touching" grids from the eight "possible" grids
390  * to the (at most) three grids which are touching the grid, and which are
391  * closer to the player than the grid itself, which eliminates more than
392  * half of the work, including all of the potentially "illegal" grids, if
393  * at most one of the three grids is a "diagonal" grid.  In addition, in
394  * almost every situation, it is possible to ignore the "SQUARE_VIEW" flag
395  * on these three "touching" grids, for a variety of technical reasons.
396  * Finally, note that in most situations, it is only necessary to check
397  * a single "touching" grid, in fact, the grid which is strictly closest
398  * to the player of all the touching grids, and in fact, it is normally
399  * only necessary to check the "SQUARE_GLOW" flag of that grid, again, for
400  * various technical reasons.  However, one of the situations which does
401  * not work with this last reduction is the very common one in which the
402  * player approaches an illuminated room from a dark hallway, in which the
403  * two wall grids which form the "entrance" to the room would not be marked
404  * as "SQUARE_SEEN", since of the three "touching" grids nearer to the player
405  * than each wall grid, only the farthest of these grids is itself marked
406  * "SQUARE_GLOW".
407  *
408  *
409  * Here are some pictures of the legal "light source" radius values, in
410  * which the numbers indicate the "order" in which the grids could have
411  * been calculated, if desired.  Note that the code will work with larger
412  * radiuses, though currently yields such a radius, and the game would
413  * become slower in some situations if it did.
414  *
415  *       Rad=0     Rad=1      Rad=2        Rad=3
416  *      No-Light Torch,etc   Lantern     Artifacts
417  *
418  *                                          333
419  *                             333         43334
420  *                  212       32123       3321233
421  *         @        1@1       31@13       331@133
422  *                  212       32123       3321233
423  *                             333         43334
424  *                                          333
425  *
426  */
427 
428 
429 /**
430  * Mark the currently seen grids, then wipe in preparation for recalculating
431  */
mark_wasseen(struct chunk * c)432 static void mark_wasseen(struct chunk *c)
433 {
434 	int x, y;
435 	/* Save the old "view" grids for later */
436 	for (y = 0; y < c->height; y++) {
437 		for (x = 0; x < c->width; x++) {
438 			struct loc grid = loc(x, y);
439 			if (square_isseen(c, grid))
440 				sqinfo_on(square(c, grid)->info, SQUARE_WASSEEN);
441 			sqinfo_off(square(c, grid)->info, SQUARE_VIEW);
442 			sqinfo_off(square(c, grid)->info, SQUARE_SEEN);
443 		}
444 	}
445 }
446 
447 /**
448  * Calculate light level for every grid in view - stolen from Sil
449  */
calc_lighting(struct chunk * c,struct player * p)450 static void calc_lighting(struct chunk *c, struct player *p)
451 {
452 	int dir, k, x, y;
453 	int light = p->state.cur_light, radius = ABS(light) - 1;
454 	int old_light = square_light(c, p->grid);
455 
456 	/* Starting values based on permanent light */
457 	for (y = 0; y < c->height; y++) {
458 		for (x = 0; x < c->width; x++) {
459 			struct loc grid = loc(x, y);
460 			c->squares[y][x].light = square_isglow(c, grid) ? 1 : 0;
461 
462 			/* Squares with bright terrain have intensity 2 */
463 			if (square_isbright(c, grid)) {
464 				c->squares[y][x].light += 2;
465 				for (dir = 0; dir < 8; dir++) {
466 					struct loc adj_grid = loc_sum(grid, ddgrid_ddd[dir]);
467 					if (!square_in_bounds(c, adj_grid)) continue;
468 					c->squares[adj_grid.y][adj_grid.x].light += 1;
469 				}
470 			}
471 		}
472 	}
473 
474 	/* Light around the player */
475 	for (y = -radius; y <= radius; y++) {
476 		for (x = -radius; x <= radius; x++) {
477 			/* Get valid grids within the player's light effect radius */
478 			struct loc grid = loc_sum(p->grid, loc(x, y));
479 			int dist = distance(p->grid, grid);
480 			if (!square_in_bounds(c, grid)) continue;
481 			if (dist > radius) continue;
482 
483 			/* Adjust the light level */
484 			if (light > 0) {
485 				/* Light getting less further away */
486 				c->squares[grid.y][grid.x].light += light - dist;
487 			} else {
488 				/* Light getting greater further away */
489 				c->squares[grid.y][grid.x].light += light + dist;
490 			}
491 		}
492 	}
493 
494 	/* Scan monster list and add monster light or darkness */
495 	for (k = 1; k < cave_monster_max(c); k++) {
496 		/* Check the k'th monster */
497 		struct monster *mon = cave_monster(c, k);
498 
499 		/* Skip dead monsters */
500 		if (!mon->race) continue;
501 
502 		/* Get light info for this monster */
503 		light = mon->race->light;
504 		radius = ABS(light) - 1;
505 
506 		/* Skip monsters not affecting light */
507 		if (!light) continue;
508 
509 		/* Light or darken around the monster */
510 		for (y = -radius; y <= radius; y++) {
511 			for (x = -radius; x <= radius; x++) {
512 				/* Get valid grids within the monster's light effect radius */
513 				struct loc grid = loc_sum(mon->grid, loc(x, y));
514 				int dist = distance(mon->grid, grid);
515 				if (!square_in_bounds(c, grid)) continue;
516 				if (dist > radius) continue;
517 
518 				/* Only set it if the player can see it */
519 				if (distance(p->grid, grid) > z_info->max_sight) continue;
520 
521 				/* Adjust the light level */
522 				if (light > 0) {
523 					/* Light getting less further away */
524 					c->squares[grid.y][grid.x].light += light - dist;
525 				} else {
526 					/* Light getting greater further away */
527 					c->squares[grid.y][grid.x].light += light + dist;
528 				}
529 			}
530 		}
531 	}
532 
533 	/* Update light level indicator */
534 	if (square_light(c, p->grid) != old_light) {
535 		p->upkeep->redraw |= PR_LIGHT;
536 	}
537 }
538 
539 /**
540  * Make a square part of the current view
541  */
become_viewable(struct chunk * c,struct loc grid,struct player * p,bool close)542 static void become_viewable(struct chunk *c, struct loc grid, struct player *p,
543 							bool close)
544 {
545 	int x = grid.x;
546 	int y = grid.y;
547 
548 	/* Already viewable, nothing to do */
549 	if (square_isview(c, grid)) return;
550 
551 	/* Add the grid to the view, make seen if it's close enough to the player */
552 	sqinfo_on(square(c, grid)->info, SQUARE_VIEW);
553 	if (close)
554 		sqinfo_on(square(c, grid)->info, SQUARE_SEEN);
555 
556 	/* Mark lit grids, and walls near to them, as seen */
557 	if (square_islit(c, grid)) {
558 		if (square_iswall(c, grid)) {
559 			/* For walls, check for a lit grid closer to the player */
560 			int xc = (x < p->grid.x) ? (x + 1) : (x > p->grid.x) ? (x - 1) : x;
561 			int yc = (y < p->grid.y) ? (y + 1) : (y > p->grid.y) ? (y - 1) : y;
562 			if (square_islit(c, loc(xc, yc))) {
563 				sqinfo_on(square(c, grid)->info, SQUARE_SEEN);
564 			}
565 		} else {
566 			sqinfo_on(square(c, grid)->info, SQUARE_SEEN);
567 		}
568 	}
569 }
570 
571 /**
572  * Decide whether to include a square in the current view
573  */
update_view_one(struct chunk * c,struct loc grid,struct player * p)574 static void update_view_one(struct chunk *c, struct loc grid, struct player *p)
575 {
576 	int x = grid.x;
577 	int y = grid.y;
578 	int xc = x, yc = y;
579 
580 	int d = distance(grid, p->grid);
581 	bool close = d < p->state.cur_light;
582 
583 	/* Too far away */
584 	if (d > z_info->max_sight) return;
585 
586 	/* UNLIGHT players have a special radius of view */
587 	if (player_has(p, PF_UNLIGHT) && (p->state.cur_light <= 1)) {
588 		close = d < (2 + p->lev / 6 - p->state.cur_light);
589 	}
590 
591 	/* Special case for wall lighting. If we are a wall and the square in
592 	 * the direction of the player is in LOS, we are in LOS. This avoids
593 	 * situations like:
594 	 * #1#############
595 	 * #............@#
596 	 * ###############
597 	 * where the wall cell marked '1' would not be lit because the LOS
598 	 * algorithm runs into the adjacent wall cell.
599 	 */
600 	if (square_iswall(c, grid)) {
601 		int dx = x - p->grid.x;
602 		int dy = y - p->grid.y;
603 		int ax = ABS(dx);
604 		int ay = ABS(dy);
605 		int sx = dx > 0 ? 1 : -1;
606 		int sy = dy > 0 ? 1 : -1;
607 
608 		xc = (x < p->grid.x) ? (x + 1) : (x > p->grid.x) ? (x - 1) : x;
609 		yc = (y < p->grid.y) ? (y + 1) : (y > p->grid.y) ? (y - 1) : y;
610 
611 		/* Check that the cell we're trying to steal LOS from isn't a
612 		 * wall. If we don't do this, double-thickness walls will have
613 		 * both sides visible.
614 		 */
615 		if (square_iswall(c, loc(xc, yc))) {
616 			xc = x;
617 			yc = y;
618 		}
619 
620 		/* Check if we got here via the 'knight's move' rule and, if so,
621 		 * don't steal LOS. */
622 		if (ax == 2 && ay == 1) {
623 			if (!square_iswall(c, loc(x - sx, y))
624 				&& square_iswall(c, loc(x - sx, y - sy))) {
625 				xc = x;
626 				yc = y;
627 			}
628 		} else if (ax == 1 && ay == 2) {
629 			if (!square_iswall(c, loc(x, y - sy))
630 				&& square_iswall(c, loc(x - sx, y - sy))) {
631 				xc = x;
632 				yc = y;
633 			}
634 		}
635 	}
636 
637 	if (los(c, p->grid, loc(xc, yc)))
638 		become_viewable(c, grid, p, close);
639 }
640 
641 /**
642  * Update view for a single square
643  */
update_one(struct chunk * c,struct loc grid,int blind)644 static void update_one(struct chunk *c, struct loc grid, int blind)
645 {
646 	/* Remove view if blind, check visible squares for traps */
647 	if (blind) {
648 		sqinfo_off(square(c, grid)->info, SQUARE_SEEN);
649 	} else if (square_isseen(c, grid)) {
650 		square_reveal_trap(c, grid, false, true);
651 	}
652 
653 	/* Square went from unseen -> seen */
654 	if (square_isseen(c, grid) && !square_wasseen(c, grid)) {
655 		if (square_isfeel(c, grid)) {
656 			c->feeling_squares++;
657 			sqinfo_off(square(c, grid)->info, SQUARE_FEEL);
658 			/* Don't display feeling if it will display for the new level */
659 			if ((c->feeling_squares == z_info->feeling_need) &&
660 				!player->upkeep->only_partial) {
661 				display_feeling(true);
662 				player->upkeep->redraw |= PR_FEELING;
663 			}
664 		}
665 
666 		square_note_spot(c, grid);
667 		square_light_spot(c, grid);
668 	}
669 
670 	/* Square went from seen -> unseen */
671 	if (!square_isseen(c, grid) && square_wasseen(c, grid))
672 		square_light_spot(c, grid);
673 
674 	sqinfo_off(square(c, grid)->info, SQUARE_WASSEEN);
675 }
676 
677 /**
678  * Update the player's current view
679  */
update_view(struct chunk * c,struct player * p)680 void update_view(struct chunk *c, struct player *p)
681 {
682 	int x, y;
683 
684 	/* Record the current view */
685 	mark_wasseen(c);
686 
687 	/* Assume we can view the player grid */
688 	sqinfo_on(square(c, p->grid)->info, SQUARE_VIEW);
689 	if (p->state.cur_light > 0 || square_isglow(c, p->grid) ||
690 		player_has(p, PF_UNLIGHT)) {
691 		sqinfo_on(square(c, p->grid)->info, SQUARE_SEEN);
692 	}
693 
694 	/* Calculate light levels */
695 	calc_lighting(c, p);
696 
697 	/* Squares we have LOS to get marked as in the view, and perhaps seen */
698 	for (y = 0; y < c->height; y++)
699 		for (x = 0; x < c->width; x++)
700 			update_view_one(c, loc(x, y), p);
701 
702 	/* Update each grid */
703 	for (y = 0; y < c->height; y++)
704 		for (x = 0; x < c->width; x++)
705 			update_one(c, loc(x, y), p->timed[TMD_BLIND]);
706 }
707 
708 
709 /**
710  * Returns true if the player's grid is dark
711  */
no_light(void)712 bool no_light(void)
713 {
714 	return (!square_isseen(cave, player->grid));
715 }
716