OSDN Git Service

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