OSDN Git Service

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