OSDN Git Service

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