From c86c190d4d38be63545530eba228193619fe65d6 Mon Sep 17 00:00:00 2001 From: deskull Date: Thu, 18 Apr 2019 15:10:27 +0900 Subject: [PATCH] =?utf8?q?[Refactor]=20#37353=20forget=5Fview()=20/=20upda?= =?utf8?q?te=5Flite()=20/=20update=5Fview()=20=E3=82=92=20floor=5Fevent()?= =?utf8?q?=20=E3=81=AB=E7=A7=BB=E5=8B=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/externs.h | 3 - src/floor-events.c | 930 +++++++++++++++++++++++++++++++++++++++++++++++++ src/floor-events.h | 5 + src/grid.c | 989 ----------------------------------------------------- src/grid.h | 65 +++- 5 files changed, 992 insertions(+), 1000 deletions(-) diff --git a/src/externs.h b/src/externs.h index b65446098..e310f639c 100644 --- a/src/externs.h +++ b/src/externs.h @@ -423,9 +423,6 @@ extern void move_cursor_relative(int row, int col); extern void print_rel(SYMBOL_CODE c, TERM_COLOR a, TERM_LEN y, TERM_LEN x); extern void display_dungeon(void); extern void prt_path(POSITION y, POSITION x); -extern void update_lite(void); -extern void forget_view(void); -extern void update_view(void); extern void update_mon_lite(void); extern void clear_mon_lite(void); extern void delayed_visual_update(void); diff --git a/src/floor-events.c b/src/floor-events.c index 9fbcbd26a..a9ef18ad3 100644 --- a/src/floor-events.c +++ b/src/floor-events.c @@ -382,3 +382,933 @@ void forget_lite(void) /* None left */ current_floor_ptr->lite_n = 0; } + + + +/* + * Update the set of grids "illuminated" by the player's lite. + * + * This routine needs to use the results of "update_view()" + * + * Note that "blindness" does NOT affect "torch lite". Be careful! + * + * We optimize most lites (all non-artifact lites) by using "obvious" + * facts about the results of "small" lite radius, and we attempt to + * list the "nearby" grids before the more "distant" ones in the + * array of torch-lit grids. + * + * We assume that "radius zero" lite is in fact no lite at all. + * + * Torch Lantern Artifacts + * (etc) + * *** + * *** ***** + * *** ***** ******* + * *@* **@** ***@*** + * *** ***** ******* + * *** ***** + * *** + */ +void update_lite(void) +{ + int i; + POSITION x, y, min_x, max_x, min_y, max_y; + POSITION p = p_ptr->cur_lite; + grid_type *g_ptr; + + /*** Special case ***/ + +#if 0 + /* Hack -- Player has no lite */ + if (p <= 0) + { + /* Forget the old lite */ + /* forget_lite(); Perhaps don't need? */ + + /* Add it to later visual update */ + cave_redraw_later(¤t_floor_ptr->grid_array[p_ptr->y][p_ptr->x], p_ptr->y, p_ptr->x); + } +#endif + + /*** Save the old "lite" grids for later ***/ + + /* Clear them all */ + for (i = 0; i < current_floor_ptr->lite_n; i++) + { + y = current_floor_ptr->lite_y[i]; + x = current_floor_ptr->lite_x[i]; + + /* Mark the grid as not "lite" */ + current_floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE); + + /* Mark the grid as "seen" */ + current_floor_ptr->grid_array[y][x].info |= (CAVE_TEMP); + + /* Add it to the "seen" set */ + tmp_pos.y[tmp_pos.n] = y; + tmp_pos.x[tmp_pos.n] = x; + tmp_pos.n++; + } + + /* None left */ + current_floor_ptr->lite_n = 0; + + + /*** Collect the new "lite" grids ***/ + + /* Radius 1 -- torch radius */ + if (p >= 1) + { + /* Player grid */ + cave_lite_hack(p_ptr->y, p_ptr->x); + + /* Adjacent grid */ + cave_lite_hack(p_ptr->y + 1, p_ptr->x); + cave_lite_hack(p_ptr->y - 1, p_ptr->x); + cave_lite_hack(p_ptr->y, p_ptr->x + 1); + cave_lite_hack(p_ptr->y, p_ptr->x - 1); + + /* Diagonal grids */ + cave_lite_hack(p_ptr->y + 1, p_ptr->x + 1); + cave_lite_hack(p_ptr->y + 1, p_ptr->x - 1); + cave_lite_hack(p_ptr->y - 1, p_ptr->x + 1); + cave_lite_hack(p_ptr->y - 1, p_ptr->x - 1); + } + + /* Radius 2 -- lantern radius */ + if (p >= 2) + { + /* South of the player */ + if (cave_los_bold(p_ptr->y + 1, p_ptr->x)) + { + cave_lite_hack(p_ptr->y + 2, p_ptr->x); + cave_lite_hack(p_ptr->y + 2, p_ptr->x + 1); + cave_lite_hack(p_ptr->y + 2, p_ptr->x - 1); + } + + /* North of the player */ + if (cave_los_bold(p_ptr->y - 1, p_ptr->x)) + { + cave_lite_hack(p_ptr->y - 2, p_ptr->x); + cave_lite_hack(p_ptr->y - 2, p_ptr->x + 1); + cave_lite_hack(p_ptr->y - 2, p_ptr->x - 1); + } + + /* East of the player */ + if (cave_los_bold(p_ptr->y, p_ptr->x + 1)) + { + cave_lite_hack(p_ptr->y, p_ptr->x + 2); + cave_lite_hack(p_ptr->y + 1, p_ptr->x + 2); + cave_lite_hack(p_ptr->y - 1, p_ptr->x + 2); + } + + /* West of the player */ + if (cave_los_bold(p_ptr->y, p_ptr->x - 1)) + { + cave_lite_hack(p_ptr->y, p_ptr->x - 2); + cave_lite_hack(p_ptr->y + 1, p_ptr->x - 2); + cave_lite_hack(p_ptr->y - 1, p_ptr->x - 2); + } + } + + /* Radius 3+ -- artifact radius */ + if (p >= 3) + { + int d; + + /* Paranoia -- see "LITE_MAX" */ + if (p > 14) p = 14; + + /* South-East of the player */ + if (cave_los_bold(p_ptr->y + 1, p_ptr->x + 1)) + { + cave_lite_hack(p_ptr->y + 2, p_ptr->x + 2); + } + + /* South-West of the player */ + if (cave_los_bold(p_ptr->y + 1, p_ptr->x - 1)) + { + cave_lite_hack(p_ptr->y + 2, p_ptr->x - 2); + } + + /* North-East of the player */ + if (cave_los_bold(p_ptr->y - 1, p_ptr->x + 1)) + { + cave_lite_hack(p_ptr->y - 2, p_ptr->x + 2); + } + + /* North-West of the player */ + if (cave_los_bold(p_ptr->y - 1, p_ptr->x - 1)) + { + cave_lite_hack(p_ptr->y - 2, p_ptr->x - 2); + } + + /* Maximal north */ + min_y = p_ptr->y - p; + if (min_y < 0) min_y = 0; + + /* Maximal south */ + max_y = p_ptr->y + p; + if (max_y > current_floor_ptr->height - 1) max_y = current_floor_ptr->height - 1; + + /* Maximal west */ + min_x = p_ptr->x - p; + if (min_x < 0) min_x = 0; + + /* Maximal east */ + max_x = p_ptr->x + p; + if (max_x > current_floor_ptr->width - 1) max_x = current_floor_ptr->width - 1; + + /* Scan the maximal box */ + for (y = min_y; y <= max_y; y++) + { + for (x = min_x; x <= max_x; x++) + { + int dy = (p_ptr->y > y) ? (p_ptr->y - y) : (y - p_ptr->y); + int dx = (p_ptr->x > x) ? (p_ptr->x - x) : (x - p_ptr->x); + + /* Skip the "central" grids (above) */ + if ((dy <= 2) && (dx <= 2)) continue; + + /* Hack -- approximate the distance */ + d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); + + /* Skip distant grids */ + if (d > p) continue; + + /* Viewable, nearby, grids get "torch lit" */ + if (current_floor_ptr->grid_array[y][x].info & CAVE_VIEW) + { + /* This grid is "torch lit" */ + cave_lite_hack(y, x); + } + } + } + } + + + /*** Complete the algorithm ***/ + + /* Draw the new grids */ + for (i = 0; i < current_floor_ptr->lite_n; i++) + { + y = current_floor_ptr->lite_y[i]; + x = current_floor_ptr->lite_x[i]; + + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* Update fresh grids */ + if (g_ptr->info & (CAVE_TEMP)) continue; + + /* Add it to later visual update */ + cave_note_and_redraw_later(g_ptr, y, x); + } + + /* Clear them all */ + for (i = 0; i < tmp_pos.n; i++) + { + y = tmp_pos.y[i]; + x = tmp_pos.x[i]; + + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* No longer in the array */ + g_ptr->info &= ~(CAVE_TEMP); + + /* Update stale grids */ + if (g_ptr->info & (CAVE_LITE)) continue; + + /* Add it to later visual update */ + cave_redraw_later(g_ptr, y, x); + } + + /* None left */ + tmp_pos.n = 0; + + /* Mega-Hack -- Visual update later */ + p_ptr->update |= (PU_DELAY_VIS); +} + + +/* + * Clear the viewable space + */ +void forget_view(void) +{ + int i; + + grid_type *g_ptr; + + /* None to forget */ + if (!current_floor_ptr->view_n) return; + + /* Clear them all */ + for (i = 0; i < current_floor_ptr->view_n; i++) + { + POSITION y = current_floor_ptr->view_y[i]; + POSITION x = current_floor_ptr->view_x[i]; + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* Forget that the grid is viewable */ + g_ptr->info &= ~(CAVE_VIEW); + + /* if (!panel_contains(y, x)) continue; */ + + /* Update the screen */ + /* lite_spot(y, x); Perhaps don't need? */ + } + + /* None left */ + current_floor_ptr->view_n = 0; +} + + + +/* + * Helper function for "update_view()" below + * + * We are checking the "viewability" of grid (y,x) by the player. + * + * This function assumes that (y,x) is legal (i.e. on the map). + * + * Grid (y1,x1) is on the "diagonal" between (p_ptr->y,p_ptr->x) and (y,x) + * Grid (y2,x2) is "adjacent", also between (p_ptr->y,p_ptr->x) and (y,x). + * + * Note that we are using the "CAVE_XTRA" field for marking grids as + * "easily viewable". This bit is cleared at the end of "update_view()". + * + * This function adds (y,x) to the "viewable set" if necessary. + * + * This function now returns "TRUE" if vision is "blocked" by grid (y,x). + */ +static bool update_view_aux(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2) +{ + bool f1, f2, v1, v2, z1, z2, wall; + + grid_type *g_ptr; + + grid_type *g1_c_ptr; + grid_type *g2_c_ptr; + + /* Access the grids */ + g1_c_ptr = ¤t_floor_ptr->grid_array[y1][x1]; + g2_c_ptr = ¤t_floor_ptr->grid_array[y2][x2]; + + + /* Check for walls */ + f1 = (cave_los_grid(g1_c_ptr)); + f2 = (cave_los_grid(g2_c_ptr)); + + /* Totally blocked by physical walls */ + if (!f1 && !f2) return (TRUE); + + + /* Check for visibility */ + v1 = (f1 && (g1_c_ptr->info & (CAVE_VIEW))); + v2 = (f2 && (g2_c_ptr->info & (CAVE_VIEW))); + + /* Totally blocked by "unviewable neighbors" */ + if (!v1 && !v2) return (TRUE); + + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + + /* Check for walls */ + wall = (!cave_los_grid(g_ptr)); + + + /* Check the "ease" of visibility */ + z1 = (v1 && (g1_c_ptr->info & (CAVE_XTRA))); + z2 = (v2 && (g2_c_ptr->info & (CAVE_XTRA))); + + /* Hack -- "easy" plus "easy" yields "easy" */ + if (z1 && z2) + { + g_ptr->info |= (CAVE_XTRA); + + cave_view_hack(g_ptr, y, x); + + return (wall); + } + + /* Hack -- primary "easy" yields "viewed" */ + if (z1) + { + cave_view_hack(g_ptr, y, x); + + return (wall); + } + + /* Hack -- "view" plus "view" yields "view" */ + if (v1 && v2) + { + /* g_ptr->info |= (CAVE_XTRA); */ + + cave_view_hack(g_ptr, y, x); + + return (wall); + } + + + /* Mega-Hack -- the "los()" function works poorly on walls */ + if (wall) + { + cave_view_hack(g_ptr, y, x); + + return (wall); + } + + + /* Hack -- check line of sight */ + if (los(p_ptr->y, p_ptr->x, y, x)) + { + cave_view_hack(g_ptr, y, x); + + return (wall); + } + + + /* Assume no line of sight. */ + return (TRUE); +} + + +/* + * Calculate the viewable space + * + * 1: Process the player + * 1a: The player is always (easily) viewable + * 2: Process the diagonals + * 2a: The diagonals are (easily) viewable up to the first wall + * 2b: But never go more than 2/3 of the "full" distance + * 3: Process the main axes + * 3a: The main axes are (easily) viewable up to the first wall + * 3b: But never go more than the "full" distance + * 4: Process sequential "strips" in each of the eight octants + * 4a: Each strip runs along the previous strip + * 4b: The main axes are "previous" to the first strip + * 4c: Process both "sides" of each "direction" of each strip + * 4c1: Each side aborts as soon as possible + * 4c2: Each side tells the next strip how far it has to check + * + * Note that the octant processing involves some pretty interesting + * observations involving when a grid might possibly be viewable from + * a given grid, and on the order in which the strips are processed. + * + * Note the use of the mathematical facts shown below, which derive + * from the fact that (1 < sqrt(2) < 1.5), and that the length of the + * hypotenuse of a right triangle is primarily determined by the length + * of the longest side, when one side is small, and is strictly less + * than one-and-a-half times as long as the longest side when both of + * the sides are large. + * + * if (manhatten(dy,dx) < R) then (hypot(dy,dx) < R) + * if (manhatten(dy,dx) > R*3/2) then (hypot(dy,dx) > R) + * + * hypot(dy,dx) is approximated by (dx+dy+MAX(dx,dy)) / 2 + * + * These observations are important because the calculation of the actual + * value of "hypot(dx,dy)" is extremely expensive, involving square roots, + * while for small values (up to about 20 or so), the approximations above + * are correct to within an error of at most one grid or so. + * + * Observe the use of "full" and "over" in the code below, and the use of + * the specialized calculation involving "limit", all of which derive from + * the observations given above. Basically, we note that the "circle" of + * view is completely contained in an "octagon" whose bounds are easy to + * determine, and that only a few steps are needed to derive the actual + * bounds of the circle given the bounds of the octagon. + * + * Note that by skipping all the grids in the corners of the octagon, we + * place an upper limit on the number of grids in the field of view, given + * that "full" is never more than 20. Of the 1681 grids in the "square" of + * view, only about 1475 of these are in the "octagon" of view, and even + * fewer are in the "circle" of view, so 1500 or 1536 is more than enough + * entries to completely contain the actual field of view. + * + * Note also the care taken to prevent "running off the map". The use of + * explicit checks on the "validity" of the "diagonal", and the fact that + * the loops are never allowed to "leave" the map, lets "update_view_aux()" + * use the optimized "cave_los_bold()" macro, and to avoid the overhead + * of multiple checks on the validity of grids. + * + * Note the "optimizations" involving the "se","sw","ne","nw","es","en", + * "ws","wn" variables. They work like this: While travelling down the + * south-bound strip just to the east of the main south axis, as soon as + * we get to a grid which does not "transmit" viewing, if all of the strips + * preceding us (in this case, just the main axis) had terminated at or before + * the same point, then we can stop, and reset the "max distance" to ourself. + * So, each strip (named by major axis plus offset, thus "se" in this case) + * maintains a "blockage" variable, initialized during the main axis step, + * and checks it whenever a blockage is observed. After processing each + * strip as far as the previous strip told us to process, the next strip is + * told not to go farther than the current strip's farthest viewable grid, + * unless open space is still available. This uses the "k" variable. + * + * Note the use of "inline" macros for efficiency. The "cave_los_grid()" + * macro is a replacement for "cave_los_bold()" which takes a pointer to + * a grid instead of its location. The "cave_view_hack()" macro is a + * chunk of code which adds the given location to the "view" array if it + * is not already there, using both the actual location and a pointer to + * the grid. See above. + * + * By the way, the purpose of this code is to reduce the dependancy on the + * "los()" function which is slow, and, in some cases, not very accurate. + * + * It is very possible that I am the only person who fully understands this + * function, and for that I am truly sorry, but efficiency was very important + * and the "simple" version of this function was just not fast enough. I am + * more than willing to replace this function with a simpler one, if it is + * equally efficient, and especially willing if the new function happens to + * derive "reverse-line-of-sight" at the same time, since currently monsters + * just use an optimized hack of "you see me, so I see you", and then use the + * actual "projectable()" function to check spell attacks. + */ +void update_view(void) +{ + int n, m, d, k, z; + POSITION y, x; + + int se, sw, ne, nw, es, en, ws, wn; + + int full, over; + + POSITION y_max = current_floor_ptr->height - 1; + POSITION x_max = current_floor_ptr->width - 1; + + grid_type *g_ptr; + + /*** Initialize ***/ + + /* Optimize */ + if (view_reduce_view && !current_floor_ptr->dun_level) + { + /* Full radius (10) */ + full = MAX_SIGHT / 2; + + /* Octagon factor (15) */ + over = MAX_SIGHT * 3 / 4; + } + + /* Normal */ + else + { + /* Full radius (20) */ + full = MAX_SIGHT; + + /* Octagon factor (30) */ + over = MAX_SIGHT * 3 / 2; + } + + + /*** Step 0 -- Begin ***/ + + /* Save the old "view" grids for later */ + for (n = 0; n < current_floor_ptr->view_n; n++) + { + y = current_floor_ptr->view_y[n]; + x = current_floor_ptr->view_x[n]; + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* Mark the grid as not in "view" */ + g_ptr->info &= ~(CAVE_VIEW); + + /* Mark the grid as "seen" */ + g_ptr->info |= (CAVE_TEMP); + + /* Add it to the "seen" set */ + tmp_pos.y[tmp_pos.n] = y; + tmp_pos.x[tmp_pos.n] = x; + tmp_pos.n++; + } + + /* Start over with the "view" array */ + current_floor_ptr->view_n = 0; + + /*** Step 1 -- adjacent grids ***/ + + /* Now start on the player */ + y = p_ptr->y; + x = p_ptr->x; + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* Assume the player grid is easily viewable */ + g_ptr->info |= (CAVE_XTRA); + + /* Assume the player grid is viewable */ + cave_view_hack(g_ptr, y, x); + + + /*** Step 2 -- Major Diagonals ***/ + + /* Hack -- Limit */ + z = full * 2 / 3; + + /* Scan south-east */ + for (d = 1; d <= z; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y + d][x + d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y + d, x + d); + if (!cave_los_grid(g_ptr)) break; + } + + /* Scan south-west */ + for (d = 1; d <= z; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y + d][x - d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y + d, x - d); + if (!cave_los_grid(g_ptr)) break; + } + + /* Scan north-east */ + for (d = 1; d <= z; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y - d][x + d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y - d, x + d); + if (!cave_los_grid(g_ptr)) break; + } + + /* Scan north-west */ + for (d = 1; d <= z; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y - d][x - d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y - d, x - d); + if (!cave_los_grid(g_ptr)) break; + } + + /*** Step 3 -- major axes ***/ + + /* Scan south */ + for (d = 1; d <= full; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y + d][x]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y + d, x); + if (!cave_los_grid(g_ptr)) break; + } + + /* Initialize the "south strips" */ + se = sw = d; + + /* Scan north */ + for (d = 1; d <= full; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y - d][x]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y - d, x); + if (!cave_los_grid(g_ptr)) break; + } + + /* Initialize the "north strips" */ + ne = nw = d; + + /* Scan east */ + for (d = 1; d <= full; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y][x + d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y, x + d); + if (!cave_los_grid(g_ptr)) break; + } + + /* Initialize the "east strips" */ + es = en = d; + + /* Scan west */ + for (d = 1; d <= full; d++) + { + g_ptr = ¤t_floor_ptr->grid_array[y][x - d]; + g_ptr->info |= (CAVE_XTRA); + cave_view_hack(g_ptr, y, x - d); + if (!cave_los_grid(g_ptr)) break; + } + + /* Initialize the "west strips" */ + ws = wn = d; + + + /*** Step 4 -- Divide each "octant" into "strips" ***/ + + /* Now check each "diagonal" (in parallel) */ + for (n = 1; n <= over / 2; n++) + { + POSITION ypn, ymn, xpn, xmn; + + /* Acquire the "bounds" of the maximal circle */ + z = over - n - n; + if (z > full - n) z = full - n; + while ((z + n + (n >> 1)) > full) z--; + + + /* Access the four diagonal grids */ + ypn = y + n; + ymn = y - n; + xpn = x + n; + xmn = x - n; + + + /* South strip */ + if (ypn < y_max) + { + /* Maximum distance */ + m = MIN(z, y_max - ypn); + + /* East side */ + if ((xpn <= x_max) && (n < se)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ypn + d, xpn, ypn + d - 1, xpn - 1, ypn + d - 1, xpn)) + { + if (n + d >= se) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + se = k + 1; + } + + /* West side */ + if ((xmn >= 0) && (n < sw)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ypn + d, xmn, ypn + d - 1, xmn + 1, ypn + d - 1, xmn)) + { + if (n + d >= sw) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + sw = k + 1; + } + } + + + /* North strip */ + if (ymn > 0) + { + /* Maximum distance */ + m = MIN(z, ymn); + + /* East side */ + if ((xpn <= x_max) && (n < ne)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ymn - d, xpn, ymn - d + 1, xpn - 1, ymn - d + 1, xpn)) + { + if (n + d >= ne) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + ne = k + 1; + } + + /* West side */ + if ((xmn >= 0) && (n < nw)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ymn - d, xmn, ymn - d + 1, xmn + 1, ymn - d + 1, xmn)) + { + if (n + d >= nw) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + nw = k + 1; + } + } + + + /* East strip */ + if (xpn < x_max) + { + /* Maximum distance */ + m = MIN(z, x_max - xpn); + + /* South side */ + if ((ypn <= x_max) && (n < es)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ypn, xpn + d, ypn - 1, xpn + d - 1, ypn, xpn + d - 1)) + { + if (n + d >= es) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + es = k + 1; + } + + /* North side */ + if ((ymn >= 0) && (n < en)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ymn, xpn + d, ymn + 1, xpn + d - 1, ymn, xpn + d - 1)) + { + if (n + d >= en) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + en = k + 1; + } + } + + + /* West strip */ + if (xmn > 0) + { + /* Maximum distance */ + m = MIN(z, xmn); + + /* South side */ + if ((ypn <= y_max) && (n < ws)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ypn, xmn - d, ypn - 1, xmn - d + 1, ypn, xmn - d + 1)) + { + if (n + d >= ws) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + ws = k + 1; + } + + /* North side */ + if ((ymn >= 0) && (n < wn)) + { + /* Scan */ + for (k = n, d = 1; d <= m; d++) + { + /* Check grid "d" in strip "n", notice "blockage" */ + if (update_view_aux(ymn, xmn - d, ymn + 1, xmn - d + 1, ymn, xmn - d + 1)) + { + if (n + d >= wn) break; + } + + /* Track most distant "non-blockage" */ + else + { + k = n + d; + } + } + + /* Limit the next strip */ + wn = k + 1; + } + } + } + + + /*** Step 5 -- Complete the algorithm ***/ + + /* Update all the new grids */ + for (n = 0; n < current_floor_ptr->view_n; n++) + { + y = current_floor_ptr->view_y[n]; + x = current_floor_ptr->view_x[n]; + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* Clear the "CAVE_XTRA" flag */ + g_ptr->info &= ~(CAVE_XTRA); + + /* Update only newly viewed grids */ + if (g_ptr->info & (CAVE_TEMP)) continue; + + /* Add it to later visual update */ + cave_note_and_redraw_later(g_ptr, y, x); + } + + /* Wipe the old grids, update as needed */ + for (n = 0; n < tmp_pos.n; n++) + { + y = tmp_pos.y[n]; + x = tmp_pos.x[n]; + g_ptr = ¤t_floor_ptr->grid_array[y][x]; + + /* No longer in the array */ + g_ptr->info &= ~(CAVE_TEMP); + + /* Update only non-viewable grids */ + if (g_ptr->info & (CAVE_VIEW)) continue; + + /* Add it to later visual update */ + cave_redraw_later(g_ptr, y, x); + } + + /* None left */ + tmp_pos.n = 0; + + /* Mega-Hack -- Visual update later */ + p_ptr->update |= (PU_DELAY_VIS); +} + + diff --git a/src/floor-events.h b/src/floor-events.h index d029986d8..26acdb99d 100644 --- a/src/floor-events.h +++ b/src/floor-events.h @@ -6,3 +6,8 @@ extern byte get_dungeon_feeling(void); extern void update_dungeon_feeling(void); extern void glow_deep_lava_and_bldg(void); extern void forget_lite(void); +extern void update_lite(void); +extern void forget_view(void); +extern void update_view(void); +extern void update_mon_lite(void); +extern void clear_mon_lite(void); diff --git a/src/grid.c b/src/grid.c index 4b2cb2bf4..6db84b8d8 100644 --- a/src/grid.c +++ b/src/grid.c @@ -1598,293 +1598,6 @@ void prt_path(POSITION y, POSITION x) * Oh, and outside of the "torch radius", only "lite" grids need to be scanned. */ - -/* - * For delayed visual update - */ -#define cave_note_and_redraw_later(C,Y,X) \ -{\ - (C)->info |= CAVE_NOTE; \ - cave_redraw_later((C), (Y), (X)); \ -} - - - /* - * For delayed visual update - */ -#define cave_redraw_later(C,Y,X) \ -{\ - if (!((C)->info & CAVE_REDRAW)) \ - { \ - (C)->info |= CAVE_REDRAW; \ - current_floor_ptr->redraw_y[current_floor_ptr->redraw_n] = (Y); \ - current_floor_ptr->redraw_x[current_floor_ptr->redraw_n++] = (X); \ - } \ -} - - - /* - * This macro allows us to efficiently add a grid to the "lite" array, - * note that we are never called for illegal grids, or for grids which - * have already been placed into the "lite" array, and we are never - * called when the "lite" array is full. - */ -#define cave_lite_hack(Y,X) \ -{\ - if (!(current_floor_ptr->grid_array[Y][X].info & (CAVE_LITE))) \ - { \ - current_floor_ptr->grid_array[Y][X].info |= (CAVE_LITE); \ - current_floor_ptr->lite_y[current_floor_ptr->lite_n] = (Y); \ - current_floor_ptr->lite_x[current_floor_ptr->lite_n++] = (X); \ - } \ -} - - - /* - * Update the set of grids "illuminated" by the player's lite. - * - * This routine needs to use the results of "update_view()" - * - * Note that "blindness" does NOT affect "torch lite". Be careful! - * - * We optimize most lites (all non-artifact lites) by using "obvious" - * facts about the results of "small" lite radius, and we attempt to - * list the "nearby" grids before the more "distant" ones in the - * array of torch-lit grids. - * - * We assume that "radius zero" lite is in fact no lite at all. - * - * Torch Lantern Artifacts - * (etc) - * *** - * *** ***** - * *** ***** ******* - * *@* **@** ***@*** - * *** ***** ******* - * *** ***** - * *** - */ -void update_lite(void) -{ - int i; - POSITION x, y, min_x, max_x, min_y, max_y; - POSITION p = p_ptr->cur_lite; - grid_type *g_ptr; - - /*** Special case ***/ - -#if 0 - /* Hack -- Player has no lite */ - if (p <= 0) - { - /* Forget the old lite */ - /* forget_lite(); Perhaps don't need? */ - - /* Add it to later visual update */ - cave_redraw_later(¤t_floor_ptr->grid_array[p_ptr->y][p_ptr->x], p_ptr->y, p_ptr->x); - } -#endif - - /*** Save the old "lite" grids for later ***/ - - /* Clear them all */ - for (i = 0; i < current_floor_ptr->lite_n; i++) - { - y = current_floor_ptr->lite_y[i]; - x = current_floor_ptr->lite_x[i]; - - /* Mark the grid as not "lite" */ - current_floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE); - - /* Mark the grid as "seen" */ - current_floor_ptr->grid_array[y][x].info |= (CAVE_TEMP); - - /* Add it to the "seen" set */ - tmp_pos.y[tmp_pos.n] = y; - tmp_pos.x[tmp_pos.n] = x; - tmp_pos.n++; - } - - /* None left */ - current_floor_ptr->lite_n = 0; - - - /*** Collect the new "lite" grids ***/ - - /* Radius 1 -- torch radius */ - if (p >= 1) - { - /* Player grid */ - cave_lite_hack(p_ptr->y, p_ptr->x); - - /* Adjacent grid */ - cave_lite_hack(p_ptr->y + 1, p_ptr->x); - cave_lite_hack(p_ptr->y - 1, p_ptr->x); - cave_lite_hack(p_ptr->y, p_ptr->x + 1); - cave_lite_hack(p_ptr->y, p_ptr->x - 1); - - /* Diagonal grids */ - cave_lite_hack(p_ptr->y + 1, p_ptr->x + 1); - cave_lite_hack(p_ptr->y + 1, p_ptr->x - 1); - cave_lite_hack(p_ptr->y - 1, p_ptr->x + 1); - cave_lite_hack(p_ptr->y - 1, p_ptr->x - 1); - } - - /* Radius 2 -- lantern radius */ - if (p >= 2) - { - /* South of the player */ - if (cave_los_bold(p_ptr->y + 1, p_ptr->x)) - { - cave_lite_hack(p_ptr->y + 2, p_ptr->x); - cave_lite_hack(p_ptr->y + 2, p_ptr->x + 1); - cave_lite_hack(p_ptr->y + 2, p_ptr->x - 1); - } - - /* North of the player */ - if (cave_los_bold(p_ptr->y - 1, p_ptr->x)) - { - cave_lite_hack(p_ptr->y - 2, p_ptr->x); - cave_lite_hack(p_ptr->y - 2, p_ptr->x + 1); - cave_lite_hack(p_ptr->y - 2, p_ptr->x - 1); - } - - /* East of the player */ - if (cave_los_bold(p_ptr->y, p_ptr->x + 1)) - { - cave_lite_hack(p_ptr->y, p_ptr->x + 2); - cave_lite_hack(p_ptr->y + 1, p_ptr->x + 2); - cave_lite_hack(p_ptr->y - 1, p_ptr->x + 2); - } - - /* West of the player */ - if (cave_los_bold(p_ptr->y, p_ptr->x - 1)) - { - cave_lite_hack(p_ptr->y, p_ptr->x - 2); - cave_lite_hack(p_ptr->y + 1, p_ptr->x - 2); - cave_lite_hack(p_ptr->y - 1, p_ptr->x - 2); - } - } - - /* Radius 3+ -- artifact radius */ - if (p >= 3) - { - int d; - - /* Paranoia -- see "LITE_MAX" */ - if (p > 14) p = 14; - - /* South-East of the player */ - if (cave_los_bold(p_ptr->y + 1, p_ptr->x + 1)) - { - cave_lite_hack(p_ptr->y + 2, p_ptr->x + 2); - } - - /* South-West of the player */ - if (cave_los_bold(p_ptr->y + 1, p_ptr->x - 1)) - { - cave_lite_hack(p_ptr->y + 2, p_ptr->x - 2); - } - - /* North-East of the player */ - if (cave_los_bold(p_ptr->y - 1, p_ptr->x + 1)) - { - cave_lite_hack(p_ptr->y - 2, p_ptr->x + 2); - } - - /* North-West of the player */ - if (cave_los_bold(p_ptr->y - 1, p_ptr->x - 1)) - { - cave_lite_hack(p_ptr->y - 2, p_ptr->x - 2); - } - - /* Maximal north */ - min_y = p_ptr->y - p; - if (min_y < 0) min_y = 0; - - /* Maximal south */ - max_y = p_ptr->y + p; - if (max_y > current_floor_ptr->height - 1) max_y = current_floor_ptr->height - 1; - - /* Maximal west */ - min_x = p_ptr->x - p; - if (min_x < 0) min_x = 0; - - /* Maximal east */ - max_x = p_ptr->x + p; - if (max_x > current_floor_ptr->width - 1) max_x = current_floor_ptr->width - 1; - - /* Scan the maximal box */ - for (y = min_y; y <= max_y; y++) - { - for (x = min_x; x <= max_x; x++) - { - int dy = (p_ptr->y > y) ? (p_ptr->y - y) : (y - p_ptr->y); - int dx = (p_ptr->x > x) ? (p_ptr->x - x) : (x - p_ptr->x); - - /* Skip the "central" grids (above) */ - if ((dy <= 2) && (dx <= 2)) continue; - - /* Hack -- approximate the distance */ - d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); - - /* Skip distant grids */ - if (d > p) continue; - - /* Viewable, nearby, grids get "torch lit" */ - if (current_floor_ptr->grid_array[y][x].info & CAVE_VIEW) - { - /* This grid is "torch lit" */ - cave_lite_hack(y, x); - } - } - } - } - - - /*** Complete the algorithm ***/ - - /* Draw the new grids */ - for (i = 0; i < current_floor_ptr->lite_n; i++) - { - y = current_floor_ptr->lite_y[i]; - x = current_floor_ptr->lite_x[i]; - - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* Update fresh grids */ - if (g_ptr->info & (CAVE_TEMP)) continue; - - /* Add it to later visual update */ - cave_note_and_redraw_later(g_ptr, y, x); - } - - /* Clear them all */ - for (i = 0; i < tmp_pos.n; i++) - { - y = tmp_pos.y[i]; - x = tmp_pos.x[i]; - - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* No longer in the array */ - g_ptr->info &= ~(CAVE_TEMP); - - /* Update stale grids */ - if (g_ptr->info & (CAVE_LITE)) continue; - - /* Add it to later visual update */ - cave_redraw_later(g_ptr, y, x); - } - - /* None left */ - tmp_pos.n = 0; - - /* Mega-Hack -- Visual update later */ - p_ptr->update |= (PU_DELAY_VIS); -} - - static bool mon_invis; static POSITION mon_fy, mon_fx; @@ -2394,708 +2107,6 @@ void clear_mon_lite(void) current_floor_ptr->mon_lite_n = 0; } - - -/* - * Clear the viewable space - */ -void forget_view(void) -{ - int i; - - grid_type *g_ptr; - - /* None to forget */ - if (!current_floor_ptr->view_n) return; - - /* Clear them all */ - for (i = 0; i < current_floor_ptr->view_n; i++) - { - POSITION y = current_floor_ptr->view_y[i]; - POSITION x = current_floor_ptr->view_x[i]; - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* Forget that the grid is viewable */ - g_ptr->info &= ~(CAVE_VIEW); - - /* if (!panel_contains(y, x)) continue; */ - - /* Update the screen */ - /* lite_spot(y, x); Perhaps don't need? */ - } - - /* None left */ - current_floor_ptr->view_n = 0; -} - - - -/* - * This macro allows us to efficiently add a grid to the "view" array, - * note that we are never called for illegal grids, or for grids which - * have already been placed into the "view" array, and we are never - * called when the "view" array is full. - */ -#define cave_view_hack(C,Y,X) \ -{\ - if (!((C)->info & (CAVE_VIEW))){\ - (C)->info |= (CAVE_VIEW); \ - current_floor_ptr->view_y[current_floor_ptr->view_n] = (Y); \ - current_floor_ptr->view_x[current_floor_ptr->view_n] = (X); \ - current_floor_ptr->view_n++;}\ -} - - - - /* - * Helper function for "update_view()" below - * - * We are checking the "viewability" of grid (y,x) by the player. - * - * This function assumes that (y,x) is legal (i.e. on the map). - * - * Grid (y1,x1) is on the "diagonal" between (p_ptr->y,p_ptr->x) and (y,x) - * Grid (y2,x2) is "adjacent", also between (p_ptr->y,p_ptr->x) and (y,x). - * - * Note that we are using the "CAVE_XTRA" field for marking grids as - * "easily viewable". This bit is cleared at the end of "update_view()". - * - * This function adds (y,x) to the "viewable set" if necessary. - * - * This function now returns "TRUE" if vision is "blocked" by grid (y,x). - */ -static bool update_view_aux(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2) -{ - bool f1, f2, v1, v2, z1, z2, wall; - - grid_type *g_ptr; - - grid_type *g1_c_ptr; - grid_type *g2_c_ptr; - - /* Access the grids */ - g1_c_ptr = ¤t_floor_ptr->grid_array[y1][x1]; - g2_c_ptr = ¤t_floor_ptr->grid_array[y2][x2]; - - - /* Check for walls */ - f1 = (cave_los_grid(g1_c_ptr)); - f2 = (cave_los_grid(g2_c_ptr)); - - /* Totally blocked by physical walls */ - if (!f1 && !f2) return (TRUE); - - - /* Check for visibility */ - v1 = (f1 && (g1_c_ptr->info & (CAVE_VIEW))); - v2 = (f2 && (g2_c_ptr->info & (CAVE_VIEW))); - - /* Totally blocked by "unviewable neighbors" */ - if (!v1 && !v2) return (TRUE); - - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - - /* Check for walls */ - wall = (!cave_los_grid(g_ptr)); - - - /* Check the "ease" of visibility */ - z1 = (v1 && (g1_c_ptr->info & (CAVE_XTRA))); - z2 = (v2 && (g2_c_ptr->info & (CAVE_XTRA))); - - /* Hack -- "easy" plus "easy" yields "easy" */ - if (z1 && z2) - { - g_ptr->info |= (CAVE_XTRA); - - cave_view_hack(g_ptr, y, x); - - return (wall); - } - - /* Hack -- primary "easy" yields "viewed" */ - if (z1) - { - cave_view_hack(g_ptr, y, x); - - return (wall); - } - - /* Hack -- "view" plus "view" yields "view" */ - if (v1 && v2) - { - /* g_ptr->info |= (CAVE_XTRA); */ - - cave_view_hack(g_ptr, y, x); - - return (wall); - } - - - /* Mega-Hack -- the "los()" function works poorly on walls */ - if (wall) - { - cave_view_hack(g_ptr, y, x); - - return (wall); - } - - - /* Hack -- check line of sight */ - if (los(p_ptr->y, p_ptr->x, y, x)) - { - cave_view_hack(g_ptr, y, x); - - return (wall); - } - - - /* Assume no line of sight. */ - return (TRUE); -} - - - -/* - * Calculate the viewable space - * - * 1: Process the player - * 1a: The player is always (easily) viewable - * 2: Process the diagonals - * 2a: The diagonals are (easily) viewable up to the first wall - * 2b: But never go more than 2/3 of the "full" distance - * 3: Process the main axes - * 3a: The main axes are (easily) viewable up to the first wall - * 3b: But never go more than the "full" distance - * 4: Process sequential "strips" in each of the eight octants - * 4a: Each strip runs along the previous strip - * 4b: The main axes are "previous" to the first strip - * 4c: Process both "sides" of each "direction" of each strip - * 4c1: Each side aborts as soon as possible - * 4c2: Each side tells the next strip how far it has to check - * - * Note that the octant processing involves some pretty interesting - * observations involving when a grid might possibly be viewable from - * a given grid, and on the order in which the strips are processed. - * - * Note the use of the mathematical facts shown below, which derive - * from the fact that (1 < sqrt(2) < 1.5), and that the length of the - * hypotenuse of a right triangle is primarily determined by the length - * of the longest side, when one side is small, and is strictly less - * than one-and-a-half times as long as the longest side when both of - * the sides are large. - * - * if (manhatten(dy,dx) < R) then (hypot(dy,dx) < R) - * if (manhatten(dy,dx) > R*3/2) then (hypot(dy,dx) > R) - * - * hypot(dy,dx) is approximated by (dx+dy+MAX(dx,dy)) / 2 - * - * These observations are important because the calculation of the actual - * value of "hypot(dx,dy)" is extremely expensive, involving square roots, - * while for small values (up to about 20 or so), the approximations above - * are correct to within an error of at most one grid or so. - * - * Observe the use of "full" and "over" in the code below, and the use of - * the specialized calculation involving "limit", all of which derive from - * the observations given above. Basically, we note that the "circle" of - * view is completely contained in an "octagon" whose bounds are easy to - * determine, and that only a few steps are needed to derive the actual - * bounds of the circle given the bounds of the octagon. - * - * Note that by skipping all the grids in the corners of the octagon, we - * place an upper limit on the number of grids in the field of view, given - * that "full" is never more than 20. Of the 1681 grids in the "square" of - * view, only about 1475 of these are in the "octagon" of view, and even - * fewer are in the "circle" of view, so 1500 or 1536 is more than enough - * entries to completely contain the actual field of view. - * - * Note also the care taken to prevent "running off the map". The use of - * explicit checks on the "validity" of the "diagonal", and the fact that - * the loops are never allowed to "leave" the map, lets "update_view_aux()" - * use the optimized "cave_los_bold()" macro, and to avoid the overhead - * of multiple checks on the validity of grids. - * - * Note the "optimizations" involving the "se","sw","ne","nw","es","en", - * "ws","wn" variables. They work like this: While travelling down the - * south-bound strip just to the east of the main south axis, as soon as - * we get to a grid which does not "transmit" viewing, if all of the strips - * preceding us (in this case, just the main axis) had terminated at or before - * the same point, then we can stop, and reset the "max distance" to ourself. - * So, each strip (named by major axis plus offset, thus "se" in this case) - * maintains a "blockage" variable, initialized during the main axis step, - * and checks it whenever a blockage is observed. After processing each - * strip as far as the previous strip told us to process, the next strip is - * told not to go farther than the current strip's farthest viewable grid, - * unless open space is still available. This uses the "k" variable. - * - * Note the use of "inline" macros for efficiency. The "cave_los_grid()" - * macro is a replacement for "cave_los_bold()" which takes a pointer to - * a grid instead of its location. The "cave_view_hack()" macro is a - * chunk of code which adds the given location to the "view" array if it - * is not already there, using both the actual location and a pointer to - * the grid. See above. - * - * By the way, the purpose of this code is to reduce the dependancy on the - * "los()" function which is slow, and, in some cases, not very accurate. - * - * It is very possible that I am the only person who fully understands this - * function, and for that I am truly sorry, but efficiency was very important - * and the "simple" version of this function was just not fast enough. I am - * more than willing to replace this function with a simpler one, if it is - * equally efficient, and especially willing if the new function happens to - * derive "reverse-line-of-sight" at the same time, since currently monsters - * just use an optimized hack of "you see me, so I see you", and then use the - * actual "projectable()" function to check spell attacks. - */ -void update_view(void) -{ - int n, m, d, k, z; - POSITION y, x; - - int se, sw, ne, nw, es, en, ws, wn; - - int full, over; - - POSITION y_max = current_floor_ptr->height - 1; - POSITION x_max = current_floor_ptr->width - 1; - - grid_type *g_ptr; - - /*** Initialize ***/ - - /* Optimize */ - if (view_reduce_view && !current_floor_ptr->dun_level) - { - /* Full radius (10) */ - full = MAX_SIGHT / 2; - - /* Octagon factor (15) */ - over = MAX_SIGHT * 3 / 4; - } - - /* Normal */ - else - { - /* Full radius (20) */ - full = MAX_SIGHT; - - /* Octagon factor (30) */ - over = MAX_SIGHT * 3 / 2; - } - - - /*** Step 0 -- Begin ***/ - - /* Save the old "view" grids for later */ - for (n = 0; n < current_floor_ptr->view_n; n++) - { - y = current_floor_ptr->view_y[n]; - x = current_floor_ptr->view_x[n]; - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* Mark the grid as not in "view" */ - g_ptr->info &= ~(CAVE_VIEW); - - /* Mark the grid as "seen" */ - g_ptr->info |= (CAVE_TEMP); - - /* Add it to the "seen" set */ - tmp_pos.y[tmp_pos.n] = y; - tmp_pos.x[tmp_pos.n] = x; - tmp_pos.n++; - } - - /* Start over with the "view" array */ - current_floor_ptr->view_n = 0; - - /*** Step 1 -- adjacent grids ***/ - - /* Now start on the player */ - y = p_ptr->y; - x = p_ptr->x; - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* Assume the player grid is easily viewable */ - g_ptr->info |= (CAVE_XTRA); - - /* Assume the player grid is viewable */ - cave_view_hack(g_ptr, y, x); - - - /*** Step 2 -- Major Diagonals ***/ - - /* Hack -- Limit */ - z = full * 2 / 3; - - /* Scan south-east */ - for (d = 1; d <= z; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y + d][x + d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y + d, x + d); - if (!cave_los_grid(g_ptr)) break; - } - - /* Scan south-west */ - for (d = 1; d <= z; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y + d][x - d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y + d, x - d); - if (!cave_los_grid(g_ptr)) break; - } - - /* Scan north-east */ - for (d = 1; d <= z; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y - d][x + d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y - d, x + d); - if (!cave_los_grid(g_ptr)) break; - } - - /* Scan north-west */ - for (d = 1; d <= z; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y - d][x - d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y - d, x - d); - if (!cave_los_grid(g_ptr)) break; - } - - /*** Step 3 -- major axes ***/ - - /* Scan south */ - for (d = 1; d <= full; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y + d][x]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y + d, x); - if (!cave_los_grid(g_ptr)) break; - } - - /* Initialize the "south strips" */ - se = sw = d; - - /* Scan north */ - for (d = 1; d <= full; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y - d][x]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y - d, x); - if (!cave_los_grid(g_ptr)) break; - } - - /* Initialize the "north strips" */ - ne = nw = d; - - /* Scan east */ - for (d = 1; d <= full; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y][x + d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y, x + d); - if (!cave_los_grid(g_ptr)) break; - } - - /* Initialize the "east strips" */ - es = en = d; - - /* Scan west */ - for (d = 1; d <= full; d++) - { - g_ptr = ¤t_floor_ptr->grid_array[y][x - d]; - g_ptr->info |= (CAVE_XTRA); - cave_view_hack(g_ptr, y, x - d); - if (!cave_los_grid(g_ptr)) break; - } - - /* Initialize the "west strips" */ - ws = wn = d; - - - /*** Step 4 -- Divide each "octant" into "strips" ***/ - - /* Now check each "diagonal" (in parallel) */ - for (n = 1; n <= over / 2; n++) - { - POSITION ypn, ymn, xpn, xmn; - - /* Acquire the "bounds" of the maximal circle */ - z = over - n - n; - if (z > full - n) z = full - n; - while ((z + n + (n >> 1)) > full) z--; - - - /* Access the four diagonal grids */ - ypn = y + n; - ymn = y - n; - xpn = x + n; - xmn = x - n; - - - /* South strip */ - if (ypn < y_max) - { - /* Maximum distance */ - m = MIN(z, y_max - ypn); - - /* East side */ - if ((xpn <= x_max) && (n < se)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ypn + d, xpn, ypn + d - 1, xpn - 1, ypn + d - 1, xpn)) - { - if (n + d >= se) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - se = k + 1; - } - - /* West side */ - if ((xmn >= 0) && (n < sw)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ypn + d, xmn, ypn + d - 1, xmn + 1, ypn + d - 1, xmn)) - { - if (n + d >= sw) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - sw = k + 1; - } - } - - - /* North strip */ - if (ymn > 0) - { - /* Maximum distance */ - m = MIN(z, ymn); - - /* East side */ - if ((xpn <= x_max) && (n < ne)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ymn - d, xpn, ymn - d + 1, xpn - 1, ymn - d + 1, xpn)) - { - if (n + d >= ne) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - ne = k + 1; - } - - /* West side */ - if ((xmn >= 0) && (n < nw)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ymn - d, xmn, ymn - d + 1, xmn + 1, ymn - d + 1, xmn)) - { - if (n + d >= nw) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - nw = k + 1; - } - } - - - /* East strip */ - if (xpn < x_max) - { - /* Maximum distance */ - m = MIN(z, x_max - xpn); - - /* South side */ - if ((ypn <= x_max) && (n < es)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ypn, xpn + d, ypn - 1, xpn + d - 1, ypn, xpn + d - 1)) - { - if (n + d >= es) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - es = k + 1; - } - - /* North side */ - if ((ymn >= 0) && (n < en)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ymn, xpn + d, ymn + 1, xpn + d - 1, ymn, xpn + d - 1)) - { - if (n + d >= en) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - en = k + 1; - } - } - - - /* West strip */ - if (xmn > 0) - { - /* Maximum distance */ - m = MIN(z, xmn); - - /* South side */ - if ((ypn <= y_max) && (n < ws)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ypn, xmn - d, ypn - 1, xmn - d + 1, ypn, xmn - d + 1)) - { - if (n + d >= ws) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - ws = k + 1; - } - - /* North side */ - if ((ymn >= 0) && (n < wn)) - { - /* Scan */ - for (k = n, d = 1; d <= m; d++) - { - /* Check grid "d" in strip "n", notice "blockage" */ - if (update_view_aux(ymn, xmn - d, ymn + 1, xmn - d + 1, ymn, xmn - d + 1)) - { - if (n + d >= wn) break; - } - - /* Track most distant "non-blockage" */ - else - { - k = n + d; - } - } - - /* Limit the next strip */ - wn = k + 1; - } - } - } - - - /*** Step 5 -- Complete the algorithm ***/ - - /* Update all the new grids */ - for (n = 0; n < current_floor_ptr->view_n; n++) - { - y = current_floor_ptr->view_y[n]; - x = current_floor_ptr->view_x[n]; - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* Clear the "CAVE_XTRA" flag */ - g_ptr->info &= ~(CAVE_XTRA); - - /* Update only newly viewed grids */ - if (g_ptr->info & (CAVE_TEMP)) continue; - - /* Add it to later visual update */ - cave_note_and_redraw_later(g_ptr, y, x); - } - - /* Wipe the old grids, update as needed */ - for (n = 0; n < tmp_pos.n; n++) - { - y = tmp_pos.y[n]; - x = tmp_pos.x[n]; - g_ptr = ¤t_floor_ptr->grid_array[y][x]; - - /* No longer in the array */ - g_ptr->info &= ~(CAVE_TEMP); - - /* Update only non-viewable grids */ - if (g_ptr->info & (CAVE_VIEW)) continue; - - /* Add it to later visual update */ - cave_redraw_later(g_ptr, y, x); - } - - /* None left */ - tmp_pos.n = 0; - - /* Mega-Hack -- Visual update later */ - p_ptr->update |= (PU_DELAY_VIS); -} - - /* * Mega-Hack -- Delayed visual update * Only used if update_view(), update_lite() or update_mon_lite() was called diff --git a/src/grid.h b/src/grid.h index 92532e192..e38b479fa 100644 --- a/src/grid.h +++ b/src/grid.h @@ -343,11 +343,6 @@ extern void lite_spot(POSITION y, POSITION x); extern void prt_map(void); extern void prt_path(POSITION y, POSITION x); extern void display_map(int *cy, int *cx); -extern void update_lite(void); -extern void forget_view(void); -extern void update_view(void); -extern void update_mon_lite(void); -extern void clear_mon_lite(void); extern void delayed_visual_update(void); extern void forget_flow(void); extern void update_flow(void); @@ -369,8 +364,62 @@ extern bool check_local_illumination(POSITION y, POSITION x); ((((C)->info & (CAVE_VIEW | CAVE_LITE | CAVE_MNLT | CAVE_MNDK)) == (CAVE_VIEW | CAVE_MNDK)) && \ !p_ptr->see_nocto) - /* - * Get feature mimic from f_info[] (applying "mimic" field) - */ +/* + * Get feature mimic from f_info[] (applying "mimic" field) + */ #define get_feat_mimic(C) \ (f_info[(C)->mimic ? (C)->mimic : (C)->feat].mimic) + +/* + * This macro allows us to efficiently add a grid to the "lite" array, + * note that we are never called for illegal grids, or for grids which + * have already been placed into the "lite" array, and we are never + * called when the "lite" array is full. + */ +#define cave_lite_hack(Y,X) \ +{\ + if (!(current_floor_ptr->grid_array[Y][X].info & (CAVE_LITE))) \ + { \ + current_floor_ptr->grid_array[Y][X].info |= (CAVE_LITE); \ + current_floor_ptr->lite_y[current_floor_ptr->lite_n] = (Y); \ + current_floor_ptr->lite_x[current_floor_ptr->lite_n++] = (X); \ + } \ +} + +/* + * For delayed visual update + */ +#define cave_note_and_redraw_later(C,Y,X) \ +{\ + (C)->info |= CAVE_NOTE; \ + cave_redraw_later((C), (Y), (X)); \ +} + +/* + * For delayed visual update + */ +#define cave_redraw_later(C,Y,X) \ +{\ + if (!((C)->info & CAVE_REDRAW)) \ + { \ + (C)->info |= CAVE_REDRAW; \ + current_floor_ptr->redraw_y[current_floor_ptr->redraw_n] = (Y); \ + current_floor_ptr->redraw_x[current_floor_ptr->redraw_n++] = (X); \ + } \ +} + + /* + * This macro allows us to efficiently add a grid to the "view" array, + * note that we are never called for illegal grids, or for grids which + * have already been placed into the "view" array, and we are never + * called when the "view" array is full. + */ +#define cave_view_hack(C,Y,X) \ +{\ + if (!((C)->info & (CAVE_VIEW))){\ + (C)->info |= (CAVE_VIEW); \ + current_floor_ptr->view_y[current_floor_ptr->view_n] = (Y); \ + current_floor_ptr->view_x[current_floor_ptr->view_n] = (X); \ + current_floor_ptr->view_n++;}\ +} + -- 2.11.0