OSDN Git Service

80dab8832fbb5ad0a075c1258a0974461cdc7590
[hengbandforosx/hengbandosx.git] / src / window / main-window-stat-poster.cpp
1 #include "window/main-window-stat-poster.h"
2 #include "game-option/game-play-options.h"
3 #include "io/input-key-requester.h"
4 #include "mind/stances-table.h"
5 #include "monster/monster-status.h"
6 #include "player-base/player-class.h"
7 #include "player-info/bluemage-data-type.h"
8 #include "player-info/mane-data-type.h"
9 #include "player-info/monk-data-type.h"
10 #include "player-info/ninja-data-type.h"
11 #include "player-info/samurai-data-type.h"
12 #include "player-info/sniper-data-type.h"
13 #include "player/attack-defense-types.h"
14 #include "player/digestion-processor.h"
15 #include "player/player-status-table.h"
16 #include "player/player-status.h"
17 #include "realm/realm-hex-numbers.h"
18 #include "realm/realm-types.h"
19 #include "spell-realm/spells-hex.h"
20 #include "status/element-resistance.h"
21 #include "system/floor-type-definition.h"
22 #include "system/monster-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "term/screen-processor.h"
25 #include "term/term-color-types.h"
26 #include "timed-effect/player-cut.h"
27 #include "timed-effect/player-stun.h"
28 #include "timed-effect/timed-effects.h"
29 #include "view/status-bars-table.h"
30 #include "window/main-window-row-column.h"
31
32 /*!
33  * @brief 32ビット変数配列の指定位置のビットフラグを1にする。
34  * @param FLG フラグ位置(ビット)
35  */
36 #define ADD_BAR_FLAG(FLG) (bar_flags[FLG / 32] |= (1UL << (FLG % 32)))
37
38 /*!
39  * @brief 32ビット変数配列の指定位置のビットフラグが1かどうかを返す。
40  * @param FLG フラグ位置(ビット)
41  * @return 1ならば0以外を返す
42  */
43 #define IS_BAR_FLAG(FLG) (bar_flags[FLG / 32] & (1UL << (FLG % 32)))
44
45 /*!
46  * @brief プレイヤー能力値を描画する / Print character stat in given row, column
47  * @param stat 描画するステータスのID
48  */
49 void print_stat(PlayerType *player_ptr, int stat)
50 {
51     GAME_TEXT tmp[32];
52     if (player_ptr->stat_cur[stat] < player_ptr->stat_max[stat]) {
53         put_str(stat_names_reduced[stat], ROW_STAT + stat, 0);
54         cnv_stat(player_ptr->stat_use[stat], tmp);
55         c_put_str(TERM_YELLOW, tmp, ROW_STAT + stat, COL_STAT + 6);
56     } else {
57         put_str(stat_names[stat], ROW_STAT + stat, 0);
58         cnv_stat(player_ptr->stat_use[stat], tmp);
59         c_put_str(TERM_L_GREEN, tmp, ROW_STAT + stat, COL_STAT + 6);
60     }
61
62     if (player_ptr->stat_max[stat] != player_ptr->stat_max_max[stat])
63         return;
64
65 #ifdef JP
66     /* 日本語にかぶらないように表示位置を変更 */
67     put_str("!", ROW_STAT + stat, 5);
68 #else
69     put_str("!", ROW_STAT + stat, 3);
70 #endif
71 }
72
73 /*!
74  * @brief プレイヤーの負傷状態を表示する
75  */
76 void print_cut(PlayerType *player_ptr)
77 {
78     auto player_cut = player_ptr->effects()->cut();
79     if (!player_cut->is_cut()) {
80         put_str("            ", ROW_CUT, COL_CUT);
81         return;
82     }
83
84     auto [color, stat] = player_cut->get_expr();
85     c_put_str(color, stat.data(), ROW_CUT, COL_CUT);
86 }
87
88 /*!
89  * @brief プレイヤーの朦朧状態を表示する
90  * @param player_ptr プレイヤーへの参照ポインタ
91  */
92 void print_stun(PlayerType *player_ptr)
93 {
94     auto player_stun = player_ptr->effects()->stun();
95     if (!player_stun->is_stunned()) {
96         put_str("            ", ROW_STUN, COL_STUN);
97         return;
98     }
99
100     auto [color, stat] = player_stun->get_expr();
101     c_put_str(color, stat.data(), ROW_STUN, COL_STUN);
102 }
103
104 /*!
105  * @brief プレイヤーの空腹状態を表示する / Prints status of hunger
106  * @param player_ptr プレイヤーへの参照ポインタ
107  */
108 void print_hunger(PlayerType *player_ptr)
109 {
110     if (allow_debug_options && player_ptr->current_floor_ptr->inside_arena)
111         return;
112
113     if (player_ptr->food < PY_FOOD_FAINT) {
114         c_put_str(TERM_RED, _("衰弱  ", "Weak  "), ROW_HUNGRY, COL_HUNGRY);
115         return;
116     }
117
118     if (player_ptr->food < PY_FOOD_WEAK) {
119         c_put_str(TERM_ORANGE, _("衰弱  ", "Weak  "), ROW_HUNGRY, COL_HUNGRY);
120         return;
121     }
122
123     if (player_ptr->food < PY_FOOD_ALERT) {
124         c_put_str(TERM_YELLOW, _("空腹  ", "Hungry"), ROW_HUNGRY, COL_HUNGRY);
125         return;
126     }
127
128     if (player_ptr->food < PY_FOOD_FULL) {
129         c_put_str(TERM_L_GREEN, "      ", ROW_HUNGRY, COL_HUNGRY);
130         return;
131     }
132
133     if (player_ptr->food < PY_FOOD_MAX) {
134         c_put_str(TERM_L_GREEN, _("満腹  ", "Full  "), ROW_HUNGRY, COL_HUNGRY);
135         return;
136     }
137
138     c_put_str(TERM_GREEN, _("食過ぎ", "Gorged"), ROW_HUNGRY, COL_HUNGRY);
139 }
140
141 /*!
142  * @brief プレイヤーの行動状態を表示する / Prints Searching, Resting, Paralysis, or 'count' status
143  * @param player_ptr プレイヤーへの参照ポインタ
144  * @details
145  * Display is always exactly 10 characters wide (see below)
146  * This function was a major bottleneck when resting, so a lot of
147  * the text formatting code was optimized in place below.
148  */
149 void print_state(PlayerType *player_ptr)
150 {
151     TERM_COLOR attr = TERM_WHITE;
152     GAME_TEXT text[16];
153     if (command_rep) {
154         if (command_rep > 999) {
155             (void)sprintf(text, "%2d00", command_rep / 100);
156         } else {
157             (void)sprintf(text, "  %2d", command_rep);
158         }
159
160         c_put_str(attr, format("%5.5s", text), ROW_STATE, COL_STATE);
161         return;
162     }
163
164     switch (player_ptr->action) {
165     case ACTION_SEARCH: {
166         strcpy(text, _("探索", "Sear"));
167         break;
168     }
169     case ACTION_REST:
170         strcpy(text, _("    ", "    "));
171         if (player_ptr->resting > 0) {
172             sprintf(text, "%4d", player_ptr->resting);
173         } else if (player_ptr->resting == COMMAND_ARG_REST_FULL_HEALING) {
174             text[0] = text[1] = text[2] = text[3] = '*';
175         } else if (player_ptr->resting == COMMAND_ARG_REST_UNTIL_DONE) {
176             text[0] = text[1] = text[2] = text[3] = '&';
177         }
178
179         break;
180
181     case ACTION_LEARN: {
182         strcpy(text, _("学習", "lear"));
183         auto bluemage_data = PlayerClass(player_ptr).get_specific_data<bluemage_data_type>();
184         if (bluemage_data->new_magic_learned)
185             attr = TERM_L_RED;
186         break;
187     }
188     case ACTION_FISH: {
189         strcpy(text, _("釣り", "fish"));
190         break;
191     }
192     case ACTION_MONK_STANCE: {
193         if (auto stance = PlayerClass(player_ptr).get_monk_stance();
194             stance != MonkStanceType::NONE) {
195             switch (stance) {
196             case MonkStanceType::GENBU:
197                 attr = TERM_GREEN;
198                 break;
199             case MonkStanceType::BYAKKO:
200                 attr = TERM_WHITE;
201                 break;
202             case MonkStanceType::SEIRYU:
203                 attr = TERM_L_BLUE;
204                 break;
205             case MonkStanceType::SUZAKU:
206                 attr = TERM_L_RED;
207                 break;
208             default:
209                 break;
210             }
211             strcpy(text, monk_stances[enum2i(stance) - 1].desc);
212         }
213         break;
214     }
215     case ACTION_SAMURAI_STANCE: {
216         if (auto stance = PlayerClass(player_ptr).get_samurai_stance();
217             stance != SamuraiStanceType::NONE) {
218             strcpy(text, samurai_stances[enum2i(stance) - 1].desc);
219         }
220         break;
221     }
222     case ACTION_SING: {
223         strcpy(text, _("歌  ", "Sing"));
224         break;
225     }
226     case ACTION_HAYAGAKE: {
227         strcpy(text, _("速駆", "Fast"));
228         break;
229     }
230     case ACTION_SPELL: {
231         strcpy(text, _("詠唱", "Spel"));
232         break;
233     }
234     default: {
235         strcpy(text, "    ");
236         break;
237     }
238     }
239
240     c_put_str(attr, format("%5.5s", text), ROW_STATE, COL_STATE);
241 }
242
243 /*!
244  * @brief プレイヤーの行動速度を表示する / Prints the speed_value of a character.                        -CJS-
245  * @param player_ptr プレイヤーへの参照ポインタ
246  */
247 void print_speed(PlayerType *player_ptr)
248 {
249     TERM_LEN wid, hgt;
250     term_get_size(&wid, &hgt);
251     TERM_LEN col_speed = wid + COL_SPEED;
252     TERM_LEN row_speed = hgt + ROW_SPEED;
253
254     int speed_value = player_ptr->pspeed - 110;
255
256     floor_type *floor_ptr = player_ptr->current_floor_ptr;
257     bool is_player_fast = is_fast(player_ptr);
258     char buf[32] = "";
259     TERM_COLOR attr = TERM_WHITE;
260     if (speed_value > 0) {
261         if (player_ptr->riding) {
262             monster_type *m_ptr = &floor_ptr->m_list[player_ptr->riding];
263             if (monster_fast_remaining(m_ptr) && !monster_slow_remaining(m_ptr))
264                 attr = TERM_L_BLUE;
265             else if (monster_slow_remaining(m_ptr) && !monster_fast_remaining(m_ptr))
266                 attr = TERM_VIOLET;
267             else
268                 attr = TERM_GREEN;
269         } else if ((is_player_fast && !player_ptr->slow) || player_ptr->lightspeed)
270             attr = TERM_YELLOW;
271         else if (player_ptr->slow && !is_player_fast)
272             attr = TERM_VIOLET;
273         else
274             attr = TERM_L_GREEN;
275         sprintf(buf, "%s(+%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("加速", "Fast")), speed_value);
276     } else if (speed_value < 0) {
277         if (player_ptr->riding) {
278             monster_type *m_ptr = &floor_ptr->m_list[player_ptr->riding];
279             if (monster_fast_remaining(m_ptr) && !monster_slow_remaining(m_ptr))
280                 attr = TERM_L_BLUE;
281             else if (monster_slow_remaining(m_ptr) && !monster_fast_remaining(m_ptr))
282                 attr = TERM_VIOLET;
283             else
284                 attr = TERM_RED;
285         } else if (is_player_fast && !player_ptr->slow)
286             attr = TERM_YELLOW;
287         else if (player_ptr->slow && !is_player_fast)
288             attr = TERM_VIOLET;
289         else
290             attr = TERM_L_UMBER;
291         sprintf(buf, "%s(%d)", (player_ptr->riding ? _("乗馬", "Ride") : _("減速", "Slow")), speed_value);
292     } else if (player_ptr->riding) {
293         attr = TERM_GREEN;
294         strcpy(buf, _("乗馬中", "Riding"));
295     }
296
297     c_put_str(attr, format("%-9s", buf), row_speed, col_speed);
298 }
299
300 /*!
301  * @brief プレイヤーの呪文学習可能状態を表示する
302  * @param player_ptr プレイヤーへの参照ポインタ
303  */
304 void print_study(PlayerType *player_ptr)
305 {
306     TERM_LEN wid, hgt;
307     term_get_size(&wid, &hgt);
308     TERM_LEN col_study = wid + COL_STUDY;
309     TERM_LEN row_study = hgt + ROW_STUDY;
310
311     if (player_ptr->new_spells) {
312         put_str(_("学習", "Stud"), row_study, col_study);
313     } else {
314         put_str("    ", row_study, col_study);
315     }
316 }
317
318 /*!
319  * @brief プレイヤーのものまね可能状態を表示する
320  * @param player_ptr プレイヤーへの参照ポインタ
321  */
322 void print_imitation(PlayerType *player_ptr)
323 {
324     TERM_LEN wid, hgt;
325     term_get_size(&wid, &hgt);
326     TERM_LEN col_study = wid + COL_STUDY;
327     TERM_LEN row_study = hgt + ROW_STUDY;
328
329     if (player_ptr->pclass != PlayerClassType::IMITATOR)
330         return;
331
332     auto mane_data = PlayerClass(player_ptr).get_specific_data<mane_data_type>();
333
334     if (mane_data->mane_list.size() == 0) {
335         put_str("    ", row_study, col_study);
336         return;
337     }
338
339     TERM_COLOR attr = mane_data->new_mane ? TERM_L_RED : TERM_WHITE;
340     c_put_str(attr, _("まね", "Imit"), row_study, col_study);
341 }
342
343 /*!
344  * @brief 画面下部に表示すべき呪術の呪文をリストアップする
345  * @param player_ptr プレイヤーへの参照ポインタ
346  * @bar_flags 表示可否を決めるためのフラグ群
347  */
348 static void add_hex_status_flags(PlayerType *player_ptr, BIT_FLAGS *bar_flags)
349 {
350     if (player_ptr->realm1 != REALM_HEX) {
351         return;
352     }
353
354     SpellHex spell_hex(player_ptr);
355     if (spell_hex.is_spelling_specific(HEX_BLESS)) {
356         ADD_BAR_FLAG(BAR_BLESSED);
357     }
358
359     if (spell_hex.is_spelling_specific(HEX_DEMON_AURA)) {
360         ADD_BAR_FLAG(BAR_SHFIRE);
361         ADD_BAR_FLAG(BAR_REGENERATION);
362     }
363
364     if (spell_hex.is_spelling_specific(HEX_XTRA_MIGHT)) {
365         ADD_BAR_FLAG(BAR_MIGHT);
366     }
367
368     if (spell_hex.is_spelling_specific(HEX_DETECT_EVIL)) {
369         ADD_BAR_FLAG(BAR_ESP_EVIL);
370     }
371
372     if (spell_hex.is_spelling_specific(HEX_ICE_ARMOR)) {
373         ADD_BAR_FLAG(BAR_SHCOLD);
374     }
375
376     if (spell_hex.is_spelling_specific(HEX_RUNESWORD)) {
377         ADD_BAR_FLAG(BAR_RUNESWORD);
378     }
379
380     if (spell_hex.is_spelling_specific(HEX_BUILDING)) {
381         ADD_BAR_FLAG(BAR_BUILD);
382     }
383
384     if (spell_hex.is_spelling_specific(HEX_ANTI_TELE)) {
385         ADD_BAR_FLAG(BAR_ANTITELE);
386     }
387
388     if (spell_hex.is_spelling_specific(HEX_SHOCK_CLOAK)) {
389         ADD_BAR_FLAG(BAR_SHELEC);
390     }
391
392     if (spell_hex.is_spelling_specific(HEX_SHADOW_CLOAK)) {
393         ADD_BAR_FLAG(BAR_SHSHADOW);
394     }
395
396     if (spell_hex.is_spelling_specific(HEX_CONFUSION)) {
397         ADD_BAR_FLAG(BAR_ATTKCONF);
398     }
399
400     if (spell_hex.is_spelling_specific(HEX_EYE_FOR_EYE)) {
401         ADD_BAR_FLAG(BAR_EYEEYE);
402     }
403
404     if (spell_hex.is_spelling_specific(HEX_ANTI_MULTI)) {
405         ADD_BAR_FLAG(BAR_ANTIMULTI);
406     }
407
408     if (spell_hex.is_spelling_specific(HEX_VAMP_BLADE)) {
409         ADD_BAR_FLAG(BAR_VAMPILIC);
410     }
411
412     if (spell_hex.is_spelling_specific(HEX_ANTI_MAGIC)) {
413         ADD_BAR_FLAG(BAR_ANTIMAGIC);
414     }
415
416     if (spell_hex.is_spelling_specific(HEX_CURE_LIGHT) || spell_hex.is_spelling_specific(HEX_CURE_SERIOUS)
417         || spell_hex.is_spelling_specific(HEX_CURE_CRITICAL)) {
418         ADD_BAR_FLAG(BAR_CURE);
419     }
420
421     if (spell_hex.get_revenge_turn() > 0) {
422         auto revenge_type = spell_hex.get_revenge_type();
423         if (revenge_type == SpellHexRevengeType::PATIENCE) {
424             ADD_BAR_FLAG(BAR_PATIENCE);
425         }
426
427         if (revenge_type == SpellHexRevengeType::REVENGE) {
428             ADD_BAR_FLAG(BAR_REVENGE);
429         }
430     }
431 }
432
433 /*!
434  * @brief 下部に状態表示を行う / Show status bar
435  */
436 void print_status(PlayerType *player_ptr)
437 {
438     TERM_LEN wid, hgt;
439     term_get_size(&wid, &hgt);
440     TERM_LEN row_statbar = hgt + ROW_STATBAR;
441     TERM_LEN max_col_statbar = wid + MAX_COL_STATBAR;
442
443     term_erase(0, row_statbar, max_col_statbar);
444
445     BIT_FLAGS bar_flags[3];
446     bar_flags[0] = bar_flags[1] = bar_flags[2] = 0L;
447
448     if (player_ptr->tsuyoshi)
449         ADD_BAR_FLAG(BAR_TSUYOSHI);
450
451     if (player_ptr->hallucinated)
452         ADD_BAR_FLAG(BAR_HALLUCINATION);
453
454     if (player_ptr->blind)
455         ADD_BAR_FLAG(BAR_BLINDNESS);
456
457     if (player_ptr->paralyzed)
458         ADD_BAR_FLAG(BAR_PARALYZE);
459
460     if (player_ptr->confused)
461         ADD_BAR_FLAG(BAR_CONFUSE);
462
463     if (player_ptr->poisoned)
464         ADD_BAR_FLAG(BAR_POISONED);
465
466     if (player_ptr->tim_invis)
467         ADD_BAR_FLAG(BAR_SENSEUNSEEN);
468
469     auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
470     if (sniper_data && (sniper_data->concent >= CONCENT_RADAR_THRESHOLD)) {
471         ADD_BAR_FLAG(BAR_SENSEUNSEEN);
472         ADD_BAR_FLAG(BAR_NIGHTSIGHT);
473     }
474
475     if (is_time_limit_esp(player_ptr))
476         ADD_BAR_FLAG(BAR_TELEPATHY);
477
478     if (player_ptr->tim_regen)
479         ADD_BAR_FLAG(BAR_REGENERATION);
480
481     if (player_ptr->tim_infra)
482         ADD_BAR_FLAG(BAR_INFRAVISION);
483
484     if (player_ptr->protevil)
485         ADD_BAR_FLAG(BAR_PROTEVIL);
486
487     if (is_invuln(player_ptr))
488         ADD_BAR_FLAG(BAR_INVULN);
489
490     if (player_ptr->wraith_form)
491         ADD_BAR_FLAG(BAR_WRAITH);
492
493     if (player_ptr->tim_pass_wall)
494         ADD_BAR_FLAG(BAR_PASSWALL);
495
496     if (player_ptr->tim_reflect)
497         ADD_BAR_FLAG(BAR_REFLECTION);
498
499     if (is_hero(player_ptr))
500         ADD_BAR_FLAG(BAR_HEROISM);
501
502     if (is_shero(player_ptr))
503         ADD_BAR_FLAG(BAR_BERSERK);
504
505     if (is_blessed(player_ptr))
506         ADD_BAR_FLAG(BAR_BLESSED);
507
508     if (player_ptr->magicdef)
509         ADD_BAR_FLAG(BAR_MAGICDEFENSE);
510
511     if (player_ptr->tsubureru)
512         ADD_BAR_FLAG(BAR_EXPAND);
513
514     if (player_ptr->shield)
515         ADD_BAR_FLAG(BAR_STONESKIN);
516
517     auto ninja_data = PlayerClass(player_ptr).get_specific_data<ninja_data_type>();
518     if (ninja_data && ninja_data->kawarimi)
519         ADD_BAR_FLAG(BAR_KAWARIMI);
520
521     if (player_ptr->special_defense & DEFENSE_ACID)
522         ADD_BAR_FLAG(BAR_IMMACID);
523     if (is_oppose_acid(player_ptr))
524         ADD_BAR_FLAG(BAR_RESACID);
525
526     if (player_ptr->special_defense & DEFENSE_ELEC)
527         ADD_BAR_FLAG(BAR_IMMELEC);
528     if (is_oppose_elec(player_ptr))
529         ADD_BAR_FLAG(BAR_RESELEC);
530
531     if (player_ptr->special_defense & DEFENSE_FIRE)
532         ADD_BAR_FLAG(BAR_IMMFIRE);
533     if (is_oppose_fire(player_ptr))
534         ADD_BAR_FLAG(BAR_RESFIRE);
535
536     if (player_ptr->special_defense & DEFENSE_COLD)
537         ADD_BAR_FLAG(BAR_IMMCOLD);
538     if (is_oppose_cold(player_ptr))
539         ADD_BAR_FLAG(BAR_RESCOLD);
540
541     if (is_oppose_pois(player_ptr))
542         ADD_BAR_FLAG(BAR_RESPOIS);
543
544     if (player_ptr->word_recall)
545         ADD_BAR_FLAG(BAR_RECALL);
546
547     if (player_ptr->alter_reality)
548         ADD_BAR_FLAG(BAR_ALTER);
549
550     if (player_ptr->afraid)
551         ADD_BAR_FLAG(BAR_AFRAID);
552
553     if (player_ptr->tim_res_time)
554         ADD_BAR_FLAG(BAR_RESTIME);
555
556     if (player_ptr->multishadow)
557         ADD_BAR_FLAG(BAR_MULTISHADOW);
558
559     if (player_ptr->special_attack & ATTACK_CONFUSE)
560         ADD_BAR_FLAG(BAR_ATTKCONF);
561
562     if (player_ptr->resist_magic)
563         ADD_BAR_FLAG(BAR_REGMAGIC);
564
565     if (player_ptr->ult_res)
566         ADD_BAR_FLAG(BAR_ULTIMATE);
567
568     if (player_ptr->tim_levitation)
569         ADD_BAR_FLAG(BAR_LEVITATE);
570
571     if (player_ptr->tim_res_nether)
572         ADD_BAR_FLAG(BAR_RESNETH);
573
574     if (player_ptr->dustrobe)
575         ADD_BAR_FLAG(BAR_DUSTROBE);
576
577     if (player_ptr->special_attack & ATTACK_FIRE)
578         ADD_BAR_FLAG(BAR_ATTKFIRE);
579     if (player_ptr->special_attack & ATTACK_COLD)
580         ADD_BAR_FLAG(BAR_ATTKCOLD);
581     if (player_ptr->special_attack & ATTACK_ELEC)
582         ADD_BAR_FLAG(BAR_ATTKELEC);
583     if (player_ptr->special_attack & ATTACK_ACID)
584         ADD_BAR_FLAG(BAR_ATTKACID);
585     if (player_ptr->special_attack & ATTACK_POIS)
586         ADD_BAR_FLAG(BAR_ATTKPOIS);
587     if (ninja_data && ninja_data->s_stealth)
588         ADD_BAR_FLAG(BAR_SUPERSTEALTH);
589
590     if (player_ptr->tim_sh_fire)
591         ADD_BAR_FLAG(BAR_SHFIRE);
592
593     if (is_time_limit_stealth(player_ptr))
594         ADD_BAR_FLAG(BAR_STEALTH);
595
596     if (player_ptr->tim_sh_touki)
597         ADD_BAR_FLAG(BAR_TOUKI);
598
599     if (player_ptr->tim_sh_holy)
600         ADD_BAR_FLAG(BAR_SHHOLY);
601
602     if (player_ptr->tim_eyeeye)
603         ADD_BAR_FLAG(BAR_EYEEYE);
604
605     add_hex_status_flags(player_ptr, bar_flags);
606     TERM_LEN col = 0, num = 0;
607     for (int i = 0; stat_bars[i].sstr; i++) {
608         if (IS_BAR_FLAG(i)) {
609             col += strlen(stat_bars[i].lstr) + 1;
610             num++;
611         }
612     }
613
614     int space = 2;
615     if (col - 1 > max_col_statbar) {
616         space = 0;
617         col = 0;
618
619         for (int i = 0; stat_bars[i].sstr; i++) {
620             if (IS_BAR_FLAG(i)) {
621                 col += strlen(stat_bars[i].sstr);
622             }
623         }
624
625         if (col - 1 <= max_col_statbar - (num - 1)) {
626             space = 1;
627             col += num - 1;
628         }
629     }
630
631     col = (max_col_statbar - col) / 2;
632     for (int i = 0; stat_bars[i].sstr; i++) {
633         if (!IS_BAR_FLAG(i))
634             continue;
635
636         concptr str;
637         if (space == 2)
638             str = stat_bars[i].lstr;
639         else
640             str = stat_bars[i].sstr;
641
642         c_put_str(stat_bars[i].attr, str, row_statbar, col);
643         col += strlen(str);
644         if (space > 0)
645             col++;
646         if (col > max_col_statbar)
647             break;
648     }
649 }
650
651 /*!
652  * @brief プレイヤーのステータスを一括表示する(下部分) / Display extra info (mostly below map)
653  * @param player_ptr プレイヤーへの参照ポインタ
654  */
655 void print_frame_extra(PlayerType *player_ptr)
656 {
657     print_cut(player_ptr);
658     print_stun(player_ptr);
659     print_hunger(player_ptr);
660     print_state(player_ptr);
661     print_speed(player_ptr);
662     print_study(player_ptr);
663     print_imitation(player_ptr);
664     print_status(player_ptr);
665 }