OSDN Git Service

[Refactor] #40572 Separated cave-generator.c/h from floor-generator.c
[hengbandforosx/hengbandosx.git] / src / floor / floor-generator.c
1 /*!
2  * @file generate.c
3  * @brief ダンジョンの生成 / Dungeon generation
4  * @date 2014/01/04
5  * @author
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
7  * This software may be copied and distributed for educational, research,\n
8  * and not for profit purposes provided that this copyright and statement\n
9  * are included in all such copies.  Other copyrights may also apply.\n
10  * 2014 Deskull rearranged comment for Doxygen. \n
11  */
12
13 #include "floor/floor-generator.h"
14 #include "cmd-building/cmd-building.h"
15 #include "cmd-io/cmd-dump.h"
16 #include "dungeon/dungeon-flag-types.h"
17 #include "dungeon/dungeon.h"
18 #include "dungeon/quest.h"
19 #include "floor/cave.h"
20 #include "floor/dungeon-tunnel-util.h"
21 #include "floor/cave-generator.h"
22 #include "floor/floor-allocation-types.h"
23 #include "floor/floor-events.h"
24 #include "floor/floor-generator-util.h"
25 #include "floor/floor-save.h"
26 #include "floor/floor-streams.h"
27 #include "floor/floor.h" // todo 相互依存している、後で消す.
28 #include "floor/object-allocator.h"
29 #include "floor/wild.h"
30 #include "game-option/birth-options.h"
31 #include "game-option/cheat-types.h"
32 #include "game-option/game-play-options.h"
33 #include "game-option/play-record-options.h"
34 #include "grid/feature.h"
35 #include "grid/grid.h"
36 #include "grid/trap.h"
37 #include "info-reader/feature-reader.h"
38 #include "info-reader/fixed-map-parser.h"
39 #include "io/write-diary.h"
40 #include "market/arena-info-table.h"
41 #include "monster-floor/monster-generator.h"
42 #include "monster-floor/monster-remover.h"
43 #include "monster-floor/monster-summon.h"
44 #include "monster-floor/place-monster-types.h"
45 #include "monster-race/monster-race.h"
46 #include "monster-race/race-flags1.h"
47 #include "monster/monster-flag-types.h"
48 #include "monster/monster-info.h"
49 #include "monster/monster-status.h"
50 #include "monster/monster-update.h"
51 #include "monster/monster-util.h"
52 #include "player/player-status.h"
53 #include "room/lake-types.h"
54 #include "room/room-generator.h"
55 #include "room/rooms-builder.h"
56 #include "room/rooms-maze-vault.h"
57 #include "system/dungeon-data-definition.h"
58 #include "system/floor-type-definition.h"
59 #include "system/system-variables.h"
60 #include "util/bit-flags-calculator.h"
61 #include "view/display-messages.h"
62 #include "window/main-window-util.h"
63 #include "wizard/wizard-messages.h"
64 #include "world/world.h"
65
66 /*!
67  * @brief クエストに関わるモンスターの配置を行う / Place quest monsters
68  * @param creature_ptr プレーヤーへの参照ポインタ
69  * @return 成功したならばTRUEを返す
70  */
71 bool place_quest_monsters(player_type *creature_ptr)
72 {
73     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
74     for (int i = 0; i < max_q_idx; i++) {
75         monster_race *r_ptr;
76         BIT_FLAGS mode;
77         if (quest[i].status != QUEST_STATUS_TAKEN || (quest[i].type != QUEST_TYPE_KILL_LEVEL && quest[i].type != QUEST_TYPE_RANDOM)
78             || quest[i].level != floor_ptr->dun_level || creature_ptr->dungeon_idx != quest[i].dungeon || (quest[i].flags & QUEST_FLAG_PRESET)) {
79             continue;
80         }
81
82         r_ptr = &r_info[quest[i].r_idx];
83         if ((r_ptr->flags1 & RF1_UNIQUE) && (r_ptr->cur_num >= r_ptr->max_num))
84             continue;
85
86         mode = (PM_NO_KAGE | PM_NO_PET);
87         if (!(r_ptr->flags1 & RF1_FRIENDS))
88             mode |= PM_ALLOW_GROUP;
89
90         for (int j = 0; j < (quest[i].max_num - quest[i].cur_num); j++) {
91             int k;
92             for (k = 0; k < SAFE_MAX_ATTEMPTS; k++) {
93                 POSITION x = 0;
94                 POSITION y = 0;
95                 int l;
96                 for (l = SAFE_MAX_ATTEMPTS; l > 0; l--) {
97                     grid_type *g_ptr;
98                     feature_type *f_ptr;
99                     y = randint0(floor_ptr->height);
100                     x = randint0(floor_ptr->width);
101                     g_ptr = &floor_ptr->grid_array[y][x];
102                     f_ptr = &f_info[g_ptr->feat];
103                     if (!have_flag(f_ptr->flags, FF_MOVE) && !have_flag(f_ptr->flags, FF_CAN_FLY))
104                         continue;
105
106                     if (!monster_can_enter(creature_ptr, y, x, r_ptr, 0))
107                         continue;
108
109                     if (distance(y, x, creature_ptr->y, creature_ptr->x) < 10)
110                         continue;
111
112                     if (g_ptr->info & CAVE_ICKY)
113                         continue;
114                     else
115                         break;
116                 }
117
118                 if (l == 0)
119                     return FALSE;
120
121                 if (place_monster_aux(creature_ptr, 0, y, x, quest[i].r_idx, mode))
122                     break;
123                 else
124                     continue;
125             }
126
127             if (k == SAFE_MAX_ATTEMPTS)
128                 return FALSE;
129         }
130     }
131
132     return TRUE;
133 }
134
135 /*!
136  * @brief 闘技場用のアリーナ地形を作成する / Builds the arena after it is entered -KMW-
137  * @param player_ptr プレーヤーへの参照ポインタ
138  * @return なし
139  */
140 static void build_arena(player_type *player_ptr, POSITION *start_y, POSITION *start_x)
141 {
142     POSITION yval = SCREEN_HGT / 2;
143     POSITION xval = SCREEN_WID / 2;
144     POSITION y_height = yval - 10;
145     POSITION y_depth = yval + 10;
146     POSITION x_left = xval - 32;
147     POSITION x_right = xval + 32;
148     floor_type *floor_ptr = player_ptr->current_floor_ptr;
149     for (POSITION i = y_height; i <= y_height + 5; i++)
150         for (POSITION j = x_left; j <= x_right; j++) {
151             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
152             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
153         }
154
155     for (POSITION i = y_depth; i >= y_depth - 5; i--)
156         for (POSITION j = x_left; j <= x_right; j++) {
157             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
158             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
159         }
160
161     for (POSITION j = x_left; j <= x_left + 17; j++)
162         for (POSITION i = y_height; i <= y_depth; i++) {
163             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
164             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
165         }
166
167     for (POSITION j = x_right; j >= x_right - 17; j--)
168         for (POSITION i = y_height; i <= y_depth; i++) {
169             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
170             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
171         }
172
173     place_bold(player_ptr, y_height + 6, x_left + 18, GB_EXTRA_PERM);
174     floor_ptr->grid_array[y_height + 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
175     place_bold(player_ptr, y_depth - 6, x_left + 18, GB_EXTRA_PERM);
176     floor_ptr->grid_array[y_depth - 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
177     place_bold(player_ptr, y_height + 6, x_right - 18, GB_EXTRA_PERM);
178     floor_ptr->grid_array[y_height + 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
179     place_bold(player_ptr, y_depth - 6, x_right - 18, GB_EXTRA_PERM);
180     floor_ptr->grid_array[y_depth - 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
181
182     *start_y = y_height + 5;
183     *start_x = xval;
184     floor_ptr->grid_array[*start_y][*start_x].feat = f_tag_to_index("ARENA_GATE");
185     floor_ptr->grid_array[*start_y][*start_x].info |= CAVE_GLOW | CAVE_MARK;
186 }
187
188 /*!
189  * @brief 挑戦時闘技場への入場処理 / Town logic flow for generation of arena -KMW-
190  * @return なし
191  */
192 static void generate_challenge_arena(player_type *challanger_ptr)
193 {
194     POSITION qy = 0;
195     POSITION qx = 0;
196     floor_type *floor_ptr = challanger_ptr->current_floor_ptr;
197     floor_ptr->height = SCREEN_HGT;
198     floor_ptr->width = SCREEN_WID;
199
200     POSITION y, x;
201     for (y = 0; y < MAX_HGT; y++)
202         for (x = 0; x < MAX_WID; x++) {
203             place_bold(challanger_ptr, y, x, GB_SOLID_PERM);
204             floor_ptr->grid_array[y][x].info |= (CAVE_GLOW | CAVE_MARK);
205         }
206
207     for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++)
208         for (x = qx + 1; x < qx + SCREEN_WID - 1; x++)
209             floor_ptr->grid_array[y][x].feat = feat_floor;
210
211     build_arena(challanger_ptr, &y, &x);
212     player_place(challanger_ptr, y, x);
213     if (place_monster_aux(challanger_ptr, 0, challanger_ptr->y + 5, challanger_ptr->x, arena_info[challanger_ptr->arena_number].r_idx, PM_NO_KAGE | PM_NO_PET))
214         return;
215
216     challanger_ptr->exit_bldg = TRUE;
217     challanger_ptr->arena_number++;
218     msg_print(_("相手は欠場した。あなたの不戦勝だ。", "The enemy is unable appear. You won by default."));
219 }
220
221 /*!
222  * @brief モンスター闘技場のフロア生成 / Builds the arena after it is entered -KMW-
223  * @param player_ptr プレーヤーへの参照ポインタ
224  * @return なし
225  */
226 static void build_battle(player_type *player_ptr, POSITION *y, POSITION *x)
227 {
228     POSITION yval = SCREEN_HGT / 2;
229     POSITION xval = SCREEN_WID / 2;
230     POSITION y_height = yval - 10;
231     POSITION y_depth = yval + 10;
232     POSITION x_left = xval - 32;
233     POSITION x_right = xval + 32;
234
235     floor_type *floor_ptr = player_ptr->current_floor_ptr;
236     for (int i = y_height; i <= y_height + 5; i++)
237         for (int j = x_left; j <= x_right; j++) {
238             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
239             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
240         }
241
242     for (int i = y_depth; i >= y_depth - 3; i--)
243         for (int j = x_left; j <= x_right; j++) {
244             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
245             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
246         }
247
248     for (int j = x_left; j <= x_left + 17; j++)
249         for (int i = y_height; i <= y_depth; i++) {
250             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
251             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
252         }
253
254     for (int j = x_right; j >= x_right - 17; j--)
255         for (int i = y_height; i <= y_depth; i++) {
256             place_bold(player_ptr, i, j, GB_EXTRA_PERM);
257             floor_ptr->grid_array[i][j].info |= (CAVE_GLOW | CAVE_MARK);
258         }
259
260     place_bold(player_ptr, y_height + 6, x_left + 18, GB_EXTRA_PERM);
261     floor_ptr->grid_array[y_height + 6][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
262     place_bold(player_ptr, y_depth - 4, x_left + 18, GB_EXTRA_PERM);
263     floor_ptr->grid_array[y_depth - 4][x_left + 18].info |= CAVE_GLOW | CAVE_MARK;
264     place_bold(player_ptr, y_height + 6, x_right - 18, GB_EXTRA_PERM);
265     floor_ptr->grid_array[y_height + 6][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
266     place_bold(player_ptr, y_depth - 4, x_right - 18, GB_EXTRA_PERM);
267     floor_ptr->grid_array[y_depth - 4][x_right - 18].info |= CAVE_GLOW | CAVE_MARK;
268
269     for (int i = y_height + 1; i <= y_height + 5; i++)
270         for (int j = x_left + 20 + 2 * (y_height + 5 - i); j <= x_right - 20 - 2 * (y_height + 5 - i); j++) {
271             floor_ptr->grid_array[i][j].feat = feat_permanent_glass_wall;
272         }
273
274     POSITION last_y = y_height + 1;
275     POSITION last_x = xval;
276     floor_ptr->grid_array[last_y][last_x].feat = f_tag_to_index("BUILDING_3");
277     floor_ptr->grid_array[last_y][last_x].info |= CAVE_GLOW | CAVE_MARK;
278     *y = last_y;
279     *x = last_x;
280 }
281
282 /*!
283  * @brief モンスター闘技場への導入処理 / Town logic flow for generation of arena -KMW-
284  * @return なし
285  */
286 static void generate_gambling_arena(player_type *creature_ptr)
287 {
288     POSITION y, x;
289     POSITION qy = 0;
290     POSITION qx = 0;
291     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
292     for (y = 0; y < MAX_HGT; y++)
293         for (x = 0; x < MAX_WID; x++) {
294             place_bold(creature_ptr, y, x, GB_SOLID_PERM);
295             floor_ptr->grid_array[y][x].info |= (CAVE_GLOW | CAVE_MARK);
296         }
297
298     for (y = qy + 1; y < qy + SCREEN_HGT - 1; y++)
299         for (x = qx + 1; x < qx + SCREEN_WID - 1; x++)
300             floor_ptr->grid_array[y][x].feat = feat_floor;
301
302     build_battle(creature_ptr, &y, &x);
303     player_place(creature_ptr, y, x);
304     for (MONSTER_IDX i = 0; i < 4; i++) {
305         place_monster_aux(creature_ptr, 0, creature_ptr->y + 8 + (i / 2) * 4, creature_ptr->x - 2 + (i % 2) * 4, battle_mon[i], (PM_NO_KAGE | PM_NO_PET));
306         set_friendly(&floor_ptr->m_list[floor_ptr->grid_array[creature_ptr->y + 8 + (i / 2) * 4][creature_ptr->x - 2 + (i % 2) * 4].m_idx]);
307     }
308
309     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
310         monster_type *m_ptr = &floor_ptr->m_list[i];
311         if (!monster_is_valid(m_ptr))
312             continue;
313
314         m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
315         update_monster(creature_ptr, i, FALSE);
316     }
317 }
318
319 /*!
320  * @brief 固定マップクエストのフロア生成 / Generate a quest level
321  * @param player_ptr プレーヤーへの参照ポインタ
322  * @return なし
323  */
324 static void generate_fixed_floor(player_type *player_ptr)
325 {
326     floor_type *floor_ptr = player_ptr->current_floor_ptr;
327     for (POSITION y = 0; y < floor_ptr->height; y++)
328         for (POSITION x = 0; x < floor_ptr->width; x++)
329             place_bold(player_ptr, y, x, GB_SOLID_PERM);
330
331     floor_ptr->base_level = quest[floor_ptr->inside_quest].level;
332     floor_ptr->dun_level = floor_ptr->base_level;
333     floor_ptr->object_level = floor_ptr->base_level;
334     floor_ptr->monster_level = floor_ptr->base_level;
335     if (record_stair)
336         exe_write_diary(player_ptr, DIARY_TO_QUEST, floor_ptr->inside_quest, NULL);
337
338     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), NULL);
339     init_flags = INIT_CREATE_DUNGEON;
340     parse_fixed_map(player_ptr, "q_info.txt", 0, 0, MAX_HGT, MAX_WID);
341 }
342
343 /*!
344  * @brief ダンジョン時のランダムフロア生成 / Make a real level
345  * @param player_ptr プレーヤーへの参照ポインタ
346  * @param concptr
347  * @return フロアの生成に成功したらTRUE
348  */
349 static bool level_gen(player_type *player_ptr, concptr *why)
350 {
351     floor_type *floor_ptr = player_ptr->current_floor_ptr;
352     DUNGEON_IDX d_idx = floor_ptr->dungeon_idx;
353     if ((always_small_levels || ironman_small_levels || (one_in_(SMALL_LEVEL) && small_levels) || (d_info[d_idx].flags1 & DF1_BEGINNER)
354             || (d_info[d_idx].flags1 & DF1_SMALLEST))
355         && !(d_info[d_idx].flags1 & DF1_BIG)) {
356         int level_height;
357         int level_width;
358         if (d_info[d_idx].flags1 & DF1_SMALLEST) {
359             level_height = 1;
360             level_width = 1;
361         } else if (d_info[d_idx].flags1 & DF1_BEGINNER) {
362             level_height = 2;
363             level_width = 2;
364         } else {
365             level_height = randint1(MAX_HGT / SCREEN_HGT);
366             level_width = randint1(MAX_WID / SCREEN_WID);
367             bool is_first_level_area = TRUE;
368             bool is_max_area = (level_height == MAX_HGT / SCREEN_HGT) && (level_width == MAX_WID / SCREEN_WID);
369             while (is_first_level_area || is_max_area) {
370                 level_height = randint1(MAX_HGT / SCREEN_HGT);
371                 level_width = randint1(MAX_WID / SCREEN_WID);
372                 is_first_level_area = FALSE;
373                 is_max_area = (level_height == MAX_HGT / SCREEN_HGT) && (level_width == MAX_WID / SCREEN_WID);
374             }
375         }
376
377         floor_ptr->height = level_height * SCREEN_HGT;
378         floor_ptr->width = level_width * SCREEN_WID;
379
380         /* Assume illegal panel */
381         panel_row_min = floor_ptr->height;
382         panel_col_min = floor_ptr->width;
383
384         msg_format_wizard(
385             player_ptr, CHEAT_DUNGEON, _("小さなフロア: X:%d, Y:%d", "A 'small' dungeon level: X:%d, Y:%d."), floor_ptr->width, floor_ptr->height);
386     } else {
387         floor_ptr->height = MAX_HGT;
388         floor_ptr->width = MAX_WID;
389         panel_row_min = floor_ptr->height;
390         panel_col_min = floor_ptr->width;
391     }
392
393     return cave_gen(player_ptr, why);
394 }
395
396 /*!
397  * @brief フロアに存在する全マスの記憶状態を初期化する / Wipe all unnecessary flags after grid_array generation
398  * @return なし
399  */
400 void wipe_generate_random_floor_flags(floor_type *floor_ptr)
401 {
402     for (POSITION y = 0; y < floor_ptr->height; y++)
403         for (POSITION x = 0; x < floor_ptr->width; x++)
404             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
405
406     if (floor_ptr->dun_level > 0)
407         for (POSITION y = 1; y < floor_ptr->height - 1; y++)
408             for (POSITION x = 1; x < floor_ptr->width - 1; x++)
409                 floor_ptr->grid_array[y][x].info |= CAVE_UNSAFE;
410 }
411
412 /*!
413  * @brief フロアの全情報を初期化する / Clear and empty floor.
414  * @parama player_ptr プレーヤーへの参照ポインタ
415  * @return なし
416  */
417 void clear_cave(player_type *player_ptr)
418 {
419     floor_type *floor_ptr = player_ptr->current_floor_ptr;
420     (void)C_WIPE(floor_ptr->o_list, floor_ptr->o_max, object_type);
421     floor_ptr->o_max = 1;
422     floor_ptr->o_cnt = 0;
423
424     for (int i = 1; i < max_r_idx; i++)
425         r_info[i].cur_num = 0;
426
427     (void)C_WIPE(floor_ptr->m_list, floor_ptr->m_max, monster_type);
428     floor_ptr->m_max = 1;
429     floor_ptr->m_cnt = 0;
430     for (int i = 0; i < MAX_MTIMED; i++)
431         floor_ptr->mproc_max[i] = 0;
432
433     precalc_cur_num_of_pet(player_ptr);
434     for (POSITION y = 0; y < MAX_HGT; y++) {
435         for (POSITION x = 0; x < MAX_WID; x++) {
436             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
437             g_ptr->info = 0;
438             g_ptr->feat = 0;
439             g_ptr->o_idx = 0;
440             g_ptr->m_idx = 0;
441             g_ptr->special = 0;
442             g_ptr->mimic = 0;
443             g_ptr->cost = 0;
444             g_ptr->dist = 0;
445             g_ptr->when = 0;
446         }
447     }
448
449     floor_ptr->base_level = floor_ptr->dun_level;
450     floor_ptr->monster_level = floor_ptr->base_level;
451     floor_ptr->object_level = floor_ptr->base_level;
452 }
453
454 /*!
455  * ダンジョンのランダムフロアを生成する / Generates a random dungeon level -RAK-
456  * @parama player_ptr プレーヤーへの参照ポインタ
457  * @return なし
458  * @note Hack -- regenerate any "overflow" levels
459  */
460 void generate_floor(player_type *player_ptr)
461 {
462     floor_type *floor_ptr = player_ptr->current_floor_ptr;
463     floor_ptr->dungeon_idx = player_ptr->dungeon_idx;
464     set_floor_and_wall(floor_ptr->dungeon_idx);
465     for (int num = 0; TRUE; num++) {
466         bool okay = TRUE;
467         concptr why = NULL;
468         clear_cave(player_ptr);
469         player_ptr->x = player_ptr->y = 0;
470         if (floor_ptr->inside_arena)
471             generate_challenge_arena(player_ptr);
472         else if (player_ptr->phase_out)
473             generate_gambling_arena(player_ptr);
474         else if (floor_ptr->inside_quest)
475             generate_fixed_floor(player_ptr);
476         else if (!floor_ptr->dun_level)
477             if (player_ptr->wild_mode)
478                 wilderness_gen_small(player_ptr);
479             else
480                 wilderness_gen(player_ptr);
481         else
482             okay = level_gen(player_ptr, &why);
483
484         if (floor_ptr->o_max >= current_world_ptr->max_o_idx) {
485             why = _("アイテムが多すぎる", "too many objects");
486             okay = FALSE;
487         } else if (floor_ptr->m_max >= current_world_ptr->max_m_idx) {
488             why = _("モンスターが多すぎる", "too many monsters");
489             okay = FALSE;
490         }
491
492         if (okay)
493             break;
494
495         if (why)
496             msg_format(_("生成やり直し(%s)", "Generation restarted (%s)"), why);
497
498         wipe_o_list(floor_ptr);
499         wipe_monsters_list(player_ptr);
500     }
501
502     glow_deep_lava_and_bldg(player_ptr);
503     player_ptr->enter_dungeon = FALSE;
504     wipe_generate_random_floor_flags(floor_ptr);
505 }
506
507 /*!
508  * @brief build_tunnel用に通路を掘るための方向をランダムに決める / Pick a random direction
509  * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
510  * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
511  * @return なし
512  */
513 static void rand_dir(POSITION *rdir, POSITION *cdir)
514 {
515     int i = randint0(4);
516     *rdir = ddy_ddd[i];
517     *cdir = ddx_ddd[i];
518 }
519
520 /*!
521  * @brief build_tunnel用に通路を掘るための方向を位置関係通りに決める / Always picks a correct direction
522  * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
523  * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
524  * @param y1 始点Y座標
525  * @param x1 始点X座標
526  * @param y2 終点Y座標
527  * @param x2 終点X座標
528  * @return なし
529  */
530 static void correct_dir(POSITION *rdir, POSITION *cdir, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
531 {
532     *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
533     *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
534     if (*rdir && *cdir) {
535         if (randint0(100) < 50)
536             *rdir = 0;
537         else
538             *cdir = 0;
539     }
540 }
541
542 /*!
543  * @brief 部屋間のトンネルを生成する / Constructs a tunnel between two points
544  * @param player_ptr プレーヤーへの参照ポインタ
545  * @param row1 始点Y座標
546  * @param col1 始点X座標
547  * @param row2 終点Y座標
548  * @param col2 終点X座標
549  * @return 生成に成功したらTRUEを返す
550  * @details
551  * This function must be called BEFORE any streamers are created,\n
552  * since we use the special "granite wall" sub-types to keep track\n
553  * of legal places for corridors to pierce rooms.\n
554  *\n
555  * We use "door_flag" to prevent excessive construction of doors\n
556  * along overlapping corridors.\n
557  *\n
558  * We queue the tunnel grids to prevent door creation along a corridor\n
559  * which intersects itself.\n
560  *\n
561  * We queue the wall piercing grids to prevent a corridor from leaving\n
562  * a room and then coming back in through the same entrance.\n
563  *\n
564  * We "pierce" grids which are "outer" walls of rooms, and when we\n
565  * do so, we change all adjacent "outer" walls of rooms into "solid"\n
566  * walls so that no two corridors may use adjacent grids for exits.\n
567  *\n
568  * The "solid" wall check prevents corridors from "chopping" the\n
569  * corners of rooms off, as well as "silly" door placement, and\n
570  * "excessively wide" room entrances.\n
571  *\n
572  * Kind of walls:\n
573  *   extra -- walls\n
574  *   inner -- inner room walls\n
575  *   outer -- outer room walls\n
576  *   solid -- solid room walls\n
577  */
578 bool build_tunnel(player_type *player_ptr, dt_type *dt_ptr, POSITION row1, POSITION col1, POSITION row2, POSITION col2)
579 {
580     POSITION tmp_row, tmp_col;
581     POSITION row_dir, col_dir;
582     POSITION start_row, start_col;
583     int main_loop_count = 0;
584     bool door_flag = FALSE;
585     grid_type *g_ptr;
586     start_row = row1;
587     start_col = col1;
588     correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
589     floor_type *floor_ptr = player_ptr->current_floor_ptr;
590     while ((row1 != row2) || (col1 != col2)) {
591         if (main_loop_count++ > 2000)
592             return FALSE;
593
594         if (randint0(100) < dt_ptr->dun_tun_chg) {
595             correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
596             if (randint0(100) < dt_ptr->dun_tun_rnd)
597                 rand_dir(&row_dir, &col_dir);
598         }
599
600         tmp_row = row1 + row_dir;
601         tmp_col = col1 + col_dir;
602         while (!in_bounds(floor_ptr, tmp_row, tmp_col)) {
603             correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
604             if (randint0(100) < dt_ptr->dun_tun_rnd)
605                 rand_dir(&row_dir, &col_dir);
606
607             tmp_row = row1 + row_dir;
608             tmp_col = col1 + col_dir;
609         }
610
611         g_ptr = &floor_ptr->grid_array[tmp_row][tmp_col];
612         if (is_solid_grid(g_ptr))
613             continue;
614
615         if (is_outer_grid(g_ptr)) {
616             POSITION y = tmp_row + row_dir;
617             POSITION x = tmp_col + col_dir;
618             if (is_outer_bold(floor_ptr, y, x) || is_solid_bold(floor_ptr, y, x))
619                 continue;
620
621             row1 = tmp_row;
622             col1 = tmp_col;
623             if (dun_data->wall_n >= WALL_MAX)
624                 return FALSE;
625
626             dun_data->wall[dun_data->wall_n].y = row1;
627             dun_data->wall[dun_data->wall_n].x = col1;
628             dun_data->wall_n++;
629             for (y = row1 - 1; y <= row1 + 1; y++)
630                 for (x = col1 - 1; x <= col1 + 1; x++)
631                     if (is_outer_bold(floor_ptr, y, x))
632                         place_bold(player_ptr, y, x, GB_SOLID_NOPERM);
633
634         } else if (g_ptr->info & (CAVE_ROOM)) {
635             row1 = tmp_row;
636             col1 = tmp_col;
637         } else if (is_extra_grid(g_ptr) || is_inner_grid(g_ptr) || is_solid_grid(g_ptr)) {
638             row1 = tmp_row;
639             col1 = tmp_col;
640             if (dun_data->tunn_n >= TUNN_MAX)
641                 return FALSE;
642
643             dun_data->tunn[dun_data->tunn_n].y = row1;
644             dun_data->tunn[dun_data->tunn_n].x = col1;
645             dun_data->tunn_n++;
646             door_flag = FALSE;
647         } else {
648             row1 = tmp_row;
649             col1 = tmp_col;
650             if (!door_flag) {
651                 if (dun_data->door_n >= DOOR_MAX)
652                     return FALSE;
653
654                 dun_data->door[dun_data->door_n].y = row1;
655                 dun_data->door[dun_data->door_n].x = col1;
656                 dun_data->door_n++;
657                 door_flag = TRUE;
658             }
659
660             if (randint0(100) >= dt_ptr->dun_tun_con) {
661                 tmp_row = row1 - start_row;
662                 if (tmp_row < 0)
663                     tmp_row = (-tmp_row);
664
665                 tmp_col = col1 - start_col;
666                 if (tmp_col < 0)
667                     tmp_col = (-tmp_col);
668
669                 if ((tmp_row > 10) || (tmp_col > 10))
670                     break;
671             }
672         }
673     }
674
675     return TRUE;
676 }
677
678 /*!
679  * @brief トンネル生成のための基準点を指定する。
680  * @param player_ptr プレーヤーへの参照ポインタ
681  * @param x 基準点を指定するX座標の参照ポインタ、適時値が修正される。
682  * @param y 基準点を指定するY座標の参照ポインタ、適時値が修正される。
683  * @param affectwall (調査中)
684  * @return なし
685  * @details
686  * This routine adds the square to the tunnel\n
687  * It also checks for SOLID walls - and returns a nearby\n
688  * non-SOLID square in (x,y) so that a simple avoiding\n
689  * routine can be used. The returned boolean value reflects\n
690  * whether or not this routine hit a SOLID wall.\n
691  *\n
692  * "affectwall" toggles whether or not this new square affects\n
693  * the boundaries of rooms. - This is used by the catacomb\n
694  * routine.\n
695  * @todo 特に詳細な処理の意味を調査すべし
696  */
697 static bool set_tunnel(player_type *player_ptr, POSITION *x, POSITION *y, bool affectwall)
698 {
699     floor_type *floor_ptr = player_ptr->current_floor_ptr;
700     grid_type *g_ptr = &floor_ptr->grid_array[*y][*x];
701     if (!in_bounds(floor_ptr, *y, *x) || is_inner_grid(g_ptr))
702         return TRUE;
703
704     if (is_extra_bold(floor_ptr, *y, *x)) {
705         if (dun_data->tunn_n >= TUNN_MAX)
706             return FALSE;
707
708         dun_data->tunn[dun_data->tunn_n].y = *y;
709         dun_data->tunn[dun_data->tunn_n].x = *x;
710         dun_data->tunn_n++;
711         return TRUE;
712     }
713
714     if (is_floor_bold(floor_ptr, *y, *x))
715         return TRUE;
716
717     if (is_outer_grid(g_ptr) && affectwall) {
718         if (dun_data->wall_n >= WALL_MAX)
719             return FALSE;
720
721         dun_data->wall[dun_data->wall_n].y = *y;
722         dun_data->wall[dun_data->wall_n].x = *x;
723         dun_data->wall_n++;
724         for (int j = *y - 1; j <= *y + 1; j++)
725             for (int i = *x - 1; i <= *x + 1; i++)
726                 if (is_outer_bold(floor_ptr, j, i))
727                     place_bold(player_ptr, j, i, GB_SOLID_NOPERM);
728
729         floor_ptr->grid_array[*y][*x].mimic = 0;
730         place_bold(player_ptr, *y, *x, GB_FLOOR);
731         return TRUE;
732     }
733
734     if (is_solid_grid(g_ptr) && affectwall) {
735         int i = 50;
736         int dy = 0;
737         int dx = 0;
738         while ((i > 0) && is_solid_bold(floor_ptr, *y + dy, *x + dx)) {
739             dy = randint0(3) - 1;
740             dx = randint0(3) - 1;
741             if (!in_bounds(floor_ptr, *y + dy, *x + dx)) {
742                 dx = 0;
743                 dy = 0;
744             }
745
746             i--;
747         }
748
749         if (i == 0) {
750             place_grid(player_ptr, g_ptr, GB_OUTER);
751             dx = 0;
752             dy = 0;
753         }
754
755         *x = *x + dx;
756         *y = *y + dy;
757         return FALSE;
758     }
759
760     return TRUE;
761 }
762
763 /*!
764  * @brief 外壁を削って「カタコンベ状」の通路を作成する / This routine creates the catacomb-like tunnels by removing extra rock.
765  * @param player_ptr プレーヤーへの参照ポインタ
766  * @param x 基準点のX座標
767  * @param y 基準点のY座標
768  * @return なし
769  * @details
770  * Note that this routine is only called on "even" squares - so it gives
771  * a natural checkerboard pattern.
772  */
773 static void create_cata_tunnel(player_type *player_ptr, POSITION x, POSITION y)
774 {
775     POSITION x1 = x - 1;
776     POSITION y1 = y;
777     set_tunnel(player_ptr, &x1, &y1, FALSE);
778
779     x1 = x + 1;
780     y1 = y;
781     set_tunnel(player_ptr, &x1, &y1, FALSE);
782
783     x1 = x;
784     y1 = y - 1;
785     set_tunnel(player_ptr, &x1, &y1, FALSE);
786
787     x1 = x;
788     y1 = y + 1;
789     set_tunnel(player_ptr, &x1, &y1, FALSE);
790 }
791
792 /*!
793  * @brief トンネル生成処理(詳細調査中)/ This routine does the bulk of the work in creating the new types of tunnels.
794  * @param player_ptr プレーヤーへの参照ポインタ
795  * @return なし
796  * @todo 詳細用調査
797  * @details
798  * It is designed to use very simple algorithms to go from (x1,y1) to (x2,y2)\n
799  * It doesn't need to add any complexity - straight lines are fine.\n
800  * The SOLID walls are avoided by a recursive algorithm which tries random ways\n
801  * around the obstical until it works.  The number of itterations is counted, and it\n
802  * this gets too large the routine exits. This should stop any crashes - but may leave\n
803  * small gaps in the tunnel where there are too many SOLID walls.\n
804  *\n
805  * Type 1 tunnels are extremely simple - straight line from A to B.  This is only used\n
806  * as a part of the dodge SOLID walls algorithm.\n
807  *\n
808  * Type 2 tunnels are made of two straight lines at right angles. When this is used with\n
809  * short line segments it gives the "cavelike" tunnels seen deeper in the dungeon.\n
810  *\n
811  * Type 3 tunnels are made of two straight lines like type 2, but with extra rock removed.\n
812  * This, when used with longer line segments gives the "catacomb-like" tunnels seen near\n
813  * the surface.\n
814  */
815 static void short_seg_hack(player_type *player_ptr, const POSITION x1, const POSITION y1, const POSITION x2, const POSITION y2, int type, int count, bool *fail)
816 {
817     if (!(*fail))
818         return;
819
820     int length = distance(x1, y1, x2, y2);
821     count++;
822     POSITION x, y;
823     if ((type == 1) && (length != 0)) {
824         for (int i = 0; i <= length; i++) {
825             x = x1 + i * (x2 - x1) / length;
826             y = y1 + i * (y2 - y1) / length;
827             if (!set_tunnel(player_ptr, &x, &y, TRUE)) {
828                 if (count > 50) {
829                     *fail = FALSE;
830                     return;
831                 }
832
833                 short_seg_hack(player_ptr, x, y, x1 + (i - 1) * (x2 - x1) / length, y1 + (i - 1) * (y2 - y1) / length, 1, count, fail);
834                 short_seg_hack(player_ptr, x, y, x1 + (i + 1) * (x2 - x1) / length, y1 + (i + 1) * (y2 - y1) / length, 1, count, fail);
835             }
836         }
837
838         return;
839     }
840
841     if ((type != 2) && (type != 3))
842         return;
843
844     if (x1 < x2) {
845         for (int i = x1; i <= x2; i++) {
846             x = i;
847             y = y1;
848             if (!set_tunnel(player_ptr, &x, &y, TRUE)) {
849                 short_seg_hack(player_ptr, x, y, i - 1, y1, 1, count, fail);
850                 short_seg_hack(player_ptr, x, y, i + 1, y1, 1, count, fail);
851             }
852
853             if ((type == 3) && ((x + y) % 2))
854                 create_cata_tunnel(player_ptr, i, y1);
855         }
856     } else {
857         for (int i = x2; i <= x1; i++) {
858             x = i;
859             y = y1;
860             if (!set_tunnel(player_ptr, &x, &y, TRUE)) {
861                 short_seg_hack(player_ptr, x, y, i - 1, y1, 1, count, fail);
862                 short_seg_hack(player_ptr, x, y, i + 1, y1, 1, count, fail);
863             }
864
865             if ((type == 3) && ((x + y) % 2))
866                 create_cata_tunnel(player_ptr, i, y1);
867         }
868     }
869
870     if (y1 < y2) {
871         for (int i = y1; i <= y2; i++) {
872             x = x2;
873             y = i;
874             if (!set_tunnel(player_ptr, &x, &y, TRUE)) {
875                 short_seg_hack(player_ptr, x, y, x2, i - 1, 1, count, fail);
876                 short_seg_hack(player_ptr, x, y, x2, i + 1, 1, count, fail);
877             }
878
879             if ((type == 3) && ((x + y) % 2))
880                 create_cata_tunnel(player_ptr, x2, i);
881         }
882     } else {
883         for (int i = y2; i <= y1; i++) {
884             x = x2;
885             y = i;
886             if (!set_tunnel(player_ptr, &x, &y, TRUE)) {
887                 short_seg_hack(player_ptr, x, y, x2, i - 1, 1, count, fail);
888                 short_seg_hack(player_ptr, x, y, x2, i + 1, 1, count, fail);
889             }
890
891             if ((type == 3) && ((x + y) % 2))
892                 create_cata_tunnel(player_ptr, x2, i);
893         }
894     }
895 }
896
897 /*!
898  * @brief 特定の壁(永久壁など)を避けながら部屋間の通路を作成する / This routine maps a path from (x1, y1) to (x2, y2) avoiding SOLID walls.
899  * @return なし
900  * @todo 詳細要調査
901  * @details
902  * Permanent rock is ignored in this path finding- sometimes there is no\n
903  * path around anyway -so there will be a crash if we try to find one.\n
904  * This routine is much like the river creation routine in Zangband.\n
905  * It works by dividing a line segment into two.  The segments are divided\n
906  * until they are less than "cutoff" - when the corresponding routine from\n
907  * "short_seg_hack" is called.\n
908  * Note it is VERY important that the "stop if hit another passage" logic\n
909  * stays as is.  Without this the dungeon turns into Swiss Cheese...\n
910  */
911 bool build_tunnel2(player_type *player_ptr, POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int cutoff)
912 {
913     POSITION x3, y3, dx, dy;
914     POSITION changex, changey;
915     bool retval, firstsuccede;
916     grid_type *g_ptr;
917
918     int length = distance(x1, y1, x2, y2);
919     floor_type *floor_ptr = player_ptr->current_floor_ptr;
920     if (length <= cutoff) {
921         retval = TRUE;
922         short_seg_hack(player_ptr, x1, y1, x2, y2, type, 0, &retval);
923         return TRUE;
924     }
925
926     dx = (x2 - x1) / 2;
927     dy = (y2 - y1) / 2;
928     changex = (randint0(abs(dy) + 2) * 2 - abs(dy) - 1) / 2;
929     changey = (randint0(abs(dx) + 2) * 2 - abs(dx) - 1) / 2;
930     x3 = x1 + dx + changex;
931     y3 = y1 + dy + changey;
932     if (!in_bounds(floor_ptr, y3, x3)) {
933         x3 = (x1 + x2) / 2;
934         y3 = (y1 + y2) / 2;
935     }
936
937     g_ptr = &floor_ptr->grid_array[y3][x3];
938     if (is_solid_grid(g_ptr)) {
939         int i = 50;
940         dy = 0;
941         dx = 0;
942         while ((i > 0) && is_solid_bold(floor_ptr, y3 + dy, x3 + dx)) {
943             dy = randint0(3) - 1;
944             dx = randint0(3) - 1;
945             if (!in_bounds(floor_ptr, y3 + dy, x3 + dx)) {
946                 dx = 0;
947                 dy = 0;
948             }
949             i--;
950         }
951
952         if (i == 0) {
953             place_bold(player_ptr, y3, x3, GB_OUTER);
954             dx = 0;
955             dy = 0;
956         }
957
958         y3 += dy;
959         x3 += dx;
960         g_ptr = &floor_ptr->grid_array[y3][x3];
961     }
962
963     if (is_floor_grid(g_ptr)) {
964         if (build_tunnel2(player_ptr, x1, y1, x3, y3, type, cutoff)) {
965             if ((floor_ptr->grid_array[y3][x3].info & CAVE_ROOM) || (randint1(100) > 95)) {
966                 retval = build_tunnel2(player_ptr, x3, y3, x2, y2, type, cutoff);
967             } else {
968                 retval = FALSE;
969                 if (dun_data->door_n >= DOOR_MAX)
970                     return FALSE;
971
972                 dun_data->door[dun_data->door_n].y = y3;
973                 dun_data->door[dun_data->door_n].x = x3;
974                 dun_data->door_n++;
975             }
976
977             firstsuccede = TRUE;
978         } else {
979             retval = FALSE;
980             firstsuccede = FALSE;
981         }
982     } else {
983         if (build_tunnel2(player_ptr, x1, y1, x3, y3, type, cutoff)) {
984             retval = build_tunnel2(player_ptr, x3, y3, x2, y2, type, cutoff);
985             firstsuccede = TRUE;
986         } else {
987             retval = FALSE;
988             firstsuccede = FALSE;
989         }
990     }
991
992     if (firstsuccede)
993         set_tunnel(player_ptr, &x3, &y3, TRUE);
994
995     return retval;
996 }