OSDN Git Service

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