1 #include "floor/tunnel-generator.h"
2 #include "floor/cave.h"
3 #include "floor/dungeon-tunnel-util.h"
4 #include "floor/geometry.h"
6 #include "system/dungeon-data-definition.h"
7 #include "system/floor-type-definition.h"
10 * @brief build_tunnel用に通路を掘るための方向をランダムに決める / Pick a random direction
11 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
12 * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
15 static void rand_dir(POSITION *rdir, POSITION *cdir)
23 * @brief build_tunnel用に通路を掘るための方向を位置関係通りに決める / Always picks a correct direction
24 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
25 * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
32 static void correct_dir(POSITION *rdir, POSITION *cdir, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
34 *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
35 *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
37 if (randint0(100) < 50)
45 * @brief 部屋間のトンネルを生成する / Constructs a tunnel between two points
46 * @param player_ptr プレーヤーへの参照ポインタ
51 * @return 生成に成功したらTRUEを返す
53 bool build_tunnel(player_type *player_ptr, dun_data_type *dd_ptr, dt_type *dt_ptr, POSITION row1, POSITION col1, POSITION row2, POSITION col2)
55 POSITION tmp_row, tmp_col;
56 POSITION row_dir, col_dir;
57 POSITION start_row, start_col;
58 int main_loop_count = 0;
59 bool door_flag = FALSE;
63 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
64 floor_type *floor_ptr = player_ptr->current_floor_ptr;
65 while ((row1 != row2) || (col1 != col2)) {
66 if (main_loop_count++ > 2000)
69 if (randint0(100) < dt_ptr->dun_tun_chg) {
70 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
71 if (randint0(100) < dt_ptr->dun_tun_rnd)
72 rand_dir(&row_dir, &col_dir);
75 tmp_row = row1 + row_dir;
76 tmp_col = col1 + col_dir;
77 while (!in_bounds(floor_ptr, tmp_row, tmp_col)) {
78 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
79 if (randint0(100) < dt_ptr->dun_tun_rnd)
80 rand_dir(&row_dir, &col_dir);
82 tmp_row = row1 + row_dir;
83 tmp_col = col1 + col_dir;
86 g_ptr = &floor_ptr->grid_array[tmp_row][tmp_col];
87 if (is_solid_grid(g_ptr))
90 if (is_outer_grid(g_ptr)) {
91 POSITION y = tmp_row + row_dir;
92 POSITION x = tmp_col + col_dir;
93 if (is_outer_bold(floor_ptr, y, x) || is_solid_bold(floor_ptr, y, x))
98 if (dd_ptr->wall_n >= WALL_MAX)
101 dd_ptr->wall[dd_ptr->wall_n].y = row1;
102 dd_ptr->wall[dd_ptr->wall_n].x = col1;
104 for (y = row1 - 1; y <= row1 + 1; y++)
105 for (x = col1 - 1; x <= col1 + 1; x++)
106 if (is_outer_bold(floor_ptr, y, x))
107 place_bold(player_ptr, y, x, GB_SOLID_NOPERM);
109 } else if (g_ptr->info & (CAVE_ROOM)) {
112 } else if (is_extra_grid(g_ptr) || is_inner_grid(g_ptr) || is_solid_grid(g_ptr)) {
115 if (dd_ptr->tunn_n >= TUNN_MAX)
118 dd_ptr->tunn[dd_ptr->tunn_n].y = row1;
119 dd_ptr->tunn[dd_ptr->tunn_n].x = col1;
126 if (dd_ptr->door_n >= DOOR_MAX)
129 dd_ptr->door[dd_ptr->door_n].y = row1;
130 dd_ptr->door[dd_ptr->door_n].x = col1;
135 if (randint0(100) >= dt_ptr->dun_tun_con) {
136 tmp_row = row1 - start_row;
138 tmp_row = (-tmp_row);
140 tmp_col = col1 - start_col;
142 tmp_col = (-tmp_col);
144 if ((tmp_row > 10) || (tmp_col > 10))
154 * todo 特に詳細な処理の意味を調査すべし
155 * @brief トンネル生成のための基準点を指定する。
156 * @param player_ptr プレーヤーへの参照ポインタ
157 * @param x 基準点を指定するX座標の参照ポインタ、適時値が修正される。
158 * @param y 基準点を指定するY座標の参照ポインタ、適時値が修正される。
159 * @param affectwall (調査中)
162 static bool set_tunnel(player_type *player_ptr, dun_data_type *dd_ptr, POSITION *x, POSITION *y, bool affectwall)
164 floor_type *floor_ptr = player_ptr->current_floor_ptr;
165 grid_type *g_ptr = &floor_ptr->grid_array[*y][*x];
166 if (!in_bounds(floor_ptr, *y, *x) || is_inner_grid(g_ptr))
169 if (is_extra_bold(floor_ptr, *y, *x)) {
170 if (dd_ptr->tunn_n >= TUNN_MAX)
173 dd_ptr->tunn[dd_ptr->tunn_n].y = *y;
174 dd_ptr->tunn[dd_ptr->tunn_n].x = *x;
179 if (is_floor_bold(floor_ptr, *y, *x))
182 if (is_outer_grid(g_ptr) && affectwall) {
183 if (dd_ptr->wall_n >= WALL_MAX)
186 dd_ptr->wall[dd_ptr->wall_n].y = *y;
187 dd_ptr->wall[dd_ptr->wall_n].x = *x;
189 for (int j = *y - 1; j <= *y + 1; j++)
190 for (int i = *x - 1; i <= *x + 1; i++)
191 if (is_outer_bold(floor_ptr, j, i))
192 place_bold(player_ptr, j, i, GB_SOLID_NOPERM);
194 floor_ptr->grid_array[*y][*x].mimic = 0;
195 place_bold(player_ptr, *y, *x, GB_FLOOR);
199 if (is_solid_grid(g_ptr) && affectwall) {
203 while ((i > 0) && is_solid_bold(floor_ptr, *y + dy, *x + dx)) {
204 dy = randint0(3) - 1;
205 dx = randint0(3) - 1;
206 if (!in_bounds(floor_ptr, *y + dy, *x + dx)) {
215 place_grid(player_ptr, g_ptr, GB_OUTER);
229 * @brief 外壁を削って「カタコンベ状」の通路を作成する / This routine creates the catacomb-like tunnels by removing extra rock.
230 * @param player_ptr プレーヤーへの参照ポインタ
235 static void create_cata_tunnel(player_type *player_ptr, dun_data_type *dd_ptr, POSITION x, POSITION y)
239 set_tunnel(player_ptr, dd_ptr, &x1, &y1, FALSE);
243 set_tunnel(player_ptr, dd_ptr, &x1, &y1, FALSE);
247 set_tunnel(player_ptr, dd_ptr, &x1, &y1, FALSE);
251 set_tunnel(player_ptr, dd_ptr, &x1, &y1, FALSE);
256 * @brief トンネル生成処理(詳細調査中)/ This routine does the bulk of the work in creating the new types of tunnels.
257 * @param player_ptr プレーヤーへの参照ポインタ
260 static void short_seg_hack(
261 player_type *player_ptr, dun_data_type *dd_ptr, const POSITION x1, const POSITION y1, const POSITION x2, const POSITION y2, int type, int count, bool *fail)
266 int length = distance(x1, y1, x2, y2);
269 if ((type == 1) && (length != 0)) {
270 for (int i = 0; i <= length; i++) {
271 x = x1 + i * (x2 - x1) / length;
272 y = y1 + i * (y2 - y1) / length;
273 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, TRUE)) {
279 short_seg_hack(player_ptr, dd_ptr, x, y, x1 + (i - 1) * (x2 - x1) / length, y1 + (i - 1) * (y2 - y1) / length, 1, count, fail);
280 short_seg_hack(player_ptr, dd_ptr, x, y, x1 + (i + 1) * (x2 - x1) / length, y1 + (i + 1) * (y2 - y1) / length, 1, count, fail);
287 if ((type != 2) && (type != 3))
291 for (int i = x1; i <= x2; i++) {
294 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, TRUE)) {
295 short_seg_hack(player_ptr, dd_ptr, x, y, i - 1, y1, 1, count, fail);
296 short_seg_hack(player_ptr, dd_ptr, x, y, i + 1, y1, 1, count, fail);
299 if ((type == 3) && ((x + y) % 2))
300 create_cata_tunnel(player_ptr, dd_ptr, i, y1);
303 for (int i = x2; i <= x1; i++) {
306 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, TRUE)) {
307 short_seg_hack(player_ptr, dd_ptr, x, y, i - 1, y1, 1, count, fail);
308 short_seg_hack(player_ptr, dd_ptr, x, y, i + 1, y1, 1, count, fail);
311 if ((type == 3) && ((x + y) % 2))
312 create_cata_tunnel(player_ptr, dd_ptr, i, y1);
317 for (int i = y1; i <= y2; i++) {
320 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, TRUE)) {
321 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i - 1, 1, count, fail);
322 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i + 1, 1, count, fail);
325 if ((type == 3) && ((x + y) % 2))
326 create_cata_tunnel(player_ptr, dd_ptr, x2, i);
329 for (int i = y2; i <= y1; i++) {
332 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, TRUE)) {
333 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i - 1, 1, count, fail);
334 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i + 1, 1, count, fail);
337 if ((type == 3) && ((x + y) % 2))
338 create_cata_tunnel(player_ptr, dd_ptr, x2, i);
345 * @brief 特定の壁(永久壁など)を避けながら部屋間の通路を作成する / This routine maps a path from (x1, y1) to (x2, y2) avoiding SOLID walls.
348 bool build_tunnel2(player_type *player_ptr, dun_data_type *dd_ptr, POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int cutoff)
350 POSITION x3, y3, dx, dy;
351 POSITION changex, changey;
352 bool retval, firstsuccede;
355 int length = distance(x1, y1, x2, y2);
356 floor_type *floor_ptr = player_ptr->current_floor_ptr;
357 if (length <= cutoff) {
359 short_seg_hack(player_ptr, dd_ptr, x1, y1, x2, y2, type, 0, &retval);
365 changex = (randint0(abs(dy) + 2) * 2 - abs(dy) - 1) / 2;
366 changey = (randint0(abs(dx) + 2) * 2 - abs(dx) - 1) / 2;
367 x3 = x1 + dx + changex;
368 y3 = y1 + dy + changey;
369 if (!in_bounds(floor_ptr, y3, x3)) {
374 g_ptr = &floor_ptr->grid_array[y3][x3];
375 if (is_solid_grid(g_ptr)) {
379 while ((i > 0) && is_solid_bold(floor_ptr, y3 + dy, x3 + dx)) {
380 dy = randint0(3) - 1;
381 dx = randint0(3) - 1;
382 if (!in_bounds(floor_ptr, y3 + dy, x3 + dx)) {
390 place_bold(player_ptr, y3, x3, GB_OUTER);
397 g_ptr = &floor_ptr->grid_array[y3][x3];
400 if (is_floor_grid(g_ptr)) {
401 if (build_tunnel2(player_ptr, dd_ptr, x1, y1, x3, y3, type, cutoff)) {
402 if ((floor_ptr->grid_array[y3][x3].info & CAVE_ROOM) || (randint1(100) > 95)) {
403 retval = build_tunnel2(player_ptr, dd_ptr, x3, y3, x2, y2, type, cutoff);
406 if (dd_ptr->door_n >= DOOR_MAX)
409 dd_ptr->door[dd_ptr->door_n].y = y3;
410 dd_ptr->door[dd_ptr->door_n].x = x3;
417 firstsuccede = FALSE;
420 if (build_tunnel2(player_ptr, dd_ptr, x1, y1, x3, y3, type, cutoff)) {
421 retval = build_tunnel2(player_ptr, dd_ptr, x3, y3, x2, y2, type, cutoff);
425 firstsuccede = FALSE;
430 set_tunnel(player_ptr, dd_ptr, &x3, &y3, TRUE);