OSDN Git Service

841086ee5c19c9d52013dbf3d476071071f522f3
[hengbandforosx/hengbandosx.git] / src / player / digestion-processor.cpp
1 #include "player/digestion-processor.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "core/speed-table.h"
6 #include "core/stuff-handler.h"
7 #include "floor/wild.h"
8 #include "game-option/disturbance-options.h"
9 #include "main/sound-definitions-table.h"
10 #include "main/sound-of-music.h"
11 #include "object-enchant/trc-types.h"
12 #include "player-base/player-class.h"
13 #include "player-info/monk-data-type.h"
14 #include "player-info/samurai-data-type.h"
15 #include "player/player-damage.h"
16 #include "player/player-status.h"
17 #include "player/special-defense-types.h"
18 #include "status/bad-status-setter.h"
19 #include "system/player-type-definition.h"
20 #include "system/redrawing-flags-updater.h"
21 #include "timed-effect/player-paralysis.h"
22 #include "timed-effect/timed-effects.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
25
26 /*!
27  * @brief 10ゲームターンが進行するごとにプレイヤーの腹を減らす
28  * @param player_ptr プレイヤーへの参照ポインタ
29  */
30 void starve_player(PlayerType *player_ptr)
31 {
32     if (player_ptr->phase_out) {
33         return;
34     }
35
36     if (player_ptr->food >= PY_FOOD_MAX) {
37         (void)set_food(player_ptr, player_ptr->food - 100);
38     } else if (!(w_ptr->game_turn % (TURNS_PER_TICK * 5))) {
39         int digestion = speed_to_energy(player_ptr->pspeed);
40         if (player_ptr->regenerate) {
41             digestion += 20;
42         }
43         PlayerClass pc(player_ptr);
44         if (!pc.monk_stance_is(MonkStanceType::NONE) || !pc.samurai_stance_is(SamuraiStanceType::NONE)) {
45             digestion += 20;
46         }
47         if (player_ptr->cursed.has(CurseTraitType::FAST_DIGEST)) {
48             digestion += 30;
49         }
50
51         if (player_ptr->slow_digest) {
52             digestion -= 5;
53         }
54
55         if (digestion < 1) {
56             digestion = 1;
57         }
58         if (digestion > 100) {
59             digestion = 100;
60         }
61
62         (void)set_food(player_ptr, player_ptr->food - digestion);
63     }
64
65     if ((player_ptr->food >= PY_FOOD_FAINT)) {
66         return;
67     }
68
69     if (!player_ptr->effects()->paralysis()->is_paralyzed() && (randint0(100) < 10)) {
70         msg_print(_("あまりにも空腹で気絶してしまった。", "You faint from the lack of food."));
71         disturb(player_ptr, true, true);
72         (void)BadStatusSetter(player_ptr).mod_paralysis(1 + randint0(5));
73     }
74
75     if (player_ptr->food < PY_FOOD_STARVE) {
76         int dam = (PY_FOOD_STARVE - player_ptr->food) / 10;
77         if (!is_invuln(player_ptr)) {
78             take_hit(player_ptr, DAMAGE_LOSELIFE, dam, _("空腹", "starvation"));
79         }
80     }
81 }
82
83 /*!
84  * @brief 空腹状態をセットする / Set "food", notice observable changes
85  * @param v 継続時間
86  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す
87  * @details
88  * Set "", notice observable changes\n
89  *\n
90  * The "food" variable can get as large as 20000, allowing the
91  * addition of the most "filling" item, Elvish Waybread, which adds
92  * 7500 food units, without overflowing the 32767 maximum limit.\n
93  *\n
94  * Perhaps we should disturb the player with various messages,
95  * especially messages about hunger status changes.  \n
96  *\n
97  * Digestion of food is handled in "dungeon.c", in which, normally,
98  * the player digests about 20 food units per 100 game turns, more
99  * when "fast", more when "regenerating", less with "slow digestion",
100  * but when the player is "gorged", he digests 100 food units per 10
101  * game turns, or a full 1000 food units per 100 game turns.\n
102  *\n
103  * Note that the player's speed is reduced by 10 units while gorged,
104  * so if the player eats a single food ration (5000 food units) when
105  * full (15000 food units), he will be gorged for (5000/100)*10 = 500
106  * game turns, or 500/(100/5) = 25 player turns (if nothing else is
107  * affecting the player speed).\n
108  */
109 bool set_food(PlayerType *player_ptr, TIME_EFFECT v)
110 {
111     int old_aux, new_aux;
112
113     bool notice = false;
114     v = (v > 20000) ? 20000 : (v < 0) ? 0
115                                       : v;
116     if (player_ptr->food < PY_FOOD_FAINT) {
117         old_aux = 0;
118     } else if (player_ptr->food < PY_FOOD_WEAK) {
119         old_aux = 1;
120     } else if (player_ptr->food < PY_FOOD_ALERT) {
121         old_aux = 2;
122     } else if (player_ptr->food < PY_FOOD_FULL) {
123         old_aux = 3;
124     } else if (player_ptr->food < PY_FOOD_MAX) {
125         old_aux = 4;
126     } else {
127         old_aux = 5;
128     }
129
130     if (v < PY_FOOD_FAINT) {
131         new_aux = 0;
132     } else if (v < PY_FOOD_WEAK) {
133         new_aux = 1;
134     } else if (v < PY_FOOD_ALERT) {
135         new_aux = 2;
136     } else if (v < PY_FOOD_FULL) {
137         new_aux = 3;
138     } else if (v < PY_FOOD_MAX) {
139         new_aux = 4;
140     } else {
141         new_aux = 5;
142     }
143
144     if (old_aux < 1 && new_aux > 0) {
145         chg_virtue(player_ptr, Virtue::PATIENCE, 2);
146     } else if (old_aux < 3 && (old_aux != new_aux)) {
147         chg_virtue(player_ptr, Virtue::PATIENCE, 1);
148     }
149     if (old_aux == 2) {
150         chg_virtue(player_ptr, Virtue::TEMPERANCE, 1);
151     }
152     if (old_aux == 0) {
153         chg_virtue(player_ptr, Virtue::TEMPERANCE, -1);
154     }
155
156     if (new_aux > old_aux) {
157         switch (new_aux) {
158         case 1:
159             msg_print(_("まだ空腹で倒れそうだ。", "You are still weak."));
160             break;
161         case 2:
162             msg_print(_("まだ空腹だ。", "You are still hungry."));
163             break;
164         case 3:
165             msg_print(_("空腹感がおさまった。", "You are no longer hungry."));
166             break;
167         case 4:
168             msg_print(_("満腹だ!", "You are full!"));
169             break;
170
171         case 5:
172             msg_print(_("食べ過ぎだ!", "You have gorged yourself!"));
173             chg_virtue(player_ptr, Virtue::HARMONY, -1);
174             chg_virtue(player_ptr, Virtue::PATIENCE, -1);
175             chg_virtue(player_ptr, Virtue::TEMPERANCE, -2);
176             break;
177         }
178
179         notice = true;
180     } else if (new_aux < old_aux) {
181         switch (new_aux) {
182         case 0:
183             sound(SOUND_FAINT);
184             msg_print(_("あまりにも空腹で気を失ってしまった!", "You are getting faint from hunger!"));
185             break;
186         case 1:
187             sound(SOUND_WEAK);
188             msg_print(_("お腹が空いて倒れそうだ。", "You are getting weak from hunger!"));
189             break;
190         case 2:
191             sound(SOUND_HUNGRY);
192             msg_print(_("お腹が空いてきた。", "You are getting hungry."));
193             break;
194         case 3:
195             msg_print(_("満腹感がなくなった。", "You are no longer full."));
196             break;
197         case 4:
198             msg_print(_("やっとお腹がきつくなくなった。", "You are no longer gorged."));
199             break;
200         }
201
202         if (player_ptr->wild_mode && (new_aux < 2)) {
203             change_wild_mode(player_ptr, false);
204         }
205
206         notice = true;
207     }
208
209     player_ptr->food = v;
210     if (!notice) {
211         return false;
212     }
213
214     if (disturb_state) {
215         disturb(player_ptr, false, false);
216     }
217
218     auto &rfu = RedrawingFlagsUpdater::get_instance();
219     rfu.set_flag(StatusRedrawingFlag::BONUS);
220     rfu.set_flag(MainWindowRedrawingFlag::HUNGER);
221     handle_stuff(player_ptr);
222
223     return true;
224 }