OSDN Git Service

[Refactor] #37353 BIAS_* と artifact_bias_name を artifact.c/h へ移動。 / Move BIAS_* and...
[hengband/hengband.git] / src / floor-generate.c
index 2d4a63e..e92bd4c 100644 (file)
  * 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
@@ -93,7 +93,7 @@
  * 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;
@@ -124,7 +126,7 @@ dun_data *dun;
  * @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;
 
@@ -143,9 +145,8 @@ static int next_to_walls(int y, int x)
  * @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 */
@@ -184,7 +185,7 @@ static bool alloc_stairs(IDX feat, int num, int walls)
        }
        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)
@@ -212,7 +213,7 @@ static bool alloc_stairs(IDX feat, int num, int walls)
        {
                while (TRUE)
                {
-                       int y = 0, x = 0;
+                       POSITION y, x = 0;
                        cave_type *c_ptr;
 
                        int candidates = 0;
@@ -259,8 +260,6 @@ static bool alloc_stairs(IDX feat, int num, int walls)
 
                                if (!pick) break;
                        }
-
-                       /* Access the grid */
                        c_ptr = &cave[y][x];
 
                        /* Clear possible garbage of hidden trap */
@@ -286,9 +285,10 @@ static bool alloc_stairs(IDX feat, int num, int walls)
  * @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;
 
@@ -305,7 +305,6 @@ static void alloc_object(int set, int typ, int num)
 
                        dummy++;
 
-                       /* Location */
                        y = randint0(cur_hgt);
                        x = randint0(cur_wid);
 
@@ -415,7 +414,7 @@ bool place_quest_monsters(void)
 
                        for (k = 0; k < SAFE_MAX_ATTEMPTS; k++)
                        {
-                               int x = 0, y = 0;
+                               POSITION x = 0, y = 0;
                                int l;
 
                                /* Find an empty grid */
@@ -600,8 +599,6 @@ static bool cave_gen(void)
 
        /* 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 */
@@ -714,20 +711,43 @@ static bool cave_gen(void)
                /* 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)
                        {
@@ -792,12 +812,8 @@ static bool cave_gen(void)
                        {
                                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];
 
@@ -815,12 +831,8 @@ static bool cave_gen(void)
                        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 */
@@ -981,7 +993,7 @@ static bool cave_gen(void)
  */
 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;
@@ -1038,9 +1050,9 @@ static void build_arena(void)
  */
 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;
@@ -1086,7 +1098,7 @@ static void arena_gen(void)
  */
 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;
@@ -1149,10 +1161,10 @@ static void build_battle(void)
  */
 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++)
@@ -1181,8 +1193,7 @@ static void battle_gen(void)
 
        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++)
@@ -1191,11 +1202,8 @@ static void battle_gen(void)
 
                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);
        }
 }
 
@@ -1205,8 +1213,7 @@ static void battle_gen(void)
  */
 static void quest_gen(void)
 {
-       int x, y;
-
+       POSITION x, y;
 
        /* Start with perm walls */
        for (y = 0; y < cur_hgt; y++)
@@ -1224,8 +1231,6 @@ static void quest_gen(void)
        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;
@@ -1237,7 +1242,7 @@ static void quest_gen(void)
  * @brief ダンジョン時のランダムフロア生成 / Make a real level
  * @return フロアの生成に成功したらTRUE
  */
-static bool level_gen(cptr *why)
+static bool level_gen(concptr *why)
 {
        int level_height, level_width;
 
@@ -1264,8 +1269,7 @@ static bool level_gen(cptr *why)
                                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;
@@ -1293,12 +1297,7 @@ static bool level_gen(cptr *why)
        /* 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;
@@ -1310,7 +1309,7 @@ static bool level_gen(cptr *why)
  */
 void wipe_generate_cave_flags(void)
 {
-       int x, y;
+       POSITION x, y;
 
        for (y = 0; y < cur_hgt; y++)
        {
@@ -1340,7 +1339,8 @@ void wipe_generate_cave_flags(void)
  */
 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);
@@ -1365,26 +1365,12 @@ void clear_cave(void)
                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;
@@ -1422,7 +1408,7 @@ void generate_cave(void)
        {
                bool okay = TRUE;
 
-               cptr why = NULL;
+               concptr why = NULL;
 
                /* Clear and empty the cave */
                clear_cave();
@@ -1464,47 +1450,22 @@ void generate_cave(void)
                /* 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();
        }
 
@@ -1516,3 +1477,659 @@ if (why) msg_format("生成やり直し(%s)", why);
 
        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;
+       }
+}
+