OSDN Git Service

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