diff --git a/ball/level.h b/ball/level.h index 33a00c34f..dfbbbbc3c 100644 --- a/ball/level.h +++ b/ball/level.h @@ -13,6 +13,12 @@ enum SCORE_COIN }; +struct stats { + int completed; + int timeout; + int fallout; +}; + #define LEVEL_LOCKED 0x1 #define LEVEL_COMPLETED 0x2 @@ -32,6 +38,7 @@ struct level int goal; /* Coins needed */ struct score scores[3]; + struct stats stats; /* Set information. */ diff --git a/ball/progress.c b/ball/progress.c index aa7eb0598..98a20772e 100644 --- a/ball/progress.c +++ b/ball/progress.c @@ -157,7 +157,7 @@ void progress_step(void) void progress_stat(int s) { - int i, dirty = 0; + int i; status = s; @@ -178,15 +178,16 @@ void progress_stat(int s) curr.score += coins; curr.times += timer; - dirty = level_score_update(level, timer, coins, + level_score_update(level, timer, coins, &time_rank, goal == 0 ? &goal_rank : NULL, &coin_rank); + level->stats.completed++; + if (!level_completed(level)) { level_complete(level); - dirty = 1; } /* Compute next level. */ @@ -200,7 +201,6 @@ void progress_stat(int s) if (!level_opened(next)) { level_open(next); - dirty = 1; } } } @@ -217,7 +217,6 @@ void progress_stat(int s) if (next) { level_open(next); - dirty = 1; } else done = mode == MODE_CHALLENGE; @@ -236,11 +235,12 @@ void progress_stat(int s) curr.times += timer; curr.balls -= 1; + status == GAME_FALL ? level->stats.fallout++ : level->stats.timeout++; + break; } - if (dirty && mode != MODE_STANDALONE) - set_store_hs(); + set_store_hs(); demo_play_stat(status, coins, timer); } diff --git a/ball/set.c b/ball/set.c index 93c034fb1..1df4ba301 100644 --- a/ball/set.c +++ b/ball/set.c @@ -123,6 +123,9 @@ void set_store_hs(void) fs_printf(fp, "level %d %d %s\n", flags, l->version_num, l->file); + fs_printf(fp, "stats %d %d %d\n", l->stats.completed, + l->stats.timeout, l->stats.fallout); + put_score(fp, &l->scores[SCORE_TIME]); put_score(fp, &l->scores[SCORE_GOAL]); put_score(fp, &l->scores[SCORE_COIN]); @@ -173,6 +176,28 @@ static struct level *find_level(const struct set *s, const char *file) return NULL; } +static void get_stats(fs_file fp, struct level *l) +{ + char line[MAXSTR]; + + if (!fs_gets(line, sizeof(line), fp)) + return; + + strip_newline(line); + + if (sscanf(line, "stats %d %d %d", &l->stats.completed, + &l->stats.timeout, + &l->stats.fallout) < 3) { + /* compatible with save files without stats info */ + l->stats.completed = 0; + l->stats.timeout = 0; + l->stats.fallout = 0; + + /* stats not available, rewind file pointer */ + fs_seek(fp, - strlen(line) - 1, SEEK_CUR); + } +} + static void set_load_hs_v2(fs_file fp, struct set *s, char *buf, int size) { struct score time_score; @@ -202,6 +227,7 @@ static void set_load_hs_v2(fs_file fp, struct set *s, char *buf, int size) if ((l = find_level(s, buf + n))) { + get_stats(fp, l); /* Always prefer "locked" flag from the score file. */ l->is_locked = !!(flags & LEVEL_LOCKED); diff --git a/ball/st_goal.c b/ball/st_goal.c index 1e609a9f9..89fa1c508 100644 --- a/ball/st_goal.c +++ b/ball/st_goal.c @@ -228,6 +228,8 @@ static int goal_gui(void) } + gui_set_stats(curr_level()); + set_score_board(level_score(curr_level(), SCORE_COIN), progress_coin_rank(), level_score(curr_level(), SCORE_TIME), progress_time_rank(), level_score(curr_level(), SCORE_GOAL), progress_goal_rank()); diff --git a/ball/st_start.c b/ball/st_start.c index 2d7828cfd..4c30f868d 100644 --- a/ball/st_start.c +++ b/ball/st_start.c @@ -85,6 +85,8 @@ static void start_over_level(int i) { gui_set_image(shot_id, level_shot(l)); + gui_set_stats(l); + set_score_board(level_score(l, SCORE_COIN), -1, level_score(l, SCORE_TIME), -1, level_score(l, SCORE_GOAL), -1); diff --git a/ball/util.c b/ball/util.c index ac3ffd07d..b7cffc225 100644 --- a/ball/util.c +++ b/ball/util.c @@ -57,6 +57,12 @@ static int score_coin[4]; static int score_name[4]; static int score_time[4]; +struct { + int completed; + int timeout; + int fallout; +} stats_labels; + static int score_extra_row; /* Build a top three score list with default values. */ @@ -110,6 +116,24 @@ static void gui_scores(int id, int e) } } +static void gui_stats(int id) +{ + int at; + + if ((at = gui_vstack(id))) + { + gui_filler(at); + gui_label(at, _("Stats"), GUI_SML, 0, 0); + + stats_labels.completed = gui_label(at, " ", GUI_SML, gui_grn, gui_wht); + stats_labels.timeout = gui_label(at, " ", GUI_SML, gui_yel, gui_wht); + stats_labels.fallout = gui_label(at, " ", GUI_SML, gui_red, gui_wht); + + gui_set_rect(at, GUI_ALL); + gui_filler(at); + } +} + /* Set the top three score list values. */ static void gui_set_scores(const char *label, const struct score *s, int hilite) @@ -214,6 +238,8 @@ void gui_score_board(int pd, unsigned int types, int e, int h) gui_scores(id, e); + gui_stats(id); + gui_filler(id); } } @@ -256,6 +282,17 @@ int gui_score_get(void) return score_type; } +void gui_set_stats(const struct level *l) +{ + char buffer[10]; + sprintf(buffer, "%d", l->stats.completed); + gui_set_label(stats_labels.completed, buffer); + sprintf(buffer, "%d", l->stats.timeout); + gui_set_label(stats_labels.timeout, buffer); + sprintf(buffer, "%d", l->stats.fallout); + gui_set_label(stats_labels.fallout, buffer); +} + /*---------------------------------------------------------------------------*/ static int lock = 1; diff --git a/ball/util.h b/ball/util.h index 4bf52f387..f6dac5435 100644 --- a/ball/util.h +++ b/ball/util.h @@ -19,6 +19,8 @@ void gui_score_set(int); int gui_score_get(void); +void gui_set_stats(const struct level *); + void gui_score_board(int, unsigned int, int, int); void set_score_board(const struct score *, int, const struct score *, int,