OSDN Git Service

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