OSDN Git Service

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