OSDN Git Service

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