From 3e36bfd56f79b01535068f61f217cd7464a4a89a Mon Sep 17 00:00:00 2001 From: Dav999-v Date: Sat, 25 Dec 2021 17:13:46 +0100 Subject: [PATCH] Simplify time formatting functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here's my notes on all the existing functions and what kind of time formats they output: - Game::giventimestring(int hrs, int min, int sec) H:MM:SS MM:SS - Game::timestring() // uses game.hours/minutes/seconds H:MM:SS MM:SS - Game::partimestring() // uses game.timetrialpar (seconds) MM:SS - Game::resulttimestring() // uses game.timetrialresulttime (sec) + timetrialresultframes (1/30s) MM:SS.CC - Game::timetstring(int t) // t = seconds MM:SS - Game::timestringcenti(char* buffer, const size_t buffer_size) // uses game.hours/minutes/seconds/frames H:MM:SS.CC MM:SS.CC - UtilityClass::timestring(int t) // t = frames, 30 frames = 1 second S:CC M:SS:CC This is kind of a mess, and there's a lot of functions that do the same thing except using different variables. For localization, I also want translators to be able to localize all these time formats - many languages use the decimal comma instead of the decimal point (12:34,56) maybe some languages really prefer something like 1時02分11秒44瞬... Which I don't know to be correct, but it's good to be prepared for it and not restrict translators arbitrarily to only changing ":" and "." when we can start making the system better in the first place. I added a new function, UtilityClass::format_time. This is the place where all time formats come together, given the number of seconds and optionally frames. I have simplified the above-mentioned functions somewhat, but I haven't given them a complete refactor or renaming - I mainly made sure that they all use the same backend so I can make the formats consistent and properly localizable. (And before we start shoving more temporary char buffers everywhere just to get rid of the std::string's, maybe we need to think of a globally used working buffer of size SCREEN_WIDTH_CHARS+1, as a register of sorts, for when any line of text needs to be made or processed, then printed, and then goes unused. Maybe help.textrow, or something like that.) As for this commit, the available time formats are now more consistent and changed a little in some places. Leading zeroes for the first unit are now no longer included, time trial results and the Super Gravitron can now display hours when they went to 60 minutes before, and we now always use .CC instead of :CC. These are the formats: - H:MM:SS - H:MM:SS.CC - M:SS - M:SS.CC - S.CC (only used when always_minutes=false, for the Gravitrons) Here's what changes to the current functions: - Game::partimestring() is removed - it was used in two places, and could be replaced by game.timetstring(game.timetrialpar) - Game::giventimestring(h,m,s) and Game::timestring() are now wrappers for the other functions - The four remaining functions (Game::resulttimestring(), Game::timetstring(t), Game::timestringcenti(buffer, buffer_size) and UtilityClass::timestring(t)) are now wrappers for the "central function", UtilityClass::format_time. - UtilityClass::twodigits(int t) is now unused so it's also removed. - I also added int UtilityClass::hms_to_seconds(int h, int m, int s) --- desktop_version/src/Game.cpp | 80 ++++++---------------------- desktop_version/src/Game.h | 2 - desktop_version/src/Render.cpp | 8 +-- desktop_version/src/UtilityClass.cpp | 55 +++++++++++-------- desktop_version/src/UtilityClass.h | 4 +- 5 files changed, 56 insertions(+), 93 deletions(-) diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 92100071..c7b5c0d7 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -1412,7 +1412,7 @@ void Game::updatestate(void) obj.removetrigger(82); hascontrol = false; - timetrialresulttime = seconds + (minutes * 60) + (hours * 60 * 60); + timetrialresulttime = help.hms_to_seconds(hours, minutes, seconds); timetrialresultframes = frames; timetrialresulttrinkets = trinkets(); timetrialresultshinytarget = timetrialshinytarget; @@ -2605,13 +2605,16 @@ void Game::updatestate(void) graphics.textboxcenterx(); break; case 3502: + { state++; statedelay = 45+15; graphics.createtextboxflipme(" All Crew Members Rescued! ", -1, 64, 0, 0, 0); - savetime = timestring(); - savetime += "." + help.twodigits(frames*100 / 30); + char buffer[SCREEN_WIDTH_CHARS + 1]; + timestringcenti(buffer, sizeof(buffer)); + savetime = buffer; break; + } case 3503: { state++; @@ -5748,86 +5751,33 @@ void Game::gameclock(void) std::string Game::giventimestring( int hrs, int min, int sec ) { - std::string tempstring = ""; - if (hrs > 0) - { - tempstring += help.String(hrs) + ":"; - } - tempstring += help.twodigits(min) + ":" + help.twodigits(sec); - return tempstring; + return timetstring(help.hms_to_seconds(hrs, min, sec)); } std::string Game::timestring(void) { - std::string tempstring = ""; - if (hours > 0) - { - tempstring += help.String(hours) + ":"; - } - tempstring += help.twodigits(minutes) + ":" + help.twodigits(seconds); - return tempstring; -} - -std::string Game::partimestring(void) -{ - //given par time in seconds: - std::string tempstring = ""; - if (timetrialpar >= 60) - { - tempstring = help.twodigits(timetrialpar / 60) + ":" + help.twodigits(timetrialpar % 60); - } - else - { - tempstring = "00:" + help.twodigits(timetrialpar); - } - return tempstring; + return giventimestring(hours, minutes, seconds); } std::string Game::resulttimestring(void) { //given result time in seconds: - std::string tempstring = ""; - if (timetrialresulttime >= 60) - { - tempstring = help.twodigits(timetrialresulttime / 60) + ":" - + help.twodigits(timetrialresulttime % 60); - } - else - { - tempstring = "00:" + help.twodigits(timetrialresulttime); - } - tempstring += "." + help.twodigits(timetrialresultframes*100 / 30); - return tempstring; + char output[SCREEN_WIDTH_CHARS + 1]; + help.format_time(output, sizeof(output), timetrialresulttime, timetrialresultframes, true); + return output; } std::string Game::timetstring( int t ) { //given par time in seconds: - std::string tempstring = ""; - if (t >= 60) - { - tempstring = help.twodigits(t / 60) + ":" + help.twodigits(t % 60); - } - else - { - tempstring = "00:" + help.twodigits(t); - } - return tempstring; + char output[SCREEN_WIDTH_CHARS + 1]; + help.format_time(output, sizeof(output), t, -1, true); + return output; } void Game::timestringcenti(char* buffer, const size_t buffer_size) { - /* 16 chars should be plenty for int32s */ - char hours_str[16] = {'\0'}; - if (hours > 0) - { - SDL_snprintf(hours_str, sizeof(hours_str), "%i:", hours); - } - SDL_snprintf( - buffer, buffer_size, - "%s%02i:%02i.%02i", - hours_str, minutes, seconds, frames * 100 / 30 - ); + help.format_time(buffer, buffer_size, help.hms_to_seconds(hours, minutes, seconds), frames, true); } void Game::returnmenu(void) diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index dad68415..9d2d4c9d 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -139,8 +139,6 @@ public: std::string timestring(void); - std::string partimestring(void); - std::string resulttimestring(void); std::string timetstring(int t); diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index b00b5422..de4a8a20 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -1708,7 +1708,7 @@ void gamerender(void) if (graphics.fademode==0 && !game.intimetrial && !game.isingamecompletescreen() && (!game.swnmode || game.swngame != 1) && game.showingametimer) { - char buffer[SCREEN_WIDTH_TILES + 1]; /* ASCII only */ + char buffer[SCREEN_WIDTH_CHARS + 1]; graphics.bprint(6, 6, "TIME:", 255,255,255); game.timestringcenti(buffer, sizeof(buffer)); graphics.bprint(46, 6, buffer, 196, 196, 196); @@ -1918,7 +1918,7 @@ void gamerender(void) } else { - char buffer[SCREEN_WIDTH_TILES + 1]; /* ASCII only */ + char buffer[SCREEN_WIDTH_CHARS + 1]; game.timestringcenti(buffer, sizeof(buffer)); //Draw OSD stuff @@ -1954,12 +1954,12 @@ void gamerender(void) if(game.timetrialparlost) { graphics.bprint(195, 214, "PAR TIME:", 80, 80, 80); - graphics.bprint(275, 214, game.partimestring(), 80, 80, 80); + graphics.bprint(275, 214, game.timetstring(game.timetrialpar), 80, 80, 80); } else { graphics.bprint(195, 214, "PAR TIME:", 255, 255, 255); - graphics.bprint(275, 214, game.partimestring(), 196, 196, 196); + graphics.bprint(275, 214, game.timetstring(game.timetrialpar), 196, 196, 196); } } } diff --git a/desktop_version/src/UtilityClass.cpp b/desktop_version/src/UtilityClass.cpp index ec2fda32..c03cde5c 100644 --- a/desktop_version/src/UtilityClass.cpp +++ b/desktop_version/src/UtilityClass.cpp @@ -4,6 +4,7 @@ #include #include +#include "Constants.h" #include "Maths.h" static const char* GCChar(const SDL_GameControllerButton button) @@ -168,37 +169,49 @@ std::string UtilityClass::GCString(const std::vector& return retval; } -std::string UtilityClass::twodigits( int t ) +int UtilityClass::hms_to_seconds(int h, int m, int s) { - if (t < 10) + return h*3600 + m*60 + s; +} + +void UtilityClass::format_time(char* buffer, const size_t buffer_size, int seconds, int frames, bool always_minutes) +{ + int s = seconds % 60; + int m = (seconds / 60) % 60; + int h = seconds / 3600; + + if (h > 0) { - return "0" + String(t); + /* H:MM:SS / H:MM:SS.CC */ + SDL_snprintf(buffer, buffer_size, + frames == -1 ? "%d:%02d:%02d" : "%d:%02d:%02d.%02d", + h, m, s, frames * 100 / 30 + ); } - if (t >= 100) + else if (m > 0 || always_minutes || frames == -1) { - return "??"; + /* M:SS / M:SS.CC */ + SDL_snprintf(buffer, buffer_size, + frames == -1 ? "%d:%02d" : "%d:%02d.%02d", + m, s, frames * 100 / 30 + ); + } + else + { + /* S.CC */ + SDL_snprintf(buffer, buffer_size, + "%d.%02d", + s, frames * 100 / 30 + ); } - return String(t); } std::string UtilityClass::timestring( int t ) { //given a time t in frames, return a time in seconds - std::string tempstring = ""; - int temp = t / 30; - if (temp < 60) //less than one minute - { - t = t % 30; - tempstring = String(temp) + ":" + twodigits(t * 100 / 30); - } - else - { - int temp2 = temp / 60; - temp = temp % 60; - t = t % 30; - tempstring = String(temp2) + ":" + twodigits(temp) + ":" + twodigits(t * 100 / 30); - } - return tempstring; + char output[SCREEN_WIDTH_CHARS + 1]; + format_time(output, sizeof(output), t / 30, t % 30, false); + return output; } std::string UtilityClass::number_words( int _t ) diff --git a/desktop_version/src/UtilityClass.h b/desktop_version/src/UtilityClass.h index 50f33043..6d11d1f6 100644 --- a/desktop_version/src/UtilityClass.h +++ b/desktop_version/src/UtilityClass.h @@ -95,7 +95,9 @@ public: static std::string GCString(const std::vector& buttons); - std::string twodigits(int t); + int hms_to_seconds(int h, int m, int s); + + void format_time(char* buffer, const size_t buffer_size, int seconds, int frames, bool always_minutes); std::string timestring(int t);