OSDN Git Service

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