OSDN Git Service

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