OSDN Git Service

ef178a214a745df2ca0a29a2c099582ca4c36767
[hengband/hengband.git] / src / room / room-generator.c
1 #include "room/room-generator.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "floor/floor-generate.h" // 相互依存、後で消す.
5 #include "game-option/birth-options.h"
6 #include "game-option/cheat-types.h"
7 #include "grid/grid.h"
8 #include "room/room-info-table.h"
9 #include "room/room-types.h"
10 #include "room/rooms-city.h" // 相互依存、後で消す.
11 #include "room/rooms-fractal.h"
12 #include "room/rooms-normal.h"
13 #include "room/rooms-pit-nest.h"
14 #include "room/rooms-special.h"
15 #include "room/rooms-trap.h"
16 #include "room/rooms-vault.h"
17 #include "room/rooms.h"
18 #include "system/floor-type-definition.h"
19 #include "wizard/wizard-messages.h"
20
21 /* Create a new floor room with optional light */
22 void generate_room_floor(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, int light)
23 {
24     grid_type *g_ptr;
25     for (POSITION y = y1; y <= y2; y++) {
26         for (POSITION x = x1; x <= x2; x++) {
27             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
28             place_grid(player_ptr, g_ptr, GB_FLOOR);
29             g_ptr->info |= (CAVE_ROOM);
30             if (light)
31                 g_ptr->info |= (CAVE_GLOW);
32         }
33     }
34 }
35
36 void generate_fill_perm_bold(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
37 {
38     for (POSITION y = y1; y <= y2; y++)
39         for (POSITION x = x1; x <= x2; x++)
40             place_bold(player_ptr, y, x, GB_INNER_PERM);
41 }
42
43 /*!
44  * @brief 与えられた部屋型IDに応じて部屋の生成処理分岐を行い結果を返す / Attempt to build a room of the given type at the given block
45  * @param player_ptr プレーヤーへの参照ポインタ
46  * @param type 部屋型ID
47  * @note that we restrict the number of "crowded" rooms to reduce the chance of overflowing the monster list during level creation.
48  * @return 部屋の生成に成功した場合 TRUE を返す。
49  */
50 static bool room_build(player_type *player_ptr, EFFECT_ID typ)
51 {
52     switch (typ) {
53     case ROOM_T_NORMAL:
54         return build_type1(player_ptr);
55     case ROOM_T_OVERLAP:
56         return build_type2(player_ptr);
57     case ROOM_T_CROSS:
58         return build_type3(player_ptr);
59     case ROOM_T_INNER_FEAT:
60         return build_type4(player_ptr);
61     case ROOM_T_NEST:
62         return build_type5(player_ptr);
63     case ROOM_T_PIT:
64         return build_type6(player_ptr);
65     case ROOM_T_LESSER_VAULT:
66         return build_type7(player_ptr);
67     case ROOM_T_GREATER_VAULT:
68         return build_type8(player_ptr);
69     case ROOM_T_FRACAVE:
70         return build_type9(player_ptr);
71     case ROOM_T_RANDOM_VAULT:
72         return build_type10(player_ptr);
73     case ROOM_T_OVAL:
74         return build_type11(player_ptr);
75     case ROOM_T_CRYPT:
76         return build_type12(player_ptr);
77     case ROOM_T_TRAP_PIT:
78         return build_type13(player_ptr);
79     case ROOM_T_TRAP:
80         return build_type14(player_ptr);
81     case ROOM_T_GLASS:
82         return build_type15(player_ptr);
83     case ROOM_T_ARCADE:
84         return build_type16(player_ptr);
85     case ROOM_T_FIXED:
86         return build_type17(player_ptr);
87     default:
88         return FALSE;
89     }
90 }
91
92 /*!
93  * @brief 指定した部屋の生成確率を別の部屋に加算し、指定した部屋の生成率を0にする
94  * @param dst 確率を移す先の部屋種ID
95  * @param src 確率を与える元の部屋種ID
96  */
97 static void move_prob_list(room_type dst, room_type src, int *prob_list)
98 {
99     prob_list[dst] += prob_list[src];
100     prob_list[src] = 0;
101 }
102
103 /*!
104  * @brief 部屋生成処理のメインルーチン(Sangbandを経由してOangbandからの実装を引用) / Generate rooms in dungeon.  Build bigger rooms at first. [from SAngband
105  * (originally from OAngband)]
106  * @param player_ptr プレーヤーへの参照ポインタ
107  * @return 部屋生成に成功した場合 TRUE を返す。
108  */
109 bool generate_rooms(player_type *player_ptr)
110 {
111     floor_type *floor_ptr = player_ptr->current_floor_ptr;
112     int crowded = 0;
113     int prob_list[ROOM_T_MAX];
114     int rooms_built = 0;
115     int area_size = 100 * (floor_ptr->height * floor_ptr->width) / (MAX_HGT * MAX_WID);
116     int level_index = MIN(10, div_round(floor_ptr->dun_level, 10));
117     s16b room_num[ROOM_T_MAX];
118     int dun_rooms = DUN_ROOMS_MAX * area_size / 100;
119     room_info_type *room_info_ptr = room_info_normal;
120     for (int i = 0; i < ROOM_T_MAX; i++) {
121         if (floor_ptr->dun_level < room_info_ptr[i].min_level)
122             prob_list[i] = 0;
123         else
124             prob_list[i] = room_info_ptr[i].prob[level_index];
125     }
126
127     /*!
128      * @details ダンジョンにBEGINNER、CHAMELEON、SMALLESTいずれのフラグもなく、
129      * かつ「常に通常でない部屋を生成する」フラグがONならば、
130      * GRATER_VAULTのみを生成対象とする。 / Ironman sees only Greater Vaults
131      */
132     if (ironman_rooms && !((d_info[floor_ptr->dungeon_idx].flags1 & (DF1_BEGINNER | DF1_CHAMELEON | DF1_SMALLEST)))) {
133         for (int i = 0; i < ROOM_T_MAX; i++) {
134             if (i == ROOM_T_GREATER_VAULT)
135                 prob_list[i] = 1;
136             else
137                 prob_list[i] = 0;
138         }
139     } else if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_VAULT) {
140         /*! @details ダンジョンにNO_VAULTフラグがあるならば、LESSER_VAULT / GREATER_VAULT/ RANDOM_VAULTを除外 / Forbidden vaults */
141         prob_list[ROOM_T_LESSER_VAULT] = 0;
142         prob_list[ROOM_T_GREATER_VAULT] = 0;
143         prob_list[ROOM_T_RANDOM_VAULT] = 0;
144     }
145
146     /*! @details ダンジョンにBEGINNERフラグがあるならば、FIXED_ROOMを除外 / Forbidden vaults */
147     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_BEGINNER)
148         prob_list[ROOM_T_FIXED] = 0;
149
150     /*! @details ダンジョンにNO_CAVEフラグがある場合、FRACAVEの生成枠がNORMALに与えられる。CRIPT、OVALの生成枠がINNER_Fに与えられる。/ NO_CAVE dungeon */
151     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) {
152         move_prob_list(ROOM_T_NORMAL, ROOM_T_FRACAVE, prob_list);
153         move_prob_list(ROOM_T_INNER_FEAT, ROOM_T_CRYPT, prob_list);
154         move_prob_list(ROOM_T_INNER_FEAT, ROOM_T_OVAL, prob_list);
155     } else if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_CAVE) {
156         /*! @details ダンジョンにCAVEフラグがある場合、NORMALの生成枠がFRACAVEに与えられる。/ CAVE dungeon (Orc floor_ptr->grid_array etc.) */
157         move_prob_list(ROOM_T_FRACAVE, ROOM_T_NORMAL, prob_list);
158     } else if (dun->cavern || dun->empty_level) {
159         /*! @details ダンジョンの基本地形が最初から渓谷かアリーナ型の場合 FRACAVE は生成から除外。 /  No caves when a (random) cavern exists: they look bad */
160         prob_list[ROOM_T_FRACAVE] = 0;
161     }
162
163     /*! @details ダンジョンに最初からGLASS_ROOMフラグがある場合、GLASS を生成から除外。/ Forbidden glass rooms */
164     if (!(d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_ROOM))
165         prob_list[ROOM_T_GLASS] = 0;
166
167     /*! @details ARCADEは同フラグがダンジョンにないと生成されない。 / Forbidden glass rooms */
168     if (!(d_info[floor_ptr->dungeon_idx].flags1 & DF1_ARCADE))
169         prob_list[ROOM_T_ARCADE] = 0;
170
171     int total_prob = 0;
172     for (int i = 0; i < ROOM_T_MAX; i++) {
173         room_num[i] = 0;
174         total_prob += prob_list[i];
175     }
176
177     for (int i = dun_rooms; i > 0; i--) {
178         int room_type;
179         int rand = randint0(total_prob);
180         for (room_type = 0; room_type < ROOM_T_MAX; room_type++) {
181             if (rand < prob_list[room_type])
182                 break;
183             else
184                 rand -= prob_list[room_type];
185         }
186
187         if (room_type >= ROOM_T_MAX)
188             room_type = ROOM_T_NORMAL;
189
190         room_num[room_type]++;
191         switch (room_type) {
192         case ROOM_T_NEST:
193         case ROOM_T_PIT:
194         case ROOM_T_LESSER_VAULT:
195         case ROOM_T_TRAP_PIT:
196         case ROOM_T_GLASS:
197         case ROOM_T_ARCADE:
198             /* Large room */
199             i -= 2;
200             break;
201         case ROOM_T_GREATER_VAULT:
202         case ROOM_T_RANDOM_VAULT:
203             /* Largest room */
204             i -= 3;
205             break;
206         }
207     }
208
209     bool remain;
210     while (TRUE) {
211         remain = FALSE;
212         for (int i = 0; i < ROOM_T_MAX; i++) {
213             int room_type = room_build_order[i];
214             if (!room_num[room_type])
215                 continue;
216
217             room_num[room_type]--;
218             if (!room_build(player_ptr, room_type))
219                 continue;
220
221             rooms_built++;
222             remain = TRUE;
223             switch (room_type) {
224             case ROOM_T_PIT:
225             case ROOM_T_NEST:
226             case ROOM_T_TRAP_PIT:
227                 if (++crowded >= 2) {
228                     room_num[ROOM_T_PIT] = 0;
229                     room_num[ROOM_T_NEST] = 0;
230                     room_num[ROOM_T_TRAP_PIT] = 0;
231                 }
232
233                 break;
234             case ROOM_T_ARCADE:
235                 room_num[ROOM_T_ARCADE] = 0;
236                 break;
237             }
238         }
239
240         if (!remain)
241             break;
242     }
243
244     /*! @details 部屋生成数が2未満の場合生成失敗を返す */
245     if (rooms_built < 2) {
246         msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("部屋数が2未満でした。生成を再試行します。", "Number of rooms was under 2. Retry."), rooms_built);
247         return FALSE;
248     }
249
250     msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("このダンジョンの部屋数は %d です。", "Number of Rooms: %d"), rooms_built);
251     return TRUE;
252 }