OSDN Git Service

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