OSDN Git Service

Merge pull request #857 from sikabane-works/feature/fix-doxygen-syntax
[hengbandforosx/hengbandosx.git] / src / room / rooms-pit-nest.cpp
1 #include "room/rooms-pit-nest.h"
2 #include "dungeon/dungeon.h"
3 #include "floor/floor-generator.h"
4 #include "game-option/cheat-options.h"
5 #include "game-option/cheat-types.h"
6 #include "grid/door.h"
7 #include "grid/feature.h"
8 #include "grid/grid.h"
9 #include "monster-floor/monster-generator.h"
10 #include "monster-floor/place-monster-types.h"
11 #include "monster-race/monster-race-hook.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-flags-resistance.h"
14 #include "monster-race/race-flags1.h"
15 #include "monster-race/race-flags2.h"
16 #include "monster-race/race-flags3.h"
17 #include "monster-race/race-flags7.h"
18 #include "monster/monster-info.h"
19 #include "monster/monster-list.h"
20 #include "monster/monster-util.h"
21 #include "room/space-finder.h"
22 #include "system/floor-type-definition.h"
23 #include "util/probability-table.h"
24 #include "util/sort.h"
25 #include "view/display-messages.h"
26 #include "wizard/wizard-messages.h"
27 #include <vector>
28
29 /*!
30  * @brief ダンジョン毎に指定されたピット配列を基準にランダムなpit/nestタイプを決める
31  * @param l_ptr 選択されたpit/nest情報を返す参照ポインタ
32  * @param allow_flag_mask 生成が許されるpit/nestのビット配列
33  * @return 選択されたpit/nestのID、選択失敗した場合-1を返す。
34  */
35 static int pick_vault_type(floor_type *floor_ptr, std::vector<nest_pit_type>& l_ptr, BIT_FLAGS16 allow_flag_mask)
36 {
37     ProbabilityTable<int> table;
38     for (size_t i = 0; i < l_ptr.size(); i++) {
39         nest_pit_type *n_ptr = &l_ptr.at(i);
40
41         if (n_ptr->level > floor_ptr->dun_level)
42             continue;
43
44         if (!(allow_flag_mask & (1UL << i)))
45             continue;
46
47         table.entry_item(i, n_ptr->chance * MAX_DEPTH / (MIN(floor_ptr->dun_level, MAX_DEPTH - 1) - n_ptr->level + 5));
48     }
49
50     return !table.empty() ? table.pick_one_at_random() : -1;
51 }
52
53 /*!
54  * @brief デバッグ時に生成されたpit/nestの型を出力する処理
55  * @param type pit/nestの型ID
56  * @param nest TRUEならばnest、FALSEならばpit
57  * @return デバッグ表示文字列の参照ポインタ
58  * @details
59  * Hack -- Get the string describing subtype of pit/nest
60  * Determined in prepare function (some pit/nest only)
61  */
62 static concptr pit_subtype_string(int type, bool nest)
63 {
64     static char inner_buf[256] = "";
65     inner_buf[0] = '\0';
66     if (nest) {
67         switch (type) {
68         case NEST_TYPE_CLONE:
69             sprintf(inner_buf, "(%s)", r_info[vault_aux_race].name.c_str());
70             break;
71         case NEST_TYPE_SYMBOL_GOOD:
72         case NEST_TYPE_SYMBOL_EVIL:
73             sprintf(inner_buf, "(%c)", vault_aux_char);
74             break;
75         }
76
77         return inner_buf;
78     }
79
80     /* Pits */
81     switch (type) {
82     case PIT_TYPE_SYMBOL_GOOD:
83     case PIT_TYPE_SYMBOL_EVIL:
84         sprintf(inner_buf, "(%c)", vault_aux_char);
85         break;
86     case PIT_TYPE_DRAGON:
87         if (vault_aux_dragon_mask4.has_all_of({ RF_ABILITY::BR_ACID, RF_ABILITY::BR_ELEC, RF_ABILITY::BR_FIRE, RF_ABILITY::BR_COLD, RF_ABILITY::BR_POIS })) {
88             strcpy(inner_buf, _("(万色)", "(multi-hued)"));
89         } else if (vault_aux_dragon_mask4.has(RF_ABILITY::BR_ACID)) {
90             strcpy(inner_buf, _("(酸)", "(acid)"));
91         }else if (vault_aux_dragon_mask4.has(RF_ABILITY::BR_ELEC)) {
92             strcpy(inner_buf, _("(稲妻)", "(lightning)"));
93         }else if (vault_aux_dragon_mask4.has(RF_ABILITY::BR_FIRE)) {
94             strcpy(inner_buf, _("(火炎)", "(fire)"));
95         }else if (vault_aux_dragon_mask4.has(RF_ABILITY::BR_COLD)) {
96             strcpy(inner_buf, _("(冷気)", "(frost)"));
97         }else if (vault_aux_dragon_mask4.has(RF_ABILITY::BR_POIS)) {
98             strcpy(inner_buf, _("(毒)", "(poison)"));
99         } else {
100             strcpy(inner_buf, _("(未定義)", "(undefined)"));
101         }
102         break;
103     }
104
105     return inner_buf;
106 }
107
108 /*
109  *! @brief nestのモンスターリストをソートするための関数 /
110  *  Comp function for sorting nest monster information
111  *  @param u ソート処理対象配列ポインタ
112  *  @param v 未使用
113  *  @param a 比較対象参照ID1
114  *  @param b 比較対象参照ID2
115  *  TODO: to sort.c
116  */
117 static bool ang_sort_comp_nest_mon_info(player_type *player_ptr, vptr u, vptr v, int a, int b)
118 {
119     /* Unused */
120     (void)player_ptr;
121     (void)v;
122
123     nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u;
124     MONSTER_IDX w1 = nest_mon_info[a].r_idx;
125     MONSTER_IDX w2 = nest_mon_info[b].r_idx;
126     monster_race *r1_ptr = &r_info[w1];
127     monster_race *r2_ptr = &r_info[w2];
128     int z1 = nest_mon_info[a].used;
129     int z2 = nest_mon_info[b].used;
130
131     if (z1 < z2)
132         return FALSE;
133     if (z1 > z2)
134         return TRUE;
135
136     if (r1_ptr->level < r2_ptr->level)
137         return TRUE;
138     if (r1_ptr->level > r2_ptr->level)
139         return FALSE;
140
141     if (r1_ptr->mexp < r2_ptr->mexp)
142         return TRUE;
143     if (r1_ptr->mexp > r2_ptr->mexp)
144         return FALSE;
145
146     return w1 <= w2;
147 }
148
149 /*!
150  * @brief nestのモンスターリストをスワップするための関数 /
151  * Swap function for sorting nest monster information
152  * @param u スワップ処理対象配列ポインタ
153  * @param v 未使用
154  * @param a スワップ対象参照ID1
155  * @param b スワップ対象参照ID2
156  * TODO: to sort.c
157  */
158 static void ang_sort_swap_nest_mon_info(player_type *player_ptr, vptr u, vptr v, int a, int b)
159 {
160     /* Unused */
161     (void)player_ptr;
162     (void)v;
163
164     nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u;
165     nest_mon_info_type holder = nest_mon_info[a];
166     nest_mon_info[a] = nest_mon_info[b];
167     nest_mon_info[b] = holder;
168 }
169
170 /*!
171  * @brief 生成するNestの情報テーブル
172  */
173 std::vector<nest_pit_type> nest_types = {
174     { _("クローン", "clone"), vault_aux_clone, vault_prep_clone, 5, 3 },
175     { _("ゼリー", "jelly"), vault_aux_jelly, NULL, 5, 6 },
176     { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 },
177     { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 },
178     { _("ミミック", "mimic"), vault_aux_mimic, NULL, 30, 4 },
179     { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 70, 2 },
180     { _("犬小屋", "kennel"), vault_aux_kennel, NULL, 45, 4 },
181     { _("動物園", "animal"), vault_aux_animal, NULL, 35, 5 },
182     { _("教会", "chapel"), vault_aux_chapel_g, NULL, 75, 4 },
183     { _("アンデッド", "undead"), vault_aux_undead, NULL, 75, 5 },
184 };
185
186 /*!
187  * @brief タイプ5の部屋…nestを生成する / Type 5 -- Monster nests
188  * @param player_ptr プレーヤーへの参照ポインタ
189  * @return なし
190  * @details
191  * A monster nest is a "big" room, with an "inner" room, containing\n
192  * a "collection" of monsters of a given type strewn about the room.\n
193  *\n
194  * The monsters are chosen from a set of 64 randomly selected monster\n
195  * races, to allow the nest creation to fail instead of having "holes".\n
196  *\n
197  * Note the use of the "get_mon_num_prep()" function, and the special\n
198  * "get_mon_num_hook()" restriction function, to prepare the "monster\n
199  * allocation table" in such a way as to optimize the selection of\n
200  * "appropriate" non-unique monsters for the nest.\n
201  *\n
202  * Note that the "get_mon_num()" function may (rarely) fail, in which\n
203  * case the nest will be empty.\n
204  *\n
205  * Note that "monster nests" will never contain "unique" monsters.\n
206  */
207 bool build_type5(player_type *player_ptr, dun_data_type *dd_ptr)
208 {
209     POSITION y, x, y1, x1, y2, x2, xval, yval;
210     int i;
211     nest_mon_info_type nest_mon_info[NUM_NEST_MON_TYPE];
212
213     monster_type align;
214
215     grid_type *g_ptr;
216
217     floor_type *floor_ptr = player_ptr->current_floor_ptr;
218     int cur_nest_type = pick_vault_type(floor_ptr, nest_types, d_info[floor_ptr->dungeon_idx].nest);
219     nest_pit_type *n_ptr;
220
221     /* No type available */
222     if (cur_nest_type < 0)
223         return FALSE;
224
225     n_ptr = &nest_types[cur_nest_type];
226
227     /* Process a preparation function if necessary */
228     if (n_ptr->prep_func)
229         (*(n_ptr->prep_func))(player_ptr);
230     get_mon_num_prep(player_ptr, n_ptr->hook_func, NULL);
231
232     align.sub_align = SUB_ALIGN_NEUTRAL;
233
234     /* Pick some monster types */
235     for (i = 0; i < NUM_NEST_MON_TYPE; i++) {
236         MONRACE_IDX r_idx = 0;
237         int attempts = 100;
238         monster_race *r_ptr = NULL;
239
240         while (attempts--) {
241             /* Get a (hard) monster type */
242             r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
243             r_ptr = &r_info[r_idx];
244
245             /* Decline incorrect alignment */
246             if (monster_has_hostile_align(player_ptr, &align, 0, 0, r_ptr))
247                 continue;
248
249             /* Accept this monster */
250             break;
251         }
252
253         /* Notice failure */
254         if (!r_idx || !attempts)
255             return FALSE;
256
257         /* Note the alignment */
258         if (r_ptr->flags3 & RF3_EVIL)
259             align.sub_align |= SUB_ALIGN_EVIL;
260         if (r_ptr->flags3 & RF3_GOOD)
261             align.sub_align |= SUB_ALIGN_GOOD;
262
263         nest_mon_info[i].r_idx = (s16b)r_idx;
264         nest_mon_info[i].used = FALSE;
265     }
266
267     /* Find and reserve some space in the dungeon.  Get center of room. */
268     if (!find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25))
269         return FALSE;
270
271     /* Large room */
272     y1 = yval - 4;
273     y2 = yval + 4;
274     x1 = xval - 11;
275     x2 = xval + 11;
276
277     /* Place the floor area */
278     for (y = y1 - 1; y <= y2 + 1; y++) {
279         for (x = x1 - 1; x <= x2 + 1; x++) {
280             g_ptr = &floor_ptr->grid_array[y][x];
281             place_grid(player_ptr, g_ptr, GB_FLOOR);
282             g_ptr->info |= (CAVE_ROOM);
283         }
284     }
285
286     /* Place the outer walls */
287     for (y = y1 - 1; y <= y2 + 1; y++) {
288         g_ptr = &floor_ptr->grid_array[y][x1 - 1];
289         place_grid(player_ptr, g_ptr, GB_OUTER);
290         g_ptr = &floor_ptr->grid_array[y][x2 + 1];
291         place_grid(player_ptr, g_ptr, GB_OUTER);
292     }
293     for (x = x1 - 1; x <= x2 + 1; x++) {
294         g_ptr = &floor_ptr->grid_array[y1 - 1][x];
295         place_grid(player_ptr, g_ptr, GB_OUTER);
296         g_ptr = &floor_ptr->grid_array[y2 + 1][x];
297         place_grid(player_ptr, g_ptr, GB_OUTER);
298     }
299
300     /* Advance to the center room */
301     y1 = y1 + 2;
302     y2 = y2 - 2;
303     x1 = x1 + 2;
304     x2 = x2 - 2;
305
306     /* The inner walls */
307     for (y = y1 - 1; y <= y2 + 1; y++) {
308         g_ptr = &floor_ptr->grid_array[y][x1 - 1];
309         place_grid(player_ptr, g_ptr, GB_INNER);
310         g_ptr = &floor_ptr->grid_array[y][x2 + 1];
311         place_grid(player_ptr, g_ptr, GB_INNER);
312     }
313
314     for (x = x1 - 1; x <= x2 + 1; x++) {
315         g_ptr = &floor_ptr->grid_array[y1 - 1][x];
316         place_grid(player_ptr, g_ptr, GB_INNER);
317         g_ptr = &floor_ptr->grid_array[y2 + 1][x];
318         place_grid(player_ptr, g_ptr, GB_INNER);
319     }
320     for (y = y1; y <= y2; y++) {
321         for (x = x1; x <= x2; x++) {
322             add_cave_info(floor_ptr, y, x, CAVE_ICKY);
323         }
324     }
325
326     /* Place a secret door */
327     switch (randint1(4)) {
328     case 1:
329         place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
330         break;
331     case 2:
332         place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
333         break;
334     case 3:
335         place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
336         break;
337     case 4:
338         place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
339         break;
340     }
341
342     msg_format_wizard(
343         player_ptr, CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, TRUE));
344
345     /* Place some monsters */
346     for (y = yval - 2; y <= yval + 2; y++) {
347         for (x = xval - 9; x <= xval + 9; x++) {
348             MONRACE_IDX r_idx;
349
350             i = randint0(NUM_NEST_MON_TYPE);
351             r_idx = nest_mon_info[i].r_idx;
352
353             /* Place that "random" monster (no groups) */
354             (void)place_monster_aux(player_ptr, 0, y, x, r_idx, 0L);
355
356             nest_mon_info[i].used = TRUE;
357         }
358     }
359
360     if (cheat_room) {
361         ang_sort(player_ptr, nest_mon_info, NULL, NUM_NEST_MON_TYPE, ang_sort_comp_nest_mon_info, ang_sort_swap_nest_mon_info);
362
363         /* Dump the entries (prevent multi-printing) */
364         for (i = 0; i < NUM_NEST_MON_TYPE; i++) {
365             if (!nest_mon_info[i].used)
366                 break;
367             for (; i < NUM_NEST_MON_TYPE - 1; i++) {
368                 if (nest_mon_info[i].r_idx != nest_mon_info[i + 1].r_idx)
369                     break;
370                 if (!nest_mon_info[i + 1].used)
371                     break;
372             }
373
374             msg_format_wizard(player_ptr, CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, r_info[nest_mon_info[i].r_idx].name.c_str());
375         }
376     }
377
378     return TRUE;
379 }
380
381 /*!
382  * @brief 生成するPitの情報テーブル
383  */
384 std::vector<nest_pit_type> pit_types = {
385     { _("オーク", "orc"), vault_aux_orc, NULL, 5, 6 },
386     { _("トロル", "troll"), vault_aux_troll, NULL, 20, 6 },
387     { _("巨人", "giant"), vault_aux_giant, NULL, 50, 6 },
388     { _("狂気", "lovecraftian"), vault_aux_cthulhu, NULL, 80, 2 },
389     { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 },
390     { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 },
391     { _("教会", "chapel"), vault_aux_chapel_g, NULL, 65, 2 },
392     { _("ドラゴン", "dragon"), vault_aux_dragon, vault_prep_dragon, 70, 6 },
393     { _("デーモン", "demon"), vault_aux_demon, NULL, 80, 6 },
394     { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL, 45, 4 },
395 };
396
397 /*!
398  * @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits
399  * @return なし
400  * @details
401  * A monster pit is a "big" room, with an "inner" room, containing\n
402  * a "collection" of monsters of a given type organized in the room.\n
403  *\n
404  * The inside room in a monster pit appears as shown below, where the\n
405  * actual monsters in each location depend on the type of the pit\n
406  *\n
407  *   XXXXXXXXXXXXXXXXXXXXX\n
408  *   X0000000000000000000X\n
409  *   X0112233455543322110X\n
410  *   X0112233467643322110X\n
411  *   X0112233455543322110X\n
412  *   X0000000000000000000X\n
413  *   XXXXXXXXXXXXXXXXXXXXX\n
414  *\n
415  * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n
416  * to request 16 "appropriate" monsters, sorting them by level, and using\n
417  * the "even" entries in this sorted list for the contents of the pit.\n
418  *\n
419  * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n
420  * which is handled by requiring a specific "breath" attack for all of the\n
421  * dragons.  This may include "multi-hued" breath.  Note that "wyrms" may\n
422  * be present in many of the dragon pits, if they have the proper breath.\n
423  *\n
424  * Note the use of the "get_mon_num_prep()" function, and the special\n
425  * "get_mon_num_hook()" restriction function, to prepare the "monster\n
426  * allocation table" in such a way as to optimize the selection of\n
427  * "appropriate" non-unique monsters for the pit.\n
428  *\n
429  * Note that the "get_mon_num()" function may (rarely) fail, in which case\n
430  * the pit will be empty.\n
431  *\n
432  * Note that "monster pits" will never contain "unique" monsters.\n
433  */
434 bool build_type6(player_type *player_ptr, dun_data_type *dd_ptr)
435 {
436     POSITION y, x, y1, x1, y2, x2, xval, yval;
437     int i, j;
438
439     MONRACE_IDX what[16];
440
441     monster_type align;
442
443     grid_type *g_ptr;
444
445     floor_type *floor_ptr = player_ptr->current_floor_ptr;
446     int cur_pit_type = pick_vault_type(floor_ptr, pit_types, d_info[floor_ptr->dungeon_idx].pit);
447     nest_pit_type *n_ptr;
448
449     /* No type available */
450     if (cur_pit_type < 0)
451         return FALSE;
452
453     n_ptr = &pit_types[cur_pit_type];
454
455     /* Process a preparation function if necessary */
456     if (n_ptr->prep_func)
457         (*(n_ptr->prep_func))(player_ptr);
458     get_mon_num_prep(player_ptr, n_ptr->hook_func, NULL);
459
460     align.sub_align = SUB_ALIGN_NEUTRAL;
461
462     /* Pick some monster types */
463     for (i = 0; i < 16; i++) {
464         MONRACE_IDX r_idx = 0;
465         int attempts = 100;
466         monster_race *r_ptr = NULL;
467
468         while (attempts--) {
469             /* Get a (hard) monster type */
470             r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
471             r_ptr = &r_info[r_idx];
472
473             /* Decline incorrect alignment */
474             if (monster_has_hostile_align(player_ptr, &align, 0, 0, r_ptr))
475                 continue;
476
477             /* Accept this monster */
478             break;
479         }
480
481         /* Notice failure */
482         if (!r_idx || !attempts)
483             return FALSE;
484
485         /* Note the alignment */
486         if (r_ptr->flags3 & RF3_EVIL)
487             align.sub_align |= SUB_ALIGN_EVIL;
488         if (r_ptr->flags3 & RF3_GOOD)
489             align.sub_align |= SUB_ALIGN_GOOD;
490
491         what[i] = r_idx;
492     }
493
494     /* Find and reserve some space in the dungeon.  Get center of room. */
495     if (!find_space(player_ptr, dd_ptr, &yval, &xval, 11, 25))
496         return FALSE;
497
498     /* Large room */
499     y1 = yval - 4;
500     y2 = yval + 4;
501     x1 = xval - 11;
502     x2 = xval + 11;
503
504     /* Place the floor area */
505     for (y = y1 - 1; y <= y2 + 1; y++) {
506         for (x = x1 - 1; x <= x2 + 1; x++) {
507             g_ptr = &floor_ptr->grid_array[y][x];
508             place_grid(player_ptr, g_ptr, GB_FLOOR);
509             g_ptr->info |= (CAVE_ROOM);
510         }
511     }
512
513     /* Place the outer walls */
514     for (y = y1 - 1; y <= y2 + 1; y++) {
515         g_ptr = &floor_ptr->grid_array[y][x1 - 1];
516         place_grid(player_ptr, g_ptr, GB_OUTER);
517         g_ptr = &floor_ptr->grid_array[y][x2 + 1];
518         place_grid(player_ptr, g_ptr, GB_OUTER);
519     }
520     for (x = x1 - 1; x <= x2 + 1; x++) {
521         g_ptr = &floor_ptr->grid_array[y1 - 1][x];
522         place_grid(player_ptr, g_ptr, GB_OUTER);
523         g_ptr = &floor_ptr->grid_array[y2 + 1][x];
524         place_grid(player_ptr, g_ptr, GB_OUTER);
525     }
526
527     /* Advance to the center room */
528     y1 = y1 + 2;
529     y2 = y2 - 2;
530     x1 = x1 + 2;
531     x2 = x2 - 2;
532
533     /* The inner walls */
534     for (y = y1 - 1; y <= y2 + 1; y++) {
535         g_ptr = &floor_ptr->grid_array[y][x1 - 1];
536         place_grid(player_ptr, g_ptr, GB_INNER);
537         g_ptr = &floor_ptr->grid_array[y][x2 + 1];
538         place_grid(player_ptr, g_ptr, GB_INNER);
539     }
540     for (x = x1 - 1; x <= x2 + 1; x++) {
541         g_ptr = &floor_ptr->grid_array[y1 - 1][x];
542         place_grid(player_ptr, g_ptr, GB_INNER);
543         g_ptr = &floor_ptr->grid_array[y2 + 1][x];
544         place_grid(player_ptr, g_ptr, GB_INNER);
545     }
546     for (y = y1; y <= y2; y++) {
547         for (x = x1; x <= x2; x++) {
548             add_cave_info(floor_ptr, y, x, CAVE_ICKY);
549         }
550     }
551
552     /* Place a secret door */
553     switch (randint1(4)) {
554     case 1:
555         place_secret_door(player_ptr, y1 - 1, xval, DOOR_DEFAULT);
556         break;
557     case 2:
558         place_secret_door(player_ptr, y2 + 1, xval, DOOR_DEFAULT);
559         break;
560     case 3:
561         place_secret_door(player_ptr, yval, x1 - 1, DOOR_DEFAULT);
562         break;
563     case 4:
564         place_secret_door(player_ptr, yval, x2 + 1, DOOR_DEFAULT);
565         break;
566     }
567
568     /* Sort the entries */
569     for (i = 0; i < 16 - 1; i++) {
570         /* Sort the entries */
571         for (j = 0; j < 16 - 1; j++) {
572             int i1 = j;
573             int i2 = j + 1;
574
575             int p1 = r_info[what[i1]].level;
576             int p2 = r_info[what[i2]].level;
577
578             /* Bubble */
579             if (p1 > p2) {
580                 MONRACE_IDX tmp = what[i1];
581                 what[i1] = what[i2];
582                 what[i2] = tmp;
583             }
584         }
585     }
586
587     msg_format_wizard(
588         player_ptr, CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));
589
590     /* Select the entries */
591     for (i = 0; i < 8; i++) {
592         /* Every other entry */
593         what[i] = what[i * 2];
594         msg_format_wizard(player_ptr, CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_info[what[i]].name.c_str());
595     }
596
597     /* Top and bottom rows */
598     for (x = xval - 9; x <= xval + 9; x++) {
599         place_monster_aux(player_ptr, 0, yval - 2, x, what[0], PM_NO_KAGE);
600         place_monster_aux(player_ptr, 0, yval + 2, x, what[0], PM_NO_KAGE);
601     }
602
603     /* Middle columns */
604     for (y = yval - 1; y <= yval + 1; y++) {
605         place_monster_aux(player_ptr, 0, y, xval - 9, what[0], PM_NO_KAGE);
606         place_monster_aux(player_ptr, 0, y, xval + 9, what[0], PM_NO_KAGE);
607
608         place_monster_aux(player_ptr, 0, y, xval - 8, what[1], PM_NO_KAGE);
609         place_monster_aux(player_ptr, 0, y, xval + 8, what[1], PM_NO_KAGE);
610
611         place_monster_aux(player_ptr, 0, y, xval - 7, what[1], PM_NO_KAGE);
612         place_monster_aux(player_ptr, 0, y, xval + 7, what[1], PM_NO_KAGE);
613
614         place_monster_aux(player_ptr, 0, y, xval - 6, what[2], PM_NO_KAGE);
615         place_monster_aux(player_ptr, 0, y, xval + 6, what[2], PM_NO_KAGE);
616
617         place_monster_aux(player_ptr, 0, y, xval - 5, what[2], PM_NO_KAGE);
618         place_monster_aux(player_ptr, 0, y, xval + 5, what[2], PM_NO_KAGE);
619
620         place_monster_aux(player_ptr, 0, y, xval - 4, what[3], PM_NO_KAGE);
621         place_monster_aux(player_ptr, 0, y, xval + 4, what[3], PM_NO_KAGE);
622
623         place_monster_aux(player_ptr, 0, y, xval - 3, what[3], PM_NO_KAGE);
624         place_monster_aux(player_ptr, 0, y, xval + 3, what[3], PM_NO_KAGE);
625
626         place_monster_aux(player_ptr, 0, y, xval - 2, what[4], PM_NO_KAGE);
627         place_monster_aux(player_ptr, 0, y, xval + 2, what[4], PM_NO_KAGE);
628     }
629
630     /* Above/Below the center monster */
631     for (x = xval - 1; x <= xval + 1; x++) {
632         place_monster_aux(player_ptr, 0, yval + 1, x, what[5], PM_NO_KAGE);
633         place_monster_aux(player_ptr, 0, yval - 1, x, what[5], PM_NO_KAGE);
634     }
635
636     /* Next to the center monster */
637     place_monster_aux(player_ptr, 0, yval, xval + 1, what[6], PM_NO_KAGE);
638     place_monster_aux(player_ptr, 0, yval, xval - 1, what[6], PM_NO_KAGE);
639
640     /* Center monster */
641     place_monster_aux(player_ptr, 0, yval, xval, what[7], PM_NO_KAGE);
642
643     return TRUE;
644 }
645
646 // clang-format off
647 /*!
648  * @brief 開門トラップのモンスター配置テーブル
649  * @details
650  * 中央からの相対座標(X,Y)、モンスターの強さ
651  */
652 const int place_table_trapped_pit[TRAPPED_PIT_MONSTER_PLACE_MAX][3] = {
653     { -2, -9, 0 }, { -2, -8, 0 }, { -3, -7, 0 }, { -3, -6, 0 }, { +2, -9, 0 }, { +2, -8, 0 }, { +3, -7, 0 }, { +3, -6, 0 },
654     { -2, +9, 0 }, { -2, +8, 0 }, { -3, +7, 0 }, { -3, +6, 0 }, { +2, +9, 0 }, { +2, +8, 0 }, { +3, +7, 0 }, { +3, +6, 0 },
655     { -2, -7, 1 }, { -3, -5, 1 }, { -3, -4, 1 }, { -2, +7, 1 }, { -3, +5, 1 }, { -3, +4, 1 },
656     { +2, -7, 1 }, { +3, -5, 1 }, { +3, -4, 1 }, { +2, +7, 1 }, { +3, +5, 1 }, { +3, +4, 1 },
657     { -2, -6, 2 }, { -2, -5, 2 }, { -3, -3, 2 }, { -2, +6, 2 }, { -2, +5, 2 }, { -3, +3, 2 },
658     { +2, -6, 2 }, { +2, -5, 2 }, { +3, -3, 2 }, { +2, +6, 2 }, { +2, +5, 2 }, { +3, +3, 2 },
659     { -2, -4, 3 }, { -3, -2, 3 }, { -2, +4, 3 }, { -3, +2, 3 },
660     { +2, -4, 3 }, { +3, -2, 3 }, { +2, +4, 3 }, { +3, +2, 3 },
661     { -2, -3, 4 }, { -3, -1, 4 }, { +2, -3, 4 }, { +3, -1, 4 },
662     { -2, +3, 4 }, { -3, +1, 4 }, { +2, +3, 4 }, { +3, +1, 4 },
663     { -2, -2, 5 }, { -3, 0, 5 }, { -2, +2, 5 }, { +2, -2, 5 }, { +3, 0, 5 }, { +2, +2, 5 },
664     { -2, -1, 6 }, { -2, +1, 6 }, { +2, -1, 6 }, { +2, +1, 6 },
665     { -2, 0, 7 }, { +2, 0, 7 },
666     { 0, 0, -1 } };
667 // clang-format on
668
669 /*!
670  * @brief 開門トラップに配置するモンスターの条件フィルタ
671  * @detai;
672  * 穴を掘るモンスター、壁を抜けるモンスターは却下
673  */
674 static bool vault_aux_trapped_pit(player_type *player_ptr, MONRACE_IDX r_idx)
675 {
676     /* Unused */
677     (void)player_ptr;
678
679     monster_race *r_ptr = &r_info[r_idx];
680
681     if (!vault_monster_okay(player_ptr, r_idx))
682         return FALSE;
683
684     /* No wall passing monster */
685     if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL))
686         return FALSE;
687
688     return TRUE;
689 }
690
691 /*!
692  * @brief タイプ13の部屋…開門トラップpitの生成 / Type 13 -- Trapped monster pits
693  * @return なし
694  * @details
695  * A trapped monster pit is a "big" room with a straight corridor in\n
696  * which wall opening traps are placed, and with two "inner" rooms\n
697  * containing a "collection" of monsters of a given type organized in\n
698  * the room.\n
699  *\n
700  * The trapped monster pit appears as shown below, where the actual\n
701  * monsters in each location depend on the type of the pit\n
702  *\n
703  *  XXXXXXXXXXXXXXXXXXXXXXXXX\n
704  *  X                       X\n
705  *  XXXXXXXXXXXXXXXXXXXXXXX X\n
706  *  XXXXX001123454321100XXX X\n
707  *  XXX0012234567654322100X X\n
708  *  XXXXXXXXXXXXXXXXXXXXXXX X\n
709  *  X           ^           X\n
710  *  X XXXXXXXXXXXXXXXXXXXXXXX\n
711  *  X X0012234567654322100XXX\n
712  *  X XXX001123454321100XXXXX\n
713  *  X XXXXXXXXXXXXXXXXXXXXXXX\n
714  *  X                       X\n
715  *  XXXXXXXXXXXXXXXXXXXXXXXXX\n
716  *\n
717  * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n
718  * to request 16 "appropriate" monsters, sorting them by level, and using\n
719  * the "even" entries in this sorted list for the contents of the pit.\n
720  *\n
721  * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n
722  * which is handled by requiring a specific "breath" attack for all of the\n
723  * dragons.  This may include "multi-hued" breath.  Note that "wyrms" may\n
724  * be present in many of the dragon pits, if they have the proper breath.\n
725  *\n
726  * Note the use of the "get_mon_num_prep()" function, and the special\n
727  * "get_mon_num_hook()" restriction function, to prepare the "monster\n
728  * allocation table" in such a way as to optimize the selection of\n
729  * "appropriate" non-unique monsters for the pit.\n
730  *\n
731  * Note that the "get_mon_num()" function may (rarely) fail, in which case\n
732  * the pit will be empty.\n
733  *\n
734  * Note that "monster pits" will never contain "unique" monsters.\n
735  */
736 bool build_type13(player_type *player_ptr, dun_data_type *dd_ptr)
737 {
738     POSITION y, x, y1, x1, y2, x2, xval, yval;
739     int i, j;
740
741     MONRACE_IDX what[16];
742
743     monster_type align;
744
745     grid_type *g_ptr;
746
747     floor_type *floor_ptr = player_ptr->current_floor_ptr;
748     int cur_pit_type = pick_vault_type(floor_ptr, pit_types, d_info[floor_ptr->dungeon_idx].pit);
749     nest_pit_type *n_ptr;
750
751     /* Only in Angband */
752     if (floor_ptr->dungeon_idx != DUNGEON_ANGBAND)
753         return FALSE;
754
755     /* No type available */
756     if (cur_pit_type < 0)
757         return FALSE;
758
759     n_ptr = &pit_types[cur_pit_type];
760
761     /* Process a preparation function if necessary */
762     if (n_ptr->prep_func)
763         (*(n_ptr->prep_func))(player_ptr);
764     get_mon_num_prep(player_ptr, n_ptr->hook_func, vault_aux_trapped_pit);
765
766     align.sub_align = SUB_ALIGN_NEUTRAL;
767
768     /* Pick some monster types */
769     for (i = 0; i < 16; i++) {
770         MONRACE_IDX r_idx = 0;
771         int attempts = 100;
772         monster_race *r_ptr = NULL;
773
774         while (attempts--) {
775             /* Get a (hard) monster type */
776             r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 0, 0);
777             r_ptr = &r_info[r_idx];
778
779             /* Decline incorrect alignment */
780             if (monster_has_hostile_align(player_ptr, &align, 0, 0, r_ptr))
781                 continue;
782
783             /* Accept this monster */
784             break;
785         }
786
787         /* Notice failure */
788         if (!r_idx || !attempts)
789             return FALSE;
790
791         /* Note the alignment */
792         if (r_ptr->flags3 & RF3_EVIL)
793             align.sub_align |= SUB_ALIGN_EVIL;
794         if (r_ptr->flags3 & RF3_GOOD)
795             align.sub_align |= SUB_ALIGN_GOOD;
796
797         what[i] = r_idx;
798     }
799
800     /* Find and reserve some space in the dungeon.  Get center of room. */
801     if (!find_space(player_ptr, dd_ptr, &yval, &xval, 13, 25))
802         return FALSE;
803
804     /* Large room */
805     y1 = yval - 5;
806     y2 = yval + 5;
807     x1 = xval - 11;
808     x2 = xval + 11;
809
810     /* Fill with inner walls */
811     for (y = y1 - 1; y <= y2 + 1; y++) {
812         for (x = x1 - 1; x <= x2 + 1; x++) {
813             g_ptr = &floor_ptr->grid_array[y][x];
814             place_grid(player_ptr, g_ptr, GB_INNER);
815             g_ptr->info |= (CAVE_ROOM);
816         }
817     }
818
819     /* Place the floor area 1 */
820     for (x = x1 + 3; x <= x2 - 3; x++) {
821         g_ptr = &floor_ptr->grid_array[yval - 2][x];
822         place_grid(player_ptr, g_ptr, GB_FLOOR);
823         add_cave_info(floor_ptr, yval - 2, x, CAVE_ICKY);
824
825         g_ptr = &floor_ptr->grid_array[yval + 2][x];
826         place_grid(player_ptr, g_ptr, GB_FLOOR);
827         add_cave_info(floor_ptr, yval + 2, x, CAVE_ICKY);
828     }
829
830     /* Place the floor area 2 */
831     for (x = x1 + 5; x <= x2 - 5; x++) {
832         g_ptr = &floor_ptr->grid_array[yval - 3][x];
833         place_grid(player_ptr, g_ptr, GB_FLOOR);
834         add_cave_info(floor_ptr, yval - 3, x, CAVE_ICKY);
835
836         g_ptr = &floor_ptr->grid_array[yval + 3][x];
837         place_grid(player_ptr, g_ptr, GB_FLOOR);
838         add_cave_info(floor_ptr, yval + 3, x, CAVE_ICKY);
839     }
840
841     /* Corridor */
842     for (x = x1; x <= x2; x++) {
843         g_ptr = &floor_ptr->grid_array[yval][x];
844         place_grid(player_ptr, g_ptr, GB_FLOOR);
845         g_ptr = &floor_ptr->grid_array[y1][x];
846         place_grid(player_ptr, g_ptr, GB_FLOOR);
847         g_ptr = &floor_ptr->grid_array[y2][x];
848         place_grid(player_ptr, g_ptr, GB_FLOOR);
849     }
850
851     /* Place the outer walls */
852     for (y = y1 - 1; y <= y2 + 1; y++) {
853         g_ptr = &floor_ptr->grid_array[y][x1 - 1];
854         place_grid(player_ptr, g_ptr, GB_OUTER);
855         g_ptr = &floor_ptr->grid_array[y][x2 + 1];
856         place_grid(player_ptr, g_ptr, GB_OUTER);
857     }
858     for (x = x1 - 1; x <= x2 + 1; x++) {
859         g_ptr = &floor_ptr->grid_array[y1 - 1][x];
860         place_grid(player_ptr, g_ptr, GB_OUTER);
861         g_ptr = &floor_ptr->grid_array[y2 + 1][x];
862         place_grid(player_ptr, g_ptr, GB_OUTER);
863     }
864
865     /* Random corridor */
866     if (one_in_(2)) {
867         for (y = y1; y <= yval; y++) {
868             place_bold(player_ptr, y, x2, GB_FLOOR);
869             place_bold(player_ptr, y, x1 - 1, GB_SOLID);
870         }
871         for (y = yval; y <= y2 + 1; y++) {
872             place_bold(player_ptr, y, x1, GB_FLOOR);
873             place_bold(player_ptr, y, x2 + 1, GB_SOLID);
874         }
875     } else {
876         for (y = yval; y <= y2 + 1; y++) {
877             place_bold(player_ptr, y, x1, GB_FLOOR);
878             place_bold(player_ptr, y, x2 + 1, GB_SOLID);
879         }
880         for (y = y1; y <= yval; y++) {
881             place_bold(player_ptr, y, x2, GB_FLOOR);
882             place_bold(player_ptr, y, x1 - 1, GB_SOLID);
883         }
884     }
885
886     /* Place the wall open trap */
887     floor_ptr->grid_array[yval][xval].mimic = floor_ptr->grid_array[yval][xval].feat;
888     floor_ptr->grid_array[yval][xval].feat = feat_trap_open;
889
890     /* Sort the entries */
891     for (i = 0; i < 16 - 1; i++) {
892         /* Sort the entries */
893         for (j = 0; j < 16 - 1; j++) {
894             int i1 = j;
895             int i2 = j + 1;
896
897             int p1 = r_info[what[i1]].level;
898             int p2 = r_info[what[i2]].level;
899
900             /* Bubble */
901             if (p1 > p2) {
902                 MONRACE_IDX tmp = what[i1];
903                 what[i1] = what[i2];
904                 what[i2] = tmp;
905             }
906         }
907     }
908
909     msg_format_wizard(
910         player_ptr, CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));
911
912     /* Select the entries */
913     for (i = 0; i < 8; i++) {
914         /* Every other entry */
915         what[i] = what[i * 2];
916
917         if (cheat_hear) {
918             msg_print(r_info[what[i]].name.c_str());
919         }
920     }
921
922     for (i = 0; place_table_trapped_pit[i][2] >= 0; i++) {
923         y = yval + place_table_trapped_pit[i][0];
924         x = xval + place_table_trapped_pit[i][1];
925         place_monster_aux(player_ptr, 0, y, x, what[place_table_trapped_pit[i][2]], PM_NO_KAGE);
926     }
927
928     return TRUE;
929 }