OSDN Git Service

Merge pull request #857 from sikabane-works/feature/fix-doxygen-syntax
[hengbandforosx/hengbandosx.git] / src / room / cave-filler.cpp
1 /*!
2  * @brief fill_data_type構造体を使ってダンジョンを生成/構成する処理
3  * @date 2020/07/24
4  * @author Hourier
5  */
6
7 #include <queue>
8
9 #include "dungeon/dungeon-flag-types.h"
10 #include "dungeon/dungeon.h"
11 #include "floor/cave.h"
12 #include "grid/feature.h"
13 #include "grid/grid.h"
14 #include "room/cave-filler.h"
15 #include "room/lake-types.h"
16 #include "system/floor-type-definition.h"
17 #include "util/point-2d.h"
18
19 typedef struct fill_data_type {
20     POSITION xmin;
21     POSITION ymin;
22     POSITION xmax;
23     POSITION ymax;
24
25     /* cutoffs */
26     int c1;
27     int c2;
28     int c3;
29
30     /* features to fill with */
31     FEAT_IDX feat1;
32     FEAT_IDX feat2;
33     FEAT_IDX feat3;
34
35     int info1;
36     int info2;
37     int info3;
38
39     /* number of filled squares */
40     int amount;
41 } fill_data_type;
42
43 static fill_data_type fill_data;
44
45 /*!
46  * Store routine for the fractal floor generator
47  * this routine probably should be an inline function or a macro.
48  */
49 static void store_height(floor_type *floor_ptr, POSITION x, POSITION y, FEAT_IDX val)
50 {
51     if (((x == fill_data.xmin) || (y == fill_data.ymin) || (x == fill_data.xmax) || (y == fill_data.ymax)) && (val <= fill_data.c1))
52         val = fill_data.c1 + 1;
53
54     floor_ptr->grid_array[y][x].feat = val;
55     return;
56 }
57
58 void generate_hmap(floor_type *floor_ptr, POSITION y0, POSITION x0, POSITION xsiz, POSITION ysiz, int grd, int roug, int cutoff)
59 {
60     POSITION xsize = xsiz;
61     POSITION ysize = ysiz;
62
63     if (xsize > 254)
64         xsize = 254;
65
66     if (xsize < 4)
67         xsize = 4;
68
69     if (ysize > 254)
70         ysize = 254;
71
72     if (ysize < 4)
73         ysize = 4;
74
75     POSITION xhsize = xsize / 2;
76     POSITION yhsize = ysize / 2;
77     xsize = xhsize * 2;
78     ysize = yhsize * 2;
79
80     fill_data.xmin = x0 - xhsize;
81     fill_data.ymin = y0 - yhsize;
82     fill_data.xmax = x0 + xhsize;
83     fill_data.ymax = y0 + yhsize;
84     fill_data.c1 = cutoff;
85     POSITION diagsize = 362;
86     POSITION maxsize = (xsize > ysize) ? xsize : ysize;
87     for (POSITION i = 0; i <= xsize; i++) {
88         for (POSITION j = 0; j <= ysize; j++) {
89             floor_ptr->grid_array[(int)(fill_data.ymin + j)][(int)(fill_data.xmin + i)].feat = -1;
90             floor_ptr->grid_array[(int)(fill_data.ymin + j)][(int)(fill_data.xmin + i)].info &= ~(CAVE_ICKY);
91         }
92     }
93
94     floor_ptr->grid_array[fill_data.ymin][fill_data.xmin].feat = (s16b)maxsize;
95     floor_ptr->grid_array[fill_data.ymax][fill_data.xmin].feat = (s16b)maxsize;
96     floor_ptr->grid_array[fill_data.ymin][fill_data.xmax].feat = (s16b)maxsize;
97     floor_ptr->grid_array[fill_data.ymax][fill_data.xmax].feat = (s16b)maxsize;
98     floor_ptr->grid_array[y0][x0].feat = 0;
99     POSITION xstep = xsize * 256;
100     POSITION xhstep = xsize * 256;
101     POSITION ystep = ysize * 256;
102     POSITION yhstep = ysize * 256;
103     POSITION xxsize = xsize * 256;
104     POSITION yysize = ysize * 256;
105     while ((xhstep > 256) || (yhstep > 256)) {
106         xstep = xhstep;
107         xhstep /= 2;
108         ystep = yhstep;
109         yhstep /= 2;
110         POSITION xstep2 = xstep / 256;
111         POSITION ystep2 = ystep / 256;
112         POSITION xhstep2 = xhstep / 256;
113         POSITION yhstep2 = yhstep / 256;
114         for (POSITION i = xhstep; i <= xxsize - xhstep; i += xstep) {
115             for (POSITION j = 0; j <= yysize; j += ystep) {
116                 POSITION ii = i / 256 + fill_data.xmin;
117                 POSITION jj = j / 256 + fill_data.ymin;
118                 if (floor_ptr->grid_array[jj][ii].feat != -1)
119                     continue;
120
121                 if (xhstep2 > grd) {
122                     store_height(floor_ptr, ii, jj, randint1(maxsize));
123                     continue;
124                 }
125
126                 store_height(floor_ptr, ii, jj,
127                     (floor_ptr->grid_array[jj][fill_data.xmin + (i - xhstep) / 256].feat + floor_ptr->grid_array[jj][fill_data.xmin + (i + xhstep) / 256].feat)
128                             / 2
129                         + (randint1(xstep2) - xhstep2) * roug / 16);
130             }
131         }
132
133         for (POSITION j = yhstep; j <= yysize - yhstep; j += ystep) {
134             for (POSITION i = 0; i <= xxsize; i += xstep) {
135                 POSITION ii = i / 256 + fill_data.xmin;
136                 POSITION jj = j / 256 + fill_data.ymin;
137                 if (floor_ptr->grid_array[jj][ii].feat != -1)
138                     continue;
139
140                 if (xhstep2 > grd) {
141                     store_height(floor_ptr, ii, jj, randint1(maxsize));
142                     continue;
143                 }
144
145                 store_height(floor_ptr, ii, jj,
146                     (floor_ptr->grid_array[fill_data.ymin + (j - yhstep) / 256][ii].feat + floor_ptr->grid_array[fill_data.ymin + (j + yhstep) / 256][ii].feat)
147                             / 2
148                         + (randint1(ystep2) - yhstep2) * roug / 16);
149             }
150         }
151
152         for (POSITION i = xhstep; i <= xxsize - xhstep; i += xstep) {
153             for (POSITION j = yhstep; j <= yysize - yhstep; j += ystep) {
154                 POSITION ii = i / 256 + fill_data.xmin;
155                 POSITION jj = j / 256 + fill_data.ymin;
156                 if (floor_ptr->grid_array[jj][ii].feat != -1)
157                     continue;
158
159                 if (xhstep2 > grd) {
160                     store_height(floor_ptr, ii, jj, randint1(maxsize));
161                     continue;
162                 }
163
164                 POSITION xm = fill_data.xmin + (i - xhstep) / 256;
165                 POSITION xp = fill_data.xmin + (i + xhstep) / 256;
166                 POSITION ym = fill_data.ymin + (j - yhstep) / 256;
167                 POSITION yp = fill_data.ymin + (j + yhstep) / 256;
168                 store_height(floor_ptr, ii, jj,
169                     (floor_ptr->grid_array[ym][xm].feat + floor_ptr->grid_array[yp][xm].feat + floor_ptr->grid_array[ym][xp].feat
170                         + floor_ptr->grid_array[yp][xp].feat)
171                             / 4
172                         + (randint1(xstep2) - xhstep2) * (diagsize / 16) / 256 * roug);
173             }
174         }
175     }
176 }
177
178 static bool hack_isnt_wall(player_type *player_ptr, POSITION y, POSITION x, int c1, int c2, int c3, FEAT_IDX feat1, FEAT_IDX feat2, FEAT_IDX feat3,
179     BIT_FLAGS info1, BIT_FLAGS info2, BIT_FLAGS info3)
180 {
181     floor_type *floor_ptr = player_ptr->current_floor_ptr;
182     if (floor_ptr->grid_array[y][x].info & CAVE_ICKY)
183         return FALSE;
184
185     floor_ptr->grid_array[y][x].info |= (CAVE_ICKY);
186     if (floor_ptr->grid_array[y][x].feat <= c1) {
187         if (randint1(100) < 75) {
188             floor_ptr->grid_array[y][x].feat = feat1;
189             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
190             floor_ptr->grid_array[y][x].info |= info1;
191             return TRUE;
192         } else {
193             floor_ptr->grid_array[y][x].feat = feat2;
194             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
195             floor_ptr->grid_array[y][x].info |= info2;
196             return TRUE;
197         }
198     }
199
200     if (floor_ptr->grid_array[y][x].feat <= c2) {
201         if (randint1(100) < 75) {
202             floor_ptr->grid_array[y][x].feat = feat2;
203             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
204             floor_ptr->grid_array[y][x].info |= info2;
205             return TRUE;
206         } else {
207             floor_ptr->grid_array[y][x].feat = feat1;
208             floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
209             floor_ptr->grid_array[y][x].info |= info1;
210             return TRUE;
211         }
212     }
213
214     if (floor_ptr->grid_array[y][x].feat <= c3) {
215         floor_ptr->grid_array[y][x].feat = feat3;
216         floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
217         floor_ptr->grid_array[y][x].info |= info3;
218         return TRUE;
219     }
220
221     place_bold(player_ptr, y, x, GB_OUTER);
222     return FALSE;
223 }
224
225 /*
226  * Quick and nasty fill routine used to find the connected region
227  * of floor in the middle of the grids
228  */
229 static void cave_fill(player_type *player_ptr, const POSITION y, const POSITION x)
230 {
231     floor_type *floor_ptr = player_ptr->current_floor_ptr;
232
233     // 幅優先探索用のキュー。
234     std::queue<Pos2D> que;
235     que.emplace(y, x);
236
237     while (!que.empty()) {
238         const auto [y_cur, x_cur] = que.front();
239         que.pop();
240
241         for (int d = 0; d < 8; d++) {
242             int y_to = y_cur + ddy_ddd[d];
243             int x_to = x_cur + ddx_ddd[d];
244             if (!in_bounds(floor_ptr, y_to, x_to)) {
245                 floor_ptr->grid_array[y_to][x_to].info |= CAVE_ICKY;
246                 continue;
247             }
248
249             if ((x_to <= fill_data.xmin) || (x_to >= fill_data.xmax) || (y_to <= fill_data.ymin) || (y_to >= fill_data.ymax)) {
250                 floor_ptr->grid_array[y_to][x_to].info |= CAVE_ICKY;
251                 continue;
252             }
253
254             if (!hack_isnt_wall(player_ptr, y_to, x_to, fill_data.c1, fill_data.c2, fill_data.c3, fill_data.feat1, fill_data.feat2, fill_data.feat3,
255                     fill_data.info1, fill_data.info2, fill_data.info3))
256                 continue;
257
258             que.emplace(y_to, x_to);
259
260             (fill_data.amount)++;
261         }
262     }
263 }
264
265 bool generate_fracave(player_type *player_ptr, POSITION y0, POSITION x0, POSITION xsize, POSITION ysize, int cutoff, bool light, bool room)
266 {
267     POSITION xhsize = xsize / 2;
268     POSITION yhsize = ysize / 2;
269     fill_data.c1 = cutoff;
270     fill_data.c2 = 0;
271     fill_data.c3 = 0;
272     fill_data.feat1 = feat_ground_type[randint0(100)];
273     fill_data.feat2 = feat_ground_type[randint0(100)];
274     fill_data.feat3 = feat_ground_type[randint0(100)];
275     fill_data.info1 = CAVE_FLOOR;
276     fill_data.info2 = CAVE_FLOOR;
277     fill_data.info3 = CAVE_FLOOR;
278     fill_data.amount = 0;
279     floor_type *floor_ptr = player_ptr->current_floor_ptr;
280     cave_fill(player_ptr, (byte)y0, (byte)x0);
281     if (fill_data.amount < 10) {
282         for (POSITION x = 0; x <= xsize; ++x) {
283             for (POSITION y = 0; y <= ysize; ++y) {
284                 place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
285                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
286             }
287         }
288
289         return FALSE;
290     }
291
292     for (int i = 0; i <= xsize; ++i) {
293         if ((floor_ptr->grid_array[0 + y0 - yhsize][i + x0 - xhsize].info & CAVE_ICKY) && (room)) {
294             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_OUTER);
295             if (light)
296                 floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info |= (CAVE_GLOW);
297
298             floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info |= (CAVE_ROOM);
299             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_OUTER);
300         } else {
301             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_EXTRA);
302         }
303
304         if ((floor_ptr->grid_array[ysize + y0 - yhsize][i + x0 - xhsize].info & CAVE_ICKY) && (room)) {
305             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_OUTER);
306             if (light)
307                 floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info |= (CAVE_GLOW);
308
309             floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info |= (CAVE_ROOM);
310             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_OUTER);
311         } else {
312             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_EXTRA);
313         }
314
315         floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
316         floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
317     }
318
319     for (int i = 1; i < ysize; ++i) {
320         if ((floor_ptr->grid_array[i + y0 - yhsize][0 + x0 - xhsize].info & CAVE_ICKY) && room) {
321             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_OUTER);
322             if (light)
323                 floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info |= (CAVE_GLOW);
324
325             floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info |= (CAVE_ROOM);
326             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_OUTER);
327         } else {
328             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_EXTRA);
329         }
330
331         if ((floor_ptr->grid_array[i + y0 - yhsize][xsize + x0 - xhsize].info & CAVE_ICKY) && room) {
332             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_OUTER);
333             if (light)
334                 floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info |= (CAVE_GLOW);
335
336             floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info |= (CAVE_ROOM);
337             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_OUTER);
338         } else {
339             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_EXTRA);
340         }
341
342         floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info &= ~(CAVE_ICKY);
343         floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info &= ~(CAVE_ICKY);
344     }
345
346     for (POSITION x = 1; x < xsize; ++x) {
347         for (POSITION y = 1; y < ysize; ++y) {
348             if (is_floor_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize) && (floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info & CAVE_ICKY)) {
349                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~CAVE_ICKY;
350                 if (light)
351                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_GLOW);
352
353                 if (room)
354                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_ROOM);
355
356                 continue;
357             }
358
359             if (is_outer_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize) && (floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info & CAVE_ICKY)) {
360                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY);
361                 if (light)
362                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_GLOW);
363
364                 if (room) {
365                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_ROOM);
366                 } else {
367                     place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
368                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ROOM);
369                 }
370
371                 continue;
372             }
373
374             place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
375             floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
376         }
377     }
378
379     return TRUE;
380 }
381
382 bool generate_lake(player_type *player_ptr, POSITION y0, POSITION x0, POSITION xsize, POSITION ysize, int c1, int c2, int c3, int type)
383 {
384     FEAT_IDX feat1, feat2, feat3;
385     POSITION xhsize = xsize / 2;
386     POSITION yhsize = ysize / 2;
387     switch (type) {
388     case LAKE_T_LAVA: /* Lava */
389         feat1 = feat_deep_lava;
390         feat2 = feat_shallow_lava;
391         feat3 = feat_ground_type[randint0(100)];
392         break;
393     case LAKE_T_WATER: /* Water */
394         feat1 = feat_deep_water;
395         feat2 = feat_shallow_water;
396         feat3 = feat_ground_type[randint0(100)];
397         break;
398     case LAKE_T_CAVE: /* Collapsed floor_ptr->grid_array */
399         feat1 = feat_ground_type[randint0(100)];
400         feat2 = feat_ground_type[randint0(100)];
401         feat3 = feat_rubble;
402         break;
403     case LAKE_T_EARTH_VAULT: /* Earth vault */
404         feat1 = feat_rubble;
405         feat2 = feat_ground_type[randint0(100)];
406         feat3 = feat_rubble;
407         break;
408     case LAKE_T_AIR_VAULT: /* Air vault */
409         feat1 = feat_grass;
410         feat2 = feat_tree;
411         feat3 = feat_grass;
412         break;
413     case LAKE_T_WATER_VAULT: /* Water vault */
414         feat1 = feat_shallow_water;
415         feat2 = feat_deep_water;
416         feat3 = feat_shallow_water;
417         break;
418     case LAKE_T_FIRE_VAULT: /* Fire Vault */
419         feat1 = feat_shallow_lava;
420         feat2 = feat_deep_lava;
421         feat3 = feat_shallow_lava;
422         break;
423     default:
424         return FALSE;
425     }
426
427     fill_data.c1 = c1;
428     fill_data.c2 = c2;
429     fill_data.c3 = c3;
430     fill_data.feat1 = feat1;
431     fill_data.feat2 = feat2;
432     fill_data.feat3 = feat3;
433     fill_data.info1 = 0;
434     fill_data.info2 = 0;
435     fill_data.info3 = 0;
436     fill_data.amount = 0;
437
438     floor_type *floor_ptr = player_ptr->current_floor_ptr;
439     cave_fill(player_ptr, (byte)y0, (byte)x0);
440     if (fill_data.amount < 10) {
441         for (POSITION x = 0; x <= xsize; ++x) {
442             for (POSITION y = 0; y <= ysize; ++y) {
443                 place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_FLOOR);
444                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY);
445             }
446         }
447
448         return FALSE;
449     }
450
451     for (int i = 0; i <= xsize; ++i) {
452         place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_EXTRA);
453         place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_EXTRA);
454         floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
455         floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
456     }
457
458     for (int i = 1; i < ysize; ++i) {
459         place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_EXTRA);
460         place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_EXTRA);
461         floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info &= ~(CAVE_ICKY);
462         floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info &= ~(CAVE_ICKY);
463     }
464
465     for (POSITION x = 1; x < xsize; ++x) {
466         for (POSITION y = 1; y < ysize; ++y) {
467             if ((!(floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info & CAVE_ICKY)) || is_outer_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize))
468                 place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
469
470             floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
471             if (cave_has_flag_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize, FF_LAVA)) {
472                 if (!(d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
473                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= CAVE_GLOW;
474             }
475         }
476     }
477
478     return TRUE;
479 }