OSDN Git Service

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