3 * @brief ダンジョンの生成処理の基幹部分 / low-level dungeon creation primitives
6 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\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
12 * 2014 Deskull Doxygen向けのコメント整理\n
24 * @brief 新規フロアに入りたてのプレイヤーをランダムな場所に配置する / Returns random co-ordinates for player/monster/object
25 * @return 配置に成功したらTRUEを返す
27 bool new_player_spot(void)
29 POSITION y = 0, x = 0;
30 int max_attempts = 10000;
35 /* Place the player */
36 while (max_attempts--)
38 /* Pick a legal spot */
39 y = (POSITION)rand_range(1, cur_hgt - 2);
40 x = (POSITION)rand_range(1, cur_wid - 2);
44 /* Must be a "naked" floor grid */
45 if (c_ptr->m_idx) continue;
48 f_ptr = &f_info[c_ptr->feat];
50 if (max_attempts > 5000) /* Rule 1 */
52 if (!have_flag(f_ptr->flags, FF_FLOOR)) continue;
56 if (!have_flag(f_ptr->flags, FF_MOVE)) continue;
57 if (have_flag(f_ptr->flags, FF_HIT_TRAP)) continue;
60 /* Refuse to start on anti-teleport grids in dungeon */
61 if (!have_flag(f_ptr->flags, FF_TELEPORTABLE)) continue;
63 if (!player_can_enter(c_ptr->feat, 0)) continue;
64 if (!in_bounds(y, x)) continue;
66 /* Refuse to start on anti-teleport grids */
67 if (c_ptr->info & (CAVE_ICKY)) continue;
72 if (max_attempts < 1) /* Should be -1, actually if we failed... */
75 /* Save the new player grid */
85 * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
86 * @param y 配置を試みたいマスのY座標
87 * @param x 配置を試みたいマスのX座標
90 void place_random_stairs(POSITION y, POSITION x)
92 bool up_stairs = TRUE;
93 bool down_stairs = TRUE;
98 if (!is_floor_grid(c_ptr) || c_ptr->o_idx) return;
101 if (!dun_level) up_stairs = FALSE;
104 if (ironman_downward) up_stairs = FALSE;
107 if (dun_level >= d_info[dungeon_type].maxdepth) down_stairs = FALSE;
110 if (quest_number(dun_level) && (dun_level > 1)) down_stairs = FALSE;
112 /* We can't place both */
113 if (down_stairs && up_stairs)
115 /* Choose a staircase randomly */
116 if (randint0(100) < 50) up_stairs = FALSE;
117 else down_stairs = FALSE;
120 /* Place the stairs */
121 if (up_stairs) place_up_stairs(y, x);
122 else if (down_stairs) place_down_stairs(y, x);
126 * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
127 * @param y ドアの配置を試みたいマスのY座標
128 * @param x ドアの配置を試みたいマスのX座標
129 * @param room 部屋に接している場合向けのドア生成か否か
132 void place_random_door(POSITION y, POSITION x, bool room)
135 FEAT_IDX feat = feat_none;
136 cave_type *c_ptr = &cave[y][x];
138 /* Initialize mimic info */
141 if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
143 place_floor_bold(y, x);
147 type = ((d_info[dungeon_type].flags1 & DF1_CURTAIN) &&
148 one_in_((d_info[dungeon_type].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
149 ((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
151 /* Choose an object */
152 tmp = randint0(1000);
154 /* Open doors (300/1000) */
157 /* Create open door */
158 feat = feat_door[type].open;
161 /* Broken doors (100/1000) */
164 /* Create broken door */
165 feat = feat_door[type].broken;
168 /* Secret doors (200/1000) */
171 /* Create secret door */
172 place_closed_door(y, x, type);
174 if (type != DOOR_CURTAIN)
176 /* Hide. If on the edge of room, use outer wall. */
177 c_ptr->mimic = room ? feat_wall_outer : fill_type[randint0(100)];
179 /* Floor type terrain cannot hide a door */
180 if (feat_supports_los(c_ptr->mimic) && !feat_supports_los(c_ptr->feat))
182 if (have_flag(f_info[c_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[c_ptr->mimic].flags, FF_CAN_FLY))
184 c_ptr->feat = one_in_(2) ? c_ptr->mimic : floor_type[randint0(100)];
191 /* Closed, locked, or stuck doors (400/1000) */
192 else place_closed_door(y, x, type);
196 if (feat != feat_none)
198 set_cave_feat(y, x, feat);
202 place_floor_bold(y, x);
206 delete_monster(y, x);
210 * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
211 * @param y ドアの配置を試みたいマスのY座標
212 * @param x ドアの配置を試みたいマスのX座標
213 * @param type ドアの地形ID
216 void place_closed_door(POSITION y, POSITION x, int type)
219 FEAT_IDX feat = feat_none;
221 if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
223 place_floor_bold(y, x);
227 /* Choose an object */
230 /* Closed doors (300/400) */
233 /* Create closed door */
234 feat = feat_door[type].closed;
237 /* Locked doors (99/400) */
240 /* Create locked door */
241 feat = feat_locked_door_random(type);
244 /* Stuck doors (1/400) */
247 /* Create jammed door */
248 feat = feat_jammed_door_random(type);
251 if (feat != feat_none)
253 cave_set_feat(y, x, feat);
255 /* Now it is not floor */
256 cave[y][x].info &= ~(CAVE_MASK);
260 place_floor_bold(y, x);
265 * @brief 鍵のかかったドアを配置する
266 * @param y 配置したいフロアのY座標
267 * @param x 配置したいフロアのX座標
270 void place_locked_door(POSITION y, POSITION x)
272 if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
274 place_floor_bold(y, x);
278 set_cave_feat(y, x, feat_locked_door_random((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
279 cave[y][x].info &= ~(CAVE_FLOOR);
280 delete_monster(y, x);
287 * @param y 配置したいフロアのY座標
288 * @param x 配置したいフロアのX座標
289 * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
292 void place_secret_door(POSITION y, POSITION x, int type)
294 if (d_info[dungeon_type].flags1 & DF1_NO_DOORS)
296 place_floor_bold(y, x);
300 cave_type *c_ptr = &cave[y][x];
302 if (type == DOOR_DEFAULT)
304 type = ((d_info[dungeon_type].flags1 & DF1_CURTAIN) &&
305 one_in_((d_info[dungeon_type].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
306 ((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
309 /* Create secret door */
310 place_closed_door(y, x, type);
312 if (type != DOOR_CURTAIN)
314 /* Hide by inner wall because this is used in rooms only */
315 c_ptr->mimic = feat_wall_inner;
317 /* Floor type terrain cannot hide a door */
318 if (feat_supports_los(c_ptr->mimic) && !feat_supports_los(c_ptr->feat))
320 if (have_flag(f_info[c_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[c_ptr->mimic].flags, FF_CAN_FLY))
322 c_ptr->feat = one_in_(2) ? c_ptr->mimic : floor_type[randint0(100)];
328 c_ptr->info &= ~(CAVE_FLOOR);
329 delete_monster(y, x);
334 * Routine used by the random vault creators to add a door to a location
335 * Note that range checking has to be done in the calling routine.
337 * The doors must be INSIDE the allocated region.
339 void add_door(POSITION x, POSITION y)
341 /* Need to have a wall in the center square */
342 if (!is_outer_bold(y, x)) return;
353 if (is_floor_bold(y - 1, x) && is_floor_bold(y + 1, x) &&
354 (is_outer_bold(y, x - 1) && is_outer_bold(y, x + 1)))
357 place_secret_door(y, x, DOOR_DEFAULT);
359 /* set boundarys so don't get wide doors */
360 place_solid_bold(y, x - 1);
361 place_solid_bold(y, x + 1);
370 * where x = don't care
373 if (is_outer_bold(y - 1, x) && is_outer_bold(y + 1, x) &&
374 is_floor_bold(y, x - 1) && is_floor_bold(y, x + 1))
377 place_secret_door(y, x, DOOR_DEFAULT);
379 /* set boundarys so don't get wide doors */
380 place_solid_bold(y - 1, x);
381 place_solid_bold(y + 1, x);
386 * @brief 隣接4マスに存在する通路の数を返す / Count the number of "corridor" grids adjacent to the given grid.
387 * @param y1 基準となるマスのY座標
388 * @param x1 基準となるマスのX座標
390 * @note Assumes "in_bounds(y1, x1)"
392 * XXX XXX This routine currently only counts actual "empty floor"\n
393 * grids which are not in rooms. We might want to also count stairs,\n
394 * open doors, closed doors, etc.
396 static int next_to_corr(POSITION y1, POSITION x1)
403 /* Scan adjacent grids */
404 for (i = 0; i < 4; i++)
406 /* Extract the location */
411 /* Skip non floors */
412 if (cave_have_flag_grid(c_ptr, FF_WALL)) continue;
414 /* Skip non "empty floor" grids */
415 if (!is_floor_grid(c_ptr))
418 /* Skip grids inside rooms */
419 if (c_ptr->info & (CAVE_ROOM)) continue;
421 /* Count these grids */
425 /* Return the number of corridors */
430 * @brief ドアを設置可能な地形かを返す / Determine if the given location is "between" two walls, and "next to" two corridor spaces.
431 * @param y 判定を行いたいマスのY座標
432 * @param x 判定を行いたいマスのX座標
433 * @return ドアを設置可能ならばTRUEを返す
434 * @note Assumes "in_bounds(y1, x1)"
437 * Assumes "in_bounds(y, x)"\n
439 static bool possible_doorway(POSITION y, POSITION x)
441 /* Count the adjacent corridors */
442 if (next_to_corr(y, x) >= 2)
445 if (cave_have_flag_bold(y - 1, x, FF_WALL) &&
446 cave_have_flag_bold(y + 1, x, FF_WALL))
451 /* Check Horizontal */
452 if (cave_have_flag_bold(y, x - 1, FF_WALL) &&
453 cave_have_flag_bold(y, x + 1, FF_WALL))
464 * @brief ドアの設置を試みる / Places door at y, x position if at least 2 walls found
465 * @param y 設置を行いたいマスのY座標
466 * @param x 設置を行いたいマスのX座標
469 void try_door(POSITION y, POSITION x)
472 if (!in_bounds(y, x)) return;
475 if (cave_have_flag_bold(y, x, FF_WALL)) return;
477 /* Ignore room grids */
478 if (cave[y][x].info & (CAVE_ROOM)) return;
480 /* Occasional door (if allowed) */
481 if ((randint0(100) < dun_tun_jct) && possible_doorway(y, x) && !(d_info[dungeon_type].flags1 & DF1_NO_DOORS))
484 place_random_door(y, x, FALSE);
490 * @brief 長方形の空洞を生成する / Make an empty square floor, for the middle of rooms
491 * @param x1 長方形の左端X座標(-1)
492 * @param x2 長方形の右端X座標(+1)
493 * @param y1 長方形の上端Y座標(-1)
494 * @param y2 長方形の下端Y座標(+1)
498 void place_floor(POSITION x1, POSITION x2, POSITION y1, POSITION y2, bool light)
502 /* Place a full floor under the room */
503 for (y = y1 - 1; y <= y2 + 1; y++)
505 for (x = x1 - 1; x <= x2 + 1; x++)
507 place_floor_bold(y, x);
508 add_cave_info(y, x, CAVE_ROOM);
509 if (light) add_cave_info(y, x, CAVE_GLOW);
516 * @brief 長方形の部屋を生成する / Make an empty square room, only floor and wall grids
517 * @param x1 長方形の左端X座標(-1)
518 * @param x2 長方形の右端X座標(+1)
519 * @param y1 長方形の上端Y座標(-1)
520 * @param y2 長方形の下端Y座標(+1)
524 void place_room(POSITION x1, POSITION x2, POSITION y1, POSITION y2, bool light)
528 place_floor(x1, x2, y1, y2, light);
530 /* Walls around the room */
531 for (y = y1 - 1; y <= y2 + 1; y++)
533 place_outer_bold(y, x1 - 1);
534 place_outer_bold(y, x2 + 1);
536 for (x = x1 - 1; x <= x2 + 1; x++)
538 place_outer_bold(y1 - 1, x);
539 place_outer_bold(y2 + 1, x);
545 * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
546 * @param y 配置したい中心マスのY座標
547 * @param x 配置したい中心マスのX座標
551 * Only really called by some of the "vault" routines.
553 void vault_objects(POSITION y, POSITION x, int num)
556 int i = 0, j = y, k = x;
561 /* Attempt to place 'num' objects */
562 for (; num > 0; --num)
564 /* Try up to 11 spots looking for empty space */
565 for (i = 0; i < 11; ++i)
567 /* Pick a random location */
568 while (dummy < SAFE_MAX_ATTEMPTS)
570 j = rand_spread(y, 2);
571 k = rand_spread(x, 3);
573 if (!in_bounds(j, k)) continue;
577 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
579 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
582 /* Require "clean" floor space */
584 if (!is_floor_grid(c_ptr) || c_ptr->o_idx) continue;
586 if (randint0(100) < 75)
588 place_object(j, k, 0L);
595 /* Placement accomplished */
602 * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
603 * @param y トラップを配置したいマスの中心Y座標
604 * @param x トラップを配置したいマスの中心X座標
605 * @param yd Y方向の配置分散マス数
606 * @param xd X方向の配置分散マス数
609 * Only really called by some of the "vault" routines.
611 void vault_trap_aux(POSITION y, POSITION x, POSITION yd, POSITION xd)
613 int count = 0, y1 = y, x1 = x;
619 for (count = 0; count <= 5; count++)
622 while (dummy < SAFE_MAX_ATTEMPTS)
624 y1 = rand_spread(y, yd);
625 x1 = rand_spread(x, xd);
627 if (!in_bounds(y1, x1)) continue;
631 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
633 msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
636 /* Require "naked" floor grids */
637 c_ptr = &cave[y1][x1];
638 if (!is_floor_grid(c_ptr) || c_ptr->o_idx || c_ptr->m_idx) continue;
648 * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
649 * @param y トラップを配置したいマスの中心Y座標
650 * @param x トラップを配置したいマスの中心X座標
651 * @param yd Y方向の配置分散マス数
652 * @param xd X方向の配置分散マス数
653 * @param num 配置したいトラップの数
656 * Only really called by some of the "vault" routines.
658 void vault_traps(POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
662 for (i = 0; i < num; i++)
664 vault_trap_aux(y, x, yd, xd);
669 * @brief 特殊な部屋地形向けにモンスターを配置する / Hack -- Place some sleeping monsters near the given location
670 * @param y1 モンスターを配置したいマスの中心Y座標
671 * @param x1 モンスターを配置したいマスの中心X座標
672 * @param num 配置したいモンスターの数
675 * Only really called by some of the "vault" routines.
677 void vault_monsters(POSITION y1, POSITION x1, int num)
683 /* Try to summon "num" monsters "near" the given location */
684 for (k = 0; k < num; k++)
686 /* Try nine locations */
687 for (i = 0; i < 9; i++)
691 /* Pick a nearby location */
692 scatter(&y, &x, y1, x1, d, 0);
694 /* Require "empty" floor grids */
696 if (!cave_empty_grid(c_ptr)) continue;
698 /* Place the monster (allow groups) */
699 monster_level = base_level + 2;
700 (void)place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
701 monster_level = base_level;
708 * @brief build_tunnel用に通路を掘るための方向を位置関係通りに決める / Always picks a correct direction
709 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
710 * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
717 void correct_dir(POSITION *rdir, POSITION *cdir, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
719 /* Extract vertical and horizontal directions */
720 *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
721 *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
723 /* Never move diagonally */
726 if (randint0(100) < 50)
734 * @brief build_tunnel用に通路を掘るための方向をランダムに決める / Pick a random direction
735 * @param rdir Y方向に取るべきベクトル値を返す参照ポインタ
736 * @param cdir X方向に取るべきベクトル値を返す参照ポインタ
739 void rand_dir(POSITION *rdir, POSITION *cdir)
741 /* Pick a random direction */
744 /* Extract the dy/dx components */
750 * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor. (Includes range checking.)
751 * @param x チェックするマスのX座標
752 * @param y チェックするマスのY座標
753 * @return 床系地形ならばTRUE
755 bool get_is_floor(POSITION x, POSITION y)
757 if (!in_bounds(y, x))
763 /* Do the real check */
764 if (is_floor_bold(y, x)) return (TRUE);
770 * @brief 指定のマスを床地形に変える / Set a square to be floor. (Includes range checking.)
771 * @param x 地形を変えたいマスのX座標
772 * @param y 地形を変えたいマスのY座標
775 void set_floor(POSITION x, POSITION y)
777 if (!in_bounds(y, x))
783 if (cave[y][x].info & CAVE_ROOM)
785 /* A room border don't touch. */
789 /* Set to be floor if is a wall (don't touch lakes). */
790 if (is_extra_bold(y, x))
791 place_floor_bold(y, x);