OSDN Git Service

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