OSDN Git Service

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