OSDN Git Service

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