OSDN Git Service

[Refactor] #2628 Renamed object-type-definition.cpp/h to item-entity.cpp/h
[hengbandforosx/hengbandosx.git] / src / specific-object / death-scythe.cpp
1 /*!
2  * @brief 死の大鎌に特有の処理
3  * @date 2020/05/23
4  * @author Hourier
5  * @details 現時点ではダメージ反射のみ。行数に注意して関数を追加しても良い.
6  */
7
8 #include "specific-object/death-scythe.h"
9 #include "combat/attack-criticality.h"
10 #include "core/player-redraw-types.h"
11 #include "core/stuff-handler.h"
12 #include "inventory/inventory-slot-types.h"
13 #include "main/sound-definitions-table.h"
14 #include "main/sound-of-music.h"
15 #include "object-enchant/tr-types.h"
16 #include "object/object-flags.h"
17 #include "player-attack/player-attack-util.h"
18 #include "player-base/player-class.h"
19 #include "player-info/race-info.h"
20 #include "player/player-damage.h"
21 #include "player/player-status-flags.h"
22 #include "status/element-resistance.h"
23 #include "system/item-entity.h"
24 #include "system/player-type-definition.h"
25 #include "util/bit-flags-calculator.h"
26 #include "view/display-messages.h"
27
28 /*!
29  * @brief 死の大鎌ダメージが跳ね返ってきた時の、種族ごとのダメージ倍率を返す
30  * @param player_ptr プレイヤーへの参照ポインタ
31  * @return 倍率 (実際は1/10になる)
32  */
33 static int calc_death_scythe_reflection_magnification_mimic_none(PlayerType *player_ptr)
34 {
35     switch (player_ptr->prace) {
36     case PlayerRaceType::YEEK:
37     case PlayerRaceType::KLACKON:
38     case PlayerRaceType::HUMAN:
39     case PlayerRaceType::AMBERITE:
40     case PlayerRaceType::DUNADAN:
41     case PlayerRaceType::BARBARIAN:
42     case PlayerRaceType::BEASTMAN:
43         return 25;
44     case PlayerRaceType::HALF_ORC:
45     case PlayerRaceType::HALF_TROLL:
46     case PlayerRaceType::HALF_OGRE:
47     case PlayerRaceType::HALF_GIANT:
48     case PlayerRaceType::HALF_TITAN:
49     case PlayerRaceType::CYCLOPS:
50     case PlayerRaceType::IMP:
51     case PlayerRaceType::SKELETON:
52     case PlayerRaceType::ZOMBIE:
53     case PlayerRaceType::VAMPIRE:
54     case PlayerRaceType::SPECTRE:
55     case PlayerRaceType::BALROG:
56     case PlayerRaceType::DRACONIAN:
57         return 30;
58     default:
59         return 10;
60     }
61 }
62
63 /*!
64  * @brief 死の大鎌ダメージが跳ね返ってきた時の、変身中の種族も考慮したダメージ倍率を返す
65  * @param player_ptr プレイヤーへの参照ポインタ
66  * @return 倍率 (実際は1/10になる)
67  */
68 static int calc_death_scythe_reflection_magnification(PlayerType *player_ptr)
69 {
70     switch (player_ptr->mimic_form) {
71     case MimicKindType::NONE:
72         return calc_death_scythe_reflection_magnification_mimic_none(player_ptr);
73     case MimicKindType::DEMON:
74     case MimicKindType::DEMON_LORD:
75     case MimicKindType::VAMPIRE:
76         return 30;
77     default:
78         return 10;
79     }
80 }
81
82 /*!
83  * @brief 耐性等に応じて死の大鎌による反射ダメージ倍率を補正する
84  * @param player_ptr プレイヤーへの参照ポインタ
85  * @param magnification ダメージ倍率
86  * @param death_scythe_flags 死の大鎌に関するオブジェクトフラグ配列
87  */
88 static void compensate_death_scythe_reflection_magnification(PlayerType *player_ptr, int *magnification, const TrFlags &death_scythe_flags)
89 {
90     if ((player_ptr->alignment < 0) && (*magnification < 20)) {
91         *magnification = 20;
92     }
93
94     if (!(has_resist_acid(player_ptr) || is_oppose_acid(player_ptr) || has_immune_acid(player_ptr)) && (*magnification < 25)) {
95         *magnification = 25;
96     }
97
98     if (!(has_resist_elec(player_ptr) || is_oppose_elec(player_ptr) || has_immune_elec(player_ptr)) && (*magnification < 25)) {
99         *magnification = 25;
100     }
101
102     if (!(has_resist_fire(player_ptr) || is_oppose_fire(player_ptr) || has_immune_fire(player_ptr)) && (*magnification < 25)) {
103         *magnification = 25;
104     }
105
106     if (!(has_resist_cold(player_ptr) || is_oppose_cold(player_ptr) || has_immune_cold(player_ptr)) && (*magnification < 25)) {
107         *magnification = 25;
108     }
109
110     if (!(has_resist_pois(player_ptr) || is_oppose_pois(player_ptr)) && (*magnification < 25)) {
111         *magnification = 25;
112     }
113
114     if (!PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI) && (death_scythe_flags.has(TR_FORCE_WEAPON)) && (player_ptr->csp > (player_ptr->msp / 30))) {
115         player_ptr->csp -= (1 + (player_ptr->msp / 30));
116         player_ptr->redraw |= (PR_MANA);
117         *magnification = *magnification * 3 / 2 + 20;
118     }
119 }
120
121 /*!
122  * @brief 死の大鎌による反射ダメージ倍率を更に上げる
123  * @param pa_ptr 直接攻撃構造体への参照ポインタ
124  */
125 static void death_scythe_reflection_critial_hit(player_attack_type *pa_ptr)
126 {
127     if (!one_in_(6)) {
128         return;
129     }
130
131     int more_magnification = 2;
132     msg_format(_("グッサリ切り裂かれた!", "Your weapon cuts deep into yourself!"));
133     while (one_in_(4)) {
134         more_magnification++;
135     }
136
137     pa_ptr->attack_damage *= (int)more_magnification;
138 }
139
140 /*!
141  * @brief 死の大鎌によるダメージ反射のメインルーチン
142  * @param player_ptr プレイヤーへの参照ポインタ
143  * @param pa_ptr 直接攻撃構造体への参照ポインタ
144  */
145 void process_death_scythe_reflection(PlayerType *player_ptr, player_attack_type *pa_ptr)
146 {
147     sound(SOUND_HIT);
148     msg_format(_("ミス! %sにかわされた。", "You miss %s."), pa_ptr->m_name);
149     msg_print(_("振り回した大鎌が自分自身に返ってきた!", "Your scythe returns to you!"));
150
151     auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + pa_ptr->hand];
152     auto death_scythe_flags = object_flags(o_ptr);
153     pa_ptr->attack_damage = damroll(o_ptr->dd + player_ptr->to_dd[pa_ptr->hand], o_ptr->ds + player_ptr->to_ds[pa_ptr->hand]);
154     int magnification = calc_death_scythe_reflection_magnification(player_ptr);
155     compensate_death_scythe_reflection_magnification(player_ptr, &magnification, death_scythe_flags);
156     pa_ptr->attack_damage *= (int)magnification;
157     pa_ptr->attack_damage /= 10;
158     pa_ptr->attack_damage = critical_norm(player_ptr, o_ptr->weight, o_ptr->to_h, pa_ptr->attack_damage, player_ptr->to_h[pa_ptr->hand], pa_ptr->mode);
159     death_scythe_reflection_critial_hit(pa_ptr);
160     pa_ptr->attack_damage += (player_ptr->to_d[pa_ptr->hand] + o_ptr->to_d);
161     if (pa_ptr->attack_damage < 0) {
162         pa_ptr->attack_damage = 0;
163     }
164
165     take_hit(player_ptr, DAMAGE_FORCE, pa_ptr->attack_damage, _("死の大鎌", "Death scythe"));
166     handle_stuff(player_ptr);
167 }