OSDN Git Service

[Refactor] #935 Moved PY_FOOD_* from player-status.h to digestion-processor.h
[hengbandforosx/hengbandosx.git] / src / hpmp / hp-mp-processor.cpp
1 #include "hpmp/hp-mp-processor.h"
2 #include "cmd-action/cmd-pet.h"
3 #include "core/player-redraw-types.h"
4 #include "core/window-redrawer.h"
5 #include "flavor/flavor-describer.h"
6 #include "flavor/object-flavor-types.h"
7 #include "floor/pattern-walk.h"
8 #include "grid/feature.h"
9 #include "grid/grid.h"
10 #include "hpmp/hp-mp-regenerator.h"
11 #include "inventory/inventory-slot-types.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-flags2.h"
14 #include "monster-race/race-flags3.h"
15 #include "object-enchant/object-ego.h"
16 #include "object-enchant/tr-types.h"
17 #include "object-enchant/trc-types.h"
18 #include "object/object-flags.h"
19 #include "player-info/avatar.h"
20 #include "player/attack-defense-types.h"
21 #include "player/digestion-processor.h"
22 #include "player/player-damage.h"
23 #include "player/player-race-types.h"
24 #include "player/player-race.h"
25 #include "player/player-status-flags.h"
26 #include "player/player-status-resist.h"
27 #include "player/special-defense-types.h"
28 #include "status/bad-status-setter.h"
29 #include "status/element-resistance.h"
30 #include "system/floor-type-definition.h"
31 #include "system/monster-race-definition.h"
32 #include "system/monster-type-definition.h"
33 #include "system/object-type-definition.h"
34 #include "system/player-type-definition.h"
35 #include "util/bit-flags-calculator.h"
36 #include "view/display-messages.h"
37 #include "world/world.h"
38
39 /*!
40  * @brief 地形によるダメージを与える / Deal damage from feature.
41  * @param creature_ptr プレイヤー情報への参照ポインタ
42  * @param g_ptr 現在の床の情報への参照ポインタ
43  * @param msg_levitation 浮遊時にダメージを受けた場合に表示するメッセージ
44  * @param msg_normal 通常時にダメージを受けた場合に表示するメッセージの述部
45  * @param 耐性等によるダメージレートを計算する関数
46  * @param ダメージを受けた際の追加処理を行う関数
47  * @return ダメージを与えたらTRUE、なければFALSE
48  * @details
49  * ダメージを受けた場合、自然回復できない。
50  */
51 static bool deal_damege_by_feat(player_type *creature_ptr, grid_type *g_ptr, concptr msg_levitation, concptr msg_normal,
52     std::function<PERCENTAGE(player_type *)> damage_rate, std::function<void(player_type *, int)> additional_effect)
53 {
54     feature_type *f_ptr = &f_info[g_ptr->feat];
55     int damage = 0;
56
57     if (has_flag(f_ptr->flags, FF_DEEP)) {
58         damage = 6000 + randint0(4000);
59     } else if (!creature_ptr->levitation) {
60         damage = 3000 + randint0(2000);
61     }
62
63     damage *= damage_rate(creature_ptr);
64     damage /= 100;
65     if (creature_ptr->levitation)
66         damage /= 5;
67
68     damage = damage / 100 + (randint0(100) < (damage % 100));
69
70     if (damage == 0)
71         return FALSE;
72
73     if (creature_ptr->levitation) {
74         msg_print(msg_levitation);
75
76         take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, format(_("%sの上に浮遊したダメージ", "flying over %s"), f_info[get_feat_mimic(g_ptr)].name.c_str()));
77
78         if (additional_effect != NULL)
79             additional_effect(creature_ptr, damage);
80     } else {
81         concptr name = f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name.c_str();
82         msg_format(_("%s%s!", "The %s %s!"), name, msg_normal);
83         take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name);
84
85         if (additional_effect != NULL)
86             additional_effect(creature_ptr, damage);
87     }
88
89     return TRUE;
90 }
91
92 /*!
93  * @brief 10ゲームターンが進行するごとにプレイヤーのHPとMPの増減処理を行う。
94  *  / Handle timed damage and regeneration every 10 game turns
95  * @return なし
96  */
97 void process_player_hp_mp(player_type *creature_ptr)
98 {
99     grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
100     feature_type *f_ptr = &f_info[g_ptr->feat];
101     bool cave_no_regen = FALSE;
102     int upkeep_factor = 0;
103     int regen_amount = PY_REGEN_NORMAL;
104     if (creature_ptr->poisoned && !is_invuln(creature_ptr)) {
105         take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, _("毒", "poison"));
106     }
107
108     if (creature_ptr->cut && !is_invuln(creature_ptr)) {
109         HIT_POINT dam;
110         if (creature_ptr->cut > 1000) {
111             dam = 200;
112         } else if (creature_ptr->cut > 200) {
113             dam = 80;
114         } else if (creature_ptr->cut > 100) {
115             dam = 32;
116         } else if (creature_ptr->cut > 50) {
117             dam = 16;
118         } else if (creature_ptr->cut > 25) {
119             dam = 7;
120         } else if (creature_ptr->cut > 10) {
121             dam = 3;
122         } else {
123             dam = 1;
124         }
125
126         take_hit(creature_ptr, DAMAGE_NOESCAPE, dam, _("致命傷", "a fatal wound"));
127     }
128
129     if (player_race_life(creature_ptr) == PlayerRaceLife::UNDEAD && player_race_has_flag(creature_ptr, TR_VUL_LITE)) {
130         if (!is_in_dungeon(creature_ptr) && !has_resist_lite(creature_ptr) && !is_invuln(creature_ptr) && is_daytime()) {
131             if ((creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW) {
132                 msg_print(_("日光があなたのアンデッドの肉体を焼き焦がした!", "The sun's rays scorch your undead flesh!"));
133                 take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, _("日光", "sunlight"));
134                 cave_no_regen = TRUE;
135             }
136         }
137
138         object_type *o_ptr;
139         o_ptr = &creature_ptr->inventory_list[INVEN_LITE];
140         BIT_FLAGS flgs[TR_FLAG_SIZE];
141         object_flags(creature_ptr, o_ptr, flgs);
142
143         if (creature_ptr->inventory_list[INVEN_LITE].tval && !has_flag(flgs, TR_DARK_SOURCE) && !has_resist_lite(creature_ptr)) {
144             GAME_TEXT o_name[MAX_NLEN];
145             char ouch[MAX_NLEN + 40];
146             describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
147             msg_format(_("%sがあなたのアンデッドの肉体を焼き焦がした!", "The %s scorches your undead flesh!"), o_name);
148
149             cave_no_regen = TRUE;
150             describe_flavor(creature_ptr, o_name, o_ptr, OD_NAME_ONLY);
151             sprintf(ouch, _("%sを装備したダメージ", "wielding %s"), o_name);
152
153             if (!is_invuln(creature_ptr))
154                 take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, ouch);
155         }
156     }
157
158     if (has_flag(f_ptr->flags, FF_LAVA) && !is_invuln(creature_ptr) && !has_immune_fire(creature_ptr)) {
159         cave_no_regen = deal_damege_by_feat(
160             creature_ptr, g_ptr, _("熱で火傷した!", "The heat burns you!"), _("で火傷した!", "burns you!"), calc_fire_damage_rate, NULL);
161     }
162
163     if (has_flag(f_ptr->flags, FF_COLD_PUDDLE) && !is_invuln(creature_ptr) && !has_immune_cold(creature_ptr)) {
164         cave_no_regen = deal_damege_by_feat(
165             creature_ptr, g_ptr, _("冷気に覆われた!", "The cold engulfs you!"), _("に凍えた!", "frostbites you!"), calc_cold_damage_rate, NULL);
166     }
167
168     if (has_flag(f_ptr->flags, FF_ELEC_PUDDLE) && !is_invuln(creature_ptr) && !has_immune_elec(creature_ptr)) {
169         cave_no_regen = deal_damege_by_feat(
170             creature_ptr, g_ptr, _("電撃を受けた!", "The electricity shocks you!"), _("に感電した!", "shocks you!"), calc_elec_damage_rate, NULL);
171     }
172
173     if (has_flag(f_ptr->flags, FF_ACID_PUDDLE) && !is_invuln(creature_ptr) && !has_immune_acid(creature_ptr)) {
174         cave_no_regen = deal_damege_by_feat(
175             creature_ptr, g_ptr, _("酸が飛び散った!", "The acid melts you!"), _("に溶かされた!", "melts you!"), calc_acid_damage_rate, NULL);
176     }
177
178     if (has_flag(f_ptr->flags, FF_POISON_PUDDLE) && !is_invuln(creature_ptr)) {
179         cave_no_regen = deal_damege_by_feat(creature_ptr, g_ptr, _("毒気を吸い込んだ!", "The gas poisons you!"), _("に毒された!", "poisons you!"),
180             calc_acid_damage_rate, [](player_type *creature_ptr, int damage) {
181                 if (!has_resist_pois(creature_ptr))
182                     (void)set_poisoned(creature_ptr, creature_ptr->poisoned + damage);
183             });
184     }
185
186     if (has_flag(f_ptr->flags, FF_WATER) && has_flag(f_ptr->flags, FF_DEEP) && !creature_ptr->levitation && !creature_ptr->can_swim
187         && !has_resist_water(creature_ptr)) {
188         if (calc_inventory_weight(creature_ptr) > calc_weight_limit(creature_ptr)) {
189             msg_print(_("溺れている!", "You are drowning!"));
190             take_hit(creature_ptr, DAMAGE_NOESCAPE, randint1(creature_ptr->lev), _("溺れ", "drowning"));
191             cave_no_regen = TRUE;
192         }
193     }
194
195     if (creature_ptr->riding) {
196         HIT_POINT damage;
197         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags2 & RF2_AURA_FIRE) && !has_immune_fire(creature_ptr)) {
198             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
199             if (player_race_has_flag(creature_ptr, TR_VUL_FIRE))
200                 damage += damage / 3;
201             if (has_resist_fire(creature_ptr))
202                 damage = damage / 3;
203             if (is_oppose_fire(creature_ptr))
204                 damage = damage / 3;
205             msg_print(_("熱い!", "It's hot!"));
206             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("炎のオーラ", "Fire aura"));
207         }
208         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags2 & RF2_AURA_ELEC) && !has_immune_elec(creature_ptr)) {
209             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
210             if (player_race_has_flag(creature_ptr, TR_VUL_ELEC))
211                 damage += damage / 3;
212             if (has_resist_elec(creature_ptr))
213                 damage = damage / 3;
214             if (is_oppose_elec(creature_ptr))
215                 damage = damage / 3;
216             msg_print(_("痛い!", "It hurts!"));
217             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("電気のオーラ", "Elec aura"));
218         }
219         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags3 & RF3_AURA_COLD) && !has_immune_cold(creature_ptr)) {
220             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
221             if (player_race_has_flag(creature_ptr, TR_VUL_COLD))
222                 damage += damage / 3;
223             if (has_resist_cold(creature_ptr))
224                 damage = damage / 3;
225             if (is_oppose_cold(creature_ptr))
226                 damage = damage / 3;
227             msg_print(_("冷たい!", "It's cold!"));
228             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("冷気のオーラ", "Cold aura"));
229         }
230     }
231
232     /* Spectres -- take damage when moving through walls */
233     /*
234      * Added: ANYBODY takes damage if inside through walls
235      * without wraith form -- NOTE: Spectres will never be
236      * reduced below 0 hp by being inside a stone wall; others
237      * WILL BE!
238      */
239     if (!has_flag(f_ptr->flags, FF_MOVE) && !has_flag(f_ptr->flags, FF_CAN_FLY)) {
240         if (!is_invuln(creature_ptr) && !creature_ptr->wraith_form && !creature_ptr->tim_pass_wall
241             && ((creature_ptr->chp > (creature_ptr->lev / 5)) || !has_pass_wall(creature_ptr))) {
242             concptr dam_desc;
243             cave_no_regen = TRUE;
244
245             if (has_pass_wall(creature_ptr)) {
246                 msg_print(_("体の分子が分解した気がする!", "Your molecules feel disrupted!"));
247                 dam_desc = _("密度", "density");
248             } else {
249                 msg_print(_("崩れた岩に押し潰された!", "You are being crushed!"));
250                 dam_desc = _("硬い岩", "solid rock");
251             }
252
253             take_hit(creature_ptr, DAMAGE_NOESCAPE, 1 + (creature_ptr->lev / 5), dam_desc);
254         }
255     }
256
257     if (creature_ptr->food < PY_FOOD_WEAK) {
258         if (creature_ptr->food < PY_FOOD_STARVE) {
259             regen_amount = 0;
260         } else if (creature_ptr->food < PY_FOOD_FAINT) {
261             regen_amount = PY_REGEN_FAINT;
262         } else {
263             regen_amount = PY_REGEN_WEAK;
264         }
265     }
266
267     if (pattern_effect(creature_ptr)) {
268         cave_no_regen = TRUE;
269     } else {
270         if (creature_ptr->regenerate) {
271             regen_amount = regen_amount * 2;
272         }
273         if (creature_ptr->special_defense & (KAMAE_MASK | KATA_MASK)) {
274             regen_amount /= 2;
275         }
276         if (creature_ptr->cursed & TRC_SLOW_REGEN) {
277             regen_amount /= 5;
278         }
279     }
280
281     if ((creature_ptr->action == ACTION_SEARCH) || (creature_ptr->action == ACTION_REST)) {
282         regen_amount = regen_amount * 2;
283     }
284
285     upkeep_factor = calculate_upkeep(creature_ptr);
286     if ((creature_ptr->action == ACTION_LEARN) || (creature_ptr->action == ACTION_HAYAGAKE) || (creature_ptr->special_defense & KATA_KOUKIJIN)) {
287         upkeep_factor += 100;
288     }
289
290     regenmana(creature_ptr, upkeep_factor, regen_amount);
291     if (creature_ptr->pclass == CLASS_MAGIC_EATER) {
292         regenmagic(creature_ptr, regen_amount);
293     }
294
295     if ((creature_ptr->csp == 0) && (creature_ptr->csp_frac == 0)) {
296         while (upkeep_factor > 100) {
297             msg_print(_("こんなに多くのペットを制御できない!", "Too many pets to control at once!"));
298             msg_print(NULL);
299             do_cmd_pet_dismiss(creature_ptr);
300
301             upkeep_factor = calculate_upkeep(creature_ptr);
302
303             msg_format(_("維持MPは %d%%", "Upkeep: %d%% mana."), upkeep_factor);
304             msg_print(NULL);
305         }
306     }
307
308     if (creature_ptr->poisoned)
309         regen_amount = 0;
310     if (creature_ptr->cut)
311         regen_amount = 0;
312     if (cave_no_regen)
313         regen_amount = 0;
314
315     regen_amount = (regen_amount * creature_ptr->mutant_regenerate_mod) / 100;
316     if ((creature_ptr->chp < creature_ptr->mhp) && !cave_no_regen) {
317         regenhp(creature_ptr, regen_amount);
318     }
319 }
320
321 /*
322  * Increase players hit points, notice effects
323  */
324 bool hp_player(player_type *creature_ptr, int num)
325 {
326     int vir;
327     vir = virtue_number(creature_ptr, V_VITALITY);
328
329     if (num <= 0)
330         return FALSE;
331
332     if (vir) {
333         num = num * (creature_ptr->virtues[vir - 1] + 1250) / 1250;
334     }
335
336     if (creature_ptr->chp < creature_ptr->mhp) {
337         if ((num > 0) && (creature_ptr->chp < (creature_ptr->mhp / 3)))
338             chg_virtue(creature_ptr, V_TEMPERANCE, 1);
339
340         creature_ptr->chp += num;
341         if (creature_ptr->chp >= creature_ptr->mhp) {
342             creature_ptr->chp = creature_ptr->mhp;
343             creature_ptr->chp_frac = 0;
344         }
345
346         creature_ptr->redraw |= (PR_HP);
347         creature_ptr->window_flags |= (PW_PLAYER);
348         if (num < 5) {
349             msg_print(_("少し気分が良くなった。", "You feel a little better."));
350         } else if (num < 15) {
351             msg_print(_("気分が良くなった。", "You feel better."));
352         } else if (num < 35) {
353             msg_print(_("とても気分が良くなった。", "You feel much better."));
354         } else {
355             msg_print(_("ひじょうに気分が良くなった。", "You feel very good."));
356         }
357
358         return TRUE;
359     }
360
361     return FALSE;
362 }