OSDN Git Service

[Refactor] #37353 型の置換。 / Type replacement.
[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-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/nestタイプを決める\r
52 * @param l_ptr 選択されたpit/nest情報を返す参照ポインタ\r
53 * @param allow_flag_mask 生成が許されるpit/nestのビット配列\r
54 * @return 選択されたpit/nestのID、選択失敗した場合-1を返す。\r
55 */\r
56 static int pick_vault_type(vault_aux_type *l_ptr, BIT_FLAGS16 allow_flag_mask)\r
57 {\r
58         int tmp, total, count;\r
59 \r
60         vault_aux_type *n_ptr;\r
61 \r
62         /* Calculate the total possibilities */\r
63         for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++)\r
64         {\r
65                 /* Note end */\r
66                 if (!n_ptr->name) break;\r
67 \r
68                 /* Ignore excessive depth */\r
69                 if (n_ptr->level > dun_level) continue;\r
70 \r
71                 /* Not matched with pit/nest flag */\r
72                 if (!(allow_flag_mask & (1L << count))) continue;\r
73 \r
74                 /* Count this possibility */\r
75                 total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5);\r
76         }\r
77 \r
78         /* Pick a random type */\r
79         tmp = randint0(total);\r
80 \r
81         /* Find this type */\r
82         for (n_ptr = l_ptr, total = 0, count = 0; TRUE; n_ptr++, count++)\r
83         {\r
84                 /* Note end */\r
85                 if (!n_ptr->name) break;\r
86 \r
87                 /* Ignore excessive depth */\r
88                 if (n_ptr->level > dun_level) continue;\r
89 \r
90                 /* Not matched with pit/nest flag */\r
91                 if (!(allow_flag_mask & (1L << count))) continue;\r
92 \r
93                 /* Count this possibility */\r
94                 total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5);\r
95 \r
96                 /* Found the type */\r
97                 if (tmp < total) break;\r
98         }\r
99 \r
100         return n_ptr->name ? count : -1;\r
101 }\r
102 \r
103 /*!\r
104 * @brief デバッグ時に生成されたpit/nestの型を出力する処理\r
105 * @param type pit/nestの型ID\r
106 * @param nest TRUEならばnest、FALSEならばpit\r
107 * @return デバッグ表示文字列の参照ポインタ\r
108 * @details\r
109 * Hack -- Get the string describing subtype of pit/nest\r
110 * Determined in prepare function (some pit/nest only)\r
111 */\r
112 static cptr pit_subtype_string(int type, bool nest)\r
113 {\r
114         static char inner_buf[256] = "";\r
115 \r
116         inner_buf[0] = '\0'; /* Init string */\r
117 \r
118         if (nest) /* Nests */\r
119         {\r
120                 switch (type)\r
121                 {\r
122                 case NEST_TYPE_CLONE:\r
123                         sprintf(inner_buf, "(%s)", r_name + r_info[vault_aux_race].name);\r
124                         break;\r
125                 case NEST_TYPE_SYMBOL_GOOD:\r
126                 case NEST_TYPE_SYMBOL_EVIL:\r
127                         sprintf(inner_buf, "(%c)", vault_aux_char);\r
128                         break;\r
129                 }\r
130         }\r
131         else /* Pits */\r
132         {\r
133                 switch (type)\r
134                 {\r
135                 case PIT_TYPE_SYMBOL_GOOD:\r
136                 case PIT_TYPE_SYMBOL_EVIL:\r
137                         sprintf(inner_buf, "(%c)", vault_aux_char);\r
138                         break;\r
139                 case PIT_TYPE_DRAGON:\r
140                         switch (vault_aux_dragon_mask4)\r
141                         {\r
142                         case RF4_BR_ACID: strcpy(inner_buf, _("(酸)", "(acid)"));   break;\r
143                         case RF4_BR_ELEC: strcpy(inner_buf, _("(稲妻)", "(lightning)")); break;\r
144                         case RF4_BR_FIRE: strcpy(inner_buf, _("(火炎)", "(fire)")); break;\r
145                         case RF4_BR_COLD: strcpy(inner_buf, _("(冷気)", "(frost)")); break;\r
146                         case RF4_BR_POIS: strcpy(inner_buf, _("(毒)", "(poison)"));   break;\r
147                         case (RF4_BR_ACID | RF4_BR_ELEC | RF4_BR_FIRE | RF4_BR_COLD | RF4_BR_POIS) :\r
148                                 strcpy(inner_buf, _("(万色)", "(multi-hued)")); break;\r
149                         default: strcpy(inner_buf, _("(未定義)", "(undefined)")); break;\r
150                         }\r
151                         break;\r
152                 }\r
153         }\r
154 \r
155         return inner_buf;\r
156 }\r
157 \r
158 /*\r
159 *! @brief nestのモンスターリストをソートするための関数 /\r
160 *  Comp function for sorting nest monster information\r
161 *  @param u ソート処理対象配列ポインタ\r
162 *  @param v 未使用\r
163 *  @param a 比較対象参照ID1\r
164 *  @param b 比較対象参照ID2\r
165 */\r
166 static bool ang_sort_comp_nest_mon_info(vptr u, vptr v, int a, int b)\r
167 {\r
168         nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u;\r
169         MONSTER_IDX w1 = nest_mon_info[a].r_idx;\r
170         MONSTER_IDX w2 = nest_mon_info[b].r_idx;\r
171         monster_race *r1_ptr = &r_info[w1];\r
172         monster_race *r2_ptr = &r_info[w2];\r
173         int z1, z2;\r
174 \r
175         /* Unused */\r
176         (void)v;\r
177 \r
178         /* Extract used info */\r
179         z1 = nest_mon_info[a].used;\r
180         z2 = nest_mon_info[b].used;\r
181 \r
182         /* Compare used status */\r
183         if (z1 < z2) return FALSE;\r
184         if (z1 > z2) return TRUE;\r
185 \r
186         /* Compare levels */\r
187         if (r1_ptr->level < r2_ptr->level) return TRUE;\r
188         if (r1_ptr->level > r2_ptr->level) return FALSE;\r
189 \r
190         /* Compare experience */\r
191         if (r1_ptr->mexp < r2_ptr->mexp) return TRUE;\r
192         if (r1_ptr->mexp > r2_ptr->mexp) return FALSE;\r
193 \r
194         /* Compare indexes */\r
195         return w1 <= w2;\r
196 }\r
197 \r
198 /*!\r
199 * @brief nestのモンスターリストをスワップするための関数 /\r
200 * Swap function for sorting nest monster information\r
201 * @param u スワップ処理対象配列ポインタ\r
202 * @param v 未使用\r
203 * @param a スワップ対象参照ID1\r
204 * @param b スワップ対象参照ID2\r
205 */\r
206 static void ang_sort_swap_nest_mon_info(vptr u, vptr v, int a, int b)\r
207 {\r
208         nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u;\r
209         nest_mon_info_type holder;\r
210 \r
211         /* Unused */\r
212         (void)v;\r
213 \r
214         /* Swap */\r
215         holder = nest_mon_info[a];\r
216         nest_mon_info[a] = nest_mon_info[b];\r
217         nest_mon_info[b] = holder;\r
218 }\r
219 \r
220 \r
221 \r
222 /*!nest情報テーブル*/\r
223 static vault_aux_type nest_types[] =\r
224 {\r
225         { _("クローン", "clone"),      vault_aux_clone,    vault_prep_clone,   5, 3 },\r
226         { _("ゼリー", "jelly"),        vault_aux_jelly,    NULL,               5, 6 },\r
227         { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 25, 2 },\r
228         { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 25, 2 },\r
229         { _("ミミック", "mimic"),      vault_aux_mimic,    NULL,              30, 4 },\r
230         { _("狂気", "lovecraftian"),   vault_aux_cthulhu,  NULL,              70, 2 },\r
231         { _("犬小屋", "kennel"),       vault_aux_kennel,   NULL,              45, 4 },\r
232         { _("動物園", "animal"),       vault_aux_animal,   NULL,              35, 5 },\r
233         { _("教会", "chapel"),         vault_aux_chapel_g, NULL,              75, 4 },\r
234         { _("アンデッド", "undead"),   vault_aux_undead,   NULL,              75, 5 },\r
235         { NULL,           NULL,               NULL,               0, 0 },\r
236 };\r
237 \r
238 /*!pit情報テーブル*/\r
239 static vault_aux_type pit_types[] =\r
240 {\r
241         { _("オーク", "orc"),            vault_aux_orc,      NULL,               5, 6 },\r
242         { _("トロル", "troll"),          vault_aux_troll,    NULL,              20, 6 },\r
243         { _("ジャイアント", "giant"),    vault_aux_giant,    NULL,              50, 6 },\r
244         { _("狂気", "lovecraftian"),     vault_aux_cthulhu,  NULL,              80, 2 },\r
245         { _("シンボル(善)", "symbol good"), vault_aux_symbol_g, vault_prep_symbol, 70, 1 },\r
246         { _("シンボル(悪)", "symbol evil"), vault_aux_symbol_e, vault_prep_symbol, 70, 1 },\r
247         { _("教会", "chapel"),           vault_aux_chapel_g, NULL,              65, 2 },\r
248         { _("ドラゴン", "dragon"),       vault_aux_dragon,   vault_prep_dragon, 70, 6 },\r
249         { _("デーモン", "demon"),        vault_aux_demon,    NULL,              80, 6 },\r
250         { _("ダークエルフ", "dark elf"), vault_aux_dark_elf, NULL,              45, 4 },\r
251         { NULL,           NULL,               NULL,               0, 0 },\r
252 };\r
253 \r
254 \r
255 \r
256 \r
257 /*!\r
258 * @brief タイプ5の部屋…nestを生成する / Type 5 -- Monster nests\r
259 * @return なし\r
260 * @details\r
261 * A monster nest is a "big" room, with an "inner" room, containing\n\r
262 * a "collection" of monsters of a given type strewn about the room.\n\r
263 *\n\r
264 * The monsters are chosen from a set of 64 randomly selected monster\n\r
265 * races, to allow the nest creation to fail instead of having "holes".\n\r
266 *\n\r
267 * Note the use of the "get_mon_num_prep()" function, and the special\n\r
268 * "get_mon_num_hook()" restriction function, to prepare the "monster\n\r
269 * allocation table" in such a way as to optimize the selection of\n\r
270 * "appropriate" non-unique monsters for the nest.\n\r
271 *\n\r
272 * Note that the "get_mon_num()" function may (rarely) fail, in which\n\r
273 * case the nest will be empty.\n\r
274 *\n\r
275 * Note that "monster nests" will never contain "unique" monsters.\n\r
276 */\r
277 bool build_type5(void)\r
278 {\r
279         POSITION y, x, y1, x1, y2, x2, xval, yval;\r
280         int i;\r
281         nest_mon_info_type nest_mon_info[NUM_NEST_MON_TYPE];\r
282 \r
283         monster_type align;\r
284 \r
285         cave_type *c_ptr;\r
286 \r
287         int cur_nest_type = pick_vault_type(nest_types, d_info[dungeon_type].nest);\r
288         vault_aux_type *n_ptr;\r
289 \r
290         /* No type available */\r
291         if (cur_nest_type < 0) return FALSE;\r
292 \r
293         n_ptr = &nest_types[cur_nest_type];\r
294 \r
295         /* Process a preparation function if necessary */\r
296         if (n_ptr->prep_func) (*(n_ptr->prep_func))();\r
297 \r
298         /* Prepare allocation table */\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 \r
511         /* Prepare allocation table */\r
512         get_mon_num_prep(n_ptr->hook_func, NULL);\r
513 \r
514         align.sub_align = SUB_ALIGN_NEUTRAL;\r
515 \r
516         /* Pick some monster types */\r
517         for (i = 0; i < 16; i++)\r
518         {\r
519                 MONRACE_IDX r_idx = 0;\r
520                 int attempts = 100;\r
521                 monster_race *r_ptr = NULL;\r
522 \r
523                 while (attempts--)\r
524                 {\r
525                         /* Get a (hard) monster type */\r
526                         r_idx = get_mon_num(dun_level + 11);\r
527                         r_ptr = &r_info[r_idx];\r
528 \r
529                         /* Decline incorrect alignment */\r
530                         if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue;\r
531 \r
532                         /* Accept this monster */\r
533                         break;\r
534                 }\r
535 \r
536                 /* Notice failure */\r
537                 if (!r_idx || !attempts) return FALSE;\r
538 \r
539                 /* Note the alignment */\r
540                 if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL;\r
541                 if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD;\r
542 \r
543                 what[i] = r_idx;\r
544         }\r
545 \r
546         /* Find and reserve some space in the dungeon.  Get center of room. */\r
547         if (!find_space(&yval, &xval, 11, 25)) return FALSE;\r
548 \r
549         /* Large room */\r
550         y1 = yval - 4;\r
551         y2 = yval + 4;\r
552         x1 = xval - 11;\r
553         x2 = xval + 11;\r
554 \r
555         /* Place the floor area */\r
556         for (y = y1 - 1; y <= y2 + 1; y++)\r
557         {\r
558                 for (x = x1 - 1; x <= x2 + 1; x++)\r
559                 {\r
560                         c_ptr = &cave[y][x];\r
561                         place_floor_grid(c_ptr);\r
562                         c_ptr->info |= (CAVE_ROOM);\r
563                 }\r
564         }\r
565 \r
566         /* Place the outer walls */\r
567         for (y = y1 - 1; y <= y2 + 1; y++)\r
568         {\r
569                 c_ptr = &cave[y][x1 - 1];\r
570                 place_outer_grid(c_ptr);\r
571                 c_ptr = &cave[y][x2 + 1];\r
572                 place_outer_grid(c_ptr);\r
573         }\r
574         for (x = x1 - 1; x <= x2 + 1; x++)\r
575         {\r
576                 c_ptr = &cave[y1 - 1][x];\r
577                 place_outer_grid(c_ptr);\r
578                 c_ptr = &cave[y2 + 1][x];\r
579                 place_outer_grid(c_ptr);\r
580         }\r
581 \r
582         /* Advance to the center room */\r
583         y1 = y1 + 2;\r
584         y2 = y2 - 2;\r
585         x1 = x1 + 2;\r
586         x2 = x2 - 2;\r
587 \r
588         /* The inner walls */\r
589         for (y = y1 - 1; y <= y2 + 1; y++)\r
590         {\r
591                 c_ptr = &cave[y][x1 - 1];\r
592                 place_inner_grid(c_ptr);\r
593                 c_ptr = &cave[y][x2 + 1];\r
594                 place_inner_grid(c_ptr);\r
595         }\r
596         for (x = x1 - 1; x <= x2 + 1; x++)\r
597         {\r
598                 c_ptr = &cave[y1 - 1][x];\r
599                 place_inner_grid(c_ptr);\r
600                 c_ptr = &cave[y2 + 1][x];\r
601                 place_inner_grid(c_ptr);\r
602         }\r
603         for (y = y1; y <= y2; y++)\r
604         {\r
605                 for (x = x1; x <= x2; x++)\r
606                 {\r
607                         add_cave_info(y, x, CAVE_ICKY);\r
608                 }\r
609         }\r
610 \r
611         /* Place a secret door */\r
612         switch (randint1(4))\r
613         {\r
614         case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break;\r
615         case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break;\r
616         case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break;\r
617         case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break;\r
618         }\r
619 \r
620         /* Sort the entries */\r
621         for (i = 0; i < 16 - 1; i++)\r
622         {\r
623                 /* Sort the entries */\r
624                 for (j = 0; j < 16 - 1; j++)\r
625                 {\r
626                         int i1 = j;\r
627                         int i2 = j + 1;\r
628 \r
629                         int p1 = r_info[what[i1]].level;\r
630                         int p2 = r_info[what[i2]].level;\r
631 \r
632                         /* Bubble */\r
633                         if (p1 > p2)\r
634                         {\r
635                                 MONRACE_IDX tmp = what[i1];\r
636                                 what[i1] = what[i2];\r
637                                 what[i2] = tmp;\r
638                         }\r
639                 }\r
640         }\r
641 \r
642         msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));\r
643 \r
644         /* Select the entries */\r
645         for (i = 0; i < 8; i++)\r
646         {\r
647                 /* Every other entry */\r
648                 what[i] = what[i * 2];\r
649                 msg_format_wizard(CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_name + r_info[what[i]].name);\r
650         }\r
651 \r
652         /* Top and bottom rows */\r
653         for (x = xval - 9; x <= xval + 9; x++)\r
654         {\r
655                 place_monster_aux(0, yval - 2, x, what[0], PM_NO_KAGE);\r
656                 place_monster_aux(0, yval + 2, x, what[0], PM_NO_KAGE);\r
657         }\r
658 \r
659         /* Middle columns */\r
660         for (y = yval - 1; y <= yval + 1; y++)\r
661         {\r
662                 place_monster_aux(0, y, xval - 9, what[0], PM_NO_KAGE);\r
663                 place_monster_aux(0, y, xval + 9, what[0], PM_NO_KAGE);\r
664 \r
665                 place_monster_aux(0, y, xval - 8, what[1], PM_NO_KAGE);\r
666                 place_monster_aux(0, y, xval + 8, what[1], PM_NO_KAGE);\r
667 \r
668                 place_monster_aux(0, y, xval - 7, what[1], PM_NO_KAGE);\r
669                 place_monster_aux(0, y, xval + 7, what[1], PM_NO_KAGE);\r
670 \r
671                 place_monster_aux(0, y, xval - 6, what[2], PM_NO_KAGE);\r
672                 place_monster_aux(0, y, xval + 6, what[2], PM_NO_KAGE);\r
673 \r
674                 place_monster_aux(0, y, xval - 5, what[2], PM_NO_KAGE);\r
675                 place_monster_aux(0, y, xval + 5, what[2], PM_NO_KAGE);\r
676 \r
677                 place_monster_aux(0, y, xval - 4, what[3], PM_NO_KAGE);\r
678                 place_monster_aux(0, y, xval + 4, what[3], PM_NO_KAGE);\r
679 \r
680                 place_monster_aux(0, y, xval - 3, what[3], PM_NO_KAGE);\r
681                 place_monster_aux(0, y, xval + 3, what[3], PM_NO_KAGE);\r
682 \r
683                 place_monster_aux(0, y, xval - 2, what[4], PM_NO_KAGE);\r
684                 place_monster_aux(0, y, xval + 2, what[4], PM_NO_KAGE);\r
685         }\r
686 \r
687         /* Above/Below the center monster */\r
688         for (x = xval - 1; x <= xval + 1; x++)\r
689         {\r
690                 place_monster_aux(0, yval + 1, x, what[5], PM_NO_KAGE);\r
691                 place_monster_aux(0, yval - 1, x, what[5], PM_NO_KAGE);\r
692         }\r
693 \r
694         /* Next to the center monster */\r
695         place_monster_aux(0, yval, xval + 1, what[6], PM_NO_KAGE);\r
696         place_monster_aux(0, yval, xval - 1, what[6], PM_NO_KAGE);\r
697 \r
698         /* Center monster */\r
699         place_monster_aux(0, yval, xval, what[7], PM_NO_KAGE);\r
700 \r
701         return TRUE;\r
702 }\r
703 \r
704 \r
705 \r
706 /*\r
707 * Helper function for "trapped monster pit"\r
708 */\r
709 static bool vault_aux_trapped_pit(MONRACE_IDX r_idx)\r
710 {\r
711         monster_race *r_ptr = &r_info[r_idx];\r
712 \r
713         if (!vault_monster_okay(r_idx)) return (FALSE);\r
714 \r
715         /* No wall passing monster */\r
716         if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE);\r
717 \r
718         return (TRUE);\r
719 }\r
720 \r
721 \r
722 /*!\r
723 * @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits\r
724 * @return なし\r
725 * @details\r
726 * A trapped monster pit is a "big" room with a straight corridor in\n\r
727 * which wall opening traps are placed, and with two "inner" rooms\n\r
728 * containing a "collection" of monsters of a given type organized in\n\r
729 * the room.\n\r
730 *\n\r
731 * The trapped monster pit appears as shown below, where the actual\n\r
732 * monsters in each location depend on the type of the pit\n\r
733 *\n\r
734 *  XXXXXXXXXXXXXXXXXXXXXXXXX\n\r
735 *  X                       X\n\r
736 *  XXXXXXXXXXXXXXXXXXXXXXX X\n\r
737 *  XXXXX001123454321100XXX X\n\r
738 *  XXX0012234567654322100X X\n\r
739 *  XXXXXXXXXXXXXXXXXXXXXXX X\n\r
740 *  X           ^           X\n\r
741 *  X XXXXXXXXXXXXXXXXXXXXXXX\n\r
742 *  X X0012234567654322100XXX\n\r
743 *  X XXX001123454321100XXXXX\n\r
744 *  X XXXXXXXXXXXXXXXXXXXXXXX\n\r
745 *  X                       X\n\r
746 *  XXXXXXXXXXXXXXXXXXXXXXXXX\n\r
747 *\n\r
748 * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n\r
749 * to request 16 "appropriate" monsters, sorting them by level, and using\n\r
750 * the "even" entries in this sorted list for the contents of the pit.\n\r
751 *\n\r
752 * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n\r
753 * which is handled by requiring a specific "breath" attack for all of the\n\r
754 * dragons.  This may include "multi-hued" breath.  Note that "wyrms" may\n\r
755 * be present in many of the dragon pits, if they have the proper breath.\n\r
756 *\n\r
757 * Note the use of the "get_mon_num_prep()" function, and the special\n\r
758 * "get_mon_num_hook()" restriction function, to prepare the "monster\n\r
759 * allocation table" in such a way as to optimize the selection of\n\r
760 * "appropriate" non-unique monsters for the pit.\n\r
761 *\n\r
762 * Note that the "get_mon_num()" function may (rarely) fail, in which case\n\r
763 * the pit will be empty.\n\r
764 *\n\r
765 * Note that "monster pits" will never contain "unique" monsters.\n\r
766 */\r
767 bool build_type13(void)\r
768 {\r
769         static int placing[][3] = {\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, +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, -7, 1 },{ -3, -5, 1 },{ -3, -4, 1 },\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, -6, 2 },{ -2, -5, 2 },{ -3, -3, 2 },\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, -4, 3 },{ -3, -2, 3 },\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, -3, 4 },{ -3, -1, 4 },\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, -2, 5 },{ -3, 0, 5 },{ -2, +2, 5 },\r
791                 { +2, -2, 5 },{ +3, 0, 5 },{ +2, +2, 5 },\r
792                 { -2, -1, 6 },{ -2, +1, 6 },\r
793                 { +2, -1, 6 },{ +2, +1, 6 },\r
794                 { -2, 0, 7 },{ +2, 0, 7 },\r
795                 { 0, 0, -1 }\r
796         };\r
797 \r
798         POSITION y, x, y1, x1, y2, x2, xval, yval;\r
799         int i, j;\r
800 \r
801         MONRACE_IDX what[16];\r
802 \r
803         monster_type align;\r
804 \r
805         cave_type *c_ptr;\r
806 \r
807         int cur_pit_type = pick_vault_type(pit_types, d_info[dungeon_type].pit);\r
808         vault_aux_type *n_ptr;\r
809 \r
810         /* Only in Angband */\r
811         if (dungeon_type != DUNGEON_ANGBAND) return FALSE;\r
812 \r
813         /* No type available */\r
814         if (cur_pit_type < 0) return FALSE;\r
815 \r
816         n_ptr = &pit_types[cur_pit_type];\r
817 \r
818         /* Process a preparation function if necessary */\r
819         if (n_ptr->prep_func) (*(n_ptr->prep_func))();\r
820 \r
821         /* Prepare allocation table */\r
822         get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit);\r
823 \r
824         align.sub_align = SUB_ALIGN_NEUTRAL;\r
825 \r
826         /* Pick some monster types */\r
827         for (i = 0; i < 16; i++)\r
828         {\r
829                 MONRACE_IDX r_idx = 0;\r
830                 int attempts = 100;\r
831                 monster_race *r_ptr = NULL;\r
832 \r
833                 while (attempts--)\r
834                 {\r
835                         /* Get a (hard) monster type */\r
836                         r_idx = get_mon_num(dun_level + 0);\r
837                         r_ptr = &r_info[r_idx];\r
838 \r
839                         /* Decline incorrect alignment */\r
840                         if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue;\r
841 \r
842                         /* Accept this monster */\r
843                         break;\r
844                 }\r
845 \r
846                 /* Notice failure */\r
847                 if (!r_idx || !attempts) return FALSE;\r
848 \r
849                 /* Note the alignment */\r
850                 if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL;\r
851                 if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD;\r
852 \r
853                 what[i] = r_idx;\r
854         }\r
855 \r
856         /* Find and reserve some space in the dungeon.  Get center of room. */\r
857         if (!find_space(&yval, &xval, 13, 25)) return FALSE;\r
858 \r
859         /* Large room */\r
860         y1 = yval - 5;\r
861         y2 = yval + 5;\r
862         x1 = xval - 11;\r
863         x2 = xval + 11;\r
864 \r
865         /* Fill with inner walls */\r
866         for (y = y1 - 1; y <= y2 + 1; y++)\r
867         {\r
868                 for (x = x1 - 1; x <= x2 + 1; x++)\r
869                 {\r
870                         c_ptr = &cave[y][x];\r
871                         place_inner_grid(c_ptr);\r
872                         c_ptr->info |= (CAVE_ROOM);\r
873                 }\r
874         }\r
875 \r
876         /* Place the floor area 1 */\r
877         for (x = x1 + 3; x <= x2 - 3; x++)\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                 c_ptr = &cave[yval + 2][x];\r
884                 place_floor_grid(c_ptr);\r
885                 add_cave_info(yval + 2, x, CAVE_ICKY);\r
886         }\r
887 \r
888         /* Place the floor area 2 */\r
889         for (x = x1 + 5; x <= x2 - 5; x++)\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                 c_ptr = &cave[yval + 3][x];\r
896                 place_floor_grid(c_ptr);\r
897                 add_cave_info(yval + 3, x, CAVE_ICKY);\r
898         }\r
899 \r
900         /* Corridor */\r
901         for (x = x1; x <= x2; x++)\r
902         {\r
903                 c_ptr = &cave[yval][x];\r
904                 place_floor_grid(c_ptr);\r
905                 c_ptr = &cave[y1][x];\r
906                 place_floor_grid(c_ptr);\r
907                 c_ptr = &cave[y2][x];\r
908                 place_floor_grid(c_ptr);\r
909         }\r
910 \r
911         /* Place the outer walls */\r
912         for (y = y1 - 1; y <= y2 + 1; y++)\r
913         {\r
914                 c_ptr = &cave[y][x1 - 1];\r
915                 place_outer_grid(c_ptr);\r
916                 c_ptr = &cave[y][x2 + 1];\r
917                 place_outer_grid(c_ptr);\r
918         }\r
919         for (x = x1 - 1; x <= x2 + 1; x++)\r
920         {\r
921                 c_ptr = &cave[y1 - 1][x];\r
922                 place_outer_grid(c_ptr);\r
923                 c_ptr = &cave[y2 + 1][x];\r
924                 place_outer_grid(c_ptr);\r
925         }\r
926 \r
927         /* Random corridor */\r
928         if (one_in_(2))\r
929         {\r
930                 for (y = y1; y <= yval; y++)\r
931                 {\r
932                         place_floor_bold(y, x2);\r
933                         place_solid_bold(y, x1 - 1);\r
934                 }\r
935                 for (y = yval; y <= y2 + 1; y++)\r
936                 {\r
937                         place_floor_bold(y, x1);\r
938                         place_solid_bold(y, x2 + 1);\r
939                 }\r
940         }\r
941         else\r
942         {\r
943                 for (y = yval; y <= y2 + 1; y++)\r
944                 {\r
945                         place_floor_bold(y, x1);\r
946                         place_solid_bold(y, x2 + 1);\r
947                 }\r
948                 for (y = y1; y <= yval; y++)\r
949                 {\r
950                         place_floor_bold(y, x2);\r
951                         place_solid_bold(y, x1 - 1);\r
952                 }\r
953         }\r
954 \r
955         /* Place the wall open trap */\r
956         cave[yval][xval].mimic = cave[yval][xval].feat;\r
957         cave[yval][xval].feat = feat_trap_open;\r
958 \r
959         /* Sort the entries */\r
960         for (i = 0; i < 16 - 1; i++)\r
961         {\r
962                 /* Sort the entries */\r
963                 for (j = 0; j < 16 - 1; j++)\r
964                 {\r
965                         int i1 = j;\r
966                         int i2 = j + 1;\r
967 \r
968                         int p1 = r_info[what[i1]].level;\r
969                         int p2 = r_info[what[i2]].level;\r
970 \r
971                         /* Bubble */\r
972                         if (p1 > p2)\r
973                         {\r
974                                 MONRACE_IDX tmp = what[i1];\r
975                                 what[i1] = what[i2];\r
976                                 what[i2] = tmp;\r
977                         }\r
978                 }\r
979         }\r
980 \r
981         msg_format_wizard(CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"),\r
982                 n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));\r
983 \r
984         /* Select the entries */\r
985         for (i = 0; i < 8; i++)\r
986         {\r
987                 /* Every other entry */\r
988                 what[i] = what[i * 2];\r
989 \r
990                 if (cheat_hear)\r
991                 {\r
992                         msg_print(r_name + r_info[what[i]].name);\r
993                 }\r
994         }\r
995 \r
996         for (i = 0; placing[i][2] >= 0; i++)\r
997         {\r
998                 y = yval + placing[i][0];\r
999                 x = xval + placing[i][1];\r
1000                 place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE);\r
1001         }\r
1002 \r
1003         return TRUE;\r
1004 }\r
1005 \r