OSDN Git Service

[Refactor] #37353 関数宣言のいくつかを floor-save.h へ移動。
[hengband/hengband.git] / src / trap.c
1 #include "angband.h"
2 #include "floor.h"
3 #include "trap.h"
4 #include "player-damage.h"
5 #include "player-move.h"
6 #include "spells-summon.h"
7 #include "quest.h"
8 #include "artifact.h"
9 #include "feature.h"
10 #include "player-status.h"
11 #include "grid.h"
12 #include "spells.h"
13 #include "floor-save.h"
14
15 static s16b normal_traps[MAX_NORMAL_TRAPS];
16
17
18 /*!
19  * @brief 箱のトラップテーブル
20  * @details
21  * <pre>
22  * Each chest has a certain set of traps, determined by pval
23  * Each chest has a "pval" from 1 to the chest level (max 55)
24  * If the "pval" is negative then the trap has been disarmed
25  * The "pval" of a chest determines the quality of its treasure
26  * Note that disarming a trap on a chest also removes the lock.
27  * </pre>
28  */
29 const int chest_traps[64] =
30 {
31         0,                                      /* 0 == empty */
32         (CHEST_POISON),
33         (CHEST_LOSE_STR),
34         (CHEST_LOSE_CON),
35         (CHEST_LOSE_STR),
36         (CHEST_LOSE_CON),                       /* 5 == best small wooden */
37         0,
38         (CHEST_ALARM),
39         (CHEST_ALARM),
40         (CHEST_LOSE_STR),
41         (CHEST_LOSE_CON),
42         (CHEST_POISON),
43         (CHEST_SCATTER),
44         (CHEST_LOSE_STR | CHEST_LOSE_CON),
45         (CHEST_LOSE_STR | CHEST_LOSE_CON),
46         (CHEST_SUMMON),                 /* 15 == best large wooden */
47         0,
48         (CHEST_ALARM),
49         (CHEST_SCATTER),
50         (CHEST_PARALYZE),
51         (CHEST_LOSE_STR | CHEST_LOSE_CON),
52         (CHEST_SUMMON),
53         (CHEST_PARALYZE),
54         (CHEST_LOSE_STR),
55         (CHEST_LOSE_CON),
56         (CHEST_EXPLODE),                        /* 25 == best small iron */
57         0,
58         (CHEST_E_SUMMON),
59         (CHEST_POISON | CHEST_LOSE_CON),
60         (CHEST_LOSE_STR | CHEST_LOSE_CON),
61         (CHEST_EXPLODE | CHEST_SUMMON),
62         (CHEST_BIRD_STORM),
63         (CHEST_POISON | CHEST_SUMMON),
64         (CHEST_E_SUMMON | CHEST_ALARM),
65         (CHEST_EXPLODE),
66         (CHEST_EXPLODE | CHEST_SUMMON), /* 35 == best large iron */
67         0,
68         (CHEST_SUMMON | CHEST_ALARM),
69         (CHEST_EXPLODE),
70         (CHEST_EXPLODE | CHEST_SUMMON),
71         (CHEST_EXPLODE | CHEST_SUMMON),
72         (CHEST_POISON | CHEST_PARALYZE),
73         (CHEST_EXPLODE),
74         (CHEST_BIRD_STORM),
75         (CHEST_EXPLODE | CHEST_E_SUMMON | CHEST_ALARM),
76         (CHEST_H_SUMMON),        /* 45 == best small steel */
77         0,
78         (CHEST_EXPLODE | CHEST_SUMMON | CHEST_ALARM),
79         (CHEST_BIRD_STORM),
80         (CHEST_RUNES_OF_EVIL),
81         (CHEST_EXPLODE | CHEST_SUMMON | CHEST_ALARM),
82         (CHEST_BIRD_STORM | CHEST_ALARM),
83         (CHEST_H_SUMMON | CHEST_ALARM),
84         (CHEST_RUNES_OF_EVIL),
85         (CHEST_H_SUMMON | CHEST_SCATTER | CHEST_ALARM),
86         (CHEST_RUNES_OF_EVIL | CHEST_EXPLODE),  /* 55 == best large steel */
87         (CHEST_EXPLODE | CHEST_SUMMON),
88         (CHEST_EXPLODE | CHEST_SUMMON),
89         (CHEST_EXPLODE | CHEST_SUMMON),
90         (CHEST_EXPLODE | CHEST_SUMMON),
91         (CHEST_EXPLODE | CHEST_SUMMON),
92         (CHEST_EXPLODE | CHEST_SUMMON),
93         (CHEST_EXPLODE | CHEST_SUMMON),
94         (CHEST_EXPLODE | CHEST_SUMMON),
95 };
96
97
98 /*!
99 * @brief タグに従って、基本トラップテーブルを初期化する / Initialize arrays for normal traps
100 * @return なし
101 */
102 void init_normal_traps(void)
103 {
104         int cur_trap = 0;
105
106         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPDOOR");
107         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_PIT");
108         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SPIKED_PIT");
109         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON_PIT");
110         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TY_CURSE");
111         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TELEPORT");
112         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_FIRE");
113         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ACID");
114         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLOW");
115         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_STR");
116         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_DEX");
117         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_LOSE_CON");
118         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_BLIND");
119         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_CONFUSE");
120         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_POISON");
121         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_SLEEP");
122         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_TRAPS");
123         normal_traps[cur_trap++] = f_tag_to_index_in_init("TRAP_ALARM");
124 }
125
126 /*!
127 * @brief 基本トラップをランダムに選択する /
128 * Get random trap
129 * @return 選択したトラップのID
130 * @details
131 * This routine should be redone to reflect trap "level".\n
132 * That is, it does not make sense to have spiked pits at 50 feet.\n
133 * Actually, it is not this routine, but the "trap instantiation"\n
134 * code, which should also check for "trap doors" on quest levels.\n
135 */
136 FEAT_IDX choose_random_trap(void)
137 {
138         FEAT_IDX feat;
139
140         /* Pick a trap */
141         while (1)
142         {
143                 /* Hack -- pick a trap */
144                 feat = normal_traps[randint0(MAX_NORMAL_TRAPS)];
145
146                 /* Accept non-trapdoors */
147                 if (!have_flag(f_info[feat].flags, FF_MORE)) break;
148
149                 /* Hack -- no trap doors on special levels */
150                 if (p_ptr->inside_arena || quest_number(current_floor_ptr->dun_level)) continue;
151
152                 /* Hack -- no trap doors on the deepest level */
153                 if (current_floor_ptr->dun_level >= d_info[p_ptr->dungeon_idx].maxdepth) continue;
154
155                 break;
156         }
157
158         return feat;
159 }
160
161 /*!
162 * @brief マスに存在するトラップを秘匿する /
163 * Disclose an invisible trap
164 * @param y 秘匿したいマスのY座標
165 * @param x 秘匿したいマスのX座標
166 * @return なし
167 */
168 void disclose_grid(POSITION y, POSITION x)
169 {
170         grid_type *g_ptr = &current_floor_ptr->grid_array[y][x];
171
172         if (cave_have_flag_grid(g_ptr, FF_SECRET))
173         {
174                 /* No longer hidden */
175                 cave_alter_feat(y, x, FF_SECRET);
176         }
177         else if (g_ptr->mimic)
178         {
179                 /* No longer hidden */
180                 g_ptr->mimic = 0;
181
182                 note_spot(y, x);
183                 lite_spot(y, x);
184         }
185 }
186
187 /*!
188 * @brief マスをトラップを配置する /
189 * The location must be a legal, naked, floor grid.
190 * @param y 配置したいマスのY座標
191 * @param x 配置したいマスのX座標
192 * @return
193 * Note that all traps start out as "invisible" and "untyped", and then\n
194 * when they are "discovered" (by detecting them or setting them off),\n
195 * the trap is "instantiated" as a visible, "typed", trap.\n
196 */
197 void place_trap(POSITION y, POSITION x)
198 {
199         grid_type *g_ptr = &current_floor_ptr->grid_array[y][x];
200
201         /* Paranoia -- verify location */
202         if (!in_bounds(y, x)) return;
203
204         /* Require empty, clean, floor grid */
205         if (!cave_clean_bold(y, x)) return;
206
207         /* Place an invisible trap */
208         g_ptr->mimic = g_ptr->feat;
209         g_ptr->feat = choose_random_trap();
210 }
211
212
213
214 /*!
215 * @brief プレイヤーへのトラップ命中判定 /
216 * Determine if a trap affects the player.
217 * @param power 基本回避難度
218 * @return トラップが命中した場合TRUEを返す。
219 * @details
220 * Always miss 5% of the time, Always hit 5% of the time.
221 * Otherwise, match trap power against player armor.
222 */
223 static int check_hit(int power)
224 {
225         int k;
226         ARMOUR_CLASS ac;
227
228         /* Percentile dice */
229         k = randint0(100);
230
231         /* Hack -- 5% hit, 5% miss */
232         if (k < 10) return (k < 5);
233
234         if (p_ptr->pseikaku == SEIKAKU_NAMAKE)
235                 if (one_in_(20)) return (TRUE);
236
237         /* Paranoia -- No power */
238         if (power <= 0) return (FALSE);
239
240         /* Total armor */
241         ac = p_ptr->ac + p_ptr->to_a;
242
243         /* Power competes against Armor */
244         if (randint1(power) > ((ac * 3) / 4)) return (TRUE);
245
246         /* Assume miss */
247         return (FALSE);
248 }
249
250
251 /*!
252 * @brief 落とし穴系トラップの判定とプレイヤーの被害処理
253 * @param trap_feat_type トラップの種別ID
254 * @return なし
255 */
256 static void hit_trap_pit(int trap_feat_type)
257 {
258         HIT_POINT dam;
259         concptr trap_name = "";
260         concptr spike_name = "";
261
262         switch (trap_feat_type)
263         {
264         case TRAP_PIT:
265                 trap_name = _("落とし穴", "a pit trap");
266                 break;
267         case TRAP_SPIKED_PIT:
268                 trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit");
269                 spike_name = _("スパイク", "spikes");
270                 break;
271         case TRAP_POISON_PIT:
272                 trap_name = _("スパイクが敷かれた落とし穴", "a spiked pit");
273                 spike_name = _("毒を塗られたスパイク", "poisonous spikes");
274                 break;
275         default:
276                 return;
277         }
278
279         if (p_ptr->levitation)
280         {
281                 msg_format(_("%sを飛び越えた。", "You fly over %s."), trap_name);
282                 return;
283         }
284
285         msg_format(_("%sに落ちてしまった!", "You have fallen into %s!"), trap_name);
286
287         /* Base damage */
288         dam = damroll(2, 6);
289
290         /* Extra spike damage */
291         if ((trap_feat_type == TRAP_SPIKED_PIT || trap_feat_type == TRAP_POISON_PIT) &&
292                 one_in_(2))
293         {
294                 msg_format(_("%sが刺さった!", "You are impaled on %s!"), spike_name);
295
296                 dam = dam * 2;
297                 (void)set_cut(p_ptr->cut + randint1(dam));
298
299                 if (trap_feat_type == TRAP_POISON_PIT) {
300                         if (p_ptr->resist_pois || IS_OPPOSE_POIS())
301                         {
302                                 msg_print(_("しかし毒の影響はなかった!", "The poison does not affect you!"));
303                         }
304                         else
305                         {
306                                 dam = dam * 2;
307                                 (void)set_poisoned(p_ptr->poisoned + randint1(dam));
308                         }
309                 }
310         }
311
312         take_hit(DAMAGE_NOESCAPE, dam, trap_name, -1);
313 }
314
315 /*!
316 * @brief ダーツ系トラップ(通常ダメージ)の判定とプレイヤーの被害処理
317 * @return ダーツが命中した場合TRUEを返す
318 */
319 static bool hit_trap_dart(void)
320 {
321         bool hit = FALSE;
322
323         if (check_hit(125))
324         {
325                 msg_print(_("小さなダーツが飛んできて刺さった!", "A small dart hits you!"));
326                 take_hit(DAMAGE_ATTACK, damroll(1, 4), _("ダーツの罠", "a dart trap"), -1);
327                 if (!CHECK_MULTISHADOW()) hit = TRUE;
328         }
329         else
330         {
331                 msg_print(_("小さなダーツが飛んできた!が、運良く当たらなかった。", "A small dart barely misses you."));
332         }
333
334         return hit;
335 }
336
337 /*!
338 * @brief ダーツ系トラップ(通常ダメージ+能力値減少)の判定とプレイヤーの被害処理
339 * @param stat 低下する能力値ID
340 * @return なし
341 */
342 static void hit_trap_lose_stat(int stat)
343 {
344         if (hit_trap_dart())
345         {
346                 do_dec_stat(stat);
347         }
348 }
349
350 /*!
351 * @brief ダーツ系トラップ(通常ダメージ+減速)の判定とプレイヤーの被害処理
352 * @return なし
353 */
354 static void hit_trap_slow(void)
355 {
356         if (hit_trap_dart())
357         {
358                 set_slow(p_ptr->slow + randint0(20) + 20, FALSE);
359         }
360 }
361
362 /*!
363 * @brief ダーツ系トラップ(通常ダメージ+状態異常)の判定とプレイヤーの被害処理
364 * @param trap_message メッセージの補完文字列
365 * @param resist 状態異常に抵抗する判定が出たならTRUE
366 * @param set_status 状態異常を指定する関数ポインタ
367 * @param current_world_ptr->game_turn 状態異常の追加ターン量
368 * @return なし
369 */
370 static void hit_trap_set_abnormal_status(concptr trap_message, bool resist, bool(*set_status)(IDX), IDX turn_aux)
371 {
372         msg_print(trap_message);
373         if (!resist)
374         {
375                 set_status(turn_aux);
376         }
377 }
378
379 /*!
380 * @brief プレイヤーへのトラップ作動処理メインルーチン /
381 * Handle player hitting a real trap
382 * @param break_trap 作動後のトラップ破壊が確定しているならばTRUE
383 * @return なし
384 */
385 void hit_trap(bool break_trap)
386 {
387         int i, num, dam;
388         POSITION x = p_ptr->x, y = p_ptr->y;
389         grid_type *g_ptr = &current_floor_ptr->grid_array[y][x];
390         feature_type *f_ptr = &f_info[g_ptr->feat];
391         int trap_feat_type = have_flag(f_ptr->flags, FF_TRAP) ? f_ptr->subtype : NOT_TRAP;
392         concptr name = _("トラップ", "a trap");
393
394         disturb(FALSE, TRUE);
395
396         cave_alter_feat(y, x, FF_HIT_TRAP);
397
398         /* Analyze */
399         switch (trap_feat_type)
400         {
401         case TRAP_TRAPDOOR:
402         {
403                 if (p_ptr->levitation)
404                 {
405                         msg_print(_("落とし戸を飛び越えた。", "You fly over a trap door."));
406                 }
407                 else
408                 {
409                         msg_print(_("落とし戸に落ちた!", "You have fallen through a trap door!"));
410                         if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
411                                 msg_print(_("くっそ~!", ""));
412                         else if((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
413                                 msg_print(_("ジュラル星人の仕業に違いない!", ""));
414
415
416                         sound(SOUND_FALL);
417                         dam = damroll(2, 8);
418                         name = _("落とし戸", "a trap door");
419
420                         take_hit(DAMAGE_NOESCAPE, dam, name, -1);
421
422                         /* Still alive and autosave enabled */
423                         if (autosave_l && (p_ptr->chp >= 0))
424                                 do_cmd_save_game(TRUE);
425
426                         do_cmd_write_nikki(NIKKI_BUNSHOU, 0, _("落とし戸に落ちた", "You have fallen through a trap door!"));
427                         prepare_change_floor_mode(CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
428                         p_ptr->leaving = TRUE;
429                 }
430                 break;
431         }
432
433         case TRAP_PIT:
434         case TRAP_SPIKED_PIT:
435         case TRAP_POISON_PIT:
436         {
437                 hit_trap_pit(trap_feat_type);
438                 break;
439         }
440
441         case TRAP_TY_CURSE:
442         {
443                 msg_print(_("何かがピカッと光った!", "There is a flash of shimmering light!"));
444                 num = 2 + randint1(3);
445                 for (i = 0; i < num; i++)
446                 {
447                         (void)summon_specific(0, y, x, current_floor_ptr->dun_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET), '\0');
448                 }
449
450                 if (current_floor_ptr->dun_level > randint1(100)) /* No nasty effect for low levels */
451                 {
452                         bool stop_ty = FALSE;
453                         int count = 0;
454
455                         do
456                         {
457                                 stop_ty = activate_ty_curse(stop_ty, &count);
458                         } while (one_in_(6));
459                 }
460                 break;
461         }
462
463         case TRAP_TELEPORT:
464         {
465                 msg_print(_("テレポート・トラップにひっかかった!", "You hit a teleport trap!"));
466                 teleport_player(100, TELEPORT_PASSIVE);
467                 break;
468         }
469
470         case TRAP_FIRE:
471         {
472                 msg_print(_("炎に包まれた!", "You are enveloped in flames!"));
473                 dam = damroll(4, 6);
474                 (void)fire_dam(dam, _("炎のトラップ", "a fire trap"), -1, FALSE);
475                 break;
476         }
477
478         case TRAP_ACID:
479         {
480                 msg_print(_("酸が吹きかけられた!", "You are splashed with acid!"));
481                 dam = damroll(4, 6);
482                 (void)acid_dam(dam, _("酸のトラップ", "an acid trap"), -1, FALSE);
483                 break;
484         }
485
486         case TRAP_SLOW:
487         {
488                 hit_trap_slow();
489                 break;
490         }
491
492         case TRAP_LOSE_STR:
493         {
494                 hit_trap_lose_stat(A_STR);
495                 break;
496         }
497
498         case TRAP_LOSE_DEX:
499         {
500                 hit_trap_lose_stat(A_DEX);
501                 break;
502         }
503
504         case TRAP_LOSE_CON:
505         {
506                 hit_trap_lose_stat(A_CON);
507                 break;
508         }
509
510         case TRAP_BLIND:
511         {
512                 hit_trap_set_abnormal_status(
513                         _("黒いガスに包み込まれた!", "A black gas surrounds you!"),
514                         p_ptr->resist_blind,
515                         set_blind, p_ptr->blind + (TIME_EFFECT)randint0(50) + 25);
516                 break;
517         }
518
519         case TRAP_CONFUSE:
520         {
521                 hit_trap_set_abnormal_status(
522                         _("きらめくガスに包み込まれた!", "A gas of scintillating colors surrounds you!"),
523                         p_ptr->resist_conf,
524                         set_confused, p_ptr->confused + (TIME_EFFECT)randint0(20) + 10);
525                 break;
526         }
527
528         case TRAP_POISON:
529         {
530                 hit_trap_set_abnormal_status(
531                         _("刺激的な緑色のガスに包み込まれた!", "A pungent green gas surrounds you!"),
532                         p_ptr->resist_pois || IS_OPPOSE_POIS(),
533                         set_poisoned, p_ptr->poisoned + (TIME_EFFECT)randint0(20) + 10);
534                 break;
535         }
536
537         case TRAP_SLEEP:
538         {
539                 msg_print(_("奇妙な白い霧に包まれた!", "A strange white mist surrounds you!"));
540                 if (!p_ptr->free_act)
541                 {
542                         msg_print(_("あなたは眠りに就いた。", "You fall asleep."));
543
544                         if (ironman_nightmare)
545                         {
546                                 msg_print(_("身の毛もよだつ光景が頭に浮かんだ。", "A horrible vision enters your mind."));
547
548                                 /* Have some nightmares */
549                                 sanity_blast(NULL, FALSE);
550
551                         }
552                         (void)set_paralyzed(p_ptr->paralyzed + randint0(10) + 5);
553                 }
554                 break;
555         }
556
557         case TRAP_TRAPS:
558         {
559                 msg_print(_("まばゆい閃光が走った!", "There is a bright flash of light!"));
560                 /* Make some new traps */
561                 project(0, 1, y, x, 0, GF_MAKE_TRAP, PROJECT_HIDE | PROJECT_JUMP | PROJECT_GRID, -1);
562
563                 break;
564         }
565
566         case TRAP_ALARM:
567         {
568                 msg_print(_("けたたましい音が鳴り響いた!", "An alarm sounds!"));
569
570                 aggravate_monsters(0);
571
572                 break;
573         }
574
575         case TRAP_OPEN:
576         {
577                 msg_print(_("大音響と共にまわりの壁が崩れた!", "Suddenly, surrounding walls are opened!"));
578                 (void)project(0, 3, y, x, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1);
579                 (void)project(0, 3, y, x - 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1);
580                 (void)project(0, 3, y, x + 4, 0, GF_DISINTEGRATE, PROJECT_GRID | PROJECT_HIDE, -1);
581                 aggravate_monsters(0);
582
583                 break;
584         }
585
586         case TRAP_ARMAGEDDON:
587         {
588                 static int levs[10] = { 0, 0, 20, 10, 5, 3, 2, 1, 1, 1 };
589                 int evil_idx = 0, good_idx = 0;
590
591                 DEPTH lev;
592                 msg_print(_("突然天界の戦争に巻き込まれた!", "Suddenly, you are surrounded by immotal beings!"));
593
594                 /* Summon Demons and Angels */
595                 for (lev = current_floor_ptr->dun_level; lev >= 20; lev -= 1 + lev / 16)
596                 {
597                         num = levs[MIN(lev / 10, 9)];
598                         for (i = 0; i < num; i++)
599                         {
600                                 POSITION x1 = rand_spread(x, 7);
601                                 POSITION y1 = rand_spread(y, 5);
602
603                                 /* Skip illegal grids */
604                                 if (!in_bounds(y1, x1)) continue;
605
606                                 /* Require line of projection */
607                                 if (!projectable(p_ptr->y, p_ptr->x, y1, x1)) continue;
608
609                                 if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_EVIL, (PM_NO_PET), '\0'))
610                                         evil_idx = hack_m_idx_ii;
611
612                                 if (summon_specific(0, y1, x1, lev, SUMMON_ARMAGE_GOOD, (PM_NO_PET), '\0'))
613                                 {
614                                         good_idx = hack_m_idx_ii;
615                                 }
616
617                                 /* Let them fight each other */
618                                 if (evil_idx && good_idx)
619                                 {
620                                         monster_type *evil_ptr = &current_floor_ptr->m_list[evil_idx];
621                                         monster_type *good_ptr = &current_floor_ptr->m_list[good_idx];
622                                         evil_ptr->target_y = good_ptr->fy;
623                                         evil_ptr->target_x = good_ptr->fx;
624                                         good_ptr->target_y = evil_ptr->fy;
625                                         good_ptr->target_x = evil_ptr->fx;
626                                 }
627                         }
628                 }
629                 break;
630         }
631
632         case TRAP_PIRANHA:
633         {
634                 msg_print(_("突然壁から水が溢れ出した!ピラニアがいる!", "Suddenly, the room is filled with water with piranhas!"));
635
636                 /* Water fills room */
637                 fire_ball_hide(GF_WATER_FLOW, 0, 1, 10);
638
639                 /* Summon Piranhas */
640                 num = 1 + current_floor_ptr->dun_level / 20;
641                 for (i = 0; i < num; i++)
642                 {
643                         (void)summon_specific(0, y, x, current_floor_ptr->dun_level, SUMMON_PIRANHAS, (PM_ALLOW_GROUP | PM_NO_PET), '\0');
644                 }
645                 break;
646         }
647         }
648
649         if (break_trap && is_trap(g_ptr->feat))
650         {
651                 cave_alter_feat(y, x, FF_DISARM);
652                 msg_print(_("トラップを粉砕した。", "You destroyed the trap."));
653         }
654 }