OSDN Git Service

Changed the last sentence in the English description for the Platinum Yendorian expre...
[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 * @param player_ptr プレーヤーへの参照ポインタ
98 * @return なし
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(player_type *player_ptr, POSITION ltcy, POSITION ltcx, int stores[], int n)
107 {
108         int i;
109         POSITION y, x;
110         FEAT_IDX j;
111         ugbldg_type *cur_ugbldg;
112
113         for (i = 0; i < n; i++)
114         {
115                 cur_ugbldg = &ugbldg[i];
116
117                 /* Generate new room */
118                 generate_room_floor(player_ptr,
119                         ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2,
120                         ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2,
121                         FALSE);
122         }
123
124         for (i = 0; i < n; i++)
125         {
126                 cur_ugbldg = &ugbldg[i];
127
128                 /* Build an invulnerable rectangular building */
129                 generate_fill_perm_bold(player_ptr, 
130                         ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0,
131                         ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1);
132
133                 /* Pick a door direction (S,N,E,W) */
134                 switch (randint0(4))
135                 {
136                         /* Bottom side */
137                 case 0:
138                         y = cur_ugbldg->y1;
139                         x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
140                         break;
141
142                         /* Top side */
143                 case 1:
144                         y = cur_ugbldg->y0;
145                         x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
146                         break;
147
148                         /* Right side */
149                 case 2:
150                         y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
151                         x = cur_ugbldg->x1;
152                         break;
153
154                         /* Left side */
155                 default:
156                         y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
157                         x = cur_ugbldg->x0;
158                         break;
159                 }
160
161                 for (j = 0; j < max_f_idx; j++)
162                 {
163                         if (have_flag(f_info[j].flags, FF_STORE))
164                         {
165                                 if (f_info[j].subtype == stores[i]) break;
166                         }
167                 }
168
169                 /* Clear previous contents, add a store door */
170                 if (j < max_f_idx)
171                 {
172                         cave_set_feat(player_ptr, ltcy + y, ltcx + x, j);
173
174                         /* Init store */
175                         store_init(NO_TOWN, stores[i]);
176                 }
177         }
178 }
179
180
181 /*!
182 * @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade
183 * @return なし
184 * @details
185 * Town logic flow for generation of new town\n
186 * Originally from Vanilla 3.0.3\n
187 *\n
188 * We start with a fully wiped grids of normal floors.\n
189 *\n
190 * Note that town_gen_hack() plays games with the R.N.G.\n
191 *\n
192 * This function does NOT do anything about the owners of the stores,\n
193 * nor the contents thereof.  It only handles the physical layout.\n
194 */
195 bool build_type16(player_type *player_ptr)
196 {
197         int stores[] =
198         {
199                 STORE_GENERAL, STORE_ARMOURY, STORE_WEAPON, STORE_TEMPLE,
200                 STORE_ALCHEMIST, STORE_MAGIC, STORE_BLACK, STORE_BOOK,
201         };
202         int n = sizeof stores / sizeof(int);
203         POSITION i, y, x, y1, x1, yval, xval;
204         int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT);
205         int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID);
206         bool prevent_bm = FALSE;
207
208         /* Hack -- If already exist black market, prevent building */
209         floor_type *floor_ptr = player_ptr->current_floor_ptr;
210         for (y = 0; (y < floor_ptr->height) && !prevent_bm; y++)
211         {
212                 for (x = 0; x < floor_ptr->width; x++)
213                 {
214                         if (floor_ptr->grid_array[y][x].feat == FF_STORE)
215                         {
216                                 prevent_bm = (f_info[floor_ptr->grid_array[y][x].feat].subtype == STORE_BLACK);
217                                 break;
218                         }
219                 }
220         }
221         for (i = 0; i < n; i++)
222         {
223                 if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n];
224         }
225         if (!n) return FALSE;
226
227         /* Allocate buildings array */
228         C_MAKE(ugbldg, n, ugbldg_type);
229
230         /* If cannot build stores, abort */
231         if (!precalc_ugarcade(town_hgt, town_wid, n))
232         {
233                 /* Free buildings array */
234                 C_KILL(ugbldg, n, ugbldg_type);
235                 return FALSE;
236         }
237
238         /* Find and reserve some space in the dungeon.  Get center of room. */
239         if (!find_space(player_ptr, &yval, &xval, town_hgt + 4, town_wid + 4))
240         {
241                 /* Free buildings array */
242                 C_KILL(ugbldg, n, ugbldg_type);
243                 return FALSE;
244         }
245
246         /* Get top left corner */
247         y1 = yval - (town_hgt / 2);
248         x1 = xval - (town_wid / 2);
249
250         /* Generate new room */
251         generate_room_floor(player_ptr,
252                 y1 + town_hgt / 3, x1 + town_wid / 3,
253                 y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE);
254
255         /* Build stores */
256         build_stores(player_ptr, y1, x1, stores, n);
257
258         msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated."));
259
260         /* Free buildings array */
261         C_KILL(ugbldg, n, ugbldg_type);
262
263         return TRUE;
264 }