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"
8 #include "system/grid-type-definition.h"
9 #include "system/player-type-definition.h"
12 * @brief build_tunnel用に通路を掘るための方向をランダムに決める / Pick a random direction
13 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
14 * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
16 static void rand_dir(POSITION *rdir, POSITION *cdir)
24 * @brief build_tunnel用に通路を掘るための方向を位置関係通りに決める / Always picks a correct direction
25 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
26 * @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
36 *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1
39 if (randint0(100) < 50) {
48 * @brief 部屋間のトンネルを生成する / Constructs a tunnel between two points
49 * @param player_ptr プレイヤーへの参照ポインタ
54 * @return 生成に成功したらTRUEを返す
56 bool build_tunnel(PlayerType *player_ptr, dun_data_type *dd_ptr, dt_type *dt_ptr, POSITION row1, POSITION col1, POSITION row2, POSITION col2)
58 POSITION tmp_row, tmp_col;
59 POSITION row_dir, col_dir;
60 POSITION start_row, start_col;
61 int main_loop_count = 0;
62 bool door_flag = false;
65 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
66 auto *floor_ptr = player_ptr->current_floor_ptr;
67 while ((row1 != row2) || (col1 != col2)) {
68 if (main_loop_count++ > 2000) {
72 if (randint0(100) < dt_ptr->dun_tun_chg) {
73 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
74 if (randint0(100) < dt_ptr->dun_tun_rnd) {
75 rand_dir(&row_dir, &col_dir);
79 tmp_row = row1 + row_dir;
80 tmp_col = col1 + col_dir;
81 while (!in_bounds(floor_ptr, tmp_row, tmp_col)) {
82 correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
83 if (randint0(100) < dt_ptr->dun_tun_rnd) {
84 rand_dir(&row_dir, &col_dir);
87 tmp_row = row1 + row_dir;
88 tmp_col = col1 + col_dir;
91 auto *tmp_g_ptr = &floor_ptr->grid_array[tmp_row][tmp_col];
92 if (tmp_g_ptr->is_solid()) {
96 if (tmp_g_ptr->is_outer()) {
97 POSITION y = tmp_row + row_dir;
98 POSITION x = tmp_col + col_dir;
99 auto *g_ptr = &floor_ptr->grid_array[y][x];
100 if (g_ptr->is_outer() || g_ptr->is_solid()) {
106 if (dd_ptr->wall_n >= WALL_MAX) {
110 dd_ptr->wall[dd_ptr->wall_n].y = row1;
111 dd_ptr->wall[dd_ptr->wall_n].x = col1;
113 for (y = row1 - 1; y <= row1 + 1; y++) {
114 for (x = col1 - 1; x <= col1 + 1; x++) {
115 if (floor_ptr->grid_array[y][x].is_outer()) {
116 place_bold(player_ptr, y, x, GB_SOLID_NOPERM);
121 } else if (tmp_g_ptr->info & (CAVE_ROOM)) {
124 } else if (tmp_g_ptr->is_extra() || tmp_g_ptr->is_inner() || tmp_g_ptr->is_solid()) {
127 if (dd_ptr->tunn_n >= TUNN_MAX) {
131 dd_ptr->tunn[dd_ptr->tunn_n].y = row1;
132 dd_ptr->tunn[dd_ptr->tunn_n].x = col1;
139 if (dd_ptr->door_n >= DOOR_MAX) {
143 dd_ptr->door[dd_ptr->door_n].y = row1;
144 dd_ptr->door[dd_ptr->door_n].x = col1;
149 if (randint0(100) >= dt_ptr->dun_tun_con) {
150 tmp_row = row1 - start_row;
152 tmp_row = (-tmp_row);
155 tmp_col = col1 - start_col;
157 tmp_col = (-tmp_col);
160 if ((tmp_row > 10) || (tmp_col > 10)) {
171 * @brief トンネル生成のための基準点を指定する。
172 * @param player_ptr プレイヤーへの参照ポインタ
173 * @param x 基準点を指定するX座標の参照ポインタ、適時値が修正される。
174 * @param y 基準点を指定するY座標の参照ポインタ、適時値が修正される。
175 * @param affectwall (調査中)
176 * @todo 特に詳細な処理の意味を調査すべし
178 static bool set_tunnel(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION *x, POSITION *y, bool affectwall)
180 auto *floor_ptr = player_ptr->current_floor_ptr;
181 auto *g_ptr = &floor_ptr->grid_array[*y][*x];
182 if (!in_bounds(floor_ptr, *y, *x) || g_ptr->is_inner()) {
186 if (g_ptr->is_extra()) {
187 if (dd_ptr->tunn_n >= TUNN_MAX) {
191 dd_ptr->tunn[dd_ptr->tunn_n].y = *y;
192 dd_ptr->tunn[dd_ptr->tunn_n].x = *x;
197 if (g_ptr->is_floor()) {
201 if (g_ptr->is_outer() && affectwall) {
202 if (dd_ptr->wall_n >= WALL_MAX) {
206 dd_ptr->wall[dd_ptr->wall_n].y = *y;
207 dd_ptr->wall[dd_ptr->wall_n].x = *x;
209 for (int j = *y - 1; j <= *y + 1; j++) {
210 for (int i = *x - 1; i <= *x + 1; i++) {
211 if (floor_ptr->grid_array[j][i].is_outer()) {
212 place_bold(player_ptr, j, i, GB_SOLID_NOPERM);
217 floor_ptr->grid_array[*y][*x].mimic = 0;
218 place_bold(player_ptr, *y, *x, GB_FLOOR);
222 if (g_ptr->is_solid() && affectwall) {
226 while ((i > 0) && floor_ptr->grid_array[*y + dy][*x + dx].is_solid()) {
227 dy = randint0(3) - 1;
228 dx = randint0(3) - 1;
229 if (!in_bounds(floor_ptr, *y + dy, *x + dx)) {
238 place_grid(player_ptr, g_ptr, GB_OUTER);
252 * @brief 外壁を削って「カタコンベ状」の通路を作成する / This routine creates the catacomb-like tunnels by removing extra rock.
253 * @param player_ptr プレイヤーへの参照ポインタ
257 static void create_cata_tunnel(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION x, POSITION y)
261 set_tunnel(player_ptr, dd_ptr, &x1, &y1, false);
265 set_tunnel(player_ptr, dd_ptr, &x1, &y1, false);
269 set_tunnel(player_ptr, dd_ptr, &x1, &y1, false);
273 set_tunnel(player_ptr, dd_ptr, &x1, &y1, false);
277 * @brief トンネル生成処理(詳細調査中)/ This routine does the bulk of the work in creating the new types of tunnels.
278 * @param player_ptr プレイヤーへの参照ポインタ
281 static void short_seg_hack(
282 PlayerType *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)
288 int length = distance(x1, y1, x2, y2);
291 if ((type == 1) && (length != 0)) {
292 for (int i = 0; i <= length; i++) {
293 x = x1 + i * (x2 - x1) / length;
294 y = y1 + i * (y2 - y1) / length;
295 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, true)) {
301 short_seg_hack(player_ptr, dd_ptr, x, y, x1 + (i - 1) * (x2 - x1) / length, y1 + (i - 1) * (y2 - y1) / length, 1, count, fail);
302 short_seg_hack(player_ptr, dd_ptr, x, y, x1 + (i + 1) * (x2 - x1) / length, y1 + (i + 1) * (y2 - y1) / length, 1, count, fail);
309 if ((type != 2) && (type != 3)) {
314 for (int i = x1; i <= x2; i++) {
317 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, true)) {
318 short_seg_hack(player_ptr, dd_ptr, x, y, i - 1, y1, 1, count, fail);
319 short_seg_hack(player_ptr, dd_ptr, x, y, i + 1, y1, 1, count, fail);
322 if ((type == 3) && ((x + y) % 2)) {
323 create_cata_tunnel(player_ptr, dd_ptr, i, y1);
327 for (int i = x2; i <= x1; i++) {
330 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, true)) {
331 short_seg_hack(player_ptr, dd_ptr, x, y, i - 1, y1, 1, count, fail);
332 short_seg_hack(player_ptr, dd_ptr, x, y, i + 1, y1, 1, count, fail);
335 if ((type == 3) && ((x + y) % 2)) {
336 create_cata_tunnel(player_ptr, dd_ptr, i, y1);
342 for (int i = y1; i <= y2; i++) {
345 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, true)) {
346 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i - 1, 1, count, fail);
347 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i + 1, 1, count, fail);
350 if ((type == 3) && ((x + y) % 2)) {
351 create_cata_tunnel(player_ptr, dd_ptr, x2, i);
355 for (int i = y2; i <= y1; i++) {
358 if (!set_tunnel(player_ptr, dd_ptr, &x, &y, true)) {
359 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i - 1, 1, count, fail);
360 short_seg_hack(player_ptr, dd_ptr, x, y, x2, i + 1, 1, count, fail);
363 if ((type == 3) && ((x + y) % 2)) {
364 create_cata_tunnel(player_ptr, dd_ptr, x2, i);
371 * @brief 特定の壁(永久壁など)を避けながら部屋間の通路を作成する / This routine maps a path from (x1, y1) to (x2, y2) avoiding SOLID walls.
374 bool build_tunnel2(PlayerType *player_ptr, dun_data_type *dd_ptr, POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int cutoff)
376 POSITION x3, y3, dx, dy;
377 POSITION changex, changey;
378 bool retval, firstsuccede;
381 int length = distance(x1, y1, x2, y2);
382 auto *floor_ptr = player_ptr->current_floor_ptr;
383 if (length <= cutoff) {
385 short_seg_hack(player_ptr, dd_ptr, x1, y1, x2, y2, type, 0, &retval);
391 changex = (randint0(abs(dy) + 2) * 2 - abs(dy) - 1) / 2;
392 changey = (randint0(abs(dx) + 2) * 2 - abs(dx) - 1) / 2;
393 x3 = x1 + dx + changex;
394 y3 = y1 + dy + changey;
395 if (!in_bounds(floor_ptr, y3, x3)) {
400 g_ptr = &floor_ptr->grid_array[y3][x3];
401 if (g_ptr->is_solid()) {
405 while ((i > 0) && floor_ptr->grid_array[y3 + dy][x3 + dx].is_solid()) {
406 dy = randint0(3) - 1;
407 dx = randint0(3) - 1;
408 if (!in_bounds(floor_ptr, y3 + dy, x3 + dx)) {
416 place_bold(player_ptr, y3, x3, GB_OUTER);
423 g_ptr = &floor_ptr->grid_array[y3][x3];
426 if (g_ptr->is_floor()) {
427 if (build_tunnel2(player_ptr, dd_ptr, x1, y1, x3, y3, type, cutoff)) {
428 if (floor_ptr->grid_array[y3][x3].is_room() || (randint1(100) > 95)) {
429 retval = build_tunnel2(player_ptr, dd_ptr, x3, y3, x2, y2, type, cutoff);
432 if (dd_ptr->door_n >= DOOR_MAX) {
436 dd_ptr->door[dd_ptr->door_n].y = y3;
437 dd_ptr->door[dd_ptr->door_n].x = x3;
444 firstsuccede = false;
447 if (build_tunnel2(player_ptr, dd_ptr, x1, y1, x3, y3, type, cutoff)) {
448 retval = build_tunnel2(player_ptr, dd_ptr, x3, y3, x2, y2, type, cutoff);
452 firstsuccede = false;
457 set_tunnel(player_ptr, dd_ptr, &x3, &y3, true);