OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / grid / feature-generator.cpp
1 #include "grid/feature-generator.h"
2 #include "dungeon/dungeon-flag-mask.h"
3 #include "dungeon/dungeon-flag-types.h"
4 #include "dungeon/quest.h"
5 #include "floor/cave.h"
6 #include "floor/dungeon-tunnel-util.h"
7 #include "floor/geometry.h"
8 #include "game-option/cheat-types.h"
9 #include "game-option/game-play-options.h"
10 #include "grid/door.h"
11 #include "grid/feature-flag-types.h"
12 #include "room/lake-types.h"
13 #include "room/rooms-builder.h"
14 #include "system/dungeon-data-definition.h"
15 #include "system/dungeon-info.h"
16 #include "system/floor-type-definition.h"
17 #include "system/grid-type-definition.h"
18 #include "system/player-type-definition.h"
19 #include "wizard/wizard-messages.h"
20
21 /*
22  * @brief 洞窟らしい地形 (湖、溶岩、瓦礫、森林)の個数を決める
23  * @param d_ref ダンジョンへの参照
24  * @return briefで定義した個数
25  */
26 static int calc_cavern_terrains(const dungeon_type &d_ref)
27 {
28     auto count = 0;
29     if (d_ref.flags.has(DungeonFeatureType::LAKE_WATER)) {
30         count += 3;
31     }
32
33     if (d_ref.flags.has(DungeonFeatureType::LAKE_LAVA)) {
34         count += 3;
35     }
36
37     if (d_ref.flags.has(DungeonFeatureType::LAKE_RUBBLE)) {
38         count += 3;
39     }
40
41     if (d_ref.flags.has(DungeonFeatureType::LAKE_TREE)) {
42         count += 3;
43     }
44
45     return count;
46 }
47
48 static bool decide_cavern(const FloorType &floor_ref, const dungeon_type &dungeon_ref, const dun_data_type &dd_ref)
49 {
50     constexpr auto can_become_cavern = 20;
51     auto should_build_cavern = floor_ref.dun_level > can_become_cavern;
52     should_build_cavern &= !dd_ref.empty_level;
53     should_build_cavern &= dungeon_ref.flags.has(DungeonFeatureType::CAVERN);
54     should_build_cavern &= dd_ref.laketype == 0;
55     should_build_cavern &= !dd_ref.destroyed;
56     should_build_cavern &= randint1(1000) < floor_ref.dun_level;
57     return should_build_cavern;
58 }
59
60 /*!
61  * @brief フロアに破壊地形、洞窟、湖、溶岩、森林等を配置する.
62  */
63 void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, dun_data_type *dd_ptr)
64 {
65     const auto &floor = *player_ptr->current_floor_ptr;
66     constexpr auto chance_destroyed = 18;
67     if ((floor.dun_level > 30) && one_in_(chance_destroyed * 2) && small_levels && dungeon_ptr->flags.has(DungeonFeatureType::DESTROY)) {
68         dd_ptr->destroyed = true;
69         build_lake(player_ptr, one_in_(2) ? LAKE_T_CAVE : LAKE_T_EARTH_VAULT);
70     }
71
72     constexpr auto chance_water = 24;
73     if (one_in_(chance_water) && !dd_ptr->empty_level && !dd_ptr->destroyed && dungeon_ptr->flags.has_any_of(DF_LAKE_MASK)) {
74         auto count = calc_cavern_terrains(*dungeon_ptr);
75         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_LAVA)) {
76             if ((floor.dun_level > 80) && (randint0(count) < 2)) {
77                 dd_ptr->laketype = LAKE_T_LAVA;
78             }
79
80             count -= 2;
81             if (!dd_ptr->laketype && (floor.dun_level > 80) && one_in_(count)) {
82                 dd_ptr->laketype = LAKE_T_FIRE_VAULT;
83             }
84
85             count--;
86         }
87
88         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_WATER) && !dd_ptr->laketype) {
89             if ((floor.dun_level > 50) && randint0(count) < 2) {
90                 dd_ptr->laketype = LAKE_T_WATER;
91             }
92
93             count -= 2;
94             if (!dd_ptr->laketype && (floor.dun_level > 50) && one_in_(count)) {
95                 dd_ptr->laketype = LAKE_T_WATER_VAULT;
96             }
97
98             count--;
99         }
100
101         if (dungeon_ptr->flags.has(DungeonFeatureType::LAKE_RUBBLE) && !dd_ptr->laketype) {
102             if ((floor.dun_level > 35) && (randint0(count) < 2)) {
103                 dd_ptr->laketype = LAKE_T_CAVE;
104             }
105
106             count -= 2;
107             if (!dd_ptr->laketype && (floor.dun_level > 35) && one_in_(count)) {
108                 dd_ptr->laketype = LAKE_T_EARTH_VAULT;
109             }
110
111             count--;
112         }
113
114         if ((floor.dun_level > 5) && dungeon_ptr->flags.has(DungeonFeatureType::LAKE_TREE) && !dd_ptr->laketype) {
115             dd_ptr->laketype = LAKE_T_AIR_VAULT;
116         }
117
118         if (dd_ptr->laketype) {
119             msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("湖を生成します。", "Lake on the level."));
120             build_lake(player_ptr, dd_ptr->laketype);
121         }
122     }
123
124     const auto should_build_cavern = decide_cavern(floor, *dungeon_ptr, *dd_ptr);
125     if (should_build_cavern) {
126         dd_ptr->cavern = true;
127         msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("洞窟を生成。", "Cavern on level."));
128         build_cavern(player_ptr);
129     }
130
131     if (inside_quest(quest_number(floor, floor.dun_level))) {
132         dd_ptr->destroyed = false;
133     }
134 }
135
136 /*!
137  * @brief 隣接4マスに存在する通路の数を返す / Count the number of "corridor" grids adjacent to the given grid.
138  * @param y1 基準となるマスのY座標
139  * @param x1 基準となるマスのX座標
140  * @return 通路の数
141  * @note Assumes "in_bounds(y1, x1)"
142  * @details
143  * XXX XXX This routine currently only counts actual "empty floor"\n
144  * grids which are not in rooms.  We might want to also count stairs,\n
145  * open doors, closed doors, etc.
146  */
147 static int next_to_corr(FloorType *floor_ptr, POSITION y1, POSITION x1)
148 {
149     int k = 0;
150     for (int i = 0; i < 4; i++) {
151         POSITION y = y1 + ddy_ddd[i];
152         POSITION x = x1 + ddx_ddd[i];
153         grid_type *g_ptr;
154         g_ptr = &floor_ptr->grid_array[y][x];
155         if (g_ptr->cave_has_flag(TerrainCharacteristics::WALL) || !g_ptr->is_floor() || g_ptr->is_room()) {
156             continue;
157         }
158
159         k++;
160     }
161
162     return k;
163 }
164
165 /*!
166  * @brief ドアを設置可能な地形かを返す / Determine if the given location is "between" two walls, and "next to" two corridor spaces.
167  * @param y 判定を行いたいマスのY座標
168  * @param x 判定を行いたいマスのX座標
169  * @return ドアを設置可能ならばTRUEを返す
170  * @details まず垂直方向に、次に水平方向に調べる
171  */
172 static bool possible_doorway(FloorType *floor_ptr, POSITION y, POSITION x)
173 {
174     if (next_to_corr(floor_ptr, y, x) < 2) {
175         return false;
176     }
177
178     if (cave_has_flag_bold(floor_ptr, y - 1, x, TerrainCharacteristics::WALL) && cave_has_flag_bold(floor_ptr, y + 1, x, TerrainCharacteristics::WALL)) {
179         return true;
180     }
181
182     if (cave_has_flag_bold(floor_ptr, y, x - 1, TerrainCharacteristics::WALL) && cave_has_flag_bold(floor_ptr, y, x + 1, TerrainCharacteristics::WALL)) {
183         return true;
184     }
185
186     return false;
187 }
188
189 /*!
190  * @brief ドアの設置を試みる / Places door at y, x position if at least 2 walls found
191  * @param player_ptr プレイヤーへの参照ポインタ
192  * @param y 設置を行いたいマスのY座標
193  * @param x 設置を行いたいマスのX座標
194  */
195 void try_door(PlayerType *player_ptr, dt_type *dt_ptr, POSITION y, POSITION x)
196 {
197     auto *floor_ptr = player_ptr->current_floor_ptr;
198     if (!in_bounds(floor_ptr, y, x) || cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::WALL) || floor_ptr->grid_array[y][x].is_room()) {
199         return;
200     }
201
202     bool can_place_door = randint0(100) < dt_ptr->dun_tun_jct;
203     can_place_door &= possible_doorway(floor_ptr, y, x);
204     can_place_door &= floor_ptr->get_dungeon_definition().flags.has_not(DungeonFeatureType::NO_DOORS);
205     if (can_place_door) {
206         place_random_door(player_ptr, y, x, false);
207     }
208 }