OSDN Git Service

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