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
25 * @brief 新規フロアに入りたてのプレイヤーをランダムな場所に配置する / Returns random co-ordinates for player/monster/object
26 * @return 配置に成功したらTRUEを返す
28 bool new_player_spot(void)
30 POSITION y = 0, x = 0;
31 int max_attempts = 10000;
36 /* Place the player */
37 while (max_attempts--)
39 /* Pick a legal spot */
40 y = (POSITION)rand_range(1, cur_hgt - 2);
41 x = (POSITION)rand_range(1, cur_wid - 2);
43 g_ptr = &grid_array[y][x];
45 /* Must be a "naked" floor grid */
46 if (g_ptr->m_idx) continue;
49 f_ptr = &f_info[g_ptr->feat];
51 if (max_attempts > 5000) /* Rule 1 */
53 if (!have_flag(f_ptr->flags, FF_FLOOR)) continue;
57 if (!have_flag(f_ptr->flags, FF_MOVE)) continue;
58 if (have_flag(f_ptr->flags, FF_HIT_TRAP)) continue;
61 /* Refuse to start on anti-teleport grids in dungeon */
62 if (!have_flag(f_ptr->flags, FF_TELEPORTABLE)) continue;
64 if (!player_can_enter(g_ptr->feat, 0)) continue;
65 if (!in_bounds(y, x)) continue;
67 /* Refuse to start on anti-teleport grids */
68 if (g_ptr->info & (CAVE_ICKY)) continue;
73 if (max_attempts < 1) /* Should be -1, actually if we failed... */
76 /* Save the new player grid */
86 * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
87 * @param y 配置を試みたいマスのY座標
88 * @param x 配置を試みたいマスのX座標
91 void place_random_stairs(POSITION y, POSITION x)
93 bool up_stairs = TRUE;
94 bool down_stairs = TRUE;
98 g_ptr = &grid_array[y][x];
99 if (!is_floor_grid(g_ptr) || g_ptr->o_idx) return;
102 if (!dun_level) up_stairs = FALSE;
105 if (ironman_downward) up_stairs = FALSE;
108 if (dun_level >= d_info[p_ptr->dungeon_idx].maxdepth) down_stairs = FALSE;
111 if (quest_number(dun_level) && (dun_level > 1)) down_stairs = FALSE;
113 /* We can't place both */
114 if (down_stairs && up_stairs)
116 /* Choose a staircase randomly */
117 if (randint0(100) < 50) up_stairs = FALSE;
118 else down_stairs = FALSE;
121 /* Place the stairs */
122 if (up_stairs) place_up_stairs(y, x);
123 else if (down_stairs) place_down_stairs(y, x);
127 * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
128 * @param y ドアの配置を試みたいマスのY座標
129 * @param x ドアの配置を試みたいマスのX座標
130 * @param room 部屋に接している場合向けのドア生成か否か
133 void place_random_door(POSITION y, POSITION x, bool room)
136 FEAT_IDX feat = feat_none;
137 grid_type *g_ptr = &grid_array[y][x];
139 /* Initialize mimic info */
142 if (d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
144 place_floor_bold(y, x);
148 type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) &&
149 one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
150 ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
152 /* Choose an object */
153 tmp = randint0(1000);
155 /* Open doors (300/1000) */
158 /* Create open door */
159 feat = feat_door[type].open;
162 /* Broken doors (100/1000) */
165 /* Create broken door */
166 feat = feat_door[type].broken;
169 /* Secret doors (200/1000) */
172 /* Create secret door */
173 place_closed_door(y, x, type);
175 if (type != DOOR_CURTAIN)
177 /* Hide. If on the edge of room, use outer wall. */
178 g_ptr->mimic = room ? feat_wall_outer : feat_wall_type[randint0(100)];
180 /* Floor type terrain cannot hide a door */
181 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat))
183 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY))
185 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
192 /* Closed, locked, or stuck doors (400/1000) */
193 else place_closed_door(y, x, type);
197 if (feat != feat_none)
199 set_cave_feat(y, x, feat);
203 place_floor_bold(y, x);
207 delete_monster(y, x);
211 * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
212 * @param y ドアの配置を試みたいマスのY座標
213 * @param x ドアの配置を試みたいマスのX座標
214 * @param type ドアの地形ID
217 void place_closed_door(POSITION y, POSITION x, int type)
220 FEAT_IDX feat = feat_none;
222 if (d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
224 place_floor_bold(y, x);
228 /* Choose an object */
231 /* Closed doors (300/400) */
234 /* Create closed door */
235 feat = feat_door[type].closed;
238 /* Locked doors (99/400) */
241 /* Create locked door */
242 feat = feat_locked_door_random(type);
245 /* Stuck doors (1/400) */
248 /* Create jammed door */
249 feat = feat_jammed_door_random(type);
252 if (feat != feat_none)
254 cave_set_feat(y, x, feat);
256 /* Now it is not floor */
257 grid_array[y][x].info &= ~(CAVE_MASK);
261 place_floor_bold(y, x);
266 * @brief 鍵のかかったドアを配置する
267 * @param y 配置したいフロアのY座標
268 * @param x 配置したいフロアのX座標
271 void place_locked_door(POSITION y, POSITION x)
273 if (d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
275 place_floor_bold(y, x);
279 set_cave_feat(y, x, feat_locked_door_random((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
280 grid_array[y][x].info &= ~(CAVE_FLOOR);
281 delete_monster(y, x);
288 * @param y 配置したいフロアのY座標
289 * @param x 配置したいフロアのX座標
290 * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
293 void place_secret_door(POSITION y, POSITION x, int type)
295 if (d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
297 place_floor_bold(y, x);
301 grid_type *g_ptr = &grid_array[y][x];
303 if (type == DOOR_DEFAULT)
305 type = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_CURTAIN) &&
306 one_in_((d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
307 ((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
310 /* Create secret door */
311 place_closed_door(y, x, type);
313 if (type != DOOR_CURTAIN)
315 /* Hide by inner wall because this is used in rooms only */
316 g_ptr->mimic = feat_wall_inner;
318 /* Floor type terrain cannot hide a door */
319 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat))
321 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY))
323 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
329 g_ptr->info &= ~(CAVE_FLOOR);
330 delete_monster(y, x);
335 * Routine used by the random vault creators to add a door to a location
336 * Note that range checking has to be done in the calling routine.
338 * The doors must be INSIDE the allocated region.
340 void add_door(POSITION x, POSITION y)
342 /* Need to have a wall in the center square */
343 if (!is_outer_bold(y, x)) return;
354 if (is_floor_bold(y - 1, x) && is_floor_bold(y + 1, x) &&
355 (is_outer_bold(y, x - 1) && is_outer_bold(y, x + 1)))
358 place_secret_door(y, x, DOOR_DEFAULT);
360 /* set boundarys so don't get wide doors */
361 place_solid_bold(y, x - 1);
362 place_solid_bold(y, x + 1);
371 * where x = don't care
374 if (is_outer_bold(y - 1, x) && is_outer_bold(y + 1, x) &&
375 is_floor_bold(y, x - 1) && is_floor_bold(y, x + 1))
378 place_secret_door(y, x, DOOR_DEFAULT);
380 /* set boundarys so don't get wide doors */
381 place_solid_bold(y - 1, x);
382 place_solid_bold(y + 1, x);
387 * @brief 隣接4マスに存在する通路の数を返す / Count the number of "corridor" grids adjacent to the given grid.
388 * @param y1 基準となるマスのY座標
389 * @param x1 基準となるマスのX座標
391 * @note Assumes "in_bounds(y1, x1)"
393 * XXX XXX This routine currently only counts actual "empty floor"\n
394 * grids which are not in rooms. We might want to also count stairs,\n
395 * open doors, closed doors, etc.
397 static int next_to_corr(POSITION y1, POSITION x1)
404 /* Scan adjacent grids */
405 for (i = 0; i < 4; i++)
407 /* Extract the location */
410 g_ptr = &grid_array[y][x];
412 /* Skip non floors */
413 if (cave_have_flag_grid(g_ptr, FF_WALL)) continue;
415 /* Skip non "empty floor" grids */
416 if (!is_floor_grid(g_ptr))
419 /* Skip grids inside rooms */
420 if (g_ptr->info & (CAVE_ROOM)) continue;
422 /* Count these grids */
426 /* Return the number of corridors */
431 * @brief ドアを設置可能な地形かを返す / Determine if the given location is "between" two walls, and "next to" two corridor spaces.
432 * @param y 判定を行いたいマスのY座標
433 * @param x 判定を行いたいマスのX座標
434 * @return ドアを設置可能ならばTRUEを返す
435 * @note Assumes "in_bounds(y1, x1)"
438 * Assumes "in_bounds(y, x)"\n
440 static bool possible_doorway(POSITION y, POSITION x)
442 /* Count the adjacent corridors */
443 if (next_to_corr(y, x) >= 2)
446 if (cave_have_flag_bold(y - 1, x, FF_WALL) &&
447 cave_have_flag_bold(y + 1, x, FF_WALL))
452 /* Check Horizontal */
453 if (cave_have_flag_bold(y, x - 1, FF_WALL) &&
454 cave_have_flag_bold(y, x + 1, FF_WALL))
465 * @brief ドアの設置を試みる / Places door at y, x position if at least 2 walls found
466 * @param y 設置を行いたいマスのY座標
467 * @param x 設置を行いたいマスのX座標
470 void try_door(POSITION y, POSITION x)
473 if (!in_bounds(y, x)) return;
476 if (cave_have_flag_bold(y, x, FF_WALL)) return;
478 /* Ignore room grids */
479 if (grid_array[y][x].info & (CAVE_ROOM)) return;
481 /* Occasional door (if allowed) */
482 if ((randint0(100) < dun_tun_jct) && possible_doorway(y, x) && !(d_info[p_ptr->dungeon_idx].flags1 & DF1_NO_DOORS))
485 place_random_door(y, x, FALSE);
491 * @brief 長方形の空洞を生成する / Make an empty square floor, for the middle of rooms
492 * @param x1 長方形の左端X座標(-1)
493 * @param x2 長方形の右端X座標(+1)
494 * @param y1 長方形の上端Y座標(-1)
495 * @param y2 長方形の下端Y座標(+1)
499 void place_floor(POSITION x1, POSITION x2, POSITION y1, POSITION y2, bool light)
503 /* Place a full floor under the room */
504 for (y = y1 - 1; y <= y2 + 1; y++)
506 for (x = x1 - 1; x <= x2 + 1; x++)
508 place_floor_bold(y, x);
509 add_cave_info(y, x, CAVE_ROOM);
510 if (light) add_cave_info(y, x, CAVE_GLOW);
517 * @brief 長方形の部屋を生成する / Make an empty square room, only floor and wall grids
518 * @param x1 長方形の左端X座標(-1)
519 * @param x2 長方形の右端X座標(+1)
520 * @param y1 長方形の上端Y座標(-1)
521 * @param y2 長方形の下端Y座標(+1)
525 void place_room(POSITION x1, POSITION x2, POSITION y1, POSITION y2, bool light)
529 place_floor(x1, x2, y1, y2, light);
531 /* Walls around the room */
532 for (y = y1 - 1; y <= y2 + 1; y++)
534 place_outer_bold(y, x1 - 1);
535 place_outer_bold(y, x2 + 1);
537 for (x = x1 - 1; x <= x2 + 1; x++)
539 place_outer_bold(y1 - 1, x);
540 place_outer_bold(y2 + 1, x);
546 * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
547 * @param y 配置したい中心マスのY座標
548 * @param x 配置したい中心マスのX座標
552 * Only really called by some of the "vault" routines.
554 void vault_objects(POSITION y, POSITION x, int num)
557 int i = 0, j = y, k = x;
562 /* Attempt to place 'num' objects */
563 for (; num > 0; --num)
565 /* Try up to 11 spots looking for empty space */
566 for (i = 0; i < 11; ++i)
568 /* Pick a random location */
569 while (dummy < SAFE_MAX_ATTEMPTS)
571 j = rand_spread(y, 2);
572 k = rand_spread(x, 3);
574 if (!in_bounds(j, k)) continue;
578 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
580 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
583 /* Require "clean" floor space */
584 g_ptr = &grid_array[j][k];
585 if (!is_floor_grid(g_ptr) || g_ptr->o_idx) continue;
587 if (randint0(100) < 75)
589 place_object(j, k, 0L);
596 /* Placement accomplished */
603 * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
604 * @param y トラップを配置したいマスの中心Y座標
605 * @param x トラップを配置したいマスの中心X座標
606 * @param yd Y方向の配置分散マス数
607 * @param xd X方向の配置分散マス数
610 * Only really called by some of the "vault" routines.
612 void vault_trap_aux(POSITION y, POSITION x, POSITION yd, POSITION xd)
614 int count = 0, y1 = y, x1 = x;
620 for (count = 0; count <= 5; count++)
623 while (dummy < SAFE_MAX_ATTEMPTS)
625 y1 = rand_spread(y, yd);
626 x1 = rand_spread(x, xd);
628 if (!in_bounds(y1, x1)) continue;
632 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
634 msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
637 /* Require "naked" floor grids */
638 g_ptr = &grid_array[y1][x1];
639 if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx) continue;
649 * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
650 * @param y トラップを配置したいマスの中心Y座標
651 * @param x トラップを配置したいマスの中心X座標
652 * @param yd Y方向の配置分散マス数
653 * @param xd X方向の配置分散マス数
654 * @param num 配置したいトラップの数
657 * Only really called by some of the "vault" routines.
659 void vault_traps(POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
663 for (i = 0; i < num; i++)
665 vault_trap_aux(y, x, yd, xd);
670 * @brief 特殊な部屋地形向けにモンスターを配置する / Hack -- Place some sleeping monsters near the given location
671 * @param y1 モンスターを配置したいマスの中心Y座標
672 * @param x1 モンスターを配置したいマスの中心X座標
673 * @param num 配置したいモンスターの数
676 * Only really called by some of the "vault" routines.
678 void vault_monsters(POSITION y1, POSITION x1, int num)
684 /* Try to summon "num" monsters "near" the given location */
685 for (k = 0; k < num; k++)
687 /* Try nine locations */
688 for (i = 0; i < 9; i++)
692 /* Pick a nearby location */
693 scatter(&y, &x, y1, x1, d, 0);
695 /* Require "empty" floor grids */
696 g_ptr = &grid_array[y][x];
697 if (!cave_empty_grid(g_ptr)) continue;
699 /* Place the monster (allow groups) */
700 monster_level = base_level + 2;
701 (void)place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
702 monster_level = base_level;
708 * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor. (Includes range checking.)
709 * @param x チェックするマスのX座標
710 * @param y チェックするマスのY座標
711 * @return 床系地形ならばTRUE
713 bool get_is_floor(POSITION x, POSITION y)
715 if (!in_bounds(y, x))
721 /* Do the real check */
722 if (is_floor_bold(y, x)) return (TRUE);
728 * @brief 指定のマスを床地形に変える / Set a square to be floor. (Includes range checking.)
729 * @param x 地形を変えたいマスのX座標
730 * @param y 地形を変えたいマスのY座標
733 void set_floor(POSITION x, POSITION y)
735 if (!in_bounds(y, x))
741 if (grid_array[y][x].info & CAVE_ROOM)
743 /* A room border don't touch. */
747 /* Set to be floor if is a wall (don't touch lakes). */
748 if (is_extra_bold(y, x))
749 place_floor_bold(y, x);
753 * @brief マスにフロア端用の永久壁を配置する / Set boundary mimic and add "solid" perma-wall
754 * @param g_ptr 永久壁を配置したいマス構造体の参照ポインタ
757 void place_bound_perm_wall(grid_type *g_ptr)
759 if (bound_walls_perm)
761 /* Clear boundary mimic */
766 feature_type *f_ptr = &f_info[g_ptr->feat];
768 /* Hack -- Decline boundary walls with known treasure */
769 if ((have_flag(f_ptr->flags, FF_HAS_GOLD) || have_flag(f_ptr->flags, FF_HAS_ITEM)) &&
770 !have_flag(f_ptr->flags, FF_SECRET))
771 g_ptr->feat = feat_state(g_ptr->feat, FF_ENSECRET);
773 /* Set boundary mimic */
774 g_ptr->mimic = g_ptr->feat;
777 /* Add "solid" perma-wall */
778 place_solid_perm_grid(g_ptr);