OSDN Git Service

[Refactor] #37353 歌に関するマクロ定義を realm-song.h へ移動.
[hengband/hengband.git] / src / chest.c
1 
2 #include "angband.h"
3 #include "util.h"
4
5 #include "spells.h"
6 #include "spells-summon.h"
7 #include "floor.h"
8 #include "trap.h"
9 #include "player-status.h"
10 #include "player-effects.h"
11 #include "grid.h"
12 #include "realm-song.h"
13
14 /*!
15 * @brief 箱からアイテムを引き出す /
16 * Allocates objects upon opening a chest    -BEN-
17 * @param scatter TRUEならばトラップによるアイテムの拡散処理
18 * @param y 箱の存在するマスのY座標
19 * @param x 箱の存在するマスのX座標
20 * @param o_idx 箱のオブジェクトID
21 * @return なし
22 * @details
23 * <pre>
24 * Disperse treasures from the given chest, centered at (x,y).
25 *
26 * Small chests often contain "gold", while Large chests always contain
27 * items.  Wooden chests contain 2 items, Iron chests contain 4 items,
28 * and Steel chests contain 6 items.  The "value" of the items in a
29 * chest is based on the "power" of the chest, which is in current_world_ptr->game_turn based
30 * on the level on which the chest is generated.
31 * </pre>
32 */
33 void chest_death(bool scatter, POSITION y, POSITION x, OBJECT_IDX o_idx)
34 {
35         int number;
36
37         bool small;
38         BIT_FLAGS mode = AM_GOOD | AM_FORBID_CHEST;
39
40         object_type forge;
41         object_type *q_ptr;
42
43         object_type *o_ptr = &current_floor_ptr->o_list[o_idx];
44
45
46         /* Small chests often hold "gold" */
47         small = (o_ptr->sval < SV_CHEST_MIN_LARGE);
48
49         /* Determine how much to drop (see above) */
50         number = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2;
51
52         if (o_ptr->sval == SV_CHEST_KANDUME)
53         {
54                 number = 5;
55                 small = FALSE;
56                 mode |= AM_GREAT;
57                 current_floor_ptr->object_level = o_ptr->xtra3;
58         }
59         else
60         {
61                 /* Determine the "value" of the items */
62                 current_floor_ptr->object_level = ABS(o_ptr->pval) + 10;
63         }
64
65         /* Zero pval means empty chest */
66         if (!o_ptr->pval) number = 0;
67
68
69         /* Drop some objects (non-chests) */
70         for (; number > 0; --number)
71         {
72                 q_ptr = &forge;
73                 object_wipe(q_ptr);
74
75                 /* Small chests often drop gold */
76                 if (small && (randint0(100) < 25))
77                 {
78                         /* Make some gold */
79                         if (!make_gold(q_ptr)) continue;
80                 }
81
82                 /* Otherwise drop an item */
83                 else
84                 {
85                         /* Make a good object */
86                         if (!make_object(q_ptr, mode)) continue;
87                 }
88
89                 /* If chest scatters its contents, pick any floor square. */
90                 if (scatter)
91                 {
92                         int i;
93                         for (i = 0; i < 200; i++)
94                         {
95                                 /* Pick a totally random spot. */
96                                 y = randint0(MAX_HGT);
97                                 x = randint0(MAX_WID);
98
99                                 /* Must be an empty floor. */
100                                 if (!cave_empty_bold(y, x)) continue;
101
102                                 /* Place the object there. */
103                                 (void)drop_near(q_ptr, -1, y, x);
104
105                                 /* Done. */
106                                 break;
107                         }
108                 }
109                 /* Normally, drop object near the chest. */
110                 else (void)drop_near(q_ptr, -1, y, x);
111         }
112
113         /* Reset the object level */
114         current_floor_ptr->object_level = current_floor_ptr->base_level;
115
116         /* Empty */
117         o_ptr->pval = 0;
118
119         /* Known */
120         object_known(o_ptr);
121 }
122
123
124 /*!
125 * @brief 箱のトラップ処理 /
126 * Chests have traps too.
127 * @param y 箱の存在するマスのY座標
128 * @param x 箱の存在するマスのX座標
129 * @param o_idx 箱のオブジェクトID
130 * @return なし
131 * @details
132 * <pre>
133 * Exploding chest destroys contents (and traps).
134 * Note that the chest itself is never destroyed.
135 * </pre>
136 */
137 void chest_trap(POSITION y, POSITION x, OBJECT_IDX o_idx)
138 {
139         int i, trap;
140
141         object_type *o_ptr = &current_floor_ptr->o_list[o_idx];
142
143         int mon_level = o_ptr->xtra3;
144
145         /* Ignore disarmed chests */
146         if (o_ptr->pval <= 0) return;
147
148         /* Obtain the traps */
149         trap = chest_traps[o_ptr->pval];
150
151         /* Lose strength */
152         if (trap & (CHEST_LOSE_STR))
153         {
154                 msg_print(_("仕掛けられていた小さな針に刺されてしまった!", "A small needle has pricked you!"));
155                 take_hit(DAMAGE_NOESCAPE, damroll(1, 4), _("毒針", "a poison needle"), -1);
156                 (void)do_dec_stat(A_STR);
157         }
158
159         /* Lose constitution */
160         if (trap & (CHEST_LOSE_CON))
161         {
162                 msg_print(_("仕掛けられていた小さな針に刺されてしまった!", "A small needle has pricked you!"));
163                 take_hit(DAMAGE_NOESCAPE, damroll(1, 4), _("毒針", "a poison needle"), -1);
164                 (void)do_dec_stat(A_CON);
165         }
166
167         /* Poison */
168         if (trap & (CHEST_POISON))
169         {
170                 msg_print(_("突如吹き出した緑色のガスに包み込まれた!", "A puff of green gas surrounds you!"));
171                 if (!(p_ptr->resist_pois || IS_OPPOSE_POIS()))
172                 {
173                         (void)set_poisoned(p_ptr->poisoned + 10 + randint1(20));
174                 }
175         }
176
177         /* Paralyze */
178         if (trap & (CHEST_PARALYZE))
179         {
180                 msg_print(_("突如吹き出した黄色いガスに包み込まれた!", "A puff of yellow gas surrounds you!"));
181                 if (!p_ptr->free_act)
182                 {
183                         (void)set_paralyzed(p_ptr->paralyzed + 10 + randint1(20));
184                 }
185         }
186
187         /* Summon monsters */
188         if (trap & (CHEST_SUMMON))
189         {
190                 int num = 2 + randint1(3);
191                 msg_print(_("突如吹き出した煙に包み込まれた!", "You are enveloped in a cloud of smoke!"));
192                 for (i = 0; i < num; i++)
193                 {
194                         if (randint1(100)<current_floor_ptr->dun_level)
195                                 activate_hi_summon(p_ptr->y, p_ptr->x, FALSE);
196                         else
197                                 (void)summon_specific(0, y, x, mon_level, 0, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
198                 }
199         }
200
201         /* Elemental summon. */
202         if (trap & (CHEST_E_SUMMON))
203         {
204                 msg_print(_("宝を守るためにエレメンタルが現れた!", "Elemental beings appear to protect their treasures!"));
205                 for (i = 0; i < randint1(3) + 5; i++)
206                 {
207                         (void)summon_specific(0, y, x, mon_level, SUMMON_ELEMENTAL, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
208                 }
209         }
210
211         /* Force clouds, then summon birds. */
212         if (trap & (CHEST_BIRD_STORM))
213         {
214                 msg_print(_("鳥の群れがあなたを取り巻いた!", "A storm of birds swirls around you!"));
215
216                 for (i = 0; i < randint1(3) + 3; i++)
217                         (void)fire_meteor(-1, GF_FORCE, y, x, o_ptr->pval / 5, 7);
218
219                 for (i = 0; i < randint1(5) + o_ptr->pval / 5; i++)
220                 {
221                         (void)summon_specific(0, y, x, mon_level, SUMMON_BIRD, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
222                 }
223         }
224
225         /* Various colorful summonings. */
226         if (trap & (CHEST_H_SUMMON))
227         {
228                 /* Summon demons. */
229                 if (one_in_(4))
230                 {
231                         msg_print(_("炎と硫黄の雲の中に悪魔が姿を現した!", "Demons materialize in clouds of fire and brimstone!"));
232                         for (i = 0; i < randint1(3) + 2; i++)
233                         {
234                                 (void)fire_meteor(-1, GF_FIRE, y, x, 10, 5);
235                                 (void)summon_specific(0, y, x, mon_level, SUMMON_DEMON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
236                         }
237                 }
238
239                 /* Summon dragons. */
240                 else if (one_in_(3))
241                 {
242                         msg_print(_("暗闇にドラゴンの影がぼんやりと現れた!", "Draconic forms loom out of the darkness!"));
243                         for (i = 0; i < randint1(3) + 2; i++)
244                         {
245                                 (void)summon_specific(0, y, x, mon_level, SUMMON_DRAGON, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
246                         }
247                 }
248
249                 /* Summon hybrids. */
250                 else if (one_in_(2))
251                 {
252                         msg_print(_("奇妙な姿の怪物が襲って来た!", "Creatures strange and twisted assault you!"));
253                         for (i = 0; i < randint1(5) + 3; i++)
254                         {
255                                 (void)summon_specific(0, y, x, mon_level, SUMMON_HYBRID, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
256                         }
257                 }
258
259                 /* Summon vortices (scattered) */
260                 else
261                 {
262                         msg_print(_("渦巻が合体し、破裂した!", "Vortices coalesce and wreak destruction!"));
263                         for (i = 0; i < randint1(3) + 2; i++)
264                         {
265                                 (void)summon_specific(0, y, x, mon_level, SUMMON_VORTEX, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET));
266                         }
267                 }
268         }
269
270         /* Dispel player. */
271         if ((trap & (CHEST_RUNES_OF_EVIL)) && o_ptr->k_idx)
272         {
273                 /* Determine how many nasty tricks can be played. */
274                 int nasty_tricks_count = 4 + randint0(3);
275
276                 msg_print(_("恐ろしい声が響いた:  「暗闇が汝をつつまん!」", "Hideous voices bid:  'Let the darkness have thee!'"));
277                 /* This is gonna hurt... */
278                 for (; nasty_tricks_count > 0; nasty_tricks_count--)
279                 {
280                         /* ...but a high saving throw does help a little. */
281                         if (randint1(100 + o_ptr->pval * 2) > p_ptr->skill_sav)
282                         {
283                                 if (one_in_(6)) take_hit(DAMAGE_NOESCAPE, damroll(5, 20), _("破滅のトラップの宝箱", "a chest dispel-player trap"), -1);
284                                 else if (one_in_(5)) (void)set_cut(p_ptr->cut + 200);
285                                 else if (one_in_(4))
286                                 {
287                                         if (!p_ptr->free_act)
288                                                 (void)set_paralyzed(p_ptr->paralyzed + 2 +
289                                                         randint0(6));
290                                         else
291                                                 (void)set_stun(p_ptr->stun + 10 +
292                                                         randint0(100));
293                                 }
294                                 else if (one_in_(3)) apply_disenchant(0);
295                                 else if (one_in_(2))
296                                 {
297                                         (void)do_dec_stat(A_STR);
298                                         (void)do_dec_stat(A_DEX);
299                                         (void)do_dec_stat(A_CON);
300                                         (void)do_dec_stat(A_INT);
301                                         (void)do_dec_stat(A_WIS);
302                                         (void)do_dec_stat(A_CHR);
303                                 }
304                                 else (void)fire_meteor(-1, GF_NETHER, y, x, 150, 1);
305                         }
306                 }
307         }
308
309         /* Aggravate monsters. */
310         if (trap & (CHEST_ALARM))
311         {
312                 msg_print(_("けたたましい音が鳴り響いた!", "An alarm sounds!"));
313                 aggravate_monsters(0);
314         }
315
316         /* Explode */
317         if ((trap & (CHEST_EXPLODE)) && o_ptr->k_idx)
318         {
319                 msg_print(_("突然、箱が爆発した!", "There is a sudden explosion!"));
320                 msg_print(_("箱の中の物はすべて粉々に砕け散った!", "Everything inside the chest is destroyed!"));
321                 o_ptr->pval = 0;
322                 sound(SOUND_EXPLODE);
323                 take_hit(DAMAGE_ATTACK, damroll(5, 8), _("爆発する箱", "an exploding chest"), -1);
324         }
325         /* Scatter contents. */
326         if ((trap & (CHEST_SCATTER)) && o_ptr->k_idx)
327         {
328                 msg_print(_("宝箱の中身はダンジョンじゅうに散乱した!", "The contents of the chest scatter all over the dungeon!"));
329                 chest_death(TRUE, y, x, o_idx);
330                 o_ptr->pval = 0;
331         }
332 }
333