OSDN Git Service

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