OSDN Git Service

e734cb7da90ab96be62ae6196a340b36b575e60a
[hengbandforosx/hengbandosx.git] / src / room / rooms-vault.cpp
1 /*!
2  * @brief Vaultの生成処理
3  * @date 2018/09/11
4  * @author deskull
5  */
6
7 #include "room/rooms-vault.h"
8 #include "dungeon/dungeon-flag-types.h"
9 #include "dungeon/dungeon.h"
10 #include "floor/cave.h"
11 #include "floor/floor-generator-util.h"
12 #include "floor/floor-generator.h"
13 #include "floor/geometry.h"
14 #include "floor/wild.h"
15 #include "game-option/cheat-types.h"
16 #include "grid/door.h"
17 #include "grid/feature.h"
18 #include "grid/grid.h"
19 #include "grid/object-placer.h"
20 #include "grid/trap.h"
21 #include "monster-floor/monster-generator.h"
22 #include "monster-floor/place-monster-types.h"
23 #include "object-enchant/item-apply-magic.h"
24 #include "room/cave-filler.h"
25 #include "room/door-definition.h"
26 #include "room/lake-types.h"
27 #include "room/rooms-builder.h"
28 #include "room/rooms-maze-vault.h"
29 #include "room/space-finder.h"
30 #include "room/treasure-deployment.h"
31 #include "store/store-util.h"
32 #include "store/store.h"
33 #include "system/dungeon-data-definition.h"
34 #include "system/floor-type-definition.h"
35 #include "system/grid-type-definition.h"
36 #include "system/player-type-definition.h"
37 #include "util/probability-table.h"
38 #include "wizard/wizard-messages.h"
39
40 /*
41  * The vault generation arrays
42  */
43 std::vector<vault_type> v_info;
44
45 /*
46  * This function creates a random vault that looks like a collection of bubbles.
47  * It works by getting a set of coordinates that represent the center of each
48  * bubble.  The entire room is made by seeing which bubble center is closest. If
49  * two centers are equidistant then the square is a wall, otherwise it is a floor.
50  * The only exception is for squares really near a center, these are always floor.
51  * (It looks better than without this check.)
52  *
53  * Note: If two centers are on the same point then this algorithm will create a
54  *       blank bubble filled with walls. - This is prevented from happening.
55  */
56 static void build_bubble_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsize, POSITION ysize)
57 {
58 #define BUBBLENUM 10 /* number of bubbles */
59
60     /* array of center points of bubbles */
61     coord center[BUBBLENUM];
62
63     int i, j;
64     POSITION x = 0, y = 0;
65     uint16_t min1, min2, temp;
66     bool done;
67
68     /* Offset from center to top left hand corner */
69     POSITION xhsize = xsize / 2;
70     POSITION yhsize = ysize / 2;
71
72     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("泡型ランダムVaultを生成しました。", "Bubble-shaped Vault."));
73
74     /* Allocate center of bubbles */
75     center[0].x = (byte)randint1(xsize - 3) + 1;
76     center[0].y = (byte)randint1(ysize - 3) + 1;
77
78     for (i = 1; i < BUBBLENUM; i++) {
79         done = false;
80
81         /* get center and check to see if it is unique */
82         while (!done) {
83             done = true;
84
85             x = randint1(xsize - 3) + 1;
86             y = randint1(ysize - 3) + 1;
87
88             for (j = 0; j < i; j++) {
89                 /* rough test to see if there is an overlap */
90                 if ((x == center[j].x) && (y == center[j].y))
91                     done = false;
92             }
93         }
94
95         center[i].x = x;
96         center[i].y = y;
97     }
98
99     /* Top and bottom boundaries */
100     auto *floor_ptr = player_ptr->current_floor_ptr;
101     for (i = 0; i < xsize; i++) {
102         int side_x = x0 - xhsize + i;
103
104         place_bold(player_ptr, y0 - yhsize + 0, side_x, GB_OUTER_NOPERM);
105         floor_ptr->grid_array[y0 - yhsize + 0][side_x].info |= (CAVE_ROOM | CAVE_ICKY);
106         place_bold(player_ptr, y0 - yhsize + ysize - 1, side_x, GB_OUTER_NOPERM);
107         floor_ptr->grid_array[y0 - yhsize + ysize - 1][side_x].info |= (CAVE_ROOM | CAVE_ICKY);
108     }
109
110     /* Left and right boundaries */
111     for (i = 1; i < ysize - 1; i++) {
112         int side_y = y0 - yhsize + i;
113
114         place_bold(player_ptr, side_y, x0 - xhsize + 0, GB_OUTER_NOPERM);
115         floor_ptr->grid_array[side_y][x0 - xhsize + 0].info |= (CAVE_ROOM | CAVE_ICKY);
116         place_bold(player_ptr, side_y, x0 - xhsize + xsize - 1, GB_OUTER_NOPERM);
117         floor_ptr->grid_array[side_y][x0 - xhsize + xsize - 1].info |= (CAVE_ROOM | CAVE_ICKY);
118     }
119
120     /* Fill in middle with bubbles */
121     for (x = 1; x < xsize - 1; x++) {
122         for (y = 1; y < ysize - 1; y++) {
123             /* Get distances to two closest centers */
124
125             min1 = (uint16_t)distance(x, y, center[0].x, center[0].y);
126             min2 = (uint16_t)distance(x, y, center[1].x, center[1].y);
127
128             if (min1 > min2) {
129                 /* swap if in wrong order */
130                 temp = min1;
131                 min1 = min2;
132                 min2 = temp;
133             }
134
135             /* Scan the rest */
136             for (i = 2; i < BUBBLENUM; i++) {
137                 temp = (uint16_t)distance(x, y, center[i].x, center[i].y);
138
139                 if (temp < min1) {
140                     /* smallest */
141                     min2 = min1;
142                     min1 = temp;
143                 } else if (temp < min2) {
144                     /* second smallest */
145                     min2 = temp;
146                 }
147             }
148             if (((min2 - min1) <= 2) && (!(min1 < 3))) {
149                 /* Boundary at midpoint+ not at inner region of bubble */
150                 place_bold(player_ptr, y0 - yhsize + y, x0 - xhsize + x, GB_OUTER_NOPERM);
151             } else {
152                 /* middle of a bubble */
153                 place_bold(player_ptr, y0 - yhsize + y, x0 - xhsize + x, GB_FLOOR);
154             }
155
156             /* clean up rest of flags */
157             floor_ptr->grid_array[y0 - yhsize + y][x0 - xhsize + x].info |= (CAVE_ROOM | CAVE_ICKY);
158         }
159     }
160
161     /* Try to add some random doors */
162     for (i = 0; i < 500; i++) {
163         x = randint1(xsize - 3) - xhsize + x0 + 1;
164         y = randint1(ysize - 3) - yhsize + y0 + 1;
165         add_door(player_ptr, x, y);
166     }
167
168     /* Fill with monsters and treasure, low difficulty */
169     fill_treasure(player_ptr, x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5));
170 }
171
172 /* Create a random vault that looks like a collection of overlapping rooms */
173 static void build_room_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsize, POSITION ysize)
174 {
175     POSITION x1, x2, y1, y2, xhsize, yhsize;
176     int i;
177
178     /* get offset from center */
179     xhsize = xsize / 2;
180     yhsize = ysize / 2;
181
182     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("部屋型ランダムVaultを生成しました。", "Room Vault."));
183
184     /* fill area so don't get problems with on_defeat_arena_monster levels */
185     auto *floor_ptr = player_ptr->current_floor_ptr;
186     for (x1 = 0; x1 < xsize; x1++) {
187         POSITION x = x0 - xhsize + x1;
188
189         for (y1 = 0; y1 < ysize; y1++) {
190             POSITION y = y0 - yhsize + y1;
191
192             place_bold(player_ptr, y, x, GB_EXTRA);
193             floor_ptr->grid_array[y][x].info &= (~CAVE_ICKY);
194         }
195     }
196
197     /* add ten random rooms */
198     for (i = 0; i < 10; i++) {
199         x1 = randint1(xhsize) * 2 + x0 - xhsize;
200         x2 = randint1(xhsize) * 2 + x0 - xhsize;
201         y1 = randint1(yhsize) * 2 + y0 - yhsize;
202         y2 = randint1(yhsize) * 2 + y0 - yhsize;
203         build_room(player_ptr, x1, x2, y1, y2);
204     }
205
206     /* Add some random doors */
207     for (i = 0; i < 500; i++) {
208         x1 = randint1(xsize - 3) - xhsize + x0 + 1;
209         y1 = randint1(ysize - 3) - yhsize + y0 + 1;
210         add_door(player_ptr, x1, y1);
211     }
212
213     /* Fill with monsters and treasure, high difficulty */
214     fill_treasure(player_ptr, x0 - xhsize + 1, x0 - xhsize + xsize - 2, y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint1(5) + 5);
215 }
216
217 /* Create a random vault out of a fractal grid */
218 static void build_cave_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz)
219 {
220     int grd, roug, cutoff;
221     bool done, light, room;
222     POSITION xhsize, yhsize, xsize, ysize, x, y;
223
224     /* round to make sizes even */
225     xhsize = xsiz / 2;
226     yhsize = ysiz / 2;
227     xsize = xhsize * 2;
228     ysize = yhsize * 2;
229
230     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("洞穴ランダムVaultを生成しました。", "Cave Vault."));
231
232     light = done = false;
233     room = true;
234
235     auto *floor_ptr = player_ptr->current_floor_ptr;
236     while (!done) {
237         /* testing values for these parameters feel free to adjust */
238         grd = 1 << randint0(4);
239
240         /* want average of about 16 */
241         roug = randint1(8) * randint1(4);
242
243         /* about size/2 */
244         cutoff = randint1(xsize / 4) + randint1(ysize / 4) + randint1(xsize / 4) + randint1(ysize / 4);
245
246         /* make it */
247         generate_hmap(floor_ptr, y0, x0, xsize, ysize, grd, roug, cutoff);
248
249         /* Convert to normal format+ clean up */
250         done = generate_fracave(player_ptr, y0, x0, xsize, ysize, cutoff, light, room);
251     }
252
253     /* Set icky flag because is a vault */
254     for (x = 0; x <= xsize; x++) {
255         for (y = 0; y <= ysize; y++) {
256             floor_ptr->grid_array[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY;
257         }
258     }
259
260     /* Fill with monsters and treasure, low difficulty */
261     fill_treasure(player_ptr, x0 - xhsize + 1, x0 - xhsize + xsize - 1, y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5));
262 }
263
264 /*!
265  * @brief Vault地形を回転、上下左右反転するための座標変換を返す / coordinate translation code
266  * @param x 変換したい点のX座標参照ポインタ
267  * @param y 変換したい点のY座標参照ポインタ
268  * @param xoffset Vault生成時の基準X座標
269  * @param yoffset Vault生成時の基準Y座標
270  * @param transno 処理ID
271  */
272 static void coord_trans(POSITION *x, POSITION *y, POSITION xoffset, POSITION yoffset, int transno)
273 {
274     int i;
275     int temp;
276
277     /*
278      * transno specifies what transformation is required. (0-7)
279      * The lower two bits indicate by how much the vault is rotated,
280      * and the upper bit indicates a reflection.
281      * This is done by using rotation matrices... however since
282      * these are mostly zeros for rotations by 90 degrees this can
283      * be expressed simply in terms of swapping and inverting the
284      * x and y coordinates.
285      */
286     for (i = 0; i < transno % 4; i++) {
287         /* rotate by 90 degrees */
288         temp = *x;
289         *x = -(*y);
290         *y = temp;
291     }
292
293     if (transno / 4) {
294         /* Reflect depending on status of 3rd bit. */
295         *x = -(*x);
296     }
297
298     /* Add offsets so vault stays in the first quadrant */
299     *x += xoffset;
300     *y += yoffset;
301 }
302
303 /*!
304  * @brief Vaultをフロアに配置する / Hack -- fill in "vault" rooms
305  * @param player_ptr プレイヤーへの参照ポインタ
306  * @param yval 生成基準Y座標
307  * @param xval 生成基準X座標
308  * @param ymax VaultのYサイズ
309  * @param xmax VaultのXサイズ
310  * @param data Vaultのデータ文字列
311  * @param xoffset 変換基準X座標
312  * @param yoffset 変換基準Y座標
313  * @param transno 変換ID
314  */
315 static void build_vault(
316     PlayerType *player_ptr, POSITION yval, POSITION xval, POSITION ymax, POSITION xmax, concptr data, POSITION xoffset, POSITION yoffset, int transno)
317 {
318     POSITION dx, dy, x, y, i, j;
319     concptr t;
320     grid_type *g_ptr;
321
322     /* Place dungeon features and objects */
323     auto *floor_ptr = player_ptr->current_floor_ptr;
324     for (t = data, dy = 0; dy < ymax; dy++) {
325         for (dx = 0; dx < xmax; dx++, t++) {
326             /* prevent loop counter from being overwritten */
327             i = dx;
328             j = dy;
329
330             /* Flip / rotate */
331             coord_trans(&i, &j, xoffset, yoffset, transno);
332
333             if (transno % 2 == 0) {
334                 /* no swap of x/y */
335                 x = xval - (xmax / 2) + i;
336                 y = yval - (ymax / 2) + j;
337             } else {
338                 /* swap of x/y */
339                 x = xval - (ymax / 2) + i;
340                 y = yval - (xmax / 2) + j;
341             }
342
343             /* Hack -- skip "non-grids" */
344             if (*t == ' ')
345                 continue;
346             g_ptr = &floor_ptr->grid_array[y][x];
347
348             /* Lay down a floor */
349             place_grid(player_ptr, g_ptr, GB_FLOOR);
350
351             /* Remove any mimic */
352             g_ptr->mimic = 0;
353
354             /* Part of a vault */
355             g_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
356
357             /* Analyze the grid */
358             switch (*t) {
359                 /* Granite wall (outer) */
360             case '%':
361                 place_grid(player_ptr, g_ptr, GB_OUTER_NOPERM);
362                 break;
363
364                 /* Granite wall (inner) */
365             case '#':
366                 place_grid(player_ptr, g_ptr, GB_INNER);
367                 break;
368
369                 /* Glass wall (inner) */
370             case '$':
371                 place_grid(player_ptr, g_ptr, GB_INNER);
372                 g_ptr->feat = feat_glass_wall;
373                 break;
374
375                 /* Permanent wall (inner) */
376             case 'X':
377                 place_grid(player_ptr, g_ptr, GB_INNER_PERM);
378                 break;
379
380                 /* Permanent glass wall (inner) */
381             case 'Y':
382                 place_grid(player_ptr, g_ptr, GB_INNER_PERM);
383                 g_ptr->feat = feat_permanent_glass_wall;
384                 break;
385
386                 /* Treasure/trap */
387             case '*':
388                 if (randint0(100) < 75) {
389                     place_object(player_ptr, y, x, 0L);
390                 } else {
391                     place_trap(player_ptr, y, x);
392                 }
393                 break;
394
395                 /* Treasure */
396             case '[':
397                 place_object(player_ptr, y, x, 0L);
398                 break;
399
400                 /* Tree */
401             case ':':
402                 g_ptr->feat = feat_tree;
403                 break;
404
405                 /* Secret doors */
406             case '+':
407                 place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
408                 break;
409
410                 /* Secret glass doors */
411             case '-':
412                 place_secret_door(player_ptr, y, x, DOOR_GLASS_DOOR);
413                 if (is_closed_door(player_ptr, g_ptr->feat))
414                     g_ptr->mimic = feat_glass_wall;
415                 break;
416
417                 /* Curtains */
418             case '\'':
419                 place_secret_door(player_ptr, y, x, DOOR_CURTAIN);
420                 break;
421
422                 /* Trap */
423             case '^':
424                 place_trap(player_ptr, y, x);
425                 break;
426
427                 /* Black market in a dungeon */
428             case 'S':
429                 set_cave_feat(floor_ptr, y, x, feat_black_market);
430                 store_init(NO_TOWN, StoreSaleType::BLACK);
431                 break;
432
433                 /* The Pattern */
434             case 'p':
435                 set_cave_feat(floor_ptr, y, x, feat_pattern_start);
436                 break;
437
438             case 'a':
439                 set_cave_feat(floor_ptr, y, x, feat_pattern_1);
440                 break;
441
442             case 'b':
443                 set_cave_feat(floor_ptr, y, x, feat_pattern_2);
444                 break;
445
446             case 'c':
447                 set_cave_feat(floor_ptr, y, x, feat_pattern_3);
448                 break;
449
450             case 'd':
451                 set_cave_feat(floor_ptr, y, x, feat_pattern_4);
452                 break;
453
454             case 'P':
455                 set_cave_feat(floor_ptr, y, x, feat_pattern_end);
456                 break;
457
458             case 'B':
459                 set_cave_feat(floor_ptr, y, x, feat_pattern_exit);
460                 break;
461
462             case 'A':
463                 /* Reward for Pattern walk */
464                 floor_ptr->object_level = floor_ptr->base_level + 12;
465                 place_object(player_ptr, y, x, AM_GOOD | AM_GREAT);
466                 floor_ptr->object_level = floor_ptr->base_level;
467                 break;
468
469             case '~':
470                 set_cave_feat(floor_ptr, y, x, feat_shallow_water);
471                 break;
472
473             case '=':
474                 set_cave_feat(floor_ptr, y, x, feat_deep_water);
475                 break;
476
477             case 'v':
478                 set_cave_feat(floor_ptr, y, x, feat_shallow_lava);
479                 break;
480
481             case 'w':
482                 set_cave_feat(floor_ptr, y, x, feat_deep_lava);
483                 break;
484
485             case 'f':
486                 set_cave_feat(floor_ptr, y, x, feat_shallow_acid_puddle);
487                 break;
488
489             case 'F':
490                 set_cave_feat(floor_ptr, y, x, feat_deep_acid_puddle);
491                 break;
492
493             case 'g':
494                 set_cave_feat(floor_ptr, y, x, feat_shallow_poisonous_puddle);
495                 break;
496
497             case 'G':
498                 set_cave_feat(floor_ptr, y, x, feat_deep_poisonous_puddle);
499                 break;
500
501             case 'h':
502                 set_cave_feat(floor_ptr, y, x, feat_cold_zone);
503                 break;
504
505             case 'H':
506                 set_cave_feat(floor_ptr, y, x, feat_heavy_cold_zone);
507                 break;
508
509             case 'i':
510                 set_cave_feat(floor_ptr, y, x, feat_electrical_zone);
511                 break;
512
513             case 'I':
514                 set_cave_feat(floor_ptr, y, x, feat_heavy_electrical_zone);
515                 break;
516             }
517         }
518     }
519
520     /* Place dungeon monsters and objects */
521     for (t = data, dy = 0; dy < ymax; dy++) {
522         for (dx = 0; dx < xmax; dx++, t++) {
523             /* prevent loop counter from being overwritten */
524             i = dx;
525             j = dy;
526
527             /* Flip / rotate */
528             coord_trans(&i, &j, xoffset, yoffset, transno);
529
530             if (transno % 2 == 0) {
531                 /* no swap of x/y */
532                 x = xval - (xmax / 2) + i;
533                 y = yval - (ymax / 2) + j;
534             } else {
535                 /* swap of x/y */
536                 x = xval - (ymax / 2) + i;
537                 y = yval - (xmax / 2) + j;
538             }
539
540             /* Hack -- skip "non-grids" */
541             if (*t == ' ')
542                 continue;
543
544             /* Analyze the symbol */
545             switch (*t) {
546             case '&': {
547                 floor_ptr->monster_level = floor_ptr->base_level + 5;
548                 place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
549                 floor_ptr->monster_level = floor_ptr->base_level;
550                 break;
551             }
552
553             /* Meaner monster */
554             case '@': {
555                 floor_ptr->monster_level = floor_ptr->base_level + 11;
556                 place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
557                 floor_ptr->monster_level = floor_ptr->base_level;
558                 break;
559             }
560
561             /* Meaner monster, plus treasure */
562             case '9': {
563                 floor_ptr->monster_level = floor_ptr->base_level + 9;
564                 place_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
565                 floor_ptr->monster_level = floor_ptr->base_level;
566                 floor_ptr->object_level = floor_ptr->base_level + 7;
567                 place_object(player_ptr, y, x, AM_GOOD);
568                 floor_ptr->object_level = floor_ptr->base_level;
569                 break;
570             }
571
572             /* Nasty monster and treasure */
573             case '8': {
574                 floor_ptr->monster_level = floor_ptr->base_level + 40;
575                 place_monster(player_ptr, y, x, PM_ALLOW_SLEEP);
576                 floor_ptr->monster_level = floor_ptr->base_level;
577                 floor_ptr->object_level = floor_ptr->base_level + 20;
578                 place_object(player_ptr, y, x, AM_GOOD | AM_GREAT);
579                 floor_ptr->object_level = floor_ptr->base_level;
580                 break;
581             }
582
583             /* Monster and/or object */
584             case ',': {
585                 if (randint0(100) < 50) {
586                     floor_ptr->monster_level = floor_ptr->base_level + 3;
587                     place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
588                     floor_ptr->monster_level = floor_ptr->base_level;
589                 }
590                 if (randint0(100) < 50) {
591                     floor_ptr->object_level = floor_ptr->base_level + 7;
592                     place_object(player_ptr, y, x, 0L);
593                     floor_ptr->object_level = floor_ptr->base_level;
594                 }
595                 break;
596             }
597             }
598         }
599     }
600 }
601
602 /*
603  * Build target vault.
604  * This is made by two concentric "crypts" with perpendicular
605  * walls creating the cross-hairs.
606  */
607 static void build_target_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsize, POSITION ysize)
608 {
609     POSITION rad, x, y;
610
611     /* Make a random metric */
612     POSITION h1, h2, h3, h4;
613     h1 = randint1(32) - 16;
614     h2 = randint1(16);
615     h3 = randint1(32);
616     h4 = randint1(32) - 16;
617
618     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("対称形ランダムVaultを生成しました。", "Target Vault"));
619
620     /* work out outer radius */
621     if (xsize > ysize) {
622         rad = ysize / 2;
623     } else {
624         rad = xsize / 2;
625     }
626
627     /* Make floor */
628     auto *floor_ptr = player_ptr->current_floor_ptr;
629     for (x = x0 - rad; x <= x0 + rad; x++) {
630         for (y = y0 - rad; y <= y0 + rad; y++) {
631             /* clear room flag */
632             floor_ptr->grid_array[y][x].info &= ~(CAVE_ROOM);
633
634             /* Vault - so is "icky" */
635             floor_ptr->grid_array[y][x].info |= CAVE_ICKY;
636
637             if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1) {
638                 /* inside- so is floor */
639                 place_bold(player_ptr, y, x, GB_FLOOR);
640             } else {
641                 /* make granite outside so on_defeat_arena_monster works */
642                 place_bold(player_ptr, y, x, GB_EXTRA);
643             }
644
645             /* proper boundary for on_defeat_arena_monster */
646             if (((y + rad) == y0) || ((y - rad) == y0) || ((x + rad) == x0) || ((x - rad) == x0)) {
647                 place_bold(player_ptr, y, x, GB_EXTRA);
648             }
649         }
650     }
651
652     /* Find visible outer walls and set to be FEAT_OUTER */
653     add_outer_wall(player_ptr, x0, y0, false, x0 - rad - 1, y0 - rad - 1, x0 + rad + 1, y0 + rad + 1);
654
655     /* Add inner wall */
656     for (x = x0 - rad / 2; x <= x0 + rad / 2; x++) {
657         for (y = y0 - rad / 2; y <= y0 + rad / 2; y++) {
658             if (dist2(y0, x0, y, x, h1, h2, h3, h4) == rad / 2) {
659                 /* Make an internal wall */
660                 place_bold(player_ptr, y, x, GB_INNER);
661             }
662         }
663     }
664
665     /* Add perpendicular walls */
666     for (x = x0 - rad; x <= x0 + rad; x++) {
667         place_bold(player_ptr, y0, x, GB_INNER);
668     }
669
670     for (y = y0 - rad; y <= y0 + rad; y++) {
671         place_bold(player_ptr, y, x0, GB_INNER);
672     }
673
674     /* Make inner vault */
675     for (y = y0 - 1; y <= y0 + 1; y++) {
676         place_bold(player_ptr, y, x0 - 1, GB_INNER);
677         place_bold(player_ptr, y, x0 + 1, GB_INNER);
678     }
679     for (x = x0 - 1; x <= x0 + 1; x++) {
680         place_bold(player_ptr, y0 - 1, x, GB_INNER);
681         place_bold(player_ptr, y0 + 1, x, GB_INNER);
682     }
683
684     place_bold(player_ptr, y0, x0, GB_FLOOR);
685
686     /* Add doors to vault */
687     /* get two distances so can place doors relative to centre */
688     x = (rad - 2) / 4 + 1;
689     y = rad / 2 + x;
690
691     add_door(player_ptr, x0 + x, y0);
692     add_door(player_ptr, x0 + y, y0);
693     add_door(player_ptr, x0 - x, y0);
694     add_door(player_ptr, x0 - y, y0);
695     add_door(player_ptr, x0, y0 + x);
696     add_door(player_ptr, x0, y0 + y);
697     add_door(player_ptr, x0, y0 - x);
698     add_door(player_ptr, x0, y0 - y);
699
700     /* Fill with stuff - medium difficulty */
701     fill_treasure(player_ptr, x0 - rad, x0 + rad, y0 - rad, y0 + rad, randint1(3) + 3);
702 }
703
704 /*
705  * This routine uses a modified version of the lake code to make a
706  * distribution of some terrain type over the vault.  This type
707  * depends on the dungeon depth.
708  *
709  * Miniture rooms are then scattered across the vault.
710  */
711 static void build_elemental_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsiz, POSITION ysiz)
712 {
713     int grd, roug;
714     int c1, c2, c3;
715     bool done = false;
716     POSITION xsize, ysize, xhsize, yhsize, x, y;
717     int i;
718     int type;
719
720     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("精霊界ランダムVaultを生成しました。", "Elemental Vault"));
721
722     /* round to make sizes even */
723     xhsize = xsiz / 2;
724     yhsize = ysiz / 2;
725     xsize = xhsize * 2;
726     ysize = yhsize * 2;
727
728     auto *floor_ptr = player_ptr->current_floor_ptr;
729     if (floor_ptr->dun_level < 25) {
730         /* Earth vault  (Rubble) */
731         type = LAKE_T_EARTH_VAULT;
732     } else if (floor_ptr->dun_level < 50) {
733         /* Air vault (Trees) */
734         type = LAKE_T_AIR_VAULT;
735     } else if (floor_ptr->dun_level < 75) {
736         /* Water vault (shallow water) */
737         type = LAKE_T_WATER_VAULT;
738     } else {
739         /* Fire vault (shallow lava) */
740         type = LAKE_T_FIRE_VAULT;
741     }
742
743     while (!done) {
744         /* testing values for these parameters: feel free to adjust */
745         grd = 1 << (randint0(3));
746
747         /* want average of about 16 */
748         roug = randint1(8) * randint1(4);
749
750         /* Make up size of various componants */
751         /* Floor */
752         c3 = 2 * xsize / 3;
753
754         /* Deep water/lava */
755         c1 = randint0(c3 / 2) + randint0(c3 / 2) - 5;
756
757         /* Shallow boundary */
758         c2 = (c1 + c3) / 2;
759
760         /* make it */
761         generate_hmap(floor_ptr, y0, x0, xsize, ysize, grd, roug, c3);
762
763         /* Convert to normal format+ clean up */
764         done = generate_lake(player_ptr, y0, x0, xsize, ysize, c1, c2, c3, type);
765     }
766
767     /* Set icky flag because is a vault */
768     for (x = 0; x <= xsize; x++) {
769         for (y = 0; y <= ysize; y++) {
770             floor_ptr->grid_array[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY;
771         }
772     }
773
774     /* make a few rooms in the vault */
775     for (i = 1; i <= (xsize * ysize) / 50; i++) {
776         build_small_room(player_ptr, x0 + randint0(xsize - 4) - xsize / 2 + 2, y0 + randint0(ysize - 4) - ysize / 2 + 2);
777     }
778
779     /* Fill with monsters and treasure, low difficulty */
780     fill_treasure(player_ptr, x0 - xhsize + 1, x0 - xhsize + xsize - 1, y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint1(5));
781 }
782
783 /* Build a "mini" checkerboard vault
784  *
785  * This is done by making a permanent wall maze and setting
786  * the diagonal sqaures of the checker board to be granite.
787  * The vault has two entrances on opposite sides to guarantee
788  * a way to get in even if the vault abuts a side of the dungeon.
789  */
790 static void build_mini_c_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsize, POSITION ysize)
791 {
792     POSITION dy, dx;
793     POSITION y1, x1, y2, x2, y, x, total;
794     int m, n, num_vertices;
795
796     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("小型チェッカーランダムVaultを生成しました。", "Mini Checker Board Vault."));
797
798     /* Pick a random room size */
799     dy = ysize / 2 - 1;
800     dx = xsize / 2 - 1;
801
802     y1 = y0 - dy;
803     x1 = x0 - dx;
804     y2 = y0 + dy;
805     x2 = x0 + dx;
806
807     /* generate the room */
808     auto *floor_ptr = player_ptr->current_floor_ptr;
809     for (x = x1 - 2; x <= x2 + 2; x++) {
810         if (!in_bounds(floor_ptr, y1 - 2, x))
811             break;
812
813         floor_ptr->grid_array[y1 - 2][x].info |= (CAVE_ROOM | CAVE_ICKY);
814
815         place_bold(player_ptr, y1 - 2, x, GB_OUTER_NOPERM);
816     }
817
818     for (x = x1 - 2; x <= x2 + 2; x++) {
819         if (!in_bounds(floor_ptr, y2 + 2, x))
820             break;
821
822         floor_ptr->grid_array[y2 + 2][x].info |= (CAVE_ROOM | CAVE_ICKY);
823
824         place_bold(player_ptr, y2 + 2, x, GB_OUTER_NOPERM);
825     }
826
827     for (y = y1 - 2; y <= y2 + 2; y++) {
828         if (!in_bounds(floor_ptr, y, x1 - 2))
829             break;
830
831         floor_ptr->grid_array[y][x1 - 2].info |= (CAVE_ROOM | CAVE_ICKY);
832
833         place_bold(player_ptr, y, x1 - 2, GB_OUTER_NOPERM);
834     }
835
836     for (y = y1 - 2; y <= y2 + 2; y++) {
837         if (!in_bounds(floor_ptr, y, x2 + 2))
838             break;
839
840         floor_ptr->grid_array[y][x2 + 2].info |= (CAVE_ROOM | CAVE_ICKY);
841
842         place_bold(player_ptr, y, x2 + 2, GB_OUTER_NOPERM);
843     }
844
845     for (y = y1 - 1; y <= y2 + 1; y++) {
846         for (x = x1 - 1; x <= x2 + 1; x++) {
847             auto *g_ptr = &floor_ptr->grid_array[y][x];
848
849             g_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
850
851             /* Permanent walls */
852             place_grid(player_ptr, g_ptr, GB_INNER_PERM);
853         }
854     }
855
856     /* dimensions of vertex array */
857     m = dx + 1;
858     n = dy + 1;
859     num_vertices = m * n;
860
861     /* initialize array of visited vertices */
862     std::vector<int> visited(num_vertices);
863
864     /* traverse the graph to create a spannng tree, pick a random root */
865     r_visit(player_ptr, y1, x1, y2, x2, randint0(num_vertices), 0, visited.data());
866
867     /* Make it look like a checker board vault */
868     for (x = x1; x <= x2; x++) {
869         for (y = y1; y <= y2; y++) {
870             total = x - x1 + y - y1;
871             /* If total is odd- and is a floor then make a wall */
872             if ((total % 2 == 1) && floor_ptr->grid_array[y][x].is_floor()) {
873                 place_bold(player_ptr, y, x, GB_INNER);
874             }
875         }
876     }
877
878     /* Make a couple of entrances */
879     if (one_in_(2)) {
880         /* left and right */
881         y = randint1(dy) + dy / 2;
882         place_bold(player_ptr, y1 + y, x1 - 1, GB_INNER);
883         place_bold(player_ptr, y1 + y, x2 + 1, GB_INNER);
884     } else {
885         /* top and bottom */
886         x = randint1(dx) + dx / 2;
887         place_bold(player_ptr, y1 - 1, x1 + x, GB_INNER);
888         place_bold(player_ptr, y2 + 1, x1 + x, GB_INNER);
889     }
890
891     /* Fill with monsters and treasure, highest difficulty */
892     fill_treasure(player_ptr, x1, x2, y1, y2, 10);
893 }
894
895 /* Build a castle */
896 /* Driver routine: clear the region and call the recursive
897  * room routine.
898  *
899  *This makes a vault that looks like a castle/ city in the dungeon.
900  */
901 static void build_castle_vault(PlayerType *player_ptr, POSITION x0, POSITION y0, POSITION xsize, POSITION ysize)
902 {
903     POSITION dy, dx;
904     POSITION y1, x1, y2, x2;
905     POSITION y, x;
906
907     /* Pick a random room size */
908     dy = ysize / 2 - 1;
909     dx = xsize / 2 - 1;
910
911     y1 = y0 - dy;
912     x1 = x0 - dx;
913     y2 = y0 + dy;
914     x2 = x0 + dx;
915
916     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("城型ランダムVaultを生成しました。", "Castle Vault"));
917
918     /* generate the room */
919     auto *floor_ptr = player_ptr->current_floor_ptr;
920     for (y = y1 - 1; y <= y2 + 1; y++) {
921         for (x = x1 - 1; x <= x2 + 1; x++) {
922             floor_ptr->grid_array[y][x].info |= (CAVE_ROOM | CAVE_ICKY);
923             /* Make everything a floor */
924             place_bold(player_ptr, y, x, GB_FLOOR);
925         }
926     }
927
928     /* Make the castle */
929     build_recursive_room(player_ptr, x1, y1, x2, y2, randint1(5));
930
931     /* Fill with monsters and treasure, low difficulty */
932     fill_treasure(player_ptr, x1, x2, y1, y2, randint1(3));
933 }
934
935 /*!
936  * @brief タイプ10の部屋…ランダム生成vault / Type 10 -- Random vaults
937  * @param player_ptr プレイヤーへの参照ポインタ
938  */
939 bool build_type10(PlayerType *player_ptr, dun_data_type *dd_ptr)
940 {
941     POSITION y0, x0, xsize, ysize, vtype;
942
943     /* big enough to look good, small enough to be fairly common. */
944     xsize = randint1(22) + 22;
945     ysize = randint1(11) + 11;
946
947     /* Find and reserve some space in the dungeon.  Get center of room. */
948     auto *floor_ptr = player_ptr->current_floor_ptr;
949     if (!find_space(player_ptr, dd_ptr, &y0, &x0, ysize + 1, xsize + 1))
950         return false;
951
952     /* Select type of vault */
953     do {
954         vtype = randint1(15);
955     } while (d_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_CAVE) && ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11)));
956
957     switch (vtype) {
958         /* Build an appropriate room */
959     case 1:
960     case 9:
961         build_bubble_vault(player_ptr, x0, y0, xsize, ysize);
962         break;
963     case 2:
964     case 10:
965         build_room_vault(player_ptr, x0, y0, xsize, ysize);
966         break;
967     case 3:
968     case 11:
969         build_cave_vault(player_ptr, x0, y0, xsize, ysize);
970         break;
971     case 4:
972     case 12:
973         build_maze_vault(player_ptr, x0, y0, xsize, ysize, true);
974         break;
975     case 5:
976     case 13:
977         build_mini_c_vault(player_ptr, x0, y0, xsize, ysize);
978         break;
979     case 6:
980     case 14:
981         build_castle_vault(player_ptr, x0, y0, xsize, ysize);
982         break;
983     case 7:
984     case 15:
985         build_target_vault(player_ptr, x0, y0, xsize, ysize);
986         break;
987     case 8:
988         build_elemental_vault(player_ptr, x0, y0, xsize, ysize);
989         break;
990         /* I know how to add a few more... give me some time. */
991     default:
992         return false;
993     }
994
995     return true;
996 }
997
998 /*!
999  * @brief v_info.txtからの部屋生成 / vaults from "v_info.txt"
1000  */
1001 bool build_fixed_room(PlayerType *player_ptr, dun_data_type *dd_ptr, int typ, bool more_space)
1002 {
1003     vault_type *v_ptr = nullptr;
1004     int dummy;
1005     POSITION x, y;
1006     POSITION xval, yval;
1007     POSITION xoffset, yoffset;
1008     int transno;
1009
1010     ProbabilityTable<int> prob_table;
1011
1012     /* Pick fixed room */
1013     for (auto &v_ref : v_info) {
1014         if (v_ref.typ == typ) {
1015             prob_table.entry_item(v_ref.idx, 1);
1016         }
1017     }
1018
1019     std::vector<int> result;
1020     ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, 1);
1021
1022     v_ptr = &v_info[result[0]];
1023
1024     /* pick type of transformation (0-7) */
1025     transno = randint0(8);
1026
1027     /* calculate offsets */
1028     x = v_ptr->wid;
1029     y = v_ptr->hgt;
1030
1031     /* Some huge vault cannot be ratated to fit in the dungeon */
1032     auto *floor_ptr = player_ptr->current_floor_ptr;
1033     if (x + 2 > floor_ptr->height - 2) {
1034         /* Forbid 90 or 270 degree ratation */
1035         transno &= ~1;
1036     }
1037
1038     coord_trans(&x, &y, 0, 0, transno);
1039
1040     if (x < 0) {
1041         xoffset = -x - 1;
1042     } else {
1043         xoffset = 0;
1044     }
1045
1046     if (y < 0) {
1047         yoffset = -y - 1;
1048     } else {
1049         yoffset = 0;
1050     }
1051
1052     /*
1053      * Try to allocate space for room.  If fails, exit
1054      *
1055      * Hack -- Prepare a bit larger space (+2, +2) to
1056      * prevent generation of vaults with no-entrance.
1057      */
1058     int xsize = more_space ? abs(x) + 2 : abs(x);
1059     int ysize = more_space ? abs(y) + 2 : abs(y);
1060     /* Find and reserve some space in the dungeon.  Get center of room. */
1061     if (!find_space(player_ptr, dd_ptr, &yval, &xval, ysize, xsize))
1062         return false;
1063
1064     msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("固定部屋(%s)を生成しました。", "Fixed room (%s)."), v_ptr->name.c_str());
1065
1066     /* Hack -- Build the vault */
1067     build_vault(player_ptr, yval, xval, v_ptr->hgt, v_ptr->wid, v_ptr->text.c_str(), xoffset, yoffset, transno);
1068
1069     return true;
1070 }