OSDN Git Service

[Refactor] #38997 generate_room_floor() に floor_type * 引数を追加. / Add floor_type *...
[hengband/hengband.git] / src / rooms-city.c
1 #include "angband.h"
2 #include "util.h"
3
4 #include "grid.h"
5 #include "floor.h"
6 #include "floor-generate.h"
7 #include "rooms.h"
8 #include "rooms-city.h"
9 #include "store.h"
10 #include "wild.h"
11
12
13
14 /*
15 * Precalculate buildings' location of underground arcade
16 */
17 static bool precalc_ugarcade(int town_hgt, int town_wid, int n)
18 {
19         POSITION i, y, x, center_y, center_x;
20         int tmp, attempt = 10000;
21         POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT;
22         POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID;
23         ugbldg_type *cur_ugbldg;
24         bool **ugarcade_used, abort;
25
26         /* Allocate "ugarcade_used" array (2-dimension) */
27         C_MAKE(ugarcade_used, town_hgt, bool *);
28         C_MAKE(*ugarcade_used, town_hgt * town_wid, bool);
29         for (y = 1; y < town_hgt; y++) ugarcade_used[y] = *ugarcade_used + y * town_wid;
30
31         /* Calculate building locations */
32         for (i = 0; i < n; i++)
33         {
34                 cur_ugbldg = &ugbldg[i];
35                 (void)WIPE(cur_ugbldg, ugbldg_type);
36
37                 do
38                 {
39                         /* Find the "center" of the store */
40                         center_y = rand_range(2, town_hgt - 3);
41                         center_x = rand_range(2, town_wid - 3);
42
43                         /* Determine the store boundaries */
44                         tmp = center_y - randint1(max_bldg_hgt);
45                         cur_ugbldg->y0 = MAX(tmp, 1);
46                         tmp = center_x - randint1(max_bldg_wid);
47                         cur_ugbldg->x0 = MAX(tmp, 1);
48                         tmp = center_y + randint1(max_bldg_hgt);
49                         cur_ugbldg->y1 = MIN(tmp, town_hgt - 2);
50                         tmp = center_x + randint1(max_bldg_wid);
51                         cur_ugbldg->x1 = MIN(tmp, town_wid - 2);
52
53                         /* Scan this building's area */
54                         for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++)
55                         {
56                                 for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++)
57                                 {
58                                         if (ugarcade_used[y][x])
59                                         {
60                                                 abort = TRUE;
61                                                 break;
62                                         }
63                                 }
64                         }
65
66                         attempt--;
67                 } while (abort && attempt); /* Accept this building if no overlapping */
68
69                                                                         /* Failed to generate underground arcade */
70                 if (!attempt) break;
71
72                 /*
73                 * Mark to ugarcade_used[][] as "used"
74                 * Note: Building-adjacent grids are included for preventing
75                 * connected bulidings.
76                 */
77                 for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++)
78                 {
79                         for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++)
80                         {
81                                 ugarcade_used[y][x] = TRUE;
82                         }
83                 }
84         }
85
86         /* Free "ugarcade_used" array (2-dimension) */
87         C_KILL(*ugarcade_used, town_hgt * town_wid, bool);
88         C_KILL(ugarcade_used, town_hgt, bool *);
89
90         /* If i < n, generation is not allowed */
91         return i == n;
92 }
93
94
95 /*!
96 * @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings
97 * @return なし
98 * @param ltcy 生成基準Y座標
99 * @param ltcx 生成基準X座標
100 * @param stotes[] 生成する店舗のリスト
101 * @param n 生成する店舗の数
102 * @note
103 * Note: ltcy and ltcx indicate "left top corner".
104 */
105 static void build_stores(POSITION ltcy, POSITION ltcx, int stores[], int n)
106 {
107         int i;
108         POSITION y, x;
109         FEAT_IDX j;
110         ugbldg_type *cur_ugbldg;
111
112         for (i = 0; i < n; i++)
113         {
114                 cur_ugbldg = &ugbldg[i];
115
116                 /* Generate new room */
117                 generate_room_floor(p_ptr->current_floor_ptr, 
118                         ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2,
119                         ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2,
120                         FALSE);
121         }
122
123         for (i = 0; i < n; i++)
124         {
125                 cur_ugbldg = &ugbldg[i];
126
127                 /* Build an invulnerable rectangular building */
128                 generate_fill_perm_bold(
129                         ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0,
130                         ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1);
131
132                 /* Pick a door direction (S,N,E,W) */
133                 switch (randint0(4))
134                 {
135                         /* Bottom side */
136                 case 0:
137                         y = cur_ugbldg->y1;
138                         x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
139                         break;
140
141                         /* Top side */
142                 case 1:
143                         y = cur_ugbldg->y0;
144                         x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
145                         break;
146
147                         /* Right side */
148                 case 2:
149                         y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
150                         x = cur_ugbldg->x1;
151                         break;
152
153                         /* Left side */
154                 default:
155                         y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
156                         x = cur_ugbldg->x0;
157                         break;
158                 }
159
160                 for (j = 0; j < max_f_idx; j++)
161                 {
162                         if (have_flag(f_info[j].flags, FF_STORE))
163                         {
164                                 if (f_info[j].subtype == stores[i]) break;
165                         }
166                 }
167
168                 /* Clear previous contents, add a store door */
169                 if (j < max_f_idx)
170                 {
171                         cave_set_feat(p_ptr->current_floor_ptr, ltcy + y, ltcx + x, j);
172
173                         /* Init store */
174                         store_init(NO_TOWN, stores[i]);
175                 }
176         }
177 }
178
179
180 /*!
181 * @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade
182 * @return なし
183 * @details
184 * Town logic flow for generation of new town\n
185 * Originally from Vanilla 3.0.3\n
186 *\n
187 * We start with a fully wiped p_ptr->current_floor_ptr->grid_array of normal floors.\n
188 *\n
189 * Note that town_gen_hack() plays games with the R.N.G.\n
190 *\n
191 * This function does NOT do anything about the owners of the stores,\n
192 * nor the contents thereof.  It only handles the physical layout.\n
193 */
194 bool build_type16(floor_type *floor_ptr)
195 {
196         int stores[] =
197         {
198                 STORE_GENERAL, STORE_ARMOURY, STORE_WEAPON, STORE_TEMPLE,
199                 STORE_ALCHEMIST, STORE_MAGIC, STORE_BLACK, STORE_BOOK,
200         };
201         int n = sizeof stores / sizeof(int);
202         POSITION i, y, x, y1, x1, yval, xval;
203         int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT);
204         int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID);
205         bool prevent_bm = FALSE;
206
207         /* Hack -- If already exist black market, prevent building */
208         for (y = 0; (y < floor_ptr->height) && !prevent_bm; y++)
209         {
210                 for (x = 0; x < floor_ptr->width; x++)
211                 {
212                         if (floor_ptr->grid_array[y][x].feat == FF_STORE)
213                         {
214                                 prevent_bm = (f_info[floor_ptr->grid_array[y][x].feat].subtype == STORE_BLACK);
215                                 break;
216                         }
217                 }
218         }
219         for (i = 0; i < n; i++)
220         {
221                 if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n];
222         }
223         if (!n) return FALSE;
224
225         /* Allocate buildings array */
226         C_MAKE(ugbldg, n, ugbldg_type);
227
228         /* If cannot build stores, abort */
229         if (!precalc_ugarcade(town_hgt, town_wid, n))
230         {
231                 /* Free buildings array */
232                 C_KILL(ugbldg, n, ugbldg_type);
233                 return FALSE;
234         }
235
236         /* Find and reserve some space in the dungeon.  Get center of room. */
237         if (!find_space(&yval, &xval, town_hgt + 4, town_wid + 4))
238         {
239                 /* Free buildings array */
240                 C_KILL(ugbldg, n, ugbldg_type);
241                 return FALSE;
242         }
243
244         /* Get top left corner */
245         y1 = yval - (town_hgt / 2);
246         x1 = xval - (town_wid / 2);
247
248         /* Generate new room */
249         generate_room_floor(floor_ptr,
250                 y1 + town_hgt / 3, x1 + town_wid / 3,
251                 y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE);
252
253         /* Build stores */
254         build_stores(y1, x1, stores, n);
255
256         msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated."));
257
258         /* Free buildings array */
259         C_KILL(ugbldg, n, ugbldg_type);
260
261         return TRUE;
262 }
263