OSDN Git Service

ce9f989b35dffc7120efd7128473e7184ca352bd
[hengbandforosx/hengbandosx.git] / src / status / base-status.cpp
1 #include "status/base-status.h"
2 #include "avatar/avatar.h"
3 #include "core/player-redraw-types.h"
4 #include "core/window-redrawer.h"
5 #include "game-option/birth-options.h"
6 #include "inventory/inventory-slot-types.h"
7 #include "object-enchant/item-feeling.h"
8 #include "object-enchant/special-object-flags.h"
9 #include "perception/object-perception.h"
10 #include "player/player-status-flags.h"
11 #include "spell-kind/spells-floor.h"
12 #include "system/item-entity.h"
13 #include "system/player-type-definition.h"
14 #include "system/redrawing-flags-updater.h"
15 #include "util/bit-flags-calculator.h"
16 #include "view/display-messages.h"
17
18 /* Array of stat "descriptions" */
19 static concptr desc_stat_pos[] = {
20     _("強く", "stronger"),
21     _("知的に", "smarter"),
22     _("賢く", "wiser"),
23     _("器用に", "more dextrous"),
24     _("健康に", "healthier"),
25     _("美しく", "cuter")
26 };
27
28 /* Array of stat "descriptions" */
29 static concptr desc_stat_neg[] = {
30     _("弱く", "weaker"),
31     _("無知に", "stupider"),
32     _("愚かに", "more naive"),
33     _("不器用に", "clumsier"),
34     _("不健康に", "more sickly"),
35     _("醜く", "uglier")
36 };
37
38 /*!
39  * @brief プレイヤーの基本能力値を増加させる / Increases a stat by one randomized level -RAK-
40  * @param stat 上昇させるステータスID
41  * @return 実際に上昇した場合TRUEを返す。
42  * @details
43  * Note that this function (used by stat potions) now restores\n
44  * the stat BEFORE increasing it.\n
45  */
46 bool inc_stat(PlayerType *player_ptr, int stat)
47 {
48     auto value = player_ptr->stat_cur[stat];
49     if (value >= player_ptr->stat_max_max[stat]) {
50         return false;
51     }
52
53     if (value < 18) {
54         value += (randint0(100) < 75) ? 1 : 2;
55     } else if (value < (player_ptr->stat_max_max[stat] - 2)) {
56         auto gain = (((player_ptr->stat_max_max[stat]) - value) / 2 + 3) / 2;
57         if (gain < 1) {
58             gain = 1;
59         }
60
61         value += randint1(gain) + gain / 2;
62         if (value > (player_ptr->stat_max_max[stat] - 1)) {
63             value = player_ptr->stat_max_max[stat] - 1;
64         }
65     } else {
66         value++;
67     }
68
69     player_ptr->stat_cur[stat] = value;
70     if (value > player_ptr->stat_max[stat]) {
71         player_ptr->stat_max[stat] = value;
72     }
73
74     RedrawingFlagsUpdater::get_instance().set_flag(StatusRedrawingFlag::BONUS);
75     return true;
76 }
77
78 /*!
79  * @brief プレイヤーの基本能力値を減少させる / Decreases a stat by an amount indended to vary from 0 to 100 percent.
80  * @param stat 減少させるステータスID
81  * @param amount 減少させる基本量
82  * @param permanent TRUEならば現在の最大値を減少させる
83  * @return 実際に減少した場合TRUEを返す。
84  * @details
85  *\n
86  * Amount could be a little higher in extreme cases to mangle very high\n
87  * stats from massive assaults.  -CWS\n
88  *\n
89  * Note that "permanent" means that the *given* amount is permanent,\n
90  * not that the new value becomes permanent.  This may not work exactly\n
91  * as expected, due to "weirdness" in the algorithm, but in general,\n
92  * if your stat is already drained, the "max" value will not drop all\n
93  * the way down to the "cur" value.\n
94  */
95 bool dec_stat(PlayerType *player_ptr, int stat, int amount, int permanent)
96 {
97     auto res = false;
98     auto cur = player_ptr->stat_cur[stat];
99     auto max = player_ptr->stat_max[stat];
100     int same = (cur == max);
101     if (cur > 3) {
102         if (cur <= 18) {
103             if (amount > 90) {
104                 cur--;
105             }
106             if (amount > 50) {
107                 cur--;
108             }
109             if (amount > 20) {
110                 cur--;
111             }
112             cur--;
113         } else {
114             int loss = (((cur - 18) / 2 + 1) / 2 + 1);
115             if (loss < 1) {
116                 loss = 1;
117             }
118
119             loss = ((randint1(loss) + loss) * amount) / 100;
120             if (loss < amount / 2) {
121                 loss = amount / 2;
122             }
123
124             cur = cur - loss;
125             if (cur < 18) {
126                 cur = (amount <= 20) ? 18 : 17;
127             }
128         }
129
130         if (cur < 3) {
131             cur = 3;
132         }
133
134         if (cur != player_ptr->stat_cur[stat]) {
135             res = true;
136         }
137     }
138
139     if (permanent && (max > 3)) {
140         chg_virtue(player_ptr, Virtue::SACRIFICE, 1);
141         if (stat == A_WIS || stat == A_INT) {
142             chg_virtue(player_ptr, Virtue::ENLIGHTEN, -2);
143         }
144
145         if (max <= 18) {
146             if (amount > 90) {
147                 max--;
148             }
149             if (amount > 50) {
150                 max--;
151             }
152             if (amount > 20) {
153                 max--;
154             }
155             max--;
156         } else {
157             int loss = (((max - 18) / 2 + 1) / 2 + 1);
158             loss = ((randint1(loss) + loss) * amount) / 100;
159             if (loss < amount / 2) {
160                 loss = amount / 2;
161             }
162
163             max = max - loss;
164             if (max < 18) {
165                 max = (amount <= 20) ? 18 : 17;
166             }
167         }
168
169         if (same || (max < cur)) {
170             max = cur;
171         }
172
173         if (max != player_ptr->stat_max[stat]) {
174             res = true;
175         }
176     }
177
178     if (res) {
179         player_ptr->stat_cur[stat] = cur;
180         player_ptr->stat_max[stat] = max;
181         auto &rfu = RedrawingFlagsUpdater::get_instance();
182         rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
183         rfu.set_flag(StatusRedrawingFlag::BONUS);
184     }
185
186     return res;
187 }
188
189 /*!
190  * @brief プレイヤーの基本能力値を回復させる / Restore a stat.  Return TRUE only if this actually makes a difference.
191  * @param stat 回復ステータスID
192  * @return 実際に回復した場合TRUEを返す。
193  */
194 bool res_stat(PlayerType *player_ptr, int stat)
195 {
196     if (player_ptr->stat_cur[stat] != player_ptr->stat_max[stat]) {
197         player_ptr->stat_cur[stat] = player_ptr->stat_max[stat];
198         auto &rfu = RedrawingFlagsUpdater::get_instance();
199         rfu.set_flag(StatusRedrawingFlag::BONUS);
200         rfu.set_flag(MainWindowRedrawingFlag::ABILITY_SCORE);
201         return true;
202     }
203
204     return false;
205 }
206
207 /*
208  * Lose a "point"
209  */
210 bool do_dec_stat(PlayerType *player_ptr, int stat)
211 {
212     bool sust = false;
213     switch (stat) {
214     case A_STR:
215         if (has_sustain_str(player_ptr)) {
216             sust = true;
217         }
218         break;
219     case A_INT:
220         if (has_sustain_int(player_ptr)) {
221             sust = true;
222         }
223         break;
224     case A_WIS:
225         if (has_sustain_wis(player_ptr)) {
226             sust = true;
227         }
228         break;
229     case A_DEX:
230         if (has_sustain_dex(player_ptr)) {
231             sust = true;
232         }
233         break;
234     case A_CON:
235         if (has_sustain_con(player_ptr)) {
236             sust = true;
237         }
238         break;
239     case A_CHR:
240         if (has_sustain_chr(player_ptr)) {
241             sust = true;
242         }
243         break;
244     }
245
246     if (sust && (!ironman_nightmare || randint0(13))) {
247         msg_format(_("%sなった気がしたが、すぐに元に戻った。", "You feel %s for a moment, but the feeling passes."), desc_stat_neg[stat]);
248         return true;
249     }
250
251     if (dec_stat(player_ptr, stat, 10, (ironman_nightmare && !randint0(13)))) {
252         msg_format(_("ひどく%sなった気がする。", "You feel %s."), desc_stat_neg[stat]);
253         return true;
254     }
255
256     return false;
257 }
258
259 /*
260  * Restore lost "points" in a stat
261  */
262 bool do_res_stat(PlayerType *player_ptr, int stat)
263 {
264     if (res_stat(player_ptr, stat)) {
265         msg_format(_("元通りに%sなった気がする。", "You feel %s."), desc_stat_pos[stat]);
266         return true;
267     }
268
269     return false;
270 }
271
272 /*
273  * Gain a "point" in a stat
274  */
275 bool do_inc_stat(PlayerType *player_ptr, int stat)
276 {
277     bool res = res_stat(player_ptr, stat);
278     if (inc_stat(player_ptr, stat)) {
279         if (stat == A_WIS) {
280             chg_virtue(player_ptr, Virtue::ENLIGHTEN, 1);
281             chg_virtue(player_ptr, Virtue::FAITH, 1);
282         } else if (stat == A_INT) {
283             chg_virtue(player_ptr, Virtue::KNOWLEDGE, 1);
284             chg_virtue(player_ptr, Virtue::ENLIGHTEN, 1);
285         } else if (stat == A_CON) {
286             chg_virtue(player_ptr, Virtue::VITALITY, 1);
287         }
288
289         msg_format(_("ワーオ!とても%sなった!", "Wow! You feel %s!"), desc_stat_pos[stat]);
290         return true;
291     }
292
293     if (res) {
294         msg_format(_("元通りに%sなった気がする。", "You feel %s."), desc_stat_pos[stat]);
295         return true;
296     }
297
298     return false;
299 }
300
301 /*
302  * Forget everything
303  */
304 bool lose_all_info(PlayerType *player_ptr)
305 {
306     chg_virtue(player_ptr, Virtue::KNOWLEDGE, -5);
307     chg_virtue(player_ptr, Virtue::ENLIGHTEN, -5);
308     for (int i = 0; i < INVEN_TOTAL; i++) {
309         auto *o_ptr = &player_ptr->inventory_list[i];
310         if (!o_ptr->is_valid() || o_ptr->is_fully_known()) {
311             continue;
312         }
313
314         o_ptr->feeling = FEEL_NONE;
315         o_ptr->ident &= ~(IDENT_EMPTY);
316         o_ptr->ident &= ~(IDENT_KNOWN);
317         o_ptr->ident &= ~(IDENT_SENSE);
318     }
319
320     auto &rfu = RedrawingFlagsUpdater::get_instance();
321     const auto flags_srf = {
322         StatusRedrawingFlag::BONUS,
323         StatusRedrawingFlag::COMBINATION,
324         StatusRedrawingFlag::REORDER,
325     };
326     rfu.set_flags(flags_srf);
327     set_bits(player_ptr->window_flags, PW_INVENTORY | PW_EQUIPMENT | PW_PLAYER | PW_FLOOR_ITEMS | PW_FOUND_ITEMS);
328     wiz_dark(player_ptr);
329     return true;
330 }