OSDN Git Service

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