OSDN Git Service

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