OSDN Git Service

[Refactor] #38862 Moved object*.c/h to object/
[hengband/hengband.git] / src / object / object-broken.c
1 #include "angband.h"
2 #include "object/object-kind.h"
3 #include "snipe.h"
4 #include "spell/spells-type.h"
5 #include "spell/process-effect.h"
6 #include "effect/effect-characteristics.h"
7
8 /*!
9 * @brief アイテムが酸で破損するかどうかを判定する
10 * @param o_ptr アイテムの情報参照ポインタ
11 * @return 破損するならばTRUEを返す
12 * Note that amulets, rods, and high-level spell books are immune
13 * to "inventory damage" of any kind.  Also sling ammo and shovels.
14 * Does a given class of objects (usually) hate acid?
15 * Note that acid can either melt or corrode something.
16 */
17 bool hates_acid(object_type *o_ptr)
18 {
19         /* Analyze the type */
20         switch (o_ptr->tval)
21         {
22                 /* Wearable items */
23         case TV_ARROW:
24         case TV_BOLT:
25         case TV_BOW:
26         case TV_SWORD:
27         case TV_HAFTED:
28         case TV_POLEARM:
29         case TV_HELM:
30         case TV_CROWN:
31         case TV_SHIELD:
32         case TV_BOOTS:
33         case TV_GLOVES:
34         case TV_CLOAK:
35         case TV_SOFT_ARMOR:
36         case TV_HARD_ARMOR:
37         case TV_DRAG_ARMOR:
38         {
39                 return TRUE;
40         }
41
42         /* Staffs/Scrolls are wood/paper */
43         case TV_STAFF:
44         case TV_SCROLL:
45         {
46                 return TRUE;
47         }
48
49         /* Ouch */
50         case TV_CHEST:
51         {
52                 return TRUE;
53         }
54
55         /* Junk is useless */
56         case TV_SKELETON:
57         case TV_BOTTLE:
58         case TV_JUNK:
59         {
60                 return TRUE;
61         }
62         }
63
64         return FALSE;
65 }
66
67
68 /*!
69 * @brief アイテムが電撃で破損するかどうかを判定する /
70 * Does a given object (usually) hate electricity?
71 * @param o_ptr アイテムの情報参照ポインタ
72 * @return 破損するならばTRUEを返す
73 */
74 bool hates_elec(object_type *o_ptr)
75 {
76         switch (o_ptr->tval)
77         {
78         case TV_RING:
79         case TV_WAND:
80         {
81                 return TRUE;
82         }
83         }
84
85         return FALSE;
86 }
87
88
89 /*!
90 * @brief アイテムが火炎で破損するかどうかを判定する /
91 * Does a given object (usually) hate fire?
92 * @param o_ptr アイテムの情報参照ポインタ
93 * @return 破損するならばTRUEを返す
94 * @details
95 * Hafted/Polearm weapons have wooden shafts.
96 * Arrows/Bows are mostly wooden.
97 */
98 bool hates_fire(object_type *o_ptr)
99 {
100         /* Analyze the type */
101         switch (o_ptr->tval)
102         {
103                 /* Wearable */
104         case TV_LITE:
105         case TV_ARROW:
106         case TV_BOW:
107         case TV_HAFTED:
108         case TV_POLEARM:
109         case TV_BOOTS:
110         case TV_GLOVES:
111         case TV_CLOAK:
112         case TV_SOFT_ARMOR:
113         {
114                 return TRUE;
115         }
116
117         /* Books */
118         case TV_LIFE_BOOK:
119         case TV_SORCERY_BOOK:
120         case TV_NATURE_BOOK:
121         case TV_CHAOS_BOOK:
122         case TV_DEATH_BOOK:
123         case TV_TRUMP_BOOK:
124         case TV_ARCANE_BOOK:
125         case TV_CRAFT_BOOK:
126         case TV_DAEMON_BOOK:
127         case TV_CRUSADE_BOOK:
128         case TV_MUSIC_BOOK:
129         case TV_HISSATSU_BOOK:
130         case TV_HEX_BOOK:
131         {
132                 return TRUE;
133         }
134
135         /* Chests */
136         case TV_CHEST:
137         {
138                 return TRUE;
139         }
140
141         /* Staffs/Scrolls burn */
142         case TV_STAFF:
143         case TV_SCROLL:
144         {
145                 return TRUE;
146         }
147         }
148
149         return FALSE;
150 }
151
152
153 /*!
154 * @brief アイテムが冷気で破損するかどうかを判定する /
155 * Does a given object (usually) hate cold?
156 * @param o_ptr アイテムの情報参照ポインタ
157 * @return 破損するならばTRUEを返す
158 */
159 bool hates_cold(object_type *o_ptr)
160 {
161         switch (o_ptr->tval)
162         {
163         case TV_POTION:
164         case TV_FLASK:
165         case TV_BOTTLE:
166         {
167                 return TRUE;
168         }
169         }
170
171         return FALSE;
172 }
173
174
175 /*!
176 * @brief アイテムが酸で破損するかどうかを判定する(メインルーチン) /
177 * Melt something
178 * @param o_ptr アイテムの情報参照ポインタ
179 * @return 破損するならばTRUEを返す
180 * @todo 統合を検討
181 */
182 int set_acid_destroy(object_type *o_ptr)
183 {
184         BIT_FLAGS flgs[TR_FLAG_SIZE];
185         if (!hates_acid(o_ptr)) return FALSE;
186         object_flags(o_ptr, flgs);
187         if (have_flag(flgs, TR_IGNORE_ACID)) return FALSE;
188         return TRUE;
189 }
190
191
192 /*!
193 * @brief アイテムが電撃で破損するかどうかを判定する(メインルーチン) /
194 * Electrical damage
195 * @param o_ptr アイテムの情報参照ポインタ
196 * @return 破損するならばTRUEを返す
197 * @todo 統合を検討
198 */
199 int set_elec_destroy(object_type *o_ptr)
200 {
201         BIT_FLAGS flgs[TR_FLAG_SIZE];
202         if (!hates_elec(o_ptr)) return FALSE;
203         object_flags(o_ptr, flgs);
204         if (have_flag(flgs, TR_IGNORE_ELEC)) return FALSE;
205         return TRUE;
206 }
207
208
209 /*!
210 * @brief アイテムが火炎で破損するかどうかを判定する(メインルーチン) /
211 * Burn something
212 * @param o_ptr アイテムの情報参照ポインタ
213 * @return 破損するならばTRUEを返す
214 * @todo 統合を検討
215 */
216 int set_fire_destroy(object_type *o_ptr)
217 {
218         BIT_FLAGS flgs[TR_FLAG_SIZE];
219         if (!hates_fire(o_ptr)) return FALSE;
220         object_flags(o_ptr, flgs);
221         if (have_flag(flgs, TR_IGNORE_FIRE)) return FALSE;
222         return TRUE;
223 }
224
225
226 /*!
227 * @brief アイテムが冷気で破損するかどうかを判定する(メインルーチン) /
228 * Freeze things
229 * @param o_ptr アイテムの情報参照ポインタ
230 * @return 破損するならばTRUEを返す
231 * @todo 統合を検討
232 */
233 int set_cold_destroy(object_type *o_ptr)
234 {
235         BIT_FLAGS flgs[TR_FLAG_SIZE];
236         if (!hates_cold(o_ptr)) return FALSE;
237         object_flags(o_ptr, flgs);
238         if (have_flag(flgs, TR_IGNORE_COLD)) return FALSE;
239         return TRUE;
240 }
241
242
243 /*!
244  * @brief 薬の破損効果処理 /
245  * Potions "smash open" and cause an area effect when
246  * @param who 薬破損の主体ID(プレイヤー所持アイテムが壊れた場合0、床上のアイテムの場合モンスターID)
247  * @param y 破壊時のY座標
248  * @param x 破壊時のX座標
249  * @param k_idx 破損した薬のアイテムID
250  * @return 薬を浴びたモンスターが起こるならばTRUEを返す
251  * @details
252  * <pre>
253  * (1) they are shattered while in the player's p_ptr->inventory_list,
254  * due to cold (etc) attacks;
255  * (2) they are thrown at a monster, or obstacle;
256  * (3) they are shattered by a "cold ball" or other such spell
257  * while lying on the floor.
258  *
259  * Arguments:
260  *    who   ---  who caused the potion to shatter (0=player)
261  *          potions that smash on the floor are assumed to
262  *          be caused by no-one (who = 1), as are those that
263  *          shatter inside the player inventory.
264  *          (Not anymore -- I changed this; TY)
265  *    y, x  --- coordinates of the potion (or player if
266  *          the potion was in her inventory);
267  *    o_ptr --- pointer to the potion object.
268  * </pre>
269  */
270 bool potion_smash_effect(player_type *owner_ptr, MONSTER_IDX who, POSITION y, POSITION x, KIND_OBJECT_IDX k_idx)
271 {
272         int radius = 2;
273         int dt = 0;
274         int dam = 0;
275         bool angry = FALSE;
276         object_kind *k_ptr = &k_info[k_idx];
277         switch (k_ptr->sval)
278         {
279         case SV_POTION_SALT_WATER:
280         case SV_POTION_SLIME_MOLD:
281         case SV_POTION_LOSE_MEMORIES:
282         case SV_POTION_DEC_STR:
283         case SV_POTION_DEC_INT:
284         case SV_POTION_DEC_WIS:
285         case SV_POTION_DEC_DEX:
286         case SV_POTION_DEC_CON:
287         case SV_POTION_DEC_CHR:
288         case SV_POTION_WATER:   /* perhaps a 'water' attack? */
289         case SV_POTION_APPLE_JUICE:
290                 return TRUE;
291
292         case SV_POTION_INFRAVISION:
293         case SV_POTION_DETECT_INVIS:
294         case SV_POTION_SLOW_POISON:
295         case SV_POTION_CURE_POISON:
296         case SV_POTION_BOLDNESS:
297         case SV_POTION_RESIST_HEAT:
298         case SV_POTION_RESIST_COLD:
299         case SV_POTION_HEROISM:
300         case SV_POTION_BESERK_STRENGTH:
301         case SV_POTION_RES_STR:
302         case SV_POTION_RES_INT:
303         case SV_POTION_RES_WIS:
304         case SV_POTION_RES_DEX:
305         case SV_POTION_RES_CON:
306         case SV_POTION_RES_CHR:
307         case SV_POTION_INC_STR:
308         case SV_POTION_INC_INT:
309         case SV_POTION_INC_WIS:
310         case SV_POTION_INC_DEX:
311         case SV_POTION_INC_CON:
312         case SV_POTION_INC_CHR:
313         case SV_POTION_AUGMENTATION:
314         case SV_POTION_ENLIGHTENMENT:
315         case SV_POTION_STAR_ENLIGHTENMENT:
316         case SV_POTION_SELF_KNOWLEDGE:
317         case SV_POTION_EXPERIENCE:
318         case SV_POTION_RESISTANCE:
319         case SV_POTION_INVULNERABILITY:
320         case SV_POTION_NEW_LIFE:
321                 /* All of the above potions have no effect when shattered */
322                 return FALSE;
323         case SV_POTION_SLOWNESS:
324                 dt = GF_OLD_SLOW;
325                 dam = 5;
326                 angry = TRUE;
327                 break;
328         case SV_POTION_POISON:
329                 dt = GF_POIS;
330                 dam = 3;
331                 angry = TRUE;
332                 break;
333         case SV_POTION_BLINDNESS:
334                 dt = GF_DARK;
335                 angry = TRUE;
336                 break;
337         case SV_POTION_BOOZE:
338                 dt = GF_OLD_CONF;
339                 angry = TRUE;
340                 break;
341         case SV_POTION_SLEEP:
342                 dt = GF_OLD_SLEEP;
343                 angry = TRUE;
344                 break;
345         case SV_POTION_RUINATION:
346         case SV_POTION_DETONATIONS:
347                 dt = GF_SHARDS;
348                 dam = damroll(25, 25);
349                 angry = TRUE;
350                 break;
351         case SV_POTION_DEATH:
352                 dt = GF_DEATH_RAY;
353                 dam = k_ptr->level * 10;
354                 angry = TRUE;
355                 radius = 1;
356                 break;
357         case SV_POTION_SPEED:
358                 dt = GF_OLD_SPEED;
359                 break;
360         case SV_POTION_CURE_LIGHT:
361                 dt = GF_OLD_HEAL;
362                 dam = damroll(2, 3);
363                 break;
364         case SV_POTION_CURE_SERIOUS:
365                 dt = GF_OLD_HEAL;
366                 dam = damroll(4, 3);
367                 break;
368         case SV_POTION_CURE_CRITICAL:
369         case SV_POTION_CURING:
370                 dt = GF_OLD_HEAL;
371                 dam = damroll(6, 3);
372                 break;
373         case SV_POTION_HEALING:
374                 dt = GF_OLD_HEAL;
375                 dam = damroll(10, 10);
376                 break;
377         case SV_POTION_RESTORE_EXP:
378                 dt = GF_STAR_HEAL;
379                 dam = 0;
380                 radius = 1;
381                 break;
382         case SV_POTION_LIFE:
383                 dt = GF_STAR_HEAL;
384                 dam = damroll(50, 50);
385                 radius = 1;
386                 break;
387         case SV_POTION_STAR_HEALING:
388                 dt = GF_OLD_HEAL;
389                 dam = damroll(50, 50);
390                 radius = 1;
391                 break;
392         case SV_POTION_RESTORE_MANA:
393                 dt = GF_MANA;
394                 dam = damroll(10, 10);
395                 radius = 1;
396                 break;
397         default:
398                 break;
399         }
400
401         (void)project(owner_ptr, who, radius, y, x, dam, dt, (PROJECT_JUMP | PROJECT_ITEM | PROJECT_KILL), -1);
402         return angry;
403 }
404
405 /*!
406  * @brief 矢弾を射撃した場合の破損確率を返す /
407  * Determines the odds of an object breaking when thrown at a monster
408  * @param o_ptr 矢弾のオブジェクト構造体参照ポインタ
409  * @return 破損確率(%)
410  * @details
411  * Note that artifacts never break, see the "drop_near()" function.
412  */
413 PERCENTAGE breakage_chance(player_type *owner_ptr, object_type *o_ptr, bool has_archer_bonus, SPELL_IDX snipe_type)
414 {
415         /* Examine the snipe type */
416         if (snipe_type)
417         {
418                 if (snipe_type == SP_KILL_WALL) return 100;
419                 if (snipe_type == SP_EXPLODE) return 100;
420                 if (snipe_type == SP_PIERCE) return 100;
421                 if (snipe_type == SP_FINAL) return 100;
422                 if (snipe_type == SP_NEEDLE) return 100;
423                 if (snipe_type == SP_EVILNESS) return 40;
424                 if (snipe_type == SP_HOLYNESS) return 40;
425         }
426
427         /* Examine the item type */
428         PERCENTAGE archer_bonus = (has_archer_bonus ? (PERCENTAGE)(owner_ptr->lev - 1) / 7 + 4 : 0);
429         switch (o_ptr->tval)
430         {
431                 /* Always break */
432         case TV_FLASK:
433         case TV_POTION:
434         case TV_BOTTLE:
435         case TV_FOOD:
436         case TV_JUNK:
437                 return 100;
438
439                 /* Often break */
440         case TV_LITE:
441         case TV_SCROLL:
442         case TV_SKELETON:
443                 return 50;
444
445                 /* Sometimes break */
446         case TV_WAND:
447         case TV_SPIKE:
448                 return 25;
449         case TV_ARROW:
450                 return 20 - archer_bonus * 2;
451
452                 /* Rarely break */
453         case TV_SHOT:
454         case TV_BOLT:
455                 return 10 - archer_bonus;
456         default:
457                 return 10;
458         }
459 }