OSDN Git Service

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