OSDN Git Service

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