OSDN Git Service

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