From 27877afc2acf735e54ef8b768683de7c1da108ae Mon Sep 17 00:00:00 2001 From: Andrei Drexler Date: Sun, 24 Dec 2023 23:47:16 +0100 Subject: [PATCH] Offer to load autosave if present after selecting a map from the Levels menu or double-clicking it in Explorer --- Quake/common.c | 37 +++++++++++++++++++++++++++++++++++++ Quake/common.h | 5 ++++- Quake/host_cmd.c | 4 ++-- Quake/menu.c | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/Quake/common.c b/Quake/common.c index 78f4af4fa..dd74723db 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -1720,6 +1720,43 @@ char *COM_TempSuffix (unsigned seq) return buf; } +/* +============ +COM_DescribeDuration + +Describes the given duration, e.g. "3 minutes" +============ +*/ +void COM_DescribeDuration (char *out, size_t outsize, double seconds) +{ + const double SECOND = 1; + const double MINUTE = 60 * SECOND; + const double HOUR = 60 * MINUTE; + const double DAY = 24 * HOUR; + const double WEEK = 7 * DAY; + const double MONTH = 30.436875 * DAY; + const double YEAR = 365.2425 * DAY; + + seconds = fabs (seconds); + + if (seconds < 1) + q_strlcpy (out, "moments", outsize); + else if (seconds < 60 * SECOND) + q_snprintf (out, outsize, "%i second%s", PLURAL (seconds)); + else if (seconds < 90 * MINUTE) + q_snprintf (out, outsize, "%i minute%s", PLURAL (seconds / MINUTE)); + else if (seconds < DAY) + q_snprintf (out, outsize, "%i hour%s", PLURAL (seconds / HOUR)); + else if (seconds < WEEK) + q_snprintf (out, outsize, "%i day%s", PLURAL (seconds / DAY)); + else if (seconds < MONTH) + q_snprintf (out, outsize, "%i week%s", PLURAL (seconds / WEEK)); + else if (seconds < YEAR) + q_snprintf (out, outsize, "%i month%s", PLURAL (seconds / MONTH)); + else + q_snprintf (out, outsize, "%i year%s", PLURAL (seconds / YEAR)); +} + /* ============ COM_CreatePath diff --git a/Quake/common.h b/Quake/common.h index 2dea37d4a..fb65c1e1d 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -263,7 +263,7 @@ extern char *q_strupr (char *str); extern int q_snprintf (char *str, size_t size, const char *format, ...) FUNC_PRINTF(3,4); extern int q_vsnprintf(char *str, size_t size, const char *format, va_list args) FUNC_PRINTF(3,0); -#define PLURAL(count) (&"s"[(count)==1]) +#define PLURAL(count) ((int)(count)), (&"s"[((int)(count))==1]) //============================================================================ @@ -312,6 +312,9 @@ void COM_ExtractExtension (const char *in, char *out, size_t outsize); char *COM_TempSuffix (unsigned seq); void COM_CreatePath (char *path); +// Describes the given duration, e.g. "3 minutes" +void COM_DescribeDuration (char *out, size_t outsize, double seconds); + char *va (const char *format, ...) FUNC_PRINTF(1,2); // does a varargs printf into a temp buffer diff --git a/Quake/host_cmd.c b/Quake/host_cmd.c index 8cee9a643..b441a21ba 100644 --- a/Quake/host_cmd.c +++ b/Quake/host_cmd.c @@ -797,8 +797,8 @@ static void Modlist_RegisterAddons (void *param) "Add-on server status:\n" "%3d add-on%s available for download\n" "%3d add-on%s already installed\n\n", - total - installed, PLURAL (total - installed), - installed, PLURAL (installed) + PLURAL (total - installed), + PLURAL (installed) ); extramods_json = json; diff --git a/Quake/menu.c b/Quake/menu.c index 96496221c..eaac42d28 100644 --- a/Quake/menu.c +++ b/Quake/menu.c @@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "bgmusic.h" #include "q_ctype.h" +#include + cvar_t ui_mouse = {"ui_mouse", "1", CVAR_ARCHIVE}; cvar_t ui_mouse_sound = {"ui_mouse_sound", "0", CVAR_ARCHIVE}; cvar_t ui_sound_throttle = {"ui_sound_throttle", "0.1", CVAR_ARCHIVE}; @@ -2002,6 +2004,43 @@ void M_SetSkillMenuMap (const char *name) void M_Menu_Skill_f (void) { + char autosave[MAX_OSPATH]; + + // If there's an autosave, offer to resume it instead of starting over + q_snprintf (autosave, sizeof (autosave), "%s/autosave/%s.sav", com_gamedir, m_skill_mapname); + if (Sys_FileExists (autosave)) + { + char message[256]; + time_t now, lastplayed; + + time (&now); + if (Sys_GetFileTime (autosave, &lastplayed) && lastplayed <= now) + { + char duration[32]; + COM_DescribeDuration (duration, sizeof (duration), difftime (lastplayed, now)); + q_snprintf (message, sizeof (message), + "Load last autosave\n" + "from %s ago?\n" + "\n" + "(y/n)\n", + duration + ); + } + else + { + q_snprintf (message, sizeof (message), "Load last autosave? (y/n)\n"); + } + + if (SCR_ModalMessage (message, 0.0f)) + { + m_state = m_none; + key_dest = key_game; + Cbuf_AddText (va ("load \"autosave/%s\"\n", m_skill_mapname)); + return; + } + } + + // Show skill selection menu IN_DeactivateForMenu(); key_dest = key_menu; m_skill_prevmenu = m_state;