OSDN Git Service

[Refactor] Grid::has_monster()の定義
[hengbandforosx/hengbandosx.git] / src / grid / grid.cpp
index 88d7bc4..7ee06ef 100644 (file)
@@ -1,4 +1,4 @@
-/*!
+/*!
  * @brief グリッドの実装 / low level dungeon routines -BEN-
  * @date 2013/12/30
  * @author
@@ -34,8 +34,6 @@
 #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 "system/dungeon-info.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/item-entity.h"
+#include "system/monster-entity.h"
+#include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "system/redrawing-flags-updater.h"
+#include "system/terrain-type-definition.h"
 #include "term/gameterm.h"
 #include "term/term-color-types.h"
 #include "timed-effect/player-blindness.h"
@@ -65,9 +65,6 @@
 #include "world/world.h"
 #include <queue>
 
-#define MONSTER_FLOW_DEPTH \
-    32 /*!< 敵のプレイヤーに対する移動道のりの最大値(この値以上は処理を打ち切る) / OPTION: Maximum flow depth when using "MONSTER_FLOW" */
-
 /*!
  * @brief 新規フロアに入りたてのプレイヤーをランダムな場所に配置する / Returns random co-ordinates for player/monster/object
  * @param player_ptr プレイヤーへの参照ポインタ
  */
 bool new_player_spot(PlayerType *player_ptr)
 {
-    POSITION y = 0, x = 0;
-    int max_attempts = 10000;
-
-    grid_type *g_ptr;
-    terrain_type *f_ptr;
-
-    auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto max_attempts = 10000;
+    auto y = 0;
+    auto x = 0;
+    auto &floor = *player_ptr->current_floor_ptr;
     while (max_attempts--) {
         /* Pick a legal spot */
-        y = (POSITION)rand_range(1, floor_ptr->height - 2);
-        x = (POSITION)rand_range(1, floor_ptr->width - 2);
+        y = (POSITION)rand_range(1, floor.height - 2);
+        x = (POSITION)rand_range(1, floor.width - 2);
 
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+        const auto &grid = player_ptr->current_floor_ptr->get_grid({ y, x });
 
         /* Must be a "naked" floor grid */
-        if (g_ptr->m_idx) {
+        if (grid.has_monster()) {
             continue;
         }
-        if (floor_ptr->is_in_dungeon()) {
-            f_ptr = &terrains_info[g_ptr->feat];
+        if (floor.is_in_dungeon()) {
+            const auto &terrain = grid.get_terrain();
 
             if (max_attempts > 5000) /* Rule 1 */
             {
-                if (f_ptr->flags.has_not(FloorFeatureType::FLOOR)) {
+                if (terrain.flags.has_not(TerrainCharacteristics::FLOOR)) {
                     continue;
                 }
             } else /* Rule 2 */
             {
-                if (f_ptr->flags.has_not(FloorFeatureType::MOVE)) {
+                if (terrain.flags.has_not(TerrainCharacteristics::MOVE)) {
                     continue;
                 }
-                if (f_ptr->flags.has(FloorFeatureType::HIT_TRAP)) {
+                if (terrain.flags.has(TerrainCharacteristics::HIT_TRAP)) {
                     continue;
                 }
             }
 
             /* Refuse to start on anti-teleport grids in dungeon */
-            if (f_ptr->flags.has_not(FloorFeatureType::TELEPORTABLE)) {
+            if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
                 continue;
             }
         }
-        if (!player_can_enter(player_ptr, g_ptr->feat, 0)) {
+        if (!player_can_enter(player_ptr, grid.feat, 0)) {
             continue;
         }
-        if (!in_bounds(floor_ptr, y, x)) {
+        if (!in_bounds(&floor, y, x)) {
             continue;
         }
 
         /* Refuse to start on anti-teleport grids */
-        if (g_ptr->is_icky()) {
+        if (grid.is_icky()) {
             continue;
         }
 
@@ -145,16 +139,12 @@ bool new_player_spot(PlayerType *player_ptr)
 /*!
  * @brief マスに隠されたドアがあるかの判定を行う。 / Return TRUE if the given grid is a hidden closed door
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param g_ptr マス構造体の参照ポインタ
+ * @param grid マス構造体の参照ポインタ
  * @return 隠されたドアがあるならTRUEを返す。
  */
-bool is_hidden_door(PlayerType *player_ptr, grid_type *g_ptr)
+bool is_hidden_door(PlayerType *player_ptr, const Grid &grid)
 {
-    if ((g_ptr->mimic || g_ptr->cave_has_flag(FloorFeatureType::SECRET)) && is_closed_door(player_ptr, g_ptr->feat)) {
-        return true;
-    } else {
-        return false;
-    }
+    return (grid.mimic || grid.cave_has_flag(TerrainCharacteristics::SECRET)) && is_closed_door(player_ptr, grid.feat);
 }
 
 /*!
@@ -165,37 +155,43 @@ bool is_hidden_door(PlayerType *player_ptr, grid_type *g_ptr)
  */
 bool check_local_illumination(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    /* Hack -- move towards player */
-    POSITION yy = (y < player_ptr->y) ? (y + 1) : (y > player_ptr->y) ? (y - 1)
-                                                                      : y;
-    POSITION xx = (x < player_ptr->x) ? (x + 1) : (x > player_ptr->x) ? (x - 1)
-                                                                      : x;
-
-    /* Check for "local" illumination */
+    const auto yy = (y < player_ptr->y) ? (y + 1) : (y > player_ptr->y) ? (y - 1)
+                                                                        : y;
+    const auto xx = (x < player_ptr->x) ? (x + 1) : (x > player_ptr->x) ? (x - 1)
+                                                                        : x;
+    const auto *floor_ptr = player_ptr->current_floor_ptr;
+    const auto &grid_yyxx = floor_ptr->grid_array[yy][xx];
+    const auto &grid_yxx = floor_ptr->grid_array[y][xx];
+    const auto &grid_yyx = floor_ptr->grid_array[yy][x];
+    auto is_illuminated = feat_supports_los(grid_yyxx.get_feat_mimic()) && (grid_yyxx.info & CAVE_GLOW);
+    is_illuminated |= feat_supports_los(grid_yxx.get_feat_mimic()) && (grid_yxx.info & CAVE_GLOW);
+    is_illuminated |= feat_supports_los(grid_yyx.get_feat_mimic()) && (grid_yyx.info & CAVE_GLOW);
+    return is_illuminated;
+}
 
-    /* Check for "complex" illumination */
-    auto *floor_ptr = player_ptr->current_floor_ptr;
-    if ((feat_supports_los(floor_ptr->grid_array[yy][xx].get_feat_mimic()) && (floor_ptr->grid_array[yy][xx].info & CAVE_GLOW)) || (feat_supports_los(floor_ptr->grid_array[y][xx].get_feat_mimic()) && (floor_ptr->grid_array[y][xx].info & CAVE_GLOW)) || (feat_supports_los(floor_ptr->grid_array[yy][x].get_feat_mimic()) && (floor_ptr->grid_array[yy][x].info & CAVE_GLOW))) {
-        return true;
-    } else {
-        return false;
+/*!
+ * @brief 対象座標のマスの照明状態を更新する
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param y 更新したいマスのY座標
+ * @param x 更新したいマスのX座標
+ */
+static void update_local_illumination_aux(PlayerType *player_ptr, int y, int x)
+{
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const Pos2D pos(y, x);
+    const auto &grid = floor.get_grid(pos);
+    if (!grid.has_los()) {
+        return;
     }
-}
 
-/*! 対象座標のマスの照明状態を更新する際の補助処理マクロ */
-#define update_local_illumination_aux(C, Y, X)                                                  \
-    {                                                                                           \
-        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); \
-                                                                                                \
-            /* Notice and redraw */                                                             \
-            note_spot((C), (Y), (X));                                                           \
-            lite_spot((C), (Y), (X));                                                           \
-        }                                                                                       \
+    if (grid.has_monster()) {
+        update_monster(player_ptr, grid.m_idx, false);
     }
 
+    note_spot(player_ptr, y, x);
+    lite_spot(player_ptr, y, x);
+}
+
 /*!
  * @brief 指定された座標の照明状態を更新する / Update "local" illumination
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -284,7 +280,7 @@ void print_rel(PlayerType *player_ptr, char c, TERM_COLOR a, POSITION y, POSITIO
 
 void print_bolt_pict(PlayerType *player_ptr, POSITION y, POSITION x, POSITION ny, POSITION nx, AttributeType typ)
 {
-    const auto [a, c] = bolt_pict(y, x, ny, nx, typ);
+    const auto &[a, c] = bolt_pict(y, x, ny, nx, typ);
     print_rel(player_ptr, c, a, ny, nx);
 }
 
@@ -329,7 +325,9 @@ void print_bolt_pict(PlayerType *player_ptr, POSITION y, POSITION x, POSITION ny
  */
 void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    const Pos2D pos(y, x);
+    auto &floor = *player_ptr->current_floor_ptr;
+    auto &grid = floor.get_grid(pos);
 
     /* Blind players see nothing */
     if (player_ptr->effects()->blindness()->is_blind()) {
@@ -337,14 +335,14 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     /* Analyze non-torch-lit grids */
-    if (!(g_ptr->info & (CAVE_LITE | CAVE_MNLT))) {
+    if (!(grid.info & (CAVE_LITE | CAVE_MNLT))) {
         /* Require line of sight to the grid */
-        if (!(g_ptr->info & (CAVE_VIEW))) {
+        if (!(grid.info & (CAVE_VIEW))) {
             return;
         }
 
         /* Require "perma-lite" of the grid */
-        if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
+        if ((grid.info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) {
             /* Not Ninja */
             if (!player_ptr->see_nocto) {
                 return;
@@ -353,54 +351,53 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
     }
 
     /* Hack -- memorize objects */
-    for (const auto this_o_idx : g_ptr->o_idx_list) {
-        auto *o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
-
-        /* Memorize objects */
-        o_ptr->marked |= OM_FOUND;
+    for (const auto this_o_idx : grid.o_idx_list) {
+        auto &item = floor.o_list[this_o_idx];
+        item.marked.set(OmType::FOUND);
+        RedrawingFlagsUpdater::get_instance().set_flag(SubWindowRedrawingFlag::FOUND_ITEMS);
     }
 
     /* Hack -- memorize grids */
-    if (!g_ptr->is_mark()) {
+    if (!grid.is_mark()) {
         /* Feature code (applying "mimic" field) */
-        auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
+        const auto &terrain = grid.get_terrain_mimic();
 
         /* Memorize some "boring" grids */
-        if (f_ptr->flags.has_not(FloorFeatureType::REMEMBER)) {
+        if (terrain.flags.has_not(TerrainCharacteristics::REMEMBER)) {
             /* Option -- memorize all torch-lit floors */
-            if (view_torch_grids && ((g_ptr->info & (CAVE_LITE | CAVE_MNLT)) || player_ptr->see_nocto)) {
-                g_ptr->info |= (CAVE_MARK);
+            if (view_torch_grids && ((grid.info & (CAVE_LITE | CAVE_MNLT)) || player_ptr->see_nocto)) {
+                grid.info |= (CAVE_MARK);
             }
 
             /* Option -- memorize all perma-lit floors */
-            else if (view_perma_grids && ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW)) {
-                g_ptr->info |= (CAVE_MARK);
+            else if (view_perma_grids && ((grid.info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW)) {
+                grid.info |= (CAVE_MARK);
             }
         }
 
         /* Memorize normal grids */
-        else if (f_ptr->flags.has(FloorFeatureType::LOS)) {
-            g_ptr->info |= (CAVE_MARK);
+        else if (terrain.flags.has(TerrainCharacteristics::LOS)) {
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize torch-lit walls */
-        else if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) {
-            g_ptr->info |= (CAVE_MARK);
+        else if (grid.info & (CAVE_LITE | CAVE_MNLT)) {
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize walls seen by noctovision of Ninja */
         else if (player_ptr->see_nocto) {
-            g_ptr->info |= (CAVE_MARK);
+            grid.info |= (CAVE_MARK);
         }
 
         /* Memorize certain non-torch-lit wall grids */
         else if (check_local_illumination(player_ptr, y, x)) {
-            g_ptr->info |= (CAVE_MARK);
+            grid.info |= (CAVE_MARK);
         }
     }
 
     /* Memorize terrain of the grid */
-    g_ptr->info |= (CAVE_KNOWN);
+    grid.info |= (CAVE_KNOWN);
 }
 
 /*
@@ -410,7 +407,6 @@ void note_spot(PlayerType *player_ptr, POSITION y, POSITION x)
  */
 void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
 {
-    /* Redraw if on screen */
     if (panel_contains(y, x) && in_bounds2(player_ptr->current_floor_ptr, y, x)) {
         TERM_COLOR a;
         char c;
@@ -418,8 +414,6 @@ void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
         char tc;
 
         map_info(player_ptr, y, x, &a, &c, &ta, &tc);
-
-        /* Hack -- fake monochrome */
         if (!use_graphics) {
             if (w_ptr->timewalk_m_idx) {
                 a = TERM_DARK;
@@ -430,11 +424,12 @@ void lite_spot(PlayerType *player_ptr, POSITION y, POSITION x)
             }
         }
 
-        /* Hack -- Queue it */
         term_queue_bigchar(panel_col_of(x), y - panel_row_prt, a, c, ta, tc);
-
-        /* Update sub-windows */
-        player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
+        static constexpr auto flags = {
+            SubWindowRedrawingFlag::OVERHEAD,
+            SubWindowRedrawingFlag::DUNGEON,
+        };
+        RedrawingFlagsUpdater::get_instance().set_flags(flags);
     }
 }
 
@@ -667,23 +662,22 @@ static POSITION flow_y = 0;
  */
 void update_flow(PlayerType *player_ptr)
 {
-    POSITION x, y;
-    DIRECTION d;
-    floor_type *f_ptr = player_ptr->current_floor_ptr;
+    auto &floor = *player_ptr->current_floor_ptr;
 
     /* The last way-point is on the map */
-    if (player_ptr->running && in_bounds(f_ptr, flow_y, flow_x)) {
+    if (player_ptr->running && in_bounds(&floor, flow_y, flow_x)) {
         /* The way point is in sight - do not update.  (Speedup) */
-        if (f_ptr->grid_array[flow_y][flow_x].info & CAVE_VIEW) {
+        if (floor.grid_array[flow_y][flow_x].info & CAVE_VIEW) {
             return;
         }
     }
 
     /* Erase all of the current flow information */
-    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));
+    for (auto y = 0; y < floor.height; y++) {
+        for (auto x = 0; x < floor.width; x++) {
+            auto &grid = floor.grid_array[y][x];
+            grid.reset_costs();
+            grid.reset_dists();
         }
     }
 
@@ -691,72 +685,68 @@ void update_flow(PlayerType *player_ptr)
     flow_y = player_ptr->y;
     flow_x = player_ptr->x;
 
-    for (int i = 0; i < FLOW_MAX; i++) {
+    for (auto i = 0; i < FLOW_MAX; i++) {
         // 幅優先探索用のキュー。
         std::queue<Pos2D> que;
         que.emplace(player_ptr->y, player_ptr->x);
 
         /* Now process the queue */
         while (!que.empty()) {
-            /* Extract the next entry */
-            const auto [ty, tx] = que.front();
+            const Pos2D pos = std::move(que.front());
             que.pop();
+            const auto &grid = floor.get_grid(pos);
 
             /* Add the "children" */
-            for (d = 0; d < 8; d++) {
-                byte m = player_ptr->current_floor_ptr->grid_array[ty][tx].costs[i] + 1;
-                byte n = player_ptr->current_floor_ptr->grid_array[ty][tx].dists[i] + 1;
-
-                /* Child location */
-                y = ty + ddy_ddd[d];
-                x = tx + ddx_ddd[d];
+            for (auto d = 0; d < 8; d++) {
+                byte m = grid.costs[i] + 1;
+                byte n = grid.dists[i] + 1;
+                const Pos2D pos_neighbor(pos.y + ddy_ddd[d], pos.x + ddx_ddd[d]);
 
                 /* Ignore player's grid */
-                if (player_bold(player_ptr, y, x)) {
+                if (player_ptr->is_located_at(pos_neighbor)) {
                     continue;
                 }
 
-                auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-
-                if (is_closed_door(player_ptr, g_ptr->feat)) {
+                auto &grid_neighbor = floor.get_grid(pos_neighbor);
+                if (is_closed_door(player_ptr, grid_neighbor.feat)) {
                     m += 3;
                 }
 
                 /* Ignore "pre-stamped" entries */
-                if (g_ptr->dists[i] != 0 && g_ptr->dists[i] <= n && g_ptr->costs[i] <= m) {
+                if ((grid_neighbor.dists[i] != 0) && (grid_neighbor.dists[i] <= n) && (grid_neighbor.costs[i] <= m)) {
                     continue;
                 }
 
                 /* Ignore "walls", "holes" and "rubble" */
-                bool can_move = false;
+                auto can_move = false;
                 switch (i) {
                 case FLOW_CAN_FLY:
-                    can_move = g_ptr->cave_has_flag(FloorFeatureType::MOVE) || g_ptr->cave_has_flag(FloorFeatureType::CAN_FLY);
+                    can_move = grid_neighbor.cave_has_flag(TerrainCharacteristics::MOVE) || grid_neighbor.cave_has_flag(TerrainCharacteristics::CAN_FLY);
                     break;
                 default:
-                    can_move = g_ptr->cave_has_flag(FloorFeatureType::MOVE);
+                    can_move = grid_neighbor.cave_has_flag(TerrainCharacteristics::MOVE);
                     break;
                 }
 
-                if (!can_move && !is_closed_door(player_ptr, g_ptr->feat)) {
+                if (!can_move && !is_closed_door(player_ptr, grid_neighbor.feat)) {
                     continue;
                 }
 
                 /* Save the flow cost */
-                if (g_ptr->costs[i] == 0 || g_ptr->costs[i] > m) {
-                    g_ptr->costs[i] = m;
+                if (grid_neighbor.costs[i] == 0 || (grid_neighbor.costs[i] > m)) {
+                    grid_neighbor.costs[i] = m;
                 }
-                if (g_ptr->dists[i] == 0 || g_ptr->dists[i] > n) {
-                    g_ptr->dists[i] = n;
+                if (grid_neighbor.dists[i] == 0 || (grid_neighbor.dists[i] > n)) {
+                    grid_neighbor.dists[i] = n;
                 }
 
-                /* Hack -- limit flow depth */
-                if (n == MONSTER_FLOW_DEPTH) {
+                // 敵のプレイヤーに対する移動道のりの最大値(この値以上は処理を打ち切る).
+                constexpr auto monster_flow_depth = 32;
+                if (n == monster_flow_depth) {
                     continue;
                 }
 
-                /* Enqueue that entry */
-                que.emplace(y, x);
+                que.emplace(pos_neighbor);
             }
         }
     }
@@ -766,30 +756,29 @@ void update_flow(PlayerType *player_ptr)
  * Take a feature, determine what that feature becomes
  * through applying the given action.
  */
-FEAT_IDX feat_state(floor_type *floor_ptr, FEAT_IDX feat, FloorFeatureType action)
+FEAT_IDX feat_state(const FloorType *floor_ptr, FEAT_IDX feat, TerrainCharacteristics action)
 {
-    auto *f_ptr = &terrains_info[feat];
-    int i;
+    const auto &terrain = TerrainList::get_instance()[feat];
 
     /* Get the new feature */
-    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);
+    for (auto i = 0; i < MAX_FEAT_STATES; i++) {
+        if (terrain.state[i].action == action) {
+            return conv_dungeon_feat(floor_ptr, terrain.state[i].result);
         }
     }
 
-    if (f_ptr->flags.has(FloorFeatureType::PERMANENT)) {
+    if (terrain.flags.has(TerrainCharacteristics::PERMANENT)) {
         return feat;
     }
 
-    return (feature_action_flags[enum2i(action)] & FAF_DESTROY) ? conv_dungeon_feat(floor_ptr, f_ptr->destroyed) : feat;
+    return (terrain_action_flags[enum2i(action)] & FAF_DESTROY) ? conv_dungeon_feat(floor_ptr, terrain.destroyed) : feat;
 }
 
 /*
  * Takes a location and action and changes the feature at that
  * location through applying the given action.
  */
-void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, FloorFeatureType action)
+void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, TerrainCharacteristics action)
 {
     /* Set old feature */
     auto *floor_ptr = player_ptr->current_floor_ptr;
@@ -805,21 +794,21 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, FloorFeatur
 
     /* Set the new feature */
     cave_set_feat(player_ptr, y, x, newfeat);
-
-    if (!(feature_action_flags[enum2i(action)] & FAF_NO_DROP)) {
-        terrain_type *old_f_ptr = &terrains_info[oldfeat];
-        auto *f_ptr = &terrains_info[newfeat];
+    const auto &terrains = TerrainList::get_instance();
+    if (!(terrain_action_flags[enum2i(action)] & FAF_NO_DROP)) {
+        const auto &old_terrain = terrains[oldfeat];
+        const auto &new_terrain = terrains[newfeat];
         bool found = false;
 
         /* Handle gold */
-        if (old_f_ptr->flags.has(FloorFeatureType::HAS_GOLD) && f_ptr->flags.has_not(FloorFeatureType::HAS_GOLD)) {
+        if (old_terrain.flags.has(TerrainCharacteristics::HAS_GOLD) && new_terrain.flags.has_not(TerrainCharacteristics::HAS_GOLD)) {
             /* Place some gold */
             place_gold(player_ptr, y, x);
             found = true;
         }
 
         /* Handle item */
-        if (old_f_ptr->flags.has(FloorFeatureType::HAS_ITEM) && f_ptr->flags.has_not(FloorFeatureType::HAS_ITEM) && (randint0(100) < (15 - floor_ptr->dun_level / 2))) {
+        if (old_terrain.flags.has(TerrainCharacteristics::HAS_ITEM) && new_terrain.flags.has_not(TerrainCharacteristics::HAS_ITEM) && (randint0(100) < (15 - floor_ptr->dun_level / 2))) {
             /* Place object */
             place_object(player_ptr, y, x, 0L);
             found = true;
@@ -830,10 +819,9 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, FloorFeatur
         }
     }
 
-    if (feature_action_flags[enum2i(action)] & FAF_CRASH_GLASS) {
-        terrain_type *old_f_ptr = &terrains_info[oldfeat];
-
-        if (old_f_ptr->flags.has(FloorFeatureType::GLASS) && w_ptr->character_dungeon) {
+    if (terrain_action_flags[enum2i(action)] & FAF_CRASH_GLASS) {
+        const auto &old_terrain = terrains[oldfeat];
+        if (old_terrain.flags.has(TerrainCharacteristics::GLASS) && w_ptr->character_dungeon) {
             project(player_ptr, PROJECT_WHO_GLASS_SHARDS, 1, y, x, std::min(floor_ptr->dun_level, 100) / 4, AttributeType::SHARDS,
                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP | PROJECT_NO_HANGEKI));
         }
@@ -851,37 +839,37 @@ void cave_alter_feat(PlayerType *player_ptr, POSITION y, POSITION x, FloorFeatur
  */
 bool cave_monster_teleportable_bold(PlayerType *player_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, teleport_flags mode)
 {
-    auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    const auto &floor = *player_ptr->current_floor_ptr;
+    const auto &grid = floor.get_grid(pos);
+    const auto &terrain = grid.get_terrain();
 
     /* Require "teleportable" space */
-    if (f_ptr->flags.has_not(FloorFeatureType::TELEPORTABLE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
         return false;
     }
 
-    if (g_ptr->m_idx && (g_ptr->m_idx != m_idx)) {
+    if (grid.has_monster() && (grid.m_idx != m_idx)) {
         return false;
     }
-    if (player_bold(player_ptr, y, x)) {
+    if (player_ptr->is_located_at(pos)) {
         return false;
     }
 
     /* Hack -- no teleport onto rune of protection */
-    if (g_ptr->is_rune_protection()) {
+    if (grid.is_rune_protection()) {
         return false;
     }
-    if (g_ptr->is_rune_explosion()) {
+    if (grid.is_rune_explosion()) {
         return false;
     }
 
-    if (!(mode & TELEPORT_PASSIVE)) {
-        if (!monster_can_cross_terrain(player_ptr, g_ptr->feat, &monraces_info[m_ptr->r_idx], 0)) {
-            return false;
-        }
+    if (any_bits(mode, TELEPORT_PASSIVE)) {
+        return true;
     }
 
-    return true;
+    const auto &monster = floor.m_list[m_idx];
+    return monster_can_cross_terrain(player_ptr, grid.feat, &monster.get_monrace(), 0);
 }
 
 /*!
@@ -894,53 +882,54 @@ bool cave_monster_teleportable_bold(PlayerType *player_ptr, MONSTER_IDX m_idx, P
  */
 bool cave_player_teleportable_bold(PlayerType *player_ptr, POSITION y, POSITION x, teleport_flags mode)
 {
-    auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
-    auto *f_ptr = &terrains_info[g_ptr->feat];
+    const Pos2D pos(y, x);
+    const auto &grid = player_ptr->current_floor_ptr->get_grid(pos);
+    const auto &terrain = grid.get_terrain();
 
     /* Require "teleportable" space */
-    if (f_ptr->flags.has_not(FloorFeatureType::TELEPORTABLE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::TELEPORTABLE)) {
         return false;
     }
 
     /* No magical teleporting into vaults and such */
-    if (!(mode & TELEPORT_NONMAGICAL) && g_ptr->is_icky()) {
+    if (!(mode & TELEPORT_NONMAGICAL) && grid.is_icky()) {
         return false;
     }
 
-    if (g_ptr->m_idx && (g_ptr->m_idx != player_ptr->riding)) {
+    if (grid.has_monster() && (grid.m_idx != player_ptr->riding)) {
         return false;
     }
 
     /* don't teleport on a trap. */
-    if (f_ptr->flags.has(FloorFeatureType::HIT_TRAP)) {
+    if (terrain.flags.has(TerrainCharacteristics::HIT_TRAP)) {
         return false;
     }
 
-    if (!(mode & TELEPORT_PASSIVE)) {
-        if (!player_can_enter(player_ptr, g_ptr->feat, 0)) {
-            return false;
-        }
+    if (any_bits(mode, TELEPORT_PASSIVE)) {
+        return true;
+    }
 
-        if (f_ptr->flags.has_all_of({ FloorFeatureType::WATER, FloorFeatureType::DEEP })) {
-            if (!player_ptr->levitation && !player_ptr->can_swim) {
-                return false;
-            }
+    if (!player_can_enter(player_ptr, grid.feat, 0)) {
+        return false;
+    }
+
+    if (terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP })) {
+        if (!player_ptr->levitation && !player_ptr->can_swim) {
+            return false;
         }
+    }
 
-        if (f_ptr->flags.has(FloorFeatureType::LAVA) && !has_immune_fire(player_ptr) && !is_invuln(player_ptr)) {
-            /* Always forbid deep lava */
-            if (f_ptr->flags.has(FloorFeatureType::DEEP)) {
-                return false;
-            }
+    if (terrain.flags.has_not(TerrainCharacteristics::LAVA) || has_immune_fire(player_ptr) || is_invuln(player_ptr)) {
+        return true;
+    }
 
-            /* Forbid shallow lava when the player don't have levitation */
-            if (!player_ptr->levitation) {
-                return false;
-            }
-        }
+    /* Always forbid deep lava */
+    if (terrain.flags.has(TerrainCharacteristics::DEEP)) {
+        return false;
     }
 
-    return true;
+    /* Forbid shallow lava when the player don't have levitation */
+    return player_ptr->levitation != 0;
 }
 
 /*!
@@ -951,7 +940,8 @@ bool cave_player_teleportable_bold(PlayerType *player_ptr, POSITION y, POSITION
  */
 bool is_open(PlayerType *player_ptr, FEAT_IDX feat)
 {
-    return terrains_info[feat].flags.has(FloorFeatureType::CLOSE) && (feat != feat_state(player_ptr->current_floor_ptr, feat, FloorFeatureType::CLOSE));
+    const auto &terrain = TerrainList::get_instance()[feat];
+    return terrain.flags.has(TerrainCharacteristics::CLOSE) && (feat != feat_state(player_ptr->current_floor_ptr, feat, TerrainCharacteristics::CLOSE));
 }
 
 /*!
@@ -962,47 +952,46 @@ bool is_open(PlayerType *player_ptr, FEAT_IDX feat)
  */
 bool player_can_enter(PlayerType *player_ptr, FEAT_IDX feature, BIT_FLAGS16 mode)
 {
-    auto *f_ptr = &terrains_info[feature];
-
+    const auto &terrain = TerrainList::get_instance()[feature];
     if (player_ptr->riding) {
         return monster_can_cross_terrain(
             player_ptr, feature, &monraces_info[player_ptr->current_floor_ptr->m_list[player_ptr->riding].r_idx], mode | CEM_RIDING);
     }
 
-    if (f_ptr->flags.has(FloorFeatureType::PATTERN)) {
+    if (terrain.flags.has(TerrainCharacteristics::PATTERN)) {
         if (!(mode & CEM_P_CAN_ENTER_PATTERN)) {
             return false;
         }
     }
 
-    if (f_ptr->flags.has(FloorFeatureType::CAN_FLY) && player_ptr->levitation) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_FLY) && player_ptr->levitation) {
         return true;
     }
-    if (f_ptr->flags.has(FloorFeatureType::CAN_SWIM) && player_ptr->can_swim) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_SWIM) && player_ptr->can_swim) {
         return true;
     }
-    if (f_ptr->flags.has(FloorFeatureType::CAN_PASS) && has_pass_wall(player_ptr)) {
+    if (terrain.flags.has(TerrainCharacteristics::CAN_PASS) && has_pass_wall(player_ptr)) {
         return true;
     }
 
-    if (f_ptr->flags.has_not(FloorFeatureType::MOVE)) {
+    if (terrain.flags.has_not(TerrainCharacteristics::MOVE)) {
         return false;
     }
 
     return true;
 }
 
-void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type)
+void place_grid(PlayerType *player_ptr, Grid *g_ptr, grid_bold_type gb_type)
 {
     switch (gb_type) {
     case GB_FLOOR: {
-        g_ptr->feat = feat_ground_type[randint0(100)];
+        g_ptr->feat = rand_choice(feat_ground_type);
         g_ptr->info &= ~(CAVE_MASK);
         g_ptr->info |= CAVE_FLOOR;
         break;
     }
     case GB_EXTRA: {
-        g_ptr->feat = feat_wall_type[randint0(100)];
+        g_ptr->feat = rand_choice(feat_wall_type);
         g_ptr->info &= ~(CAVE_MASK);
         g_ptr->info |= CAVE_EXTRA;
         break;
@@ -1032,9 +1021,9 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
         break;
     }
     case GB_OUTER_NOPERM: {
-        auto *f_ptr = &terrains_info[feat_wall_outer];
-        if (permanent_wall(f_ptr)) {
-            g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_outer, FloorFeatureType::UNPERM);
+        const auto &terrain = TerrainList::get_instance()[feat_wall_outer];
+        if (terrain.is_permanent_wall()) {
+            g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_outer, TerrainCharacteristics::UNPERM);
         } else {
             g_ptr->feat = feat_wall_outer;
         }
@@ -1056,9 +1045,9 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
         break;
     }
     case GB_SOLID_NOPERM: {
-        auto *f_ptr = &terrains_info[feat_wall_solid];
-        if ((g_ptr->info & CAVE_VAULT) && permanent_wall(f_ptr)) {
-            g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_solid, FloorFeatureType::UNPERM);
+        const auto &terrain = TerrainList::get_instance()[feat_wall_solid];
+        if ((g_ptr->info & CAVE_VAULT) && terrain.is_permanent_wall()) {
+            g_ptr->feat = (int16_t)feat_state(player_ptr->current_floor_ptr, feat_wall_solid, TerrainCharacteristics::UNPERM);
         } else {
             g_ptr->feat = feat_wall_solid;
         }
@@ -1071,7 +1060,7 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
         return;
     }
 
-    if (g_ptr->m_idx > 0) {
+    if (g_ptr->has_monster()) {
         delete_monster_idx(player_ptr, g_ptr->m_idx);
     }
 }
@@ -1079,64 +1068,57 @@ void place_grid(PlayerType *player_ptr, grid_type *g_ptr, grid_bold_type gb_type
 /*!
  * モンスターにより照明が消されている地形か否かを判定する。 / Is this grid "darkened" by monster?
  * @param player_ptr プレイヤーへの参照ポインタ
- * @param g_ptr グリッドへの参照ポインタ
+ * @param grid グリッドへの参照ポインタ
  * @return 照明が消されている地形ならばTRUE
  */
-bool darkened_grid(PlayerType *player_ptr, grid_type *g_ptr)
+bool darkened_grid(PlayerType *player_ptr, Grid *g_ptr)
 {
     return ((g_ptr->info & (CAVE_VIEW | CAVE_LITE | CAVE_MNLT | CAVE_MNDK)) == (CAVE_VIEW | CAVE_MNDK)) && !player_ptr->see_nocto;
 }
 
 void place_bold(PlayerType *player_ptr, POSITION y, POSITION x, grid_bold_type gb_type)
 {
-    grid_type *const g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
+    Grid *const g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
     place_grid(player_ptr, g_ptr, gb_type);
 }
 
-void set_cave_feat(floor_type *floor_ptr, POSITION y, POSITION x, FEAT_IDX feature_idx)
+void set_cave_feat(FloorType *floor_ptr, POSITION y, POSITION x, FEAT_IDX feature_idx)
 {
     floor_ptr->grid_array[y][x].feat = feature_idx;
 }
 
 /*!
- * @brief プレイヤーの周辺9マスに該当する地形がいくつあるかを返す /
- * Attempt to open the given chest at the given location
- * @param y 該当する地形の中から1つのY座標を返す参照ポインタ
- * @param x 該当する地形の中から1つのX座標を返す参照ポインタ
+ * @brief プレイヤーの周辺9マスに該当する地形がいくつあるかを返す
+ * @param player_ptr プレイヤーへの参照ポインタ
  * @param test 地形条件を判定するための関数ポインタ
  * @param under TRUEならばプレイヤーの直下の座標も走査対象にする
- * @return 該当する地形の数
- * @details Return the number of features around (or under) the character.
- * Usually look for doors and floor traps.
+ * @return 該当する地形の数と、該当する地形の中から1つの座標
  */
-int count_dt(PlayerType *player_ptr, POSITION *y, POSITION *x, bool (*test)(PlayerType *, FEAT_IDX), bool under)
+std::pair<int, Pos2D> count_dt(PlayerType *player_ptr, bool (*test)(PlayerType *, short), bool under)
 {
-    int count = 0;
-    for (DIRECTION d = 0; d < 9; d++) {
-        grid_type *g_ptr;
-        FEAT_IDX feat;
+    auto count = 0;
+    Pos2D pos(0, 0);
+    for (auto d = 0; d < 9; d++) {
         if ((d == 8) && !under) {
             continue;
         }
 
-        POSITION yy = player_ptr->y + ddy_ddd[d];
-        POSITION xx = player_ptr->x + ddx_ddd[d];
-        g_ptr = &player_ptr->current_floor_ptr->grid_array[yy][xx];
-        if (!g_ptr->is_mark()) {
+        Pos2D pos_neighbor(player_ptr->y + ddy_ddd[d], player_ptr->x + ddx_ddd[d]);
+        const auto &grid = player_ptr->current_floor_ptr->get_grid(pos_neighbor);
+        if (!grid.is_mark()) {
             continue;
         }
 
-        feat = g_ptr->get_feat_mimic();
+        const auto feat = grid.get_feat_mimic();
         if (!((*test)(player_ptr, feat))) {
             continue;
         }
 
         ++count;
-        *y = yy;
-        *x = xx;
+        pos = pos_neighbor;
     }
 
-    return count;
+    return { count, pos };
 }
 
 /*!
@@ -1144,7 +1126,7 @@ int count_dt(PlayerType *player_ptr, POSITION *y, POSITION *x, bool (*test)(Play
  */
 bool feat_uses_special(FEAT_IDX f_idx)
 {
-    return terrains_info[(f_idx)].flags.has(FloorFeatureType::SPECIAL);
+    return TerrainList::get_instance()[(f_idx)].flags.has(TerrainCharacteristics::SPECIAL);
 }
 
 /*
@@ -1153,7 +1135,7 @@ bool feat_uses_special(FEAT_IDX f_idx)
  * 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)
+void cave_lite_hack(FloorType *floor_ptr, POSITION y, POSITION x)
 {
     auto *g_ptr = &floor_ptr->grid_array[y][x];
     if (g_ptr->is_lite()) {
@@ -1168,7 +1150,7 @@ void cave_lite_hack(floor_type *floor_ptr, POSITION y, POSITION x)
 /*
  * For delayed visual update
  */
-void cave_redraw_later(floor_type *floor_ptr, POSITION y, POSITION x)
+void cave_redraw_later(FloorType *floor_ptr, POSITION y, POSITION x)
 {
     auto *g_ptr = &floor_ptr->grid_array[y][x];
     if (g_ptr->is_redraw()) {
@@ -1183,13 +1165,13 @@ void cave_redraw_later(floor_type *floor_ptr, POSITION y, POSITION x)
 /*
  * For delayed visual update
  */
-void cave_note_and_redraw_later(floor_type *floor_ptr, POSITION y, POSITION x)
+void cave_note_and_redraw_later(FloorType *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)
+void cave_view_hack(FloorType *floor_ptr, POSITION y, POSITION x)
 {
     auto *g_ptr = &floor_ptr->grid_array[y][x];
     if (g_ptr->is_view()) {