OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / room / rooms-city.cpp
1 #include "room/rooms-city.h"
2 #include "floor/floor-generator.h"
3 #include "floor/floor-town.h"
4 #include "game-option/cheat-types.h"
5 #include "grid/feature.h"
6 #include "grid/grid.h"
7 #include "room/space-finder.h"
8 #include "store/store-util.h"
9 #include "store/store.h"
10 #include "system/floor-type-definition.h"
11 #include "system/grid-type-definition.h"
12 #include "system/player-type-definition.h"
13 #include "system/terrain-type-definition.h"
14 #include "util/bit-flags-calculator.h"
15 #include "wizard/wizard-messages.h"
16 #include <algorithm>
17
18 /*
19  * Precalculate buildings' location of underground arcade
20  */
21 static bool precalc_ugarcade(int town_hgt, int town_wid, int n, std::vector<ugbldg_type> &ugbldg)
22 {
23     POSITION i, y, x, center_y, center_x;
24     int tmp, attempt = 10000;
25     auto max_buildings_height = 3 * town_hgt / MAX_TOWN_HGT;
26     auto max_buildings_width = 5 * town_wid / MAX_TOWN_WID;
27     ugbldg_type *cur_ugbldg;
28     std::vector<std::vector<bool>> ugarcade_used(town_hgt, std::vector<bool>(town_wid));
29     bool abort;
30
31     for (i = 0; i < n; i++) {
32         cur_ugbldg = &ugbldg[i];
33         *cur_ugbldg = {};
34         do {
35             center_y = rand_range(2, town_hgt - 3);
36             center_x = rand_range(2, town_wid - 3);
37             tmp = center_y - randint1(max_buildings_height);
38             cur_ugbldg->y0 = std::max(tmp, 1);
39             tmp = center_x - randint1(max_buildings_width);
40             cur_ugbldg->x0 = std::max(tmp, 1);
41             tmp = center_y + randint1(max_buildings_height);
42             cur_ugbldg->y1 = std::min(tmp, town_hgt - 2);
43             tmp = center_x + randint1(max_buildings_width);
44             cur_ugbldg->x1 = std::min(tmp, town_wid - 2);
45             for (abort = false, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) {
46                 for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) {
47                     if (ugarcade_used[y][x]) {
48                         abort = true;
49                         break;
50                     }
51                 }
52             }
53
54             attempt--;
55         } while (abort && attempt);
56
57         if (!attempt) {
58             break;
59         }
60
61         for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++) {
62             for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++) {
63                 ugarcade_used[y][x] = true;
64             }
65         }
66     }
67
68     return i == n;
69 }
70
71 /* Create a new floor room with optional light */
72 static void generate_room_floor(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, int light)
73 {
74     grid_type *g_ptr;
75     for (POSITION y = y1; y <= y2; y++) {
76         for (POSITION x = x1; x <= x2; x++) {
77             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
78             place_grid(player_ptr, g_ptr, GB_FLOOR);
79             g_ptr->info |= (CAVE_ROOM);
80             if (light) {
81                 g_ptr->info |= (CAVE_GLOW);
82             }
83         }
84     }
85 }
86
87 static void generate_fill_perm_bold(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
88 {
89     for (POSITION y = y1; y <= y2; y++) {
90         for (POSITION x = x1; x <= x2; x++) {
91             place_bold(player_ptr, y, x, GB_INNER_PERM);
92         }
93     }
94 }
95
96 /*!
97  * @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings
98  * @param player_ptr プレイヤーへの参照ポインタ
99  * @param ltcy 生成基準Y座標
100  * @param ltcx 生成基準X座標
101  * @param stotes[] 生成する店舗のリスト
102  * @param n 生成する店舗の数
103  * @note
104  * Note: ltcy and ltcx indicate "left top corner".
105  */
106 static void build_stores(PlayerType *player_ptr, POSITION ltcy, POSITION ltcx, StoreSaleType stores[], int n, const std::vector<ugbldg_type> &ugbldg)
107 {
108     int i;
109     POSITION y, x;
110     const ugbldg_type *cur_ugbldg;
111
112     for (i = 0; i < n; i++) {
113         cur_ugbldg = &ugbldg[i];
114         generate_room_floor(player_ptr, ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2, ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2, false);
115     }
116
117     for (i = 0; i < n; i++) {
118         cur_ugbldg = &ugbldg[i];
119         generate_fill_perm_bold(player_ptr, ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0, ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1);
120
121         /* Pick a door direction (S,N,E,W) */
122         switch (randint0(4)) {
123             /* Bottom side */
124         case 0:
125             y = cur_ugbldg->y1;
126             x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
127             break;
128
129             /* Top side */
130         case 1:
131             y = cur_ugbldg->y0;
132             x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
133             break;
134
135             /* Right side */
136         case 2:
137             y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
138             x = cur_ugbldg->x1;
139             break;
140
141             /* Left side */
142         default:
143             y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
144             x = cur_ugbldg->x0;
145             break;
146         }
147
148         if (auto it = std::find_if(terrains_info.begin(), terrains_info.end(),
149                 [subtype = stores[i]](const TerrainType &f_ref) {
150                     return f_ref.flags.has(TerrainCharacteristics::STORE) && (i2enum<StoreSaleType>(static_cast<int>(f_ref.subtype)) == subtype);
151                 });
152             it != terrains_info.end()) {
153             cave_set_feat(player_ptr, ltcy + y, ltcx + x, (*it).idx);
154             store_init(VALID_TOWNS, stores[i]);
155         }
156     }
157 }
158
159 /*!
160  * @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade
161  * @details
162  * Town logic flow for generation of new town\n
163  * Originally from Vanilla 3.0.3\n
164  *\n
165  * We start with a fully wiped grids of normal floors.\n
166  *\n
167  * Note that town_gen_hack() plays games with the R.N.G.\n
168  *\n
169  * This function does NOT do anything about the owners of the stores,\n
170  * nor the contents thereof.  It only handles the physical layout.\n
171  */
172 bool build_type16(PlayerType *player_ptr, dun_data_type *dd_ptr)
173 {
174     StoreSaleType stores[] = {
175         StoreSaleType::GENERAL,
176         StoreSaleType::ARMOURY,
177         StoreSaleType::WEAPON,
178         StoreSaleType::TEMPLE,
179         StoreSaleType::ALCHEMIST,
180         StoreSaleType::MAGIC,
181         StoreSaleType::BLACK,
182         StoreSaleType::BOOK,
183     };
184     int n = sizeof stores / sizeof(int);
185     POSITION y1, x1, yval, xval;
186     int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT);
187     int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID);
188
189     if (!n) {
190         return false;
191     }
192
193     std::vector<ugbldg_type> ugbldg(n);
194     if (!precalc_ugarcade(town_hgt, town_wid, n, ugbldg)) {
195         return false;
196     }
197
198     if (!find_space(player_ptr, dd_ptr, &yval, &xval, town_hgt + 4, town_wid + 4)) {
199         return false;
200     }
201
202     y1 = yval - (town_hgt / 2);
203     x1 = xval - (town_wid / 2);
204     generate_room_floor(player_ptr, y1 + town_hgt / 3, x1 + town_wid / 3, y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, false);
205     build_stores(player_ptr, y1, x1, stores, n, ugbldg);
206     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated."));
207     return true;
208 }