OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / player-attack / blood-sucking-processor.cpp
1 /*!
2  * @brief 吸血処理
3  * @date 2020/05/23
4  * @author Hourier
5  */
6
7 #include "player-attack/blood-sucking-processor.h"
8 #include "artifact/fixed-art-types.h"
9 #include "game-option/cheat-options.h"
10 #include "hpmp/hp-mp-processor.h"
11 #include "inventory/inventory-slot-types.h"
12 #include "monster-race/monster-race-hook.h"
13 #include "object-enchant/tr-types.h"
14 #include "player-attack/player-attack.h"
15 #include "realm/realm-hex-numbers.h"
16 #include "spell-realm/spells-hex.h"
17 #include "system/item-entity.h"
18 #include "system/monster-entity.h"
19 #include "system/player-type-definition.h"
20 #include "util/bit-flags-calculator.h"
21 #include "view/display-messages.h"
22
23 /*!
24  * @brief 生命のあるモンスターから吸血できるか判定する
25  * @param player_ptr プレイヤーへの参照ポインタ
26  * @param pa_ptr 直接攻撃構造体への参照ポインタ
27  */
28 void decide_blood_sucking(PlayerType *player_ptr, player_attack_type *pa_ptr)
29 {
30     bool is_blood_sucker = pa_ptr->flags.has(TR_VAMPIRIC);
31     is_blood_sucker |= pa_ptr->chaos_effect == CE_VAMPIRIC;
32     is_blood_sucker |= pa_ptr->mode == HISSATSU_DRAIN;
33     is_blood_sucker |= SpellHex(player_ptr).is_spelling_specific(HEX_VAMP_BLADE);
34     if (!is_blood_sucker) {
35         return;
36     }
37
38     pa_ptr->can_drain = pa_ptr->m_ptr->has_living_flag();
39 }
40
41 /*!
42  * @brief 吸血量を計算する
43  * @param pa_ptr 直接攻撃構造体への参照ポインタ
44  */
45 void calc_drain(player_attack_type *pa_ptr)
46 {
47     if (pa_ptr->attack_damage <= 0) {
48         pa_ptr->can_drain = false;
49     }
50
51     if (pa_ptr->drain_result > pa_ptr->m_ptr->hp) {
52         pa_ptr->drain_result = pa_ptr->m_ptr->hp;
53     }
54 }
55
56 /*!
57  * @brief 村正による吸血処理
58  * @param player_ptr プレイヤーへの参照ポインタ
59  * @param pa_ptr 直接攻撃構造体への参照ポインタ
60  * @param is_human モンスターが人間かどうか
61  */
62 static void drain_muramasa(PlayerType *player_ptr, player_attack_type *pa_ptr, const bool is_human)
63 {
64     if (!is_human) {
65         return;
66     }
67
68     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
69     HIT_PROB to_h = o_ptr->to_h;
70     int to_d = o_ptr->to_d;
71     bool flag = true;
72     for (int i = 0; i < to_h + 3; i++) {
73         if (one_in_(4)) {
74             flag = false;
75         }
76     }
77
78     if (flag) {
79         to_h++;
80     }
81
82     flag = true;
83     for (int i = 0; i < to_d + 3; i++) {
84         if (one_in_(4)) {
85             flag = false;
86         }
87     }
88
89     if (flag) {
90         to_d++;
91     }
92
93     if ((o_ptr->to_h == to_h) && (o_ptr->to_d == to_d)) {
94         return;
95     }
96
97     msg_print(_("妖刀は血を吸って強くなった!", "Muramasa sucked blood, and became more powerful!"));
98     o_ptr->to_h = to_h;
99     o_ptr->to_d = to_d;
100 }
101
102 /*!
103  * @brief 吸血武器による吸血処理
104  * @param player_ptr プレイヤーへの参照ポインタ
105  * @param pa_ptr 直接攻撃構造体への参照ポインタ
106  * @param drain_msg 吸血をした旨のメッセージを表示するかどうか
107  * @details 1行目の5がマジックナンバーで良く分からなかったので、取り敢えず元々あったコメントをベースに定数宣言しておいた
108  */
109 static void drain_result(PlayerType *player_ptr, player_attack_type *pa_ptr, bool *drain_msg)
110 {
111     const int real_drain = 5;
112     if (pa_ptr->drain_result <= real_drain) {
113         return;
114     }
115
116     int drain_heal = damroll(2, pa_ptr->drain_result / 6);
117
118     if (SpellHex(player_ptr).is_spelling_specific(HEX_VAMP_BLADE)) {
119         drain_heal *= 2;
120     }
121
122     if (cheat_xtra) {
123         msg_format(_("Draining left: %d", "Draining left: %d"), pa_ptr->drain_left);
124     }
125
126     if (pa_ptr->drain_left == 0) {
127         return;
128     }
129
130     if (drain_heal < pa_ptr->drain_left) {
131         pa_ptr->drain_left -= drain_heal;
132     } else {
133         drain_heal = pa_ptr->drain_left;
134         pa_ptr->drain_left = 0;
135     }
136
137     if (*drain_msg) {
138         msg_format(_("刃が%sから生命力を吸い取った!", "Your weapon drains life from %s!"), pa_ptr->m_name);
139         *drain_msg = false;
140     }
141
142     drain_heal = (drain_heal * player_ptr->mutant_regenerate_mod) / 100;
143     hp_player(player_ptr, drain_heal);
144 }
145
146 /*!
147  * @brief 吸血処理のメインルーチン
148  * @param player_ptr プレイヤーへの参照ポインタ
149  * @param pa_ptr 直接攻撃構造体への参照ポインタ
150  * @param is_human 人間かどうか(村正用フラグ)
151  * @param drain_msg 吸血をした旨のメッセージを表示するかどうか
152  * @details モンスターが死んだ場合、(ゲームのフレーバー的に)吸血しない
153  */
154 void process_drain(PlayerType *player_ptr, player_attack_type *pa_ptr, const bool is_human, bool *drain_msg)
155 {
156     if (!pa_ptr->can_drain || (pa_ptr->drain_result <= 0)) {
157         return;
158     }
159
160     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
161     if (o_ptr->is_specific_artifact(FixedArtifactId::MURAMASA)) {
162         drain_muramasa(player_ptr, pa_ptr, is_human);
163     } else {
164         drain_result(player_ptr, pa_ptr, drain_msg);
165     }
166
167     pa_ptr->m_ptr->maxhp -= (pa_ptr->attack_damage + 7) / 8;
168     if (pa_ptr->m_ptr->hp > pa_ptr->m_ptr->maxhp) {
169         pa_ptr->m_ptr->hp = pa_ptr->m_ptr->maxhp;
170     }
171
172     if (pa_ptr->m_ptr->maxhp < 1) {
173         pa_ptr->m_ptr->maxhp = 1;
174     }
175
176     pa_ptr->weak = true;
177 }