OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / status / body-improvement.cpp
1 #include "status/body-improvement.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/speed-table.h"
5 #include "core/stuff-handler.h"
6 #include "core/window-redrawer.h"
7 #include "game-option/disturbance-options.h"
8 #include "player/player-status.h"
9 #include "realm/realm-song-numbers.h"
10 #include "spell-realm/spells-song.h"
11 #include "system/player-type-definition.h"
12 #include "system/redrawing-flags-updater.h"
13 #include "view/display-messages.h"
14
15 /*!
16  * @brief 対邪悪結界の継続時間をセットする / Set "protevil", notice observable changes
17  * @param v 継続時間
18  * @param do_dec 現在の継続時間より長い値のみ上書きする
19  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
20  */
21 bool set_protevil(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
22 {
23     bool notice = false;
24     v = (v > 10000) ? 10000 : (v < 0) ? 0
25                                       : v;
26
27     if (player_ptr->is_dead) {
28         return false;
29     }
30
31     if (v) {
32         if (player_ptr->protevil && !do_dec) {
33             if (player_ptr->protevil > v) {
34                 return false;
35             }
36         } else if (!player_ptr->protevil) {
37             msg_print(_("邪悪なる存在から守られているような感じがする!", "You feel safe from evil!"));
38             notice = true;
39         }
40     } else {
41         if (player_ptr->protevil) {
42             msg_print(_("邪悪なる存在から守られている感じがなくなった。", "You no longer feel safe from evil."));
43             notice = true;
44         }
45     }
46
47     player_ptr->protevil = v;
48     RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
49
50     if (!notice) {
51         return false;
52     }
53
54     if (disturb_state) {
55         disturb(player_ptr, false, false);
56     }
57
58     handle_stuff(player_ptr);
59     return true;
60 }
61
62 /*!
63  * @brief 無傷球の継続時間をセットする / Set "invuln", notice observable changes
64  * @param v 継続時間
65  * @param do_dec 現在の継続時間より長い値のみ上書きする
66  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
67  */
68 bool set_invuln(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
69 {
70     bool notice = false;
71     v = (v > 10000) ? 10000 : (v < 0) ? 0
72                                       : v;
73
74     if (player_ptr->is_dead) {
75         return false;
76     }
77
78     auto &rfu = RedrawingFlagsUpdater::get_instance();
79     static constexpr auto flags_swrf = {
80         SubWindowRedrawingFlag::OVERHEAD,
81         SubWindowRedrawingFlag::DUNGEON,
82     };
83     if (v) {
84         if (player_ptr->invuln && !do_dec) {
85             if (player_ptr->invuln > v) {
86                 return false;
87             }
88         } else if (!is_invuln(player_ptr)) {
89             msg_print(_("無敵だ!", "Invulnerability!"));
90             notice = true;
91             chg_virtue(player_ptr, Virtue::UNLIFE, -2);
92             chg_virtue(player_ptr, Virtue::HONOUR, -2);
93             chg_virtue(player_ptr, Virtue::SACRIFICE, -3);
94             chg_virtue(player_ptr, Virtue::VALOUR, -5);
95             rfu.set_flag(MainWindowRedrawingFlag::MAP);
96             rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
97             rfu.set_flags(flags_swrf);
98         }
99     } else {
100         if (player_ptr->invuln && !music_singing(player_ptr, MUSIC_INVULN)) {
101             msg_print(_("無敵ではなくなった。", "The invulnerability wears off."));
102             notice = true;
103             rfu.set_flag(MainWindowRedrawingFlag::MAP);
104             rfu.set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
105             rfu.set_flags(flags_swrf);
106             player_ptr->energy_need += ENERGY_NEED();
107         }
108     }
109
110     player_ptr->invuln = v;
111     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
112
113     if (!notice) {
114         return false;
115     }
116
117     if (disturb_state) {
118         disturb(player_ptr, false, false);
119     }
120
121     rfu.set_flag(StatusRecalculatingFlag::BONUS);
122     handle_stuff(player_ptr);
123     return true;
124 }
125
126 /*!
127  * @brief 時限急回復の継続時間をセットする / Set "tim_regen", notice observable changes
128  * @param v 継続時間
129  * @param do_dec 現在の継続時間より長い値のみ上書きする
130  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
131  */
132 bool set_tim_regen(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
133 {
134     bool notice = false;
135     v = (v > 10000) ? 10000 : (v < 0) ? 0
136                                       : v;
137
138     if (player_ptr->is_dead) {
139         return false;
140     }
141
142     if (v) {
143         if (player_ptr->tim_regen && !do_dec) {
144             if (player_ptr->tim_regen > v) {
145                 return false;
146             }
147         } else if (!player_ptr->tim_regen) {
148             msg_print(_("回復力が上がった!", "You feel yourself regenerating quickly!"));
149             notice = true;
150         }
151     } else {
152         if (player_ptr->tim_regen) {
153             msg_print(_("素早く回復する感じがなくなった。", "You feel you are no longer regenerating quickly."));
154             notice = true;
155         }
156     }
157
158     player_ptr->tim_regen = v;
159     auto &rfu = RedrawingFlagsUpdater::get_instance();
160     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
161     if (!notice) {
162         return false;
163     }
164
165     if (disturb_state) {
166         disturb(player_ptr, false, false);
167     }
168
169     rfu.set_flag(StatusRecalculatingFlag::BONUS);
170     handle_stuff(player_ptr);
171     return true;
172 }
173
174 /*!
175  * @brief 一時的反射の継続時間をセットする / Set "tim_reflect", notice observable changes
176  * @param v 継続時間
177  * @param do_dec 現在の継続時間より長い値のみ上書きする
178  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
179  */
180 bool set_tim_reflect(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
181 {
182     bool notice = false;
183     v = (v > 10000) ? 10000 : (v < 0) ? 0
184                                       : v;
185
186     if (player_ptr->is_dead) {
187         return false;
188     }
189
190     if (v) {
191         if (player_ptr->tim_reflect && !do_dec) {
192             if (player_ptr->tim_reflect > v) {
193                 return false;
194             }
195         } else if (!player_ptr->tim_reflect) {
196             msg_print(_("体の表面が滑かになった気がする。", "Your body becames smooth."));
197             notice = true;
198         }
199     } else {
200         if (player_ptr->tim_reflect) {
201             msg_print(_("体の表面が滑かでなくなった。", "Your body is no longer smooth."));
202             notice = true;
203         }
204     }
205
206     player_ptr->tim_reflect = v;
207     auto &rfu = RedrawingFlagsUpdater::get_instance();
208     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
209     if (!notice) {
210         return false;
211     }
212
213     if (disturb_state) {
214         disturb(player_ptr, false, false);
215     }
216
217     rfu.set_flag(StatusRecalculatingFlag::BONUS);
218     handle_stuff(player_ptr);
219     return true;
220 }
221
222 /*!
223  * @brief 一時的壁抜けの継続時間をセットする / Set "tim_pass_wall", notice observable changes
224  * @param v 継続時間
225  * @param do_dec 現在の継続時間より長い値のみ上書きする
226  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
227  */
228 bool set_pass_wall(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
229 {
230     bool notice = false;
231     v = (v > 10000) ? 10000 : (v < 0) ? 0
232                                       : v;
233
234     if (player_ptr->is_dead) {
235         return false;
236     }
237
238     if (v) {
239         if (player_ptr->tim_pass_wall && !do_dec) {
240             if (player_ptr->tim_pass_wall > v) {
241                 return false;
242             }
243         } else if (!player_ptr->tim_pass_wall) {
244             msg_print(_("体が半物質の状態になった。", "You became ethereal."));
245             notice = true;
246         }
247     } else {
248         if (player_ptr->tim_pass_wall) {
249             msg_print(_("体が物質化した。", "You are no longer ethereal."));
250             notice = true;
251         }
252     }
253
254     player_ptr->tim_pass_wall = v;
255     auto &rfu = RedrawingFlagsUpdater::get_instance();
256     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
257     if (!notice) {
258         return false;
259     }
260
261     if (disturb_state) {
262         disturb(player_ptr, false, false);
263     }
264
265     rfu.set_flag(StatusRecalculatingFlag::BONUS);
266     handle_stuff(player_ptr);
267     return true;
268 }