OSDN Git Service

[Refactor] #2141 floor_type *floor_ptrの宣言をautoに差し替えた
[hengbandforosx/hengbandosx.git] / src / floor / cave-generator.cpp
1 #include "floor/cave-generator.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "dungeon/quest-monster-placer.h"
5 #include "floor/dungeon-tunnel-util.h"
6 #include "floor/floor-allocation-types.h"
7 #include "floor/floor-streams.h"
8 #include "floor/geometry.h"
9 #include "floor/object-allocator.h"
10 #include "floor/tunnel-generator.h"
11 #include "floor/wild.h"
12 #include "game-option/birth-options.h"
13 #include "game-option/cheat-types.h"
14 #include "game-option/game-play-options.h"
15 #include "grid/door.h"
16 #include "grid/feature-generator.h"
17 #include "grid/feature.h"
18 #include "grid/grid.h"
19 #include "monster-floor/monster-generator.h"
20 #include "monster-floor/monster-summon.h"
21 #include "monster-floor/place-monster-types.h"
22 #include "monster/monster-util.h"
23 #include "room/lake-types.h"
24 #include "room/room-generator.h"
25 #include "room/rooms-maze-vault.h"
26 #include "system/dungeon-data-definition.h"
27 #include "system/floor-type-definition.h"
28 #include "system/grid-type-definition.h"
29 #include "system/player-type-definition.h"
30 #include "util/bit-flags-calculator.h"
31 #include "wizard/wizard-messages.h"
32
33 static void reset_lite_area(floor_type *floor_ptr)
34 {
35     floor_ptr->lite_n = 0;
36     floor_ptr->mon_lite_n = 0;
37     floor_ptr->redraw_n = 0;
38     floor_ptr->view_n = 0;
39 }
40
41 static dun_data_type *initialize_dun_data_type(dun_data_type *dd_ptr, concptr *why)
42 {
43     dd_ptr->destroyed = false;
44     dd_ptr->empty_level = false;
45     dd_ptr->cavern = false;
46     dd_ptr->laketype = 0;
47     dd_ptr->why = why;
48     return dd_ptr;
49 }
50
51 static void check_arena_floor(PlayerType *player_ptr, dun_data_type *dd_ptr)
52 {
53     auto *floor_ptr = player_ptr->current_floor_ptr;
54     if (!dd_ptr->empty_level) {
55         for (POSITION y = 0; y < floor_ptr->height; y++)
56             for (POSITION x = 0; x < floor_ptr->width; x++)
57                 place_bold(player_ptr, y, x, GB_EXTRA);
58
59         return;
60     }
61
62     for (POSITION y = 0; y < floor_ptr->height; y++)
63         for (POSITION x = 0; x < floor_ptr->width; x++)
64             place_bold(player_ptr, y, x, GB_FLOOR);
65
66     for (POSITION x = 0; x < floor_ptr->width; x++) {
67         place_bold(player_ptr, 0, x, GB_EXTRA);
68         place_bold(player_ptr, floor_ptr->height - 1, x, GB_EXTRA);
69     }
70
71     for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
72         place_bold(player_ptr, y, 0, GB_EXTRA);
73         place_bold(player_ptr, y, floor_ptr->width - 1, GB_EXTRA);
74     }
75 }
76
77 static void place_cave_contents(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
78 {
79     auto *floor_ptr = player_ptr->current_floor_ptr;
80     if (floor_ptr->dun_level == 1)
81         while (one_in_(DUN_MOS_DEN))
82             place_trees(player_ptr, randint1(floor_ptr->width - 2), randint1(floor_ptr->height - 2));
83
84     if (dd_ptr->destroyed)
85         destroy_level(player_ptr);
86
87     if (has_river_flag(d_ptr) && one_in_(3) && (randint1(floor_ptr->dun_level) > 5))
88         add_river(floor_ptr, dd_ptr);
89
90     for (int i = 0; i < dd_ptr->cent_n; i++) {
91         POSITION ty, tx;
92         int pick = rand_range(0, i);
93         ty = dd_ptr->cent[i].y;
94         tx = dd_ptr->cent[i].x;
95         dd_ptr->cent[i].y = dd_ptr->cent[pick].y;
96         dd_ptr->cent[i].x = dd_ptr->cent[pick].x;
97         dd_ptr->cent[pick].y = ty;
98         dd_ptr->cent[pick].x = tx;
99     }
100 }
101
102 static bool decide_tunnel_planned_site(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr, int i)
103 {
104     dd_ptr->tunn_n = 0;
105     dd_ptr->wall_n = 0;
106     if (randint1(player_ptr->current_floor_ptr->dun_level) > d_ptr->tunnel_percent)
107         (void)build_tunnel2(player_ptr, dd_ptr, dd_ptr->cent[i].x, dd_ptr->cent[i].y, dd_ptr->tunnel_x, dd_ptr->tunnel_y, 2, 2);
108     else if (!build_tunnel(player_ptr, dd_ptr, dt_ptr, dd_ptr->cent[i].y, dd_ptr->cent[i].x, dd_ptr->tunnel_y, dd_ptr->tunnel_x))
109         dd_ptr->tunnel_fail_count++;
110
111     if (dd_ptr->tunnel_fail_count >= 2) {
112         *dd_ptr->why = _("トンネル接続に失敗", "Failed to generate tunnels");
113         return false;
114     }
115
116     return true;
117 }
118
119 static void make_tunnels(PlayerType *player_ptr, dun_data_type *dd_ptr)
120 {
121     for (int j = 0; j < dd_ptr->tunn_n; j++) {
122         grid_type *g_ptr;
123         feature_type *f_ptr;
124         dd_ptr->tunnel_y = dd_ptr->tunn[j].y;
125         dd_ptr->tunnel_x = dd_ptr->tunn[j].x;
126         g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
127         f_ptr = &f_info[g_ptr->feat];
128         if (f_ptr->flags.has_not(FloorFeatureType::MOVE) || f_ptr->flags.has_none_of({FloorFeatureType::WATER, FloorFeatureType::LAVA})) {
129             g_ptr->mimic = 0;
130             place_grid(player_ptr, g_ptr, GB_FLOOR);
131         }
132     }
133 }
134
135 static void make_walls(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr)
136 {
137     for (int j = 0; j < dd_ptr->wall_n; j++) {
138         grid_type *g_ptr;
139         dd_ptr->tunnel_y = dd_ptr->wall[j].y;
140         dd_ptr->tunnel_x = dd_ptr->wall[j].x;
141         g_ptr = &player_ptr->current_floor_ptr->grid_array[dd_ptr->tunnel_y][dd_ptr->tunnel_x];
142         g_ptr->mimic = 0;
143         place_grid(player_ptr, g_ptr, GB_FLOOR);
144         if ((randint0(100) < dt_ptr->dun_tun_pen) && d_ptr->flags.has_not(DungeonFeatureType::NO_DOORS))
145             place_random_door(player_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x, true);
146     }
147 }
148
149 static bool make_centers(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr, dt_type *dt_ptr)
150 {
151     dd_ptr->tunnel_fail_count = 0;
152     dd_ptr->door_n = 0;
153     dd_ptr->tunnel_y = dd_ptr->cent[dd_ptr->cent_n - 1].y;
154     dd_ptr->tunnel_x = dd_ptr->cent[dd_ptr->cent_n - 1].x;
155     for (int i = 0; i < dd_ptr->cent_n; i++) {
156         if (!decide_tunnel_planned_site(player_ptr, dd_ptr, d_ptr, dt_ptr, i))
157             return false;
158
159         make_tunnels(player_ptr, dd_ptr);
160         make_walls(player_ptr, dd_ptr, d_ptr, dt_ptr);
161         dd_ptr->tunnel_y = dd_ptr->cent[i].y;
162         dd_ptr->tunnel_x = dd_ptr->cent[i].x;
163     }
164
165     return true;
166 }
167
168 static void make_doors(PlayerType *player_ptr, dun_data_type *dd_ptr, dt_type *dt_ptr)
169 {
170     for (int i = 0; i < dd_ptr->door_n; i++) {
171         dd_ptr->tunnel_y = dd_ptr->door[i].y;
172         dd_ptr->tunnel_x = dd_ptr->door[i].x;
173         try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x - 1);
174         try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y, dd_ptr->tunnel_x + 1);
175         try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y - 1, dd_ptr->tunnel_x);
176         try_door(player_ptr, dt_ptr, dd_ptr->tunnel_y + 1, dd_ptr->tunnel_x);
177     }
178 }
179
180 static void make_only_tunnel_points(floor_type *floor_ptr, dun_data_type *dd_ptr)
181 {
182     int point_num = (floor_ptr->width * floor_ptr->height) / 200 + randint1(3);
183     dd_ptr->cent_n = point_num;
184     for (int i = 0; i < point_num; i++) {
185         dd_ptr->cent[i].y = randint0(floor_ptr->height);
186         dd_ptr->cent[i].x = randint0(floor_ptr->width);
187     }
188 }
189
190 static bool make_one_floor(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
191 {
192     auto *floor_ptr = player_ptr->current_floor_ptr;
193
194     if (d_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_ROOM)) {
195         make_only_tunnel_points(floor_ptr, dd_ptr);
196     } else {
197         if (!generate_rooms(player_ptr, dd_ptr)) {
198             *dd_ptr->why = _("部屋群の生成に失敗", "Failed to generate rooms");
199             return false;
200         }
201     }
202
203     place_cave_contents(player_ptr, dd_ptr, d_ptr);
204     dt_type tmp_dt;
205     dt_type *dt_ptr = initialize_dt_type(&tmp_dt);
206     if (!make_centers(player_ptr, dd_ptr, d_ptr, dt_ptr))
207         return false;
208
209     make_doors(player_ptr, dd_ptr, dt_ptr);
210     if (!alloc_stairs(player_ptr, feat_down_stair, rand_range(3, 4), 3)) {
211         *dd_ptr->why = _("下り階段生成に失敗", "Failed to generate down stairs.");
212         return false;
213     }
214
215     if (!alloc_stairs(player_ptr, feat_up_stair, rand_range(1, 2), 3)) {
216         *dd_ptr->why = _("上り階段生成に失敗", "Failed to generate up stairs.");
217         return false;
218     }
219
220     return true;
221 }
222
223 static bool switch_making_floor(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
224 {
225     if (d_ptr->flags.has(DungeonFeatureType::MAZE)) {
226         auto *floor_ptr = player_ptr->current_floor_ptr;
227         build_maze_vault(player_ptr, floor_ptr->width / 2 - 1, floor_ptr->height / 2 - 1, floor_ptr->width - 4, floor_ptr->height - 4, false);
228         if (!alloc_stairs(player_ptr, feat_down_stair, rand_range(2, 3), 3)) {
229             *dd_ptr->why = _("迷宮ダンジョンの下り階段生成に失敗", "Failed to alloc up stairs in maze dungeon.");
230             return false;
231         }
232
233         if (!alloc_stairs(player_ptr, feat_up_stair, 1, 3)) {
234             *dd_ptr->why = _("迷宮ダンジョンの上り階段生成に失敗", "Failed to alloc down stairs in maze dungeon.");
235             return false;
236         }
237
238         return true;
239     }
240     
241     if (!make_one_floor(player_ptr, dd_ptr, d_ptr))
242         return false;
243
244     return true;
245 }
246
247 static void make_aqua_streams(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
248 {
249     if (dd_ptr->laketype != 0)
250         return;
251
252     if (d_ptr->stream2)
253         for (int i = 0; i < DUN_STR_QUA; i++)
254             build_streamer(player_ptr, d_ptr->stream2, DUN_STR_QC);
255
256     if (d_ptr->stream1)
257         for (int i = 0; i < DUN_STR_MAG; i++)
258             build_streamer(player_ptr, d_ptr->stream1, DUN_STR_MC);
259 }
260
261 /*!
262  * @brief マスにフロア端用の永久壁を配置する / Set boundary mimic and add "solid" perma-wall
263  * @param g_ptr 永久壁を配置したいマス構造体の参照ポインタ
264  */
265 static void place_bound_perm_wall(PlayerType *player_ptr, grid_type *g_ptr)
266 {
267     if (bound_walls_perm) {
268         g_ptr->mimic = 0;
269         place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
270         return;
271     }
272
273     auto *f_ptr = &f_info[g_ptr->feat];
274     if (f_ptr->flags.has_any_of({FloorFeatureType::HAS_GOLD, FloorFeatureType::HAS_ITEM}) && f_ptr->flags.has_not(FloorFeatureType::SECRET)) {
275         g_ptr->feat = feat_state(player_ptr->current_floor_ptr, g_ptr->feat, FloorFeatureType::ENSECRET);
276     }
277
278     g_ptr->mimic = g_ptr->feat;
279     place_grid(player_ptr, g_ptr, GB_SOLID_PERM);
280 }
281
282 static void make_perm_walls(PlayerType *player_ptr)
283 {
284     auto *floor_ptr = player_ptr->current_floor_ptr;
285     for (POSITION x = 0; x < floor_ptr->width; x++) {
286         place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[0][x]);
287         place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[floor_ptr->height - 1][x]);
288     }
289
290     for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
291         place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][0]);
292         place_bound_perm_wall(player_ptr, &floor_ptr->grid_array[y][floor_ptr->width - 1]);
293     }
294 }
295
296 static bool check_place_necessary_objects(PlayerType *player_ptr, dun_data_type *dd_ptr)
297 {
298     if (!new_player_spot(player_ptr)) {
299         *dd_ptr->why = _("プレイヤー配置に失敗", "Failed to place a player");
300         return false;
301     }
302
303     if (!place_quest_monsters(player_ptr)) {
304         *dd_ptr->why = _("クエストモンスター配置に失敗", "Failed to place a quest monster");
305         return false;
306     }
307
308     return true;
309 }
310
311 static void decide_dungeon_data_allocation(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
312 {
313     auto *floor_ptr = player_ptr->current_floor_ptr;
314     dd_ptr->alloc_object_num = floor_ptr->dun_level / 3;
315     if (dd_ptr->alloc_object_num > 10)
316         dd_ptr->alloc_object_num = 10;
317
318     if (dd_ptr->alloc_object_num < 2)
319         dd_ptr->alloc_object_num = 2;
320
321     dd_ptr->alloc_monster_num = d_ptr->min_m_alloc_level;
322     if (floor_ptr->height >= MAX_HGT && floor_ptr->width >= MAX_WID)
323         return;
324
325     int small_tester = dd_ptr->alloc_monster_num;
326     dd_ptr->alloc_monster_num = (dd_ptr->alloc_monster_num * floor_ptr->height) / MAX_HGT;
327     dd_ptr->alloc_monster_num = (dd_ptr->alloc_monster_num * floor_ptr->width) / MAX_WID;
328     dd_ptr->alloc_monster_num += 1;
329     if (dd_ptr->alloc_monster_num > small_tester)
330         dd_ptr->alloc_monster_num = small_tester;
331     else
332         msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("モンスター数基本値を %d から %d に減らします", "Reduced monsters base from %d to %d"), small_tester,
333             dd_ptr->alloc_monster_num);
334 }
335
336 static bool allocate_dungeon_data(PlayerType *player_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
337 {
338     dd_ptr->alloc_monster_num += randint1(8);
339     for (dd_ptr->alloc_monster_num = dd_ptr->alloc_monster_num + dd_ptr->alloc_object_num; dd_ptr->alloc_monster_num > 0; dd_ptr->alloc_monster_num--)
340         (void)alloc_monster(player_ptr, 0, PM_ALLOW_SLEEP, summon_specific);
341
342     alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_TRAP, randint1(dd_ptr->alloc_object_num));
343     if (d_ptr->flags.has_not(DungeonFeatureType::NO_CAVE))
344         alloc_object(player_ptr, ALLOC_SET_CORR, ALLOC_TYP_RUBBLE, randint1(dd_ptr->alloc_object_num));
345
346     auto *floor_ptr = player_ptr->current_floor_ptr;
347     if (player_ptr->enter_dungeon && floor_ptr->dun_level > 1)
348         floor_ptr->object_level = 1;
349
350     alloc_object(player_ptr, ALLOC_SET_ROOM, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ROOM, 3));
351     alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ITEM, 3));
352     alloc_object(player_ptr, ALLOC_SET_BOTH, ALLOC_TYP_GOLD, randnor(DUN_AMT_GOLD, 3));
353     floor_ptr->object_level = floor_ptr->base_level;
354     if (alloc_guardian(player_ptr, true))
355         return true;
356
357     *dd_ptr->why = _("ダンジョンの主配置に失敗", "Failed to place a dungeon guardian");
358     return false;
359 }
360
361 static void decide_grid_glowing(floor_type *floor_ptr, dun_data_type *dd_ptr, dungeon_type *d_ptr)
362 {
363     bool is_empty_or_dark = dd_ptr->empty_level;
364     is_empty_or_dark &= !one_in_(DARK_EMPTY) || (randint1(100) > floor_ptr->dun_level);
365     is_empty_or_dark &= d_ptr->flags.has_not(DungeonFeatureType::DARKNESS);
366     if (!is_empty_or_dark)
367         return;
368
369     for (POSITION y = 0; y < floor_ptr->height; y++)
370         for (POSITION x = 0; x < floor_ptr->width; x++)
371             floor_ptr->grid_array[y][x].info |= CAVE_GLOW;
372 }
373
374 /*!
375  * @brief ダンジョン生成のメインルーチン / Generate a new dungeon level
376  * @details Note that "dun_body" adds about 4000 bytes of memory to the stack.
377  * @param player_ptr プレイヤーへの参照ポインタ
378  * @param why エラー原因メッセージを返す
379  * @return ダンジョン生成が全て無事に成功したらTRUEを返す。
380  */
381 bool cave_gen(PlayerType *player_ptr, concptr *why)
382 {
383     auto *floor_ptr = player_ptr->current_floor_ptr;
384     reset_lite_area(floor_ptr);
385     set_floor_and_wall(floor_ptr->dungeon_idx);
386     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), nullptr);
387
388     dun_data_type tmp_dd;
389     dun_data_type *dd_ptr = initialize_dun_data_type(&tmp_dd, why);
390     dd_ptr->row_rooms = floor_ptr->height / BLOCK_HGT;
391     dd_ptr->col_rooms = floor_ptr->width / BLOCK_WID;
392     for (POSITION y = 0; y < dd_ptr->row_rooms; y++)
393         for (POSITION x = 0; x < dd_ptr->col_rooms; x++)
394             dd_ptr->room_map[y][x] = false;
395
396     dd_ptr->cent_n = 0;
397     dungeon_type *d_ptr = &d_info[floor_ptr->dungeon_idx];
398     if (ironman_empty_levels || (d_ptr->flags.has(DungeonFeatureType::ARENA) && (empty_levels && one_in_(EMPTY_LEVEL)))) {
399         dd_ptr->empty_level = true;
400         msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("アリーナレベルを生成。", "Arena level."));
401     }
402
403     check_arena_floor(player_ptr, dd_ptr);
404     gen_caverns_and_lakes(player_ptr, d_ptr, dd_ptr);
405     if (!switch_making_floor(player_ptr, dd_ptr, d_ptr))
406         return false;
407
408     make_aqua_streams(player_ptr, dd_ptr, d_ptr);
409     make_perm_walls(player_ptr);
410     if (!check_place_necessary_objects(player_ptr, dd_ptr))
411         return false;
412
413     decide_dungeon_data_allocation(player_ptr, dd_ptr, d_ptr);
414     if (!allocate_dungeon_data(player_ptr, dd_ptr, d_ptr))
415         return false;
416
417     decide_grid_glowing(floor_ptr, dd_ptr, d_ptr);
418     return true;
419 }