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"
22 * @brief 洞窟らしい地形 (湖、溶岩、瓦礫、森林)の個数を決める
23 * @param d_ref ダンジョンへの参照
24 * @return briefで定義した個数
26 static int calc_cavern_terrains(const dungeon_type &d_ref)
29 if (d_ref.flags.has(DungeonFeatureType::LAKE_WATER)) {
33 if (d_ref.flags.has(DungeonFeatureType::LAKE_LAVA)) {
37 if (d_ref.flags.has(DungeonFeatureType::LAKE_RUBBLE)) {
41 if (d_ref.flags.has(DungeonFeatureType::LAKE_TREE)) {
48 static bool decide_cavern(const FloorType &floor_ref, const dungeon_type &dungeon_ref, const dun_data_type &dd_ref)
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;
61 * @brief フロアに破壊地形、洞窟、湖、溶岩、森林等を配置する.
63 void gen_caverns_and_lakes(PlayerType *player_ptr, dungeon_type *dungeon_ptr, dun_data_type *dd_ptr)
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);
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;
81 if (!dd_ptr->laketype && (floor.dun_level > 80) && one_in_(count)) {
82 dd_ptr->laketype = LAKE_T_FIRE_VAULT;
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;
94 if (!dd_ptr->laketype && (floor.dun_level > 50) && one_in_(count)) {
95 dd_ptr->laketype = LAKE_T_WATER_VAULT;
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;
107 if (!dd_ptr->laketype && (floor.dun_level > 35) && one_in_(count)) {
108 dd_ptr->laketype = LAKE_T_EARTH_VAULT;
114 if ((floor.dun_level > 5) && dungeon_ptr->flags.has(DungeonFeatureType::LAKE_TREE) && !dd_ptr->laketype) {
115 dd_ptr->laketype = LAKE_T_AIR_VAULT;
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);
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);
131 if (inside_quest(quest_number(floor, floor.dun_level))) {
132 dd_ptr->destroyed = false;
137 * @brief 隣接4マスに存在する通路の数を返す / Count the number of "corridor" grids adjacent to the given grid.
138 * @param y1 基準となるマスのY座標
139 * @param x1 基準となるマスのX座標
141 * @note Assumes "in_bounds(y1, x1)"
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.
147 static int next_to_corr(FloorType *floor_ptr, POSITION y1, POSITION x1)
150 for (int i = 0; i < 4; i++) {
151 POSITION y = y1 + ddy_ddd[i];
152 POSITION x = x1 + ddx_ddd[i];
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()) {
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 まず垂直方向に、次に水平方向に調べる
172 static bool possible_doorway(FloorType *floor_ptr, POSITION y, POSITION x)
174 if (next_to_corr(floor_ptr, y, x) < 2) {
178 if (cave_has_flag_bold(floor_ptr, y - 1, x, TerrainCharacteristics::WALL) && cave_has_flag_bold(floor_ptr, y + 1, x, TerrainCharacteristics::WALL)) {
182 if (cave_has_flag_bold(floor_ptr, y, x - 1, TerrainCharacteristics::WALL) && cave_has_flag_bold(floor_ptr, y, x + 1, TerrainCharacteristics::WALL)) {
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座標
195 void try_door(PlayerType *player_ptr, dt_type *dt_ptr, POSITION y, POSITION x)
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()) {
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);