From 4c658f28658ba6781fbda96290bf68cfa42e5d73 Mon Sep 17 00:00:00 2001 From: Julia Nechaevskaya Date: Tue, 23 Apr 2024 14:34:13 +0300 Subject: [PATCH] Show date and time of savegame in Save/Load menu (#1200) * Doom: first working implementation * Use parametrized y coord Co-Authored-By: Fabian Greffrath * Correct comment Better do not remove it, so the purpose of "-15" will be clear. * For Heretic * For Hexen * For Strife (WIP) Working, but needs pixel perfection. * Doom: make M_DrawSaveLoadBottomLine static * For Strife (done) Strife using spaces, not tabs. ;) * Doom: inhelpscreens no longer needed for M_DrawSaveLoadBottomLine Since everything is moved slightly up and no extra file slot is being drawed over status bar, "inhelpscreens" is now redundant. Save date should not appear on status bar, since it's using same Y-coords as KIS stats. Also, this making Save/Load menu slightly less expensive in terms of CPU usage, but fortunately, we are still on capped framerate while active menu. * Remove copy-pasta remaining from ID * Heretic & Hexen: fail-safe conditions for font drawing functions Co-Authored-By: Fabian Greffrath --------- Co-authored-by: Fabian Greffrath --- src/doom/m_menu.c | 32 +++++++++++++++------ src/heretic/mn_menu.c | 38 +++++++++++++++++++------ src/hexen/mn_menu.c | 42 ++++++++++++++++++++++------ src/i_main.c | 4 +++ src/strife/m_menu.c | 65 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 154 insertions(+), 27 deletions(-) diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c index d9fcb93201..601486c5d1 100644 --- a/src/doom/m_menu.c +++ b/src/doom/m_menu.c @@ -20,6 +20,7 @@ #include #include +#include // [crispy] strftime, localtime #include "doomdef.h" @@ -851,15 +852,10 @@ void M_ReadSaveStrings(void) } // [FG] support up to 8 pages of savegames -void M_DrawSaveLoadBottomLine(void) +static void M_DrawSaveLoadBottomLine(void) { char pagestr[16]; - const int y = LoadDef.y+LINEHEIGHT*load_end; - - // [crispy] force status bar refresh - inhelpscreens = true; - - M_DrawSaveLoadBorder(LoadDef.x,y); + const int y = 152; dp_translation = cr[CR_GOLD]; @@ -871,6 +867,26 @@ void M_DrawSaveLoadBottomLine(void) M_snprintf(pagestr, sizeof(pagestr), "page %d/%d", savepage + 1, savepage_max + 1); M_WriteText(ORIGWIDTH/2-M_StringWidth(pagestr)/2, y, pagestr); + // [crispy] print "modified" (or created initially) time of savegame file + if (LoadMenu[itemOn].status) + { + struct stat st; + char filedate[32]; + + stat(P_SaveGameFile(itemOn), &st); + +// [FG] suppress the most useless compiler warning ever +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-y2k" +#endif + strftime(filedate, sizeof(filedate), "%x %X", localtime(&st.st_mtime)); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + M_WriteText(ORIGWIDTH/2-M_StringWidth(filedate)/2, y + 8, filedate); + } + dp_translation = NULL; } @@ -3457,7 +3473,7 @@ void M_Init (void) { LoadDef_y = vstep + captionheight - SHORT(patchl->height) + SHORT(patchl->topoffset); SaveDef_y = vstep + captionheight - SHORT(patchs->height) + SHORT(patchs->topoffset); - LoadDef.y = SaveDef.y = vstep + captionheight + vstep + SHORT(patchm->topoffset) - 7; // [crispy] see M_DrawSaveLoadBorder() + LoadDef.y = SaveDef.y = vstep + captionheight + vstep + SHORT(patchm->topoffset) - 15; // [crispy] moved up, so savegame date/time may appear above status bar MouseDef.y = LoadDef.y; } } diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c index 665e3bb89b..db8101bbb0 100644 --- a/src/heretic/mn_menu.c +++ b/src/heretic/mn_menu.c @@ -18,6 +18,7 @@ #include #include +#include // [crispy] strftime, localtime #include "deh_str.h" #include "doomdef.h" @@ -261,7 +262,7 @@ static MenuItem_t LoadItems[] = { }; static Menu_t LoadMenu = { - 70, 27, + 70, 27-9, // [crispy] moved up, so two lines of save pages and file date will fit DrawLoadMenu, SAVES_PER_PAGE, LoadItems, 0, @@ -278,7 +279,7 @@ static MenuItem_t SaveItems[] = { }; static Menu_t SaveMenu = { - 70, 27, + 70, 27-9, // [crispy] moved up, so two lines of save pages and file date will fit DrawSaveMenu, SAVES_PER_PAGE, SaveItems, 0, @@ -626,7 +627,7 @@ void MN_DrTextA(const char *text, int x, int y) while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 91) // [crispy] fail-safe: draw patches above FONTA59 as spaces { x += 5; } @@ -656,7 +657,7 @@ int MN_TextAWidth(const char *text) width = 0; while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 91) // [crispy] fail-safe: consider patches above FONTA59 as spaces { width += 5; } @@ -684,7 +685,7 @@ void MN_DrTextB(const char *text, int x, int y) while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 90) // [crispy] fail-safe: draw patches above FONTB58 as spaces { x += 8; } @@ -714,7 +715,7 @@ int MN_TextBWidth(const char *text) width = 0; while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 90) // [crispy] fail-safe: consider patches above FONTB58 as spaces { width += 5; } @@ -933,6 +934,25 @@ static void DrawSaveLoadBottomLine(const Menu_t *menu) M_snprintf(pagestr, sizeof(pagestr), "PAGE %d/%d", savepage + 1, SAVEPAGE_MAX + 1); MN_DrTextA(pagestr, ORIGWIDTH / 2 - MN_TextAWidth(pagestr) / 2, y); + // [crispy] print "modified" (or created initially) time of savegame file + if (SlotStatus[CurrentItPos] && !FileMenuKeySteal) + { + struct stat st; + char filedate[32]; + + stat(SV_Filename(CurrentItPos), &st); +// [FG] suppress the most useless compiler warning ever +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-y2k" +#endif + strftime(filedate, sizeof(filedate), "%x %X", localtime(&st.st_mtime)); +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + MN_DrTextA(filedate, ORIGWIDTH / 2 - MN_TextAWidth(pagestr), y + 10); + } + dp_translation = NULL; } @@ -948,12 +968,13 @@ static void DrawLoadMenu(void) title = DEH_String("LOAD GAME"); - MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 7); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&LoadMenu); + // [crispy] moved here, draw title on top of file slots + MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 1); DrawSaveLoadBottomLine(&LoadMenu); } @@ -969,12 +990,13 @@ static void DrawSaveMenu(void) title = DEH_String("SAVE GAME"); - MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 7); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&SaveMenu); + // [crispy] moved here, draw title on top of file slots + MN_DrTextB(title, 160 - MN_TextBWidth(title) / 2, 1); DrawSaveLoadBottomLine(&SaveMenu); } diff --git a/src/hexen/mn_menu.c b/src/hexen/mn_menu.c index b4f2d903bf..9d458084a6 100644 --- a/src/hexen/mn_menu.c +++ b/src/hexen/mn_menu.c @@ -18,6 +18,7 @@ // HEADER FILES ------------------------------------------------------------ #include +#include // [crispy] strftime, localtime #include "h2def.h" #include "doomkeys.h" #include "i_input.h" @@ -263,7 +264,7 @@ static MenuItem_t LoadItems[] = { }; static Menu_t LoadMenu = { - 70, 27, + 70, 27-9, // [crispy] moved up, so two lines of save pages and file date will fit DrawLoadMenu, SAVES_PER_PAGE, LoadItems, 0, @@ -280,7 +281,7 @@ static MenuItem_t SaveItems[] = { }; static Menu_t SaveMenu = { - 70, 27, + 70, 27-9, // [crispy] moved up, so two lines of save pages and file date will fit DrawSaveMenu, SAVES_PER_PAGE, SaveItems, 0, @@ -557,7 +558,7 @@ void MN_DrTextA(const char *text, int x, int y) while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 91) // [crispy] fail-safe: draw patches above FONTA59 as spaces { x += 5; } @@ -583,7 +584,7 @@ void MN_DrTextAYellow(const char *text, int x, int y) while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 91) // [crispy] fail-safe: draw patches above FONTAY59 as spaces { x += 5; } @@ -613,7 +614,7 @@ int MN_TextAWidth(const char *text) width = 0; while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 91) // [crispy] fail-safe: consider patches above FONTA(Y)59 as spaces { width += 5; } @@ -641,7 +642,7 @@ void MN_DrTextB(const char *text, int x, int y) while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 90) // [crispy] fail-safe: draw patches above FONTB58 as spaces { x += 8; } @@ -671,7 +672,7 @@ int MN_TextBWidth(const char *text) width = 0; while ((c = *text++) != 0) { - if (c < 33) + if (c < 33 || c > 90) // [crispy] fail-safe: consider patches above FONTB58 as spaces { width += 5; } @@ -907,6 +908,27 @@ static void DrawSaveLoadBottomLine(const Menu_t *menu) M_snprintf(pagestr, sizeof(pagestr), "PAGE %d/%d", savepage + 1, SAVEPAGE_MAX + 1); MN_DrTextA(pagestr, ORIGWIDTH / 2 - MN_TextAWidth(pagestr) / 2, y); + // [crispy] print "modified" (or created initially) time of savegame file + if (SlotStatus[CurrentItPos] && !FileMenuKeySteal) + { + struct stat st; + char filedate[32]; + char filename[100]; + + M_snprintf(filename, sizeof(filename), "%shex%d.hxs", SavePath, CurrentItPos + (savepage * 10)); + stat(filename, &st); +// [FG] suppress the most useless compiler warning ever +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-y2k" +#endif + strftime(filedate, sizeof(filedate), "%x %X", localtime(&st.st_mtime)); +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + MN_DrTextA(filedate, ORIGWIDTH / 2 - MN_TextAWidth(filedate) / 2, y + 10); + } + dp_translation = NULL; } @@ -918,12 +940,13 @@ static void DrawSaveLoadBottomLine(const Menu_t *menu) static void DrawLoadMenu(void) { - MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 7); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&LoadMenu); + // [crispy] moved here, draw title on top of file slots + MN_DrTextB("LOAD GAME", 160 - MN_TextBWidth("LOAD GAME") / 2, 1); DrawSaveLoadBottomLine(&LoadMenu); } @@ -935,12 +958,13 @@ static void DrawLoadMenu(void) static void DrawSaveMenu(void) { - MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 7); if (!slottextloaded) { MN_LoadSlotText(); } DrawFileSlots(&SaveMenu); + // [crispy] moved here, draw title on top of file slots + MN_DrTextB("SAVE GAME", 160 - MN_TextBWidth("SAVE GAME") / 2, 1); DrawSaveLoadBottomLine(&SaveMenu); } diff --git a/src/i_main.c b/src/i_main.c index e1091d20b5..393721162d 100644 --- a/src/i_main.c +++ b/src/i_main.c @@ -22,6 +22,7 @@ #include #include #include +#include // [crispy] setlocale #include "SDL.h" @@ -52,6 +53,9 @@ int main(int argc, char **argv) myargv[i] = M_StringDuplicate(argv[i]); } + // [crispy] Print date and time in the Load/Save Game menus in the current locale + setlocale(LC_TIME, ""); + //! // Print the program version and exit. // diff --git a/src/strife/m_menu.c b/src/strife/m_menu.c index 29d4385bfe..13676ee503 100644 --- a/src/strife/m_menu.c +++ b/src/strife/m_menu.c @@ -20,6 +20,7 @@ #include #include +#include // [crispy] strftime, localtime #include "doomdef.h" @@ -851,14 +852,40 @@ void M_DoNameChar(int choice) M_ClearMenus(0); } +// [crispy] print "modified" (or created initially) time of savegame file +static void M_DrawSaveLoadBottomLine(void) +{ + const int y = 145; + + if (LoadMenu[itemOn].status) + { + struct stat st; + char filedate[32]; + + stat(P_SaveGameFile(itemOn), &st); + +// [FG] suppress the most useless compiler warning ever +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-y2k" +#endif + strftime(filedate, sizeof(filedate), "%x %X", localtime(&st.st_mtime)); +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + M_WriteText(ORIGWIDTH/2-M_StringWidth(filedate)/2, y, filedate); + } +} + // // M_LoadGame & Cie. // +static int LoadDef_x = 80, LoadDef_y = 54; void M_DrawLoad(void) { int i; - V_DrawPatchDirect(72, 28, + V_DrawPatchDirect(LoadDef_x, LoadDef_y, W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE)); for (i = 0;i < load_end; i++) @@ -866,6 +893,8 @@ void M_DrawLoad(void) M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]); } + + M_DrawSaveLoadBottomLine(); } @@ -935,11 +964,12 @@ void M_LoadGame (int choice) // // M_SaveGame & Cie. // +static int SaveDef_x = 80, SaveDef_y = 54; void M_DrawSave(void) { int i; - V_DrawPatchDirect(72, 28, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE)); + V_DrawPatchDirect(SaveDef_x, SaveDef_y, W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE)); for (i = 0;i < load_end; i++) { M_DrawSaveLoadBorder(LoadDef.x,LoadDef.y+LINEHEIGHT*i); @@ -951,6 +981,8 @@ void M_DrawSave(void) i = M_StringWidth(savegamestrings[quickSaveSlot]); M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*quickSaveSlot,"_"); } + + M_DrawSaveLoadBottomLine(); } // @@ -3150,6 +3182,35 @@ void M_Init (void) G_WriteSaveName(5, "ME"); ClearTmp(); + // [crispy] rearrange Load Game and Save Game menus + { + const patch_t *patchl, *patchs, *patchm; + short captionheight, vstep; + + patchl = W_CacheLumpName(DEH_String("M_LOADG"), PU_CACHE); + patchs = W_CacheLumpName(DEH_String("M_SAVEG"), PU_CACHE); + patchm = W_CacheLumpName(DEH_String("M_LSLEFT"), PU_CACHE); + + LoadDef_x = (ORIGWIDTH - SHORT(patchl->width)) / 2 + SHORT(patchl->leftoffset); + SaveDef_x = (ORIGWIDTH - SHORT(patchs->width)) / 2 + SHORT(patchs->leftoffset); + LoadDef.x = SaveDef.x = (ORIGWIDTH - 24 * 8) / 2 + SHORT(patchm->leftoffset); + + captionheight = MAX(SHORT(patchl->height), SHORT(patchs->height)); + + vstep = ORIGHEIGHT - 32; // [crispy] ST_HEIGHT + vstep -= captionheight; + vstep -= (load_end - 1) * LINEHEIGHT + SHORT(patchm->height); + vstep /= 3; + + if (vstep > 0) + { + LoadDef_y = vstep + captionheight - SHORT(patchl->height) + SHORT(patchl->topoffset); + SaveDef_y = vstep + captionheight - SHORT(patchs->height) + SHORT(patchs->topoffset); + LoadDef.y = SaveDef.y = vstep + captionheight + vstep + SHORT(patchm->topoffset) - 19; // [crispy] moved up, so savegame date/time may appear above status bar + MouseDef.y = LoadDef.y; + } + } + // Here we could catch other version dependencies, // like HELP1/2, and four episodes. }