OSDN Git Service

[Refactor] #40233 Separated display-store.c/h from store.c
[hengband/hengband.git] / src / view / status-first-page.c
1 /*!
2  * @file status-first-page.c
3  * @brief キャラ基本情報及び技能値の表示
4  * @date 2020/02/23
5  * @author Hourier
6  */
7
8 #include "view/status-first-page.h"
9 #include "art-definition/art-bow-types.h"
10 #include "art-definition/art-sword-types.h"
11 #include "combat/attack-power-table.h"
12 #include "combat/shoot.h"
13 #include "display-util.h"
14 #include "game-option/text-display-options.h"
15 #include "inventory/inventory-slot-types.h"
16 #include "mutation/mutation-flag-types.h"
17 #include "object-enchant/special-object-flags.h"
18 #include "object-enchant/tr-types.h"
19 #include "object/object-flags.h"
20 #include "perception/object-perception.h"
21 #include "player/special-defense-types.h"
22 #include "sv-definition/sv-weapon-types.h"
23 #include "term/term-color-types.h"
24 #include "util/bit-flags-calculator.h"
25
26 static TERM_COLOR likert_color = TERM_WHITE;
27
28 /*!
29  * @brief 
30  * @param creature_ptr プレーヤーへの参照ポインタ
31  * @param o_ptr 装備中の弓への参照ポインタ
32  * @param shots 射撃回数
33  * @param shot_frac 射撃速度
34  * @return なし
35  */
36 static void calc_shot_params(player_type *creature_ptr, object_type *o_ptr, int *shots, int *shot_frac)
37 {
38         if (o_ptr->k_idx == 0) return;
39
40         ENERGY energy_fire = bow_energy(o_ptr->sval);
41         *shots = creature_ptr->num_fire * 100;
42         *shot_frac = ((*shots) * 100 / energy_fire) % 100;
43         *shots = (*shots) / energy_fire;
44         if (o_ptr->name1 != ART_CRIMSON) return;
45
46         *shots = 1;
47         *shot_frac = 0;
48         if (creature_ptr->pclass != CLASS_ARCHER) return;
49
50         if (creature_ptr->lev >= 10) (*shots)++;
51         if (creature_ptr->lev >= 30) (*shots)++;
52         if (creature_ptr->lev >= 45) (*shots)++;
53 }
54
55
56 /*!
57  * @brief 武器装備に制限のあるクラスで、直接攻撃のダメージを計算する
58  * @param creature_ptr プレーヤーへの参照ポインタ
59  * @param hand 手 (利き手が0、反対の手が1…のはず)
60  * @param damage 直接攻撃のダメージ
61  * @param basedam 素手における直接攻撃のダメージ
62  * @param o_ptr 装備中の武器への参照ポインタ
63  * @return 利き手ならTRUE、反対の手ならFALSE
64  */
65 static bool calc_weapon_damage_limit(player_type *creature_ptr, int hand, int *damage, int *basedam, object_type *o_ptr)
66 {
67         PLAYER_LEVEL level = creature_ptr->lev;
68         if (hand > 0)
69         {
70                 damage[hand] = 0;
71                 return FALSE;
72         }
73
74         if (creature_ptr->pclass == CLASS_FORCETRAINER) level = MAX(1, level - 3);
75         if (creature_ptr->special_defense & KAMAE_BYAKKO)
76                 *basedam = monk_ave_damage[level][1];
77         else if (creature_ptr->special_defense & (KAMAE_GENBU | KAMAE_SUZAKU))
78                 *basedam = monk_ave_damage[level][2];
79         else
80                 *basedam = monk_ave_damage[level][0];
81
82         damage[hand] += *basedam;
83         if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE)) damage[hand] = 1;
84         if (damage[hand] < 0) damage[hand] = 0;
85
86         return TRUE;
87 }
88
89
90 /*!
91  * @brief 片手あたりのダメージ量を計算する
92  * @param o_ptr 装備中の武器への参照ポインタ
93  * @param hand 手
94  * @param damage 直接攻撃のダメージ
95  * @param basedam 素手における直接攻撃のダメージ
96  * @return 素手ならFALSE、武器を持っていればTRUE
97  */
98 static bool calc_weapon_one_hand(object_type *o_ptr, int hand, int *damage, int *basedam)
99 {
100         if (o_ptr->k_idx == 0) return FALSE;
101
102         *basedam = 0;
103         damage[hand] += *basedam;
104         if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE))
105                 damage[hand] = 1;
106
107         if (damage[hand] < 0)
108                 damage[hand] = 0;
109
110         return TRUE;
111 }
112
113
114 /*!
115  * @brief ヴォーパル武器等によるダメージ強化
116  * @param creature_ptr プレーヤーへの参照ポインタ
117  * @param o_ptr 装備中の武器への参照ポインタ
118  * @param basedam 素手における直接攻撃のダメージ
119  * @param flgs オブジェクトフラグ群
120  * @return 強化後の素手ダメージ
121  */
122 static int strengthen_basedam(player_type *creature_ptr, object_type *o_ptr, int basedam, BIT_FLAGS *flgs)
123 {
124         if (object_is_fully_known(o_ptr) && ((o_ptr->name1 == ART_VORPAL_BLADE) || (o_ptr->name1 == ART_CHAINSWORD)))
125         {
126                 /* vorpal blade */
127                 basedam *= 5;
128                 basedam /= 3;
129         }
130         else if (have_flag(flgs, TR_VORPAL))
131         {
132                 /* vorpal flag only */
133                 basedam *= 11;
134                 basedam /= 9;
135         }
136
137         // 理力
138         bool is_force = creature_ptr->pclass != CLASS_SAMURAI;
139         is_force &= have_flag(flgs, TR_FORCE_WEAPON);
140         is_force &= creature_ptr->csp > (o_ptr->dd * o_ptr->ds / 5);
141         if (is_force) basedam = basedam * 7 / 2;
142
143         return basedam;
144 }
145
146
147 /*!
148  * @brief 技能ランクの表示基準を定める
149  * Returns a "rating" of x depending on y
150  * @param x 技能値
151  * @param y 技能値に対するランク基準比
152  * @return なし
153  */
154 static concptr likert(int x, int y)
155 {
156         static char dummy[20] = "", dummy2[20] = "";
157         memset(dummy, 0, strlen(dummy));
158         memset(dummy2, 0, strlen(dummy2));
159         if (y <= 0) y = 1;
160
161         if (show_actual_value)
162                 sprintf(dummy, "%3d-", x);
163
164         if (x < 0)
165         {
166                 likert_color = TERM_L_DARK;
167                 strcat(dummy, _("最低", "Very Bad"));
168                 return dummy;
169         }
170
171         switch ((x / y))
172         {
173         case 0:
174         case 1:
175         {
176                 likert_color = TERM_RED;
177                 strcat(dummy, _("悪い", "Bad"));
178                 break;
179
180         }
181         case 2:
182         {
183                 likert_color = TERM_L_RED;
184                 strcat(dummy, _("劣る", "Poor"));
185                 break;
186         }
187         case 3:
188         case 4:
189         {
190                 likert_color = TERM_ORANGE;
191                 strcat(dummy, _("普通", "Fair"));
192                 break;
193         }
194         case 5:
195         {
196                 likert_color = TERM_YELLOW;
197                 strcat(dummy, _("良い", "Good"));
198                 break;
199         }
200         case 6:
201         {
202                 likert_color = TERM_YELLOW;
203                 strcat(dummy, _("大変良い", "Very Good"));
204                 break;
205         }
206         case 7:
207         case 8:
208         {
209                 likert_color = TERM_L_GREEN;
210                 strcat(dummy, _("卓越", "Excellent"));
211                 break;
212         }
213         case 9:
214         case 10:
215         case 11:
216         case 12:
217         case 13:
218         {
219                 likert_color = TERM_GREEN;
220                 strcat(dummy, _("超越", "Superb"));
221                 break;
222         }
223         case 14:
224         case 15:
225         case 16:
226         case 17:
227         {
228                 likert_color = TERM_BLUE;
229                 strcat(dummy, _("英雄的", "Heroic"));
230                 break;
231         }
232         default:
233         {
234                 likert_color = TERM_VIOLET;
235                 sprintf(dummy2, _("伝説的[%d]", "Legendary[%d]"), (int)((((x / y) - 17) * 5) / 2));
236                 strcat(dummy, dummy2);
237                 break;
238         }
239         }
240
241         return dummy;
242 }
243
244
245 /*!
246  * @brief 弓+両手の武器それぞれについてダメージを計算する
247  * @param creature_ptr プレーヤーへの参照ポインタ
248  * @param damage 直接攻撃のダメージ
249  * @param to_h 命中補正
250  * @return なし
251  */
252 static void calc_two_hands(player_type *creature_ptr, int *damage, int *to_h)
253 {
254         object_type *o_ptr;
255         o_ptr = &creature_ptr->inventory_list[INVEN_BOW];
256         BIT_FLAGS flgs[TR_FLAG_SIZE];
257         for (int i = 0; i < 2; i++)
258         {
259                 int basedam;
260                 damage[i] = creature_ptr->dis_to_d[i] * 100;
261                 if (((creature_ptr->pclass == CLASS_MONK) || (creature_ptr->pclass == CLASS_FORCETRAINER)) && (empty_hands(creature_ptr, TRUE) & EMPTY_HAND_RARM))
262                 {
263                         if (!calc_weapon_damage_limit(creature_ptr, i, damage, &basedam, o_ptr))
264                                 break;
265
266                         continue;
267                 }
268
269                 o_ptr = &creature_ptr->inventory_list[INVEN_RARM + i];
270                 if (!calc_weapon_one_hand(o_ptr, i, damage, &basedam)) continue;
271
272                 to_h[i] = 0;
273                 bool poison_needle = FALSE;
274                 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE)) poison_needle = TRUE;
275                 if (object_is_known(o_ptr))
276                 {
277                         damage[i] += o_ptr->to_d * 100;
278                         to_h[i] += o_ptr->to_h;
279                 }
280
281                 basedam = ((o_ptr->dd + creature_ptr->to_dd[i]) * (o_ptr->ds + creature_ptr->to_ds[i] + 1)) * 50;
282                 object_flags_known(creature_ptr, o_ptr, flgs);
283
284                 basedam = calc_expect_crit(creature_ptr, o_ptr->weight, to_h[i], basedam, creature_ptr->dis_to_h[i], poison_needle);
285                 basedam = strengthen_basedam(creature_ptr, o_ptr, basedam, flgs);
286                 damage[i] += basedam;
287                 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE)) damage[i] = 1;
288                 if (damage[i] < 0) damage[i] = 0;
289         }
290 }
291
292
293 /*!
294  * @brief キャラ基本情報及び技能値をメインウィンドウに表示する
295  * @param creature_ptr プレーヤーへの参照ポインタ
296  * @param xthb 武器等を含めた最終命中率
297  * @param damage 打撃修正
298  * @param shots 射撃回数
299  * @param shot_frac 射撃速度
300  * @param display_player_one_line 1行表示用のコールバック関数
301  * @return なし
302  */
303 static void display_first_page(player_type *creature_ptr, int xthb, int *damage, int shots, int shot_frac)
304 {
305         int xthn = creature_ptr->skill_thn + (creature_ptr->to_h_m * BTH_PLUS_ADJ);
306
307         int muta_att = 0;
308         if (creature_ptr->muta2 & MUT2_HORNS) muta_att++;
309         if (creature_ptr->muta2 & MUT2_SCOR_TAIL) muta_att++;
310         if (creature_ptr->muta2 & MUT2_BEAK) muta_att++;
311         if (creature_ptr->muta2 & MUT2_TRUNK) muta_att++;
312         if (creature_ptr->muta2 & MUT2_TENTACLES) muta_att++;
313
314         int blows1 = creature_ptr->migite ? creature_ptr->num_blow[0] : 0;
315         int blows2 = creature_ptr->hidarite ? creature_ptr->num_blow[1] : 0;
316         int xdis = creature_ptr->skill_dis;
317         int xdev = creature_ptr->skill_dev;
318         int xsav = creature_ptr->skill_sav;
319         int xstl = creature_ptr->skill_stl;
320         int     xsrh = creature_ptr->skill_srh;
321         int     xfos = creature_ptr->skill_fos;
322         int xdig = creature_ptr->skill_dig;
323
324         concptr desc = likert(xthn, 12);
325         display_player_one_line(ENTRY_SKILL_FIGHT, desc, likert_color);
326
327         desc = likert(xthb, 12);
328         display_player_one_line(ENTRY_SKILL_SHOOT, desc, likert_color);
329
330         desc = likert(xsav, 7);
331         display_player_one_line(ENTRY_SKILL_SAVING, desc, likert_color);
332
333         desc = likert((xstl > 0) ? xstl : -1, 1);
334         display_player_one_line(ENTRY_SKILL_STEALTH, desc, likert_color);
335
336         desc = likert(xfos, 6);
337         display_player_one_line(ENTRY_SKILL_PERCEP, desc, likert_color);
338
339         desc = likert(xsrh, 6);
340         display_player_one_line(ENTRY_SKILL_SEARCH, desc, likert_color);
341
342         desc = likert(xdis, 8);
343         display_player_one_line(ENTRY_SKILL_DISARM, desc, likert_color);
344
345         desc = likert(xdev, 6);
346         display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
347
348         desc = likert(xdev, 6);
349         display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
350
351         desc = likert(xdig, 4);
352         display_player_one_line(ENTRY_SKILL_DIG, desc, likert_color);
353
354         if (!muta_att)
355                 display_player_one_line(ENTRY_BLOWS, format("%d+%d", blows1, blows2), TERM_L_BLUE);
356         else
357                 display_player_one_line(ENTRY_BLOWS, format("%d+%d+%d", blows1, blows2, muta_att), TERM_L_BLUE);
358
359         display_player_one_line(ENTRY_SHOTS, format("%d.%02d", shots, shot_frac), TERM_L_BLUE);
360
361         if ((damage[0] + damage[1]) == 0)
362                 desc = "nil!";
363         else
364                 desc = format("%d+%d", blows1 * damage[0] / 100, blows2 * damage[1] / 100);
365
366         display_player_one_line(ENTRY_AVG_DMG, desc, TERM_L_BLUE);
367         display_player_one_line(ENTRY_INFRA, format("%d feet", creature_ptr->see_infra * 10), TERM_WHITE);
368 }
369
370
371 /*!
372  * @brief プレイヤーステータスの1ページ目各種詳細をまとめて表示する
373  * Prints ratings on certain abilities
374  * @param creature_ptr プレーヤーへの参照ポインタ
375  * @param display_player_one_line 1行表示用のコールバック関数
376  * @return なし
377  * @details
378  * This code is "imitated" elsewhere to "dump" a character sheet.
379  */
380 void display_player_various(player_type *creature_ptr)
381 {
382         object_type *o_ptr;
383         o_ptr = &creature_ptr->inventory_list[INVEN_BOW];
384         int tmp = creature_ptr->to_h_b + o_ptr->to_h;
385         int     xthb = creature_ptr->skill_thb + (tmp * BTH_PLUS_ADJ);
386         int     shots = 0;
387         int shot_frac = 0;
388         calc_shot_params(creature_ptr, o_ptr, &shots, &shot_frac);
389
390         int damage[2];
391         int to_h[2];
392         calc_two_hands(creature_ptr, damage, to_h);
393         display_first_page(creature_ptr, xthb, damage, shots, shot_frac);
394 }