OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / floor / floor-generator.cpp
1 /*!
2  * @brief ダンジョンの生成 / Dungeon generation
3  * @date 2014/01/04
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  * This software may be copied and distributed for educational, research,\n
7  * and not for profit purposes provided that this copyright and statement\n
8  * are included in all such copies.  Other copyrights may also apply.\n
9  * 2014 Deskull rearranged comment for Doxygen. \n
10  */
11
12 #include "floor/floor-generator.h"
13 #include "dungeon/dungeon-flag-types.h"
14 #include "dungeon/quest.h"
15 #include "floor/cave-generator.h"
16 #include "floor/floor-events.h"
17 #include "floor/floor-generator.h"
18 #include "floor/floor-save.h" //!< @todo precalc_cur_num_of_pet() が依存している、違和感.
19 #include "floor/floor-util.h"
20 #include "floor/wild.h"
21 #include "game-option/birth-options.h"
22 #include "game-option/cheat-types.h"
23 #include "game-option/game-play-options.h"
24 #include "game-option/play-record-options.h"
25 #include "grid/feature.h"
26 #include "grid/grid.h"
27 #include "info-reader/feature-reader.h"
28 #include "info-reader/fixed-map-parser.h"
29 #include "io/write-diary.h"
30 #include "market/arena-info-table.h"
31 #include "monster-floor/monster-generator.h"
32 #include "monster-floor/monster-remover.h"
33 #include "monster-floor/place-monster-types.h"
34 #include "monster-race/monster-race.h"
35 #include "monster/monster-flag-types.h"
36 #include "monster/monster-status-setter.h"
37 #include "monster/monster-status.h"
38 #include "monster/monster-update.h"
39 #include "monster/monster-util.h"
40 #include "player/player-status.h"
41 #include "system/building-type-definition.h"
42 #include "system/dungeon-info.h"
43 #include "system/floor-type-definition.h"
44 #include "system/grid-type-definition.h"
45 #include "system/item-entity.h"
46 #include "system/monster-entity.h"
47 #include "system/monster-race-info.h"
48 #include "system/player-type-definition.h"
49 #include "system/terrain-type-definition.h"
50 #include "util/bit-flags-calculator.h"
51 #include "view/display-messages.h"
52 #include "window/main-window-util.h"
53 #include "wizard/wizard-messages.h"
54 #include "world/world.h"
55 #include <algorithm>
56 #include <array>
57 #include <stack>
58
59 /*!
60  * @brief 闘技場用のアリーナ地形を作成する / Builds the on_defeat_arena_monster after it is entered -KMW-
61  * @param player_ptr プレイヤーへの参照ポインタ
62  */
63 static void build_arena(PlayerType *player_ptr, POSITION *start_y, POSITION *start_x)
64 {
65     POSITION yval = SCREEN_HGT / 2;
66     POSITION xval = SCREEN_WID / 2;
67     POSITION y_height = yval - 10;
68     POSITION y_depth = yval + 10;
69     POSITION x_left = xval - 32;
70     POSITION x_right = xval + 32;
71     auto *floor_ptr = player_ptr->current_floor_ptr;
72     for (POSITION i = y_height; i <= y_height + 5; i++) {
73         for (POSITION j = x_left; j <= x_right; j++) {
74             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
75             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
76         }
77     }
78
79     for (POSITION i = y_depth; i >= y_depth - 5; i--) {
80         for (POSITION j = x_left; j <= x_right; j++) {
81             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
82             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
83         }
84     }
85
86     for (POSITION j = x_left; j <= x_left + 17; j++) {
87         for (POSITION i = y_height; i <= y_depth; i++) {
88             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
89             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
90         }
91     }
92
93     for (POSITION j = x_right; j >= x_right - 17; j--) {
94         for (POSITION i = y_height; i <= y_depth; i++) {
95             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
96             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
97         }
98     }
99
100     place_bold(player_ptr, y_height + 6, x_left + 18, GB_EXTRA_PERM);
101     floor_ptr->grid_array[y_height + 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
102     place_bold(player_ptr, y_depth - 6, x_left + 18, GB_EXTRA_PERM);
103     floor_ptr->grid_array[y_depth - 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
104     place_bold(player_ptr, y_height + 6, x_right - 18, GB_EXTRA_PERM);
105     floor_ptr->grid_array[y_height + 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
106     place_bold(player_ptr, y_depth - 6, x_right - 18, GB_EXTRA_PERM);
107     floor_ptr->grid_array[y_depth - 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
108
109     *start_y = y_height + 5;
110     *start_x = xval;
111     floor_ptr->grid_array[*start_y][*start_x].feat = f_tag_to_index("ARENA_GATE");
112     floor_ptr->grid_array[*start_y][*start_x].info |= CAVE_GLOW | CAVE_MARK;
113 }
114
115 /*!
116  * @brief 挑戦時闘技場への入場処理 / Town logic flow for generation of on_defeat_arena_monster -KMW-
117  */
118 static void generate_challenge_arena(PlayerType *player_ptr)
119 {
120     POSITION qy = 0;
121     POSITION qx = 0;
122     auto *floor_ptr = player_ptr->current_floor_ptr;
123     floor_ptr->height = SCREEN_HGT;
124     floor_ptr->width = SCREEN_WID;
125
126     POSITION y, x;
127     for (y = 0; y < MAX_HGT; y++) {
128         for (x = 0; x < MAX_WID; x++) {
129             place_bold(player_ptr, y, x, GB_SOLID_PERM);
130             floor_ptr->grid_array[y][x].info |= (CAVE_GLOW | CAVE_MARK);
131         }
132     }
133
134     for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++) {
135         for (x = qx + 1; x < qx + SCREEN_WID - 1; x++) {
136             floor_ptr->grid_array[y][x].feat = feat_floor;
137         }
138     }
139
140     build_arena(player_ptr, &y, &x);
141     player_place(player_ptr, y, x);
142     if (place_monster_aux(player_ptr, 0, player_ptr->y + 5, player_ptr->x, arena_info[player_ptr->arena_number].r_idx, PM_NO_KAGE | PM_NO_PET)) {
143         return;
144     }
145
146     player_ptr->exit_bldg = true;
147     player_ptr->arena_number++;
148     msg_print(_("相手は欠場した。あなたの不戦勝だ。", "The enemy is unable to appear. You won by default."));
149 }
150
151 /*!
152  * @brief モンスター闘技場のフロア生成 / Builds the on_defeat_arena_monster after it is entered -KMW-
153  * @param player_ptr プレイヤーへの参照ポインタ
154  */
155 static void build_battle(PlayerType *player_ptr, POSITION *y, POSITION *x)
156 {
157     POSITION yval = SCREEN_HGT / 2;
158     POSITION xval = SCREEN_WID / 2;
159     POSITION y_height = yval - 10;
160     POSITION y_depth = yval + 10;
161     POSITION x_left = xval - 32;
162     POSITION x_right = xval + 32;
163
164     auto *floor_ptr = player_ptr->current_floor_ptr;
165     for (int i = y_height; i <= y_height + 5; i++) {
166         for (int j = x_left; j <= x_right; j++) {
167             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
168             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
169         }
170     }
171
172     for (int i = y_depth; i >= y_depth - 3; i--) {
173         for (int j = x_left; j <= x_right; j++) {
174             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
175             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
176         }
177     }
178
179     for (int j = x_left; j <= x_left + 17; j++) {
180         for (int i = y_height; i <= y_depth; i++) {
181             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
182             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
183         }
184     }
185
186     for (int j = x_right; j >= x_right - 17; j--) {
187         for (int i = y_height; i <= y_depth; i++) {
188             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
189             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
190         }
191     }
192
193     place_bold(player_ptr, y_height + 6, x_left + 18, GB_EXTRA_PERM);
194     floor_ptr->grid_array[y_height + 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
195     place_bold(player_ptr, y_depth - 4, x_left + 18, GB_EXTRA_PERM);
196     floor_ptr->grid_array[y_depth - 4][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
197     place_bold(player_ptr, y_height + 6, x_right - 18, GB_EXTRA_PERM);
198     floor_ptr->grid_array[y_height + 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
199     place_bold(player_ptr, y_depth - 4, x_right - 18, GB_EXTRA_PERM);
200     floor_ptr->grid_array[y_depth - 4][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
201
202     for (int i = y_height + 1; i <= y_height + 5; i++) {
203         for (int j = x_left + 20 + 2 * (y_height + 5 - i); j <= x_right - 20 - 2 * (y_height + 5 - i); j++) {
204             floor_ptr->grid_array[i][j].feat = feat_permanent_glass_wall;
205         }
206     }
207
208     POSITION last_y = y_height + 1;
209     POSITION last_x = xval;
210     floor_ptr->grid_array[last_y][last_x].feat = f_tag_to_index("BUILDING_3");
211     floor_ptr->grid_array[last_y][last_x].info |= CAVE_GLOW | CAVE_MARK;
212     *y = last_y;
213     *x = last_x;
214 }
215
216 /*!
217  * @brief モンスター闘技場への導入処理 / Town logic flow for generation of on_defeat_arena_monster -KMW-
218  */
219 static void generate_gambling_arena(PlayerType *player_ptr)
220 {
221     POSITION y, x;
222     POSITION qy = 0;
223     POSITION qx = 0;
224     auto *floor_ptr = player_ptr->current_floor_ptr;
225     for (y = 0; y < MAX_HGT; y++) {
226         for (x = 0; x < MAX_WID; x++) {
227             place_bold(player_ptr, y, x, GB_SOLID_PERM);
228             floor_ptr->grid_array[y][x].info |= (CAVE_GLOW | CAVE_MARK);
229         }
230     }
231
232     for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++) {
233         for (x = qx + 1; x < qx + SCREEN_WID - 1; x++) {
234             floor_ptr->grid_array[y][x].feat = feat_floor;
235         }
236     }
237
238     build_battle(player_ptr, &y, &x);
239     player_place(player_ptr, y, x);
240     for (MONSTER_IDX i = 0; i < 4; i++) {
241         place_monster_aux(player_ptr, 0, player_ptr->y + 8 + (i / 2) * 4, player_ptr->x - 2 + (i % 2) * 4, battle_mon_list[i], (PM_NO_KAGE | PM_NO_PET));
242         set_friendly(&floor_ptr->m_list[floor_ptr->grid_array[player_ptr->y + 8 + (i / 2) * 4][player_ptr->x - 2 + (i % 2) * 4].m_idx]);
243     }
244
245     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
246         auto *m_ptr = &floor_ptr->m_list[i];
247         if (!m_ptr->is_valid()) {
248             continue;
249         }
250
251         m_ptr->mflag2.set({ MonsterConstantFlagType::MARK, MonsterConstantFlagType::SHOW });
252         update_monster(player_ptr, i, false);
253     }
254 }
255
256 /*!
257  * @brief 固定マップクエストのフロア生成 / Generate a quest level
258  * @param player_ptr プレイヤーへの参照ポインタ
259  */
260 static void generate_fixed_floor(PlayerType *player_ptr)
261 {
262     auto *floor_ptr = player_ptr->current_floor_ptr;
263     for (POSITION y = 0; y < floor_ptr->height; y++) {
264         for (POSITION x = 0; x < floor_ptr->width; x++) {
265             place_bold(player_ptr, y, x, GB_SOLID_PERM);
266         }
267     }
268
269     const auto &quest_list = QuestList::get_instance();
270     floor_ptr->base_level = quest_list[floor_ptr->quest_number].level;
271     floor_ptr->dun_level = floor_ptr->base_level;
272     floor_ptr->object_level = floor_ptr->base_level;
273     floor_ptr->monster_level = floor_ptr->base_level;
274     if (record_stair) {
275         exe_write_diary_quest(player_ptr, DIARY_TO_QUEST, floor_ptr->quest_number);
276     }
277     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), nullptr);
278     init_flags = INIT_CREATE_DUNGEON;
279     parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, MAX_HGT, MAX_WID);
280 }
281
282 /*!
283  * @brief ダンジョン時のランダムフロア生成 / Make a real level
284  * @param player_ptr プレイヤーへの参照ポインタ
285  * @param concptr
286  * @return フロアの生成に成功したらTRUE
287  */
288 static bool level_gen(PlayerType *player_ptr, concptr *why)
289 {
290     auto *floor_ptr = player_ptr->current_floor_ptr;
291     DUNGEON_IDX d_idx = floor_ptr->dungeon_idx;
292     const auto &dungeon = dungeons_info[d_idx];
293     constexpr auto chance_small_floor = 3;
294     auto is_small_level = always_small_levels || ironman_small_levels;
295     is_small_level |= one_in_(chance_small_floor) && small_levels;
296     is_small_level |= dungeon.flags.has(DungeonFeatureType::BEGINNER);
297     is_small_level |= dungeon.flags.has(DungeonFeatureType::SMALLEST);
298     if (is_small_level && dungeon.flags.has_not(DungeonFeatureType::BIG)) {
299         int level_height;
300         int level_width;
301         if (dungeon.flags.has(DungeonFeatureType::SMALLEST)) {
302             level_height = 1;
303             level_width = 1;
304         } else if (dungeon.flags.has(DungeonFeatureType::BEGINNER)) {
305             level_height = 2;
306             level_width = 2;
307         } else {
308             level_height = randint1(MAX_HGT / SCREEN_HGT);
309             level_width = randint1(MAX_WID / SCREEN_WID);
310             bool is_first_level_area = true;
311             bool is_max_area = (level_height == MAX_HGT / SCREEN_HGT) && (level_width == MAX_WID / SCREEN_WID);
312             while (is_first_level_area || is_max_area) {
313                 level_height = randint1(MAX_HGT / SCREEN_HGT);
314                 level_width = randint1(MAX_WID / SCREEN_WID);
315                 is_first_level_area = false;
316                 is_max_area = (level_height == MAX_HGT / SCREEN_HGT) && (level_width == MAX_WID / SCREEN_WID);
317             }
318         }
319
320         floor_ptr->height = level_height * SCREEN_HGT;
321         floor_ptr->width = level_width * SCREEN_WID;
322         panel_row_min = floor_ptr->height;
323         panel_col_min = floor_ptr->width;
324
325         msg_format_wizard(
326             player_ptr, CHEAT_DUNGEON, _("小さなフロア: X:%d, Y:%d", "A 'small' dungeon level: X:%d, Y:%d."), floor_ptr->width, floor_ptr->height);
327     } else {
328         floor_ptr->height = MAX_HGT;
329         floor_ptr->width = MAX_WID;
330         panel_row_min = floor_ptr->height;
331         panel_col_min = floor_ptr->width;
332     }
333
334     return cave_gen(player_ptr, why);
335 }
336
337 /*!
338  * @brief フロアに存在する全マスの記憶状態を初期化する / Wipe all unnecessary flags after grid_array generation
339  */
340 void wipe_generate_random_floor_flags(FloorType *floor_ptr)
341 {
342     for (POSITION y = 0; y < floor_ptr->height; y++) {
343         for (POSITION x = 0; x < floor_ptr->width; x++) {
344             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
345         }
346     }
347
348     if (floor_ptr->dun_level > 0) {
349         for (POSITION y = 1; y < floor_ptr->height - 1; y++) {
350             for (POSITION x = 1; x < floor_ptr->width - 1; x++) {
351                 floor_ptr->grid_array[y][x].info |= CAVE_UNSAFE;
352             }
353         }
354     }
355 }
356
357 /*!
358  * @brief フロアの全情報を初期化する / Clear and empty floor.
359  * @parama player_ptr プレイヤーへの参照ポインタ
360  */
361 void clear_cave(PlayerType *player_ptr)
362 {
363     auto *floor_ptr = player_ptr->current_floor_ptr;
364     std::fill_n(floor_ptr->o_list.begin(), floor_ptr->o_max, ItemEntity{});
365     floor_ptr->o_max = 1;
366     floor_ptr->o_cnt = 0;
367
368     for (auto &[r_idx, r_ref] : monraces_info) {
369         r_ref.cur_num = 0;
370     }
371
372     std::fill_n(floor_ptr->m_list.begin(), floor_ptr->m_max, MonsterEntity{});
373     floor_ptr->m_max = 1;
374     floor_ptr->m_cnt = 0;
375     for (int i = 0; i < MAX_MTIMED; i++) {
376         floor_ptr->mproc_max[i] = 0;
377     }
378
379     precalc_cur_num_of_pet(player_ptr);
380     for (POSITION y = 0; y < MAX_HGT; y++) {
381         for (POSITION x = 0; x < MAX_WID; x++) {
382             auto *g_ptr = &floor_ptr->grid_array[y][x];
383             g_ptr->info = 0;
384             g_ptr->feat = 0;
385             g_ptr->o_idx_list.clear();
386             g_ptr->m_idx = 0;
387             g_ptr->special = 0;
388             g_ptr->mimic = 0;
389             memset(g_ptr->costs, 0, sizeof(g_ptr->costs));
390             memset(g_ptr->costs, 0, sizeof(g_ptr->dists));
391             g_ptr->when = 0;
392         }
393     }
394
395     floor_ptr->base_level = floor_ptr->dun_level;
396     floor_ptr->monster_level = floor_ptr->base_level;
397     floor_ptr->object_level = floor_ptr->base_level;
398 }
399
400 typedef bool (*IsWallFunc)(const FloorType *, int, int);
401
402 // (y,x) がプレイヤーが通れない永久地形かどうかを返す。
403 static bool is_permanent_blocker(const FloorType *const floor_ptr, const int y, const int x)
404 {
405     const FEAT_IDX feat = floor_ptr->grid_array[y][x].feat;
406     const auto &flags = terrains_info[feat].flags;
407     return flags.has(TerrainCharacteristics::PERMANENT) && flags.has_not(TerrainCharacteristics::MOVE);
408 }
409
410 static void floor_is_connected_dfs(const FloorType *const floor_ptr, const IsWallFunc is_wall, const int y_start, const int x_start, bool *const visited)
411 {
412     // clang-format off
413     static const int DY[8] = { -1, -1, -1,  0, 0,  1, 1, 1 };
414     static const int DX[8] = { -1,  0,  1, -1, 1, -1, 0, 1 };
415     // clang-format on
416
417     const int h = floor_ptr->height;
418     const int w = floor_ptr->width;
419     const int start = w * y_start + x_start;
420
421     // 深さ優先探索用のスタック。
422     // 最大フロアサイズが h=66, w=198 なので、スタックオーバーフロー防止のため再帰は使わない。
423     std::stack<int> stk;
424
425     stk.emplace(start);
426     visited[start] = true;
427
428     while (!stk.empty()) {
429         const int cur = stk.top();
430         stk.pop();
431         const int y = cur / w;
432         const int x = cur % w;
433
434         for (int i = 0; i < 8; ++i) {
435             const int y_nxt = y + DY[i];
436             const int x_nxt = x + DX[i];
437             if (y_nxt < 0 || h <= y_nxt || x_nxt < 0 || w <= x_nxt) {
438                 continue;
439             }
440             const int nxt = w * y_nxt + x_nxt;
441             if (visited[nxt]) {
442                 continue;
443             }
444             if (is_wall(floor_ptr, y_nxt, x_nxt)) {
445                 continue;
446             }
447
448             stk.emplace(nxt);
449             visited[nxt] = true;
450         }
451     }
452 }
453
454 // 現在のフロアが連結かどうかを返す。
455 // 各セルの8近傍は互いに移動可能とし、is_wall が真を返すセルのみを壁とみなす。
456 //
457 // 連結成分数が 0 の場合、偽を返す。
458 static bool floor_is_connected(const FloorType *const floor_ptr, const IsWallFunc is_wall)
459 {
460     static std::array<bool, MAX_HGT * MAX_WID> visited;
461
462     const int h = floor_ptr->height;
463     const int w = floor_ptr->width;
464
465     std::fill(begin(visited), end(visited), false);
466
467     int n_component = 0; // 連結成分数
468
469     for (int y = 0; y < h; ++y) {
470         for (int x = 0; x < w; ++x) {
471             const int idx = w * y + x;
472             if (visited[idx]) {
473                 continue;
474             }
475             if (is_wall(floor_ptr, y, x)) {
476                 continue;
477             }
478
479             if (++n_component >= 2) {
480                 break;
481             }
482             floor_is_connected_dfs(floor_ptr, is_wall, y, x, visited.data());
483         }
484     }
485
486     return n_component == 1;
487 }
488
489 /*!
490  * ダンジョンのランダムフロアを生成する / Generates a random dungeon level -RAK-
491  * @parama player_ptr プレイヤーへの参照ポインタ
492  * @note Hack -- regenerate any "overflow" levels
493  */
494 void generate_floor(PlayerType *player_ptr)
495 {
496     auto *floor_ptr = player_ptr->current_floor_ptr;
497     set_floor_and_wall(floor_ptr->dungeon_idx);
498     for (int num = 0; true; num++) {
499         bool okay = true;
500         concptr why = nullptr;
501         clear_cave(player_ptr);
502         player_ptr->x = player_ptr->y = 0;
503         if (floor_ptr->inside_arena) {
504             generate_challenge_arena(player_ptr);
505         } else if (player_ptr->phase_out) {
506             generate_gambling_arena(player_ptr);
507         } else if (inside_quest(floor_ptr->quest_number)) {
508             generate_fixed_floor(player_ptr);
509         } else if (!floor_ptr->dun_level) {
510             if (player_ptr->wild_mode) {
511                 wilderness_gen_small(player_ptr);
512             } else {
513                 wilderness_gen(player_ptr);
514             }
515         } else {
516             okay = level_gen(player_ptr, &why);
517         }
518
519         if (floor_ptr->o_max >= w_ptr->max_o_idx) {
520             why = _("アイテムが多すぎる", "too many objects");
521             okay = false;
522         } else if (floor_ptr->m_max >= w_ptr->max_m_idx) {
523             why = _("モンスターが多すぎる", "too many monsters");
524             okay = false;
525         }
526
527         // ダンジョン内フロアが連結でない(永久壁で区切られた孤立部屋がある)場合、
528         // 狂戦士でのプレイに支障をきたしうるので再生成する。
529         // 地上、荒野マップ、クエストでは連結性判定は行わない。
530         // TODO: 本来はダンジョン生成アルゴリズム自身で連結性を保証するのが理想ではある。
531         const bool check_conn = okay && floor_ptr->dun_level > 0 && !inside_quest(floor_ptr->quest_number);
532         if (check_conn && !floor_is_connected(floor_ptr, is_permanent_blocker)) {
533             // 一定回数試しても連結にならないなら諦める。
534             if (num >= 1000) {
535                 plog("cannot generate connected floor. giving up...");
536             } else {
537                 why = _("フロアが連結でない", "floor is not connected");
538                 okay = false;
539             }
540         }
541
542         if (okay) {
543             break;
544         }
545
546         if (why) {
547             msg_format(_("生成やり直し(%s)", "Generation restarted (%s)"), why);
548         }
549
550         wipe_o_list(floor_ptr);
551         wipe_monsters_list(player_ptr);
552     }
553
554     glow_deep_lava_and_bldg(player_ptr);
555     player_ptr->enter_dungeon = false;
556     wipe_generate_random_floor_flags(floor_ptr);
557 }