OSDN Git Service

ea15c7081a9e156276bed3dfb13e33347bbcc51e
[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 "floor//geometry.h"
13 #include "grid/feature.h"
14 #include "grid/grid.h"
15 #include "room/cave-filler.h"
16 #include "room/lake-types.h"
17 #include "system/floor-type-definition.h"
18 #include "system/player-type-definition.h"
19 #include "util/point-2d.h"
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 = (s16b)maxsize;
97     floor_ptr->grid_array[fill_data.ymax][fill_data.xmin].feat = (s16b)maxsize;
98     floor_ptr->grid_array[fill_data.ymin][fill_data.xmax].feat = (s16b)maxsize;
99     floor_ptr->grid_array[fill_data.ymax][fill_data.xmax].feat = (s16b)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         if ((floor_ptr->grid_array[0 + y0 - yhsize][i + x0 - xhsize].info & CAVE_ICKY) && (room)) {
296             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_OUTER);
297             if (light)
298                 floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info |= (CAVE_GLOW);
299
300             floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info |= (CAVE_ROOM);
301             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_OUTER);
302         } else {
303             place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_EXTRA);
304         }
305
306         if ((floor_ptr->grid_array[ysize + y0 - yhsize][i + x0 - xhsize].info & CAVE_ICKY) && (room)) {
307             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_OUTER);
308             if (light)
309                 floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info |= (CAVE_GLOW);
310
311             floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info |= (CAVE_ROOM);
312             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_OUTER);
313         } else {
314             place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_EXTRA);
315         }
316
317         floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
318         floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
319     }
320
321     for (int i = 1; i < ysize; ++i) {
322         if ((floor_ptr->grid_array[i + y0 - yhsize][0 + x0 - xhsize].info & CAVE_ICKY) && room) {
323             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_OUTER);
324             if (light)
325                 floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info |= (CAVE_GLOW);
326
327             floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info |= (CAVE_ROOM);
328             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_OUTER);
329         } else {
330             place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_EXTRA);
331         }
332
333         if ((floor_ptr->grid_array[i + y0 - yhsize][xsize + x0 - xhsize].info & CAVE_ICKY) && room) {
334             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_OUTER);
335             if (light)
336                 floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info |= (CAVE_GLOW);
337
338             floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info |= (CAVE_ROOM);
339             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_OUTER);
340         } else {
341             place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_EXTRA);
342         }
343
344         floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info &= ~(CAVE_ICKY);
345         floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info &= ~(CAVE_ICKY);
346     }
347
348     for (POSITION x = 1; x < xsize; ++x) {
349         for (POSITION y = 1; y < ysize; ++y) {
350             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)) {
351                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~CAVE_ICKY;
352                 if (light)
353                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_GLOW);
354
355                 if (room)
356                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_ROOM);
357
358                 continue;
359             }
360
361             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)) {
362                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY);
363                 if (light)
364                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_GLOW);
365
366                 if (room) {
367                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= (CAVE_ROOM);
368                 } else {
369                     place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
370                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ROOM);
371                 }
372
373                 continue;
374             }
375
376             place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
377             floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
378         }
379     }
380
381     return true;
382 }
383
384 bool generate_lake(player_type *player_ptr, POSITION y0, POSITION x0, POSITION xsize, POSITION ysize, int c1, int c2, int c3, int type)
385 {
386     FEAT_IDX feat1, feat2, feat3;
387     POSITION xhsize = xsize / 2;
388     POSITION yhsize = ysize / 2;
389     switch (type) {
390     case LAKE_T_LAVA: /* Lava */
391         feat1 = feat_deep_lava;
392         feat2 = feat_shallow_lava;
393         feat3 = feat_ground_type[randint0(100)];
394         break;
395     case LAKE_T_WATER: /* Water */
396         feat1 = feat_deep_water;
397         feat2 = feat_shallow_water;
398         feat3 = feat_ground_type[randint0(100)];
399         break;
400     case LAKE_T_CAVE: /* Collapsed floor_ptr->grid_array */
401         feat1 = feat_ground_type[randint0(100)];
402         feat2 = feat_ground_type[randint0(100)];
403         feat3 = feat_rubble;
404         break;
405     case LAKE_T_EARTH_VAULT: /* Earth vault */
406         feat1 = feat_rubble;
407         feat2 = feat_ground_type[randint0(100)];
408         feat3 = feat_rubble;
409         break;
410     case LAKE_T_AIR_VAULT: /* Air vault */
411         feat1 = feat_grass;
412         feat2 = feat_tree;
413         feat3 = feat_grass;
414         break;
415     case LAKE_T_WATER_VAULT: /* Water vault */
416         feat1 = feat_shallow_water;
417         feat2 = feat_deep_water;
418         feat3 = feat_shallow_water;
419         break;
420     case LAKE_T_FIRE_VAULT: /* Fire Vault */
421         feat1 = feat_shallow_lava;
422         feat2 = feat_deep_lava;
423         feat3 = feat_shallow_lava;
424         break;
425     default:
426         return false;
427     }
428
429     fill_data.c1 = c1;
430     fill_data.c2 = c2;
431     fill_data.c3 = c3;
432     fill_data.feat1 = feat1;
433     fill_data.feat2 = feat2;
434     fill_data.feat3 = feat3;
435     fill_data.info1 = 0;
436     fill_data.info2 = 0;
437     fill_data.info3 = 0;
438     fill_data.amount = 0;
439
440     floor_type *floor_ptr = player_ptr->current_floor_ptr;
441     cave_fill(player_ptr, (byte)y0, (byte)x0);
442     if (fill_data.amount < 10) {
443         for (POSITION x = 0; x <= xsize; ++x) {
444             for (POSITION y = 0; y <= ysize; ++y) {
445                 place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_FLOOR);
446                 floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY);
447             }
448         }
449
450         return false;
451     }
452
453     for (int i = 0; i <= xsize; ++i) {
454         place_bold(player_ptr, y0 + 0 - yhsize, x0 + i - xhsize, GB_EXTRA);
455         place_bold(player_ptr, y0 + ysize - yhsize, x0 + i - xhsize, GB_EXTRA);
456         floor_ptr->grid_array[y0 + 0 - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
457         floor_ptr->grid_array[y0 + ysize - yhsize][x0 + i - xhsize].info &= ~(CAVE_ICKY);
458     }
459
460     for (int i = 1; i < ysize; ++i) {
461         place_bold(player_ptr, y0 + i - yhsize, x0 + 0 - xhsize, GB_EXTRA);
462         place_bold(player_ptr, y0 + i - yhsize, x0 + xsize - xhsize, GB_EXTRA);
463         floor_ptr->grid_array[y0 + i - yhsize][x0 + 0 - xhsize].info &= ~(CAVE_ICKY);
464         floor_ptr->grid_array[y0 + i - yhsize][x0 + xsize - xhsize].info &= ~(CAVE_ICKY);
465     }
466
467     for (POSITION x = 1; x < xsize; ++x) {
468         for (POSITION y = 1; y < ysize; ++y) {
469             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))
470                 place_bold(player_ptr, y0 + y - yhsize, x0 + x - xhsize, GB_EXTRA);
471
472             floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
473             if (cave_has_flag_bold(floor_ptr, y0 + y - yhsize, x0 + x - xhsize, FF_LAVA)) {
474                 if (d_info[floor_ptr->dungeon_idx].flags.has_not(DF::DARKNESS))
475                     floor_ptr->grid_array[y0 + y - yhsize][x0 + x - xhsize].info |= CAVE_GLOW;
476             }
477         }
478     }
479
480     return true;
481 }