OSDN Git Service

#37353 (2.2.0.89) feat参照タグの文字列オフセット値を負値にしてmimic, destroyedなどの地形ID変数に無理やり押し込んでいた処理をSTR...
[hengband/hengband.git] / src / grid.c
1 /*!
2  * @file grid.c
3  * @brief ダンジョンの生成処理の基幹部分 / low-level dungeon creation primitives
4  * @date 2014/01/04
5  * @author
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
7  *\n
8  * This software may be copied and distributed for educational, research,\n
9  * and not for profit purposes provided that this copyright and statement\n
10  * are included in all such copies.  Other copyrights may also apply.\n
11  * \n
12  * 2014 Deskull Doxygen向けのコメント整理\n
13  */
14
15 #include "angband.h"
16 #include "generate.h"
17 #include "grid.h"
18
19
20 /*!
21  * @brief 新規フロアに入りたてのプレイヤーをランダムな場所に配置する / Returns random co-ordinates for player/monster/object
22  * @return 配置に成功したらTRUEを返す
23  */
24 bool new_player_spot(void)
25 {
26         POSITION y = 0, x = 0;
27         int max_attempts = 10000;
28
29         cave_type *c_ptr;
30         feature_type *f_ptr;
31
32         /* Place the player */
33         while (max_attempts--)
34         {
35                 /* Pick a legal spot */
36                 y = (POSITION)rand_range(1, cur_hgt - 2);
37                 x = (POSITION)rand_range(1, cur_wid - 2);
38
39                 c_ptr = &cave[y][x];
40
41                 /* Must be a "naked" floor grid */
42                 if (c_ptr->m_idx) continue;
43                 if (dun_level)
44                 {
45                         f_ptr = &f_info[c_ptr->feat];
46
47                         if (max_attempts > 5000) /* Rule 1 */
48                         {
49                                 if (!have_flag(f_ptr->flags, FF_FLOOR)) continue;
50                         }
51                         else /* Rule 2 */
52                         {
53                                 if (!have_flag(f_ptr->flags, FF_MOVE)) continue;
54                                 if (have_flag(f_ptr->flags, FF_HIT_TRAP)) continue;
55                         }
56
57                         /* Refuse to start on anti-teleport grids in dungeon */
58                         if (!have_flag(f_ptr->flags, FF_TELEPORTABLE)) continue;
59                 }
60                 if (!player_can_enter(c_ptr->feat, 0)) continue;
61                 if (!in_bounds(y, x)) continue;
62
63                 /* Refuse to start on anti-teleport grids */
64                 if (c_ptr->info & (CAVE_ICKY)) continue;
65
66                 /* Done */
67                 break;
68         }
69
70         if (max_attempts < 1) /* Should be -1, actually if we failed... */
71                 return FALSE;
72
73         /* Save the new player grid */
74         p_ptr->y = y;
75         p_ptr->x = x;
76
77         return TRUE;
78 }
79
80
81
82 /*!
83  * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
84  * @param y 配置を試みたいマスのY座標
85  * @param x 配置を試みたいマスのX座標
86  * @return なし
87  */
88 void place_random_stairs(int y, int x)
89 {
90         bool up_stairs = TRUE;
91         bool down_stairs = TRUE;
92         cave_type *c_ptr;
93
94         /* Paranoia */
95         c_ptr = &cave[y][x];
96         if (!is_floor_grid(c_ptr) || c_ptr->o_idx) return;
97
98         /* Town */
99         if (!dun_level)
100                 up_stairs = FALSE;
101
102         /* Ironman */
103         if (ironman_downward)
104                 up_stairs = FALSE;
105
106         /* Bottom */
107         if (dun_level >= d_info[dungeon_type].maxdepth)
108                 down_stairs = FALSE;
109
110         /* Quest-level */
111         if (quest_number(dun_level) && (dun_level > 1))
112                 down_stairs = FALSE;
113
114         /* We can't place both */
115         if (down_stairs && up_stairs)
116         {
117                 /* Choose a staircase randomly */
118                 if (randint0(100) < 50)
119                         up_stairs = FALSE;
120                 else
121                         down_stairs = FALSE;
122         }
123
124         /* Place the stairs */
125         if (up_stairs)
126                 place_up_stairs(y, x);
127         else if (down_stairs)
128                 place_down_stairs(y, x);
129 }
130
131 /*!
132  * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
133  * @param y ドアの配置を試みたいマスのY座標
134  * @param x ドアの配置を試みたいマスのX座標
135  * @param room 部屋に接している場合向けのドア生成か否か
136  * @return なし
137  */
138 void place_random_door(int y, int x, bool room)
139 {
140         int tmp, type;
141         s16b feat = feat_none;
142         cave_type *c_ptr = &cave[y][x];
143
144         /* Initialize mimic info */
145         c_ptr->mimic = 0;
146
147         if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
148         {
149                 place_floor_bold(y, x);
150                 return;
151         }
152
153         type = ((d_info[dungeon_type].flags1 & DF1_CURTAIN) &&
154                 one_in_((d_info[dungeon_type].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
155                 ((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
156
157         /* Choose an object */
158         tmp = randint0(1000);
159
160         /* Open doors (300/1000) */
161         if (tmp < 300)
162         {
163                 /* Create open door */
164                 feat = feat_door[type].open;
165         }
166
167         /* Broken doors (100/1000) */
168         else if (tmp < 400)
169         {
170                 /* Create broken door */
171                 feat = feat_door[type].broken;
172         }
173
174         /* Secret doors (200/1000) */
175         else if (tmp < 600)
176         {
177                 /* Create secret door */
178                 place_closed_door(y, x, type);
179
180                 if (type != DOOR_CURTAIN)
181                 {
182                         /* Hide. If on the edge of room, use outer wall. */
183                         c_ptr->mimic = room ? feat_wall_outer : fill_type[randint0(100)];
184
185                         /* Floor type terrain cannot hide a door */
186                         if (feat_supports_los(c_ptr->mimic) && !feat_supports_los(c_ptr->feat))
187                         {
188                                 if (have_flag(f_info[c_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[c_ptr->mimic].flags, FF_CAN_FLY))
189                                 {
190                                         c_ptr->feat = one_in_(2) ? c_ptr->mimic : floor_type[randint0(100)];
191                                 }
192                                 c_ptr->mimic = 0;
193                         }
194                 }
195         }
196
197         /* Closed, locked, or stuck doors (400/1000) */
198         else place_closed_door(y, x, type);
199
200         if (tmp < 400)
201         {
202                 if (feat != feat_none)
203                 {
204                         set_cave_feat(y, x, feat);
205                 }
206                 else
207                 {
208                         place_floor_bold(y, x);
209                 }
210         }
211
212         delete_monster(y, x);
213 }
214
215 /*!
216  * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
217  * @param y ドアの配置を試みたいマスのY座標
218  * @param x ドアの配置を試みたいマスのX座標
219  * @param type ドアの地形ID
220  * @return なし
221  */
222 void place_closed_door(int y, int x, int type)
223 {
224         int tmp;
225         s16b feat = feat_none;
226
227         if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
228         {
229                 place_floor_bold(y, x);
230                 return;
231         }
232
233         /* Choose an object */
234         tmp = randint0(400);
235
236         /* Closed doors (300/400) */
237         if (tmp < 300)
238         {
239                 /* Create closed door */
240                 feat = feat_door[type].closed;
241         }
242
243         /* Locked doors (99/400) */
244         else if (tmp < 399)
245         {
246                 /* Create locked door */
247                 feat = feat_locked_door_random(type);
248         }
249
250         /* Stuck doors (1/400) */
251         else
252         {
253                 /* Create jammed door */
254                 feat = feat_jammed_door_random(type);
255         }
256
257         if (feat != feat_none)
258         {
259                 cave_set_feat(y, x, feat);
260
261                 /* Now it is not floor */
262                 cave[y][x].info &= ~(CAVE_MASK);
263         }
264         else
265         {
266                 place_floor_bold(y, x);
267         }
268 }
269
270 /*!
271  * @brief 長方形の空洞を生成する / Make an empty square floor, for the middle of rooms
272  * @param x1 長方形の左端X座標(-1)
273  * @param x2 長方形の右端X座標(+1)
274  * @param y1 長方形の上端Y座標(-1)
275  * @param y2 長方形の下端Y座標(+1)
276  * @param light 照明の有無
277  * @return なし
278  */
279 void place_floor(int x1, int x2, int y1, int y2, bool light)
280 {
281         int x, y;
282
283         /* Place a full floor under the room */
284         for (y = y1 - 1; y <= y2 + 1; y++)
285         {
286                 for (x = x1 - 1; x <= x2 + 1; x++)
287                 {
288                         place_floor_bold(y, x);
289                         add_cave_info(y, x, CAVE_ROOM);
290                         if (light) add_cave_info(y, x, CAVE_GLOW);
291                 }
292         }
293 }
294
295
296 /*!
297  * @brief 長方形の部屋を生成する / Make an empty square room, only floor and wall grids
298  * @param x1 長方形の左端X座標(-1)
299  * @param x2 長方形の右端X座標(+1)
300  * @param y1 長方形の上端Y座標(-1)
301  * @param y2 長方形の下端Y座標(+1)
302  * @param light 照明の有無
303  * @return なし
304  */
305 void place_room(int x1, int x2, int y1, int y2, bool light)
306 {
307         int y, x;
308
309         place_floor(x1, x2, y1, y2, light);
310
311         /* Walls around the room */
312         for (y = y1 - 1; y <= y2 + 1; y++)
313         {
314                 place_outer_bold(y, x1 - 1);
315                 place_outer_bold(y, x2 + 1);
316         }
317         for (x = x1 - 1; x <= x2 + 1; x++)
318         {
319                 place_outer_bold(y1 - 1, x);
320                 place_outer_bold(y2 + 1, x);
321         }
322 }
323
324
325 /*!
326  * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
327  * @param y 配置したい中心マスのY座標
328  * @param x 配置したい中心マスのX座標
329  * @param num 配置したい数
330  * @return なし
331  * @details
332  * Only really called by some of the "vault" routines.
333  */
334 void vault_objects(int y, int x, int num)
335 {
336         int dummy = 0;
337         int i = 0, j = y, k = x;
338
339         cave_type *c_ptr;
340
341
342         /* Attempt to place 'num' objects */
343         for (; num > 0; --num)
344         {
345                 /* Try up to 11 spots looking for empty space */
346                 for (i = 0; i < 11; ++i)
347                 {
348                         /* Pick a random location */
349                         while (dummy < SAFE_MAX_ATTEMPTS)
350                         {
351                                 j = rand_spread(y, 2);
352                                 k = rand_spread(x, 3);
353                                 dummy++;
354                                 if (!in_bounds(j, k)) continue;
355                                 break;
356                         }
357
358
359                         if (dummy >= SAFE_MAX_ATTEMPTS)
360                         {
361                                 if (cheat_room)
362                                 {
363 #ifdef JP
364 msg_print("警告!地下室のアイテムを配置できません!");
365 #else
366                                         msg_print("Warning! Could not place vault object!");
367 #endif
368
369                                 }
370                         }
371
372
373                         /* Require "clean" floor space */
374                         c_ptr = &cave[j][k];
375                         if (!is_floor_grid(c_ptr) || c_ptr->o_idx) continue;
376
377                         /* Place an item */
378                         if (randint0(100) < 75)
379                         {
380                                 place_object(j, k, 0L);
381                         }
382
383                         /* Place gold */
384                         else
385                         {
386                                 place_gold(j, k);
387                         }
388
389                         /* Placement accomplished */
390                         break;
391                 }
392         }
393 }
394
395 /*!
396  * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
397  * @param y トラップを配置したいマスの中心Y座標
398  * @param x トラップを配置したいマスの中心X座標
399  * @param yd Y方向の配置分散マス数
400  * @param xd X方向の配置分散マス数
401  * @return なし
402  * @details
403  * Only really called by some of the "vault" routines.
404  */
405 void vault_trap_aux(int y, int x, int yd, int xd)
406 {
407         int count = 0, y1 = y, x1 = x;
408         int dummy = 0;
409
410         cave_type *c_ptr;
411
412         /* Place traps */
413         for (count = 0; count <= 5; count++)
414         {
415                 /* Get a location */
416                 while (dummy < SAFE_MAX_ATTEMPTS)
417                 {
418                         y1 = rand_spread(y, yd);
419                         x1 = rand_spread(x, xd);
420                         dummy++;
421                         if (!in_bounds(y1, x1)) continue;
422                         break;
423                 }
424
425                 if (dummy >= SAFE_MAX_ATTEMPTS)
426                 {
427                         if (cheat_room)
428                         {
429 #ifdef JP
430 msg_print("警告!地下室のトラップを配置できません!");
431 #else
432                                 msg_print("Warning! Could not place vault trap!");
433 #endif
434
435                         }
436                 }
437
438                 /* Require "naked" floor grids */
439                 c_ptr = &cave[y1][x1];
440                 if (!is_floor_grid(c_ptr) || c_ptr->o_idx || c_ptr->m_idx) continue;
441
442                 /* Place the trap */
443                 place_trap(y1, x1);
444
445                 /* Done */
446                 break;
447         }
448 }
449
450 /*!
451  * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
452  * @param y トラップを配置したいマスの中心Y座標
453  * @param x トラップを配置したいマスの中心X座標
454  * @param yd Y方向の配置分散マス数
455  * @param xd X方向の配置分散マス数
456  * @param num 配置したいトラップの数
457  * @return なし
458  * @details
459  * Only really called by some of the "vault" routines.
460  */
461 void vault_traps(int y, int x, int yd, int xd, int num)
462 {
463         int i;
464
465         for (i = 0; i < num; i++)
466         {
467                 vault_trap_aux(y, x, yd, xd);
468         }
469 }
470
471 /*!
472  * @brief 特殊な部屋地形向けにモンスターを配置する / Hack -- Place some sleeping monsters near the given location
473  * @param y1 モンスターを配置したいマスの中心Y座標
474  * @param x1 モンスターを配置したいマスの中心X座標
475  * @param num 配置したいモンスターの数
476  * @return なし
477  * @details
478  * Only really called by some of the "vault" routines.
479  */
480 void vault_monsters(int y1, int x1, int num)
481 {
482         int k, i;
483         POSITION y, x;
484         cave_type *c_ptr;
485
486         /* Try to summon "num" monsters "near" the given location */
487         for (k = 0; k < num; k++)
488         {
489                 /* Try nine locations */
490                 for (i = 0; i < 9; i++)
491                 {
492                         int d = 1;
493
494                         /* Pick a nearby location */
495                         scatter(&y, &x, y1, x1, d, 0);
496
497                         /* Require "empty" floor grids */
498                         c_ptr = &cave[y][x];
499                         if (!cave_empty_grid(c_ptr)) continue;
500
501                         /* Place the monster (allow groups) */
502                         monster_level = base_level + 2;
503                         (void)place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
504                         monster_level = base_level;
505                 }
506         }
507 }
508
509
510 /*!
511  * @brief build_tunnel用に通路を掘るための方向を位置関係通りに決める / Always picks a correct direction
512  * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
513  * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
514  * @param y1 始点Y座標
515  * @param x1 始点X座標
516  * @param y2 終点Y座標
517  * @param x2 終点X座標
518  * @return なし
519  */
520 void correct_dir(int *rdir, int *cdir, int y1, int x1, int y2, int x2)
521 {
522         /* Extract vertical and horizontal directions */
523         *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
524         *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
525
526         /* Never move diagonally */
527         if (*rdir && *cdir)
528         {
529                 if (randint0(100) < 50)
530                         *rdir = 0;
531                 else
532                         *cdir = 0;
533         }
534 }
535
536 /*!
537  * @brief build_tunnel用に通路を掘るための方向をランダムに決める / Pick a random direction
538  * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
539  * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
540  * @return なし
541  */
542 void rand_dir(int *rdir, int *cdir)
543 {
544         /* Pick a random direction */
545         int i = randint0(4);
546
547         /* Extract the dy/dx components */
548         *rdir = ddy_ddd[i];
549         *cdir = ddx_ddd[i];
550 }
551
552 /*!
553  * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor.  (Includes range checking.)
554  * @param x チェックするマスのX座標
555  * @param y チェックするマスのY座標
556  * @return 床系地形ならばTRUE
557  */
558 bool get_is_floor(int x, int y)
559 {
560         if (!in_bounds(y, x))
561         {
562                 /* Out of bounds */
563                 return (FALSE);
564         }
565
566         /* Do the real check */
567         if (is_floor_bold(y, x)) return (TRUE);
568
569         return (FALSE);
570 }
571
572 /*!
573  * @brief 指定のマスを床地形に変える / Set a square to be floor.  (Includes range checking.)
574  * @param x 地形を変えたいマスのX座標
575  * @param y 地形を変えたいマスのY座標
576  * @return なし
577  */
578 void set_floor(int x, int y)
579 {
580         if (!in_bounds(y, x))
581         {
582                 /* Out of bounds */
583                 return;
584         }
585
586         if (cave[y][x].info & CAVE_ROOM)
587         {
588                 /* A room border don't touch. */
589                 return;
590         }
591
592         /* Set to be floor if is a wall (don't touch lakes). */
593         if (is_extra_bold(y, x))
594                 place_floor_bold(y, x);
595 }
596
597
598 /*!
599  * @brief 部屋間のトンネルを生成する / Constructs a tunnel between two points
600  * @param row1 始点Y座標
601  * @param col1 始点X座標
602  * @param row2 終点Y座標
603  * @param col2 終点X座標
604  * @return 生成に成功したらTRUEを返す
605  * @details
606  * This function must be called BEFORE any streamers are created,\n
607  * since we use the special "granite wall" sub-types to keep track\n
608  * of legal places for corridors to pierce rooms.\n
609  *\n
610  * We use "door_flag" to prevent excessive construction of doors\n
611  * along overlapping corridors.\n
612  *\n
613  * We queue the tunnel grids to prevent door creation along a corridor\n
614  * which intersects itself.\n
615  *\n
616  * We queue the wall piercing grids to prevent a corridor from leaving\n
617  * a room and then coming back in through the same entrance.\n
618  *\n
619  * We "pierce" grids which are "outer" walls of rooms, and when we\n
620  * do so, we change all adjacent "outer" walls of rooms into "solid"\n
621  * walls so that no two corridors may use adjacent grids for exits.\n
622  *\n
623  * The "solid" wall check prevents corridors from "chopping" the\n
624  * corners of rooms off, as well as "silly" door placement, and\n
625  * "excessively wide" room entrances.\n
626  *\n
627  * Kind of walls:\n
628  *   extra -- walls\n
629  *   inner -- inner room walls\n
630  *   outer -- outer room walls\n
631  *   solid -- solid room walls\n
632  */
633 bool build_tunnel(POSITION row1, POSITION col1, POSITION row2, POSITION col2)
634 {
635         int y, x;
636         POSITION tmp_row, tmp_col;
637         int row_dir, col_dir;
638         int start_row, start_col;
639         int main_loop_count = 0;
640
641         bool door_flag = FALSE;
642
643         cave_type *c_ptr;
644
645         /* Save the starting location */
646         start_row = row1;
647         start_col = col1;
648
649         /* Start out in the correct direction */
650         correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
651
652         /* Keep going until done (or bored) */
653         while ((row1 != row2) || (col1 != col2))
654         {
655                 /* Mega-Hack -- Paranoia -- prevent infinite loops */
656                 if (main_loop_count++ > 2000) return FALSE;
657
658                 /* Allow bends in the tunnel */
659                 if (randint0(100) < dun_tun_chg)
660                 {
661                         /* Acquire the correct direction */
662                         correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
663
664                         /* Random direction */
665                         if (randint0(100) < dun_tun_rnd)
666                         {
667                                 rand_dir(&row_dir, &col_dir);
668                         }
669                 }
670
671                 /* Get the next location */
672                 tmp_row = row1 + row_dir;
673                 tmp_col = col1 + col_dir;
674
675
676                 /* Extremely Important -- do not leave the dungeon */
677                 while (!in_bounds(tmp_row, tmp_col))
678                 {
679                         /* Acquire the correct direction */
680                         correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
681
682                         /* Random direction */
683                         if (randint0(100) < dun_tun_rnd)
684                         {
685                                 rand_dir(&row_dir, &col_dir);
686                         }
687
688                         /* Get the next location */
689                         tmp_row = row1 + row_dir;
690                         tmp_col = col1 + col_dir;
691                 }
692
693
694                 /* Access the location */
695                 c_ptr = &cave[tmp_row][tmp_col];
696
697                 /* Avoid "solid" walls */
698                 if (is_solid_grid(c_ptr)) continue;
699
700                 /* Pierce "outer" walls of rooms */
701                 if (is_outer_grid(c_ptr))
702                 {
703                         /* Acquire the "next" location */
704                         y = tmp_row + row_dir;
705                         x = tmp_col + col_dir;
706
707                         /* Hack -- Avoid outer/solid walls */
708                         if (is_outer_bold(y, x)) continue;
709                         if (is_solid_bold(y, x)) continue;
710
711                         /* Accept this location */
712                         row1 = (POSITION)tmp_row;
713                         col1 = (POSITION)tmp_col;
714
715                         /* Save the wall location */
716                         if (dun->wall_n < WALL_MAX)
717                         {
718                                 dun->wall[dun->wall_n].y = row1;
719                                 dun->wall[dun->wall_n].x = col1;
720                                 dun->wall_n++;
721                         }
722                         else return FALSE;
723
724                         /* Forbid re-entry near this piercing */
725                         for (y = row1 - 1; y <= row1 + 1; y++)
726                         {
727                                 for (x = col1 - 1; x <= col1 + 1; x++)
728                                 {
729                                         /* Convert adjacent "outer" walls as "solid" walls */
730                                         if (is_outer_bold(y, x))
731                                         {
732                                                 /* Change the wall to a "solid" wall */
733                                                 place_solid_noperm_bold(y, x);
734                                         }
735                                 }
736                         }
737                 }
738
739                 /* Travel quickly through rooms */
740                 else if (c_ptr->info & (CAVE_ROOM))
741                 {
742                         /* Accept the location */
743                         row1 = tmp_row;
744                         col1 = tmp_col;
745                 }
746
747                 /* Tunnel through all other walls */
748                 else if (is_extra_grid(c_ptr) || is_inner_grid(c_ptr) || is_solid_grid(c_ptr))
749                 {
750                         /* Accept this location */
751                         row1 = tmp_row;
752                         col1 = tmp_col;
753
754                         /* Save the tunnel location */
755                         if (dun->tunn_n < TUNN_MAX)
756                         {
757                                 dun->tunn[dun->tunn_n].y = row1;
758                                 dun->tunn[dun->tunn_n].x = col1;
759                                 dun->tunn_n++;
760                         }
761                         else return FALSE;
762
763                         /* Allow door in next grid */
764                         door_flag = FALSE;
765                 }
766
767                 /* Handle corridor intersections or overlaps */
768                 else
769                 {
770                         /* Accept the location */
771                         row1 = tmp_row;
772                         col1 = tmp_col;
773
774                         /* Collect legal door locations */
775                         if (!door_flag)
776                         {
777                                 /* Save the door location */
778                                 if (dun->door_n < DOOR_MAX)
779                                 {
780                                         dun->door[dun->door_n].y = row1;
781                                         dun->door[dun->door_n].x = col1;
782                                         dun->door_n++;
783                                 }
784                                 else return FALSE;
785
786                                 /* No door in next grid */
787                                 door_flag = TRUE;
788                         }
789
790                         /* Hack -- allow pre-emptive tunnel termination */
791                         if (randint0(100) >= dun_tun_con)
792                         {
793                                 /* Distance between row1 and start_row */
794                                 tmp_row = row1 - start_row;
795                                 if (tmp_row < 0) tmp_row = (-tmp_row);
796
797                                 /* Distance between col1 and start_col */
798                                 tmp_col = col1 - start_col;
799                                 if (tmp_col < 0) tmp_col = (-tmp_col);
800
801                                 /* Terminate the tunnel */
802                                 if ((tmp_row > 10) || (tmp_col > 10)) break;
803                         }
804                 }
805         }
806
807         return TRUE;
808 }
809
810
811 /*!
812  * @brief トンネル生成のための基準点を指定する。
813  * @param x 基準点を指定するX座標の参照ポインタ、適時値が修正される。
814  * @param y 基準点を指定するY座標の参照ポインタ、適時値が修正される。
815  * @param affectwall (調査中)
816  * @return なし
817  * @details
818  * This routine adds the square to the tunnel\n
819  * It also checks for SOLID walls - and returns a nearby\n
820  * non-SOLID square in (x,y) so that a simple avoiding\n
821  * routine can be used. The returned boolean value reflects\n
822  * whether or not this routine hit a SOLID wall.\n
823  *\n
824  * "affectwall" toggles whether or not this new square affects\n
825  * the boundaries of rooms. - This is used by the catacomb\n
826  * routine.\n
827  * @todo 特に詳細な処理の意味を調査すべし
828  */
829 static bool set_tunnel(POSITION *x, POSITION *y, bool affectwall)
830 {
831         int i, j, dx, dy;
832
833         cave_type *c_ptr = &cave[*y][*x];
834
835         if (!in_bounds(*y, *x)) return TRUE;
836
837         if (is_inner_grid(c_ptr))
838         {
839                 return TRUE;
840         }
841
842         if (is_extra_bold(*y,*x))
843         {
844                 /* Save the tunnel location */
845                 if (dun->tunn_n < TUNN_MAX)
846                 {
847                         dun->tunn[dun->tunn_n].y = *y;
848                         dun->tunn[dun->tunn_n].x = *x;
849                         dun->tunn_n++;
850
851                         return TRUE;
852                 }
853                 else return FALSE;
854         }
855
856         if (is_floor_bold(*y, *x))
857         {
858                 /* Don't do anything */
859                 return TRUE;
860         }
861
862         if (is_outer_grid(c_ptr) && affectwall)
863         {
864                 /* Save the wall location */
865                 if (dun->wall_n < WALL_MAX)
866                 {
867                         dun->wall[dun->wall_n].y = *y;
868                         dun->wall[dun->wall_n].x = *x;
869                         dun->wall_n++;
870                 }
871                 else return FALSE;
872
873                 /* Forbid re-entry near this piercing */
874                 for (j = *y - 1; j <= *y + 1; j++)
875                 {
876                         for (i = *x - 1; i <= *x + 1; i++)
877                         {
878                                 /* Convert adjacent "outer" walls as "solid" walls */
879                                 if (is_outer_bold(j, i))
880                                 {
881                                         /* Change the wall to a "solid" wall */
882                                         place_solid_noperm_bold(j, i);
883                                 }
884                         }
885                 }
886
887                 /* Clear mimic type */
888                 cave[*y][*x].mimic = 0;
889
890                 place_floor_bold(*y, *x);
891
892                 return TRUE;
893         }
894
895         if (is_solid_grid(c_ptr) && affectwall)
896         {
897                 /* cannot place tunnel here - use a square to the side */
898
899                 /* find usable square and return value in (x,y) */
900
901                 i = 50;
902
903                 dy = 0;
904                 dx = 0;
905                 while ((i > 0) && is_solid_bold(*y + dy, *x + dx))
906                 {
907                         dy = randint0(3) - 1;
908                         dx = randint0(3) - 1;
909
910                         if (!in_bounds(*y + dy, *x + dx))
911                         {
912                                 dx = 0;
913                                 dy = 0;
914                         }
915
916                         i--;
917                 }
918
919                 if (i == 0)
920                 {
921                         /* Failed for some reason: hack - ignore the solidness */
922                         place_outer_grid(c_ptr);
923                         dx = 0;
924                         dy = 0;
925                 }
926
927                 /* Give new, acceptable coordinate. */
928                 *x = *x + dx;
929                 *y = *y + dy;
930
931                 return FALSE;
932         }
933
934         return TRUE;
935 }
936
937
938 /*!
939  * @brief 外壁を削って「カタコンベ状」の通路を作成する / This routine creates the catacomb-like tunnels by removing extra rock.
940  * @param x 基準点のX座標
941  * @param y 基準点のY座標
942  * @return なし
943  * @details
944  * Note that this routine is only called on "even" squares - so it gives
945  * a natural checkerboard pattern.
946  */
947 static void create_cata_tunnel(POSITION x, POSITION y)
948 {
949         POSITION x1, y1;
950
951         /* Build tunnel */
952         x1 = x - 1;
953         y1 = y;
954         set_tunnel(&x1, &y1, FALSE);
955
956         x1 = x + 1;
957         y1 = y;
958         set_tunnel(&x1, &y1, FALSE);
959
960         x1 = x;
961         y1 = y - 1;
962         set_tunnel(&x1, &y1, FALSE);
963
964         x1 = x;
965         y1 = y + 1;
966         set_tunnel(&x1, &y1, FALSE);
967 }
968
969
970 /*!
971  * @brief トンネル生成処理(詳細調査中)/ This routine does the bulk of the work in creating the new types of tunnels.
972  * @return なし
973  * @todo 詳細用調査
974  * @details
975  * It is designed to use very simple algorithms to go from (x1,y1) to (x2,y2)\n
976  * It doesn't need to add any complexity - straight lines are fine.\n
977  * The SOLID walls are avoided by a recursive algorithm which tries random ways\n
978  * around the obstical until it works.  The number of itterations is counted, and it\n
979  * this gets too large the routine exits. This should stop any crashes - but may leave\n
980  * small gaps in the tunnel where there are too many SOLID walls.\n
981  *\n
982  * Type 1 tunnels are extremely simple - straight line from A to B.  This is only used\n
983  * as a part of the dodge SOLID walls algorithm.\n
984  *\n
985  * Type 2 tunnels are made of two straight lines at right angles. When this is used with\n
986  * short line segments it gives the "cavelike" tunnels seen deeper in the dungeon.\n
987  *\n
988  * Type 3 tunnels are made of two straight lines like type 2, but with extra rock removed.\n
989  * This, when used with longer line segments gives the "catacomb-like" tunnels seen near\n
990  * the surface.\n
991  */
992 static void short_seg_hack(int x1, int y1, int x2, int y2, int type, int count, bool *fail)
993 {
994         int i;
995         POSITION x, y;
996         int length;
997
998         /* Check for early exit */
999         if (!(*fail)) return;
1000
1001         length = distance(x1, y1, x2, y2);
1002
1003         count++;
1004
1005         if ((type == 1) && (length != 0))
1006         {
1007
1008                 for (i = 0; i <= length; i++)
1009                 {
1010                         x = x1 + i * (x2 - x1) / length;
1011                         y = y1 + i * (y2 - y1) / length;
1012                         if (!set_tunnel(&x, &y, TRUE))
1013                         {
1014                                 if (count > 50)
1015                                 {
1016                                         /* This isn't working - probably have an infinite loop */
1017                                         *fail = FALSE;
1018                                         return;
1019                                 }
1020
1021                                 /* solid wall - so try to go around */
1022                                 short_seg_hack(x, y, x1 + (i - 1) * (x2 - x1) / length, y1 + (i - 1) * (y2 - y1) / length, 1, count, fail);
1023                                 short_seg_hack(x, y, x1 + (i + 1) * (x2 - x1) / length, y1 + (i + 1) * (y2 - y1) / length, 1, count, fail);
1024                         }
1025                 }
1026         }
1027         else if ((type == 2) || (type == 3))
1028         {
1029                 if (x1 < x2)
1030                 {
1031                         for (i = x1; i <= x2; i++)
1032                         {
1033                                 x = i;
1034                                 y = y1;
1035                                 if (!set_tunnel(&x, &y, TRUE))
1036                                 {
1037                                         /* solid wall - so try to go around */
1038                                         short_seg_hack(x, y, i - 1, y1, 1, count, fail);
1039                                         short_seg_hack(x, y, i + 1, y1, 1, count, fail);
1040                                 }
1041                                 if ((type == 3) && ((x + y) % 2))
1042                                 {
1043                                         create_cata_tunnel(i, y1);
1044                                 }
1045                         }
1046                 }
1047                 else
1048                 {
1049                         for (i = x2; i <= x1; i++)
1050                         {
1051                                 x = i;
1052                                 y = y1;
1053                                 if (!set_tunnel(&x, &y, TRUE))
1054                                 {
1055                                         /* solid wall - so try to go around */
1056                                         short_seg_hack(x, y, i - 1, y1, 1, count, fail);
1057                                         short_seg_hack(x, y, i + 1, y1, 1, count, fail);
1058                                 }
1059                                 if ((type == 3) && ((x + y) % 2))
1060                                 {
1061                                         create_cata_tunnel(i, y1);
1062                                 }
1063                         }
1064
1065                 }
1066                 if (y1 < y2)
1067                 {
1068                         for (i = y1; i <= y2; i++)
1069                         {
1070                                 x = x2;
1071                                 y = i;
1072                                 if (!set_tunnel(&x, &y, TRUE))
1073                                 {
1074                                         /* solid wall - so try to go around */
1075                                         short_seg_hack(x, y, x2, i - 1, 1, count, fail);
1076                                         short_seg_hack(x, y, x2, i + 1, 1, count, fail);
1077                                 }
1078                                 if ((type == 3) && ((x + y) % 2))
1079                                 {
1080                                         create_cata_tunnel(x2, i);
1081                                 }
1082                         }
1083                 }
1084                 else
1085                 {
1086                         for (i = y2; i <= y1; i++)
1087                         {
1088                                 x = x2;
1089                                 y = i;
1090                                 if (!set_tunnel(&x, &y, TRUE))
1091                                 {
1092                                         /* solid wall - so try to go around */
1093                                         short_seg_hack(x, y, x2, i - 1, 1, count, fail);
1094                                         short_seg_hack(x, y, x2, i + 1, 1, count, fail);
1095                                 }
1096                                 if ((type == 3) && ((x + y) % 2))
1097                                 {
1098                                         create_cata_tunnel(x2, i);
1099                                 }
1100                         }
1101                 }
1102         }
1103 }
1104
1105
1106 /*!
1107  * @brief 特定の壁(永久壁など)を避けながら部屋間の通路を作成する / This routine maps a path from (x1, y1) to (x2, y2) avoiding SOLID walls.
1108  * @return なし
1109  * @todo 詳細要調査
1110  * @details
1111  * Permanent rock is ignored in this path finding- sometimes there is no\n
1112  * path around anyway -so there will be a crash if we try to find one.\n
1113  * This routine is much like the river creation routine in Zangband.\n
1114  * It works by dividing a line segment into two.  The segments are divided\n
1115  * until they are less than "cutoff" - when the corresponding routine from\n
1116  * "short_seg_hack" is called.\n
1117  * Note it is VERY important that the "stop if hit another passage" logic\n
1118  * stays as is.  Without this the dungeon turns into Swiss Cheese...\n
1119  */
1120 bool build_tunnel2(POSITION x1, POSITION y1, POSITION x2, POSITION y2, int type, int cutoff)
1121 {
1122         POSITION x3, y3, dx, dy;
1123         int changex, changey;
1124         int length;
1125         int i;
1126         bool retval, firstsuccede;
1127         cave_type *c_ptr;
1128
1129         length = distance(x1, y1, x2, y2);
1130
1131         if (length > cutoff)
1132         {
1133                 /*
1134                 * Divide path in half and call routine twice.
1135                  */
1136                 dx = (x2 - x1) / 2;
1137                 dy = (y2 - y1) / 2;
1138
1139                 /* perturbation perpendicular to path */
1140                 changex = (randint0(abs(dy) + 2) * 2 - abs(dy) - 1) / 2;
1141                 changey = (randint0(abs(dx) + 2) * 2 - abs(dx) - 1) / 2;
1142
1143                 /* Work out "mid" ponit */
1144                 x3 = x1 + dx + changex;
1145                 y3 = y1 + dy + changey;
1146
1147                 /* See if in bounds - if not - do not perturb point */
1148                 if (!in_bounds(y3, x3))
1149                 {
1150                         x3 = (x1 + x2) / 2;
1151                         y3 = (y1 + y2) / 2;
1152                 }
1153                 /* cache c_ptr */
1154                 c_ptr = &cave[y3][x3];
1155                 if (is_solid_grid(c_ptr))
1156                 {
1157                         /* move midpoint a bit to avoid problem. */
1158
1159                         i = 50;
1160
1161                         dy = 0;
1162                         dx = 0;
1163                         while ((i > 0) && is_solid_bold(y3 + dy, x3 + dx))
1164                         {
1165                                 dy = randint0(3) - 1;
1166                                 dx = randint0(3) - 1;
1167                                 if (!in_bounds(y3 + dy, x3 + dx))
1168                                 {
1169                                         dx = 0;
1170                                         dy = 0;
1171                                 }
1172                                 i--;
1173                         }
1174
1175                         if (i == 0)
1176                         {
1177                                 /* Failed for some reason: hack - ignore the solidness */
1178                                 place_outer_bold(y3, x3);
1179                                 dx = 0;
1180                                 dy = 0;
1181                         }
1182                         y3 += dy;
1183                         x3 += dx;
1184                         c_ptr = &cave[y3][x3];
1185                 }
1186
1187                 if (is_floor_grid(c_ptr))
1188                 {
1189                         if (build_tunnel2(x1, y1, x3, y3, type, cutoff))
1190                         {
1191                                 if ((cave[y3][x3].info & CAVE_ROOM) || (randint1(100) > 95))
1192                                 {
1193                                         /* do second half only if works + if have hit a room */
1194                                         retval = build_tunnel2(x3, y3, x2, y2, type, cutoff);
1195                                 }
1196                                 else
1197                                 {
1198                                         /* have hit another tunnel - make a set of doors here */
1199                                         retval = FALSE;
1200
1201                                         /* Save the door location */
1202                                         if (dun->door_n < DOOR_MAX)
1203                                         {
1204                                                 dun->door[dun->door_n].y = (POSITION)y3;
1205                                                 dun->door[dun->door_n].x = (POSITION)x3;
1206                                                 dun->door_n++;
1207                                         }
1208                                         else return FALSE;
1209                                 }
1210                                 firstsuccede = TRUE;
1211                         }
1212                         else
1213                         {
1214                                 /* false- didn't work all the way */
1215                                 retval = FALSE;
1216                                 firstsuccede = FALSE;
1217                         }
1218                 }
1219                 else
1220                 {
1221                         /* tunnel through walls */
1222                         if (build_tunnel2(x1, y1, (POSITION)x3, (POSITION)y3, type, cutoff))
1223                         {
1224                                 retval = build_tunnel2((POSITION)x3, (POSITION)y3, x2, y2, type, cutoff);
1225                                 firstsuccede = TRUE;
1226                         }
1227                         else
1228                         {
1229                                 /* false- didn't work all the way */
1230                                 retval = FALSE;
1231                                 firstsuccede = FALSE;
1232                         }
1233                 }
1234                 if (firstsuccede)
1235                 {
1236                         /* only do this if the first half has worked */
1237                         set_tunnel(&x3, &y3, TRUE);
1238                 }
1239                 /* return value calculated above */
1240                 return retval;
1241         }
1242         else
1243         {
1244                 /* Do a short segment */
1245                 retval = TRUE;
1246                 short_seg_hack(x1, y1, x2, y2, type, 0, &retval);
1247
1248                 /* Hack - ignore return value so avoid infinite loops */
1249                 return TRUE;
1250         }
1251 }
1252