OSDN Git Service

Merge remote-tracking branch 'remotes/hengbandosx/english-market-edits' into feature...
[hengband/hengband.git] / src / floor / object-allocator.c
1 #include "floor/object-allocator.h"
2 #include "dungeon/dungeon.h"
3 #include "dungeon/quest.h"
4 #include "floor/cave.h"
5 #include "floor/floor-allocation-types.h"
6 #include "floor/floor-generator-util.h"
7 #include "floor/dungeon-tunnel-util.h"
8 #include "game-option/birth-options.h"
9 #include "game-option/cheat-types.h"
10 #include "grid/feature.h"
11 #include "grid/grid.h"
12 #include "grid/object-placer.h"
13 #include "grid/trap.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-flags1.h"
16 #include "system/floor-type-definition.h"
17 #include "util/bit-flags-calculator.h"
18 #include "wizard/wizard-messages.h"
19
20 /*!
21  * @brief 上下左右の外壁数をカウントする / Count the number of walls adjacent to the given grid.
22  * @param y 基準のy座標
23  * @param x 基準のx座標
24  * @return 隣接する外壁の数
25  * @note Assumes "in_bounds()"
26  * @details We count only granite walls and permanent walls.
27  */
28 static int next_to_walls(floor_type *floor_ptr, POSITION y, POSITION x)
29 {
30     int k = 0;
31     if (in_bounds(floor_ptr, y + 1, x) && is_extra_bold(floor_ptr, y + 1, x))
32         k++;
33
34     if (in_bounds(floor_ptr, y - 1, x) && is_extra_bold(floor_ptr, y - 1, x))
35         k++;
36
37     if (in_bounds(floor_ptr, y, x + 1) && is_extra_bold(floor_ptr, y, x + 1))
38         k++;
39
40     if (in_bounds(floor_ptr, y, x - 1) && is_extra_bold(floor_ptr, y, x - 1))
41         k++;
42
43     return k;
44 }
45
46 /*!
47  * @brief alloc_stairs()の補助として指定の位置に階段を生成できるかの判定を行う / Helper function for alloc_stairs(). Is this a good location for stairs?
48  * @param player_ptr プレーヤーへの参照ポインタ
49  * @param y 基準のy座標
50  * @param x 基準のx座標
51  * @param walls 最低減隣接させたい外壁の数
52  * @return 階段を生成して問題がないならばTRUEを返す。
53  */
54 static bool alloc_stairs_aux(player_type *player_ptr, POSITION y, POSITION x, int walls)
55 {
56     floor_type *floor_ptr = player_ptr->current_floor_ptr;
57     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
58     if (!is_floor_grid(g_ptr) || pattern_tile(floor_ptr, y, x) || (g_ptr->o_idx != 0) || (g_ptr->m_idx != 0) || next_to_walls(floor_ptr, y, x) < walls)
59         return FALSE;
60
61     return TRUE;
62 }
63
64 /*!
65  * @brief 外壁に隣接させて階段を生成する / Places some staircases near walls
66  * @param owner_ptr プレーヤーへの参照ポインタ
67  * @param feat 配置したい地形ID
68  * @param num 配置したい階段の数
69  * @param walls 最低減隣接させたい外壁の数
70  * @return 規定数通りに生成に成功したらTRUEを返す。
71  */
72 bool alloc_stairs(player_type *owner_ptr, FEAT_IDX feat, int num, int walls)
73 {
74     int shaft_num = 0;
75     feature_type *f_ptr = &f_info[feat];
76     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
77     if (has_flag(f_ptr->flags, FF_LESS)) {
78         if (ironman_downward || !floor_ptr->dun_level)
79             return TRUE;
80
81         if (floor_ptr->dun_level > d_info[floor_ptr->dungeon_idx].mindepth)
82             shaft_num = (randint1(num + 1)) / 2;
83     } else if (has_flag(f_ptr->flags, FF_MORE)) {
84         QUEST_IDX q_idx = quest_number(owner_ptr, floor_ptr->dun_level);
85         if (floor_ptr->dun_level > 1 && q_idx) {
86             monster_race *r_ptr = &r_info[quest[q_idx].r_idx];
87             if (!(r_ptr->flags1 & RF1_UNIQUE) || 0 < r_ptr->max_num)
88                 return TRUE;
89         }
90
91         if (floor_ptr->dun_level >= d_info[floor_ptr->dungeon_idx].maxdepth)
92             return TRUE;
93
94         if ((floor_ptr->dun_level < d_info[floor_ptr->dungeon_idx].maxdepth - 1) && !quest_number(owner_ptr, floor_ptr->dun_level + 1))
95             shaft_num = (randint1(num) + 1) / 2;
96     } else
97         return FALSE;
98
99     for (int i = 0; i < num; i++) {
100         while (TRUE) {
101             grid_type *g_ptr;
102             int candidates = 0;
103             const POSITION max_x = floor_ptr->width - 1;
104             for (POSITION y = 1; y < floor_ptr->height - 1; y++)
105                 for (POSITION x = 1; x < max_x; x++)
106                     if (alloc_stairs_aux(owner_ptr, y, x, walls))
107                         candidates++;
108
109             if (!candidates) {
110                 if (walls <= 0)
111                     return FALSE;
112
113                 walls--;
114                 continue;
115             }
116
117             int pick = randint1(candidates);
118             POSITION y;
119             POSITION x = max_x;
120             for (y = 1; y < floor_ptr->height - 1; y++) {
121                 for (x = 1; x < floor_ptr->width - 1; x++) {
122                     if (alloc_stairs_aux(owner_ptr, y, x, walls)) {
123                         pick--;
124                         if (pick == 0)
125                             break;
126                     }
127                 }
128
129                 if (pick == 0)
130                     break;
131             }
132
133             g_ptr = &floor_ptr->grid_array[y][x];
134             g_ptr->mimic = 0;
135             g_ptr->feat = (i < shaft_num) ? feat_state(owner_ptr, feat, FF_SHAFT) : feat;
136             g_ptr->info &= ~(CAVE_FLOOR);
137             break;
138         }
139     }
140
141     return TRUE;
142 }
143
144 /*!
145  * @brief フロア上のランダム位置に各種オブジェクトを配置する / Allocates some objects (using "place" and "type")
146  * @param set 配置したい地形の種類
147  * @param typ 配置したいオブジェクトの種類
148  * @param num 配置したい数
149  * @return 規定数通りに生成に成功したらTRUEを返す。
150  */
151 void alloc_object(player_type *owner_ptr, dap_type set, EFFECT_ID typ, int num)
152 {
153     POSITION y = 0;
154     POSITION x = 0;
155     int dummy = 0;
156     grid_type *g_ptr;
157     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
158     num = num * floor_ptr->height * floor_ptr->width / (MAX_HGT * MAX_WID) + 1;
159     for (int k = 0; k < num; k++) {
160         while (dummy < SAFE_MAX_ATTEMPTS) {
161             dummy++;
162             y = randint0(floor_ptr->height);
163             x = randint0(floor_ptr->width);
164             g_ptr = &floor_ptr->grid_array[y][x];
165             if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx)
166                 continue;
167
168             if (player_bold(owner_ptr, y, x))
169                 continue;
170
171             bool room = (floor_ptr->grid_array[y][x].info & CAVE_ROOM) ? TRUE : FALSE;
172             if (((set == ALLOC_SET_CORR) && room) || ((set == ALLOC_SET_ROOM) && !room))
173                 continue;
174
175             break;
176         }
177
178         if (dummy >= SAFE_MAX_ATTEMPTS) {
179             msg_print_wizard(owner_ptr, CHEAT_DUNGEON, _("アイテムの配置に失敗しました。", "Failed to place object."));
180             return;
181         }
182
183         switch (typ) {
184         case ALLOC_TYP_RUBBLE:
185             place_rubble(floor_ptr, y, x);
186             floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
187             break;
188         case ALLOC_TYP_TRAP:
189             place_trap(owner_ptr, y, x);
190             floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
191             break;
192         case ALLOC_TYP_GOLD:
193             place_gold(owner_ptr, y, x);
194             break;
195         case ALLOC_TYP_OBJECT:
196             place_object(owner_ptr, y, x, 0L);
197             break;
198         }
199     }
200 }