OSDN Git Service

[Refactor] #37353 コメント整理。 / Refactor comments, (Duplicated meaning "Prepare allocatio...
[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         get_mon_num_prep(n_ptr->hook_func, NULL);\r
299 \r
300         align.sub_align = SUB_ALIGN_NEUTRAL;\r
301 \r
302         /* Pick some monster types */\r
303         for (i = 0; i < NUM_NEST_MON_TYPE; i++)\r
304         {\r
305                 MONRACE_IDX r_idx = 0;\r
306                 int attempts = 100;\r
307                 monster_race *r_ptr = NULL;\r
308 \r
309                 while (attempts--)\r
310                 {\r
311                         /* Get a (hard) monster type */\r
312                         r_idx = get_mon_num(dun_level + 11);\r
313                         r_ptr = &r_info[r_idx];\r
314 \r
315                         /* Decline incorrect alignment */\r
316                         if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue;\r
317 \r
318                         /* Accept this monster */\r
319                         break;\r
320                 }\r
321 \r
322                 /* Notice failure */\r
323                 if (!r_idx || !attempts) return FALSE;\r
324 \r
325                 /* Note the alignment */\r
326                 if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL;\r
327                 if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD;\r
328 \r
329                 nest_mon_info[i].r_idx = (s16b)r_idx;\r
330                 nest_mon_info[i].used = FALSE;\r
331         }\r
332 \r
333         /* Find and reserve some space in the dungeon.  Get center of room. */\r
334         if (!find_space(&yval, &xval, 11, 25)) return FALSE;\r
335 \r
336         /* Large room */\r
337         y1 = yval - 4;\r
338         y2 = yval + 4;\r
339         x1 = xval - 11;\r
340         x2 = xval + 11;\r
341 \r
342         /* Place the floor area */\r
343         for (y = y1 - 1; y <= y2 + 1; y++)\r
344         {\r
345                 for (x = x1 - 1; x <= x2 + 1; x++)\r
346                 {\r
347                         c_ptr = &cave[y][x];\r
348                         place_floor_grid(c_ptr);\r
349                         c_ptr->info |= (CAVE_ROOM);\r
350                 }\r
351         }\r
352 \r
353         /* Place the outer walls */\r
354         for (y = y1 - 1; y <= y2 + 1; y++)\r
355         {\r
356                 c_ptr = &cave[y][x1 - 1];\r
357                 place_outer_grid(c_ptr);\r
358                 c_ptr = &cave[y][x2 + 1];\r
359                 place_outer_grid(c_ptr);\r
360         }\r
361         for (x = x1 - 1; x <= x2 + 1; x++)\r
362         {\r
363                 c_ptr = &cave[y1 - 1][x];\r
364                 place_outer_grid(c_ptr);\r
365                 c_ptr = &cave[y2 + 1][x];\r
366                 place_outer_grid(c_ptr);\r
367         }\r
368 \r
369 \r
370         /* Advance to the center room */\r
371         y1 = y1 + 2;\r
372         y2 = y2 - 2;\r
373         x1 = x1 + 2;\r
374         x2 = x2 - 2;\r
375 \r
376         /* The inner walls */\r
377         for (y = y1 - 1; y <= y2 + 1; y++)\r
378         {\r
379                 c_ptr = &cave[y][x1 - 1];\r
380                 place_inner_grid(c_ptr);\r
381                 c_ptr = &cave[y][x2 + 1];\r
382                 place_inner_grid(c_ptr);\r
383         }\r
384 \r
385         for (x = x1 - 1; x <= x2 + 1; x++)\r
386         {\r
387                 c_ptr = &cave[y1 - 1][x];\r
388                 place_inner_grid(c_ptr);\r
389                 c_ptr = &cave[y2 + 1][x];\r
390                 place_inner_grid(c_ptr);\r
391         }\r
392         for (y = y1; y <= y2; y++)\r
393         {\r
394                 for (x = x1; x <= x2; x++)\r
395                 {\r
396                         add_cave_info(y, x, CAVE_ICKY);\r
397                 }\r
398         }\r
399 \r
400         /* Place a secret door */\r
401         switch (randint1(4))\r
402         {\r
403         case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break;\r
404         case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break;\r
405         case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break;\r
406         case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break;\r
407         }\r
408 \r
409         msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, TRUE));\r
410 \r
411         /* Place some monsters */\r
412         for (y = yval - 2; y <= yval + 2; y++)\r
413         {\r
414                 for (x = xval - 9; x <= xval + 9; x++)\r
415                 {\r
416                         MONRACE_IDX r_idx;\r
417 \r
418                         i = randint0(NUM_NEST_MON_TYPE);\r
419                         r_idx = nest_mon_info[i].r_idx;\r
420 \r
421                         /* Place that "random" monster (no groups) */\r
422                         (void)place_monster_aux(0, y, x, r_idx, 0L);\r
423 \r
424                         nest_mon_info[i].used = TRUE;\r
425                 }\r
426         }\r
427 \r
428         if (cheat_room)\r
429         {\r
430                 ang_sort_comp = ang_sort_comp_nest_mon_info;\r
431                 ang_sort_swap = ang_sort_swap_nest_mon_info;\r
432                 ang_sort(nest_mon_info, NULL, NUM_NEST_MON_TYPE);\r
433 \r
434                 /* Dump the entries (prevent multi-printing) */\r
435                 for (i = 0; i < NUM_NEST_MON_TYPE; i++)\r
436                 {\r
437                         if (!nest_mon_info[i].used) break;\r
438                         for (; i < NUM_NEST_MON_TYPE - 1; i++)\r
439                         {\r
440                                 if (nest_mon_info[i].r_idx != nest_mon_info[i + 1].r_idx) break;\r
441                                 if (!nest_mon_info[i + 1].used) break;\r
442                         }\r
443                         msg_format_wizard(CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, r_name + r_info[nest_mon_info[i].r_idx].name);\r
444                 }\r
445         }\r
446 \r
447         return TRUE;\r
448 }\r
449 \r
450 \r
451 /*!\r
452 * @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits\r
453 * @return なし\r
454 * @details\r
455 * A monster pit is a "big" room, with an "inner" room, containing\n\r
456 * a "collection" of monsters of a given type organized in the room.\n\r
457 *\n\r
458 * The inside room in a monster pit appears as shown below, where the\n\r
459 * actual monsters in each location depend on the type of the pit\n\r
460 *\n\r
461 *   XXXXXXXXXXXXXXXXXXXXX\n\r
462 *   X0000000000000000000X\n\r
463 *   X0112233455543322110X\n\r
464 *   X0112233467643322110X\n\r
465 *   X0112233455543322110X\n\r
466 *   X0000000000000000000X\n\r
467 *   XXXXXXXXXXXXXXXXXXXXX\n\r
468 *\n\r
469 * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n\r
470 * to request 16 "appropriate" monsters, sorting them by level, and using\n\r
471 * the "even" entries in this sorted list for the contents of the pit.\n\r
472 *\n\r
473 * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n\r
474 * which is handled by requiring a specific "breath" attack for all of the\n\r
475 * dragons.  This may include "multi-hued" breath.  Note that "wyrms" may\n\r
476 * be present in many of the dragon pits, if they have the proper breath.\n\r
477 *\n\r
478 * Note the use of the "get_mon_num_prep()" function, and the special\n\r
479 * "get_mon_num_hook()" restriction function, to prepare the "monster\n\r
480 * allocation table" in such a way as to optimize the selection of\n\r
481 * "appropriate" non-unique monsters for the pit.\n\r
482 *\n\r
483 * Note that the "get_mon_num()" function may (rarely) fail, in which case\n\r
484 * the pit will be empty.\n\r
485 *\n\r
486 * Note that "monster pits" will never contain "unique" monsters.\n\r
487 */\r
488 bool build_type6(void)\r
489 {\r
490         POSITION y, x, y1, x1, y2, x2, xval, yval;\r
491         int i, j;\r
492 \r
493         MONRACE_IDX what[16];\r
494 \r
495         monster_type align;\r
496 \r
497         cave_type *c_ptr;\r
498 \r
499         int cur_pit_type = pick_vault_type(pit_types, d_info[dungeon_type].pit);\r
500         vault_aux_type *n_ptr;\r
501 \r
502         /* No type available */\r
503         if (cur_pit_type < 0) return FALSE;\r
504 \r
505         n_ptr = &pit_types[cur_pit_type];\r
506 \r
507         /* Process a preparation function if necessary */\r
508         if (n_ptr->prep_func) (*(n_ptr->prep_func))();\r
509         get_mon_num_prep(n_ptr->hook_func, NULL);\r
510 \r
511         align.sub_align = SUB_ALIGN_NEUTRAL;\r
512 \r
513         /* Pick some monster types */\r
514         for (i = 0; i < 16; i++)\r
515         {\r
516                 MONRACE_IDX r_idx = 0;\r
517                 int attempts = 100;\r
518                 monster_race *r_ptr = NULL;\r
519 \r
520                 while (attempts--)\r
521                 {\r
522                         /* Get a (hard) monster type */\r
523                         r_idx = get_mon_num(dun_level + 11);\r
524                         r_ptr = &r_info[r_idx];\r
525 \r
526                         /* Decline incorrect alignment */\r
527                         if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue;\r
528 \r
529                         /* Accept this monster */\r
530                         break;\r
531                 }\r
532 \r
533                 /* Notice failure */\r
534                 if (!r_idx || !attempts) return FALSE;\r
535 \r
536                 /* Note the alignment */\r
537                 if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL;\r
538                 if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD;\r
539 \r
540                 what[i] = r_idx;\r
541         }\r
542 \r
543         /* Find and reserve some space in the dungeon.  Get center of room. */\r
544         if (!find_space(&yval, &xval, 11, 25)) return FALSE;\r
545 \r
546         /* Large room */\r
547         y1 = yval - 4;\r
548         y2 = yval + 4;\r
549         x1 = xval - 11;\r
550         x2 = xval + 11;\r
551 \r
552         /* Place the floor area */\r
553         for (y = y1 - 1; y <= y2 + 1; y++)\r
554         {\r
555                 for (x = x1 - 1; x <= x2 + 1; x++)\r
556                 {\r
557                         c_ptr = &cave[y][x];\r
558                         place_floor_grid(c_ptr);\r
559                         c_ptr->info |= (CAVE_ROOM);\r
560                 }\r
561         }\r
562 \r
563         /* Place the outer walls */\r
564         for (y = y1 - 1; y <= y2 + 1; y++)\r
565         {\r
566                 c_ptr = &cave[y][x1 - 1];\r
567                 place_outer_grid(c_ptr);\r
568                 c_ptr = &cave[y][x2 + 1];\r
569                 place_outer_grid(c_ptr);\r
570         }\r
571         for (x = x1 - 1; x <= x2 + 1; x++)\r
572         {\r
573                 c_ptr = &cave[y1 - 1][x];\r
574                 place_outer_grid(c_ptr);\r
575                 c_ptr = &cave[y2 + 1][x];\r
576                 place_outer_grid(c_ptr);\r
577         }\r
578 \r
579         /* Advance to the center room */\r
580         y1 = y1 + 2;\r
581         y2 = y2 - 2;\r
582         x1 = x1 + 2;\r
583         x2 = x2 - 2;\r
584 \r
585         /* The inner walls */\r
586         for (y = y1 - 1; y <= y2 + 1; y++)\r
587         {\r
588                 c_ptr = &cave[y][x1 - 1];\r
589                 place_inner_grid(c_ptr);\r
590                 c_ptr = &cave[y][x2 + 1];\r
591                 place_inner_grid(c_ptr);\r
592         }\r
593         for (x = x1 - 1; x <= x2 + 1; x++)\r
594         {\r
595                 c_ptr = &cave[y1 - 1][x];\r
596                 place_inner_grid(c_ptr);\r
597                 c_ptr = &cave[y2 + 1][x];\r
598                 place_inner_grid(c_ptr);\r
599         }\r
600         for (y = y1; y <= y2; y++)\r
601         {\r
602                 for (x = x1; x <= x2; x++)\r
603                 {\r
604                         add_cave_info(y, x, CAVE_ICKY);\r
605                 }\r
606         }\r
607 \r
608         /* Place a secret door */\r
609         switch (randint1(4))\r
610         {\r
611         case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break;\r
612         case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break;\r
613         case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break;\r
614         case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break;\r
615         }\r
616 \r
617         /* Sort the entries */\r
618         for (i = 0; i < 16 - 1; i++)\r
619         {\r
620                 /* Sort the entries */\r
621                 for (j = 0; j < 16 - 1; j++)\r
622                 {\r
623                         int i1 = j;\r
624                         int i2 = j + 1;\r
625 \r
626                         int p1 = r_info[what[i1]].level;\r
627                         int p2 = r_info[what[i2]].level;\r
628 \r
629                         /* Bubble */\r
630                         if (p1 > p2)\r
631                         {\r
632                                 MONRACE_IDX tmp = what[i1];\r
633                                 what[i1] = what[i2];\r
634                                 what[i2] = tmp;\r
635                         }\r
636                 }\r
637         }\r
638 \r
639         msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));\r
640 \r
641         /* Select the entries */\r
642         for (i = 0; i < 8; i++)\r
643         {\r
644                 /* Every other entry */\r
645                 what[i] = what[i * 2];\r
646                 msg_format_wizard(CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_name + r_info[what[i]].name);\r
647         }\r
648 \r
649         /* Top and bottom rows */\r
650         for (x = xval - 9; x <= xval + 9; x++)\r
651         {\r
652                 place_monster_aux(0, yval - 2, x, what[0], PM_NO_KAGE);\r
653                 place_monster_aux(0, yval + 2, x, what[0], PM_NO_KAGE);\r
654         }\r
655 \r
656         /* Middle columns */\r
657         for (y = yval - 1; y <= yval + 1; y++)\r
658         {\r
659                 place_monster_aux(0, y, xval - 9, what[0], PM_NO_KAGE);\r
660                 place_monster_aux(0, y, xval + 9, what[0], PM_NO_KAGE);\r
661 \r
662                 place_monster_aux(0, y, xval - 8, what[1], PM_NO_KAGE);\r
663                 place_monster_aux(0, y, xval + 8, what[1], PM_NO_KAGE);\r
664 \r
665                 place_monster_aux(0, y, xval - 7, what[1], PM_NO_KAGE);\r
666                 place_monster_aux(0, y, xval + 7, what[1], PM_NO_KAGE);\r
667 \r
668                 place_monster_aux(0, y, xval - 6, what[2], PM_NO_KAGE);\r
669                 place_monster_aux(0, y, xval + 6, what[2], PM_NO_KAGE);\r
670 \r
671                 place_monster_aux(0, y, xval - 5, what[2], PM_NO_KAGE);\r
672                 place_monster_aux(0, y, xval + 5, what[2], PM_NO_KAGE);\r
673 \r
674                 place_monster_aux(0, y, xval - 4, what[3], PM_NO_KAGE);\r
675                 place_monster_aux(0, y, xval + 4, what[3], PM_NO_KAGE);\r
676 \r
677                 place_monster_aux(0, y, xval - 3, what[3], PM_NO_KAGE);\r
678                 place_monster_aux(0, y, xval + 3, what[3], PM_NO_KAGE);\r
679 \r
680                 place_monster_aux(0, y, xval - 2, what[4], PM_NO_KAGE);\r
681                 place_monster_aux(0, y, xval + 2, what[4], PM_NO_KAGE);\r
682         }\r
683 \r
684         /* Above/Below the center monster */\r
685         for (x = xval - 1; x <= xval + 1; x++)\r
686         {\r
687                 place_monster_aux(0, yval + 1, x, what[5], PM_NO_KAGE);\r
688                 place_monster_aux(0, yval - 1, x, what[5], PM_NO_KAGE);\r
689         }\r
690 \r
691         /* Next to the center monster */\r
692         place_monster_aux(0, yval, xval + 1, what[6], PM_NO_KAGE);\r
693         place_monster_aux(0, yval, xval - 1, what[6], PM_NO_KAGE);\r
694 \r
695         /* Center monster */\r
696         place_monster_aux(0, yval, xval, what[7], PM_NO_KAGE);\r
697 \r
698         return TRUE;\r
699 }\r
700 \r
701 \r
702 \r
703 /*\r
704 * Helper function for "trapped monster pit"\r
705 */\r
706 static bool vault_aux_trapped_pit(MONRACE_IDX r_idx)\r
707 {\r
708         monster_race *r_ptr = &r_info[r_idx];\r
709 \r
710         if (!vault_monster_okay(r_idx)) return (FALSE);\r
711 \r
712         /* No wall passing monster */\r
713         if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE);\r
714 \r
715         return (TRUE);\r
716 }\r
717 \r
718 \r
719 /*!\r
720 * @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits\r
721 * @return なし\r
722 * @details\r
723 * A trapped monster pit is a "big" room with a straight corridor in\n\r
724 * which wall opening traps are placed, and with two "inner" rooms\n\r
725 * containing a "collection" of monsters of a given type organized in\n\r
726 * the room.\n\r
727 *\n\r
728 * The trapped monster pit appears as shown below, where the actual\n\r
729 * monsters in each location depend on the type of the pit\n\r
730 *\n\r
731 *  XXXXXXXXXXXXXXXXXXXXXXXXX\n\r
732 *  X                       X\n\r
733 *  XXXXXXXXXXXXXXXXXXXXXXX X\n\r
734 *  XXXXX001123454321100XXX X\n\r
735 *  XXX0012234567654322100X X\n\r
736 *  XXXXXXXXXXXXXXXXXXXXXXX X\n\r
737 *  X           ^           X\n\r
738 *  X XXXXXXXXXXXXXXXXXXXXXXX\n\r
739 *  X X0012234567654322100XXX\n\r
740 *  X XXX001123454321100XXXXX\n\r
741 *  X XXXXXXXXXXXXXXXXXXXXXXX\n\r
742 *  X                       X\n\r
743 *  XXXXXXXXXXXXXXXXXXXXXXXXX\n\r
744 *\n\r
745 * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n\r
746 * to request 16 "appropriate" monsters, sorting them by level, and using\n\r
747 * the "even" entries in this sorted list for the contents of the pit.\n\r
748 *\n\r
749 * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n\r
750 * which is handled by requiring a specific "breath" attack for all of the\n\r
751 * dragons.  This may include "multi-hued" breath.  Note that "wyrms" may\n\r
752 * be present in many of the dragon pits, if they have the proper breath.\n\r
753 *\n\r
754 * Note the use of the "get_mon_num_prep()" function, and the special\n\r
755 * "get_mon_num_hook()" restriction function, to prepare the "monster\n\r
756 * allocation table" in such a way as to optimize the selection of\n\r
757 * "appropriate" non-unique monsters for the pit.\n\r
758 *\n\r
759 * Note that the "get_mon_num()" function may (rarely) fail, in which case\n\r
760 * the pit will be empty.\n\r
761 *\n\r
762 * Note that "monster pits" will never contain "unique" monsters.\n\r
763 */\r
764 bool build_type13(void)\r
765 {\r
766         static int placing[][3] = {\r
767                 { -2, -9, 0 },{ -2, -8, 0 },{ -3, -7, 0 },{ -3, -6, 0 },\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, -7, 1 },{ -3, -5, 1 },{ -3, -4, 1 },\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, -6, 2 },{ -2, -5, 2 },{ -3, -3, 2 },\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, -4, 3 },{ -3, -2, 3 },\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, -3, 4 },{ -3, -1, 4 },\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, -2, 5 },{ -3, 0, 5 },{ -2, +2, 5 },\r
788                 { +2, -2, 5 },{ +3, 0, 5 },{ +2, +2, 5 },\r
789                 { -2, -1, 6 },{ -2, +1, 6 },\r
790                 { +2, -1, 6 },{ +2, +1, 6 },\r
791                 { -2, 0, 7 },{ +2, 0, 7 },\r
792                 { 0, 0, -1 }\r
793         };\r
794 \r
795         POSITION y, x, y1, x1, y2, x2, xval, yval;\r
796         int i, j;\r
797 \r
798         MONRACE_IDX what[16];\r
799 \r
800         monster_type align;\r
801 \r
802         cave_type *c_ptr;\r
803 \r
804         int cur_pit_type = pick_vault_type(pit_types, d_info[dungeon_type].pit);\r
805         vault_aux_type *n_ptr;\r
806 \r
807         /* Only in Angband */\r
808         if (dungeon_type != DUNGEON_ANGBAND) return FALSE;\r
809 \r
810         /* No type available */\r
811         if (cur_pit_type < 0) return FALSE;\r
812 \r
813         n_ptr = &pit_types[cur_pit_type];\r
814 \r
815         /* Process a preparation function if necessary */\r
816         if (n_ptr->prep_func) (*(n_ptr->prep_func))();\r
817         get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit);\r
818 \r
819         align.sub_align = SUB_ALIGN_NEUTRAL;\r
820 \r
821         /* Pick some monster types */\r
822         for (i = 0; i < 16; i++)\r
823         {\r
824                 MONRACE_IDX r_idx = 0;\r
825                 int attempts = 100;\r
826                 monster_race *r_ptr = NULL;\r
827 \r
828                 while (attempts--)\r
829                 {\r
830                         /* Get a (hard) monster type */\r
831                         r_idx = get_mon_num(dun_level + 0);\r
832                         r_ptr = &r_info[r_idx];\r
833 \r
834                         /* Decline incorrect alignment */\r
835                         if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue;\r
836 \r
837                         /* Accept this monster */\r
838                         break;\r
839                 }\r
840 \r
841                 /* Notice failure */\r
842                 if (!r_idx || !attempts) return FALSE;\r
843 \r
844                 /* Note the alignment */\r
845                 if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL;\r
846                 if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD;\r
847 \r
848                 what[i] = r_idx;\r
849         }\r
850 \r
851         /* Find and reserve some space in the dungeon.  Get center of room. */\r
852         if (!find_space(&yval, &xval, 13, 25)) return FALSE;\r
853 \r
854         /* Large room */\r
855         y1 = yval - 5;\r
856         y2 = yval + 5;\r
857         x1 = xval - 11;\r
858         x2 = xval + 11;\r
859 \r
860         /* Fill with inner walls */\r
861         for (y = y1 - 1; y <= y2 + 1; y++)\r
862         {\r
863                 for (x = x1 - 1; x <= x2 + 1; x++)\r
864                 {\r
865                         c_ptr = &cave[y][x];\r
866                         place_inner_grid(c_ptr);\r
867                         c_ptr->info |= (CAVE_ROOM);\r
868                 }\r
869         }\r
870 \r
871         /* Place the floor area 1 */\r
872         for (x = x1 + 3; x <= x2 - 3; x++)\r
873         {\r
874                 c_ptr = &cave[yval - 2][x];\r
875                 place_floor_grid(c_ptr);\r
876                 add_cave_info(yval - 2, x, CAVE_ICKY);\r
877 \r
878                 c_ptr = &cave[yval + 2][x];\r
879                 place_floor_grid(c_ptr);\r
880                 add_cave_info(yval + 2, x, CAVE_ICKY);\r
881         }\r
882 \r
883         /* Place the floor area 2 */\r
884         for (x = x1 + 5; x <= x2 - 5; x++)\r
885         {\r
886                 c_ptr = &cave[yval - 3][x];\r
887                 place_floor_grid(c_ptr);\r
888                 add_cave_info(yval - 3, x, CAVE_ICKY);\r
889 \r
890                 c_ptr = &cave[yval + 3][x];\r
891                 place_floor_grid(c_ptr);\r
892                 add_cave_info(yval + 3, x, CAVE_ICKY);\r
893         }\r
894 \r
895         /* Corridor */\r
896         for (x = x1; x <= x2; x++)\r
897         {\r
898                 c_ptr = &cave[yval][x];\r
899                 place_floor_grid(c_ptr);\r
900                 c_ptr = &cave[y1][x];\r
901                 place_floor_grid(c_ptr);\r
902                 c_ptr = &cave[y2][x];\r
903                 place_floor_grid(c_ptr);\r
904         }\r
905 \r
906         /* Place the outer walls */\r
907         for (y = y1 - 1; y <= y2 + 1; y++)\r
908         {\r
909                 c_ptr = &cave[y][x1 - 1];\r
910                 place_outer_grid(c_ptr);\r
911                 c_ptr = &cave[y][x2 + 1];\r
912                 place_outer_grid(c_ptr);\r
913         }\r
914         for (x = x1 - 1; x <= x2 + 1; x++)\r
915         {\r
916                 c_ptr = &cave[y1 - 1][x];\r
917                 place_outer_grid(c_ptr);\r
918                 c_ptr = &cave[y2 + 1][x];\r
919                 place_outer_grid(c_ptr);\r
920         }\r
921 \r
922         /* Random corridor */\r
923         if (one_in_(2))\r
924         {\r
925                 for (y = y1; y <= yval; y++)\r
926                 {\r
927                         place_floor_bold(y, x2);\r
928                         place_solid_bold(y, x1 - 1);\r
929                 }\r
930                 for (y = yval; y <= y2 + 1; y++)\r
931                 {\r
932                         place_floor_bold(y, x1);\r
933                         place_solid_bold(y, x2 + 1);\r
934                 }\r
935         }\r
936         else\r
937         {\r
938                 for (y = yval; y <= y2 + 1; y++)\r
939                 {\r
940                         place_floor_bold(y, x1);\r
941                         place_solid_bold(y, x2 + 1);\r
942                 }\r
943                 for (y = y1; y <= yval; y++)\r
944                 {\r
945                         place_floor_bold(y, x2);\r
946                         place_solid_bold(y, x1 - 1);\r
947                 }\r
948         }\r
949 \r
950         /* Place the wall open trap */\r
951         cave[yval][xval].mimic = cave[yval][xval].feat;\r
952         cave[yval][xval].feat = feat_trap_open;\r
953 \r
954         /* Sort the entries */\r
955         for (i = 0; i < 16 - 1; i++)\r
956         {\r
957                 /* Sort the entries */\r
958                 for (j = 0; j < 16 - 1; j++)\r
959                 {\r
960                         int i1 = j;\r
961                         int i2 = j + 1;\r
962 \r
963                         int p1 = r_info[what[i1]].level;\r
964                         int p2 = r_info[what[i2]].level;\r
965 \r
966                         /* Bubble */\r
967                         if (p1 > p2)\r
968                         {\r
969                                 MONRACE_IDX tmp = what[i1];\r
970                                 what[i1] = what[i2];\r
971                                 what[i2] = tmp;\r
972                         }\r
973                 }\r
974         }\r
975 \r
976         msg_format_wizard(CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"),\r
977                 n_ptr->name, pit_subtype_string(cur_pit_type, FALSE));\r
978 \r
979         /* Select the entries */\r
980         for (i = 0; i < 8; i++)\r
981         {\r
982                 /* Every other entry */\r
983                 what[i] = what[i * 2];\r
984 \r
985                 if (cheat_hear)\r
986                 {\r
987                         msg_print(r_name + r_info[what[i]].name);\r
988                 }\r
989         }\r
990 \r
991         for (i = 0; placing[i][2] >= 0; i++)\r
992         {\r
993                 y = yval + placing[i][0];\r
994                 x = xval + placing[i][1];\r
995                 place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE);\r
996         }\r
997 \r
998         return TRUE;\r
999 }\r
1000 \r