OSDN Git Service

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