2 * @file status-first-page.c
3 * @brief キャラ基本情報及び技能値の表示
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-info/equipment-info.h"
21 #include "player-status/player-hand-types.h"
22 #include "player/player-status-flags.h"
23 #include "player/special-defense-types.h"
24 #include "sv-definition/sv-weapon-types.h"
25 #include "system/object-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "term/term-color-types.h"
28 #include "util/bit-flags-calculator.h"
30 static TERM_COLOR likert_color = TERM_WHITE;
34 * @param player_ptr プレイヤーへの参照ポインタ
35 * @param o_ptr 装備中の弓への参照ポインタ
37 * @param shot_frac 射撃速度
39 static void calc_shot_params(player_type *player_ptr, object_type *o_ptr, int *shots, int *shot_frac)
41 if (o_ptr->k_idx == 0)
44 ENERGY energy_fire = bow_energy(o_ptr->sval);
45 *shots = player_ptr->num_fire * 100;
46 *shot_frac = ((*shots) * 100 / energy_fire) % 100;
47 *shots = (*shots) / energy_fire;
48 if (o_ptr->name1 != ART_CRIMSON)
53 if (player_ptr->pclass != CLASS_ARCHER)
56 if (player_ptr->lev >= 10)
58 if (player_ptr->lev >= 30)
60 if (player_ptr->lev >= 45)
65 * @brief 武器装備に制限のあるクラスで、直接攻撃のダメージを計算する
66 * @param player_ptr プレイヤーへの参照ポインタ
67 * @param hand 手 (利き手が0、反対の手が1…のはず)
68 * @param damage 直接攻撃のダメージ
69 * @param basedam 素手における直接攻撃のダメージ
70 * @param o_ptr 装備中の武器への参照ポインタ
71 * @return 利き手ならTRUE、反対の手ならFALSE
73 static bool calc_weapon_damage_limit(player_type *player_ptr, int hand, int *damage, int *basedam, object_type *o_ptr)
75 PLAYER_LEVEL level = player_ptr->lev;
81 if (player_ptr->pclass == CLASS_FORCETRAINER)
82 level = MAX(1, level - 3);
83 if (player_ptr->special_defense & KAMAE_BYAKKO)
84 *basedam = monk_ave_damage[level][1];
85 else if (player_ptr->special_defense & (KAMAE_GENBU | KAMAE_SUZAKU))
86 *basedam = monk_ave_damage[level][2];
88 *basedam = monk_ave_damage[level][0];
90 damage[hand] += *basedam;
91 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE))
100 * @brief 片手あたりのダメージ量を計算する
101 * @param o_ptr 装備中の武器への参照ポインタ
103 * @param damage 直接攻撃のダメージ
104 * @param basedam 素手における直接攻撃のダメージ
105 * @return 素手ならFALSE、武器を持っていればTRUE
107 static bool calc_weapon_one_hand(object_type *o_ptr, int hand, int *damage, int *basedam)
109 if (o_ptr->k_idx == 0)
113 damage[hand] += *basedam;
114 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE))
117 if (damage[hand] < 0)
124 * @brief ヴォーパル武器等によるダメージ強化
125 * @param player_ptr プレイヤーへの参照ポインタ
126 * @param o_ptr 装備中の武器への参照ポインタ
127 * @param basedam 素手における直接攻撃のダメージ
128 * @param flgs オブジェクトフラグ群
131 static int strengthen_basedam(player_type *player_ptr, object_type *o_ptr, int basedam, const TrFlags &flgs)
133 if (o_ptr->is_fully_known() && ((o_ptr->name1 == ART_VORPAL_BLADE) || (o_ptr->name1 == ART_CHAINSWORD))) {
137 } else if (flgs.has(TR_VORPAL)) {
138 /* vorpal flag only */
144 bool is_force = player_ptr->pclass != CLASS_SAMURAI;
145 is_force &= flgs.has(TR_FORCE_WEAPON);
146 is_force &= player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5);
148 basedam = basedam * 7 / 2;
154 * @brief 技能ランクの表示基準を定める
155 * Returns a "rating" of x depending on y
157 * @param y 技能値に対するランク基準比
159 static concptr likert(int x, int y)
161 static char dummy[20] = "", dummy2[20] = "";
162 memset(dummy, 0, strlen(dummy));
163 memset(dummy2, 0, strlen(dummy2));
167 if (show_actual_value)
168 sprintf(dummy, "%3d-", x);
171 likert_color = TERM_L_DARK;
172 strcat(dummy, _("最低", "Very Bad"));
179 likert_color = TERM_RED;
180 strcat(dummy, _("悪い", "Bad"));
184 likert_color = TERM_L_RED;
185 strcat(dummy, _("劣る", "Poor"));
190 likert_color = TERM_ORANGE;
191 strcat(dummy, _("普通", "Fair"));
195 likert_color = TERM_YELLOW;
196 strcat(dummy, _("良い", "Good"));
200 likert_color = TERM_YELLOW;
201 strcat(dummy, _("大変良い", "Very Good"));
206 likert_color = TERM_L_GREEN;
207 strcat(dummy, _("卓越", "Excellent"));
215 likert_color = TERM_GREEN;
216 strcat(dummy, _("超越", "Superb"));
223 likert_color = TERM_BLUE;
224 strcat(dummy, _("英雄的", "Heroic"));
228 likert_color = TERM_VIOLET;
229 sprintf(dummy2, _("伝説的[%d]", "Legendary[%d]"), (int)((((x / y) - 17) * 5) / 2));
230 strcat(dummy, dummy2);
239 * @brief 弓+両手の武器それぞれについてダメージを計算する
240 * @param player_ptr プレイヤーへの参照ポインタ
241 * @param damage 直接攻撃のダメージ
244 static void calc_two_hands(player_type *player_ptr, int *damage, int *to_h)
247 o_ptr = &player_ptr->inventory_list[INVEN_BOW];
249 for (int i = 0; i < 2; i++) {
251 damage[i] = player_ptr->dis_to_d[i] * 100;
252 if (((player_ptr->pclass == CLASS_MONK) || (player_ptr->pclass == CLASS_FORCETRAINER)) && (empty_hands(player_ptr, true) & EMPTY_HAND_MAIN)) {
253 if (!calc_weapon_damage_limit(player_ptr, i, damage, &basedam, o_ptr))
259 o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
260 if (!calc_weapon_one_hand(o_ptr, i, damage, &basedam))
264 bool poison_needle = false;
265 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE))
266 poison_needle = true;
267 if (o_ptr->is_known()) {
268 damage[i] += o_ptr->to_d * 100;
269 to_h[i] += o_ptr->to_h;
272 basedam = ((o_ptr->dd + player_ptr->to_dd[i]) * (o_ptr->ds + player_ptr->to_ds[i] + 1)) * 50;
273 auto flgs = object_flags_known(o_ptr);
275 bool impact = player_ptr->impact != 0;
276 basedam = calc_expect_crit(player_ptr, o_ptr->weight, to_h[i], basedam, player_ptr->dis_to_h[i], poison_needle, impact);
277 basedam = strengthen_basedam(player_ptr, o_ptr, basedam, flgs);
278 damage[i] += basedam;
279 if ((o_ptr->tval == TV_SWORD) && (o_ptr->sval == SV_POISON_NEEDLE))
287 * @brief キャラ基本情報及び技能値をメインウィンドウに表示する
288 * @param player_ptr プレイヤーへの参照ポインタ
289 * @param xthb 武器等を含めた最終命中率
292 * @param shot_frac 射撃速度
293 * @param display_player_one_line 1行表示用のコールバック関数
295 static void display_first_page(player_type *player_ptr, int xthb, int *damage, int shots, int shot_frac)
297 int xthn = player_ptr->skill_thn + (player_ptr->to_h_m * BTH_PLUS_ADJ);
300 if (player_ptr->muta.has(MUTA::HORNS))
302 if (player_ptr->muta.has(MUTA::SCOR_TAIL))
304 if (player_ptr->muta.has(MUTA::BEAK))
306 if (player_ptr->muta.has(MUTA::TRUNK))
308 if (player_ptr->muta.has(MUTA::TENTACLES))
311 int blows1 = can_attack_with_main_hand(player_ptr) ? player_ptr->num_blow[0] : 0;
312 int blows2 = can_attack_with_sub_hand(player_ptr) ? player_ptr->num_blow[1] : 0;
313 int xdis = player_ptr->skill_dis;
314 int xdev = player_ptr->skill_dev;
315 int xsav = player_ptr->skill_sav;
316 int xstl = player_ptr->skill_stl;
317 int xsrh = player_ptr->skill_srh;
318 int xfos = player_ptr->skill_fos;
319 int xdig = player_ptr->skill_dig;
321 concptr desc = likert(xthn, 12);
322 display_player_one_line(ENTRY_SKILL_FIGHT, desc, likert_color);
324 desc = likert(xthb, 12);
325 display_player_one_line(ENTRY_SKILL_SHOOT, desc, likert_color);
327 desc = likert(xsav, 7);
328 display_player_one_line(ENTRY_SKILL_SAVING, desc, likert_color);
330 desc = likert((xstl > 0) ? xstl : -1, 1);
331 display_player_one_line(ENTRY_SKILL_STEALTH, desc, likert_color);
333 desc = likert(xfos, 6);
334 display_player_one_line(ENTRY_SKILL_PERCEP, desc, likert_color);
336 desc = likert(xsrh, 6);
337 display_player_one_line(ENTRY_SKILL_SEARCH, desc, likert_color);
339 desc = likert(xdis, 8);
340 display_player_one_line(ENTRY_SKILL_DISARM, desc, likert_color);
342 desc = likert(xdev, 6);
343 display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
345 desc = likert(xdev, 6);
346 display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
348 desc = likert(xdig, 4);
349 display_player_one_line(ENTRY_SKILL_DIG, desc, likert_color);
352 display_player_one_line(ENTRY_BLOWS, format("%d+%d", blows1, blows2), TERM_L_BLUE);
354 display_player_one_line(ENTRY_BLOWS, format("%d+%d+%d", blows1, blows2, muta_att), TERM_L_BLUE);
356 display_player_one_line(ENTRY_SHOTS, format("%d.%02d", shots, shot_frac), TERM_L_BLUE);
358 if ((damage[0] + damage[1]) == 0)
361 desc = format("%d+%d", blows1 * damage[0] / 100, blows2 * damage[1] / 100);
363 display_player_one_line(ENTRY_AVG_DMG, desc, TERM_L_BLUE);
364 display_player_one_line(ENTRY_INFRA, format("%d feet", player_ptr->see_infra * 10), TERM_WHITE);
368 * @brief プレイヤーステータスの1ページ目各種詳細をまとめて表示する
369 * Prints ratings on certain abilities
370 * @param player_ptr プレイヤーへの参照ポインタ
371 * @param display_player_one_line 1行表示用のコールバック関数
373 * This code is "imitated" elsewhere to "dump" a character sheet.
375 void display_player_various(player_type *player_ptr)
378 o_ptr = &player_ptr->inventory_list[INVEN_BOW];
379 int tmp = player_ptr->to_h_b + o_ptr->to_h;
380 int xthb = player_ptr->skill_thb + (tmp * BTH_PLUS_ADJ);
383 calc_shot_params(player_ptr, o_ptr, &shots, &shot_frac);
387 calc_two_hands(player_ptr, damage, to_h);
388 display_first_page(player_ptr, xthb, damage, shots, shot_frac);