OSDN Git Service

27dba59c0d6658b99878eed4008061db1ea55966
[hengbandforosx/hengbandosx.git] / src / hpmp / hp-mp-regenerator.cpp
1 #include "hpmp/hp-mp-regenerator.h"
2 #include "cmd-item/cmd-magiceat.h"
3 #include "core/player-redraw-types.h"
4 #include "core/window-redrawer.h"
5 #include "inventory/inventory-slot-types.h"
6 #include "monster-race/monster-race.h"
7 #include "monster-race/race-flags2.h"
8 #include "monster/monster-status.h"
9 #include "player-base/player-class.h"
10 #include "player-info/magic-eater-data-type.h"
11 #include "player-info/samurai-data-type.h"
12 #include "player/attack-defense-types.h"
13 #include "player/player-status-table.h"
14 #include "player/special-defense-types.h"
15 #include "system/floor-type-definition.h"
16 #include "system/item-entity.h"
17 #include "system/monster-entity.h"
18 #include "system/monster-race-info.h"
19 #include "system/player-type-definition.h"
20 #include "system/redrawing-flags-updater.h"
21
22 /*!<広域マップ移動時の自然回復処理カウンタ(広域マップ1マス毎に20回処理を基本とする)*/
23 int wild_regen = 20;
24
25 /*!
26  * @brief プレイヤーのHP自然回復処理 / Regenerate hit points -RAK-
27  * @param percent 回復比率
28  */
29 void regenhp(PlayerType *player_ptr, int percent)
30 {
31     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::KOUKIJIN)) {
32         return;
33     }
34     if (player_ptr->action == ACTION_HAYAGAKE) {
35         return;
36     }
37
38     int old_chp = player_ptr->chp;
39
40     /*
41      * Extract the new hitpoints
42      *
43      * 'percent' is the Regen factor in unit (1/2^16)
44      */
45     int new_chp = 0;
46     uint32_t new_chp_frac = (player_ptr->mhp * percent + PY_REGEN_HPBASE);
47     s64b_lshift(&new_chp, &new_chp_frac, 16);
48     s64b_add(&(player_ptr->chp), &(player_ptr->chp_frac), new_chp, new_chp_frac);
49     if (0 < s64b_cmp(player_ptr->chp, player_ptr->chp_frac, player_ptr->mhp, 0)) {
50         player_ptr->chp = player_ptr->mhp;
51         player_ptr->chp_frac = 0;
52     }
53
54     if (old_chp != player_ptr->chp) {
55         auto &rfu = RedrawingFlagsUpdater::get_instance();
56         rfu.set_flag(MainWindowRedrawingFlag::HP);
57         player_ptr->window_flags |= (PW_PLAYER);
58         wild_regen = 20;
59     }
60 }
61
62 /*!
63  * @brief プレイヤーのMP自然回復処理(regen_magic()のサブセット) / Regenerate mana points
64  * @param upkeep_factor ペット維持によるMPコスト量
65  * @param regen_amount 回復量
66  */
67 void regenmana(PlayerType *player_ptr, MANA_POINT upkeep_factor, MANA_POINT regen_amount)
68 {
69     MANA_POINT old_csp = player_ptr->csp;
70     int32_t regen_rate = regen_amount * 100 - upkeep_factor * PY_REGEN_NORMAL;
71
72     /*
73      * Excess mana will decay 32 times faster than normal
74      * regeneration rate.
75      */
76     if (player_ptr->csp > player_ptr->msp) {
77         int32_t decay = 0;
78         uint32_t decay_frac = (player_ptr->msp * 32 * PY_REGEN_NORMAL + PY_REGEN_MNBASE);
79         s64b_lshift(&decay, &decay_frac, 16);
80         s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), decay, decay_frac);
81         if (player_ptr->csp < player_ptr->msp) {
82             player_ptr->csp = player_ptr->msp;
83             player_ptr->csp_frac = 0;
84         }
85     }
86
87     /* Regenerating mana (unless the player has excess mana) */
88     else if (regen_rate > 0) {
89         MANA_POINT new_mana = 0;
90         uint32_t new_mana_frac = (player_ptr->msp * regen_rate / 100 + PY_REGEN_MNBASE);
91         s64b_lshift(&new_mana, &new_mana_frac, 16);
92         s64b_add(&(player_ptr->csp), &(player_ptr->csp_frac), new_mana, new_mana_frac);
93         if (player_ptr->csp >= player_ptr->msp) {
94             player_ptr->csp = player_ptr->msp;
95             player_ptr->csp_frac = 0;
96         }
97     }
98
99     /* Reduce mana (even when the player has excess mana) */
100     if (regen_rate < 0) {
101         int32_t reduce_mana = 0;
102         uint32_t reduce_mana_frac = (player_ptr->msp * (-1) * regen_rate / 100 + PY_REGEN_MNBASE);
103         s64b_lshift(&reduce_mana, &reduce_mana_frac, 16);
104         s64b_sub(&(player_ptr->csp), &(player_ptr->csp_frac), reduce_mana, reduce_mana_frac);
105         if (player_ptr->csp < 0) {
106             player_ptr->csp = 0;
107             player_ptr->csp_frac = 0;
108         }
109     }
110
111     if (old_csp != player_ptr->csp) {
112         auto &rfu = RedrawingFlagsUpdater::get_instance();
113         rfu.set_flag(MainWindowRedrawingFlag::MP);
114         player_ptr->window_flags |= (PW_PLAYER);
115         player_ptr->window_flags |= (PW_SPELL);
116         wild_regen = 20;
117     }
118 }
119
120 /*!
121  * @brief 取り込んだ魔道具の自然回復処理 / Regenerate magic regen_amount: PY_REGEN_NORMAL * 2 (if resting) * 2 (if having regenarate)
122  * @param regen_amount 回復量
123  */
124 void regenmagic(PlayerType *player_ptr, int regen_amount)
125 {
126     auto magic_eater_data = PlayerClass(player_ptr).get_specific_data<magic_eater_data_type>();
127     if (!magic_eater_data) {
128         return;
129     }
130
131     const int dev = 30;
132     const int mult = (dev + adj_mag_mana[player_ptr->stat_index[A_INT]]); /* x1 to x2 speed bonus for recharging */
133
134     for (auto tval : { ItemKindType::STAFF, ItemKindType::WAND }) {
135         for (auto &item : magic_eater_data->get_item_group(tval)) {
136             const int maximum_charge = item.count * EATER_CHARGE;
137             if (item.count == 0 || item.charge == maximum_charge) {
138                 continue;
139             }
140
141             /* Increase remaining charge number like float value */
142             auto new_mana = (regen_amount * mult * (item.count + 13)) / (dev * 8);
143             item.charge += new_mana;
144
145             /* Check maximum charge */
146             item.charge = std::min(item.charge, maximum_charge);
147         }
148     }
149
150     for (auto &item : magic_eater_data->get_item_group(ItemKindType::ROD)) {
151         if (item.count == 0 || item.charge == 0) {
152             continue;
153         }
154
155         /* Decrease remaining period for charging */
156         auto new_mana = (regen_amount * mult * (item.count + 10) * EATER_ROD_CHARGE) / (dev * 16 * PY_REGEN_NORMAL);
157         item.charge -= new_mana;
158
159         /* Check minimum remaining period for charging */
160         item.charge = std::max(item.charge, 0);
161     }
162
163     wild_regen = 20;
164 }
165
166 /*!
167  * @brief 100ゲームターン毎のモンスターのHP自然回復処理 / Regenerate the monsters (once per 100 game turns)
168  * @param player_ptr プレイヤーへの参照ポインタ
169  * @note Should probably be done during monster turns.
170  */
171 void regenerate_monsters(PlayerType *player_ptr)
172 {
173     for (int i = 1; i < player_ptr->current_floor_ptr->m_max; i++) {
174         auto *m_ptr = &player_ptr->current_floor_ptr->m_list[i];
175         auto *r_ptr = &monraces_info[m_ptr->r_idx];
176
177         if (!m_ptr->is_valid()) {
178             continue;
179         }
180
181         if (m_ptr->hp < m_ptr->maxhp) {
182             int frac = m_ptr->maxhp / 100;
183             if (!frac) {
184                 if (one_in_(2)) {
185                     frac = 1;
186                 }
187             }
188
189             if (r_ptr->flags2 & RF2_REGENERATE) {
190                 frac *= 2;
191             }
192
193             m_ptr->hp += frac;
194             if (m_ptr->hp > m_ptr->maxhp) {
195                 m_ptr->hp = m_ptr->maxhp;
196             }
197
198             auto &rfu = RedrawingFlagsUpdater::get_instance();
199             if (player_ptr->health_who == i) {
200                 rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
201             }
202             if (player_ptr->riding == i) {
203                 rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
204             }
205         }
206     }
207 }
208
209 /*!
210  * @brief 30ゲームターン毎のボール中モンスターのHP自然回復処理 / Regenerate the captured monsters (once per 30 game turns)
211  * @param player_ptr プレイヤーへの参照ポインタ
212  * @note Should probably be done during monster turns.
213  */
214 void regenerate_captured_monsters(PlayerType *player_ptr)
215 {
216     bool heal = false;
217     for (int i = 0; i < INVEN_TOTAL; i++) {
218         auto *o_ptr = &player_ptr->inventory_list[i];
219         if (!o_ptr->is_valid()) {
220             continue;
221         }
222         if (o_ptr->bi_key.tval() != ItemKindType::CAPTURE) {
223             continue;
224         }
225         if (!o_ptr->pval) {
226             continue;
227         }
228
229         heal = true;
230         const auto r_idx = i2enum<MonsterRaceId>(o_ptr->pval);
231         const auto *r_ptr = &monraces_info[r_idx];
232         if (o_ptr->captured_monster_current_hp < o_ptr->captured_monster_max_hp) {
233             short frac = o_ptr->captured_monster_max_hp / 100;
234             if (!frac) {
235                 if (one_in_(2)) {
236                     frac = 1;
237                 }
238             }
239
240             if (r_ptr->flags2 & RF2_REGENERATE) {
241                 frac *= 2;
242             }
243
244             o_ptr->captured_monster_current_hp += frac;
245             if (o_ptr->captured_monster_current_hp > o_ptr->captured_monster_max_hp) {
246                 o_ptr->captured_monster_current_hp = o_ptr->captured_monster_max_hp;
247             }
248         }
249     }
250
251     if (heal) {
252         RedrawingFlagsUpdater::get_instance().set_flag(StatusRedrawingFlag::COMBINATION);
253
254         /*!
255          * @todo FIXME 広域マップ移動で1歩毎に何度も再描画されて重くなる.
256          * 現在はボール中モンスターのHP回復でボールの表示は変わらないためコメントアウトする.
257          */
258         // rfu.set_flag(SubWindowRedrawingFlag::INVENTORY);
259         // rfu.set_flag(SubWindowRedrawingFlag::EQUIPMENT);
260         wild_regen = 20;
261     }
262 }