OSDN Git Service

[refactor] #39076 /* Skip non-objects */ を削除。
[hengband/hengband.git] / src / player-damage.c
1 #include "angband.h"
2 #include "util.h"
3
4 #include "player-damage.h"
5 #include "artifact.h"
6 #include "object-flavor.h"
7 #include "object-hook.h"
8 #include "object-broken.h"
9 #include "player-status.h"
10 #include "player-effects.h"
11 #include "monster-spell.h"
12
13
14 /*!
15 * @brief アイテムが酸で破損するかどうかを判定する
16 * @param o_ptr アイテムの情報参照ポインタ
17 * @return 破損するならばTRUEを返す
18 * Note that amulets, rods, and high-level spell books are immune
19 * to "inventory damage" of any kind.  Also sling ammo and shovels.
20 * Does a given class of objects (usually) hate acid?
21 * Note that acid can either melt or corrode something.
22 */
23 bool hates_acid(object_type *o_ptr)
24 {
25         /* Analyze the type */
26         switch (o_ptr->tval)
27         {
28                 /* Wearable items */
29         case TV_ARROW:
30         case TV_BOLT:
31         case TV_BOW:
32         case TV_SWORD:
33         case TV_HAFTED:
34         case TV_POLEARM:
35         case TV_HELM:
36         case TV_CROWN:
37         case TV_SHIELD:
38         case TV_BOOTS:
39         case TV_GLOVES:
40         case TV_CLOAK:
41         case TV_SOFT_ARMOR:
42         case TV_HARD_ARMOR:
43         case TV_DRAG_ARMOR:
44         {
45                 return (TRUE);
46         }
47
48         /* Staffs/Scrolls are wood/paper */
49         case TV_STAFF:
50         case TV_SCROLL:
51         {
52                 return (TRUE);
53         }
54
55         /* Ouch */
56         case TV_CHEST:
57         {
58                 return (TRUE);
59         }
60
61         /* Junk is useless */
62         case TV_SKELETON:
63         case TV_BOTTLE:
64         case TV_JUNK:
65         {
66                 return (TRUE);
67         }
68         }
69
70         return (FALSE);
71 }
72
73
74 /*!
75 * @brief アイテムが電撃で破損するかどうかを判定する /
76 * Does a given object (usually) hate electricity?
77 * @param o_ptr アイテムの情報参照ポインタ
78 * @return 破損するならばTRUEを返す
79 */
80 bool hates_elec(object_type *o_ptr)
81 {
82         switch (o_ptr->tval)
83         {
84         case TV_RING:
85         case TV_WAND:
86         {
87                 return (TRUE);
88         }
89         }
90
91         return (FALSE);
92 }
93
94
95 /*!
96 * @brief アイテムが火炎で破損するかどうかを判定する /
97 * Does a given object (usually) hate fire?
98 * @param o_ptr アイテムの情報参照ポインタ
99 * @return 破損するならばTRUEを返す
100 * @details
101 * Hafted/Polearm weapons have wooden shafts.
102 * Arrows/Bows are mostly wooden.
103 */
104 bool hates_fire(object_type *o_ptr)
105 {
106         /* Analyze the type */
107         switch (o_ptr->tval)
108         {
109                 /* Wearable */
110         case TV_LITE:
111         case TV_ARROW:
112         case TV_BOW:
113         case TV_HAFTED:
114         case TV_POLEARM:
115         case TV_BOOTS:
116         case TV_GLOVES:
117         case TV_CLOAK:
118         case TV_SOFT_ARMOR:
119         {
120                 return (TRUE);
121         }
122
123         /* Books */
124         case TV_LIFE_BOOK:
125         case TV_SORCERY_BOOK:
126         case TV_NATURE_BOOK:
127         case TV_CHAOS_BOOK:
128         case TV_DEATH_BOOK:
129         case TV_TRUMP_BOOK:
130         case TV_ARCANE_BOOK:
131         case TV_CRAFT_BOOK:
132         case TV_DAEMON_BOOK:
133         case TV_CRUSADE_BOOK:
134         case TV_MUSIC_BOOK:
135         case TV_HISSATSU_BOOK:
136         case TV_HEX_BOOK:
137         {
138                 return (TRUE);
139         }
140
141         /* Chests */
142         case TV_CHEST:
143         {
144                 return (TRUE);
145         }
146
147         /* Staffs/Scrolls burn */
148         case TV_STAFF:
149         case TV_SCROLL:
150         {
151                 return (TRUE);
152         }
153         }
154
155         return (FALSE);
156 }
157
158
159 /*!
160 * @brief アイテムが冷気で破損するかどうかを判定する /
161 * Does a given object (usually) hate cold?
162 * @param o_ptr アイテムの情報参照ポインタ
163 * @return 破損するならばTRUEを返す
164 */
165 bool hates_cold(object_type *o_ptr)
166 {
167         switch (o_ptr->tval)
168         {
169         case TV_POTION:
170         case TV_FLASK:
171         case TV_BOTTLE:
172         {
173                 return (TRUE);
174         }
175         }
176
177         return (FALSE);
178 }
179
180
181 /*!
182 * @brief アイテムが酸で破損するかどうかを判定する(メインルーチン) /
183 * Melt something
184 * @param o_ptr アイテムの情報参照ポインタ
185 * @return 破損するならばTRUEを返す
186 * @todo 統合を検討
187 */
188 int set_acid_destroy(object_type *o_ptr)
189 {
190         BIT_FLAGS flgs[TR_FLAG_SIZE];
191         if (!hates_acid(o_ptr)) return (FALSE);
192         object_flags(o_ptr, flgs);
193         if (have_flag(flgs, TR_IGNORE_ACID)) return (FALSE);
194         return (TRUE);
195 }
196
197
198 /*!
199 * @brief アイテムが電撃で破損するかどうかを判定する(メインルーチン) /
200 * Electrical damage
201 * @param o_ptr アイテムの情報参照ポインタ
202 * @return 破損するならばTRUEを返す
203 * @todo 統合を検討
204 */
205 int set_elec_destroy(object_type *o_ptr)
206 {
207         BIT_FLAGS flgs[TR_FLAG_SIZE];
208         if (!hates_elec(o_ptr)) return (FALSE);
209         object_flags(o_ptr, flgs);
210         if (have_flag(flgs, TR_IGNORE_ELEC)) return (FALSE);
211         return (TRUE);
212 }
213
214
215 /*!
216 * @brief アイテムが火炎で破損するかどうかを判定する(メインルーチン) /
217 * Burn something
218 * @param o_ptr アイテムの情報参照ポインタ
219 * @return 破損するならばTRUEを返す
220 * @todo 統合を検討
221 */
222 int set_fire_destroy(object_type *o_ptr)
223 {
224         BIT_FLAGS flgs[TR_FLAG_SIZE];
225         if (!hates_fire(o_ptr)) return (FALSE);
226         object_flags(o_ptr, flgs);
227         if (have_flag(flgs, TR_IGNORE_FIRE)) return (FALSE);
228         return (TRUE);
229 }
230
231
232 /*!
233 * @brief アイテムが冷気で破損するかどうかを判定する(メインルーチン) /
234 * Freeze things
235 * @param o_ptr アイテムの情報参照ポインタ
236 * @return 破損するならばTRUEを返す
237 * @todo 統合を検討
238 */
239 int set_cold_destroy(object_type *o_ptr)
240 {
241         BIT_FLAGS flgs[TR_FLAG_SIZE];
242         if (!hates_cold(o_ptr)) return (FALSE);
243         object_flags(o_ptr, flgs);
244         if (have_flag(flgs, TR_IGNORE_COLD)) return (FALSE);
245         return (TRUE);
246 }
247
248
249 /*!
250 * @brief アイテムが指定確率で破損するかどうかを判定する /
251 * Destroys a type of item on a given percent chance
252 * @param typ 破損判定関数ポインタ
253 * @param perc 基本確率
254 * @return 破損したアイテムの数
255 * @details
256 * Note that missiles are no longer necessarily all destroyed
257 * Destruction taken from "melee.c" code for "stealing".
258 * New-style wands and rods handled correctly. -LM-
259 * Returns number of items destroyed.
260 */
261 int inven_damage(inven_func typ, int perc)
262 {
263         INVENTORY_IDX i;
264         int j, k, amt;
265         object_type *o_ptr;
266         GAME_TEXT o_name[MAX_NLEN];
267
268         if (CHECK_MULTISHADOW()) return 0;
269
270         if (p_ptr->inside_arena) return 0;
271
272         /* Count the casualties */
273         k = 0;
274
275         /* Scan through the slots backwards */
276         for (i = 0; i < INVEN_PACK; i++)
277         {
278                 o_ptr = &inventory[i];
279                 if (!o_ptr->k_idx) continue;
280
281                 /* Hack -- for now, skip artifacts */
282                 if (object_is_artifact(o_ptr)) continue;
283
284                 /* Give this item slot a shot at death */
285                 if ((*typ)(o_ptr))
286                 {
287                         /* Count the casualties */
288                         for (amt = j = 0; j < o_ptr->number; ++j)
289                         {
290                                 if (randint0(100) < perc) amt++;
291                         }
292
293                         /* Some casualities */
294                         if (amt)
295                         {
296                                 object_desc(o_name, o_ptr, OD_OMIT_PREFIX);
297
298                                 msg_format(_("%s(%c)が%s壊れてしまった!", "%sour %s (%c) %s destroyed!"),
299 #ifdef JP
300                                         o_name, index_to_label(i), ((o_ptr->number > 1) ?
301                                                 ((amt == o_ptr->number) ? "全部" : (amt > 1 ? "何個か" : "一個")) : ""));
302 #else
303                                         ((o_ptr->number > 1) ? ((amt == o_ptr->number) ? "All of y" :
304                                                 (amt > 1 ? "Some of y" : "One of y")) : "Y"), o_name, index_to_label(i), ((amt > 1) ? "were" : "was"));
305 #endif
306
307 #ifdef JP
308                                 if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
309                                         msg_print("やりやがったな!");
310                                 else if ((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
311                                 {
312                                         if (randint0(2) == 0) msg_print(_("ジュラル星人め!", ""));
313                                         else msg_print(_("弱い者いじめは止めるんだ!", ""));
314                                 }
315 #endif
316
317                                 /* Potions smash open */
318                                 if (object_is_potion(o_ptr))
319                                 {
320                                         (void)potion_smash_effect(0, p_ptr->y, p_ptr->x, o_ptr->k_idx);
321                                 }
322
323                                 /* Reduce the charges of rods/wands */
324                                 reduce_charges(o_ptr, amt);
325
326                                 /* Destroy "amt" items */
327                                 inven_item_increase(i, -amt);
328                                 inven_item_optimize(i);
329
330                                 /* Count the casualties */
331                                 k += amt;
332                         }
333                 }
334         }
335
336         /* Return the casualty count */
337         return (k);
338 }
339
340
341 /*!
342 * @brief 酸攻撃による装備のAC劣化処理 /
343 * Acid has hit the player, attempt to affect some armor.
344 * @return 装備による軽減があったならTRUEを返す
345 * @details
346 * Note that the "base armor" of an object never changes.
347 * If any armor is damaged (or resists), the player takes less damage.
348 */
349 static bool acid_minus_ac(void)
350 {
351         object_type *o_ptr = NULL;
352         BIT_FLAGS flgs[TR_FLAG_SIZE];
353         GAME_TEXT o_name[MAX_NLEN];
354
355         /* Pick a (possibly empty) inventory slot */
356         switch (randint1(7))
357         {
358         case 1: o_ptr = &inventory[INVEN_RARM]; break;
359         case 2: o_ptr = &inventory[INVEN_LARM]; break;
360         case 3: o_ptr = &inventory[INVEN_BODY]; break;
361         case 4: o_ptr = &inventory[INVEN_OUTER]; break;
362         case 5: o_ptr = &inventory[INVEN_HANDS]; break;
363         case 6: o_ptr = &inventory[INVEN_HEAD]; break;
364         case 7: o_ptr = &inventory[INVEN_FEET]; break;
365         }
366
367         if (!o_ptr->k_idx) return (FALSE);
368         if (!object_is_armour(o_ptr)) return (FALSE);
369
370         object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
371         object_flags(o_ptr, flgs);
372         /* No damage left to be done */
373         if (o_ptr->ac + o_ptr->to_a <= 0)
374         {
375                 msg_format(_("%sは既にボロボロだ!", "Your %s is already crumble!"), o_name);
376                 return (FALSE);
377         }
378
379         /* Object resists */
380         if (have_flag(flgs, TR_IGNORE_ACID))
381         {
382                 msg_format(_("しかし%sには効果がなかった!", "Your %s is unaffected!"), o_name);
383                 return (TRUE);
384         }
385
386         msg_format(_("%sが酸で腐食した!", "Your %s is corroded!"), o_name);
387
388         /* Damage the item */
389         o_ptr->to_a--;
390
391         /* Calculate bonuses */
392         p_ptr->update |= (PU_BONUS);
393         p_ptr->window |= (PW_EQUIP | PW_PLAYER);
394
395         calc_android_exp();
396
397         /* Item was damaged */
398         return (TRUE);
399 }
400
401
402 /*!
403 * @brief 酸属性によるプレイヤー損害処理 /
404 * Hurt the player with Acid
405 * @param dam 基本ダメージ量
406 * @param kb_str ダメージ原因記述
407 * @param monspell 原因となったモンスター特殊攻撃ID
408 * @param aura オーラよるダメージが原因ならばTRUE
409 * @return 修正HPダメージ量
410 */
411 HIT_POINT acid_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura)
412 {
413         HIT_POINT get_damage;
414         int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
415         bool double_resist = IS_OPPOSE_ACID();
416
417         /* Total Immunity */
418         if (p_ptr->immune_acid || (dam <= 0))
419         {
420                 learn_spell(monspell);
421                 return 0;
422         }
423
424         /* Vulnerability (Ouch!) */
425         if (p_ptr->muta3 & MUT3_VULN_ELEM) dam *= 2;
426         if (p_ptr->special_defense & KATA_KOUKIJIN) dam += dam / 3;
427
428         /* Resist the damage */
429         if (p_ptr->resist_acid) dam = (dam + 2) / 3;
430         if (double_resist) dam = (dam + 2) / 3;
431
432         if (aura || !CHECK_MULTISHADOW())
433         {
434                 if ((!(double_resist || p_ptr->resist_acid)) &&
435                         one_in_(HURT_CHANCE))
436                         (void)do_dec_stat(A_CHR);
437
438                 /* If any armor gets hit, defend the player */
439                 if (acid_minus_ac()) dam = (dam + 1) / 2;
440         }
441
442         get_damage = take_hit(aura ? DAMAGE_NOESCAPE : DAMAGE_ATTACK, dam, kb_str, monspell);
443
444         /* Inventory damage */
445         if (!aura && !(double_resist && p_ptr->resist_acid))
446                 inven_damage(set_acid_destroy, inv);
447         return get_damage;
448 }
449
450
451 /*!
452 * @brief 電撃属性によるプレイヤー損害処理 /
453 * Hurt the player with electricity
454 * @param dam 基本ダメージ量
455 * @param kb_str ダメージ原因記述
456 * @param monspell 原因となったモンスター特殊攻撃ID
457 * @param aura オーラよるダメージが原因ならばTRUE
458 * @return 修正HPダメージ量
459 */
460 HIT_POINT elec_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura)
461 {
462         HIT_POINT get_damage;
463         int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
464         bool double_resist = IS_OPPOSE_ELEC();
465
466         /* Total immunity */
467         if (p_ptr->immune_elec || (dam <= 0))
468         {
469                 learn_spell(monspell);
470                 return 0;
471         }
472
473         /* Vulnerability (Ouch!) */
474         if (p_ptr->muta3 & MUT3_VULN_ELEM) dam *= 2;
475         if (p_ptr->special_defense & KATA_KOUKIJIN) dam += dam / 3;
476         if (prace_is_(RACE_ANDROID)) dam += dam / 3;
477
478         /* Resist the damage */
479         if (p_ptr->resist_elec) dam = (dam + 2) / 3;
480         if (double_resist) dam = (dam + 2) / 3;
481
482         if (aura || !CHECK_MULTISHADOW())
483         {
484                 if ((!(double_resist || p_ptr->resist_elec)) &&
485                         one_in_(HURT_CHANCE))
486                         (void)do_dec_stat(A_DEX);
487         }
488
489         get_damage = take_hit(aura ? DAMAGE_NOESCAPE : DAMAGE_ATTACK, dam, kb_str, monspell);
490
491         /* Inventory damage */
492         if (!aura && !(double_resist && p_ptr->resist_elec))
493                 inven_damage(set_elec_destroy, inv);
494
495         return get_damage;
496 }
497
498
499 /*!
500 * @brief 火炎属性によるプレイヤー損害処理 /
501 * Hurt the player with Fire
502 * @param dam 基本ダメージ量
503 * @param kb_str ダメージ原因記述
504 * @param monspell 原因となったモンスター特殊攻撃ID
505 * @param aura オーラよるダメージが原因ならばTRUE
506 * @return 修正HPダメージ量
507 */
508 HIT_POINT fire_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura)
509 {
510         HIT_POINT get_damage;
511         int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
512         bool double_resist = IS_OPPOSE_FIRE();
513
514         /* Totally immune */
515         if (p_ptr->immune_fire || (dam <= 0))
516         {
517                 learn_spell(monspell);
518                 return 0;
519         }
520
521         /* Vulnerability (Ouch!) */
522         if (p_ptr->muta3 & MUT3_VULN_ELEM) dam *= 2;
523         if (prace_is_(RACE_ENT)) dam += dam / 3;
524         if (p_ptr->special_defense & KATA_KOUKIJIN) dam += dam / 3;
525
526         /* Resist the damage */
527         if (p_ptr->resist_fire) dam = (dam + 2) / 3;
528         if (double_resist) dam = (dam + 2) / 3;
529
530         if (aura || !CHECK_MULTISHADOW())
531         {
532                 if ((!(double_resist || p_ptr->resist_fire)) &&
533                         one_in_(HURT_CHANCE))
534                         (void)do_dec_stat(A_STR);
535         }
536
537         get_damage = take_hit(aura ? DAMAGE_NOESCAPE : DAMAGE_ATTACK, dam, kb_str, monspell);
538
539         /* Inventory damage */
540         if (!aura && !(double_resist && p_ptr->resist_fire))
541                 inven_damage(set_fire_destroy, inv);
542
543         return get_damage;
544 }
545
546
547 /*!
548 * @brief 冷気属性によるプレイヤー損害処理 /
549 * Hurt the player with Cold
550 * @param dam 基本ダメージ量
551 * @param kb_str ダメージ原因記述
552 * @param monspell 原因となったモンスター特殊攻撃ID
553 * @param aura オーラよるダメージが原因ならばTRUE
554 * @return 修正HPダメージ量
555 */
556 HIT_POINT cold_dam(HIT_POINT dam, concptr kb_str, int monspell, bool aura)
557 {
558         HIT_POINT get_damage;
559         int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
560         bool double_resist = IS_OPPOSE_COLD();
561
562         /* Total immunity */
563         if (p_ptr->immune_cold || (dam <= 0))
564         {
565                 learn_spell(monspell);
566                 return 0;
567         }
568
569         /* Vulnerability (Ouch!) */
570         if (p_ptr->muta3 & MUT3_VULN_ELEM) dam *= 2;
571         if (p_ptr->special_defense & KATA_KOUKIJIN) dam += dam / 3;
572
573         /* Resist the damage */
574         if (p_ptr->resist_cold) dam = (dam + 2) / 3;
575         if (double_resist) dam = (dam + 2) / 3;
576
577         if (aura || !CHECK_MULTISHADOW())
578         {
579                 if ((!(double_resist || p_ptr->resist_cold)) &&
580                         one_in_(HURT_CHANCE))
581                         (void)do_dec_stat(A_STR);
582         }
583
584         get_damage = take_hit(aura ? DAMAGE_NOESCAPE : DAMAGE_ATTACK, dam, kb_str, monspell);
585
586         /* Inventory damage */
587         if (!aura && !(double_resist && p_ptr->resist_cold))
588                 inven_damage(set_cold_destroy, inv);
589
590         return get_damage;
591 }