OSDN Git Service

[Refactor] #38862 Moved object*.c/h to object/
[hengband/hengband.git] / src / rooms-city.c
1 #include "angband.h"
2 #include "util.h"
3
4 #include "grid.h"
5 #include "floor/floor.h"
6 #include "floor/floor-generate.h"
7 #include "rooms.h"
8 #include "rooms-city.h"
9 #include "market/store.h"
10 #include "wild.h"
11 #include "market/store-util.h"
12
13 /*
14 * Precalculate buildings' location of underground arcade
15 */
16 static bool precalc_ugarcade(int town_hgt, int town_wid, int n)
17 {
18         POSITION i, y, x, center_y, center_x;
19         int tmp, attempt = 10000;
20         POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT;
21         POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID;
22         ugbldg_type *cur_ugbldg;
23         bool **ugarcade_used, abort;
24
25         /* Allocate "ugarcade_used" array (2-dimension) */
26         C_MAKE(ugarcade_used, town_hgt, bool *);
27         C_MAKE(*ugarcade_used, town_hgt * town_wid, bool);
28         for (y = 1; y < town_hgt; y++) ugarcade_used[y] = *ugarcade_used + y * town_wid;
29
30         /* Calculate building locations */
31         for (i = 0; i < n; i++)
32         {
33                 cur_ugbldg = &ugbldg[i];
34                 (void)WIPE(cur_ugbldg, ugbldg_type);
35
36                 do
37                 {
38                         /* Find the "center" of the store */
39                         center_y = rand_range(2, town_hgt - 3);
40                         center_x = rand_range(2, town_wid - 3);
41
42                         /* Determine the store boundaries */
43                         tmp = center_y - randint1(max_bldg_hgt);
44                         cur_ugbldg->y0 = MAX(tmp, 1);
45                         tmp = center_x - randint1(max_bldg_wid);
46                         cur_ugbldg->x0 = MAX(tmp, 1);
47                         tmp = center_y + randint1(max_bldg_hgt);
48                         cur_ugbldg->y1 = MIN(tmp, town_hgt - 2);
49                         tmp = center_x + randint1(max_bldg_wid);
50                         cur_ugbldg->x1 = MIN(tmp, town_wid - 2);
51
52                         /* Scan this building's area */
53                         for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++)
54                         {
55                                 for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++)
56                                 {
57                                         if (ugarcade_used[y][x])
58                                         {
59                                                 abort = TRUE;
60                                                 break;
61                                         }
62                                 }
63                         }
64
65                         attempt--;
66                 } while (abort && attempt); /* Accept this building if no overlapping */
67
68                                                                         /* Failed to generate underground arcade */
69                 if (!attempt) break;
70
71                 /*
72                 * Mark to ugarcade_used[][] as "used"
73                 * Note: Building-adjacent grids are included for preventing
74                 * connected bulidings.
75                 */
76                 for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++)
77                 {
78                         for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++)
79                         {
80                                 ugarcade_used[y][x] = TRUE;
81                         }
82                 }
83         }
84
85         /* Free "ugarcade_used" array (2-dimension) */
86         C_KILL(*ugarcade_used, town_hgt * town_wid, bool);
87         C_KILL(ugarcade_used, town_hgt, bool *);
88
89         /* If i < n, generation is not allowed */
90         return i == n;
91 }
92
93
94 /*!
95 * @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings
96 * @param player_ptr プレーヤーへの参照ポインタ
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(player_type *player_ptr, 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(player_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(player_ptr, 
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(player_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 grids 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(player_type *player_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         floor_type *floor_ptr = player_ptr->current_floor_ptr;
209         for (y = 0; (y < floor_ptr->height) && !prevent_bm; y++)
210         {
211                 for (x = 0; x < floor_ptr->width; x++)
212                 {
213                         if (floor_ptr->grid_array[y][x].feat == FF_STORE)
214                         {
215                                 prevent_bm = (f_info[floor_ptr->grid_array[y][x].feat].subtype == STORE_BLACK);
216                                 break;
217                         }
218                 }
219         }
220         for (i = 0; i < n; i++)
221         {
222                 if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n];
223         }
224         if (!n) return FALSE;
225
226         /* Allocate buildings array */
227         C_MAKE(ugbldg, n, ugbldg_type);
228
229         /* If cannot build stores, abort */
230         if (!precalc_ugarcade(town_hgt, town_wid, n))
231         {
232                 /* Free buildings array */
233                 C_KILL(ugbldg, n, ugbldg_type);
234                 return FALSE;
235         }
236
237         /* Find and reserve some space in the dungeon.  Get center of room. */
238         if (!find_space(player_ptr, &yval, &xval, town_hgt + 4, town_wid + 4))
239         {
240                 /* Free buildings array */
241                 C_KILL(ugbldg, n, ugbldg_type);
242                 return FALSE;
243         }
244
245         /* Get top left corner */
246         y1 = yval - (town_hgt / 2);
247         x1 = xval - (town_wid / 2);
248
249         /* Generate new room */
250         generate_room_floor(player_ptr,
251                 y1 + town_hgt / 3, x1 + town_wid / 3,
252                 y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE);
253
254         /* Build stores */
255         build_stores(player_ptr, y1, x1, stores, n);
256
257         msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated."));
258
259         /* Free buildings array */
260         C_KILL(ugbldg, n, ugbldg_type);
261
262         return TRUE;
263 }