OSDN Git Service

[Refactor] #40570 Removed unused headers in rooms-builder.c
[hengband/hengband.git] / src / room / rooms-builder.c
1 /*!
2  * @brief ダンジョンフロアの部屋生成処理 / make rooms. Used by generate.c when creating dungeons.
3  * @date 2014/01/06
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  * This software may be copied and distributed for educational, research,\n
7  * and not for profit purposes provided that this copyright and statement\n
8  * are included in all such copies.  Other copyrights may also apply.\n
9  * 2014 Deskull rearranged comment for Doxygen. \n
10  * @details
11  * Room building routines.\n
12  *\n
13  * Room types:\n
14  *   1 -- normal\n
15  *   2 -- overlapping\n
16  *   3 -- cross shaped\n
17  *   4 -- large room with features\n
18  *   5 -- monster nests\n
19  *   6 -- monster pits\n
20  *   7 -- simple vaults\n
21  *   8 -- greater vaults\n
22  *   9 -- fractal caves\n
23  *  10 -- random vaults\n
24  *  11 -- circular rooms\n
25  *  12 -- crypts\n
26  *  13 -- trapped monster pits\n
27  *  14 -- trapped room\n
28  *  15 -- glass room\n
29  *  16 -- underground arcade\n
30  *\n
31  * Some functions are used to determine if the given monster\n
32  * is appropriate for inclusion in a monster nest or monster pit or\n
33  * the given type.\n
34  *\n
35  * None of the pits/nests are allowed to include "unique" monsters.\n
36  */
37
38 #include "room/rooms-builder.h"
39 #include "dungeon/dungeon-flag-types.h"
40 #include "dungeon/dungeon.h"
41 #include "floor/cave.h"
42 #include "floor/floor.h"
43 #include "grid/grid.h"
44 #include "room/cave-filler.h"
45 #include "room/lake-types.h"
46 #include "system/floor-type-definition.h"
47 #include "view/display-messages.h"
48
49 /*!
50  * @brief 1マスだけの部屋を作成し、上下左右いずれか一つに隠しドアを配置する。
51  * @param player_ptr プレーヤーへの参照ポインタ
52  * @param y0 配置したい中心のY座標
53  * @param x0 配置したい中心のX座標
54  * @details
55  * This funtion makes a very small room centred at (x0, y0)
56  * This is used in crypts, and random elemental vaults.
57  *
58  * Note - this should be used only on allocated regions
59  * within another room.
60  */
61 void build_small_room(player_type *player_ptr, POSITION x0, POSITION y0)
62 {
63     for (POSITION y = y0 - 1; y <= y0 + 1; y++) {
64         place_bold(player_ptr, y, x0 - 1, GB_INNER);
65         place_bold(player_ptr, y, x0 + 1, GB_INNER);
66     }
67
68     for (POSITION x = x0 - 1; x <= x0 + 1; x++) {
69         place_bold(player_ptr, y0 - 1, x, GB_INNER);
70         place_bold(player_ptr, y0 + 1, x, GB_INNER);
71     }
72
73     switch (randint0(4)) {
74     case 0:
75         place_secret_door(player_ptr, y0, x0 - 1, DOOR_DEFAULT);
76         break;
77     case 1:
78         place_secret_door(player_ptr, y0, x0 + 1, DOOR_DEFAULT);
79         break;
80     case 2:
81         place_secret_door(player_ptr, y0 - 1, x0, DOOR_DEFAULT);
82         break;
83     case 3:
84         place_secret_door(player_ptr, y0 + 1, x0, DOOR_DEFAULT);
85         break;
86     }
87
88     player_ptr->current_floor_ptr->grid_array[y0][x0].mimic = 0;
89     place_bold(player_ptr, y0, x0, GB_FLOOR);
90 }
91
92 /*
93  * Builds a cave system in the center of the dungeon.
94  */
95 void build_cavern(player_type *player_ptr)
96 {
97     bool light = FALSE;
98     bool done = FALSE;
99     floor_type *floor_ptr = player_ptr->current_floor_ptr;
100     if ((floor_ptr->dun_level <= randint1(50)) && !(d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
101         light = TRUE;
102
103     POSITION xsize = floor_ptr->width - 1;
104     POSITION ysize = floor_ptr->height - 1;
105     POSITION x0 = xsize / 2;
106     POSITION y0 = ysize / 2;
107     xsize = x0 * 2;
108     ysize = y0 * 2;
109
110     while (!done) {
111         int grd = randint1(4) + 4;
112         int roug = randint1(8) * randint1(4);
113         int cutoff = xsize / 2;
114         generate_hmap(floor_ptr, y0 + 1, x0 + 1, xsize, ysize, grd, roug, cutoff);
115         done = generate_fracave(player_ptr, y0 + 1, x0 + 1, xsize, ysize, cutoff, light, FALSE);
116     }
117 }
118
119 /*
120  * makes a lake/collapsed floor in the center of the dungeon
121  */
122 void build_lake(player_type *player_ptr, int type)
123 {
124     if ((type < LAKE_T_LAVA) || (type > LAKE_T_FIRE_VAULT)) {
125         msg_format("Invalid lake type (%d)", type);
126         return;
127     }
128
129     floor_type *floor_ptr = player_ptr->current_floor_ptr;
130     int xsize = floor_ptr->width - 1;
131     int ysize = floor_ptr->height - 1;
132     int x0 = xsize / 2;
133     int y0 = ysize / 2;
134     xsize = x0 * 2;
135     ysize = y0 * 2;
136     bool done = FALSE;
137     while (!done) {
138         int grd = randint1(3) + 4;
139         int roug = randint1(8) * randint1(4);
140         int c3 = 3 * xsize / 4;
141         int c1 = randint0(c3 / 2) + randint0(c3 / 2) - 5;
142         int c2 = (c1 + c3) / 2;
143         generate_hmap(floor_ptr, y0 + 1, x0 + 1, xsize, ysize, grd, roug, c3);
144         done = generate_lake(player_ptr, y0 + 1, x0 + 1, xsize, ysize, c1, c2, c3, type);
145     }
146 }
147
148 /*
149  * Overlay a rectangular room given its bounds
150  * This routine is used by build_room_vault
151  * The area inside the walls is not touched:
152  * only granite is removed- normal walls stay
153  */
154 void build_room(player_type *player_ptr, POSITION x1, POSITION x2, POSITION y1, POSITION y2)
155 {
156     int temp;
157     if ((x1 == x2) || (y1 == y2))
158         return;
159
160     if (x1 > x2) {
161         temp = x1;
162         x1 = x2;
163         x2 = temp;
164     }
165
166     if (y1 > y2) {
167         temp = y1;
168         y1 = y2;
169         y2 = temp;
170     }
171
172     POSITION xsize = x2 - x1;
173     POSITION ysize = y2 - y1;
174     floor_type *floor_ptr = player_ptr->current_floor_ptr;
175     for (int i = 0; i <= xsize; i++) {
176         place_bold(player_ptr, y1, x1 + i, GB_OUTER_NOPERM);
177         floor_ptr->grid_array[y1][x1 + i].info |= (CAVE_ROOM | CAVE_ICKY);
178         place_bold(player_ptr, y2, x1 + i, GB_OUTER_NOPERM);
179         floor_ptr->grid_array[y2][x1 + i].info |= (CAVE_ROOM | CAVE_ICKY);
180     }
181
182     for (int i = 1; i < ysize; i++) {
183         place_bold(player_ptr, y1 + i, x1, GB_OUTER_NOPERM);
184         floor_ptr->grid_array[y1 + i][x1].info |= (CAVE_ROOM | CAVE_ICKY);
185         place_bold(player_ptr, y1 + i, x2, GB_OUTER_NOPERM);
186         floor_ptr->grid_array[y1 + i][x2].info |= (CAVE_ROOM | CAVE_ICKY);
187     }
188
189     for (POSITION x = 1; x < xsize; x++) {
190         for (POSITION y = 1; y < ysize; y++) {
191             if (is_extra_bold(floor_ptr, y1 + y, x1 + x)) {
192                 place_bold(player_ptr, y1 + y, x1 + x, GB_FLOOR);
193                 floor_ptr->grid_array[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
194             } else {
195                 floor_ptr->grid_array[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
196             }
197         }
198     }
199 }
200
201 /*
202  * Build a town/ castle by using a recursive algorithm.
203  * Basically divide each region in a probalistic way to create
204  * smaller regions.  When the regions get too small stop.
205  *
206  * The power variable is a measure of how well defended a region is.
207  * This alters the possible choices.
208  */
209 void build_recursive_room(player_type *player_ptr, POSITION x1, POSITION y1, POSITION x2, POSITION y2, int power)
210 {
211     POSITION xsize = x2 - x1;
212     POSITION ysize = y2 - y1;
213
214     int choice;
215     if ((power < 3) && (xsize > 12) && (ysize > 12)) {
216         choice = 1;
217     } else {
218         if (power < 10) {
219             if ((randint1(10) > 2) && (xsize < 8) && (ysize < 8)) {
220                 choice = 4;
221             } else {
222                 choice = randint1(2) + 1;
223             }
224         } else {
225             choice = randint1(3) + 1;
226         }
227     }
228
229     switch (choice) {
230     case 1: {
231         /* Outer walls */
232         int x;
233         int y;
234         for (x = x1; x <= x2; x++) {
235             place_bold(player_ptr, y1, x, GB_OUTER);
236             place_bold(player_ptr, y2, x, GB_OUTER);
237         }
238
239         for (y = y1 + 1; y < y2; y++) {
240             place_bold(player_ptr, y, x1, GB_OUTER);
241             place_bold(player_ptr, y, x2, GB_OUTER);
242         }
243
244         if (one_in_(2)) {
245             y = randint1(ysize) + y1;
246             place_bold(player_ptr, y, x1, GB_FLOOR);
247             place_bold(player_ptr, y, x2, GB_FLOOR);
248         } else {
249             x = randint1(xsize) + x1;
250             place_bold(player_ptr, y1, x, GB_FLOOR);
251             place_bold(player_ptr, y2, x, GB_FLOOR);
252         }
253
254         int t1 = randint1(ysize / 3) + y1;
255         int t2 = y2 - randint1(ysize / 3);
256         int t3 = randint1(xsize / 3) + x1;
257         int t4 = x2 - randint1(xsize / 3);
258
259         /* Do outside areas */
260         build_recursive_room(player_ptr, x1 + 1, y1 + 1, x2 - 1, t1, power + 1);
261         build_recursive_room(player_ptr, x1 + 1, t2, x2 - 1, y2, power + 1);
262         build_recursive_room(player_ptr, x1 + 1, t1 + 1, t3, t2 - 1, power + 3);
263         build_recursive_room(player_ptr, t4, t1 + 1, x2 - 1, t2 - 1, power + 3);
264
265         x1 = t3;
266         x2 = t4;
267         y1 = t1;
268         y2 = t2;
269         xsize = x2 - x1;
270         ysize = y2 - y1;
271         power += 2;
272     }
273         /* Fall through */
274     case 4: {
275         /* Try to build a room */
276         if ((xsize < 3) || (ysize < 3)) {
277             for (int y = y1; y < y2; y++) {
278                 for (int x = x1; x < x2; x++) {
279                     place_bold(player_ptr, y, x, GB_INNER);
280                 }
281             }
282
283             return;
284         }
285
286         for (int x = x1 + 1; x <= x2 - 1; x++) {
287             place_bold(player_ptr, y1 + 1, x, GB_INNER);
288             place_bold(player_ptr, y2 - 1, x, GB_INNER);
289         }
290
291         for (int y = y1 + 1; y <= y2 - 1; y++) {
292             place_bold(player_ptr, y, x1 + 1, GB_INNER);
293             place_bold(player_ptr, y, x2 - 1, GB_INNER);
294         }
295
296         int y = randint1(ysize - 3) + y1 + 1;
297         if (one_in_(2)) {
298             /* left */
299             place_bold(player_ptr, y, x1 + 1, GB_FLOOR);
300         } else {
301             /* right */
302             place_bold(player_ptr, y, x2 - 1, GB_FLOOR);
303         }
304
305         build_recursive_room(player_ptr, x1 + 2, y1 + 2, x2 - 2, y2 - 2, power + 3);
306         break;
307     }
308     case 2: {
309         /* Try and divide vertically */
310         if (xsize < 3) {
311             for (int y = y1; y < y2; y++) {
312                 for (int x = x1; x < x2; x++) {
313                     place_bold(player_ptr, y, x, GB_INNER);
314                 }
315             }
316             return;
317         }
318
319         int t1 = randint1(xsize - 2) + x1 + 1;
320         build_recursive_room(player_ptr, x1, y1, t1, y2, power - 2);
321         build_recursive_room(player_ptr, t1 + 1, y1, x2, y2, power - 2);
322         break;
323     }
324     case 3: {
325         /* Try and divide horizontally */
326         if (ysize < 3) {
327             for (int y = y1; y < y2; y++)
328                 for (int x = x1; x < x2; x++)
329                     place_bold(player_ptr, y, x, GB_INNER);
330
331             return;
332         }
333
334         int t1 = randint1(ysize - 2) + y1 + 1;
335         build_recursive_room(player_ptr, x1, y1, x2, t1, power - 2);
336         build_recursive_room(player_ptr, x1, t1 + 1, x2, y2, power - 2);
337         break;
338     }
339     }
340 }
341
342 /*
343  * Add outer wall to a floored region
344  * Note: no range checking is done so must be inside dungeon
345  * This routine also stomps on doors
346  */
347 void add_outer_wall(player_type *player_ptr, POSITION x, POSITION y, int light, POSITION x1, POSITION y1, POSITION x2, POSITION y2)
348 {
349     floor_type *floor_ptr = player_ptr->current_floor_ptr;
350     if (!in_bounds(floor_ptr, y, x))
351         return;
352
353     grid_type *g_ptr;
354     g_ptr = &floor_ptr->grid_array[y][x];
355     if (g_ptr->info & CAVE_ROOM)
356         return;
357
358     g_ptr->info |= CAVE_ROOM;
359     feature_type *f_ptr;
360     f_ptr = &f_info[g_ptr->feat];
361     if (is_floor_bold(floor_ptr, y, x)) {
362         for (int i = -1; i <= 1; i++) {
363             for (int j = -1; j <= 1; j++) {
364                 if ((x + i >= x1) && (x + i <= x2) && (y + j >= y1) && (y + j <= y2)) {
365                     add_outer_wall(player_ptr, x + i, y + j, light, x1, y1, x2, y2);
366                     if (light)
367                         g_ptr->info |= CAVE_GLOW;
368                 }
369             }
370         }
371
372         return;
373     }
374
375     if (is_extra_bold(floor_ptr, y, x)) {
376         place_bold(player_ptr, y, x, GB_OUTER);
377         if (light)
378             g_ptr->info |= CAVE_GLOW;
379
380         return;
381     }
382
383     if (permanent_wall(f_ptr)) {
384         if (light)
385             g_ptr->info |= CAVE_GLOW;
386     }
387 }
388
389 /*
390  * Hacked distance formula - gives the 'wrong' answer.
391  * Used to build crypts
392  */
393 POSITION dist2(POSITION x1, POSITION y1, POSITION x2, POSITION y2, POSITION h1, POSITION h2, POSITION h3, POSITION h4)
394 {
395     POSITION dx = abs(x2 - x1);
396     POSITION dy = abs(y2 - y1);
397     if (dx >= 2 * dy)
398         return (dx + (dy * h1) / h2);
399
400     if (dy >= 2 * dx)
401         return (dy + (dx * h1) / h2);
402
403     return (((dx + dy) * 128) / 181 + (dx * dx / (dy * h3) + dy * dy / (dx * h3)) * h4);
404 }