OSDN Git Service

Merge remote-tracking branch 'remotes/hengbandosx/english-mind-edits' into feature...
[hengband/hengband.git] / src / room / rooms-city.c
1 #include "room/rooms-city.h"
2 #include "floor/floor-generator.h"
3 #include "floor/wild.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 "util/bit-flags-calculator.h"
12 #include "wizard/wizard-messages.h"
13
14 static ugbldg_type *ugbldg;
15
16 /*
17  * Precalculate buildings' location of underground arcade
18  */
19 static bool precalc_ugarcade(int town_hgt, int town_wid, int n)
20 {
21     POSITION i, y, x, center_y, center_x;
22     int tmp, attempt = 10000;
23     POSITION max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT;
24     POSITION max_bldg_wid = 5 * town_wid / MAX_TOWN_WID;
25     ugbldg_type *cur_ugbldg;
26     bool **ugarcade_used, abort;
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++)
30         ugarcade_used[y] = *ugarcade_used + y * town_wid;
31
32     for (i = 0; i < n; i++) {
33         cur_ugbldg = &ugbldg[i];
34         (void)WIPE(cur_ugbldg, ugbldg_type);
35         do {
36             center_y = rand_range(2, town_hgt - 3);
37             center_x = rand_range(2, town_wid - 3);
38             tmp = center_y - randint1(max_bldg_hgt);
39             cur_ugbldg->y0 = MAX(tmp, 1);
40             tmp = center_x - randint1(max_bldg_wid);
41             cur_ugbldg->x0 = MAX(tmp, 1);
42             tmp = center_y + randint1(max_bldg_hgt);
43             cur_ugbldg->y1 = MIN(tmp, town_hgt - 2);
44             tmp = center_x + randint1(max_bldg_wid);
45             cur_ugbldg->x1 = MIN(tmp, town_wid - 2);
46             for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) {
47                 for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) {
48                     if (ugarcade_used[y][x]) {
49                         abort = TRUE;
50                         break;
51                     }
52                 }
53             }
54
55             attempt--;
56         } while (abort && attempt);
57
58         if (!attempt)
59             break;
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     C_KILL(*ugarcade_used, town_hgt * town_wid, bool);
69     C_KILL(ugarcade_used, town_hgt, bool *);
70     return i == n;
71 }
72
73 /* Create a new floor room with optional light */
74 static void generate_room_floor(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, int light)
75 {
76     grid_type *g_ptr;
77     for (POSITION y = y1; y <= y2; y++) {
78         for (POSITION x = x1; x <= x2; x++) {
79             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
80             place_grid(player_ptr, g_ptr, GB_FLOOR);
81             g_ptr->info |= (CAVE_ROOM);
82             if (light)
83                 g_ptr->info |= (CAVE_GLOW);
84         }
85     }
86 }
87
88 static void generate_fill_perm_bold(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
89 {
90     for (POSITION y = y1; y <= y2; y++)
91         for (POSITION x = x1; x <= x2; x++)
92             place_bold(player_ptr, y, x, GB_INNER_PERM);
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         cur_ugbldg = &ugbldg[i];
115         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);
116     }
117
118     for (i = 0; i < n; i++) {
119         cur_ugbldg = &ugbldg[i];
120         generate_fill_perm_bold(player_ptr, ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0, ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1);
121
122         /* Pick a door direction (S,N,E,W) */
123         switch (randint0(4)) {
124             /* Bottom side */
125         case 0:
126             y = cur_ugbldg->y1;
127             x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
128             break;
129
130             /* Top side */
131         case 1:
132             y = cur_ugbldg->y0;
133             x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1);
134             break;
135
136             /* Right side */
137         case 2:
138             y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
139             x = cur_ugbldg->x1;
140             break;
141
142             /* Left side */
143         default:
144             y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1);
145             x = cur_ugbldg->x0;
146             break;
147         }
148
149         for (j = 0; j < max_f_idx; j++) {
150             if (has_flag(f_info[j].flags, FF_STORE)) {
151                 if (f_info[j].subtype == stores[i])
152                     break;
153             }
154         }
155
156         if (j < max_f_idx) {
157             cave_set_feat(player_ptr, ltcy + y, ltcx + x, j);
158             store_init(NO_TOWN, stores[i]);
159         }
160     }
161 }
162
163 /*!
164  * @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade
165  * @return なし
166  * @details
167  * Town logic flow for generation of new town\n
168  * Originally from Vanilla 3.0.3\n
169  *\n
170  * We start with a fully wiped grids of normal floors.\n
171  *\n
172  * Note that town_gen_hack() plays games with the R.N.G.\n
173  *\n
174  * This function does NOT do anything about the owners of the stores,\n
175  * nor the contents thereof.  It only handles the physical layout.\n
176  */
177 bool build_type16(player_type *player_ptr, dun_data_type *dd_ptr)
178 {
179     int stores[] = {
180         STORE_GENERAL,
181         STORE_ARMOURY,
182         STORE_WEAPON,
183         STORE_TEMPLE,
184         STORE_ALCHEMIST,
185         STORE_MAGIC,
186         STORE_BLACK,
187         STORE_BOOK,
188     };
189     int n = sizeof stores / sizeof(int);
190     POSITION i, y, x, y1, x1, yval, xval;
191     int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT);
192     int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID);
193     bool prevent_bm = FALSE;
194     floor_type *floor_ptr = player_ptr->current_floor_ptr;
195     for (y = 0; (y < floor_ptr->height) && !prevent_bm; y++) {
196         for (x = 0; x < floor_ptr->width; x++) {
197             if (floor_ptr->grid_array[y][x].feat == FF_STORE) {
198                 prevent_bm = (f_info[floor_ptr->grid_array[y][x].feat].subtype == STORE_BLACK);
199                 break;
200             }
201         }
202     }
203
204     for (i = 0; i < n; i++)
205         if ((stores[i] == STORE_BLACK) && prevent_bm)
206             stores[i] = stores[--n];
207
208     if (!n)
209         return FALSE;
210
211     C_MAKE(ugbldg, n, ugbldg_type);
212     if (!precalc_ugarcade(town_hgt, town_wid, n)) {
213         C_KILL(ugbldg, n, ugbldg_type);
214         return FALSE;
215     }
216
217     if (!find_space(player_ptr, dd_ptr, &yval, &xval, town_hgt + 4, town_wid + 4)) {
218         C_KILL(ugbldg, n, ugbldg_type);
219         return FALSE;
220     }
221
222     y1 = yval - (town_hgt / 2);
223     x1 = xval - (town_wid / 2);
224     generate_room_floor(player_ptr, y1 + town_hgt / 3, x1 + town_wid / 3, y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE);
225     build_stores(player_ptr, y1, x1, stores, n);
226     msg_print_wizard(player_ptr, CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated."));
227     C_KILL(ugbldg, n, ugbldg_type);
228     return TRUE;
229 }