mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-23 03:52:12 -04:00
add snapshots to savegames (#741)
* add snapshots to savegames * WIP * revert debugging aid * clean up * replace strncpy() with memcpy() We *are* going to truncate before the terminating NUL. This isn't a string, it's an indicator for the following snapshot data. * fix initializer to be compile time constant * limit maximum snapshot size * array length should be const * show savegame modification time below snapshots * suppress the most useless compiler warning ever * restrict warning suppression to GCC, sigh * use M_stat() in M_ReadSavegameTime()
This commit is contained in:
parent
21f0b0e754
commit
c815ac2102
@ -50,6 +50,7 @@ set(WOOF_SOURCES
|
||||
m_misc.c m_misc.h
|
||||
m_misc2.c m_misc2.h
|
||||
m_random.c m_random.h
|
||||
m_snapshot.c m_snapshot.h
|
||||
m_swap.h
|
||||
memio.c memio.h
|
||||
midifile.c midifile.h
|
||||
|
@ -65,6 +65,7 @@
|
||||
#include "u_mapinfo.h"
|
||||
#include "m_input.h"
|
||||
#include "memio.h"
|
||||
#include "m_snapshot.h"
|
||||
|
||||
#define SAVEGAMESIZE 0x20000
|
||||
#define SAVESTRINGSIZE 24
|
||||
@ -1909,6 +1910,11 @@ static void G_DoSaveGame(void)
|
||||
CheckSaveGame(sizeof extrakills);
|
||||
saveg_write32(extrakills);
|
||||
|
||||
// [FG] save snapshot
|
||||
CheckSaveGame(M_SnapshotDataSize());
|
||||
M_WriteSnapshot(save_p);
|
||||
save_p += M_SnapshotDataSize();
|
||||
|
||||
length = save_p - savebuffer;
|
||||
|
||||
if (!M_WriteFile(name, savebuffer, length))
|
||||
|
@ -201,6 +201,7 @@ int M_stat(const char *path, struct stat *buf)
|
||||
// incompatible with struct stat*. We copy only the required compatible
|
||||
// field.
|
||||
buf->st_mode = wbuf.st_mode;
|
||||
buf->st_mtime = wbuf.st_mtime;
|
||||
|
||||
free(wpath);
|
||||
|
||||
|
94
src/m_menu.c
94
src/m_menu.c
@ -61,6 +61,7 @@
|
||||
#include "r_sky.h" // [FG] R_InitSkyMap()
|
||||
#include "r_plane.h" // [FG] R_InitPlanes()
|
||||
#include "m_argv.h"
|
||||
#include "m_snapshot.h"
|
||||
|
||||
// [crispy] remove DOS reference from the game quit confirmation dialogs
|
||||
#include "SDL_platform.h"
|
||||
@ -145,6 +146,8 @@ boolean menuactive; // The menus are up
|
||||
#define M_THRM_STEP 6
|
||||
#define M_THRM_WIDTH (M_THRM_STEP * (M_THRM_SIZE + 2))
|
||||
#define M_X_THRM (M_X - M_THRM_WIDTH)
|
||||
#define M_X_LOADSAVE 80
|
||||
#define M_LOADSAVE_WIDTH (24 * 8 + 8) // [FG] c.f. M_DrawSaveLoadBorder()
|
||||
|
||||
#define DISABLE_ITEM(condition, item) \
|
||||
((condition) ? (item.m_flags |= S_DISABLE) : (item.m_flags &= ~S_DISABLE))
|
||||
@ -797,12 +800,78 @@ menu_t LoadDef =
|
||||
&MainDef,
|
||||
LoadMenu,
|
||||
M_DrawLoad,
|
||||
80,34, //jff 3/15/98 move menu up
|
||||
M_X_LOADSAVE,34, //jff 3/15/98 move menu up
|
||||
0
|
||||
};
|
||||
|
||||
#define LOADGRAPHIC_Y 8
|
||||
|
||||
// [FG] draw a snapshot of the n'th savegame into a separate window,
|
||||
// or fill window with solid color and "n/a" if snapshot not available
|
||||
|
||||
static int snapshot_width, snapshot_height;
|
||||
|
||||
static void M_DrawBorderedSnapshot (int n)
|
||||
{
|
||||
int x, y;
|
||||
patch_t *patch;
|
||||
char *txt;
|
||||
|
||||
const int snapshot_x = MAX((WIDESCREENDELTA + SaveDef.x + SKULLXOFF - snapshot_width) / 2, 8);
|
||||
const int snapshot_y = LoadDef.y + MAX((load_end * LINEHEIGHT - snapshot_height) * n / load_end, 0);
|
||||
|
||||
// [FG] a snapshot window smaller than 80*48 px is considered too small
|
||||
if (snapshot_width < ORIGWIDTH/4)
|
||||
return;
|
||||
|
||||
if (!M_DrawSnapshot(n, snapshot_x, snapshot_y, snapshot_width, snapshot_height))
|
||||
{
|
||||
txt = "n/a";
|
||||
M_WriteText(snapshot_x + snapshot_width/2 - M_StringWidth(txt)/2 - WIDESCREENDELTA,
|
||||
snapshot_y + snapshot_height/2 - M_StringHeight(txt)/2,
|
||||
txt);
|
||||
}
|
||||
|
||||
txt = M_GetSavegameTime(n);
|
||||
M_DrawString(snapshot_x + snapshot_width/2 - M_GetPixelWidth(txt)/2 - WIDESCREENDELTA,
|
||||
snapshot_y + snapshot_height + M_StringHeight(txt),
|
||||
CR_GOLD, txt);
|
||||
|
||||
// [FG] draw the view border around the snapshot
|
||||
|
||||
patch = W_CacheLumpName("brdr_t", PU_CACHE);
|
||||
for (x = 0; x < snapshot_width; x += 8)
|
||||
V_DrawPatch(snapshot_x + x - WIDESCREENDELTA, snapshot_y - 8, 0, patch);
|
||||
|
||||
patch = W_CacheLumpName("brdr_b", PU_CACHE);
|
||||
for (x = 0; x < snapshot_width; x += 8)
|
||||
V_DrawPatch(snapshot_x + x - WIDESCREENDELTA, snapshot_y + snapshot_height, 0, patch);
|
||||
|
||||
patch = W_CacheLumpName("brdr_l", PU_CACHE);
|
||||
for (y = 0; y < snapshot_height; y += 8)
|
||||
V_DrawPatch(snapshot_x - 8 - WIDESCREENDELTA, snapshot_y + y, 0, patch);
|
||||
|
||||
patch = W_CacheLumpName("brdr_r", PU_CACHE);
|
||||
for (y = 0; y < snapshot_height; y += 8)
|
||||
V_DrawPatch(snapshot_x + snapshot_width - WIDESCREENDELTA, snapshot_y + y, 0, patch);
|
||||
|
||||
V_DrawPatch(snapshot_x - 8 - WIDESCREENDELTA,
|
||||
snapshot_y - 8,
|
||||
0, W_CacheLumpName("brdr_tl", PU_CACHE));
|
||||
|
||||
V_DrawPatch(snapshot_x + snapshot_width - WIDESCREENDELTA,
|
||||
snapshot_y - 8,
|
||||
0, W_CacheLumpName("brdr_tr", PU_CACHE));
|
||||
|
||||
V_DrawPatch(snapshot_x - 8 - WIDESCREENDELTA,
|
||||
snapshot_y + snapshot_height,
|
||||
0, W_CacheLumpName("brdr_bl", PU_CACHE));
|
||||
|
||||
V_DrawPatch(snapshot_x + snapshot_width - WIDESCREENDELTA,
|
||||
snapshot_y + snapshot_height,
|
||||
0, W_CacheLumpName("brdr_br", PU_CACHE));
|
||||
}
|
||||
|
||||
// [FG] delete a savegame
|
||||
|
||||
static boolean delete_verify = false;
|
||||
@ -839,7 +908,7 @@ void M_DrawSaveLoadBottomLine(void)
|
||||
M_DrawString(LoadDef.x+(SAVESTRINGSIZE-2)*8, y, CR_GOLD, "->");
|
||||
|
||||
M_snprintf(pagestr, sizeof(pagestr), "page %d/%d", savepage + 1, savepage_max + 1);
|
||||
M_DrawString(ORIGWIDTH/2-M_StringWidth(pagestr)/2, y, CR_GOLD, pagestr);
|
||||
M_DrawString(LoadDef.x+M_LOADSAVE_WIDTH/2-M_StringWidth(pagestr)/2, y, CR_GOLD, pagestr);
|
||||
}
|
||||
|
||||
//
|
||||
@ -858,6 +927,8 @@ void M_DrawLoad(void)
|
||||
M_WriteText(LoadDef.x,LoadDef.y+LINEHEIGHT*i,savegamestrings[i]);
|
||||
}
|
||||
|
||||
M_DrawBorderedSnapshot(itemOn);
|
||||
|
||||
M_DrawSaveLoadBottomLine();
|
||||
|
||||
if (delete_verify)
|
||||
@ -983,7 +1054,7 @@ menu_t SaveDef =
|
||||
&MainDef,
|
||||
SaveMenu,
|
||||
M_DrawSave,
|
||||
80,34, //jff 3/15/98 move menu up
|
||||
M_X_LOADSAVE,34, //jff 3/15/98 move menu up
|
||||
0
|
||||
};
|
||||
|
||||
@ -995,14 +1066,25 @@ void M_ReadSaveStrings(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// [FG] shift savegame descriptions a bit to the right
|
||||
// to make room for the snapshots on the left
|
||||
SaveDef.x = LoadDef.x = M_X_LOADSAVE + MIN(M_LOADSAVE_WIDTH/2, WIDESCREENDELTA);
|
||||
|
||||
// [FG] fit the snapshots into the resulting space
|
||||
snapshot_width = MIN((WIDESCREENDELTA + SaveDef.x + 2 * SKULLXOFF) & ~7, ORIGWIDTH/2); // [FG] multiple of 8
|
||||
snapshot_height = MIN((snapshot_width * ORIGHEIGHT / ORIGWIDTH) & ~7, ORIGHEIGHT/2);
|
||||
|
||||
for (i = 0 ; i < load_end ; i++)
|
||||
{
|
||||
FILE *fp; // killough 11/98: change to use stdio
|
||||
|
||||
char *name = G_SaveGameName(i); // killough 3/22/98
|
||||
fp = M_fopen(name,"rb");
|
||||
M_ReadSavegameTime(i, name);
|
||||
if (name) free(name);
|
||||
|
||||
M_ResetSnapshot(i);
|
||||
|
||||
if (!fp)
|
||||
{ // Ty 03/27/98 - externalized:
|
||||
name = G_MBFSaveGameName(i);
|
||||
@ -1022,6 +1104,10 @@ void M_ReadSaveStrings(void)
|
||||
LoadMenu[i].status = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!M_ReadSnapshot(i, fp))
|
||||
M_ResetSnapshot(i);
|
||||
|
||||
fclose(fp);
|
||||
LoadMenu[i].status = 1;
|
||||
}
|
||||
@ -1048,6 +1134,8 @@ void M_DrawSave(void)
|
||||
M_WriteText(LoadDef.x + i,LoadDef.y+LINEHEIGHT*saveSlot,"_");
|
||||
}
|
||||
|
||||
M_DrawBorderedSnapshot(itemOn);
|
||||
|
||||
M_DrawSaveLoadBottomLine();
|
||||
|
||||
if (delete_verify)
|
||||
|
180
src/m_snapshot.c
Normal file
180
src/m_snapshot.c
Normal file
@ -0,0 +1,180 @@
|
||||
//
|
||||
// Copyright (C) 2022 Fabian Greffrath
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Savegame snapshots
|
||||
//
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
#include "i_video.h"
|
||||
#include "m_io.h"
|
||||
#include "v_video.h"
|
||||
|
||||
static const char snapshot_str[] = "WOOF_SNAPSHOT";
|
||||
static const int snapshot_len = arrlen(snapshot_str);
|
||||
static const int snapshot_size = ORIGWIDTH * ORIGHEIGHT;
|
||||
|
||||
static byte *snapshots[10];
|
||||
static byte *current_snapshot;
|
||||
static char savegametimes[10][32];
|
||||
|
||||
const int M_SnapshotDataSize (void)
|
||||
{
|
||||
return snapshot_len + snapshot_size;
|
||||
}
|
||||
|
||||
void M_ResetSnapshot (int i)
|
||||
{
|
||||
if (snapshots[i])
|
||||
{
|
||||
free(snapshots[i]);
|
||||
snapshots[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// [FG] try to read snapshot data from the end of a savegame file
|
||||
|
||||
boolean M_ReadSnapshot (int i, FILE *fp)
|
||||
{
|
||||
char str[16] = {0};
|
||||
|
||||
M_ResetSnapshot (i);
|
||||
|
||||
if (fseek(fp, -M_SnapshotDataSize(), SEEK_END) != 0)
|
||||
return false;
|
||||
|
||||
if (fread(str, 1, snapshot_len, fp) != snapshot_len)
|
||||
return false;
|
||||
|
||||
if (strncasecmp(str, snapshot_str, snapshot_len) != 0)
|
||||
return false;
|
||||
|
||||
if ((snapshots[i] = malloc(snapshot_size * sizeof(**snapshots))) == NULL)
|
||||
return false;
|
||||
|
||||
if (fread(snapshots[i], 1, snapshot_size, fp) != snapshot_size)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void M_ReadSavegameTime (int i, char *name)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (M_stat(name, &st) == -1)
|
||||
savegametimes[i][0] = '\0';
|
||||
else
|
||||
// [FG] suppress the most useless compiler warning ever
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-y2k"
|
||||
#endif
|
||||
strftime(savegametimes[i], sizeof(savegametimes[i]), "%x %X", localtime(&st.st_mtime));
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
char *M_GetSavegameTime (int i)
|
||||
{
|
||||
return savegametimes[i];
|
||||
}
|
||||
|
||||
// [FG] take a snapshot in ORIGWIDTH*ORIGHEIGHT resolution, i.e.
|
||||
// in hires mode only only each second pixel in each second row is saved,
|
||||
// in widescreen mode only the non-widescreen part in the middle is saved
|
||||
|
||||
static void M_TakeSnapshot (void)
|
||||
{
|
||||
const int inc = hires ? 2 : 1;
|
||||
int x, y;
|
||||
byte *p;
|
||||
const byte *s = screens[0];
|
||||
|
||||
if (!current_snapshot)
|
||||
{
|
||||
current_snapshot = malloc(snapshot_size * sizeof(**snapshots));
|
||||
}
|
||||
p = current_snapshot;
|
||||
|
||||
for (y = 0; y < (SCREENHEIGHT << hires); y += inc)
|
||||
{
|
||||
for (x = 0; x < (NONWIDEWIDTH << hires); x += inc)
|
||||
{
|
||||
*p++ = s[y * (SCREENWIDTH << hires) + (WIDESCREENDELTA << hires) + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void M_WriteSnapshot (byte *p)
|
||||
{
|
||||
M_TakeSnapshot();
|
||||
|
||||
memcpy(p, snapshot_str, snapshot_len);
|
||||
p += snapshot_len;
|
||||
|
||||
memcpy(p, current_snapshot, snapshot_size);
|
||||
p += snapshot_size;
|
||||
}
|
||||
|
||||
// [FG] draw snapshot for the n'th savegame, if no snapshot is found
|
||||
// fill the area with palette index 0 (i.e. mostly black)
|
||||
|
||||
boolean M_DrawSnapshot (int n, int x, int y, int w, int h)
|
||||
{
|
||||
byte *dest = screens[0] + y * (SCREENWIDTH << (2 * hires)) + (x << hires);
|
||||
|
||||
if (!snapshots[n])
|
||||
{
|
||||
int desty;
|
||||
|
||||
for (desty = 0; desty < (h << hires); desty++)
|
||||
{
|
||||
memset(dest, 0, w << hires);
|
||||
dest += SCREENWIDTH << hires;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const fixed_t step_x = (ORIGWIDTH << FRACBITS) / (w << hires);
|
||||
const fixed_t step_y = (ORIGHEIGHT << FRACBITS) / (h << hires);
|
||||
int destx, desty;
|
||||
fixed_t srcx, srcy;
|
||||
byte *destline, *srcline;
|
||||
|
||||
for (desty = 0, srcy = 0; desty < (h << hires); desty++, srcy += step_y)
|
||||
{
|
||||
destline = dest + desty * (SCREENWIDTH << hires);
|
||||
srcline = snapshots[n] + (srcy >> FRACBITS) * ORIGWIDTH;
|
||||
|
||||
for (destx = 0, srcx = 0; destx < (w << hires); destx++, srcx += step_x)
|
||||
{
|
||||
*destline++ = srcline[srcx >> FRACBITS];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
35
src/m_snapshot.h
Normal file
35
src/m_snapshot.h
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Copyright (C) 2022 Fabian Greffrath
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// Savegame snapshots
|
||||
//
|
||||
|
||||
#ifndef __M_SNAPSHOT__
|
||||
#define __M_SNAPSHOT__
|
||||
|
||||
const int M_SnapshotDataSize (void);
|
||||
void M_ResetSnapshot (int i);
|
||||
boolean M_ReadSnapshot (int i, FILE *fp);
|
||||
void M_WriteSnapshot (byte *p);
|
||||
boolean M_DrawSnapshot (int i, int x, int y, int w, int h);
|
||||
|
||||
void M_ReadSavegameTime (int i, char *name);
|
||||
char *M_GetSavegameTime (int i);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user