1 #include "floor/object-allocator.h"
2 #include "dungeon/quest.h"
3 #include "floor/cave.h"
4 #include "floor/dungeon-tunnel-util.h"
5 #include "floor/floor-allocation-types.h"
6 #include "floor/floor-generator-util.h"
7 #include "game-option/birth-options.h"
8 #include "game-option/cheat-types.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "grid/object-placer.h"
12 #include "grid/trap.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-flags1.h"
15 #include "system/dungeon-info.h"
16 #include "system/floor-type-definition.h"
17 #include "system/grid-type-definition.h"
18 #include "system/monster-race-info.h"
19 #include "system/player-type-definition.h"
20 #include "system/terrain-type-definition.h"
21 #include "util/bit-flags-calculator.h"
22 #include "wizard/wizard-messages.h"
25 * @brief 上下左右の外壁数をカウントする / Count the number of walls adjacent to the given grid.
29 * @note Assumes "in_bounds()"
30 * @details We count only granite walls and permanent walls.
32 static int next_to_walls(FloorType *floor_ptr, POSITION y, POSITION x)
35 if (in_bounds(floor_ptr, y + 1, x) && floor_ptr->grid_array[y + 1][x].is_extra()) {
39 if (in_bounds(floor_ptr, y - 1, x) && floor_ptr->grid_array[y - 1][x].is_extra()) {
43 if (in_bounds(floor_ptr, y, x + 1) && floor_ptr->grid_array[y][x + 1].is_extra()) {
47 if (in_bounds(floor_ptr, y, x - 1) && floor_ptr->grid_array[y][x - 1].is_extra()) {
55 * @brief alloc_stairs()の補助として指定の位置に階段を生成できるかの判定を行う / Helper function for alloc_stairs(). Is this a good location for stairs?
56 * @param player_ptr プレイヤーへの参照ポインタ
59 * @param walls 最低減隣接させたい外壁の数
60 * @return 階段を生成して問題がないならばTRUEを返す。
62 static bool alloc_stairs_aux(PlayerType *player_ptr, POSITION y, POSITION x, int walls)
64 auto *floor_ptr = player_ptr->current_floor_ptr;
65 auto *g_ptr = &floor_ptr->grid_array[y][x];
66 if (!g_ptr->is_floor() || pattern_tile(floor_ptr, y, x) || !g_ptr->o_idx_list.empty() || (g_ptr->m_idx != 0) || next_to_walls(floor_ptr, y, x) < walls) {
74 * @brief 外壁に隣接させて階段を生成する / Places some staircases near walls
75 * @param player_ptr プレイヤーへの参照ポインタ
76 * @param feat 配置したい地形ID
77 * @param num 配置したい階段の数
78 * @param walls 最低減隣接させたい外壁の数
79 * @return 規定数通りに生成に成功したらTRUEを返す。
81 bool alloc_stairs(PlayerType *player_ptr, FEAT_IDX feat, int num, int walls)
84 auto *f_ptr = &terrains_info[feat];
85 auto &floor = *player_ptr->current_floor_ptr;
86 const auto &dungeon = floor.get_dungeon_definition();
87 if (f_ptr->flags.has(TerrainCharacteristics::LESS)) {
88 if (ironman_downward || !floor.dun_level) {
92 if (floor.dun_level > dungeon.mindepth) {
93 shaft_num = (randint1(num + 1)) / 2;
95 } else if (f_ptr->flags.has(TerrainCharacteristics::MORE)) {
96 auto q_idx = quest_number(floor, floor.dun_level);
97 const auto &quest_list = QuestList::get_instance();
98 if (floor.dun_level > 1 && inside_quest(q_idx)) {
99 auto *r_ptr = &monraces_info[quest_list[q_idx].r_idx];
100 if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) || 0 < r_ptr->max_num) {
105 if (floor.dun_level >= dungeon.maxdepth) {
109 if ((floor.dun_level < dungeon.maxdepth - 1) && !inside_quest(quest_number(floor, floor.dun_level + 1))) {
110 shaft_num = (randint1(num) + 1) / 2;
116 for (int i = 0; i < num; i++) {
120 const POSITION max_x = floor.width - 1;
121 for (POSITION y = 1; y < floor.height - 1; y++) {
122 for (POSITION x = 1; x < max_x; x++) {
123 if (alloc_stairs_aux(player_ptr, y, x, walls)) {
138 int pick = randint1(candidates);
141 for (y = 1; y < floor.height - 1; y++) {
142 for (x = 1; x < floor.width - 1; x++) {
143 if (alloc_stairs_aux(player_ptr, y, x, walls)) {
156 g_ptr = &floor.grid_array[y][x];
158 g_ptr->feat = (i < shaft_num) ? feat_state(&floor, feat, TerrainCharacteristics::SHAFT) : feat;
159 g_ptr->info &= ~(CAVE_FLOOR);
168 * @brief 指定座標に瓦礫を配置する
172 static void place_rubble(FloorType *floor_ptr, POSITION y, POSITION x)
174 set_cave_feat(floor_ptr, y, x, feat_rubble);
178 * @brief フロア上のランダム位置に各種オブジェクトを配置する / Allocates some objects (using "place" and "type")
179 * @param set 配置したい地形の種類
180 * @param typ 配置したいオブジェクトの種類
182 * @return 規定数通りに生成に成功したらTRUEを返す。
184 void alloc_object(PlayerType *player_ptr, dap_type set, dungeon_allocation_type typ, int num)
190 auto *floor_ptr = player_ptr->current_floor_ptr;
191 num = num * floor_ptr->height * floor_ptr->width / (MAX_HGT * MAX_WID) + 1;
192 for (int k = 0; k < num; k++) {
193 while (dummy < SAFE_MAX_ATTEMPTS) {
195 y = randint0(floor_ptr->height);
196 x = randint0(floor_ptr->width);
197 g_ptr = &floor_ptr->grid_array[y][x];
198 if (!g_ptr->is_floor() || !g_ptr->o_idx_list.empty() || g_ptr->m_idx) {
202 if (player_bold(player_ptr, y, x)) {
206 auto is_room = floor_ptr->grid_array[y][x].is_room();
207 if (((set == ALLOC_SET_CORR) && is_room) || ((set == ALLOC_SET_ROOM) && !is_room)) {
214 if (dummy >= SAFE_MAX_ATTEMPTS) {
215 msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("アイテムの配置に失敗しました。", "Failed to place object."));
220 case ALLOC_TYP_RUBBLE:
221 place_rubble(floor_ptr, y, x);
222 floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
225 place_trap(player_ptr, y, x);
226 floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
229 place_gold(player_ptr, y, x);
231 case ALLOC_TYP_OBJECT:
232 place_object(player_ptr, y, x, 0L);