OSDN Git Service

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