* Note that the dungeon generation routines are much different (2.7.5)\n
* and perhaps "DUN_ROOMS" should be less than 50.\n
*\n
- * XXX XXX XXX Note that it is possible to create a room which is only\n
+ * Note that it is possible to create a room which is only\n
* connected to itself, because the "tunnel generation" code allows a\n
* tunnel to leave a room, wander around, and then re-enter the room.\n
*\n
- * XXX XXX XXX Note that it is possible to create a set of rooms which\n
+ * Note that it is possible to create a set of rooms which\n
* are only connected to other rooms in that set, since there is nothing\n
* explicit in the code to prevent this from happening. But this is less\n
* likely than the "isolated room" problem, because each room attempts to\n
* but we must be careful not to allow, for example, the user to display\n
* hidden traps in a different way from floors, or secret doors in a way\n
* different from granite walls, or even permanent granite in a different\n
- * way from granite. XXX XXX XXX\n
+ * way from granite. \n
*/
#include "angband.h"
#include "rooms.h"
#include "floor-streams.h"
#include "trap.h"
+#include "monster.h"
+#include "quest.h"
int dun_tun_rnd;
int dun_tun_chg;
* @note Assumes "in_bounds(y, x)"
* @details We count only granite walls and permanent walls.
*/
-static int next_to_walls(int y, int x)
+static int next_to_walls(POSITION y, POSITION x)
{
int k = 0;
* @param walls 最低減隣接させたい外壁の数
* @return 階段を生成して問題がないならばTRUEを返す。
*/
-static bool alloc_stairs_aux(int y, int x, int walls)
+static bool alloc_stairs_aux(POSITION y, POSITION x, int walls)
{
- /* Access the grid */
cave_type *c_ptr = &cave[y][x];
/* Require "naked" floor grid */
}
else if (have_flag(f_ptr->flags, FF_MORE))
{
- int q_idx = quest_number(dun_level);
+ QUEST_IDX q_idx = quest_number(dun_level);
/* No downstairs on quest levels */
if (dun_level > 1 && q_idx)
{
while (TRUE)
{
- int y = 0, x = 0;
+ POSITION y, x = 0;
cave_type *c_ptr;
int candidates = 0;
if (!pick) break;
}
-
- /* Access the grid */
c_ptr = &cave[y][x];
/* Clear possible garbage of hidden trap */
* @param num 配置したい数
* @return 規定数通りに生成に成功したらTRUEを返す。
*/
-static void alloc_object(int set, int typ, int num)
+static void alloc_object(int set, EFFECT_ID typ, int num)
{
- int y = 0, x = 0, k;
+ POSITION y = 0, x = 0;
+ int k;
int dummy = 0;
cave_type *c_ptr;
dummy++;
- /* Location */
y = randint0(cur_hgt);
x = randint0(cur_wid);
for (k = 0; k < SAFE_MAX_ATTEMPTS; k++)
{
- int x = 0, y = 0;
+ POSITION x = 0, y = 0;
int l;
/* Find an empty grid */
/* Fill the arrays of floors and walls in the good proportions */
set_floor_and_wall(dungeon_type);
-
- /* Prepare allocation table */
get_mon_num_prep(get_monster_hook(), NULL);
/* Randomize the dungeon creation values */
/* Hack -- Add some rivers */
if (one_in_(3) && (randint1(dun_level) > 5))
{
- IDX feat1 = 0, feat2 = 0;
+ FEAT_IDX feat1 = 0, feat2 = 0;
- /* Choose water or lava */
+ /* Choose water mainly */
if ((randint1(MAX_DEPTH * 2) - 1 > dun_level) && (d_info[dungeon_type].flags1 & DF1_WATER_RIVER))
{
feat1 = feat_deep_water;
feat2 = feat_shallow_water;
}
- else if (d_info[dungeon_type].flags1 & DF1_LAVA_RIVER)
+ else /* others */
{
- feat1 = feat_deep_lava;
- feat2 = feat_shallow_lava;
+ FEAT_IDX select_deep_feat[10];
+ FEAT_IDX select_shallow_feat[10];
+ int select_id_max = 0, selected;
+
+ if (d_info[dungeon_type].flags1 & DF1_LAVA_RIVER)
+ {
+ select_deep_feat[select_id_max] = feat_deep_lava;
+ select_shallow_feat[select_id_max] = feat_shallow_lava;
+ select_id_max++;
+ }
+ if (d_info[dungeon_type].flags1 & DF1_POISONOUS_RIVER)
+ {
+ select_deep_feat[select_id_max] = feat_deep_poisonous_puddle;
+ select_shallow_feat[select_id_max] = feat_shallow_poisonous_puddle;
+ select_id_max++;
+ }
+ if (d_info[dungeon_type].flags1 & DF1_ACID_RIVER)
+ {
+ select_deep_feat[select_id_max] = feat_deep_acid_puddle;
+ select_shallow_feat[select_id_max] = feat_shallow_acid_puddle;
+ select_id_max++;
+ }
+
+ selected = randint0(select_id_max);
+ feat1 = select_deep_feat[selected];
+ feat2 = select_shallow_feat[selected];
}
- else feat1 = 0;
if (feat1)
{
{
cave_type *c_ptr;
feature_type *f_ptr;
-
- /* Access the grid */
y = dun->tunn[j].y;
x = dun->tunn[j].x;
-
- /* Access the grid */
c_ptr = &cave[y][x];
f_ptr = &f_info[c_ptr->feat];
for (j = 0; j < dun->wall_n; j++)
{
cave_type *c_ptr;
-
- /* Access the grid */
y = dun->wall[j].y;
x = dun->wall[j].x;
-
- /* Access the grid */
c_ptr = &cave[y][x];
/* Clear mimic type */
*/
static void build_arena(void)
{
- int yval, y_height, y_depth, xval, x_left, x_right;
+ POSITION yval, y_height, y_depth, xval, x_left, x_right;
register int i, j;
yval = SCREEN_HGT / 2;
*/
static void arena_gen(void)
{
- int y, x;
- int qy = 0;
- int qx = 0;
+ POSITION y, x;
+ POSITION qy = 0;
+ POSITION qx = 0;
/* Smallest area */
cur_hgt = SCREEN_HGT;
*/
static void build_battle(void)
{
- int yval, y_height, y_depth, xval, x_left, x_right;
+ POSITION yval, y_height, y_depth, xval, x_left, x_right;
register int i, j;
yval = SCREEN_HGT / 2;
*/
static void battle_gen(void)
{
- int y, x;
+ POSITION y, x;
MONSTER_IDX i;
- int qy = 0;
- int qx = 0;
+ POSITION qy = 0;
+ POSITION qx = 0;
/* Start with solid walls */
for (y = 0; y < MAX_HGT; y++)
for(i = 0; i < 4; i++)
{
- place_monster_aux(0, p_ptr->y + 8 + (i/2)*4, p_ptr->x - 2 + (i%2)*4, battle_mon[i],
- (PM_NO_KAGE | PM_NO_PET));
+ place_monster_aux(0, p_ptr->y + 8 + (i/2)*4, p_ptr->x - 2 + (i%2)*4, battle_mon[i], (PM_NO_KAGE | PM_NO_PET));
set_friendly(&m_list[cave[p_ptr->y+8+(i/2)*4][p_ptr->x-2+(i%2)*4].m_idx]);
}
for(i = 1; i < m_max; i++)
if (!m_ptr->r_idx) continue;
- /* Hack -- Detect monster */
m_ptr->mflag2 |= (MFLAG2_MARK | MFLAG2_SHOW);
-
- /* Update the monster */
- update_mon(i, FALSE);
+ update_monster(i, FALSE);
}
}
*/
static void quest_gen(void)
{
- int x, y;
-
+ POSITION x, y;
/* Start with perm walls */
for (y = 0; y < cur_hgt; y++)
monster_level = base_level;
if (record_stair) do_cmd_write_nikki(NIKKI_TO_QUEST, p_ptr->inside_quest, NULL);
-
- /* Prepare allocation table */
get_mon_num_prep(get_monster_hook(), NULL);
init_flags = INIT_CREATE_DUNGEON;
* @brief ダンジョン時のランダムフロア生成 / Make a real level
* @return フロアの生成に成功したらTRUE
*/
-static bool level_gen(cptr *why)
+static bool level_gen(concptr *why)
{
int level_height, level_width;
level_height = randint1(MAX_HGT/SCREEN_HGT);
level_width = randint1(MAX_WID/SCREEN_WID);
}
- while ((level_height == MAX_HGT/SCREEN_HGT) &&
- (level_width == MAX_WID/SCREEN_WID));
+ while ((level_height == MAX_HGT/SCREEN_HGT) && (level_width == MAX_WID/SCREEN_WID));
}
cur_hgt = level_height * SCREEN_HGT;
/* Make a dungeon */
if (!cave_gen())
{
-#ifdef JP
-*why = "ダンジョン生成に失敗";
-#else
- *why = "could not place player";
-#endif
-
+ *why = _("ダンジョン生成に失敗", "could not place player");
return FALSE;
}
else return TRUE;
*/
void wipe_generate_cave_flags(void)
{
- int x, y;
+ POSITION x, y;
for (y = 0; y < cur_hgt; y++)
{
*/
void clear_cave(void)
{
- int x, y, i;
+ POSITION x, y;
+ int i;
/* Very simplified version of wipe_o_list() */
(void)C_WIPE(o_list, o_max, object_type);
for (x = 0; x < MAX_WID; x++)
{
cave_type *c_ptr = &cave[y][x];
-
- /* No flags */
c_ptr->info = 0;
-
- /* No features */
c_ptr->feat = 0;
-
- /* No objects */
c_ptr->o_idx = 0;
-
- /* No monsters */
c_ptr->m_idx = 0;
-
- /* No special */
c_ptr->special = 0;
-
- /* No mimic */
c_ptr->mimic = 0;
-
- /* No flow */
c_ptr->cost = 0;
c_ptr->dist = 0;
c_ptr->when = 0;
{
bool okay = TRUE;
- cptr why = NULL;
+ concptr why = NULL;
/* Clear and empty the cave */
clear_cave();
/* Prevent object over-flow */
if (o_max >= max_o_idx)
{
- /* Message */
-#ifdef JP
-why = "アイテムが多すぎる";
-#else
- why = "too many objects";
-#endif
-
-
- /* Message */
+ why = _("アイテムが多すぎる", "too many objects");
okay = FALSE;
}
/* Prevent monster over-flow */
else if (m_max >= max_m_idx)
{
- /* Message */
-#ifdef JP
-why = "モンスターが多すぎる";
-#else
- why = "too many monsters";
-#endif
-
-
- /* Message */
+ why = _("モンスターが多すぎる", "too many monsters");
okay = FALSE;
}
/* Accept */
if (okay) break;
- /* Message */
-#ifdef JP
-if (why) msg_format("生成やり直し(%s)", why);
-#else
- if (why) msg_format("Generation restarted (%s)", why);
-#endif
+ if (why) msg_format(_("生成やり直し(%s)", "Generation restarted (%s)"), why);
-
- /* Wipe the objects */
wipe_o_list();
-
- /* Wipe the monsters */
wipe_m_list();
}
wipe_generate_cave_flags();
}
+
+/*!
+* @brief 部屋間のトンネルを生成する / Constructs a tunnel between two points
+* @param row1 始点Y座標
+* @param col1 始点X座標
+* @param row2 終点Y座標
+* @param col2 終点X座標
+* @return 生成に成功したらTRUEを返す
+* @details
+* This function must be called BEFORE any streamers are created,\n
+* since we use the special "granite wall" sub-types to keep track\n
+* of legal places for corridors to pierce rooms.\n
+*\n
+* We use "door_flag" to prevent excessive construction of doors\n
+* along overlapping corridors.\n
+*\n
+* We queue the tunnel grids to prevent door creation along a corridor\n
+* which intersects itself.\n
+*\n
+* We queue the wall piercing grids to prevent a corridor from leaving\n
+* a room and then coming back in through the same entrance.\n
+*\n
+* We "pierce" grids which are "outer" walls of rooms, and when we\n
+* do so, we change all adjacent "outer" walls of rooms into "solid"\n
+* walls so that no two corridors may use adjacent grids for exits.\n
+*\n
+* The "solid" wall check prevents corridors from "chopping" the\n
+* corners of rooms off, as well as "silly" door placement, and\n
+* "excessively wide" room entrances.\n
+*\n
+* Kind of walls:\n
+* extra -- walls\n
+* inner -- inner room walls\n
+* outer -- outer room walls\n
+* solid -- solid room walls\n
+*/
+bool build_tunnel(POSITION row1, POSITION col1, POSITION row2, POSITION col2)
+{
+ POSITION y, x;
+ POSITION tmp_row, tmp_col;
+ POSITION row_dir, col_dir;
+ POSITION start_row, start_col;
+ int main_loop_count = 0;
+
+ bool door_flag = FALSE;
+
+ cave_type *c_ptr;
+
+ /* Save the starting location */
+ start_row = row1;
+ start_col = col1;
+
+ /* Start out in the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Keep going until done (or bored) */
+ while ((row1 != row2) || (col1 != col2))
+ {
+ /* Mega-Hack -- Paranoia -- prevent infinite loops */
+ if (main_loop_count++ > 2000) return FALSE;
+
+ /* Allow bends in the tunnel */
+ if (randint0(100) < dun_tun_chg)
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (randint0(100) < dun_tun_rnd)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+
+
+ /* Extremely Important -- do not leave the dungeon */
+ while (!in_bounds(tmp_row, tmp_col))
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (randint0(100) < dun_tun_rnd)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+ }
+
+
+ /* Access the location */
+ c_ptr = &cave[tmp_row][tmp_col];
+
+ /* Avoid "solid" walls */
+ if (is_solid_grid(c_ptr)) continue;
+
+ /* Pierce "outer" walls of rooms */
+ if (is_outer_grid(c_ptr))
+ {
+ /* Acquire the "next" location */
+ y = tmp_row + row_dir;
+ x = tmp_col + col_dir;
+
+ /* Hack -- Avoid outer/solid walls */
+ if (is_outer_bold(y, x)) continue;
+ if (is_solid_bold(y, x)) continue;
+
+ /* Accept this location */
+ row1 = (POSITION)tmp_row;
+ col1 = (POSITION)tmp_col;
+
+ /* Save the wall location */
+ if (dun->wall_n < WALL_MAX)
+ {
+ dun->wall[dun->wall_n].y = row1;
+ dun->wall[dun->wall_n].x = col1;
+ dun->wall_n++;
+ }
+ else return FALSE;
+
+ /* Forbid re-entry near this piercing */
+ for (y = row1 - 1; y <= row1 + 1; y++)
+ {
+ for (x = col1 - 1; x <= col1 + 1; x++)
+ {
+ /* Convert adjacent "outer" walls as "solid" walls */
+ if (is_outer_bold(y, x))
+ {
+ /* Change the wall to a "solid" wall */
+ place_solid_noperm_bold(y, x);
+ }
+ }
+ }
+ }
+
+ /* Travel quickly through rooms */
+ else if (c_ptr->info & (CAVE_ROOM))
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+ }
+
+ /* Tunnel through all other walls */
+ else if (is_extra_grid(c_ptr) || is_inner_grid(c_ptr) || is_solid_grid(c_ptr))
+ {
+ /* Accept this location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Save the tunnel location */
+ if (dun->tunn_n < TUNN_MAX)
+ {
+ dun->tunn[dun->tunn_n].y = row1;
+ dun->tunn[dun->tunn_n].x = col1;
+ dun->tunn_n++;
+ }
+ else return FALSE;
+
+ /* Allow door in next grid */
+ door_flag = FALSE;
+ }
+
+ /* Handle corridor intersections or overlaps */
+ else
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Collect legal door locations */
+ if (!door_flag)
+ {
+ /* Save the door location */
+ if (dun->door_n < DOOR_MAX)
+ {
+ dun->door[dun->door_n].y = row1;
+ dun->door[dun->door_n].x = col1;
+ dun->door_n++;
+ }
+ else return FALSE;
+
+ /* No door in next grid */
+ door_flag = TRUE;
+ }
+
+ /* Hack -- allow pre-emptive tunnel termination */
+ if (randint0(100) >= dun_tun_con)
+ {
+ /* Distance between row1 and start_row */
+ tmp_row = row1 - start_row;
+ if (tmp_row < 0) tmp_row = (-tmp_row);
+
+ /* Distance between col1 and start_col */
+ tmp_col = col1 - start_col;
+ if (tmp_col < 0) tmp_col = (-tmp_col);
+
+ /* Terminate the tunnel */
+ if ((tmp_row > 10) || (tmp_col > 10)) break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*!
+* @brief トンネル生成のための基準点を指定する。
+* @param x 基準点を指定するX座標の参照ポインタ、適時値が修正される。
+* @param y 基準点を指定するY座標の参照ポインタ、適時値が修正される。
+* @param affectwall (調査中)
+* @return なし
+* @details
+* This routine adds the square to the tunnel\n
+* It also checks for SOLID walls - and returns a nearby\n
+* non-SOLID square in (x,y) so that a simple avoiding\n
+* routine can be used. The returned boolean value reflects\n
+* whether or not this routine hit a SOLID wall.\n
+*\n
+* "affectwall" toggles whether or not this new square affects\n
+* the boundaries of rooms. - This is used by the catacomb\n
+* routine.\n
+* @todo 特に詳細な処理の意味を調査すべし
+*/
+static bool set_tunnel(POSITION *x, POSITION *y, bool affectwall)
+{
+ int i, j, dx, dy;
+
+ cave_type *c_ptr = &cave[*y][*x];
+
+ if (!in_bounds(*y, *x)) return TRUE;
+
+ if (is_inner_grid(c_ptr))
+ {
+ return TRUE;
+ }
+
+ if (is_extra_bold(*y, *x))
+ {
+ /* Save the tunnel location */
+ if (dun->tunn_n < TUNN_MAX)
+ {
+ dun->tunn[dun->tunn_n].y = *y;
+ dun->tunn[dun->tunn_n].x = *x;
+ dun->tunn_n++;
+
+ return TRUE;
+ }
+ else return FALSE;
+ }
+
+ if (is_floor_bold(*y, *x))
+ {
+ /* Don't do anything */
+ return TRUE;
+ }
+
+ if (is_outer_grid(c_ptr) && affectwall)
+ {
+ /* Save the wall location */
+ if (dun->wall_n < WALL_MAX)
+ {
+ dun->wall[dun->wall_n].y = *y;
+ dun->wall[dun->wall_n].x = *x;
+ dun->wall_n++;
+ }
+ else return FALSE;
+
+ /* Forbid re-entry near this piercing */
+ for (j = *y - 1; j <= *y + 1; j++)
+ {
+ for (i = *x - 1; i <= *x + 1; i++)
+ {
+ /* Convert adjacent "outer" walls as "solid" walls */
+ if (is_outer_bold(j, i))
+ {
+ /* Change the wall to a "solid" wall */
+ place_solid_noperm_bold(j, i);
+ }
+ }
+ }
+
+ /* Clear mimic type */
+ cave[*y][*x].mimic = 0;
+
+ place_floor_bold(*y, *x);
+
+ return TRUE;
+ }
+
+ if (is_solid_grid(c_ptr) && affectwall)
+ {
+ /* cannot place tunnel here - use a square to the side */
+
+ /* find usable square and return value in (x,y) */
+
+ i = 50;
+
+ dy = 0;
+ dx = 0;
+ while ((i > 0) && is_solid_bold(*y + dy, *x + dx))
+ {
+ dy = randint0(3) - 1;
+ dx = randint0(3) - 1;
+
+ if (!in_bounds(*y + dy, *x + dx))
+ {
+ dx = 0;
+ dy = 0;
+ }
+
+ i--;
+ }
+
+ if (i == 0)
+ {
+ /* Failed for some reason: hack - ignore the solidness */
+ place_outer_grid(c_ptr);
+ dx = 0;
+ dy = 0;
+ }
+
+ /* Give new, acceptable coordinate. */
+ *x = *x + dx;
+ *y = *y + dy;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*!
+* @brief 外壁を削って「カタコンベ状」の通路を作成する / This routine creates the catacomb-like tunnels by removing extra rock.
+* @param x 基準点のX座標
+* @param y 基準点のY座標
+* @return なし
+* @details
+* Note that this routine is only called on "even" squares - so it gives
+* a natural checkerboard pattern.
+*/
+static void create_cata_tunnel(POSITION x, POSITION y)
+{
+ POSITION x1, y1;
+
+ /* Build tunnel */
+ x1 = x - 1;
+ y1 = y;
+ set_tunnel(&x1, &y1, FALSE);
+
+ x1 = x + 1;
+ y1 = y;
+ set_tunnel(&x1, &y1, FALSE);
+
+ x1 = x;
+ y1 = y - 1;
+ set_tunnel(&x1, &y1, FALSE);
+
+ x1 = x;
+ y1 = y + 1;
+ set_tunnel(&x1, &y1, FALSE);
+}
+
+
+/*!
+* @brief トンネル生成処理(詳細調査中)/ This routine does the bulk of the work in creating the new types of tunnels.
+* @return なし
+* @todo 詳細用調査
+* @details
+* It is designed to use very simple algorithms to go from (x1,y1) to (x2,y2)\n
+* It doesn't need to add any complexity - straight lines are fine.\n
+* The SOLID walls are avoided by a recursive algorithm which tries random ways\n
+* around the obstical until it works. The number of itterations is counted, and it\n
+* this gets too large the routine exits. This should stop any crashes - but may leave\n
+* small gaps in the tunnel where there are too many SOLID walls.\n
+*\n
+* Type 1 tunnels are extremely simple - straight line from A to B. This is only used\n
+* as a part of the dodge SOLID walls algorithm.\n
+*\n
+* Type 2 tunnels are made of two straight lines at right angles. When this is used with\n
+* short line segments it gives the "cavelike" tunnels seen deeper in the dungeon.\n
+*\n
+* Type 3 tunnels are made of two straight lines like type 2, but with extra rock removed.\n
+* This, when used with longer line segments gives the "catacomb-like" tunnels seen near\n
+* the surface.\n
+*/
+static void short_seg_hack(POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int count, bool *fail)
+{
+ int i;
+ POSITION x, y;
+ int length;
+
+ /* Check for early exit */
+ if (!(*fail)) return;
+
+ length = distance(x1, y1, x2, y2);
+
+ count++;
+
+ if ((type == 1) && (length != 0))
+ {
+
+ for (i = 0; i <= length; i++)
+ {
+ x = x1 + i * (x2 - x1) / length;
+ y = y1 + i * (y2 - y1) / length;
+ if (!set_tunnel(&x, &y, TRUE))
+ {
+ if (count > 50)
+ {
+ /* This isn't working - probably have an infinite loop */
+ *fail = FALSE;
+ return;
+ }
+
+ /* solid wall - so try to go around */
+ short_seg_hack(x, y, x1 + (i - 1) * (x2 - x1) / length, y1 + (i - 1) * (y2 - y1) / length, 1, count, fail);
+ short_seg_hack(x, y, x1 + (i + 1) * (x2 - x1) / length, y1 + (i + 1) * (y2 - y1) / length, 1, count, fail);
+ }
+ }
+ }
+ else if ((type == 2) || (type == 3))
+ {
+ if (x1 < x2)
+ {
+ for (i = x1; i <= x2; i++)
+ {
+ x = i;
+ y = y1;
+ if (!set_tunnel(&x, &y, TRUE))
+ {
+ /* solid wall - so try to go around */
+ short_seg_hack(x, y, i - 1, y1, 1, count, fail);
+ short_seg_hack(x, y, i + 1, y1, 1, count, fail);
+ }
+ if ((type == 3) && ((x + y) % 2))
+ {
+ create_cata_tunnel(i, y1);
+ }
+ }
+ }
+ else
+ {
+ for (i = x2; i <= x1; i++)
+ {
+ x = i;
+ y = y1;
+ if (!set_tunnel(&x, &y, TRUE))
+ {
+ /* solid wall - so try to go around */
+ short_seg_hack(x, y, i - 1, y1, 1, count, fail);
+ short_seg_hack(x, y, i + 1, y1, 1, count, fail);
+ }
+ if ((type == 3) && ((x + y) % 2))
+ {
+ create_cata_tunnel(i, y1);
+ }
+ }
+
+ }
+ if (y1 < y2)
+ {
+ for (i = y1; i <= y2; i++)
+ {
+ x = x2;
+ y = i;
+ if (!set_tunnel(&x, &y, TRUE))
+ {
+ /* solid wall - so try to go around */
+ short_seg_hack(x, y, x2, i - 1, 1, count, fail);
+ short_seg_hack(x, y, x2, i + 1, 1, count, fail);
+ }
+ if ((type == 3) && ((x + y) % 2))
+ {
+ create_cata_tunnel(x2, i);
+ }
+ }
+ }
+ else
+ {
+ for (i = y2; i <= y1; i++)
+ {
+ x = x2;
+ y = i;
+ if (!set_tunnel(&x, &y, TRUE))
+ {
+ /* solid wall - so try to go around */
+ short_seg_hack(x, y, x2, i - 1, 1, count, fail);
+ short_seg_hack(x, y, x2, i + 1, 1, count, fail);
+ }
+ if ((type == 3) && ((x + y) % 2))
+ {
+ create_cata_tunnel(x2, i);
+ }
+ }
+ }
+ }
+}
+
+
+/*!
+* @brief 特定の壁(永久壁など)を避けながら部屋間の通路を作成する / This routine maps a path from (x1, y1) to (x2, y2) avoiding SOLID walls.
+* @return なし
+* @todo 詳細要調査
+* @details
+* Permanent rock is ignored in this path finding- sometimes there is no\n
+* path around anyway -so there will be a crash if we try to find one.\n
+* This routine is much like the river creation routine in Zangband.\n
+* It works by dividing a line segment into two. The segments are divided\n
+* until they are less than "cutoff" - when the corresponding routine from\n
+* "short_seg_hack" is called.\n
+* Note it is VERY important that the "stop if hit another passage" logic\n
+* stays as is. Without this the dungeon turns into Swiss Cheese...\n
+*/
+bool build_tunnel2(POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int cutoff)
+{
+ POSITION x3, y3, dx, dy;
+ POSITION changex, changey;
+ int length;
+ int i;
+ bool retval, firstsuccede;
+ cave_type *c_ptr;
+
+ length = distance(x1, y1, x2, y2);
+
+ if (length > cutoff)
+ {
+ /*
+ * Divide path in half and call routine twice.
+ */
+ dx = (x2 - x1) / 2;
+ dy = (y2 - y1) / 2;
+
+ /* perturbation perpendicular to path */
+ changex = (randint0(abs(dy) + 2) * 2 - abs(dy) - 1) / 2;
+ changey = (randint0(abs(dx) + 2) * 2 - abs(dx) - 1) / 2;
+
+ /* Work out "mid" ponit */
+ x3 = x1 + dx + changex;
+ y3 = y1 + dy + changey;
+
+ /* See if in bounds - if not - do not perturb point */
+ if (!in_bounds(y3, x3))
+ {
+ x3 = (x1 + x2) / 2;
+ y3 = (y1 + y2) / 2;
+ }
+ /* cache c_ptr */
+ c_ptr = &cave[y3][x3];
+ if (is_solid_grid(c_ptr))
+ {
+ /* move midpoint a bit to avoid problem. */
+
+ i = 50;
+
+ dy = 0;
+ dx = 0;
+ while ((i > 0) && is_solid_bold(y3 + dy, x3 + dx))
+ {
+ dy = randint0(3) - 1;
+ dx = randint0(3) - 1;
+ if (!in_bounds(y3 + dy, x3 + dx))
+ {
+ dx = 0;
+ dy = 0;
+ }
+ i--;
+ }
+
+ if (i == 0)
+ {
+ /* Failed for some reason: hack - ignore the solidness */
+ place_outer_bold(y3, x3);
+ dx = 0;
+ dy = 0;
+ }
+ y3 += dy;
+ x3 += dx;
+ c_ptr = &cave[y3][x3];
+ }
+
+ if (is_floor_grid(c_ptr))
+ {
+ if (build_tunnel2(x1, y1, x3, y3, type, cutoff))
+ {
+ if ((cave[y3][x3].info & CAVE_ROOM) || (randint1(100) > 95))
+ {
+ /* do second half only if works + if have hit a room */
+ retval = build_tunnel2(x3, y3, x2, y2, type, cutoff);
+ }
+ else
+ {
+ /* have hit another tunnel - make a set of doors here */
+ retval = FALSE;
+
+ /* Save the door location */
+ if (dun->door_n < DOOR_MAX)
+ {
+ dun->door[dun->door_n].y = (POSITION)y3;
+ dun->door[dun->door_n].x = (POSITION)x3;
+ dun->door_n++;
+ }
+ else return FALSE;
+ }
+ firstsuccede = TRUE;
+ }
+ else
+ {
+ /* false- didn't work all the way */
+ retval = FALSE;
+ firstsuccede = FALSE;
+ }
+ }
+ else
+ {
+ /* tunnel through walls */
+ if (build_tunnel2(x1, y1, (POSITION)x3, (POSITION)y3, type, cutoff))
+ {
+ retval = build_tunnel2((POSITION)x3, (POSITION)y3, x2, y2, type, cutoff);
+ firstsuccede = TRUE;
+ }
+ else
+ {
+ /* false- didn't work all the way */
+ retval = FALSE;
+ firstsuccede = FALSE;
+ }
+ }
+ if (firstsuccede)
+ {
+ /* only do this if the first half has worked */
+ set_tunnel(&x3, &y3, TRUE);
+ }
+ /* return value calculated above */
+ return retval;
+ }
+ else
+ {
+ /* Do a short segment */
+ retval = TRUE;
+ short_seg_hack(x1, y1, x2, y2, type, 0, &retval);
+
+ /* Hack - ignore return value so avoid infinite loops */
+ return TRUE;
+ }
+}
+