OSDN Git Service

[Refactor] #37353 externs.h から util.h への宣言移動。
[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
280                 /* Skip non-objects */
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) || (inventory[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) inventory slot */
358         switch (randint1(7))
359         {
360         case 1: o_ptr = &inventory[INVEN_RARM]; break;
361         case 2: o_ptr = &inventory[INVEN_LARM]; break;
362         case 3: o_ptr = &inventory[INVEN_BODY]; break;
363         case 4: o_ptr = &inventory[INVEN_OUTER]; break;
364         case 5: o_ptr = &inventory[INVEN_HANDS]; break;
365         case 6: o_ptr = &inventory[INVEN_HEAD]; break;
366         case 7: o_ptr = &inventory[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 }