Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show date and time of savegame in Save/Load menu #1200

Merged
merged 11 commits into from
Apr 23, 2024
32 changes: 24 additions & 8 deletions src/doom/m_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include <stdlib.h>
#include <ctype.h>
#include <time.h> // [crispy] strftime, localtime


#include "doomdef.h"
Expand Down Expand Up @@ -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];

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
Expand Down
38 changes: 30 additions & 8 deletions src/heretic/mn_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <stdlib.h>
#include <ctype.h>
#include <time.h> // [crispy] strftime, localtime

#include "deh_str.h"
#include "doomdef.h"
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
Copy link
Collaborator Author

@JNechaevsky JNechaevsky Apr 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a Right Thing to do in terms of fail-safe, but there is still some potential for improvement. Small example, I'm using British Antigua and Barbuda locale, which is using lowercase for am/pm designation. Unlike Doom, Heretic can't handle lowercase characters, that's why all game strings are always uppercased. In this case, designation can't appear:

image

Possible solution is to forcefully convert lower case chars to uppercase, this will do the trick:

    while ((c = *text++) != 0)
    {
+++        if (c > 96 && c < 123) // means, all ASCII chars "a" ... "z"
+++            c -= 32;           // ... will be reindexed to "A" ... "Z"

But how to properly make this condition friendly with newly introduced || c > 91) and avoid messy maze of conditions, that's a good question. 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this, but needs support for big font (it doesn't have [ symbol (№59) which is a cursor) and probably smarter conditions for indexes checking.

+++ international-doom/src/heretic/mn_menu.c	Wed Apr 24 08:41:20 2024
@@ -4148,6 +4148,24 @@
 //
 //---------------------------------------------------------------------------
 
+static const char MN_CheckValidChar (char ascii_index, int small_font)
+{
+    // Following characters not exising in font graphics, replace with spaces:
+    // \ ] ^ _ { | } ~
+    if ((ascii_index >= 92 && ascii_index <= 96) || ascii_index >= 123)
+    {
+        return 32;
+    }
+    // Force lowercase a...z characters to uppercase A...Z.
+    if (ascii_index >= 97 && ascii_index <= 122)
+    {
+        return ascii_index -= 32;
+    }
+
+    // Valid char, do not modify ASCII index.
+    return ascii_index;
+}
+
 void MN_DrTextA (const char *text, int x, int y, byte *table)
 {
     char c;
@@ -4157,6 +4175,8 void MN_DrTextA (const char *text, int x, int y, byte *table) @@
 
     while ((c = *text++) != 0)
     {
+        c = MN_CheckValidChar(c, 1);
+
         if (c < 33)
         {
             x += 5;

image

This way, even such messy string will work: E1M1: THE \\ {|} ~ dOcKs

{
x += 5;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woke up with a bad feeling, that it can be unsafe since Raven's font set doesn't have a backslash symbol, and attempt to draw non existing symbol is a direct path to program crash. But looks likes it is safe all around, none of existing date formats are using \.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just fix font drawing to skip non-existent character patches.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat idea, even outside of this PR, this can potentially improve compatibility with custom texts. For small font drawing, it should be something like this:

+++ crispy-doom/src/heretic/mn_menu.c	Tue Apr 23 10:24:01 2024
@@ -631,6 +631,10 @@ void MN_DrTextA(const char *text, int x, int y)
         {
             x += 5;
         }
+        else if (c > 91)
+        {
+            continue;
+        }
         else
         {
             p = W_CacheLumpNum(FontABaseLump + c - 33, PU_CACHE);

Why exactly > 91: no font characters available starting from 92, acording to ASCII table. Raven fonts starting from FONTA01, while in ASCII characters it's a 33. Last available lump for small font is FONTA59, so 59 + 33 equals 92.

Hopefully. 🙂 At least this way I no longer have crashes by using \ symbol in text drawing. But probably worth to leave it for separated PR?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Heretic's A-font does only have 59 characters, so everything after 33+59 should be skipped. I would extend the earlier check, though, and just print a blank space.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡! True, patch drawing is guarded by following else condition, so it can be simplified to just

        if (c < 33 || c > 91)
        {
            x += 5;
        }

Worth to do same trick with big font FONTB**, except it have 58 characters, so check should be if (c < 33 || c > 90)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please. And I think it belongs into this bug report, because the time and date string is not under our control.

#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
MN_DrTextA(filedate, ORIGWIDTH / 2 - MN_TextAWidth(pagestr), y + 10);
}

dp_translation = NULL;
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down
42 changes: 33 additions & 9 deletions src/hexen/mn_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// HEADER FILES ------------------------------------------------------------

#include <ctype.h>
#include <time.h> // [crispy] strftime, localtime
#include "h2def.h"
#include "doomkeys.h"
#include "i_input.h"
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down
4 changes: 4 additions & 0 deletions src/i_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h> // [crispy] setlocale

#include "SDL.h"

Expand Down Expand Up @@ -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.
//
Expand Down
Loading