OSDN Git Service

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