OSDN Git Service

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