OSDN Git Service

[Refactor] #40521 Separated inventory-slot-types.h from player-status.h
[hengband/hengband.git] / src / core / hp-mp-processor.c
1 #include "core/hp-mp-processor.h"
2 #include "cmd-action/cmd-pet.h"
3 #include "core/hp-mp-regenerator.h"
4 #include "floor/floor.h"
5 #include "floor/pattern-walk.h"
6 #include "grid/feature.h"
7 #include "grid/grid.h"
8 #include "inventory/inventory-slot-types.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-flags2.h"
11 #include "monster-race/race-flags3.h"
12 #include "object-enchant/object-ego.h"
13 #include "object-enchant/trc-types.h"
14 #include "object/object-flavor.h"
15 #include "player/avatar.h"
16 #include "player/player-damage.h"
17 #include "player/player-race-types.h"
18 #include "player/player-race.h"
19 #include "player/special-defense-types.h"
20 #include "status/bad-status-setter.h"
21 #include "status/element-resistance.h"
22 #include "util/bit-flags-calculator.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
25
26 /*!
27  * @brief 10ゲームターンが進行するごとにプレイヤーのHPとMPの増減処理を行う。
28  *  / Handle timed damage and regeneration every 10 game turns
29  * @return なし
30  */
31 void process_player_hp_mp(player_type *creature_ptr)
32 {
33     feature_type *f_ptr = &f_info[creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].feat];
34     bool cave_no_regen = FALSE;
35     int upkeep_factor = 0;
36     int regen_amount = PY_REGEN_NORMAL;
37     if (creature_ptr->poisoned && !is_invuln(creature_ptr)) {
38         take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, _("毒", "poison"), -1);
39     }
40
41     if (creature_ptr->cut && !is_invuln(creature_ptr)) {
42         HIT_POINT dam;
43         if (creature_ptr->cut > 1000) {
44             dam = 200;
45         } else if (creature_ptr->cut > 200) {
46             dam = 80;
47         } else if (creature_ptr->cut > 100) {
48             dam = 32;
49         } else if (creature_ptr->cut > 50) {
50             dam = 16;
51         } else if (creature_ptr->cut > 25) {
52             dam = 7;
53         } else if (creature_ptr->cut > 10) {
54             dam = 3;
55         } else {
56             dam = 1;
57         }
58
59         take_hit(creature_ptr, DAMAGE_NOESCAPE, dam, _("致命傷", "a fatal wound"), -1);
60     }
61
62     if (is_specific_player_race(creature_ptr, RACE_VAMPIRE) || (creature_ptr->mimic_form == MIMIC_VAMPIRE)) {
63         if (!creature_ptr->current_floor_ptr->dun_level && !creature_ptr->resist_lite && !is_invuln(creature_ptr) && is_daytime()) {
64             if ((creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].info & (CAVE_GLOW | CAVE_MNDK)) == CAVE_GLOW) {
65                 msg_print(_("日光があなたのアンデッドの肉体を焼き焦がした!", "The sun's rays scorch your undead flesh!"));
66                 take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, _("日光", "sunlight"), -1);
67                 cave_no_regen = TRUE;
68             }
69         }
70
71         if (creature_ptr->inventory_list[INVEN_LITE].tval && (creature_ptr->inventory_list[INVEN_LITE].name2 != EGO_LITE_DARKNESS)
72             && !creature_ptr->resist_lite) {
73             object_type *o_ptr = &creature_ptr->inventory_list[INVEN_LITE];
74             GAME_TEXT o_name[MAX_NLEN];
75             char ouch[MAX_NLEN + 40];
76             object_desc(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
77             msg_format(_("%sがあなたのアンデッドの肉体を焼き焦がした!", "The %s scorches your undead flesh!"), o_name);
78
79             cave_no_regen = TRUE;
80             object_desc(creature_ptr, o_name, o_ptr, OD_NAME_ONLY);
81             sprintf(ouch, _("%sを装備したダメージ", "wielding %s"), o_name);
82
83             if (!is_invuln(creature_ptr))
84                 take_hit(creature_ptr, DAMAGE_NOESCAPE, 1, ouch, -1);
85         }
86     }
87
88     if (have_flag(f_ptr->flags, FF_LAVA) && !is_invuln(creature_ptr) && !creature_ptr->immune_fire) {
89         int damage = 0;
90
91         if (have_flag(f_ptr->flags, FF_DEEP)) {
92             damage = 6000 + randint0(4000);
93         } else if (!creature_ptr->levitation) {
94             damage = 3000 + randint0(2000);
95         }
96
97         if (damage) {
98             if (is_specific_player_race(creature_ptr, RACE_ENT))
99                 damage += damage / 3;
100             if (creature_ptr->resist_fire)
101                 damage = damage / 3;
102             if (is_oppose_fire(creature_ptr))
103                 damage = damage / 3;
104             if (creature_ptr->levitation)
105                 damage = damage / 5;
106
107             damage = damage / 100 + (randint0(100) < (damage % 100));
108
109             if (creature_ptr->levitation) {
110                 msg_print(_("熱で火傷した!", "The heat burns you!"));
111                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage,
112                     format(_("%sの上に浮遊したダメージ", "flying over %s"),
113                         f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
114                     -1);
115             } else {
116                 concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
117                 msg_format(_("%sで火傷した!", "The %s burns you!"), name);
118                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
119             }
120
121             cave_no_regen = TRUE;
122         }
123     }
124
125     if (have_flag(f_ptr->flags, FF_COLD_PUDDLE) && !is_invuln(creature_ptr) && !creature_ptr->immune_cold) {
126         int damage = 0;
127
128         if (have_flag(f_ptr->flags, FF_DEEP)) {
129             damage = 6000 + randint0(4000);
130         } else if (!creature_ptr->levitation) {
131             damage = 3000 + randint0(2000);
132         }
133
134         if (damage) {
135             if (creature_ptr->resist_cold)
136                 damage = damage / 3;
137             if (is_oppose_cold(creature_ptr))
138                 damage = damage / 3;
139             if (creature_ptr->levitation)
140                 damage = damage / 5;
141
142             damage = damage / 100 + (randint0(100) < (damage % 100));
143
144             if (creature_ptr->levitation) {
145                 msg_print(_("冷気に覆われた!", "The cold engulfs you!"));
146                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage,
147                     format(_("%sの上に浮遊したダメージ", "flying over %s"),
148                         f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
149                     -1);
150             } else {
151                 concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
152                 msg_format(_("%sに凍えた!", "The %s frostbites you!"), name);
153                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
154             }
155
156             cave_no_regen = TRUE;
157         }
158     }
159
160     if (have_flag(f_ptr->flags, FF_ELEC_PUDDLE) && !is_invuln(creature_ptr) && !creature_ptr->immune_elec) {
161         int damage = 0;
162
163         if (have_flag(f_ptr->flags, FF_DEEP)) {
164             damage = 6000 + randint0(4000);
165         } else if (!creature_ptr->levitation) {
166             damage = 3000 + randint0(2000);
167         }
168
169         if (damage) {
170             if (creature_ptr->resist_elec)
171                 damage = damage / 3;
172             if (is_oppose_elec(creature_ptr))
173                 damage = damage / 3;
174             if (creature_ptr->levitation)
175                 damage = damage / 5;
176
177             damage = damage / 100 + (randint0(100) < (damage % 100));
178
179             if (creature_ptr->levitation) {
180                 msg_print(_("電撃を受けた!", "The electricity shocks you!"));
181                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage,
182                     format(_("%sの上に浮遊したダメージ", "flying over %s"),
183                         f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
184                     -1);
185             } else {
186                 concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
187                 msg_format(_("%sに感電した!", "The %s shocks you!"), name);
188                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
189             }
190
191             cave_no_regen = TRUE;
192         }
193     }
194
195     if (have_flag(f_ptr->flags, FF_ACID_PUDDLE) && !is_invuln(creature_ptr) && !creature_ptr->immune_acid) {
196         int damage = 0;
197
198         if (have_flag(f_ptr->flags, FF_DEEP)) {
199             damage = 6000 + randint0(4000);
200         } else if (!creature_ptr->levitation) {
201             damage = 3000 + randint0(2000);
202         }
203
204         if (damage) {
205             if (creature_ptr->resist_acid)
206                 damage = damage / 3;
207             if (is_oppose_acid(creature_ptr))
208                 damage = damage / 3;
209             if (creature_ptr->levitation)
210                 damage = damage / 5;
211
212             damage = damage / 100 + (randint0(100) < (damage % 100));
213
214             if (creature_ptr->levitation) {
215                 msg_print(_("酸が飛び散った!", "The acid melts you!"));
216                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage,
217                     format(_("%sの上に浮遊したダメージ", "flying over %s"),
218                         f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
219                     -1);
220             } else {
221                 concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
222                 msg_format(_("%sに溶かされた!", "The %s melts you!"), name);
223                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
224             }
225
226             cave_no_regen = TRUE;
227         }
228     }
229
230     if (have_flag(f_ptr->flags, FF_POISON_PUDDLE) && !is_invuln(creature_ptr)) {
231         int damage = 0;
232
233         if (have_flag(f_ptr->flags, FF_DEEP)) {
234             damage = 6000 + randint0(4000);
235         } else if (!creature_ptr->levitation) {
236             damage = 3000 + randint0(2000);
237         }
238
239         if (damage) {
240             if (creature_ptr->resist_pois)
241                 damage = damage / 3;
242             if (is_oppose_pois(creature_ptr))
243                 damage = damage / 3;
244             if (creature_ptr->levitation)
245                 damage = damage / 5;
246
247             damage = damage / 100 + (randint0(100) < (damage % 100));
248
249             if (creature_ptr->levitation) {
250                 msg_print(_("毒気を吸い込んだ!", "The gas poisons you!"));
251                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage,
252                     format(_("%sの上に浮遊したダメージ", "flying over %s"),
253                         f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name),
254                     -1);
255                 if (creature_ptr->resist_pois)
256                     (void)set_poisoned(creature_ptr, creature_ptr->poisoned + 1);
257             } else {
258                 concptr name = f_name + f_info[get_feat_mimic(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])].name;
259                 msg_format(_("%sに毒された!", "The %s poisons you!"), name);
260                 take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, name, -1);
261                 if (creature_ptr->resist_pois)
262                     (void)set_poisoned(creature_ptr, creature_ptr->poisoned + 3);
263             }
264
265             cave_no_regen = TRUE;
266         }
267     }
268
269     if (have_flag(f_ptr->flags, FF_WATER) && have_flag(f_ptr->flags, FF_DEEP) && !creature_ptr->levitation && !creature_ptr->can_swim
270         && !creature_ptr->resist_water) {
271         if (creature_ptr->total_weight > weight_limit(creature_ptr)) {
272             msg_print(_("溺れている!", "You are drowning!"));
273             take_hit(creature_ptr, DAMAGE_NOESCAPE, randint1(creature_ptr->lev), _("溺れ", "drowning"), -1);
274             cave_no_regen = TRUE;
275         }
276     }
277
278     if (creature_ptr->riding) {
279         HIT_POINT damage;
280         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags2 & RF2_AURA_FIRE) && !creature_ptr->immune_fire) {
281             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
282             if (is_specific_player_race(creature_ptr, RACE_ENT))
283                 damage += damage / 3;
284             if (creature_ptr->resist_fire)
285                 damage = damage / 3;
286             if (is_oppose_fire(creature_ptr))
287                 damage = damage / 3;
288             msg_print(_("熱い!", "It's hot!"));
289             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("炎のオーラ", "Fire aura"), -1);
290         }
291         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags2 & RF2_AURA_ELEC) && !creature_ptr->immune_elec) {
292             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
293             if (is_specific_player_race(creature_ptr, RACE_ANDROID))
294                 damage += damage / 3;
295             if (creature_ptr->resist_elec)
296                 damage = damage / 3;
297             if (is_oppose_elec(creature_ptr))
298                 damage = damage / 3;
299             msg_print(_("痛い!", "It hurts!"));
300             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("電気のオーラ", "Elec aura"), -1);
301         }
302         if ((r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].flags3 & RF3_AURA_COLD) && !creature_ptr->immune_cold) {
303             damage = r_info[creature_ptr->current_floor_ptr->m_list[creature_ptr->riding].r_idx].level / 2;
304             if (creature_ptr->resist_cold)
305                 damage = damage / 3;
306             if (is_oppose_cold(creature_ptr))
307                 damage = damage / 3;
308             msg_print(_("冷たい!", "It's cold!"));
309             take_hit(creature_ptr, DAMAGE_NOESCAPE, damage, _("冷気のオーラ", "Cold aura"), -1);
310         }
311     }
312
313     /* Spectres -- take damage when moving through walls */
314     /*
315      * Added: ANYBODY takes damage if inside through walls
316      * without wraith form -- NOTE: Spectres will never be
317      * reduced below 0 hp by being inside a stone wall; others
318      * WILL BE!
319      */
320     if (!have_flag(f_ptr->flags, FF_MOVE) && !have_flag(f_ptr->flags, FF_CAN_FLY)) {
321         if (!is_invuln(creature_ptr) && !creature_ptr->wraith_form && !creature_ptr->tim_pass_wall
322             && ((creature_ptr->chp > (creature_ptr->lev / 5)) || !creature_ptr->pass_wall)) {
323             concptr dam_desc;
324             cave_no_regen = TRUE;
325
326             if (creature_ptr->pass_wall) {
327                 msg_print(_("体の分子が分解した気がする!", "Your molecules feel disrupted!"));
328                 dam_desc = _("密度", "density");
329             } else {
330                 msg_print(_("崩れた岩に押し潰された!", "You are being crushed!"));
331                 dam_desc = _("硬い岩", "solid rock");
332             }
333
334             take_hit(creature_ptr, DAMAGE_NOESCAPE, 1 + (creature_ptr->lev / 5), dam_desc, -1);
335         }
336     }
337
338     if (creature_ptr->food < PY_FOOD_WEAK) {
339         if (creature_ptr->food < PY_FOOD_STARVE) {
340             regen_amount = 0;
341         } else if (creature_ptr->food < PY_FOOD_FAINT) {
342             regen_amount = PY_REGEN_FAINT;
343         } else {
344             regen_amount = PY_REGEN_WEAK;
345         }
346     }
347
348     if (pattern_effect(creature_ptr)) {
349         cave_no_regen = TRUE;
350     } else {
351         if (creature_ptr->regenerate) {
352             regen_amount = regen_amount * 2;
353         }
354         if (creature_ptr->special_defense & (KAMAE_MASK | KATA_MASK)) {
355             regen_amount /= 2;
356         }
357         if (creature_ptr->cursed & TRC_SLOW_REGEN) {
358             regen_amount /= 5;
359         }
360     }
361
362     if ((creature_ptr->action == ACTION_SEARCH) || (creature_ptr->action == ACTION_REST)) {
363         regen_amount = regen_amount * 2;
364     }
365
366     upkeep_factor = calculate_upkeep(creature_ptr);
367     if ((creature_ptr->action == ACTION_LEARN) || (creature_ptr->action == ACTION_HAYAGAKE) || (creature_ptr->special_defense & KATA_KOUKIJIN)) {
368         upkeep_factor += 100;
369     }
370
371     regenmana(creature_ptr, upkeep_factor, regen_amount);
372     if (creature_ptr->pclass == CLASS_MAGIC_EATER) {
373         regenmagic(creature_ptr, regen_amount);
374     }
375
376     if ((creature_ptr->csp == 0) && (creature_ptr->csp_frac == 0)) {
377         while (upkeep_factor > 100) {
378             msg_print(_("こんなに多くのペットを制御できない!", "Too many pets to control at once!"));
379             msg_print(NULL);
380             do_cmd_pet_dismiss(creature_ptr);
381
382             upkeep_factor = calculate_upkeep(creature_ptr);
383
384             msg_format(_("維持MPは %d%%", "Upkeep: %d%% mana."), upkeep_factor);
385             msg_print(NULL);
386         }
387     }
388
389     if (creature_ptr->poisoned)
390         regen_amount = 0;
391     if (creature_ptr->cut)
392         regen_amount = 0;
393     if (cave_no_regen)
394         regen_amount = 0;
395
396     regen_amount = (regen_amount * creature_ptr->mutant_regenerate_mod) / 100;
397     if ((creature_ptr->chp < creature_ptr->mhp) && !cave_no_regen) {
398         regenhp(creature_ptr, regen_amount);
399     }
400 }
401
402 /*
403  * Increase players hit points, notice effects
404  */
405 bool hp_player(player_type *creature_ptr, int num)
406 {
407     int vir;
408     vir = virtue_number(creature_ptr, V_VITALITY);
409
410     if (num <= 0)
411         return FALSE;
412
413     if (vir) {
414         num = num * (creature_ptr->virtues[vir - 1] + 1250) / 1250;
415     }
416
417     if (creature_ptr->chp < creature_ptr->mhp) {
418         if ((num > 0) && (creature_ptr->chp < (creature_ptr->mhp / 3)))
419             chg_virtue(creature_ptr, V_TEMPERANCE, 1);
420
421         creature_ptr->chp += num;
422         if (creature_ptr->chp >= creature_ptr->mhp) {
423             creature_ptr->chp = creature_ptr->mhp;
424             creature_ptr->chp_frac = 0;
425         }
426
427         creature_ptr->redraw |= (PR_HP);
428         creature_ptr->window |= (PW_PLAYER);
429         if (num < 5) {
430             msg_print(_("少し気分が良くなった。", "You feel a little better."));
431         } else if (num < 15) {
432             msg_print(_("気分が良くなった。", "You feel better."));
433         } else if (num < 35) {
434             msg_print(_("とても気分が良くなった。", "You feel much better."));
435         } else {
436             msg_print(_("ひじょうに気分が良くなった。", "You feel very good."));
437         }
438
439         return TRUE;
440     }
441
442     return FALSE;
443 }