1 #include "floor/cave-generator.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "dungeon/quest-monster-placer.h"
5 #include "floor/dungeon-tunnel-util.h"
6 #include "floor/floor-allocation-types.h"
7 #include "floor/floor-streams.h"
8 #include "floor/geometry.h"
9 #include "floor/object-allocator.h"
10 #include "floor/tunnel-generator.h"
11 #include "floor/wild.h"
12 #include "game-option/birth-options.h"
13 #include "game-option/cheat-types.h"
14 #include "game-option/game-play-options.h"
15 #include "grid/door.h"
16 #include "grid/feature-generator.h"
17 #include "grid/feature.h"
18 #include "grid/grid.h"
19 #include "monster-floor/monster-generator.h"
20 #include "monster-floor/monster-summon.h"
21 #include "monster-floor/place-monster-types.h"
22 #include "monster/monster-util.h"
23 #include "room/lake-types.h"
24 #include "room/room-generator.h"
25 #include "room/rooms-maze-vault.h"
26 #include "system/dungeon-data-definition.h"
27 #include "system/floor-type-definition.h"
28 #include "system/grid-type-definition.h"
29 #include "system/player-type-definition.h"
30 #include "util/bit-flags-calculator.h"
31 #include "wizard/wizard-messages.h"
33 static void reset_lite_area(floor_type *floor_ptr)
35 floor_ptr->lite_n = 0;
36 floor_ptr->mon_lite_n = 0;
37 floor_ptr->redraw_n = 0;
38 floor_ptr->view_n = 0;
41 static dun_data_type *initialize_dun_data_type(dun_data_type *dd_ptr, concptr *why)
43 dd_ptr->destroyed = false;
44 dd_ptr->empty_level = false;
45 dd_ptr->cavern = false;
51 static void check_arena_floor(player_type *player_ptr, dun_data_type *dd_ptr)
53 floor_type *floor_ptr = player_ptr->current_floor_ptr;
54 if (!dd_ptr->empty_level) {
55 for (POSITION y = 0; y < floor_ptr->height; y++)
56 for (POSITION x = 0; x < floor_ptr->width; x++)
57 place_bold(player_ptr, y, x, GB_EXTRA);
62 for (POSITION y = 0; y < floor_ptr->height; y++)
63 for (POSITION x = 0; x < floor_ptr->width; x++)
64 place_bold(player_ptr, y, x, GB_FLOOR);
66 for (POSITION x = 0; x < floor_ptr->width; x++) {
67 place_bold(player_ptr, 0, x, GB_EXTRA);
68 place_bold(player_ptr, floor_ptr->height - 1, x, GB_EXTRA);
71 for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
72 place_bold(player_ptr, y, 0, GB_EXTRA);
73 place_bold(player_ptr, y, floor_ptr->width - 1, GB_EXTRA);
77 static void place_cave_contents(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
79 floor_type *floor_ptr = player_ptr->current_floor_ptr;
80 if (floor_ptr->dun_level == 1)
81 while (one_in_(DUN_MOS_DEN))
82 place_trees(player_ptr, randint1(floor_ptr->width - 2), randint1(floor_ptr->height - 2));
84 if (dd_ptr->destroyed)
85 destroy_level(player_ptr);
87 if (has_river_flag(d_ptr) && one_in_(3) && (randint1(floor_ptr->dun_level) > 5))
88 add_river(floor_ptr, dd_ptr);
90 for (int i = 0; i < dd_ptr->cent_n; i++) {
92 int pick = rand_range(0, i);
93 ty = dd_ptr->cent[i].y;
94 tx = dd_ptr->cent[i].x;
95 dd_ptr->cent[i].y = dd_ptr->cent[pick].y;
96 dd_ptr->cent[i].x = dd_ptr->cent[pick].x;
97 dd_ptr->cent[pick].y = ty;
98 dd_ptr->cent[pick].x = tx;
102 static bool decide_tunnel_planned_site(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr, int i)
106 if (randint1(player_ptr->current_floor_ptr->dun_level) > d_ptr->tunnel_percent)
107 (void)build_tunnel2(player_ptr, dd_ptr, dd_ptr->cent[i].x, dd_ptr->cent[i].y, dd_ptr->tunnel_x, dd_ptr->tunnel_y, 2, 2);
108 else if (!build_tunnel(player_ptr, dd_ptr, dt_ptr, dd_ptr->cent[i].y, dd_ptr->cent[i].x, dd_ptr->tunnel_y, dd_ptr->tunnel_x))
109 dd_ptr->tunnel_fail_count++;
111 if (dd_ptr->tunnel_fail_count >= 2) {
112 *dd_ptr->why = _("トンネル接続に失敗", "Failed to generate tunnels");
119 static void make_tunnels(player_type *player_ptr, dun_data_type *dd_ptr)
121 for (int j = 0; j < dd_ptr->tunn_n; j++) {
124 dd_ptr->tunnel_y = dd_ptr->tunn[j].y;
125 dd_ptr->tunnel_x = dd_ptr->tunn[j].x;
126 g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
127 f_ptr = &f_info[g_ptr->feat];
128 if (!has_flag(f_ptr->flags, FF_MOVE) || (!has_flag(f_ptr->flags, FF_WATER) && !has_flag(f_ptr->flags, FF_LAVA))) {
130 place_grid(player_ptr, g_ptr, GB_FLOOR);
135 static void make_walls(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr)
137 for (int j = 0; j < dd_ptr->wall_n; j++) {
139 dd_ptr->tunnel_y = dd_ptr->wall[j].y;
140 dd_ptr->tunnel_x = dd_ptr->wall[j].x;
141 g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
143 place_grid(player_ptr, g_ptr, GB_FLOOR);
144 if ((randint0(100) < dt_ptr->dun_tun_pen) && d_ptr->flags.has_not(DF::NO_DOORS))
145 place_random_door(player_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x, true);
149 static bool make_centers(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr)
151 dd_ptr->tunnel_fail_count = 0;
153 dd_ptr->tunnel_y = dd_ptr->cent[dd_ptr->cent_n - 1].y;
154 dd_ptr->tunnel_x = dd_ptr->cent[dd_ptr->cent_n - 1].x;
155 for (int i = 0; i < dd_ptr->cent_n; i++) {
156 if (!decide_tunnel_planned_site(player_ptr, dd_ptr, d_ptr, dt_ptr, i))
159 make_tunnels(player_ptr, dd_ptr);
160 make_walls(player_ptr, dd_ptr, d_ptr, dt_ptr);
161 dd_ptr->tunnel_y = dd_ptr->cent[i].y;
162 dd_ptr->tunnel_x = dd_ptr->cent[i].x;
168 static void make_doors(player_type *player_ptr, dun_data_type *dd_ptr, dt_type *dt_ptr)
170 for (int i = 0; i < dd_ptr->door_n; i++) {
171 dd_ptr->tunnel_y = dd_ptr->door[i].y;
172 dd_ptr->tunnel_x = dd_ptr->door[i].x;
173 try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x - 1);
174 try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x + 1);
175 try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y - 1, dd_ptr->tunnel_x);
176 try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y + 1, dd_ptr->tunnel_x);
180 static void make_only_tunnel_points(floor_type *floor_ptr, dun_data_type *dd_ptr)
182 int point_num = (floor_ptr->width * floor_ptr->height) / 200 + randint1(3);
183 dd_ptr->cent_n = point_num;
184 for (int i = 0; i < point_num; i++) {
185 dd_ptr->cent[i].y = randint0(floor_ptr->height);
186 dd_ptr->cent[i].x = randint0(floor_ptr->width);
190 static bool make_one_floor(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
192 floor_type *floor_ptr = player_ptr->current_floor_ptr;
194 if (d_info[floor_ptr->dungeon_idx].flags.has(DF::NO_ROOM)) {
195 make_only_tunnel_points(floor_ptr, dd_ptr);
197 if (!generate_rooms(player_ptr, dd_ptr)) {
198 *dd_ptr->why = _("部屋群の生成に失敗", "Failed to generate rooms");
203 place_cave_contents(player_ptr, dd_ptr, d_ptr);
205 dt_type *dt_ptr = initialize_dt_type(&tmp_dt);
206 if (!make_centers(player_ptr, dd_ptr, d_ptr, dt_ptr))
209 make_doors(player_ptr, dd_ptr, dt_ptr);
210 if (!alloc_stairs(player_ptr, feat_down_stair, rand_range(3, 4), 3)) {
211 *dd_ptr->why = _("下り階段生成に失敗", "Failed to generate down stairs.");
215 if (!alloc_stairs(player_ptr, feat_up_stair, rand_range(1, 2), 3)) {
216 *dd_ptr->why = _("上り階段生成に失敗", "Failed to generate up stairs.");
223 static bool switch_making_floor(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
225 if (d_ptr->flags.has(DF::MAZE)) {
226 floor_type *floor_ptr = player_ptr->current_floor_ptr;
227 build_maze_vault(player_ptr, floor_ptr->width / 2 - 1, floor_ptr->height / 2 - 1, floor_ptr->width - 4, floor_ptr->height - 4, false);
228 if (!alloc_stairs(player_ptr, feat_down_stair, rand_range(2, 3), 3)) {
229 *dd_ptr->why = _("迷宮ダンジョンの下り階段生成に失敗", "Failed to alloc up stairs in maze dungeon.");
233 if (!alloc_stairs(player_ptr, feat_up_stair, 1, 3)) {
234 *dd_ptr->why = _("迷宮ダンジョンの上り階段生成に失敗", "Failed to alloc down stairs in maze dungeon.");
241 if (!make_one_floor(player_ptr, dd_ptr, d_ptr))
247 static void make_aqua_streams(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
249 if (dd_ptr->laketype != 0)
253 for (int i = 0; i < DUN_STR_QUA; i++)
254 build_streamer(player_ptr, d_ptr->stream2, DUN_STR_QC);
257 for (int i = 0; i < DUN_STR_MAG; i++)
258 build_streamer(player_ptr, d_ptr->stream1, DUN_STR_MC);
262 * @brief マスにフロア端用の永久壁を配置する / Set boundary mimic and add "solid" perma-wall
263 * @param g_ptr 永久壁を配置したいマス構造体の参照ポインタ
265 static void place_bound_perm_wall(player_type *player_ptr, grid_type *g_ptr)
267 if (bound_walls_perm) {
269 place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
273 auto *f_ptr = &f_info[g_ptr->feat];
274 if ((has_flag(f_ptr->flags, FF_HAS_GOLD) || has_flag(f_ptr->flags, FF_HAS_ITEM)) && !has_flag(f_ptr->flags, FF_SECRET)) {
275 g_ptr->feat = feat_state(player_ptr->current_floor_ptr, g_ptr->feat, FF_ENSECRET);
278 g_ptr->mimic = g_ptr->feat;
279 place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
282 static void make_perm_walls(player_type *player_ptr)
284 floor_type *floor_ptr = player_ptr->current_floor_ptr;
285 for (POSITION x = 0; x < floor_ptr->width; x++) {
286 place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[0][x]);
287 place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[floor_ptr->height - 1][x]);
290 for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
291 place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][0]);
292 place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][floor_ptr->width - 1]);
296 static bool check_place_necessary_objects(player_type *player_ptr, dun_data_type *dd_ptr)
298 if (!new_player_spot(player_ptr)) {
299 *dd_ptr->why = _("プレイヤー配置に失敗", "Failed to place a player");
303 if (!place_quest_monsters(player_ptr)) {
304 *dd_ptr->why = _("クエストモンスター配置に失敗", "Failed to place a quest monster");
311 static void decide_dungeon_data_allocation(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
313 floor_type *floor_ptr = player_ptr->current_floor_ptr;
314 dd_ptr->alloc_object_num = floor_ptr->dun_level / 3;
315 if (dd_ptr->alloc_object_num > 10)
316 dd_ptr->alloc_object_num = 10;
318 if (dd_ptr->alloc_object_num < 2)
319 dd_ptr->alloc_object_num = 2;
321 dd_ptr->alloc_monster_num = d_ptr->min_m_alloc_level;
322 if (floor_ptr->height >= MAX_HGT && floor_ptr->width >= MAX_WID)
325 int small_tester = dd_ptr->alloc_monster_num;
326 dd_ptr->alloc_monster_num = (dd_ptr->alloc_monster_num * floor_ptr->height) / MAX_HGT;
327 dd_ptr->alloc_monster_num = (dd_ptr->alloc_monster_num * floor_ptr->width) / MAX_WID;
328 dd_ptr->alloc_monster_num += 1;
329 if (dd_ptr->alloc_monster_num > small_tester)
330 dd_ptr->alloc_monster_num = small_tester;
332 msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("モンスター数基本値を %d から %d に減らします", "Reduced monsters base from %d to %d"), small_tester,
333 dd_ptr->alloc_monster_num);
336 static bool allocate_dungeon_data(player_type *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
338 dd_ptr->alloc_monster_num += randint1(8);
339 for (dd_ptr->alloc_monster_num = dd_ptr->alloc_monster_num + dd_ptr->alloc_object_num; dd_ptr->alloc_monster_num > 0; dd_ptr->alloc_monster_num--)
340 (void)alloc_monster(player_ptr, 0, PM_ALLOW_SLEEP, summon_specific);
342 alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_TRAP, randint1(dd_ptr->alloc_object_num));
343 if (d_ptr->flags.has_not(DF::NO_CAVE))
344 alloc_object(player_ptr, ALLOC_SET_CORR, ALLOC_TYP_RUBBLE, randint1(dd_ptr->alloc_object_num));
346 floor_type *floor_ptr = player_ptr->current_floor_ptr;
347 if (player_ptr->enter_dungeon && floor_ptr->dun_level > 1)
348 floor_ptr->object_level = 1;
350 alloc_object(player_ptr, ALLOC_SET_ROOM, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ROOM, 3));
351 alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ITEM, 3));
352 alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_GOLD, randnor(DUN_AMT_GOLD, 3));
353 floor_ptr->object_level = floor_ptr->base_level;
354 if (alloc_guardian(player_ptr, true))
357 *dd_ptr->why = _("ダンジョンの主配置に失敗", "Failed to place a dungeon guardian");
361 static void decide_grid_glowing(floor_type *floor_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
363 bool is_empty_or_dark = dd_ptr->empty_level;
364 is_empty_or_dark &= !one_in_(DARK_EMPTY) || (randint1(100) > floor_ptr->dun_level);
365 is_empty_or_dark &= d_ptr->flags.has_not(DF::DARKNESS);
366 if (!is_empty_or_dark)
369 for (POSITION y = 0; y < floor_ptr->height; y++)
370 for (POSITION x = 0; x < floor_ptr->width; x++)
371 floor_ptr->grid_array[y][x].info |= CAVE_GLOW;
375 * @brief ダンジョン生成のメインルーチン / Generate a new dungeon level
376 * @details Note that "dun_body" adds about 4000 bytes of memory to the stack.
377 * @param player_ptr プレーヤーへの参照ポインタ
378 * @param why エラー原因メッセージを返す
379 * @return ダンジョン生成が全て無事に成功したらTRUEを返す。
381 bool cave_gen(player_type *player_ptr, concptr *why)
383 floor_type *floor_ptr = player_ptr->current_floor_ptr;
384 reset_lite_area(floor_ptr);
385 set_floor_and_wall(floor_ptr->dungeon_idx);
386 get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), NULL);
388 dun_data_type tmp_dd;
389 dun_data_type *dd_ptr = initialize_dun_data_type(&tmp_dd, why);
390 dd_ptr->row_rooms = floor_ptr->height / BLOCK_HGT;
391 dd_ptr->col_rooms = floor_ptr->width / BLOCK_WID;
392 for (POSITION y = 0; y < dd_ptr->row_rooms; y++)
393 for (POSITION x = 0; x < dd_ptr->col_rooms; x++)
394 dd_ptr->room_map[y][x] = false;
397 dungeon_type *d_ptr = &d_info[floor_ptr->dungeon_idx];
398 if (ironman_empty_levels || (d_ptr->flags.has(DF::ARENA) && (empty_levels && one_in_(EMPTY_LEVEL)))) {
399 dd_ptr->empty_level = true;
400 msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("アリーナレベルを生成。", "Arena level."));
403 check_arena_floor(player_ptr, dd_ptr);
404 gen_caverns_and_lakes(player_ptr, d_ptr, dd_ptr);
405 if (!switch_making_floor(player_ptr, dd_ptr, d_ptr))
408 make_aqua_streams(player_ptr, dd_ptr, d_ptr);
409 make_perm_walls(player_ptr);
410 if (!check_place_necessary_objects(player_ptr, dd_ptr))
413 decide_dungeon_data_allocation(player_ptr, dd_ptr, d_ptr);
414 if (!allocate_dungeon_data(player_ptr, dd_ptr, d_ptr))
417 decide_grid_glowing(floor_ptr, dd_ptr, d_ptr);