OSDN Git Service

[Refactor] #3677 object_known() をItemEntity のオブジェクトメソッドに繰り込んだ
[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/attribute-types.h"
8 #include "effect/effect-characteristics.h"
9 #include "effect/effect-processor.h"
10 #include "mind/snipe-types.h"
11 #include "object-enchant/tr-types.h"
12 #include "object/tval-types.h"
13 #include "sv-definition/sv-potion-types.h"
14 #include "system/baseitem-info.h"
15 #include "system/item-entity.h"
16 #include "system/player-type-definition.h"
17 #include "util/bit-flags-calculator.h"
18
19 ObjectBreaker::ObjectBreaker(tr_type ignore_flg)
20     : ignore_flg(ignore_flg)
21 {
22 }
23
24 BreakerAcid::BreakerAcid()
25     : ObjectBreaker(TR_IGNORE_ACID)
26 {
27 }
28
29 BreakerElec::BreakerElec()
30     : ObjectBreaker(TR_IGNORE_ELEC)
31 {
32 }
33
34 BreakerFire::BreakerFire()
35     : ObjectBreaker(TR_IGNORE_FIRE)
36 {
37 }
38
39 BreakerCold::BreakerCold()
40     : ObjectBreaker(TR_IGNORE_COLD)
41 {
42 }
43
44 /*!
45  * @brief アイテムが酸で破損するかどうかを判定する
46  * @param o_ptr アイテムの情報参照ポインタ
47  * @return 破損するならばTRUEを返す
48  * Note that amulets, rods, and high-level spell books are immune
49  * to "inventory damage" of any kind.  Also sling ammo and shovels.
50  * Does a given class of objects (usually) hate acid?
51  * Note that acid can either melt or corrode something.
52  */
53 bool BreakerAcid::hates(ItemEntity *o_ptr) const
54 {
55     switch (o_ptr->bi_key.tval()) {
56     case ItemKindType::ARROW:
57     case ItemKindType::BOLT:
58     case ItemKindType::BOW:
59     case ItemKindType::SWORD:
60     case ItemKindType::HAFTED:
61     case ItemKindType::POLEARM:
62     case ItemKindType::HELM:
63     case ItemKindType::CROWN:
64     case ItemKindType::SHIELD:
65     case ItemKindType::BOOTS:
66     case ItemKindType::GLOVES:
67     case ItemKindType::CLOAK:
68     case ItemKindType::SOFT_ARMOR:
69     case ItemKindType::HARD_ARMOR:
70     case ItemKindType::DRAG_ARMOR:
71     case ItemKindType::STAFF:
72     case ItemKindType::SCROLL:
73     case ItemKindType::CHEST:
74     case ItemKindType::SKELETON:
75     case ItemKindType::BOTTLE:
76     case ItemKindType::JUNK:
77         return true;
78     default:
79         return false;
80     }
81 }
82
83 /*!
84  * @brief アイテムが電撃で破損するかどうかを判定する /
85  * Does a given object (usually) hate electricity?
86  * @param o_ptr アイテムの情報参照ポインタ
87  * @return 破損するならばTRUEを返す
88  */
89 bool BreakerElec::hates(ItemEntity *o_ptr) const
90 {
91     switch (o_ptr->bi_key.tval()) {
92     case ItemKindType::RING:
93     case ItemKindType::WAND:
94         return true;
95     default:
96         return false;
97     }
98 }
99
100 /*!
101  * @brief アイテムが火炎で破損するかどうかを判定する /
102  * Does a given object (usually) hate fire?
103  * @param o_ptr アイテムの情報参照ポインタ
104  * @return 破損するならばTRUEを返す
105  * @details
106  * Hafted/Polearm weapons have wooden shafts.
107  * Arrows/Bows are mostly wooden.
108  */
109 bool BreakerFire::hates(ItemEntity *o_ptr) const
110 {
111     switch (o_ptr->bi_key.tval()) {
112     case ItemKindType::LITE:
113     case ItemKindType::ARROW:
114     case ItemKindType::BOW:
115     case ItemKindType::HAFTED:
116     case ItemKindType::POLEARM:
117     case ItemKindType::BOOTS:
118     case ItemKindType::GLOVES:
119     case ItemKindType::CLOAK:
120     case ItemKindType::SOFT_ARMOR:
121     case ItemKindType::LIFE_BOOK:
122     case ItemKindType::SORCERY_BOOK:
123     case ItemKindType::NATURE_BOOK:
124     case ItemKindType::CHAOS_BOOK:
125     case ItemKindType::DEATH_BOOK:
126     case ItemKindType::TRUMP_BOOK:
127     case ItemKindType::ARCANE_BOOK:
128     case ItemKindType::CRAFT_BOOK:
129     case ItemKindType::DEMON_BOOK:
130     case ItemKindType::CRUSADE_BOOK:
131     case ItemKindType::MUSIC_BOOK:
132     case ItemKindType::HISSATSU_BOOK:
133     case ItemKindType::HEX_BOOK:
134     case ItemKindType::CHEST:
135     case ItemKindType::STAFF:
136     case ItemKindType::SCROLL:
137         return true;
138     default:
139         return false;
140     }
141 }
142
143 /*!
144  * @brief アイテムが冷気で破損するかどうかを判定する /
145  * Does a given object (usually) hate cold?
146  * @param o_ptr アイテムの情報参照ポインタ
147  * @return 破損するならばTRUEを返す
148  */
149 bool BreakerCold::hates(ItemEntity *o_ptr) const
150 {
151     switch (o_ptr->bi_key.tval()) {
152     case ItemKindType::POTION:
153     case ItemKindType::FLASK:
154     case ItemKindType::BOTTLE:
155         return true;
156     default:
157         return false;
158     }
159 }
160
161 /*!
162  * @brief アイテムが属性で破損するかどうかを判定する(メインルーチン) /
163  * Destroy things
164  * @param o_ptr アイテムの情報参照ポインタ
165  * @return 破損するならばTRUEを返す
166  * @todo 統合を検討
167  */
168 bool ObjectBreaker::can_destroy(ItemEntity *o_ptr) const
169 {
170     if (!this->hates(o_ptr)) {
171         return false;
172     }
173
174     return o_ptr->get_flags().has_not(this->ignore_flg);
175 }
176
177 /*!
178  * @brief 薬の破損効果処理 /
179  * Potions "smash open" and cause an area effect when
180  * @param who 薬破損の主体ID(プレイヤー所持アイテムが壊れた場合0、床上のアイテムの場合モンスターID)
181  * @param y 破壊時のY座標
182  * @param x 破壊時のX座標
183  * @param bi_id 破損した薬のアイテムID
184  * @return 薬を浴びたモンスターが起こるならばTRUEを返す
185  * @details
186  * <pre>
187  * (1) they are shattered while in the player's p_ptr->inventory_list,
188  * due to cold (etc) attacks;
189  * (2) they are thrown at a monster, or obstacle;
190  * (3) they are shattered by a "cold ball" or other such spell
191  * while lying on the floor.
192  *
193  * Arguments:
194  *    who   ---  who caused the potion to shatter (0=player)
195  *          potions that smash on the floor are assumed to
196  *          be caused by no-one (who = 1), as are those that
197  *          shatter inside the player inventory.
198  *          (Not anymore -- I changed this; TY)
199  *    y, x  --- coordinates of the potion (or player if
200  *          the potion was in her inventory);
201  *    o_ptr --- pointer to the potion object.
202  * </pre>
203  */
204 bool potion_smash_effect(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSITION x, short bi_id)
205 {
206     int radius = 2;
207     AttributeType dt = AttributeType::NONE;
208     int dam = 0;
209     bool angry = false;
210     const auto &baseitem = baseitems_info[bi_id];
211     switch (baseitem.bi_key.sval().value()) {
212     case SV_POTION_SALT_WATER:
213     case SV_POTION_SLIME_MOLD:
214     case SV_POTION_LOSE_MEMORIES:
215     case SV_POTION_DEC_STR:
216     case SV_POTION_DEC_INT:
217     case SV_POTION_DEC_WIS:
218     case SV_POTION_DEC_DEX:
219     case SV_POTION_DEC_CON:
220     case SV_POTION_DEC_CHR:
221     case SV_POTION_WATER: /* perhaps a 'water' attack? */
222     case SV_POTION_APPLE_JUICE:
223         return true;
224     case SV_POTION_INFRAVISION:
225     case SV_POTION_DETECT_INVIS:
226     case SV_POTION_SLOW_POISON:
227     case SV_POTION_CURE_POISON:
228     case SV_POTION_BOLDNESS:
229     case SV_POTION_RESIST_HEAT:
230     case SV_POTION_RESIST_COLD:
231     case SV_POTION_HEROISM:
232     case SV_POTION_BESERK_STRENGTH:
233     case SV_POTION_RES_STR:
234     case SV_POTION_RES_INT:
235     case SV_POTION_RES_WIS:
236     case SV_POTION_RES_DEX:
237     case SV_POTION_RES_CON:
238     case SV_POTION_RES_CHR:
239     case SV_POTION_INC_STR:
240     case SV_POTION_INC_INT:
241     case SV_POTION_INC_WIS:
242     case SV_POTION_INC_DEX:
243     case SV_POTION_INC_CON:
244     case SV_POTION_INC_CHR:
245     case SV_POTION_AUGMENTATION:
246     case SV_POTION_ENLIGHTENMENT:
247     case SV_POTION_STAR_ENLIGHTENMENT:
248     case SV_POTION_SELF_KNOWLEDGE:
249     case SV_POTION_EXPERIENCE:
250     case SV_POTION_RESISTANCE:
251     case SV_POTION_INVULNERABILITY:
252     case SV_POTION_NEW_LIFE:
253         /* All of the above potions have no effect when shattered */
254         return false;
255     case SV_POTION_SLOWNESS:
256         dt = AttributeType::OLD_SLOW;
257         dam = 5;
258         angry = true;
259         break;
260     case SV_POTION_POISON:
261         dt = AttributeType::POIS;
262         dam = 3;
263         angry = true;
264         break;
265     case SV_POTION_BLINDNESS:
266         dt = AttributeType::DARK;
267         angry = true;
268         break;
269     case SV_POTION_BOOZE:
270         dt = AttributeType::OLD_CONF;
271         angry = true;
272         break;
273     case SV_POTION_SLEEP:
274         dt = AttributeType::OLD_SLEEP;
275         angry = true;
276         break;
277     case SV_POTION_RUINATION:
278     case SV_POTION_DETONATIONS:
279         dt = AttributeType::SHARDS;
280         dam = damroll(25, 25);
281         angry = true;
282         break;
283     case SV_POTION_DEATH:
284         dt = AttributeType::DEATH_RAY;
285         dam = baseitem.level * 10;
286         angry = true;
287         radius = 1;
288         break;
289     case SV_POTION_SPEED:
290         dt = AttributeType::OLD_SPEED;
291         break;
292     case SV_POTION_CURE_LIGHT:
293         dt = AttributeType::OLD_HEAL;
294         dam = damroll(2, 3);
295         break;
296     case SV_POTION_CURE_SERIOUS:
297         dt = AttributeType::OLD_HEAL;
298         dam = damroll(4, 3);
299         break;
300     case SV_POTION_CURE_CRITICAL:
301     case SV_POTION_CURING:
302         dt = AttributeType::OLD_HEAL;
303         dam = damroll(6, 3);
304         break;
305     case SV_POTION_HEALING:
306         dt = AttributeType::OLD_HEAL;
307         dam = damroll(10, 10);
308         break;
309     case SV_POTION_RESTORE_EXP:
310         dt = AttributeType::STAR_HEAL;
311         dam = 0;
312         radius = 1;
313         break;
314     case SV_POTION_LIFE:
315         dt = AttributeType::STAR_HEAL;
316         dam = damroll(50, 50);
317         radius = 1;
318         break;
319     case SV_POTION_STAR_HEALING:
320         dt = AttributeType::OLD_HEAL;
321         dam = damroll(50, 50);
322         radius = 1;
323         break;
324     case SV_POTION_RESTORE_MANA:
325         dt = AttributeType::MANA;
326         dam = damroll(10, 10);
327         radius = 1;
328         break;
329     case SV_POTION_POLY_SELF:
330         dt = AttributeType::NEXUS;
331         dam = damroll(20, 20);
332         radius = 1;
333         break;
334     default:
335         break;
336     }
337
338     (void)project(player_ptr, who, radius, y, x, dam, dt, (PROJECT_JUMP | PROJECT_ITEM | PROJECT_KILL));
339     return angry;
340 }
341
342 /*!
343  * @brief 矢弾を射撃した場合の破損確率を返す /
344  * Determines the odds of an object breaking when thrown at a monster
345  * @param o_ptr 矢弾のオブジェクト構造体参照ポインタ
346  * @return 破損確率(%)
347  * @details
348  * Note that artifacts never break, see the "drop_near()" function.
349  */
350 PERCENTAGE breakage_chance(PlayerType *player_ptr, ItemEntity *o_ptr, bool has_archer_bonus, SPELL_IDX snipe_type)
351 {
352     /* Examine the snipe type */
353     if (snipe_type) {
354         if (snipe_type == SP_KILL_WALL) {
355             return 100;
356         }
357         if (snipe_type == SP_EXPLODE) {
358             return 100;
359         }
360         if (snipe_type == SP_PIERCE) {
361             return 100;
362         }
363         if (snipe_type == SP_FINAL) {
364             return 100;
365         }
366         if (snipe_type == SP_NEEDLE) {
367             return 100;
368         }
369         if (snipe_type == SP_EVILNESS) {
370             return 40;
371         }
372         if (snipe_type == SP_HOLYNESS) {
373             return 40;
374         }
375     }
376
377     /* Examine the item type */
378     PERCENTAGE archer_bonus = (has_archer_bonus ? (PERCENTAGE)(player_ptr->lev - 1) / 7 + 4 : 0);
379     switch (o_ptr->bi_key.tval()) {
380         /* Always break */
381     case ItemKindType::FLASK:
382     case ItemKindType::POTION:
383     case ItemKindType::BOTTLE:
384     case ItemKindType::FOOD:
385     case ItemKindType::JUNK:
386         return 100;
387
388         /* Often break */
389     case ItemKindType::LITE:
390     case ItemKindType::SCROLL:
391     case ItemKindType::SKELETON:
392         return 50;
393
394         /* Sometimes break */
395     case ItemKindType::WAND:
396     case ItemKindType::SPIKE:
397         return 25;
398     case ItemKindType::ARROW:
399         return 20 - archer_bonus * 2;
400
401         /* Rarely break */
402     case ItemKindType::SHOT:
403     case ItemKindType::BOLT:
404         return 10 - archer_bonus;
405     default:
406         return 10;
407     }
408 }