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 "game-option/text-display-options.h"
13 #include "inventory/inventory-slot-types.h"
14 #include "mutation/mutation-flag-types.h"
15 #include "object-enchant/special-object-flags.h"
16 #include "object-enchant/tr-types.h"
17 #include "object/tval-types.h"
18 #include "perception/object-perception.h"
19 #include "player-base/player-class.h"
20 #include "player-info/equipment-info.h"
21 #include "player-info/monk-data-type.h"
22 #include "player-status/player-hand-types.h"
23 #include "player/player-status-flags.h"
24 #include "player/special-defense-types.h"
25 #include "sv-definition/sv-weapon-types.h"
26 #include "system/item-entity.h"
27 #include "system/player-type-definition.h"
28 #include "term/term-color-types.h"
29 #include "term/z-form.h"
30 #include "util/bit-flags-calculator.h"
31 #include "view/display-util.h"
35 * @param player_ptr プレイヤーへの参照ポインタ
36 * @param o_ptr 装備中の弓への参照ポインタ
38 * @param shot_frac 射撃速度
40 static void calc_shot_params(PlayerType *player_ptr, ItemEntity *o_ptr, int *shots, int *shot_frac)
42 if (!o_ptr->is_valid()) {
46 const auto energy_fire = o_ptr->get_bow_energy();
47 *shots = player_ptr->num_fire * 100;
48 *shot_frac = ((*shots) * 100 / energy_fire) % 100;
49 *shots = (*shots) / energy_fire;
50 if (!o_ptr->is_specific_artifact(FixedArtifactId::CRIMSON)) {
56 if (!PlayerClass(player_ptr).equals(PlayerClassType::ARCHER)) {
60 if (player_ptr->lev >= 10) {
63 if (player_ptr->lev >= 30) {
66 if (player_ptr->lev >= 45) {
72 * @brief 武器装備に制限のあるクラスで、直接攻撃のダメージを計算する
73 * @param player_ptr プレイヤーへの参照ポインタ
74 * @param hand 手 (利き手が0、反対の手が1…のはず)
75 * @param damage 直接攻撃のダメージ
76 * @param basedam 素手における直接攻撃のダメージ
77 * @param o_ptr 装備中の武器への参照ポインタ
78 * @return 利き手ならTRUE、反対の手ならFALSE
80 static bool calc_weapon_damage_limit(PlayerType *player_ptr, int hand, int *damage, int *basedam, ItemEntity *o_ptr)
82 PLAYER_LEVEL level = player_ptr->lev;
88 PlayerClass pc(player_ptr);
89 if (pc.equals(PlayerClassType::FORCETRAINER)) {
90 level = std::max<short>(1, level - 3);
93 if (pc.monk_stance_is(MonkStanceType::BYAKKO)) {
94 *basedam = monk_ave_damage[level][1];
95 } else if (pc.monk_stance_is(MonkStanceType::GENBU) || pc.monk_stance_is(MonkStanceType::SUZAKU)) {
96 *basedam = monk_ave_damage[level][2];
98 *basedam = monk_ave_damage[level][0];
101 damage[hand] += *basedam;
102 if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
105 if (damage[hand] < 0) {
113 * @brief 片手あたりのダメージ量を計算する
114 * @param o_ptr 装備中の武器への参照ポインタ
116 * @param damage 直接攻撃のダメージ
117 * @param basedam 素手における直接攻撃のダメージ
118 * @return 素手ならFALSE、武器を持っていればTRUE
120 static bool calc_weapon_one_hand(ItemEntity *o_ptr, int hand, int *damage, int *basedam)
122 if (!o_ptr->is_valid()) {
127 damage[hand] += *basedam;
128 if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
132 if (damage[hand] < 0) {
140 * @brief ヴォーパル武器等によるダメージ強化
141 * @param player_ptr プレイヤーへの参照ポインタ
142 * @param o_ptr 装備中の武器への参照ポインタ
143 * @param basedam 素手における直接攻撃のダメージ
144 * @param flags オブジェクトフラグ群
146 * @todo ヴォーパル計算処理が building-craft-weapon::compare_weapon_aux() と多重実装.
148 static int strengthen_basedam(PlayerType *player_ptr, ItemEntity *o_ptr, int basedam, const TrFlags &flags)
150 const auto is_vorpal_blade = o_ptr->is_specific_artifact(FixedArtifactId::VORPAL_BLADE);
151 const auto is_chainsword = o_ptr->is_specific_artifact(FixedArtifactId::CHAINSWORD);
152 if (o_ptr->is_fully_known() && (is_vorpal_blade || is_chainsword)) {
156 } else if (flags.has(TR_VORPAL)) {
157 /* vorpal flag only */
163 bool is_force = !PlayerClass(player_ptr).equals(PlayerClassType::SAMURAI);
164 is_force &= flags.has(TR_FORCE_WEAPON);
165 is_force &= player_ptr->csp > (o_ptr->dd * o_ptr->ds / 5);
167 basedam = basedam * 7 / 2;
174 * @brief 技能ランクの表示基準を定める
175 * Returns a "rating" of x depending on y
177 * @param y 技能値に対するランク基準比
178 * @return スキル レベルのテキスト説明とその説明のカラー インデックスのペア
180 static std::pair<std::string, TERM_COLOR> likert(int x, int y)
184 if (show_actual_value) {
185 desc = format("%3d-", x);
189 return make_pair(desc.append(_("最低", "Very Bad")), TERM_L_DARK);
199 return make_pair(desc.append(_("悪い", "Bad")), TERM_RED);
202 return make_pair(desc.append(_("劣る", "Poor")), TERM_L_RED);
206 return make_pair(desc.append(_("普通", "Fair")), TERM_ORANGE);
209 return make_pair(desc.append(_("良い", "Good")), TERM_YELLOW);
212 return make_pair(desc.append(_("大変良い", "Very Good")), TERM_YELLOW);
216 return make_pair(desc.append(_("卓越", "Excellent")), TERM_L_GREEN);
223 return make_pair(desc.append(_("超越", "Superb")), TERM_GREEN);
229 return make_pair(desc.append(_("英雄的", "Heroic")), TERM_BLUE);
232 desc.append(format(_("伝説的[%d]", "Legendary[%d]"), (int)((((x / y) - 17) * 5) / 2)));
233 return make_pair(desc, TERM_VIOLET);
239 * @brief 弓+両手の武器それぞれについてダメージを計算する
240 * @param player_ptr プレイヤーへの参照ポインタ
241 * @param damage 直接攻撃のダメージ
244 static void calc_two_hands(PlayerType *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 PlayerClass pc(player_ptr);
253 if (pc.is_martial_arts_pro() && (empty_hands(player_ptr, true) & EMPTY_HAND_MAIN)) {
254 if (!calc_weapon_damage_limit(player_ptr, i, damage, &basedam, o_ptr)) {
261 o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + i];
262 if (!calc_weapon_one_hand(o_ptr, i, damage, &basedam)) {
267 auto poison_needle = false;
268 if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
269 poison_needle = true;
272 if (o_ptr->is_known()) {
273 damage[i] += o_ptr->to_d * 100;
274 to_h[i] += o_ptr->to_h;
277 basedam = ((o_ptr->dd + player_ptr->to_dd[i]) * (o_ptr->ds + player_ptr->to_ds[i] + 1)) * 50;
278 auto flags = o_ptr->get_flags_known();
280 bool impact = player_ptr->impact != 0;
281 basedam = calc_expect_crit(player_ptr, o_ptr->weight, to_h[i], basedam, player_ptr->dis_to_h[i], poison_needle, impact);
282 basedam = strengthen_basedam(player_ptr, o_ptr, basedam, flags);
283 damage[i] += basedam;
284 if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
294 * @brief キャラ基本情報及び技能値をメインウィンドウに表示する
295 * @param player_ptr プレイヤーへの参照ポインタ
296 * @param xthb 武器等を含めた最終命中率
299 * @param shot_frac 射撃速度
300 * @param display_player_one_line 1行表示用のコールバック関数
302 static void display_first_page(PlayerType *player_ptr, int xthb, int *damage, int shots, int shot_frac)
304 int xthn = player_ptr->skill_thn + (player_ptr->to_h_m * BTH_PLUS_ADJ);
307 if (player_ptr->muta.has(PlayerMutationType::HORNS)) {
310 if (player_ptr->muta.has(PlayerMutationType::SCOR_TAIL)) {
313 if (player_ptr->muta.has(PlayerMutationType::BEAK)) {
316 if (player_ptr->muta.has(PlayerMutationType::TRUNK)) {
319 if (player_ptr->muta.has(PlayerMutationType::TENTACLES)) {
323 int blows1 = can_attack_with_main_hand(player_ptr) ? player_ptr->num_blow[0] : 0;
324 int blows2 = can_attack_with_sub_hand(player_ptr) ? player_ptr->num_blow[1] : 0;
325 int xdis = player_ptr->skill_dis;
326 int xdev = player_ptr->skill_dev;
327 int xsav = player_ptr->skill_sav;
328 int xstl = player_ptr->skill_stl;
329 int xsrh = player_ptr->skill_srh;
330 int xfos = player_ptr->skill_fos;
331 int xdig = player_ptr->skill_dig;
333 auto sd = likert(xthn, 12);
334 display_player_one_line(ENTRY_SKILL_FIGHT, sd.first, sd.second);
336 sd = likert(xthb, 12);
337 display_player_one_line(ENTRY_SKILL_SHOOT, sd.first, sd.second);
339 sd = likert(xsav, 7);
340 display_player_one_line(ENTRY_SKILL_SAVING, sd.first, sd.second);
342 sd = likert((xstl > 0) ? xstl : -1, 1);
343 display_player_one_line(ENTRY_SKILL_STEALTH, sd.first, sd.second);
345 sd = likert(xfos, 6);
346 display_player_one_line(ENTRY_SKILL_PERCEP, sd.first, sd.second);
348 sd = likert(xsrh, 6);
349 display_player_one_line(ENTRY_SKILL_SEARCH, sd.first, sd.second);
351 sd = likert(xdis, 8);
352 display_player_one_line(ENTRY_SKILL_DISARM, sd.first, sd.second);
354 sd = likert(xdev, 6);
355 display_player_one_line(ENTRY_SKILL_DEVICE, sd.first, sd.second);
357 sd = likert(xdig, 4);
358 display_player_one_line(ENTRY_SKILL_DIG, sd.first, sd.second);
361 display_player_one_line(ENTRY_BLOWS, format("%d+%d", blows1, blows2), TERM_L_BLUE);
363 display_player_one_line(ENTRY_BLOWS, format("%d+%d+%d", blows1, blows2, muta_att), TERM_L_BLUE);
366 display_player_one_line(ENTRY_SHOTS, format("%d.%02d", shots, shot_frac), TERM_L_BLUE);
369 if ((damage[0] + damage[1]) == 0) {
372 desc = format("%d+%d", blows1 * damage[0] / 100, blows2 * damage[1] / 100);
375 display_player_one_line(ENTRY_AVG_DMG, desc, TERM_L_BLUE);
376 display_player_one_line(ENTRY_INFRA, format("%d feet", player_ptr->see_infra * 10), TERM_WHITE);
380 * @brief プレイヤーステータスの1ページ目各種詳細をまとめて表示する
381 * Prints ratings on certain abilities
382 * @param player_ptr プレイヤーへの参照ポインタ
383 * @param display_player_one_line 1行表示用のコールバック関数
385 * This code is "imitated" elsewhere to "dump" a character sheet.
387 void display_player_various(PlayerType *player_ptr)
390 o_ptr = &player_ptr->inventory_list[INVEN_BOW];
391 int tmp = player_ptr->to_h_b + o_ptr->to_h;
392 int xthb = player_ptr->skill_thb + (tmp * BTH_PLUS_ADJ);
395 calc_shot_params(player_ptr, o_ptr, &shots, &shot_frac);
399 calc_two_hands(player_ptr, damage, to_h);
400 display_first_page(player_ptr, xthb, damage, shots, shot_frac);