/* * Just determine where a new score *would* be placed * Return the location (0 is best) or -1 on failure */ static int highscore_where(high_score *score) { int i; high_score the_score; int my_score; my_score = atoi(score->pts); /* Paranoia -- it may not have opened */ if (highscore_fd < 0) return (-1); /* Go to the start of the highscore file */ if (highscore_seek(0)) return (-1); /* Read until we get to a higher score */ for (i = 0; i < MAX_HISCORES; i++) { int old_score; if (highscore_read(&the_score)) return (i); old_score = atoi(the_score.pts); /* if (strcmp(the_score.pts, score->pts) < 0) return (i); */ if (my_score > old_score) return (i); } /* The "last" entry is always usable */ return (MAX_HISCORES - 1); }
/* * Predict the players location, and display it. */ void predict_score(void) { int j; high_score the_score; high_score scores[MAX_HISCORES]; /* Read scores, place current score */ highscore_read(scores, N_ELEMENTS(scores)); build_score(&the_score, "nobody (yet!)", NULL); if (p_ptr->is_dead) j = highscore_where(&the_score, scores, N_ELEMENTS(scores)); else j = highscore_add(&the_score, scores, N_ELEMENTS(scores)); /* Hack -- Display the top fifteen scores */ if (j < 10) { display_scores_aux(scores, 0, 15, j); } /* Display some "useful" scores */ else { display_scores_aux(scores, 0, 5, -1); display_scores_aux(scores, j - 2, j + 7, j); } }
/** * Enters a players name on a hi-score table, if "legal". * * Assumes "signals_ignore_tstp()" has been called. */ void enter_score(time_t *death_time) { int j; /* Cheaters are not scored */ for (j = 0; j < OPT_MAX; ++j) { if (option_type(j) != OP_SCORE) continue; if (!player->opts.opt[j]) continue; msg("Score not registered for cheaters."); event_signal(EVENT_MESSAGE_FLUSH); return; } /* Add a new entry, if allowed */ if (player->noscore & (NOSCORE_WIZARD | NOSCORE_DEBUG)) { msg("Score not registered for wizards."); event_signal(EVENT_MESSAGE_FLUSH); } else if (!player->total_winner && streq(player->died_from, "Interrupting")) { msg("Score not registered due to interruption."); event_signal(EVENT_MESSAGE_FLUSH); } else if (!player->total_winner && streq(player->died_from, "Quitting")) { msg("Score not registered due to quitting."); event_signal(EVENT_MESSAGE_FLUSH); } else { high_score entry; high_score scores[MAX_HISCORES]; build_score(&entry, player->died_from, death_time); highscore_read(scores, N_ELEMENTS(scores)); highscore_add(&entry, scores, N_ELEMENTS(scores)); highscore_write(scores, N_ELEMENTS(scores)); } /* Success */ return; }
/* * Show scores. */ void show_scores(void) { screen_save(); /* Display the scores */ if (character_generated) { predict_score(); } else { high_score scores[MAX_HISCORES]; highscore_read(scores, N_ELEMENTS(scores)); display_scores_aux(scores, 0, MAX_HISCORES, -1); } screen_load(); /* Hack - Flush it */ Term_fresh(); }
/* * Actually place an entry into the high score file * Return the location (0 is best) or -1 on "failure" */ static int highscore_add(high_score *score) { int i, slot; bool done = FALSE; high_score the_score, tmpscore; /* Paranoia -- it may not have opened */ if (highscore_fd < 0) return (-1); /* Determine where the score should go */ slot = highscore_where(score); /* Hack -- Not on the list */ if (slot < 0) return (-1); /* Hack -- prepare to dump the new score */ the_score = (*score); /* Slide all the scores down one */ for (i = slot; !done && (i < MAX_HISCORES); i++) { /* Read the old guy, note errors */ if (highscore_seek(i)) return (-1); if (highscore_read(&tmpscore)) done = TRUE; /* Back up and dump the score we were holding */ if (highscore_seek(i)) return (-1); if (highscore_write(&the_score)) return (-1); /* Hack -- Save the old score, for the next pass */ the_score = tmpscore; } /* Return location used */ return (slot); }
/* * Enters a players name on a hi-score table, if "legal". * * Assumes "signals_ignore_tstp()" has been called. */ void enter_score(time_t *death_time) { int j; /* Cheaters are not scored */ for (j = OPT_SCORE; j < OPT_MAX; ++j) { if (!op_ptr->opt[j]) continue; msg_print("Score not registered for cheaters."); message_flush(); return; } /* Wizard-mode pre-empts scoring */ if (p_ptr->noscore & (NOSCORE_WIZARD | NOSCORE_DEBUG)) { msg_print("Score not registered for wizards."); message_flush(); } #ifndef SCORE_BORGS /* Borg-mode pre-empts scoring */ else if (p_ptr->noscore & NOSCORE_BORG) { msg_print("Score not registered for borgs."); message_flush(); } #endif /* SCORE_BORGS */ /* Hack -- Interupted */ else if (!p_ptr->total_winner && streq(p_ptr->died_from, "Interrupting")) { msg_print("Score not registered due to interruption."); message_flush(); } /* Hack -- Quitter */ else if (!p_ptr->total_winner && streq(p_ptr->died_from, "Quitting")) { msg_print("Score not registered due to quitting."); message_flush(); } /* Add a new entry to the score list, see where it went */ else { high_score entry; high_score scores[MAX_HISCORES]; build_score(&entry, p_ptr->died_from, death_time); highscore_read(scores, N_ELEMENTS(scores)); highscore_add(&entry, scores, N_ELEMENTS(scores)); highscore_write(scores, N_ELEMENTS(scores)); } /* Success */ return; }
/* * Race Legends * -KMW- */ void race_score(int race_num) { register int i = 0, j, m = 0; int pr, clev, lastlev; high_score the_score; char buf[1024], out_val[256], tmp_str[80]; lastlev = 0; /* rr9: TODO - pluralize the race */ sprintf(tmp_str,"The Greatest of all the %s", get_race_t_aux(race_num, 0)->name); prt(tmp_str, 5, 15); /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); highscore_fd = fd_open(buf, O_RDONLY); if (highscore_fd < 0) { msg_print("Score file unavailable."); msg_print(NULL); return; } if (highscore_seek(0)) return; for (i = 0; i < MAX_HISCORES; i++) { if (highscore_read(&the_score)) break; } m = 0; j = 0; while ((m < 10) || (j < MAX_HISCORES)) { if (highscore_seek(j)) break; if (highscore_read(&the_score)) break; pr = atoi(the_score.p_r); clev = atoi(the_score.cur_lev); if (pr == race_num) { sprintf(out_val, "%3d) %s the %s (Level %3d)", (m + 1), the_score.who, get_race_t_aux(pr, 0)->name, clev); prt(out_val, (m + 7), 0); m++; lastlev = clev; } j++; } /* add player if qualified */ if ((p_ptr->prace == race_num) && (p_ptr->lev >= lastlev)) { sprintf(out_val, "You) %s the %s (Level %3d)", player_name, get_race_t_aux(p_ptr->prace, p_ptr->psubrace)->name, p_ptr->lev); prt(out_val, (m + 8), 0); } (void)fd_close(highscore_fd); highscore_fd = -1; }
/* * show_highclass - selectively list highscores based on class * -KMW- */ void show_highclass(void) { register int i = 0, j, m = 0; int pr, clev/*, al*/; high_score the_score; char buf[1024], out_val[256]; screen_save(); /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); highscore_fd = fd_open(buf, O_RDONLY); if (highscore_fd < 0) { msg_print("Score file unavailable."); msg_print(NULL); return; } if (highscore_seek(0)) return; for (i = 0; i < MAX_HISCORES; i++) if (highscore_read(&the_score)) break; m = 0; j = 0; clev = 0; while ((m < 9) && (j < MAX_HISCORES)) { if (highscore_seek(j)) break; if (highscore_read(&the_score)) break; pr = atoi(the_score.p_r); clev = atoi(the_score.cur_lev); sprintf(out_val, "%3d) %s the %s (Level %2d)", (m + 1), the_score.who, get_race_t_aux(pr, 0)->name, clev); prt(out_val, (m + 7), 0); m++; j++; } sprintf(out_val, "You) %s the %s (Level %2d)", player_name, get_race_t_aux(p_ptr->prace, p_ptr->psubrace)->name, p_ptr->lev); prt(out_val, (m + 8), 0); (void)fd_close(highscore_fd); highscore_fd = -1; prt("Hit any key to continue",0,0); (void)inkey(); for (j = 5; j < 18; j++) prt("", j, 0); screen_load(); }
/* * Display the scores in a given range. * Assumes the high score list is already open. * Only five entries per line, too much info. * * Mega-Hack -- allow "fake" entry at the given position. */ void display_scores_aux(int from, int to, int note, high_score *score) { int i, j, k, n, place; byte attr; high_score the_score; char out_val[256]; char tmp_val[160]; int wid, hgt, per_screen; Term_get_size(&wid, &hgt); per_screen = (hgt - 4) / 4; /* Paranoia -- it may not have opened */ if (highscore_fd < 0) return; /* Assume we will show the first 10 */ if (from < 0) from = 0; if (to < 0) to = 10; if (to > MAX_HISCORES) to = MAX_HISCORES; /* Seek to the beginning */ if (highscore_seek(0)) return; /* Hack -- Count the high scores */ for (i = 0; i < MAX_HISCORES; i++) { if (highscore_read(&the_score)) break; } /* Hack -- allow "fake" entry to be last */ if ((note == i) && score) i++; /* Forget about the last entries */ if (i > to) i = to; /* Show per_screen per page, until "done" */ for (k = from, place = k+1; k < i; k += per_screen) { /* Clear screen */ Term_clear(); /* Title */ put_str(" PosChengband Hall of Fame", 0, 0); /* Indicate non-top scores */ if (k > 0) { sprintf(tmp_val, "(from position %d)", k + 1); put_str(tmp_val, 0, 40); } /* Dump per_screen entries */ for (j = k, n = 0; j < i && n < per_screen; place++, j++, n++) { int pr, pc, pa, clev, mlev, cdun, mdun; cptr user, gold, when, aged; /* Hack -- indicate death in yellow */ attr = (j == note) ? TERM_YELLOW : TERM_WHITE; /* Mega-Hack -- insert a "fake" record */ if ((note == j) && score) { the_score = (*score); attr = TERM_L_GREEN; score = NULL; note = -1; j--; } /* Read a normal record */ else { /* Read the proper record */ if (highscore_seek(j)) break; if (highscore_read(&the_score)) break; } /* Extract the race/class */ pr = atoi(the_score.p_r); pc = atoi(the_score.p_c); pa = atoi(the_score.p_a); /* Extract the level info */ clev = atoi(the_score.cur_lev); mlev = atoi(the_score.max_lev); cdun = atoi(the_score.cur_dun); mdun = atoi(the_score.max_dun); /* Hack -- extract the gold and such */ for (user = the_score.uid; isspace(*user); user++) /* loop */; for (when = the_score.day; isspace(*when); when++) /* loop */; for (gold = the_score.gold; isspace(*gold); gold++) /* loop */; for (aged = the_score.turns; isspace(*aged); aged++) /* loop */; /* Clean up standard encoded form of "when" */ if ((*when == '@') && strlen(when) == 9) { sprintf(tmp_val, "%.4s-%.2s-%.2s", when + 1, when + 5, when + 7); when = tmp_val; } /* Dump some info */ sprintf(out_val, "%3d.%9s %s %s the %s %s, Level %d", place, the_score.pts, seikaku_info[pa].title, the_score.who, get_race_t_aux(pr, 0)->name, get_class_t_aux(pc, 0)->name, clev); /* Append a "maximum level" */ if (mlev > clev) strcat(out_val, format(" (Max %d)", mlev)); /* Dump the first line */ c_put_str(attr, out_val, n*4 + 2, 0); /* Another line of info */ /* Some people die outside of the dungeon */ if (!cdun) sprintf(out_val, " Killed by %s on the surface", the_score.how); else sprintf(out_val, " Killed by %s on %s %d", the_score.how, "Dungeon Level", cdun); /* Append a "maximum level" */ if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun)); /* Dump the info */ c_put_str(attr, out_val, n*4 + 3, 0); /* And still another line of info */ sprintf(out_val, " (User %s, Date %s, Gold %s, Turn %s).", user, when, gold, aged); c_put_str(attr, out_val, n*4 + 4, 0); } /* Wait for response */ prt("[Press ESC to quit, any other key to continue.]", hgt - 1, 17); j = inkey(); prt("", hgt - 1, 0); /* Hack -- notice Escape */ if (j == ESCAPE) break; } }
/*! * @brief スコアランキングの簡易表示 / * show_highclass - selectively list highscores based on class -KMW- * @return なし */ void show_highclass(void) { register int i = 0, j, m = 0; int pr, clev/*, al*/; high_score the_score; char buf[1024], out_val[256]; screen_save(); /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw"); highscore_fd = fd_open(buf, O_RDONLY); if (highscore_fd < 0) { msg_print(_("スコア・ファイルが使用できません。", "Score file unavailable.")); msg_print(NULL); return; } if (highscore_seek(0)) return; for (i = 0; i < MAX_HISCORES; i++) if (highscore_read(&the_score)) break; m = 0; j = 0; clev = 0; while ((m < 9) && (j < MAX_HISCORES)) { if (highscore_seek(j)) break; if (highscore_read(&the_score)) break; pr = atoi(the_score.p_r); clev = atoi(the_score.cur_lev); #ifdef JP sprintf(out_val, " %3d) %sの%s (レベル %2d)", (m + 1), race_info[pr].title,the_score.who, clev); #else sprintf(out_val, "%3d) %s the %s (Level %2d)", (m + 1), the_score.who, race_info[pr].title, clev); #endif prt(out_val, (m + 7), 0); m++; j++; } #ifdef JP sprintf(out_val, "あなた) %sの%s (レベル %2d)", race_info[p_ptr->prace].title,player_name, p_ptr->lev); #else sprintf(out_val, "You) %s the %s (Level %2d)", player_name, race_info[p_ptr->prace].title, p_ptr->lev); #endif prt(out_val, (m + 8), 0); (void)fd_close(highscore_fd); highscore_fd = -1; prt(_("何かキーを押すとゲームに戻ります", "Hit any key to continue"),0,0); (void)inkey(); for (j = 5; j < 18; j++) prt("", j, 0); screen_load(); }
/*! * @brief 指定された順位範囲でスコアを並べて表示する / Display the scores in a given range. * @param from 順位先頭 * @param to 順位末尾 * @param note 黄色表示でハイライトする順位 * @param score スコア配列参照ポインタ * @return なし * @details * <pre> * Assumes the high score list is already open. * Only five entries per line, too much info. * * Mega-Hack -- allow "fake" entry at the given position. * </pre> */ void display_scores_aux(int from, int to, int note, high_score *score) { int i, j, k, n, place; byte attr; high_score the_score; char out_val[256]; char tmp_val[160]; int wid, hgt, per_screen; Term_get_size(&wid, &hgt); per_screen = (hgt - 4) / 4; /* Paranoia -- it may not have opened */ if (highscore_fd < 0) return; /* Assume we will show the first 10 */ if (from < 0) from = 0; if (to < 0) to = 10; if (to > MAX_HISCORES) to = MAX_HISCORES; /* Seek to the beginning */ if (highscore_seek(0)) return; /* Hack -- Count the high scores */ for (i = 0; i < MAX_HISCORES; i++) { if (highscore_read(&the_score)) break; } /* Hack -- allow "fake" entry to be last */ if ((note == i) && score) i++; /* Forget about the last entries */ if (i > to) i = to; /* Show per_screen per page, until "done" */ for (k = from, place = k+1; k < i; k += per_screen) { /* Clear screen */ Term_clear(); /* Title */ put_str(_(" 変愚蛮怒: 勇者の殿堂", " Hengband Hall of Fame"), 0, 0); /* Indicate non-top scores */ if (k > 0) { sprintf(tmp_val, _("( %d 位以下 )", "(from position %d)"), k + 1); put_str(tmp_val, 0, 40); } /* Dump per_screen entries */ for (j = k, n = 0; j < i && n < per_screen; place++, j++, n++) { int pr, pc, pa, clev, mlev, cdun, mdun; cptr user, gold, when, aged; /* Hack -- indicate death in yellow */ attr = (j == note) ? TERM_YELLOW : TERM_WHITE; /* Mega-Hack -- insert a "fake" record */ if ((note == j) && score) { the_score = (*score); attr = TERM_L_GREEN; score = NULL; note = -1; j--; } /* Read a normal record */ else { /* Read the proper record */ if (highscore_seek(j)) break; if (highscore_read(&the_score)) break; } /* Extract the race/class */ pr = atoi(the_score.p_r); pc = atoi(the_score.p_c); pa = atoi(the_score.p_a); /* Extract the level info */ clev = atoi(the_score.cur_lev); mlev = atoi(the_score.max_lev); cdun = atoi(the_score.cur_dun); mdun = atoi(the_score.max_dun); /* Hack -- extract the gold and such */ for (user = the_score.uid; iswspace(*user); user++) /* loop */; for (when = the_score.day; iswspace(*when); when++) /* loop */; for (gold = the_score.gold; iswspace(*gold); gold++) /* loop */; for (aged = the_score.turns; iswspace(*aged); aged++) /* loop */; /* Clean up standard encoded form of "when" */ if ((*when == '@') && strlen(when) == 9) { sprintf(tmp_val, "%.4s-%.2s-%.2s", when + 1, when + 5, when + 7); when = tmp_val; } /* Dump some info */ #ifdef JP /*sprintf(out_val, "%3d.%9s %s%s%sという名の%sの%s (レベル %d)", */ sprintf(out_val, "%3d.%9s %s%s%s - %s%s (レベル %d)", place, the_score.pts, seikaku_info[pa].title, (seikaku_info[pa].no ? "の" : ""), the_score.who, race_info[pr].title, class_info[pc].title, clev); #else sprintf(out_val, "%3d.%9s %s %s the %s %s, Level %d", place, the_score.pts, seikaku_info[pa].title, the_score.who, race_info[pr].title, class_info[pc].title, clev); #endif /* Append a "maximum level" */ if (mlev > clev) strcat(out_val, format(_(" (最高%d)", " (Max %d)"), mlev)); /* Dump the first line */ c_put_str(attr, out_val, n*4 + 2, 0); /* Another line of info */ #ifdef JP if (mdun != 0) sprintf(out_val, " 最高%3d階", mdun); else sprintf(out_val, " "); /* 死亡原因をオリジナルより細かく表示 */ if (streq(the_score.how, "yet")) { sprintf(out_val+13, " まだ生きている (%d%s)", cdun, "階"); } else if (streq(the_score.how, "ripe")) { sprintf(out_val+13, " 勝利の後に引退 (%d%s)", cdun, "階"); } else if (streq(the_score.how, "Seppuku")) { sprintf(out_val+13, " 勝利の後に切腹 (%d%s)", cdun, "階"); } else { codeconv(the_score.how); /* Some people die outside of the dungeon */ if (!cdun) sprintf(out_val+13, " 地上で%sに殺された", the_score.how); else sprintf(out_val+13, " %d階で%sに殺された", cdun, the_score.how); } #else /* Some people die outside of the dungeon */ if (!cdun) sprintf(out_val, " Killed by %s on the surface", the_score.how); else sprintf(out_val, " Killed by %s on %s %d", the_score.how, "Dungeon Level", cdun); /* Append a "maximum level" */ if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun)); #endif /* Dump the info */ c_put_str(attr, out_val, n*4 + 3, 0); /* And still another line of info */ #ifdef JP { char buf[11]; /* 日付を 19yy/mm/dd の形式に変更する */ if (strlen(when) == 8 && when[2] == '/' && when[5] == '/') { sprintf(buf, "%d%s/%.5s", 19 + (when[6] < '8'), when + 6, when); when = buf; } sprintf(out_val, " (ユーザー:%s, 日付:%s, 所持金:%s, ターン:%s)", user, when, gold, aged); } #else sprintf(out_val, " (User %s, Date %s, Gold %s, Turn %s).", user, when, gold, aged); #endif c_put_str(attr, out_val, n*4 + 4, 0); } /* Wait for response */ prt(_("[ ESCで中断, その他のキーで続けます ]", "[Press ESC to quit, any other key to continue.]"), hgt - 1, _(21, 17)); j = inkey(); prt("", hgt - 1, 0); /* Hack -- notice Escape */ if (j == ESCAPE) break; } }