OSDN Git Service

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