OSDN Git Service

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