OSDN Git Service

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