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