3 /* Purpose: Highscores handling */
6 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
8 * This software may be copied and distributed for educational, research, and
9 * not for profit purposes provided that this copyright and statement are
10 * included in all such copies.
17 * Seek score 'i' in the highscore file
19 static int highscore_seek(int i)
21 /* Seek for the requested record */
22 return (fd_seek(highscore_fd, (huge)(i) * sizeof(high_score)));
27 * Read one score from the highscore file
29 static errr highscore_read(high_score *score)
31 /* Read the record, note failure */
32 return (fd_read(highscore_fd, (char*)(score), sizeof(high_score)));
37 * Write one score to the highscore file
39 static int highscore_write(high_score *score)
41 /* Write the record, note failure */
42 return (fd_write(highscore_fd, (char*)(score), sizeof(high_score)));
47 * Just determine where a new score *would* be placed
48 * Return the location (0 is best) or -1 on failure
50 static int highscore_where(high_score *score)
57 my_score = atoi(score->pts);
59 /* Paranoia -- it may not have opened */
60 if (highscore_fd < 0) return (-1);
62 /* Go to the start of the highscore file */
63 if (highscore_seek(0)) return (-1);
65 /* Read until we get to a higher score */
66 for (i = 0; i < MAX_HISCORES; i++)
69 if (highscore_read(&the_score)) return (i);
70 old_score = atoi(the_score.pts);
71 /* if (strcmp(the_score.pts, score->pts) < 0) return (i); */
72 if (my_score > old_score) return (i);
75 /* The "last" entry is always usable */
76 return (MAX_HISCORES - 1);
81 * Actually place an entry into the high score file
82 * Return the location (0 is best) or -1 on "failure"
84 static int highscore_add(high_score *score)
89 high_score the_score, tmpscore;
92 /* Paranoia -- it may not have opened */
93 if (highscore_fd < 0) return (-1);
95 /* Determine where the score should go */
96 slot = highscore_where(score);
98 /* Hack -- Not on the list */
99 if (slot < 0) return (-1);
101 /* Hack -- prepare to dump the new score */
102 the_score = (*score);
104 /* Slide all the scores down one */
105 for (i = slot; !done && (i < MAX_HISCORES); i++)
107 /* Read the old guy, note errors */
108 if (highscore_seek(i)) return (-1);
109 if (highscore_read(&tmpscore)) done = TRUE;
111 /* Back up and dump the score we were holding */
112 if (highscore_seek(i)) return (-1);
113 if (highscore_write(&the_score)) return (-1);
115 /* Hack -- Save the old score, for the next pass */
116 the_score = tmpscore;
119 /* Return location used */
126 * Display the scores in a given range.
127 * Assumes the high score list is already open.
128 * Only five entries per line, too much info.
130 * Mega-Hack -- allow "fake" entry at the given position.
132 void display_scores_aux(int from, int to, int note, high_score *score)
134 int i, j, k, n, place;
137 high_score the_score;
143 /* Paranoia -- it may not have opened */
144 if (highscore_fd < 0) return;
147 /* Assume we will show the first 10 */
148 if (from < 0) from = 0;
150 if (to > MAX_HISCORES) to = MAX_HISCORES;
153 /* Seek to the beginning */
154 if (highscore_seek(0)) return;
156 /* Hack -- Count the high scores */
157 for (i = 0; i < MAX_HISCORES; i++)
159 if (highscore_read(&the_score)) break;
162 /* Hack -- allow "fake" entry to be last */
163 if ((note == i) && score) i++;
165 /* Forget about the last entries */
169 /* Show 5 per page, until "done" */
170 for (k = from, place = k+1; k < i; k += 5)
177 put_str(" ÊѶòÈÚÅÜ: ͦ¼Ô¤ÎÅÂƲ", 0, 0);
179 put_str(" Hengband Hall of Fame", 0, 0);
183 /* Indicate non-top scores */
187 sprintf(tmp_val, "( %d °Ì°Ê²¼ )", k + 1);
189 sprintf(tmp_val, "(from position %d)", k + 1);
192 put_str(tmp_val, 0, 40);
196 for (j = k, n = 0; j < i && n < 5; place++, j++, n++)
198 int pr, pc, pa, clev, mlev, cdun, mdun;
200 cptr user, gold, when, aged;
203 /* Hack -- indicate death in yellow */
204 attr = (j == note) ? TERM_YELLOW : TERM_WHITE;
207 /* Mega-Hack -- insert a "fake" record */
208 if ((note == j) && score)
210 the_score = (*score);
217 /* Read a normal record */
220 /* Read the proper record */
221 if (highscore_seek(j)) break;
222 if (highscore_read(&the_score)) break;
225 /* Extract the race/class */
226 pr = atoi(the_score.p_r);
227 pc = atoi(the_score.p_c);
228 pa = atoi(the_score.p_a);
230 /* Extract the level info */
231 clev = atoi(the_score.cur_lev);
232 mlev = atoi(the_score.max_lev);
233 cdun = atoi(the_score.cur_dun);
234 mdun = atoi(the_score.max_dun);
236 /* Hack -- extract the gold and such */
237 for (user = the_score.uid; isspace(*user); user++) /* loop */;
238 for (when = the_score.day; isspace(*when); when++) /* loop */;
239 for (gold = the_score.gold; isspace(*gold); gold++) /* loop */;
240 for (aged = the_score.turns; isspace(*aged); aged++) /* loop */;
242 /* Clean up standard encoded form of "when" */
243 if ((*when == '@') && strlen(when) == 9)
245 sprintf(tmp_val, "%.4s-%.2s-%.2s",
246 when + 1, when + 5, when + 7);
252 /*sprintf(out_val, "%3d.%9s %s%s%s¤È¤¤¤¦Ì¾¤Î%s¤Î%s (¥ì¥Ù¥ë %d)", */
253 sprintf(out_val, "%3d.%9s %s%s%s - %s%s (¥ì¥Ù¥ë %d)",
254 place, the_score.pts,
255 seikaku_info[pa].title, (seikaku_info[pa].no ? "¤Î" : ""),
257 race_info[pr].title, class_info[pc].title,
261 sprintf(out_val, "%3d.%9s %s %s the %s %s, Level %d",
262 place, the_score.pts,
263 seikaku_info[pa].title,
264 the_score.who, race_info[pr].title, class_info[pc].title,
269 /* Append a "maximum level" */
271 if (mlev > clev) strcat(out_val, format(" (ºÇ¹â%d)", mlev));
273 if (mlev > clev) strcat(out_val, format(" (Max %d)", mlev));
277 /* Dump the first line */
278 c_put_str(attr, out_val, n*4 + 2, 0);
280 /* Another line of info */
283 sprintf(out_val, " ºÇ¹â%3d³¬", mdun);
285 sprintf(out_val, " ");
288 /* »àË´¸¶°ø¤ò¥ª¥ê¥¸¥Ê¥ë¤è¤êºÙ¤«¤¯É½¼¨ */
289 if (streq(the_score.how, "yet"))
291 sprintf(out_val+13, " ¤Þ¤ÀÀ¸¤¤Æ¤¤¤ë (%d%s)",
295 if (streq(the_score.how, "ripe"))
297 sprintf(out_val+13, " ¾¡Íø¤Î¸å¤Ë°úÂà (%d%s)",
300 else if (streq(the_score.how, "Seppuku"))
302 sprintf(out_val+13, " ¾¡Íø¤Î¸å¤ËÀÚÊ¢ (%d%s)",
307 /* Some people die outside of the dungeon */
309 sprintf(out_val+13, " ÃϾå¤Ç%s¤Ë»¦¤µ¤ì¤¿", the_score.how);
311 sprintf(out_val+13, " %d³¬¤Ç%s¤Ë»¦¤µ¤ì¤¿",
312 cdun, the_score.how);
316 /* Some people die outside of the dungeon */
319 " Killed by %s on the surface",
323 " Killed by %s on %s %d",
324 the_score.how, "Dungeon Level", cdun);
326 /* Append a "maximum level" */
327 if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun));
331 c_put_str(attr, out_val, n*4 + 3, 0);
333 /* And still another line of info */
338 /* ÆüÉÕ¤ò 19yy/mm/dd ¤Î·Á¼°¤ËÊѹ¹¤¹¤ë */
339 if (strlen(when) == 8 && when[2] == '/' && when[5] == '/') {
340 sprintf(buf, "%d%s/%.5s", 19 + (when[6] < '8'), when + 6, when);
344 " (¥æ¡¼¥¶¡¼:%s, ÆüÉÕ:%s, ½ê»ý¶â:%s, ¥¿¡¼¥ó:%s)",
345 user, when, gold, aged);
350 " (User %s, Date %s, Gold %s, Turn %s).",
351 user, when, gold, aged);
354 c_put_str(attr, out_val, n*4 + 4, 0);
358 /* Wait for response */
360 prt("[ ESC¤ÇÃæÃÇ, ¤½¤Î¾¤Î¥¡¼¤Ç³¤±¤Þ¤¹ ]", 23, 21);
362 prt("[Press ESC to quit, any other key to continue.]", 23, 17);
368 /* Hack -- notice Escape */
369 if (j == ESCAPE) break;
375 * Hack -- Display the scores in a given range and quit.
377 * This function is only called from "main.c" when the user asks
378 * to see the "high scores".
380 void display_scores(int from, int to)
384 /* Build the filename */
385 path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
387 /* Open the binary high score file, for reading */
388 highscore_fd = fd_open(buf, O_RDONLY);
390 /* Paranoia -- No score file */
392 if (highscore_fd < 0) quit("¥¹¥³¥¢¡¦¥Õ¥¡¥¤¥ë¤¬»ÈÍѤǤ¤Þ¤»¤ó¡£");
394 if (highscore_fd < 0) quit("Score file unavailable.");
401 /* Display the scores */
402 display_scores_aux(from, to, -1, NULL);
404 /* Shut the high score file */
405 (void)fd_close(highscore_fd);
407 /* Forget the high score fd */
416 bool send_world_score(bool do_send)
419 if(send_score && do_send)
424 msg_print("½é¿´¼Ô¥â¡¼¥É¤Ç¤Ï¥ï¡¼¥ë¥É¥¹¥³¥¢¤ËÅÐÏ¿¤Ç¤¤Þ¤»¤ó¡£");
426 msg_print("Since you are in the Easy Mode, you cannot send score to world score server.");
430 else if(get_check("¥¹¥³¥¢¤ò¥¹¥³¥¢¡¦¥µ¡¼¥Ð¤ËÅÐÏ¿¤·¤Þ¤¹¤«? "))
432 else if(get_check("Do you send score to the world score sever? "))
438 prt("Á÷¿®Ãæ¡¥¡¥",0,0);
440 prt("Sending...",0,0);
444 err = report_score();
451 prt("´°Î»¡£²¿¤«¥¡¼¤ò²¡¤·¤Æ¤¯¤À¤µ¤¤¡£", 0, 0);
453 prt("Completed. Hit any key.", 0, 0);
464 * Enters a players name on a hi-score table, if "legal", and in any
465 * case, displays some relevant portion of the high score list.
467 * Assumes "signals_ignore_tstp()" has been called.
469 errr top_twenty(void)
473 high_score the_score;
475 time_t ct = time((time_t*)0);
477 /* Clear the record */
478 (void)WIPE(&the_score, high_score);
480 /* Save the version */
481 sprintf(the_score.what, "%u.%u.%u",
482 VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
484 /* Calculate and save the points */
485 sprintf(the_score.pts, "%9ld", (long)total_points());
486 the_score.pts[9] = '\0';
488 /* Save the current gold */
489 sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
490 the_score.gold[9] = '\0';
492 /* Save the current turn */
493 sprintf(the_score.turns, "%9lu", (long)turn_real(turn));
494 the_score.turns[9] = '\0';
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);
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));
506 /* Save the player name (15 chars) */
507 sprintf(the_score.who, "%-.15s", player_name);
509 /* Save the player info XXX XXX XXX */
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", p_ptr->prace);
513 sprintf(the_score.p_c, "%2d", p_ptr->pclass);
514 sprintf(the_score.p_a, "%2d", p_ptr->pseikaku);
516 /* Save the level and such */
517 sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
518 sprintf(the_score.cur_dun, "%3d", dun_level);
519 sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
520 sprintf(the_score.max_dun, "%3d", max_dlv[dungeon_type]);
522 /* Save the cause of death (31 chars) */
526 /* 2byte ʸ»ú¤ò¹Íθ¤·¤Ê¤¬¤é¥³¥Ô¡¼(EUC ¤ò²¾Äê) */
528 unsigned char *d = (unsigned char*)died_from;
529 unsigned char *h = (unsigned char*)the_score.how;
530 while(*d && cnt < 31){
532 if(cnt + 2 > 31) break;
537 if(cnt + 1 > 31) break;
545 if (strlen(died_from) >= 39)
547 mb_strlcpy(the_score.how, died_from, 37+1);
548 strcat(the_score.how, "¡Ä");
551 strcpy(the_score.how, died_from);
554 sprintf(the_score.how, "%-.31s", died_from);
558 /* Lock (for writing) the highscore file, or fail */
559 if (fd_lock(highscore_fd, F_WRLCK)) return (1);
561 /* Add a new entry to the score list, see where it went */
562 j = highscore_add(&the_score);
564 /* Unlock the highscore file, or fail */
565 if (fd_lock(highscore_fd, F_UNLCK)) return (1);
568 /* Hack -- Display the top fifteen scores */
571 display_scores_aux(0, 15, j, NULL);
574 /* Display the scores surrounding the player */
577 display_scores_aux(0, 5, j, NULL);
578 display_scores_aux(j - 2, j + 7, j, NULL);
588 * Predict the players location, and display it.
590 errr predict_score(void)
594 high_score the_score;
598 if (highscore_fd < 0)
601 msg_print("¥¹¥³¥¢¡¦¥Õ¥¡¥¤¥ë¤¬»ÈÍѤǤ¤Þ¤»¤ó¡£");
603 msg_print("Score file unavailable.");
611 /* Save the version */
612 sprintf(the_score.what, "%u.%u.%u",
613 VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
615 /* Calculate and save the points */
616 sprintf(the_score.pts, "%9ld", (long)total_points());
618 /* Save the current gold */
619 sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
621 /* Save the current turn */
622 sprintf(the_score.turns, "%9lu", (long)turn_real(turn));
624 /* Hack -- no time needed */
626 strcpy(the_score.day, "º£Æü");
628 strcpy(the_score.day, "TODAY");
632 /* Save the player name (15 chars) */
633 sprintf(the_score.who, "%-.15s", player_name);
635 /* Save the player info XXX XXX XXX */
636 sprintf(the_score.uid, "%7u", player_uid);
637 sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
638 sprintf(the_score.p_r, "%2d", p_ptr->prace);
639 sprintf(the_score.p_c, "%2d", p_ptr->pclass);
640 sprintf(the_score.p_a, "%2d", p_ptr->pseikaku);
642 /* Save the level and such */
643 sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
644 sprintf(the_score.cur_dun, "%3d", dun_level);
645 sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
646 sprintf(the_score.max_dun, "%3d", max_dlv[dungeon_type]);
648 /* Hack -- no cause of death */
650 /* ¤Þ¤À»à¤ó¤Ç¤¤¤Ê¤¤¤È¤¤Î¼±ÊÌʸ»ú */
651 strcpy(the_score.how, "yet");
653 strcpy(the_score.how, "nobody (yet!)");
658 /* See where the entry would be placed */
659 j = highscore_where(&the_score);
662 /* Hack -- Display the top fifteen scores */
665 display_scores_aux(0, 15, j, &the_score);
668 /* Display some "useful" scores */
671 display_scores_aux(0, 5, -1, NULL);
672 display_scores_aux(j - 2, j + 7, j, &the_score);
683 * show_highclass - selectively list highscores based on class
686 void show_highclass(int building)
689 register int i = 0, j, m = 0;
690 int pr, pc, pa, clev/*, al*/;
691 high_score the_score;
692 char buf[1024], out_val[256];
696 /* Build the filename */
697 path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
699 highscore_fd = fd_open(buf, O_RDONLY);
701 if (highscore_fd < 0)
704 msg_print("¥¹¥³¥¢¡¦¥Õ¥¡¥¤¥ë¤¬»ÈÍѤǤ¤Þ¤»¤ó¡£");
706 msg_print("Score file unavailable.");
713 if (highscore_seek(0)) return;
715 for (i = 0; i < MAX_HISCORES; i++)
716 if (highscore_read(&the_score)) break;
722 while ((m < 9) && (j < MAX_HISCORES))
724 if (highscore_seek(j)) break;
725 if (highscore_read(&the_score)) break;
726 pr = atoi(the_score.p_r);
727 pc = atoi(the_score.p_c);
728 pa = atoi(the_score.p_a);
729 clev = atoi(the_score.cur_lev);
732 sprintf(out_val, " %3d) %s¤Î%s (¥ì¥Ù¥ë %2d)",
733 (m + 1), race_info[pr].title,the_score.who, clev);
735 sprintf(out_val, "%3d) %s the %s (Level %2d)",
736 (m + 1), the_score.who, race_info[pr].title, clev);
739 prt(out_val, (m + 7), 0);
745 sprintf(out_val, "¤¢¤Ê¤¿) %s¤Î%s (¥ì¥Ù¥ë %2d)",
746 race_info[p_ptr->prace].title,player_name, p_ptr->lev);
748 sprintf(out_val, "You) %s the %s (Level %2d)",
749 player_name, race_info[p_ptr->prace].title, p_ptr->lev);
752 prt(out_val, (m + 8), 0);
754 (void)fd_close(highscore_fd);
757 prt("²¿¤«¥¡¼¤ò²¡¤¹¤È¥²¡¼¥à¤ËÌá¤ê¤Þ¤¹",0,0);
759 prt("Hit any key to continue",0,0);
764 for (j = 5; j < 18; j++) prt("", j, 0);
773 void race_score(int race_num)
775 register int i = 0, j, m = 0;
776 int pr, pc, pa, clev, lastlev;
777 high_score the_score;
778 char buf[1024], out_val[256], tmp_str[80];
782 /* rr9: TODO - pluralize the race */
784 sprintf(tmp_str,"ºÇ¹â¤Î%s", race_info[race_num].title);
786 sprintf(tmp_str,"The Greatest of all the %s", race_info[race_num].title);
791 /* Build the filename */
792 path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
794 highscore_fd = fd_open(buf, O_RDONLY);
796 if (highscore_fd < 0)
799 msg_print("¥¹¥³¥¢¡¦¥Õ¥¡¥¤¥ë¤¬»ÈÍѤǤ¤Þ¤»¤ó¡£");
801 msg_print("Score file unavailable.");
808 if (highscore_seek(0)) return;
810 for (i = 0; i < MAX_HISCORES; i++)
812 if (highscore_read(&the_score)) break;
818 while ((m < 10) || (j < MAX_HISCORES))
820 if (highscore_seek(j)) break;
821 if (highscore_read(&the_score)) break;
822 pr = atoi(the_score.p_r);
823 pc = atoi(the_score.p_c);
824 pa = atoi(the_score.p_a);
825 clev = atoi(the_score.cur_lev);
830 sprintf(out_val, " %3d) %s¤Î%s (¥ì¥Ù¥ë %2d)",
831 (m + 1), race_info[pr].title,
834 sprintf(out_val, "%3d) %s the %s (Level %3d)",
835 (m + 1), the_score.who,
836 race_info[pr].title, clev);
839 prt(out_val, (m + 7), 0);
846 /* add player if qualified */
847 if ((p_ptr->prace == race_num) && (p_ptr->lev >= lastlev))
850 sprintf(out_val, "¤¢¤Ê¤¿) %s¤Î%s (¥ì¥Ù¥ë %2d)",
851 race_info[p_ptr->prace].title,player_name, p_ptr->lev);
853 sprintf(out_val, "You) %s the %s (Level %3d)",
854 player_name, race_info[p_ptr->prace].title, p_ptr->lev);
857 prt(out_val, (m + 8), 0);
860 (void)fd_close(highscore_fd);
869 void race_legends(void)
873 for (i = 0; i < MAX_RACES; i++)
877 msg_print("²¿¤«¥¡¼¤ò²¡¤¹¤È¥²¡¼¥à¤ËÌá¤ê¤Þ¤¹");
879 msg_print("Hit any key to continue");
883 for (j = 5; j < 19; j++)
890 * Change the player into a King! -RAK-
894 /* Hack -- retire in town */
898 if (!streq(died_from, "Seppuku"))
900 /* °úÂष¤¿¤È¤¤Î¼±ÊÌʸ»ú */
901 (void)strcpy(died_from, "ripe");
903 (void)strcpy(died_from, "Ripe Old Age");
907 /* Restore the experience */
908 p_ptr->exp = p_ptr->max_exp;
910 /* Restore the level */
911 p_ptr->lev = p_ptr->max_plv;
913 /* Hack -- Instant Gold */
914 p_ptr->au += 10000000L;
919 /* Display a crown */
921 put_str("#####", 2, 32);
923 put_str(",,, $$$ ,,,", 4, 28);
924 put_str(",,=$ \"$$$$$\" $=,,", 5, 24);
925 put_str(",$$ $$$ $$,", 6, 22);
926 put_str("*> <*> <*", 7, 22);
927 put_str("$$ $$$ $$", 8, 22);
928 put_str("\"$$ $$$ $$\"", 9, 22);
929 put_str("\"$$ $$$ $$\"", 10, 23);
930 put_str("*#########*#########*", 11, 24);
931 put_str("*#########*#########*", 12, 24);
933 /* Display a message */
935 put_str("Veni, Vidi, Vici!", 15, 26);
936 put_str("Í褿¡¢¸«¤¿¡¢¾¡¤Ã¤¿¡ª", 16, 25);
937 put_str(format("°ÎÂç¤Ê¤ë%sËüºÐ¡ª", sp_ptr->winner), 17, 22);
939 put_str("Veni, Vidi, Vici!", 15, 26);
940 put_str("I came, I saw, I conquered!", 16, 21);
941 put_str(format("All Hail the Mighty %s!", sp_ptr->winner), 17, 22);
945 do_cmd_write_nikki(NIKKI_BUNSHOU, 0, "¥À¥ó¥¸¥ç¥ó¤Îõº÷¤«¤é°úÂष¤¿¡£");
946 do_cmd_write_nikki(NIKKI_GAMESTART, 1, "-------- ¥²¡¼¥à¥ª¡¼¥Ð¡¼ --------");
948 do_cmd_write_nikki(NIKKI_BUNSHOU, 0, "retire exploring dungeons.");
949 do_cmd_write_nikki(NIKKI_GAMESTART, 1, "-------- Game Over --------");
951 do_cmd_write_nikki(NIKKI_BUNSHOU, 1, "\n\n\n\n");
956 /* Wait for response */