OSDN Git Service

[Refactor] mind_mirror_master をパスカルケース化
[hengbandforosx/hengbandosx.git] / src / view / display-player-stat-info.cpp
1 /*!
2  * @brief プレイヤーの耐性と能力値を表示する
3  * @date 2020/02/27
4  * @author Hourier
5  * @details
6  * ここにこれ以上関数を引っ越してくるのは禁止。何ならここから更に分割していく
7  */
8
9 #include "view/display-player-stat-info.h"
10 #include "inventory/inventory-slot-types.h"
11 #include "mutation/mutation-flag-types.h"
12 #include "object-enchant/tr-types.h"
13 #include "object/object-flags.h"
14 #include "player-base/player-race.h"
15 #include "player-info/class-info.h"
16 #include "player-info/mimic-info-table.h"
17 #include "player/permanent-resistances.h"
18 #include "player/player-personality.h"
19 #include "player/player-status-table.h"
20 #include "player/player-status.h"
21 #include "system/object-type-definition.h"
22 #include "system/player-type-definition.h"
23 #include "term/screen-processor.h"
24 #include "term/term-color-types.h"
25 #include "util/bit-flags-calculator.h"
26
27 /*!
28  * @brief プレイヤーのパラメータ基礎値 (腕力等)を18以下になるようにして返す
29  * @param player_ptr プレイヤーへの参照ポインタ
30  * @param stat_num 能力値番号
31  * @return 基礎値
32  * @details 最大が18になるのはD&D由来
33  */
34 static int calc_basic_stat(PlayerType *player_ptr, int stat_num)
35 {
36     int e_adj = 0;
37     if ((player_ptr->stat_max[stat_num] > 18) && (player_ptr->stat_top[stat_num] > 18)) {
38         e_adj = (player_ptr->stat_top[stat_num] - player_ptr->stat_max[stat_num]) / 10;
39     }
40
41     if ((player_ptr->stat_max[stat_num] <= 18) && (player_ptr->stat_top[stat_num] <= 18)) {
42         e_adj = player_ptr->stat_top[stat_num] - player_ptr->stat_max[stat_num];
43     }
44
45     if ((player_ptr->stat_max[stat_num] <= 18) && (player_ptr->stat_top[stat_num] > 18)) {
46         e_adj = (player_ptr->stat_top[stat_num] - 18) / 10 - player_ptr->stat_max[stat_num] + 18;
47     }
48
49     if ((player_ptr->stat_max[stat_num] > 18) && (player_ptr->stat_top[stat_num] <= 18)) {
50         e_adj = player_ptr->stat_top[stat_num] - (player_ptr->stat_max[stat_num] - 19) / 10 - 19;
51     }
52
53     return e_adj;
54 }
55
56 /*!
57  * @brief 特殊な種族の時、腕力等の基礎パラメータを変動させる
58  * @param player_ptr プレイヤーへの参照ポインタ
59  * @param stat_num 能力値番号
60  * @return 補正後の基礎パラメータ
61  */
62 static int compensate_special_race(PlayerType *player_ptr, int stat_num)
63 {
64     if (!PlayerRace(player_ptr).equals(PlayerRaceType::ENT)) {
65         return 0;
66     }
67
68     int r_adj = 0;
69     switch (stat_num) {
70     case A_STR:
71     case A_CON:
72         if (player_ptr->lev > 25) {
73             r_adj++;
74         }
75         if (player_ptr->lev > 40) {
76             r_adj++;
77         }
78         if (player_ptr->lev > 45) {
79             r_adj++;
80         }
81         break;
82     case A_DEX:
83         if (player_ptr->lev > 25) {
84             r_adj--;
85         }
86         if (player_ptr->lev > 40) {
87             r_adj--;
88         }
89         if (player_ptr->lev > 45) {
90             r_adj--;
91         }
92         break;
93     }
94
95     return r_adj;
96 }
97
98 /*!
99  * @brief 能力値名を(もし一時的減少なら'x'を付けて)表示する
100  * @param player_ptr プレイヤーへの参照ポインタ
101  * @param stat_num 能力値番号
102  * @param row 行数
103  * @param stat_col 列数
104  */
105 static void display_basic_stat_name(PlayerType *player_ptr, int stat_num, int row, int stat_col)
106 {
107     if (player_ptr->stat_cur[stat_num] < player_ptr->stat_max[stat_num]) {
108         c_put_str(TERM_WHITE, stat_names_reduced[stat_num], row + stat_num + 1, stat_col + 1);
109     } else {
110         c_put_str(TERM_WHITE, stat_names[stat_num], row + stat_num + 1, stat_col + 1);
111     }
112 }
113
114 /*!
115  * @brief 能力値を、基本・種族補正・職業補正・性格補正・装備補正・合計・現在 (一時的減少のみ) の順で表示する
116  * @param player_ptr プレイヤーへの参照ポインタ
117  * @param stat_num 能力値番号
118  * @param r_adj 補正後の基礎パラメータ
119  * @param e_adj 種族補正値
120  * @param row 行数
121  * @param stat_col 列数
122  * @param buf 能力値の数値
123  */
124 static void display_basic_stat_value(PlayerType *player_ptr, int stat_num, int r_adj, int e_adj, int row, int stat_col, char *buf)
125 {
126     (void)sprintf(buf, "%3d", r_adj);
127     c_put_str(TERM_L_BLUE, buf, row + stat_num + 1, stat_col + 13);
128
129     (void)sprintf(buf, "%3d", (int)cp_ptr->c_adj[stat_num]);
130     c_put_str(TERM_L_BLUE, buf, row + stat_num + 1, stat_col + 16);
131
132     (void)sprintf(buf, "%3d", (int)ap_ptr->a_adj[stat_num]);
133     c_put_str(TERM_L_BLUE, buf, row + stat_num + 1, stat_col + 19);
134
135     (void)sprintf(buf, "%3d", (int)e_adj);
136     c_put_str(TERM_L_BLUE, buf, row + stat_num + 1, stat_col + 22);
137
138     cnv_stat(player_ptr->stat_top[stat_num], buf);
139     c_put_str(TERM_L_GREEN, buf, row + stat_num + 1, stat_col + 26);
140
141     if (player_ptr->stat_use[stat_num] < player_ptr->stat_top[stat_num]) {
142         cnv_stat(player_ptr->stat_use[stat_num], buf);
143         c_put_str(TERM_YELLOW, buf, row + stat_num + 1, stat_col + 33);
144     }
145 }
146
147 /*!
148  * @brief 能力値を補正しつつ表示する
149  * @param player_ptr プレイヤーへの参照ポインタ
150  * @param row 行数
151  * @param stat_col 列数
152  */
153 static void process_stats(PlayerType *player_ptr, int row, int stat_col)
154 {
155     char buf[80];
156     for (int i = 0; i < A_MAX; i++) {
157         int r_adj = player_ptr->mimic_form != MimicKindType::NONE ? mimic_info.at(player_ptr->mimic_form).r_adj[i] : rp_ptr->r_adj[i];
158         int e_adj = calc_basic_stat(player_ptr, i);
159         r_adj += compensate_special_race(player_ptr, i);
160         e_adj -= r_adj;
161         e_adj -= cp_ptr->c_adj[i];
162         e_adj -= ap_ptr->a_adj[i];
163
164         display_basic_stat_name(player_ptr, i, row, stat_col);
165         cnv_stat(player_ptr->stat_max[i], buf);
166         if (player_ptr->stat_max[i] == player_ptr->stat_max_max[i]) {
167             c_put_str(TERM_WHITE, "!", row + i + 1, _(stat_col + 6, stat_col + 4));
168         }
169
170         c_put_str(TERM_BLUE, buf, row + i + 1, stat_col + 13 - strlen(buf));
171
172         display_basic_stat_value(player_ptr, i, r_adj, e_adj, row, stat_col, buf);
173     }
174 }
175
176 /*!
177  * @brief pval付きの装備に依るステータス補正を表示する
178  * @param c 補正後の表示記号
179  * @param a 表示色
180  * @param o_ptr 装備品への参照ポインタ
181  * @param stat 能力値番号
182  * @param flags 装備品に立っているフラグ
183  */
184 static void compensate_stat_by_weapon(char *c, TERM_COLOR *a, ObjectType *o_ptr, tr_type tr_flag, const TrFlags &flags)
185 {
186     *c = '*';
187
188     if (o_ptr->pval > 0) {
189         *a = TERM_L_GREEN;
190         if (o_ptr->pval < 10) {
191             *c = '0' + o_ptr->pval;
192         }
193     }
194
195     if (flags.has(tr_flag)) {
196         *a = TERM_GREEN;
197     }
198
199     if (o_ptr->pval < 0) {
200         *a = TERM_RED;
201         if (o_ptr->pval > -10) {
202             *c = '0' - o_ptr->pval;
203         }
204     }
205 }
206
207 /*!
208  * @brief 装備品を走査してpval付きのものをそれと分かるように表示する
209  * @param player_ptr プレイヤーへの参照ポインタ
210  * @param flags 装備品に立っているフラグ
211  * @param row 行数
212  * @param col 列数
213  */
214 static void display_equipments_compensation(PlayerType *player_ptr, int row, int *col)
215 {
216     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
217         ObjectType *o_ptr;
218         o_ptr = &player_ptr->inventory_list[i];
219         auto flags = object_flags_known(o_ptr);
220         for (int stat = 0; stat < A_MAX; stat++) {
221             TERM_COLOR a = TERM_SLATE;
222             char c = '.';
223             if (flags.has(TR_STATUS_LIST[stat])) {
224                 compensate_stat_by_weapon(&c, &a, o_ptr, TR_SUST_STATUS_LIST[stat], flags);
225             } else if (flags.has(TR_SUST_STATUS_LIST[stat])) {
226                 a = TERM_GREEN;
227                 c = 's';
228             }
229
230             term_putch(*col, row + stat + 1, a, c);
231         }
232
233         (*col)++;
234     }
235 }
236
237 /*!
238  * @brief 各能力値の補正
239  * @param player_ptr プレイヤーへの参照ポインタ
240  * @param stat 能力値番号
241  */
242 static int compensation_stat_by_mutation(PlayerType *player_ptr, int stat)
243 {
244     int compensation = 0;
245     if (stat == A_STR) {
246         if (player_ptr->muta.has(PlayerMutationType::HYPER_STR)) {
247             compensation += 4;
248         }
249         if (player_ptr->muta.has(PlayerMutationType::PUNY)) {
250             compensation -= 4;
251         }
252         if (player_ptr->tsuyoshi) {
253             compensation += 4;
254         }
255         return compensation;
256     }
257
258     if (stat == A_WIS || stat == A_INT) {
259         if (player_ptr->muta.has(PlayerMutationType::HYPER_INT)) {
260             compensation += 4;
261         }
262         if (player_ptr->muta.has(PlayerMutationType::MORONIC)) {
263             compensation -= 4;
264         }
265         return compensation;
266     }
267
268     if (stat == A_DEX) {
269         if (player_ptr->muta.has(PlayerMutationType::IRON_SKIN)) {
270             compensation -= 1;
271         }
272         if (player_ptr->muta.has(PlayerMutationType::LIMBER)) {
273             compensation += 3;
274         }
275         if (player_ptr->muta.has(PlayerMutationType::ARTHRITIS)) {
276             compensation -= 3;
277         }
278         return compensation;
279     }
280
281     if (stat == A_CON) {
282         if (player_ptr->muta.has(PlayerMutationType::RESILIENT)) {
283             compensation += 4;
284         }
285         if (player_ptr->muta.has(PlayerMutationType::XTRA_FAT)) {
286             compensation += 2;
287         }
288         if (player_ptr->muta.has(PlayerMutationType::ALBINO)) {
289             compensation -= 4;
290         }
291         if (player_ptr->muta.has(PlayerMutationType::FLESH_ROT)) {
292             compensation -= 2;
293         }
294         if (player_ptr->tsuyoshi) {
295             compensation += 4;
296         }
297         return compensation;
298     }
299
300     if (stat == A_CHR) {
301         if (player_ptr->muta.has(PlayerMutationType::SILLY_VOI)) {
302             compensation -= 4;
303         }
304         if (player_ptr->muta.has(PlayerMutationType::BLANK_FAC)) {
305             compensation -= 1;
306         }
307         if (player_ptr->muta.has(PlayerMutationType::FLESH_ROT)) {
308             compensation -= 1;
309         }
310         if (player_ptr->muta.has(PlayerMutationType::SCALES)) {
311             compensation -= 1;
312         }
313         if (player_ptr->muta.has(PlayerMutationType::WART_SKIN)) {
314             compensation -= 2;
315         }
316         if (player_ptr->muta.has(PlayerMutationType::ILL_NORM)) {
317             compensation = 0;
318         }
319         return compensation;
320     }
321
322     return 0;
323 }
324
325 /*!
326  * @brief 突然変異 (と、つよしスペシャル)による能力値の補正有無で表示する記号を変える
327  * @param player_ptr プレイヤーへの参照ポインタ
328  * @param stat 能力値番号
329  * @param c 補正後の表示記号
330  * @param a 表示色
331  */
332 static void change_display_by_mutation(PlayerType *player_ptr, int stat, char *c, TERM_COLOR *a)
333 {
334     int compensation = compensation_stat_by_mutation(player_ptr, stat);
335     if (compensation == 0) {
336         return;
337     }
338
339     *c = '*';
340     if (compensation > 0) {
341         *a = TERM_L_GREEN;
342         if (compensation < 10) {
343             *c = '0' + compensation;
344         }
345     }
346
347     if (compensation < 0) {
348         *a = TERM_RED;
349         if (compensation > -10) {
350             *c = '0' - compensation;
351         }
352     }
353 }
354
355 /*!
356  * @brief 能力値を走査し、突然変異 (と、つよしスペシャル)で補正をかける必要があればかける
357  * @param player_ptr プレイヤーへの参照ポインタ
358  * @param col 列数
359  * @param row 行数
360  */
361 static void display_mutation_compensation(PlayerType *player_ptr, int row, int col)
362 {
363     TrFlags flags;
364     player_flags(player_ptr, flags);
365
366     for (int stat = 0; stat < A_MAX; stat++) {
367         byte a = TERM_SLATE;
368         char c = '.';
369         change_display_by_mutation(player_ptr, stat, &c, &a);
370
371         if (flags.has(TR_SUST_STATUS_LIST[stat])) {
372             a = TERM_GREEN;
373             c = 's';
374         }
375
376         term_putch(col, row + stat + 1, a, c);
377     }
378 }
379
380 /*!
381  * @brief プレイヤーの特性フラグ一覧表示2b /
382  * Special display, part 2b
383  * @param player_ptr プレイヤーへの参照ポインタ
384  * @details
385  * <pre>
386  * How to print out the modifications and sustains.
387  * Positive mods with no sustain will be light green.
388  * Positive mods with a sustain will be dark green.
389  * Sustains (with no modification) will be a dark green 's'.
390  * Negative mods (from a curse) will be red.
391  * Huge mods (>9), like from MICoMorgoth, will be a '*'
392  * No mod, no sustain, will be a slate '.'
393  * </pre>
394  */
395 void display_player_stat_info(PlayerType *player_ptr)
396 {
397     int stat_col = 22;
398     int row = 3;
399     c_put_str(TERM_WHITE, _("能力", "Stat"), row, stat_col + 1);
400     c_put_str(TERM_BLUE, _("  基本", "  Base"), row, stat_col + 7);
401     c_put_str(TERM_L_BLUE, _(" 種 職 性 装 ", "RacClaPerMod"), row, stat_col + 13);
402     c_put_str(TERM_L_GREEN, _("合計", "Actual"), row, stat_col + 28);
403     c_put_str(TERM_YELLOW, _("現在", "Current"), row, stat_col + 35);
404     process_stats(player_ptr, row, stat_col);
405
406     int col = stat_col + 41;
407     c_put_str(TERM_WHITE, "abcdefghijkl@", row, col);
408     c_put_str(TERM_L_GREEN, _("能力修正", "Modification"), row - 1, col);
409
410     display_equipments_compensation(player_ptr, row, &col);
411     display_mutation_compensation(player_ptr, row, col);
412 }