OSDN Git Service

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