OSDN Git Service

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