#include "effect/effect-processor.h"
#include "floor/cave.h"
#include "floor/floor-generator.h"
+#include "floor/geometry.h"
#include "game-option/game-play-options.h"
#include "game-option/map-screen-options.h"
#include "game-option/special-options.h"
#include "io/screen-util.h"
#include "monster-floor/monster-remover.h"
#include "monster-race/monster-race.h"
+#include "monster-race/race-flags2.h"
+#include "monster-race/race-flags7.h"
#include "monster/monster-info.h"
#include "monster/monster-status.h"
#include "monster/monster-update.h"
#include "room/rooms-builder.h"
#include "spell/spell-types.h"
#include "system/floor-type-definition.h"
+#include "system/grid-type-definition.h"
+#include "system/monster-race-definition.h"
+#include "system/monster-type-definition.h"
+#include "system/object-type-definition.h"
+#include "system/player-type-definition.h"
#include "term/term-color-types.h"
#include "util/bit-flags-calculator.h"
+#include "util/point-2d.h"
#include "view/display-map.h"
#include "view/display-messages.h"
#include "window/main-window-util.h"
#include "world/world.h"
+#include <queue>
#define MONSTER_FLOW_DEPTH \
32 /*!< 敵のプレイヤーに対する移動道のりの最大値(この値以上は処理を打ち切る) / OPTION: Maximum flow depth when using "MONSTER_FLOW" */
#define FAF_NO_DROP 0x02
#define FAF_CRASH_GLASS 0x04
-pos_list tmp_pos;
-
/*!
* @brief 地形状態フラグテーブル /
* The table of features' actions
/* Must be a "naked" floor grid */
if (g_ptr->m_idx)
continue;
- if (creature_ptr->current_floor_ptr->dun_level) {
+ if (is_in_dungeon(creature_ptr)) {
f_ptr = &f_info[g_ptr->feat];
if (max_attempts > 5000) /* Rule 1 */
continue;
/* Refuse to start on anti-teleport grids */
- if (g_ptr->info & (CAVE_ICKY))
+ if (g_ptr->is_icky())
continue;
break;
}
if (max_attempts < 1) /* Should be -1, actually if we failed... */
- return FALSE;
+ return false;
/* Save the new player grid */
creature_ptr->y = y;
creature_ptr->x = x;
- return TRUE;
-}
-
-/*!
- * @brief マスにフロア端用の永久壁を配置する / Set boundary mimic and add "solid" perma-wall
- * @param g_ptr 永久壁を配置したいマス構造体の参照ポインタ
- * @return なし
- */
-void place_bound_perm_wall(player_type *player_ptr, grid_type *g_ptr)
-{
- if (bound_walls_perm) {
- /* Clear boundary mimic */
- g_ptr->mimic = 0;
- } else {
- feature_type *f_ptr = &f_info[g_ptr->feat];
-
- /* Hack -- Decline boundary walls with known treasure */
- if ((has_flag(f_ptr->flags, FF_HAS_GOLD) || has_flag(f_ptr->flags, FF_HAS_ITEM)) && !has_flag(f_ptr->flags, FF_SECRET))
- g_ptr->feat = feat_state(player_ptr, g_ptr->feat, FF_ENSECRET);
-
- /* Set boundary mimic */
- g_ptr->mimic = g_ptr->feat;
- }
-
- /* Add "solid" perma-wall */
- place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
-}
-
-/*!
- * @brief マスに看破済みの罠があるかの判定を行う。 / Return TRUE if the given grid is a known trap
- * @param player_ptr プレーヤーへの参照ポインタ
- * @param g_ptr マス構造体の参照ポインタ
- * @return 看破済みの罠があるならTRUEを返す。
- */
-bool is_known_trap(player_type *player_ptr, grid_type *g_ptr)
-{
- if (!g_ptr->mimic && !cave_has_flag_grid(g_ptr, FF_SECRET) && is_trap(player_ptr, g_ptr->feat))
- return TRUE;
- else
- return FALSE;
+ return true;
}
/*!
bool is_hidden_door(player_type *player_ptr, grid_type *g_ptr)
{
if ((g_ptr->mimic || cave_has_flag_grid(g_ptr, FF_SECRET)) && is_closed_door(player_ptr, g_ptr->feat))
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
/*!
&& (creature_ptr->current_floor_ptr->grid_array[y][xx].info & CAVE_GLOW))
|| (feat_supports_los(get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[yy][x]))
&& (creature_ptr->current_floor_ptr->grid_array[yy][x].info & CAVE_GLOW))) {
- return TRUE;
+ return true;
} else
- return FALSE;
+ return false;
}
/*! 対象座標のマスの照明状態を更新する際の補助処理マクロ */
if (player_has_los_bold((C), (Y), (X))) { \
/* Update the monster */ \
if ((C)->current_floor_ptr->grid_array[(Y)][(X)].m_idx) \
- update_monster((C), (C)->current_floor_ptr->grid_array[(Y)][(X)].m_idx, FALSE); \
+ update_monster((C), (C)->current_floor_ptr->grid_array[(Y)][(X)].m_idx, false); \
\
/* Notice and redraw */ \
note_spot((C), (Y), (X)); \
* @param creature_ptr 視界元のクリーチャー
* @param y 視界先y座標
* @param x 視界先x座標
- * @return なし
*/
void update_local_illumination(player_type *creature_ptr, POSITION y, POSITION x)
{
* @return 視覚に収められていないならTRUEを返す
* @details player_can_see_bold()関数の返り値の否定を返している。
*/
-bool no_lite(player_type *creature_ptr) { return (!player_can_see_bold(creature_ptr, creature_ptr->y, creature_ptr->x)); }
+bool no_lite(player_type *creature_ptr)
+{
+ return (!player_can_see_bold(creature_ptr, creature_ptr->y, creature_ptr->x));
+}
/*
* Place an attr/char pair at the given map coordinate, if legal.
}
}
-/*
- * todo ここにplayer_type を追加した時のコンパイルエラーに対処できなかったので保留
+/*!
+ * @todo ここにplayer_type を追加した時のコンパイルエラーに対処できなかったので保留
* Memorize interesting viewable object/features in the given grid
*
* This function should only be called on "legal" grids.
void note_spot(player_type *player_ptr, POSITION y, POSITION x)
{
grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
- OBJECT_IDX this_o_idx, next_o_idx = 0;
/* Blind players see nothing */
if (player_ptr->blind)
}
/* Hack -- memorize objects */
- for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
+ for (const auto this_o_idx : g_ptr->o_idx_list) {
object_type *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
- next_o_idx = o_ptr->next_o_idx;
/* Memorize objects */
o_ptr->marked |= OM_FOUND;
}
/* Hack -- memorize grids */
- if (!(g_ptr->info & (CAVE_MARK))) {
+ if (!g_ptr->is_mark()) {
/* Feature code (applying "mimic" field) */
feature_type *f_ptr = &f_info[get_feat_mimic(g_ptr)];
{
POSITION x, y;
DIRECTION d;
- int flow_head_grid = 1;
- int flow_tail_grid = 0;
-
- /* Paranoia -- make sure the array is empty */
- if (tmp_pos.n)
- return;
+ floor_type *f_ptr = subject_ptr->current_floor_ptr;
/* The last way-point is on the map */
- if (subject_ptr->running && in_bounds(subject_ptr->current_floor_ptr, flow_y, flow_x)) {
+ if (subject_ptr->running && in_bounds(f_ptr, flow_y, flow_x)) {
/* The way point is in sight - do not update. (Speedup) */
- if (subject_ptr->current_floor_ptr->grid_array[flow_y][flow_x].info & CAVE_VIEW)
+ if (f_ptr->grid_array[flow_y][flow_x].info & CAVE_VIEW)
return;
}
/* Erase all of the current flow information */
- for (y = 0; y < subject_ptr->current_floor_ptr->height; y++) {
- for (x = 0; x < subject_ptr->current_floor_ptr->width; x++) {
- subject_ptr->current_floor_ptr->grid_array[y][x].cost = 0;
- subject_ptr->current_floor_ptr->grid_array[y][x].dist = 0;
+ for (y = 0; y < f_ptr->height; y++) {
+ for (x = 0; x < f_ptr->width; x++) {
+ memset(&f_ptr->grid_array[y][x].costs, 0, sizeof(f_ptr->grid_array[y][x].costs));
+ memset(&f_ptr->grid_array[y][x].dists, 0, sizeof(f_ptr->grid_array[y][x].dists));
}
}
flow_y = subject_ptr->y;
flow_x = subject_ptr->x;
- /* Add the player's grid to the queue */
- tmp_pos.y[0] = subject_ptr->y;
- tmp_pos.x[0] = subject_ptr->x;
-
- /* Now process the queue */
- while (flow_head_grid != flow_tail_grid) {
- int ty, tx;
-
- /* Extract the next entry */
- ty = tmp_pos.y[flow_tail_grid];
- tx = tmp_pos.x[flow_tail_grid];
+ for (int i = 0; i < FLOW_MAX; i++) {
+ // 幅優先探索用のキュー。
+ std::queue<Pos2D> que;
+ que.emplace(subject_ptr->y, subject_ptr->x);
- /* Forget that entry */
- if (++flow_tail_grid == TEMP_MAX)
- flow_tail_grid = 0;
+ /* Now process the queue */
+ while (!que.empty()) {
+ /* Extract the next entry */
+ const auto [ty, tx] = que.front();
+ que.pop();
- /* Add the "children" */
- for (d = 0; d < 8; d++) {
- int old_head = flow_head_grid;
- byte m = subject_ptr->current_floor_ptr->grid_array[ty][tx].cost + 1;
- byte n = subject_ptr->current_floor_ptr->grid_array[ty][tx].dist + 1;
- grid_type *g_ptr;
+ /* Add the "children" */
+ for (d = 0; d < 8; d++) {
+ byte m = subject_ptr->current_floor_ptr->grid_array[ty][tx].costs[i] + 1;
+ byte n = subject_ptr->current_floor_ptr->grid_array[ty][tx].dists[i] + 1;
- /* Child location */
- y = ty + ddy_ddd[d];
- x = tx + ddx_ddd[d];
+ /* Child location */
+ y = ty + ddy_ddd[d];
+ x = tx + ddx_ddd[d];
- /* Ignore player's grid */
- if (player_bold(subject_ptr, y, x))
- continue;
-
- g_ptr = &subject_ptr->current_floor_ptr->grid_array[y][x];
-
- if (is_closed_door(subject_ptr, g_ptr->feat))
- m += 3;
+ /* Ignore player's grid */
+ if (player_bold(subject_ptr, y, x))
+ continue;
- /* Ignore "pre-stamped" entries */
- if (g_ptr->dist != 0 && g_ptr->dist <= n && g_ptr->cost <= m)
- continue;
+ grid_type *g_ptr = &subject_ptr->current_floor_ptr->grid_array[y][x];
- /* Ignore "walls" and "rubble" */
- if (!cave_has_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(subject_ptr, g_ptr->feat))
- continue;
+ if (is_closed_door(subject_ptr, g_ptr->feat))
+ m += 3;
- /* Save the flow cost */
- if (g_ptr->cost == 0 || g_ptr->cost > m)
- g_ptr->cost = m;
- if (g_ptr->dist == 0 || g_ptr->dist > n)
- g_ptr->dist = n;
+ /* Ignore "pre-stamped" entries */
+ if (g_ptr->dists[i] != 0 && g_ptr->dists[i] <= n && g_ptr->costs[i] <= m)
+ continue;
- /* Hack -- limit flow depth */
- if (n == MONSTER_FLOW_DEPTH)
- continue;
+ /* Ignore "walls", "holes" and "rubble" */
+ bool can_move = false;
+ switch (i) {
+ case FLOW_CAN_FLY:
+ can_move = cave_has_flag_grid(g_ptr, FF_MOVE) || cave_has_flag_grid(g_ptr, FF_CAN_FLY);
+ break;
+ default:
+ can_move = cave_has_flag_grid(g_ptr, FF_MOVE);
+ break;
+ }
+
+ if (!can_move && !is_closed_door(subject_ptr, g_ptr->feat))
+ continue;
- /* Enqueue that entry */
- tmp_pos.y[flow_head_grid] = y;
- tmp_pos.x[flow_head_grid] = x;
+ /* Save the flow cost */
+ if (g_ptr->costs[i] == 0 || g_ptr->costs[i] > m)
+ g_ptr->costs[i] = m;
+ if (g_ptr->dists[i] == 0 || g_ptr->dists[i] > n)
+ g_ptr->dists[i] = n;
- /* Advance the queue */
- if (++flow_head_grid == TEMP_MAX)
- flow_head_grid = 0;
+ /* Hack -- limit flow depth */
+ if (n == MONSTER_FLOW_DEPTH)
+ continue;
- /* Hack -- notice overflow by forgetting new entry */
- if (flow_head_grid == flow_tail_grid)
- flow_head_grid = old_head;
+ /* Enqueue that entry */
+ que.emplace(y, x);
+ }
}
}
}
* Take a feature, determine what that feature becomes
* through applying the given action.
*/
-FEAT_IDX feat_state(player_type *player_ptr, FEAT_IDX feat, int action)
+FEAT_IDX feat_state(floor_type *floor_ptr, FEAT_IDX feat, int action)
{
feature_type *f_ptr = &f_info[feat];
int i;
/* Get the new feature */
- floor_type *floor_ptr = player_ptr->current_floor_ptr;
for (i = 0; i < MAX_FEAT_STATES; i++) {
if (f_ptr->state[i].action == action)
return conv_dungeon_feat(floor_ptr, f_ptr->state[i].result);
FEAT_IDX oldfeat = floor_ptr->grid_array[y][x].feat;
/* Get the new feat */
- FEAT_IDX newfeat = feat_state(player_ptr, oldfeat, action);
+ FEAT_IDX newfeat = feat_state(player_ptr->current_floor_ptr, oldfeat, action);
/* No change */
if (newfeat == oldfeat)
if (!(feature_action_flags[action] & FAF_NO_DROP)) {
feature_type *old_f_ptr = &f_info[oldfeat];
feature_type *f_ptr = &f_info[newfeat];
- bool found = FALSE;
+ bool found = false;
/* Handle gold */
if (has_flag(old_f_ptr->flags, FF_HAS_GOLD) && !has_flag(f_ptr->flags, FF_HAS_GOLD)) {
/* Place some gold */
place_gold(player_ptr, y, x);
- found = TRUE;
+ found = true;
}
/* Handle item */
if (has_flag(old_f_ptr->flags, FF_HAS_ITEM) && !has_flag(f_ptr->flags, FF_HAS_ITEM) && (randint0(100) < (15 - floor_ptr->dun_level / 2))) {
/* Place object */
place_object(player_ptr, y, x, 0L);
- found = TRUE;
+ found = true;
}
if (found && current_world_ptr->character_dungeon && player_can_see_bold(player_ptr, y, x)) {
if (has_flag(old_f_ptr->flags, FF_GLASS) && current_world_ptr->character_dungeon) {
project(player_ptr, PROJECT_WHO_GLASS_SHARDS, 1, y, x, MIN(floor_ptr->dun_level, 100) / 4, GF_SHARDS,
- (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP | PROJECT_NO_HANGEKI), -1);
+ (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP | PROJECT_NO_HANGEKI));
}
}
}
g_ptr->info &= ~(CAVE_OBJECT);
g_ptr->mimic = 0;
- if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS) {
+ if (d_info[caster_ptr->dungeon_idx].flags.has(DF::DARKNESS)) {
g_ptr->info &= ~(CAVE_GLOW);
if (!view_torch_grids)
g_ptr->info &= ~(CAVE_MARK);
if (g_ptr->m_idx)
- update_monster(caster_ptr, g_ptr->m_idx, FALSE);
+ update_monster(caster_ptr, g_ptr->m_idx, false);
update_local_illumination(caster_ptr, y, x);
}
lite_spot(caster_ptr, y, x);
}
-/*
- * Return TRUE if there is a mirror on the grid.
- */
-bool is_mirror_grid(grid_type *g_ptr)
-{
- if ((g_ptr->info & CAVE_OBJECT) && has_flag(f_info[g_ptr->mimic].flags, FF_MIRROR))
- return TRUE;
- else
- return FALSE;
-}
-
-/*
- * Return TRUE if there is a rune of protection on the grid.
- */
-bool is_rune_protection_grid(grid_type *g_ptr)
-{
- if ((g_ptr->info & CAVE_OBJECT) && has_flag(f_info[g_ptr->mimic].flags, FF_RUNE_PROTECTION))
- return TRUE;
- else
- return FALSE;
-}
-
-/*
- * Return TRUE if there is a rune of explosion on the grid.
- */
-bool is_rune_explosion_grid(grid_type *g_ptr)
-{
- if ((g_ptr->info & CAVE_OBJECT) && has_flag(f_info[g_ptr->mimic].flags, FF_RUNE_EXPLOSION))
- return TRUE;
- else
- return FALSE;
-}
-
/*!
* @brief 指定されたマスがモンスターのテレポート可能先かどうかを判定する。
* @param player_ptr プレーヤーへの参照ポインタ
/* Require "teleportable" space */
if (!has_flag(f_ptr->flags, FF_TELEPORTABLE))
- return FALSE;
+ return false;
if (g_ptr->m_idx && (g_ptr->m_idx != m_idx))
- return FALSE;
+ return false;
if (player_bold(player_ptr, y, x))
- return FALSE;
+ return false;
/* Hack -- no teleport onto rune of protection */
- if (is_rune_protection_grid(g_ptr))
- return FALSE;
- if (is_rune_explosion_grid(g_ptr))
- return FALSE;
+ if (g_ptr->is_rune_protection())
+ return false;
+ if (g_ptr->is_rune_explosion())
+ return false;
if (!(mode & TELEPORT_PASSIVE)) {
if (!monster_can_cross_terrain(player_ptr, g_ptr->feat, &r_info[m_ptr->r_idx], 0))
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/*!
/* Require "teleportable" space */
if (!has_flag(f_ptr->flags, FF_TELEPORTABLE))
- return FALSE;
+ return false;
/* No magical teleporting into vaults and such */
- if (!(mode & TELEPORT_NONMAGICAL) && (g_ptr->info & CAVE_ICKY))
- return FALSE;
+ if (!(mode & TELEPORT_NONMAGICAL) && g_ptr->is_icky())
+ return false;
if (g_ptr->m_idx && (g_ptr->m_idx != player_ptr->riding))
- return FALSE;
+ return false;
/* don't teleport on a trap. */
if (has_flag(f_ptr->flags, FF_HIT_TRAP))
- return FALSE;
+ return false;
if (!(mode & TELEPORT_PASSIVE)) {
if (!player_can_enter(player_ptr, g_ptr->feat, 0))
- return FALSE;
+ return false;
if (has_flag(f_ptr->flags, FF_WATER) && has_flag(f_ptr->flags, FF_DEEP)) {
if (!player_ptr->levitation && !player_ptr->can_swim)
- return FALSE;
+ return false;
}
if (has_flag(f_ptr->flags, FF_LAVA) && !has_immune_fire(player_ptr) && !is_invuln(player_ptr)) {
/* Always forbid deep lava */
if (has_flag(f_ptr->flags, FF_DEEP))
- return FALSE;
+ return false;
/* Forbid shallow lava when the player don't have levitation */
if (!player_ptr->levitation)
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/*!
* @param feat 地形ID
* @return 開いた地形である場合TRUEを返す / Return TRUE if the given feature is an open door
*/
-bool is_open(player_type *player_ptr, FEAT_IDX feat) { return has_flag(f_info[feat].flags, FF_CLOSE) && (feat != feat_state(player_ptr, feat, FF_CLOSE)); }
+bool is_open(player_type *player_ptr, FEAT_IDX feat)
+{
+ return has_flag(f_info[feat].flags, FF_CLOSE) && (feat != feat_state(player_ptr->current_floor_ptr, feat, FF_CLOSE));
+}
/*!
* @brief プレイヤーが地形踏破可能かを返す
if (has_flag(f_ptr->flags, FF_PATTERN)) {
if (!(mode & CEM_P_CAN_ENTER_PATTERN))
- return FALSE;
+ return false;
}
if (has_flag(f_ptr->flags, FF_CAN_FLY) && creature_ptr->levitation)
- return TRUE;
+ return true;
if (has_flag(f_ptr->flags, FF_CAN_SWIM) && creature_ptr->can_swim)
- return TRUE;
+ return true;
if (has_flag(f_ptr->flags, FF_CAN_PASS) && has_pass_wall(creature_ptr))
- return TRUE;
+ return true;
if (!has_flag(f_ptr->flags, FF_MOVE))
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
void place_grid(player_type *player_ptr, grid_type *g_ptr, grid_bold_type gb_type)
case GB_OUTER_NOPERM: {
feature_type *f_ptr = &f_info[feat_wall_outer];
if (permanent_wall(f_ptr)) {
- g_ptr->feat = (s16b)feat_state(player_ptr, feat_wall_outer, FF_UNPERM);
+ g_ptr->feat = (s16b)feat_state(player_ptr->current_floor_ptr, feat_wall_outer, FF_UNPERM);
} else {
g_ptr->feat = feat_wall_outer;
}
case GB_SOLID_NOPERM: {
feature_type *f_ptr = &f_info[feat_wall_solid];
if ((g_ptr->info & CAVE_VAULT) && permanent_wall(f_ptr))
- g_ptr->feat = (s16b)feat_state(player_ptr, feat_wall_solid, FF_UNPERM);
+ g_ptr->feat = (s16b)feat_state(player_ptr->current_floor_ptr, feat_wall_solid, FF_UNPERM);
else
g_ptr->feat = feat_wall_solid;
g_ptr->info &= ~(CAVE_MASK);
place_grid(player_ptr, g_ptr, gb_type);
}
-void set_cave_feat(floor_type *floor_ptr, POSITION y, POSITION x, FEAT_IDX feature_idx) { floor_ptr->grid_array[y][x].feat = feature_idx; }
+void set_cave_feat(floor_type *floor_ptr, POSITION y, POSITION x, FEAT_IDX feature_idx)
+{
+ floor_ptr->grid_array[y][x].feat = feature_idx;
+}
/*!
- * todo intをenumに変更する
+ * @todo intをenumに変更する
*/
-void add_cave_info(floor_type *floor_ptr, POSITION y, POSITION x, int cave_mask) { floor_ptr->grid_array[y][x].info |= cave_mask; }
+void add_cave_info(floor_type *floor_ptr, POSITION y, POSITION x, int cave_mask)
+{
+ floor_ptr->grid_array[y][x].info |= cave_mask;
+}
/*
* @brief Get feature mimic from f_info[] (applying "mimic" field)
* @param g_ptr グリッドへの参照ポインタ
* @return 地形情報
*/
-FEAT_IDX get_feat_mimic(grid_type *g_ptr) { return (f_info[g_ptr->mimic ? g_ptr->mimic : g_ptr->feat].mimic); }
+FEAT_IDX get_feat_mimic(grid_type *g_ptr)
+{
+ return (f_info[g_ptr->mimic ? g_ptr->mimic : g_ptr->feat].mimic);
+}
/*!
* @brief プレイヤーの周辺9マスに該当する地形がいくつあるかを返す /
POSITION yy = creature_ptr->y + ddy_ddd[d];
POSITION xx = creature_ptr->x + ddx_ddd[d];
g_ptr = &creature_ptr->current_floor_ptr->grid_array[yy][xx];
- if (!(g_ptr->info & (CAVE_MARK)))
+ if (!g_ptr->is_mark())
continue;
feat = get_feat_mimic(g_ptr);
return count;
}
-bool feat_uses_special(FEAT_IDX f_idx) { return has_flag(f_info[(f_idx)].flags, FF_SPECIAL); }
+/*!
+ * @brief マス構造体のspecial要素を利用する地形かどうかを判定する.
+ */
+bool feat_uses_special(FEAT_IDX f_idx)
+{
+ return has_flag(f_info[(f_idx)].flags, FF_SPECIAL);
+}
+
+/*
+ * This function 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.
+ */
+void cave_lite_hack(floor_type *floor_ptr, POSITION y, POSITION x)
+{
+ auto *g_ptr = &floor_ptr->grid_array[y][x];
+ if (g_ptr->is_lite()) {
+ return;
+ }
+
+ g_ptr->info |= CAVE_LITE;
+ floor_ptr->lite_y[floor_ptr->lite_n] = y;
+ floor_ptr->lite_x[floor_ptr->lite_n++] = x;
+}
+
+/*
+ * For delayed visual update
+ */
+void cave_redraw_later(floor_type *floor_ptr, POSITION y, POSITION x)
+{
+ auto *g_ptr = &floor_ptr->grid_array[y][x];
+ if (g_ptr->is_redraw()) {
+ return;
+ }
+
+ g_ptr->info |= CAVE_REDRAW;
+ floor_ptr->redraw_y[floor_ptr->redraw_n] = y;
+ floor_ptr->redraw_x[floor_ptr->redraw_n++] = x;
+}
+
+/*
+ * For delayed visual update
+ */
+void cave_note_and_redraw_later(floor_type *floor_ptr, POSITION y, POSITION x)
+{
+ floor_ptr->grid_array[y][x].info |= CAVE_NOTE;
+ cave_redraw_later(floor_ptr, y, x);
+}
+
+void cave_view_hack(floor_type *floor_ptr, POSITION y, POSITION x)
+{
+ auto *g_ptr = &floor_ptr->grid_array[y][x];
+ if (g_ptr->is_view()) {
+ return;
+ }
+
+ g_ptr->info |= CAVE_VIEW;
+ floor_ptr->view_y[floor_ptr->view_n] = y;
+ floor_ptr->view_x[floor_ptr->view_n] = x;
+ floor_ptr->view_n++;
+}