From 5e75c63e7b3cf40d5f3ea1348df90c36bea6e5e6 Mon Sep 17 00:00:00 2001 From: Leo Prikler Date: Tue, 23 Feb 2021 11:37:23 +0100 Subject: [PATCH] beatmap: implement advanced scoring system. Early and late hits are now only awared a third of a point, just like in osu! --- include/beatmap/beatmap.h | 6 ++++++ include/ui/score.h | 3 +-- lib/beatmap/helpers.cc | 33 +++++++++++++++++++++++++++++++++ lib/game/tty.cc | 25 ++++++++----------------- lib/ui/score.cc | 16 +++------------- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/include/beatmap/beatmap.h b/include/beatmap/beatmap.h index e552009..9844c36 100644 --- a/include/beatmap/beatmap.h +++ b/include/beatmap/beatmap.h @@ -946,6 +946,12 @@ int load_beatmap_headers(const char *path, oshu::beatmap *beatmap); */ void destroy_beatmap(oshu::beatmap *beatmap); +/** + * Return a numeric value between 0 (no hits) and 1 (perfect) based on the + * player's hit/miss ratio. + */ +double score(oshu::beatmap *beatmap); + /** \} */ } diff --git a/include/ui/score.h b/include/ui/score.h index b907e02..ce476ec 100644 --- a/include/ui/score.h +++ b/include/ui/score.h @@ -26,8 +26,7 @@ struct display; struct score_frame { oshu::display *display; oshu::beatmap *beatmap; - int good; - int bad; + double score; }; /** diff --git a/lib/beatmap/helpers.cc b/lib/beatmap/helpers.cc index dc9185a..8e17739 100644 --- a/lib/beatmap/helpers.cc +++ b/lib/beatmap/helpers.cc @@ -7,6 +7,8 @@ */ #include "beatmap/beatmap.h" +#include +#include double oshu::hit_end_time(oshu::hit *hit) { @@ -23,3 +25,34 @@ oshu::point oshu::end_point(oshu::hit *hit) else return hit->p; } + +double oshu::score(oshu::beatmap *beatmap) +{ + double score = 0, total = 0; + auto leniency = beatmap->difficulty.leniency; + + for (oshu::hit *hit = beatmap->hits; hit; hit = hit->next) { + switch (hit->state) { + case oshu::GOOD_HIT: + if (hit->offset < - leniency / 2) + score += 1.0/3; + else if (hit->offset > leniency / 2) + score += 1.0/3; + else + score += 1.0; + [[fallthrough]]; + case oshu::MISSED_HIT: + ++total; + break; + } + } + + score /= total; + if (total == 0) { + if (!std::isnan(score)) + score = std::numeric_limits::quiet_NaN(); + } + else + assert ((0 <= score) && (score <= 1)); + return score; +} diff --git a/lib/game/tty.cc b/lib/game/tty.cc index 6f1ba20..34952bc 100644 --- a/lib/game/tty.cc +++ b/lib/game/tty.cc @@ -74,22 +74,13 @@ void oshu::congratulate(oshu::game_base *game) { /* Clear the status line. */ printf("\r \r"); - /* Compute the score. */ - int good = 0; - int missed = 0; - for (oshu::hit *hit = game->beatmap.hits; hit; hit = hit->next) { - if (hit->state == oshu::MISSED_HIT) - missed++; - else if (hit->state == oshu::GOOD_HIT) - good++; - } - double rate = (double) good / (good + missed); + double score = oshu::score(&game->beatmap); + if (std::isnan(score)) return; + + int score_color = 0; + if (score >= 0.9) score_color = 32; + else if (score < 0.5) score_color = 31; printf( - " \033[1mScore:\033[0m\n" - " \033[%dm%3d\033[0m good\n" - " \033[%dm%3d\033[0m miss\n" - "\n", - rate >= 0.9 ? 32 : 0, good, - rate < 0.5 ? 31 : 0, missed - ); + " \033[1mScore: \033[%dm%3.2f\033[0m%%\n\n", + score_color, score * 100); } diff --git a/lib/ui/score.cc b/lib/ui/score.cc index ace2124..25ca5f0 100644 --- a/lib/ui/score.cc +++ b/lib/ui/score.cc @@ -17,23 +17,13 @@ int oshu::create_score_frame(oshu::display *display, oshu::beatmap *beatmap, osh memset(frame, 0, sizeof(*frame)); frame->display = display; frame->beatmap = beatmap; - - for (oshu::hit *hit = beatmap->hits; hit; hit = hit->next) { - if (hit->state == oshu::MISSED_HIT) - ++frame->bad; - else if (hit->state == oshu::GOOD_HIT) - ++frame->good; - } - + frame->score = oshu::score(beatmap); return 0; } void oshu::show_score_frame(oshu::score_frame *frame, double opacity) { - int notes = frame->good + frame->bad; - if (notes == 0) - return; - + if (std::isnan(frame->score)) return; SDL_SetRenderDrawBlendMode(frame->display->renderer, SDL_BLENDMODE_BLEND); SDL_Rect bar = { @@ -46,7 +36,7 @@ void oshu::show_score_frame(oshu::score_frame *frame, double opacity) SDL_Rect good = { .x = bar.x, .y = bar.y, - .w = (int) ((double) frame->good / notes * bar.w), + .w = (int) ((double) frame->score * bar.w), .h = bar.h, }; SDL_SetRenderDrawColor(frame->display->renderer, 0, 255, 0, 196 * opacity);