OSDN Git Service

[Fix] 消去時に画面右端までの消去されないことがある
[hengbandforosx/hengbandosx.git] / src / view / display-scores.cpp
1 #include "view/display-scores.h"
2 #include "core/score-util.h"
3 #include "io/files-util.h"
4 #include "io/input-key-acceptor.h"
5 #include "locale/japanese.h"
6 #include "player-info/class-info.h"
7 #include "player/player-personality.h"
8 #include "player/race-info-table.h"
9 #include "system/angband.h"
10 #include "term/gameterm.h"
11 #include "term/screen-processor.h"
12 #include "term/term-color-types.h"
13 #include "term/z-form.h"
14 #include "util/angband-files.h"
15 #include "util/int-char-converter.h"
16
17 /*!
18  * @brief 指定された順位範囲でスコアを並べて表示する / Display the scores in a given range.
19  * @param from 順位先頭
20  * @param to 順位末尾
21  * @param note 黄色表示でハイライトする順位
22  * @param score スコア配列参照ポインタ
23  * @details
24  * <pre>
25  * Assumes the high score list is already open.
26  * Only five entries per line, too much info.
27  *
28  * Mega-Hack -- allow "fake" entry at the given position.
29  * </pre>
30  */
31 void display_scores(int from, int to, int note, high_score *score)
32 {
33     if (highscore_fd < 0) {
34         return;
35     }
36
37     if (from < 0) {
38         from = 0;
39     }
40
41     if (to < 0) {
42         to = 10;
43     }
44
45     if (to > MAX_HISCORES) {
46         to = MAX_HISCORES;
47     }
48
49     if (highscore_seek(0)) {
50         return;
51     }
52
53     auto num_scores = 0;
54     high_score the_score;
55     for (; num_scores < MAX_HISCORES; num_scores++) {
56         if (highscore_read(&the_score)) {
57             break;
58         }
59     }
60
61     if ((note == num_scores) && score) {
62         num_scores++;
63     }
64
65     if (num_scores > to) {
66         num_scores = to;
67     }
68
69     constexpr auto per_screen = (MAIN_TERM_MIN_ROWS - 4) / 4;
70     for (auto k = from, place = k + 1; k < num_scores; k += per_screen) {
71         TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
72
73         term_clear();
74         put_str(_("                変愚蛮怒: 勇者の殿堂", "                Hengband Hall of Fame"), 0, 0);
75         if (k > 0) {
76             put_str(format(_("( %d 位以下 )", "(from position %d)"), k + 1), 0, 40);
77         }
78
79         for (auto n = 0, j = k; (j < num_scores) && (n < per_screen); place++, j++, n++) {
80             auto attr = (j == note) ? TERM_YELLOW : TERM_WHITE;
81             if ((note == j) && score) {
82                 the_score = (*score);
83                 attr = TERM_L_GREEN;
84                 score = nullptr;
85                 note = -1;
86                 j--;
87             } else if (highscore_seek(j) || highscore_read(&the_score)) {
88                 break;
89             }
90
91             auto pr = atoi(the_score.p_r);
92             auto pc = atoi(the_score.p_c);
93             auto pa = atoi(the_score.p_a);
94
95             auto clev = atoi(the_score.cur_lev);
96             auto mlev = atoi(the_score.max_lev);
97             auto cdun = atoi(the_score.cur_dun);
98             auto mdun = atoi(the_score.max_dun);
99
100             concptr user;
101             for (user = the_score.uid; iswspace(*user); user++) { /* loop */
102                 ;
103             }
104
105             concptr when;
106             for (when = the_score.day; iswspace(*when); when++) { /* loop */
107                 ;
108             }
109
110             concptr gold;
111             for (gold = the_score.gold; iswspace(*gold); gold++) { /* loop */
112                 ;
113             }
114
115             concptr aged;
116             for (aged = the_score.turns; iswspace(*aged); aged++) { /* loop */
117                 ;
118             }
119
120             std::string alt_when;
121             if ((*when == '@') && strlen(when) == 9) {
122                 alt_when = format("%.4s-%.2s-%.2s", when + 1, when + 5, when + 7);
123                 when = alt_when.data();
124             }
125
126             std::string out_val;
127 #ifdef JP
128             /* out_val = format("%3d.%9s  %s%s%sという名の%sの%s (レベル %d)", */
129             out_val = format("%3d.%9s  %s%s%s - %s%s (レベル %d)", place, the_score.pts, personality_info[pa].title, (personality_info[pa].no ? "の" : ""),
130                 the_score.who, race_info[pr].title, class_info[pc].title, clev);
131
132 #else
133             out_val = format("%3d.%9s  %s %s the %s %s, Level %d", place, the_score.pts, personality_info[pa].title, the_score.who, race_info[pr].title,
134                 class_info[pc].title, clev);
135 #endif
136             if (mlev > clev) {
137                 out_val.append(format(_(" (最高%d)", " (Max %d)"), mlev));
138             }
139
140             c_put_str(attr, out_val, n * 4 + 2, 0);
141 #ifdef JP
142             if (mdun != 0) {
143                 out_val = format("    最高%3d階", mdun);
144             } else {
145                 out_val = "             ";
146             }
147
148             /* 死亡原因をオリジナルより細かく表示 */
149             if (streq(the_score.how, "yet")) {
150                 out_val.append(format("  まだ生きている (%d%s)", cdun, "階"));
151             } else if (streq(the_score.how, "ripe")) {
152                 out_val.append(format("  勝利の後に引退 (%d%s)", cdun, "階"));
153             } else if (streq(the_score.how, "Seppuku")) {
154                 out_val.append(format("  勝利の後に切腹 (%d%s)", cdun, "階"));
155             } else {
156                 codeconv(the_score.how);
157                 if (!cdun) {
158                     out_val.append(format("  地上で%sに殺された", the_score.how));
159                 } else {
160                     out_val.append(format("  %d階で%sに殺された", cdun, the_score.how));
161                 }
162             }
163 #else
164             if (!cdun) {
165                 out_val = format("               Killed by %s on the surface", the_score.how);
166             } else {
167                 out_val = format("               Killed by %s on %s %d", the_score.how, "Dungeon Level", cdun);
168             }
169
170             if (mdun > cdun) {
171                 out_val.append(format(" (Max %d)", mdun));
172             }
173 #endif
174             c_put_str(attr, out_val, n * 4 + 3, 0);
175 #ifdef JP
176             /* 日付を 19yy/mm/dd の形式に変更する */
177             if (strlen(when) == 8 && when[2] == '/' && when[5] == '/') {
178                 alt_when = format("%d%s/%.5s", 19 + (when[6] < '8'), when + 6, when);
179                 when = alt_when.data();
180             }
181
182             out_val = format("        (ユーザー:%s, 日付:%s, 所持金:%s, ターン:%s)", user, when, gold, aged);
183 #else
184             out_val = format("               (User %s, Date %s, Gold %s, Turn %s).", user, when, gold, aged);
185 #endif
186
187             c_put_str(attr, out_val, n * 4 + 4, 0);
188         }
189
190         prt(_("[ ESCで中断, その他のキーで続けます ]", "[Press ESC to quit, any other key to continue.]"), MAIN_TERM_MIN_ROWS - 1, _(21, 17));
191         auto key = inkey();
192         prt("", MAIN_TERM_MIN_ROWS - 1, 0);
193         if (key == ESCAPE) {
194             break;
195         }
196     }
197 }
198
199 #ifndef WINDOWS
200 /*!
201  * @brief スコア表示処理メインルーチン / Display the scores in a given range and quit.
202  * @param from 順位先頭
203  * @param to 順位末尾
204  * @details
205  * スコア表示した後、或いは表示に失敗したら終了する (Windows版は表示処理の中で終了することはない)
206  * main.cpp からしか呼ばれていない。暫定でプリプロで包んでおく
207  * 取り敢えずWindows版はオーバーロード解決できている。他は不明
208  */
209 void display_scores(int from, int to)
210 {
211     const auto &path = path_build(ANGBAND_DIR_APEX, "scores.raw");
212     const auto &filename = path.string();
213     highscore_fd = fd_open(filename, O_RDONLY);
214     if (highscore_fd < 0) {
215         quit(_("スコア・ファイルが使用できません。", "Score file unavailable."));
216     }
217
218     term_clear();
219     display_scores(from, to, -1, nullptr);
220     (void)fd_close(highscore_fd);
221     highscore_fd = -1;
222     quit(nullptr);
223 }
224 #endif