OSDN Git Service

[Refactor] #37353 player-race.c/h を作成して関連構造体と変数を移動.
[hengband/hengband.git] / src / scores.c
1 /*!
2  * @file scores.c
3  * @brief ハイスコア処理 / Highscores handling
4  * @date 2014/07/14
5  * @author
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.  Other copyrights may also apply.
10  * 2014 Deskull rearranged comment for Doxygen.
11  */
12
13 #include "angband.h"
14 #include "util.h"
15
16 #include "player-race.h"
17 #include "player-status.h"
18 #include "player-class.h"
19 #include "files.h"
20 #include "scores.h"
21 #include "floor.h"
22 #include "world.h"
23
24 /*!
25  * @brief i番目のスコア情報にバッファ位置をシークする / Seek score 'i' in the highscore file
26  * @param i スコア情報ID
27  * @return 問題がなければ0を返す
28  */
29 static int highscore_seek(int i)
30 {
31         /* Seek for the requested record */
32         return (fd_seek(highscore_fd, (huge)(i) * sizeof(high_score)));
33 }
34
35
36 /*!
37  * @brief 所定ポインタからスコア情報を読み取る / Read one score from the highscore file
38  * @param score スコア情報参照ポインタ
39  * @return エラーコード
40  */
41 static errr highscore_read(high_score *score)
42 {
43         /* Read the record, note failure */
44         return (fd_read(highscore_fd, (char*)(score), sizeof(high_score)));
45 }
46
47
48 /*!
49  * @brief 所定ポインタへスコア情報を書き込む / Write one score to the highscore file
50  * @param score スコア情報参照ポインタ
51  * @return エラーコード(問題がなければ0を返す)
52  */
53 static int highscore_write(high_score *score)
54 {
55         /* Write the record, note failure */
56         return (fd_write(highscore_fd, (char*)(score), sizeof(high_score)));
57 }
58
59 /*!
60  * @brief スコア情報を全て得るまで繰り返し取得する / Just determine where a new score *would* be placed
61  * @param score スコア情報参照ポインタ
62  * @return 正常ならば(MAX_HISCORES - 1)、問題があれば-1を返す
63  */
64 static int highscore_where(high_score *score)
65 {
66         int                     i;
67
68         high_score              the_score;
69         int my_score;
70
71         my_score = atoi(score->pts);
72
73         /* Paranoia -- it may not have opened */
74         if (highscore_fd < 0) return (-1);
75
76         /* Go to the start of the highscore file */
77         if (highscore_seek(0)) return (-1);
78
79         /* Read until we get to a higher score */
80         for (i = 0; i < MAX_HISCORES; i++)
81         {
82                 int old_score;
83                 if (highscore_read(&the_score)) return (i);
84                 old_score = atoi(the_score.pts);
85 /*              if (strcmp(the_score.pts, score->pts) < 0) return (i); */
86                 if (my_score > old_score) return (i);
87         }
88
89         /* The "last" entry is always usable */
90         return (MAX_HISCORES - 1);
91 }
92
93
94 /*!
95  * @brief スコア情報をバッファの末尾に追加する / Actually place an entry into the high score file
96  * @param score スコア情報参照ポインタ
97  * @return 正常ならば書き込んだスロット位置、問題があれば-1を返す / Return the location (0 is best) or -1 on "failure"
98  */
99 static int highscore_add(high_score *score)
100 {
101         int                     i, slot;
102         bool            done = FALSE;
103
104         high_score              the_score, tmpscore;
105
106
107         /* Paranoia -- it may not have opened */
108         if (highscore_fd < 0) return (-1);
109
110         /* Determine where the score should go */
111         slot = highscore_where(score);
112
113         /* Hack -- Not on the list */
114         if (slot < 0) return (-1);
115
116         /* Hack -- prepare to dump the new score */
117         the_score = (*score);
118
119         /* Slide all the scores down one */
120         for (i = slot; !done && (i < MAX_HISCORES); i++)
121         {
122                 /* Read the old guy, note errors */
123                 if (highscore_seek(i)) return (-1);
124                 if (highscore_read(&tmpscore)) done = TRUE;
125
126                 /* Back up and dump the score we were holding */
127                 if (highscore_seek(i)) return (-1);
128                 if (highscore_write(&the_score)) return (-1);
129
130                 /* Hack -- Save the old score, for the next pass */
131                 the_score = tmpscore;
132         }
133
134         /* Return location used */
135         return (slot);
136 }
137
138
139
140 /*!
141  * @brief 指定された順位範囲でスコアを並べて表示する / Display the scores in a given range.
142  * @param from 順位先頭
143  * @param to 順位末尾
144  * @param note 黄色表示でハイライトする順位
145  * @param score スコア配列参照ポインタ
146  * @return なし
147  * @details
148  * <pre>
149  * Assumes the high score list is already open.
150  * Only five entries per line, too much info.
151  *
152  * Mega-Hack -- allow "fake" entry at the given position.
153  * </pre>
154  */
155 void display_scores_aux(int from, int to, int note, high_score *score)
156 {
157         int i, j, k, n, place;
158         TERM_COLOR attr;
159
160         high_score the_score;
161
162         GAME_TEXT out_val[256];
163         GAME_TEXT tmp_val[160];
164
165         TERM_LEN wid, hgt, per_screen;
166
167         Term_get_size(&wid, &hgt);
168         per_screen = (hgt - 4) / 4;
169
170         /* Paranoia -- it may not have opened */
171         if (highscore_fd < 0) return;
172
173
174         /* Assume we will show the first 10 */
175         if (from < 0) from = 0;
176         if (to < 0) to = 10;
177         if (to > MAX_HISCORES) to = MAX_HISCORES;
178
179
180         /* Seek to the beginning */
181         if (highscore_seek(0)) return;
182
183         /* Hack -- Count the high scores */
184         for (i = 0; i < MAX_HISCORES; i++)
185         {
186                 if (highscore_read(&the_score)) break;
187         }
188
189         /* Hack -- allow "fake" entry to be last */
190         if ((note == i) && score) i++;
191
192         /* Forget about the last entries */
193         if (i > to) i = to;
194
195
196         /* Show per_screen per page, until "done" */
197         for (k = from, place = k+1; k < i; k += per_screen)
198         {
199                 Term_clear();
200
201                 /* Title */
202                 put_str(_("                変愚蛮怒: 勇者の殿堂", "                Hengband Hall of Fame"), 0, 0);
203
204                 /* Indicate non-top scores */
205                 if (k > 0)
206                 {
207                         sprintf(tmp_val, _("( %d 位以下 )", "(from position %d)"), k + 1);
208                         put_str(tmp_val, 0, 40);
209                 }
210
211                 /* Dump per_screen entries */
212                 for (j = k, n = 0; j < i && n < per_screen; place++, j++, n++)
213                 {
214                         int pr, pc, pa, clev, mlev, cdun, mdun;
215
216                         concptr user, gold, when, aged;
217
218
219                         /* Hack -- indicate death in yellow */
220                         attr = (j == note) ? TERM_YELLOW : TERM_WHITE;
221
222
223                         /* Mega-Hack -- insert a "fake" record */
224                         if ((note == j) && score)
225                         {
226                                 the_score = (*score);
227                                 attr = TERM_L_GREEN;
228                                 score = NULL;
229                                 note = -1;
230                                 j--;
231                         }
232
233                         /* Read a normal record */
234                         else
235                         {
236                                 /* Read the proper record */
237                                 if (highscore_seek(j)) break;
238                                 if (highscore_read(&the_score)) break;
239                         }
240
241                         /* Extract the race/class */
242                         pr = atoi(the_score.p_r);
243                         pc = atoi(the_score.p_c);
244                         pa = atoi(the_score.p_a);
245
246                         /* Extract the level info */
247                         clev = atoi(the_score.cur_lev);
248                         mlev = atoi(the_score.max_lev);
249                         cdun = atoi(the_score.cur_dun);
250                         mdun = atoi(the_score.max_dun);
251
252                         /* Hack -- extract the gold and such */
253                         for (user = the_score.uid; iswspace(*user); user++) /* loop */;
254                         for (when = the_score.day; iswspace(*when); when++) /* loop */;
255                         for (gold = the_score.gold; iswspace(*gold); gold++) /* loop */;
256                         for (aged = the_score.turns; iswspace(*aged); aged++) /* loop */;
257
258                         /* Clean up standard encoded form of "when" */
259                         if ((*when == '@') && strlen(when) == 9)
260                         {
261                                 sprintf(tmp_val, "%.4s-%.2s-%.2s",
262                                         when + 1, when + 5, when + 7);
263                                 when = tmp_val;
264                         }
265
266                         /* Dump some info */
267 #ifdef JP
268 /*sprintf(out_val, "%3d.%9s  %s%s%sという名の%sの%s (レベル %d)", */
269                         sprintf(out_val, "%3d.%9s  %s%s%s - %s%s (レベル %d)",
270                                 place, the_score.pts,
271                                 seikaku_info[pa].title, (seikaku_info[pa].no ? "の" : ""),
272                                 the_score.who,
273                                 race_info[pr].title, class_info[pc].title,
274                                 clev);
275
276 #else
277                         sprintf(out_val, "%3d.%9s  %s %s the %s %s, Level %d",
278                                 place, the_score.pts,
279                                 seikaku_info[pa].title,
280                                 the_score.who, race_info[pr].title, class_info[pc].title,
281                                 clev);
282 #endif
283
284
285                         /* Append a "maximum level" */
286                         if (mlev > clev) strcat(out_val, format(_(" (最高%d)", " (Max %d)"), mlev));
287
288                         /* Dump the first line */
289                         c_put_str(attr, out_val, n*4 + 2, 0);
290
291                         /* Another line of info */
292 #ifdef JP
293                         if (mdun != 0)
294                                 sprintf(out_val, "    最高%3d階", mdun);
295                         else
296                                 sprintf(out_val, "             ");
297
298
299                         /* 死亡原因をオリジナルより細かく表示 */
300                         if (streq(the_score.how, "yet"))
301                         {
302                                 sprintf(out_val+13, "  まだ生きている (%d%s)",
303                                        cdun, "階");
304                         }
305                         else
306                         if (streq(the_score.how, "ripe"))
307                         {
308                                 sprintf(out_val+13, "  勝利の後に引退 (%d%s)",
309                                         cdun, "階");
310                         }
311                         else if (streq(the_score.how, "Seppuku"))
312                         {
313                                 sprintf(out_val+13, "  勝利の後に切腹 (%d%s)",
314                                         cdun, "階");
315                         }
316                         else
317                         {
318                                 codeconv(the_score.how);
319
320                                 /* Some people die outside of the dungeon */
321                                 if (!cdun)
322                                         sprintf(out_val+13, "  地上で%sに殺された", the_score.how);
323                                 else
324                                         sprintf(out_val+13, "  %d階で%sに殺された",
325                                                 cdun, the_score.how);
326                         }
327
328 #else
329                         /* Some people die outside of the dungeon */
330                         if (!cdun)
331                                 sprintf(out_val, 
332                                         "               Killed by %s on the surface",
333                                         the_score.how);
334                         else
335                                 sprintf(out_val, 
336                                         "               Killed by %s on %s %d",
337                                         the_score.how, "Dungeon Level", cdun);
338
339                         /* Append a "maximum level" */
340                         if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun));
341 #endif
342
343                         /* Dump the info */
344                         c_put_str(attr, out_val, n*4 + 3, 0);
345
346                         /* And still another line of info */
347 #ifdef JP
348                         {
349                                 char buf[11];
350
351                                 /* 日付を 19yy/mm/dd の形式に変更する */
352                                 if (strlen(when) == 8 && when[2] == '/' && when[5] == '/') {
353                                         sprintf(buf, "%d%s/%.5s", 19 + (when[6] < '8'), when + 6, when);
354                                         when = buf;
355                                 }
356                                 sprintf(out_val,
357                                                 "        (ユーザー:%s, 日付:%s, 所持金:%s, ターン:%s)",
358                                                 user, when, gold, aged);
359                         }
360
361 #else
362                         sprintf(out_val,
363                                 "               (User %s, Date %s, Gold %s, Turn %s).",
364                                 user, when, gold, aged);
365 #endif
366
367                         c_put_str(attr, out_val, n*4 + 4, 0);
368                 }
369
370
371                 /* Wait for response */
372                 prt(_("[ ESCで中断, その他のキーで続けます ]", "[Press ESC to quit, any other key to continue.]"), hgt - 1, _(21, 17));
373
374                 j = inkey();
375                 prt("", hgt - 1, 0);
376
377                 /* Hack -- notice Escape */
378                 if (j == ESCAPE) break;
379         }
380 }
381
382
383 /*!
384  * @brief スコア表示処理メインルーチン / Hack -- Display the scores in a given range and quit.
385  * @param from 順位先頭
386  * @param to 順位末尾
387  * @return なし
388  * @details
389  * <pre>
390  * This function is only called from "main.c" when the user asks
391  * to see the "high scores".
392  * </pre>
393  */
394 void display_scores(int from, int to)
395 {
396         char buf[1024];
397
398         /* Build the filename */
399         path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
400
401         /* Open the binary high score file, for reading */
402         highscore_fd = fd_open(buf, O_RDONLY);
403
404         /* Paranoia -- No score file */
405         if (highscore_fd < 0) quit(_("スコア・ファイルが使用できません。", "Score file unavailable."));
406         Term_clear();
407
408         /* Display the scores */
409         display_scores_aux(from, to, -1, NULL);
410
411         /* Shut the high score file */
412         (void)fd_close(highscore_fd);
413
414         /* Forget the high score fd */
415         highscore_fd = -1;
416
417         /* Quit */
418         quit(NULL);
419 }
420
421
422 /*!
423  * @brief スコアサーバへの転送処理
424  * @param do_send 実際に転送ア処置を行うか否か
425  * @return 転送が成功したらTRUEを返す
426  */
427 bool send_world_score(bool do_send)
428 {
429 #ifdef WORLD_SCORE
430         if(send_score && do_send)
431         {
432                 if(easy_band)
433                 {
434                         msg_print(_("初心者モードではワールドスコアに登録できません。",
435                         "Since you are in the Easy Mode, you cannot send score to world score server."));
436                 }
437                 else if(get_check_strict(_("スコアをスコア・サーバに登録しますか? ", "Do you send score to the world score sever? "), 
438                                 (CHECK_NO_ESCAPE | CHECK_NO_HISTORY)))
439                 {
440                         errr err;
441                         prt("",0,0);
442                         prt(_("送信中..", "Sending..."),0,0);
443                         Term_fresh();
444                         screen_save();
445                         err = report_score();
446                         screen_load();
447                         if (err)
448                         {
449                                 return FALSE;
450                         }
451                         prt(_("完了。何かキーを押してください。", "Completed.  Hit any key."), 0, 0);
452                         (void)inkey();
453                 }
454                 else return FALSE;
455         }
456 #endif
457         return TRUE;
458 }
459
460 /*!
461  * @brief スコアの過去二十位内ランキングを表示する
462  * Enters a players name on a hi-score table, if "legal", and in any
463  * case, displays some relevant portion of the high score list.
464  * @return エラーコード
465  * @details
466  * Assumes "signals_ignore_tstp()" has been called.
467  */
468 errr top_twenty(void)
469 {
470         int          j;
471
472         high_score   the_score;
473
474         time_t ct = time((time_t*)0);
475
476         errr err;
477
478         /* Clear the record */
479         (void)WIPE(&the_score, high_score);
480
481         /* Save the version */
482         sprintf(the_score.what, "%u.%u.%u",
483                 FAKE_VER_MAJOR, FAKE_VER_MINOR, FAKE_VER_PATCH);
484
485         /* Calculate and save the points */
486         sprintf(the_score.pts, "%9ld", (long)calc_score());
487         the_score.pts[9] = '\0';
488
489         /* Save the current gold */
490         sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
491         the_score.gold[9] = '\0';
492
493         /* Save the current current_world_ptr->game_turn */
494         sprintf(the_score.turns, "%9lu", (long)turn_real(current_world_ptr->game_turn));
495         the_score.turns[9] = '\0';
496
497 #ifdef HIGHSCORE_DATE_HACK
498         /* Save the date in a hacked up form (9 chars) */
499         (void)sprintf(the_score.day, "%-.6s %-.2s", ctime(&ct) + 4, ctime(&ct) + 22);
500 #else
501         /* Save the date in standard form (8 chars) */
502 /*      (void)strftime(the_score.day, 9, "%m/%d/%y", localtime(&ct)); */
503         /* Save the date in standard encoded form (9 chars) */
504         strftime(the_score.day, 10, "@%Y%m%d", localtime(&ct));
505 #endif
506
507         /* Save the player name (15 chars) */
508         sprintf(the_score.who, "%-.15s", p_ptr->name);
509
510         /* Save the player info */
511         sprintf(the_score.uid, "%7u", player_uid);
512         sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
513         sprintf(the_score.p_r, "%2d", MIN(p_ptr->prace, MAX_RACES));
514         sprintf(the_score.p_c, "%2d", MIN(p_ptr->pclass, MAX_CLASS));
515         sprintf(the_score.p_a, "%2d", MIN(p_ptr->pseikaku, MAX_SEIKAKU));
516
517         /* Save the level and such */
518         sprintf(the_score.cur_lev, "%3d", MIN((u16b)p_ptr->lev, 999));
519         sprintf(the_score.cur_dun, "%3d", (int)current_floor_ptr->dun_level);
520         sprintf(the_score.max_lev, "%3d", MIN((u16b)p_ptr->max_plv, 999));
521         sprintf(the_score.max_dun, "%3d", (int)max_dlv[p_ptr->dungeon_idx]);
522
523         /* Save the cause of death (31 chars) */
524         if (strlen(p_ptr->died_from) >= sizeof(the_score.how))
525         {
526 #ifdef JP
527                 my_strcpy(the_score.how, p_ptr->died_from, sizeof(the_score.how) - 2);
528                 strcat(the_score.how, "…");
529 #else
530                 my_strcpy(the_score.how, p_ptr->died_from, sizeof(the_score.how) - 3);
531                 strcat(the_score.how, "...");
532 #endif
533         }
534         else
535         {
536                 strcpy(the_score.how, p_ptr->died_from);
537         }
538
539         /* Grab permissions */
540         safe_setuid_grab();
541
542         /* Lock (for writing) the highscore file, or fail */
543         err = fd_lock(highscore_fd, F_WRLCK);
544
545         /* Drop permissions */
546         safe_setuid_drop();
547
548         if (err) return (1);
549
550         /* Add a new entry to the score list, see where it went */
551         j = highscore_add(&the_score);
552
553         /* Grab permissions */
554         safe_setuid_grab();
555
556         /* Unlock the highscore file, or fail */
557         err = fd_lock(highscore_fd, F_UNLCK);
558
559         /* Drop permissions */
560         safe_setuid_drop();
561
562         if (err) return (1);
563
564
565         /* Hack -- Display the top fifteen scores */
566         if (j < 10)
567         {
568                 display_scores_aux(0, 15, j, NULL);
569         }
570
571         /* Display the scores surrounding the player */
572         else
573         {
574                 display_scores_aux(0, 5, j, NULL);
575                 display_scores_aux(j - 2, j + 7, j, NULL);
576         }
577
578
579         /* Success */
580         return (0);
581 }
582
583 /*!
584  * @brief プレイヤーの現在のスコアをランキングに挟む /
585  * Predict the players location, and display it.
586  * @return エラーコード
587  */
588 errr predict_score(void)
589 {
590         int          j;
591
592         high_score   the_score;
593
594
595         /* No score file */
596         if (highscore_fd < 0)
597         {
598                 msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
599                 msg_print(NULL);
600                 return (0);
601         }
602
603
604         /* Save the version */
605         sprintf(the_score.what, "%u.%u.%u",
606                 FAKE_VER_MAJOR, FAKE_VER_MINOR, FAKE_VER_PATCH);
607
608         /* Calculate and save the points */
609         sprintf(the_score.pts, "%9ld", (long)calc_score());
610
611         /* Save the current gold */
612         sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
613
614         /* Save the current current_world_ptr->game_turn */
615         sprintf(the_score.turns, "%9lu", (long)turn_real(current_world_ptr->game_turn));
616
617         /* Hack -- no time needed */
618         strcpy(the_score.day, _("今日", "TODAY"));
619
620         /* Save the player name (15 chars) */
621         sprintf(the_score.who, "%-.15s", p_ptr->name);
622
623         /* Save the player info */
624         sprintf(the_score.uid, "%7u", player_uid);
625         sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
626         sprintf(the_score.p_r, "%2d", MIN(p_ptr->prace, MAX_RACES));
627         sprintf(the_score.p_c, "%2d", MIN(p_ptr->pclass, MAX_CLASS));
628         sprintf(the_score.p_a, "%2d", MIN(p_ptr->pseikaku, MAX_SEIKAKU));
629
630         /* Save the level and such */
631         sprintf(the_score.cur_lev, "%3d", MIN((u16b)p_ptr->lev, 999));
632         sprintf(the_score.cur_dun, "%3d", (int)current_floor_ptr->dun_level);
633         sprintf(the_score.max_lev, "%3d", MIN((u16b)p_ptr->max_plv, 999));
634         sprintf(the_score.max_dun, "%3d", (int)max_dlv[p_ptr->dungeon_idx]);
635
636         /* Hack -- no cause of death */
637         /* まだ死んでいないときの識別文字 */
638         strcpy(the_score.how, _("yet", "nobody (yet!)"));
639
640         /* See where the entry would be placed */
641         j = highscore_where(&the_score);
642
643
644         /* Hack -- Display the top fifteen scores */
645         if (j < 10)
646         {
647                 display_scores_aux(0, 15, j, &the_score);
648         }
649
650         /* Display some "useful" scores */
651         else
652         {
653                 display_scores_aux(0, 5, -1, NULL);
654                 display_scores_aux(j - 2, j + 7, j, &the_score);
655         }
656
657
658         /* Success */
659         return (0);
660 }
661
662
663 /*!
664  * @brief スコアランキングの簡易表示 /
665  * show_highclass - selectively list highscores based on class -KMW-
666  * @return なし
667  */
668 void show_highclass(void)
669 {
670
671         register int i = 0, j, m = 0;
672         int pr;
673         PLAYER_LEVEL clev/*, al*/;
674         high_score the_score;
675         char buf[1024], out_val[256];
676
677         screen_save();
678
679         /* Build the filename */
680         path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
681
682         highscore_fd = fd_open(buf, O_RDONLY);
683
684         if (highscore_fd < 0)
685         {
686                 msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
687                 msg_print(NULL);
688                 return;
689         }
690
691         if (highscore_seek(0)) return;
692
693         for (i = 0; i < MAX_HISCORES; i++)
694                 if (highscore_read(&the_score)) break;
695
696         m = 0;
697         j = 0;
698         clev = 0;
699
700         while ((m < 9) && (j < MAX_HISCORES))
701         {
702                 if (highscore_seek(j)) break;
703                 if (highscore_read(&the_score)) break;
704                 pr = atoi(the_score.p_r);
705                 clev = (PLAYER_LEVEL)atoi(the_score.cur_lev);
706
707 #ifdef JP
708                 sprintf(out_val, "   %3d) %sの%s (レベル %2d)",
709                     (m + 1), race_info[pr].title,the_score.who, clev);
710 #else
711                 sprintf(out_val, "%3d) %s the %s (Level %2d)",
712                     (m + 1), the_score.who, race_info[pr].title, clev);
713 #endif
714
715                 prt(out_val, (m + 7), 0);
716                 m++;
717                 j++;
718         }
719
720 #ifdef JP
721         sprintf(out_val, "あなた) %sの%s (レベル %2d)",
722             race_info[p_ptr->prace].title,p_ptr->name, p_ptr->lev);
723 #else
724         sprintf(out_val, "You) %s the %s (Level %2d)",
725             p_ptr->name, race_info[p_ptr->prace].title, p_ptr->lev);
726 #endif
727
728         prt(out_val, (m + 8), 0);
729
730         (void)fd_close(highscore_fd);
731         highscore_fd = -1;
732         prt(_("何かキーを押すとゲームに戻ります", "Hit any key to continue"),0,0);
733
734         (void)inkey();
735
736         for (j = 5; j < 18; j++) prt("", j, 0);
737         screen_load();
738 }
739
740 /*!
741  * @brief スコアランキングの簡易表示(種族毎)サブルーチン /
742  * Race Legends -KMW-
743  * @param race_num 種族ID
744  * @return なし
745  */
746 void race_score(int race_num)
747 {
748         register int i = 0, j, m = 0;
749         int pr, clev, lastlev;
750         high_score the_score;
751         char buf[1024], out_val[256], tmp_str[80];
752
753         lastlev = 0;
754
755         /* rr9: TODO - pluralize the race */
756         sprintf(tmp_str,_("最高の%s", "The Greatest of all the %s"), race_info[race_num].title);
757
758         prt(tmp_str, 5, 15);
759
760         /* Build the filename */
761         path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
762
763         highscore_fd = fd_open(buf, O_RDONLY);
764
765         if (highscore_fd < 0)
766         {
767                 msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable."));
768                 msg_print(NULL);
769                 return;
770         }
771
772         if (highscore_seek(0)) return;
773
774         for (i = 0; i < MAX_HISCORES; i++)
775         {
776                 if (highscore_read(&the_score)) break;
777         }
778
779         m = 0;
780         j = 0;
781
782         while ((m < 10) || (j < MAX_HISCORES))
783         {
784                 if (highscore_seek(j)) break;
785                 if (highscore_read(&the_score)) break;
786                 pr = atoi(the_score.p_r);
787                 clev = atoi(the_score.cur_lev);
788
789                 if (pr == race_num)
790                 {
791 #ifdef JP
792                 sprintf(out_val, "   %3d) %sの%s (レベル %2d)",
793                             (m + 1), race_info[pr].title, 
794                                 the_score.who,clev);
795 #else
796                         sprintf(out_val, "%3d) %s the %s (Level %3d)",
797                             (m + 1), the_score.who,
798                         race_info[pr].title, clev);
799 #endif
800
801                         prt(out_val, (m + 7), 0);
802                         m++;
803                         lastlev = clev;
804                 }
805                 j++;
806         }
807
808         /* add player if qualified */
809         if ((p_ptr->prace == race_num) && (p_ptr->lev >= lastlev))
810         {
811 #ifdef JP
812         sprintf(out_val, "あなた) %sの%s (レベル %2d)",
813                      race_info[p_ptr->prace].title,p_ptr->name, p_ptr->lev);
814 #else
815                 sprintf(out_val, "You) %s the %s (Level %3d)",
816                     p_ptr->name, race_info[p_ptr->prace].title, p_ptr->lev);
817 #endif
818
819                 prt(out_val, (m + 8), 0);
820         }
821
822         (void)fd_close(highscore_fd);
823         highscore_fd = -1;
824 }
825
826
827 /*!
828  * @brief スコアランキングの簡易表示(種族毎)メインルーチン /
829  * Race Legends -KMW-
830  * @return なし
831  */
832 void race_legends(void)
833 {
834         int i, j;
835
836         for (i = 0; i < MAX_RACES; i++)
837         {
838                 race_score(i);
839                 msg_print(_("何かキーを押すとゲームに戻ります", "Hit any key to continue"));
840                 msg_print(NULL);
841                 for (j = 5; j < 19; j++)
842                         prt("", j, 0);
843         }
844 }
845
846 /*!
847  * @brief 勝利者用の引退演出処理 /
848  * Change the player into a King! -RAK-
849  * @return なし
850  */
851 void kingly(void)
852 {
853         TERM_LEN wid, hgt;
854         TERM_LEN cx, cy;
855         bool seppuku = streq(p_ptr->died_from, "Seppuku");
856
857         /* Hack -- retire in town */
858         current_floor_ptr->dun_level = 0;
859
860         /* Fake death */
861         if (!seppuku)
862                 /* 引退したときの識別文字 */
863                 (void)strcpy(p_ptr->died_from, _("ripe", "Ripe Old Age"));
864
865         /* Restore the experience */
866         p_ptr->exp = p_ptr->max_exp;
867
868         /* Restore the level */
869         p_ptr->lev = p_ptr->max_plv;
870
871         Term_get_size(&wid, &hgt);
872         cy = hgt / 2;
873         cx = wid / 2;
874
875         /* Hack -- Instant Gold */
876         p_ptr->au += 10000000L;
877         Term_clear();
878
879         /* Display a crown */
880         put_str("#", cy - 11, cx - 1);
881         put_str("#####", cy - 10, cx - 3);
882         put_str("#", cy - 9, cx - 1);
883         put_str(",,,  $$$  ,,,", cy - 8, cx - 7);
884         put_str(",,=$   \"$$$$$\"   $=,,", cy - 7, cx - 11);
885         put_str(",$$        $$$        $$,", cy - 6, cx - 13);
886         put_str("*>         <*>         <*", cy - 5, cx - 13);
887         put_str("$$         $$$         $$", cy - 4, cx - 13);
888         put_str("\"$$        $$$        $$\"", cy - 3, cx - 13);
889         put_str("\"$$       $$$       $$\"", cy - 2, cx - 12);
890         put_str("*#########*#########*", cy - 1, cx - 11);
891         put_str("*#########*#########*", cy, cx - 11);
892
893         /* Display a message */
894 #ifdef JP
895         put_str("Veni, Vidi, Vici!", cy + 3, cx - 9);
896         put_str("来た、見た、勝った!", cy + 4, cx - 10);
897         put_str(format("偉大なる%s万歳!", sp_ptr->winner), cy + 5, cx - 11);
898 #else
899         put_str("Veni, Vidi, Vici!", cy + 3, cx - 9);
900         put_str("I came, I saw, I conquered!", cy + 4, cx - 14);
901         put_str(format("All Hail the Mighty %s!", sp_ptr->winner), cy + 5, cx - 13);
902 #endif
903
904         /* If player did Seppuku, that is already written in playrecord */
905         if (!seppuku)
906         {
907                 do_cmd_write_nikki(NIKKI_BUNSHOU, 0, _("ダンジョンの探索から引退した。", "retired exploring dungeons."));
908                 do_cmd_write_nikki(NIKKI_GAMESTART, 1, _("-------- ゲームオーバー --------", "--------   Game  Over   --------"));
909                 do_cmd_write_nikki(NIKKI_BUNSHOU, 1, "\n\n\n\n");
910         }
911
912         /* Flush input */
913         flush();
914
915         /* Wait for response */
916         pause_line(hgt - 1);
917 }