Add auto save feature (#1939)

* Add auto save menu item

* Allow appending to default save name

* Add saving auto save

* Add loading auto save

* Add auto save slot to load game menu

* Fix rect x-offset

* Enable by default
This commit is contained in:
ceski 2024-10-03 18:07:22 -07:00 committed by GitHub
parent ed349ec34e
commit 9a43e5494b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 570 additions and 152 deletions

View File

@ -78,6 +78,8 @@ typedef enum
ga_worlddone, ga_worlddone,
ga_screenshot, ga_screenshot,
ga_reloadlevel, ga_reloadlevel,
ga_loadautosave,
ga_saveautosave,
} gameaction_t; } gameaction_t;

View File

@ -23,6 +23,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <time.h> #include <time.h>
#include "am_map.h" #include "am_map.h"
@ -212,6 +213,9 @@ boolean joybuttons[NUM_GAMEPAD_BUTTONS];
int savegameslot = -1; int savegameslot = -1;
char savedescription[32]; char savedescription[32];
static boolean save_autosave;
static boolean autosave;
//jff 3/24/98 declare startskill external, define defaultskill here //jff 3/24/98 declare startskill external, define defaultskill here
int default_skill; //note 1-based int default_skill; //note 1-based
@ -1961,6 +1965,11 @@ static void G_DoWorldDone(void)
gameaction = ga_nothing; gameaction = ga_nothing;
viewactive = true; viewactive = true;
AM_clearMarks(); //jff 4/12/98 clear any marks on the automap AM_clearMarks(); //jff 4/12/98 clear any marks on the automap
if (autosave && !demorecording && !demoplayback && !netgame)
{
M_SaveAutoSave();
}
} }
// killough 2/28/98: A ridiculously large number // killough 2/28/98: A ridiculously large number
@ -2268,6 +2277,12 @@ static char *savename = NULL;
static boolean forced_loadgame = false; static boolean forced_loadgame = false;
static boolean command_loadgame = false; static boolean command_loadgame = false;
void G_ForcedLoadAutoSave(void)
{
gameaction = ga_loadautosave;
forced_loadgame = true;
}
void G_ForcedLoadGame(void) void G_ForcedLoadGame(void)
{ {
gameaction = ga_loadgame; gameaction = ga_loadgame;
@ -2277,6 +2292,15 @@ void G_ForcedLoadGame(void)
// killough 3/16/98: add slot info // killough 3/16/98: add slot info
// killough 5/15/98: add command-line // killough 5/15/98: add command-line
void G_LoadAutoSave(char *name)
{
free(savename);
savename = M_StringDuplicate(name);
gameaction = ga_loadautosave;
forced_loadgame = false;
command_loadgame = false;
}
void G_LoadGame(char *name, int slot, boolean command) void G_LoadGame(char *name, int slot, boolean command)
{ {
if (savename) free(savename); if (savename) free(savename);
@ -2290,6 +2314,12 @@ void G_LoadGame(char *name, int slot, boolean command)
// killough 5/15/98: // killough 5/15/98:
// Consistency Error when attempting to load savegame. // Consistency Error when attempting to load savegame.
static void G_LoadAutoSaveErr(const char *msg)
{
Z_Free(savebuffer);
MN_ForcedLoadAutoSave(msg);
}
static void G_LoadGameErr(const char *msg) static void G_LoadGameErr(const char *msg)
{ {
Z_Free(savebuffer); // Free the savegame buffer Z_Free(savebuffer); // Free the savegame buffer
@ -2308,6 +2338,12 @@ static void G_LoadGameErr(const char *msg)
// Description is a 24 byte text string // Description is a 24 byte text string
// //
void G_SaveAutoSave(char *description)
{
strcpy(savedescription, description);
save_autosave = true;
}
void G_SaveGame(int slot, char *description) void G_SaveGame(int slot, char *description)
{ {
savegameslot = slot; savegameslot = slot;
@ -2330,13 +2366,8 @@ void CheckSaveGame(size_t size)
// [FG] support up to 8 pages of savegames // [FG] support up to 8 pages of savegames
char* G_SaveGameName(int slot) static char *SaveGameName(const char *buf)
{ {
// Ty 05/04/98 - use savegamename variable (see d_deh.c)
// killough 12/98: add .7 to truncate savegamename
char buf[16] = {0};
sprintf(buf, "%.7s%d.dsg", savegamename, 10*savepage+slot);
char *filepath = M_StringJoin(basesavegame, DIR_SEPARATOR_S, buf); char *filepath = M_StringJoin(basesavegame, DIR_SEPARATOR_S, buf);
char *existing = M_FileCaseExists(filepath); char *existing = M_FileCaseExists(filepath);
@ -2353,6 +2384,20 @@ char* G_SaveGameName(int slot)
} }
} }
char *G_AutoSaveName(void)
{
return SaveGameName("autosave.dsg");
}
char *G_SaveGameName(int slot)
{
// Ty 05/04/98 - use savegamename variable (see d_deh.c)
// killough 12/98: add .7 to truncate savegamename
char buf[16] = {0};
sprintf(buf, "%.7s%d.dsg", savegamename, 10 * savepage + slot);
return SaveGameName(buf);
}
char* G_MBFSaveGameName(int slot) char* G_MBFSaveGameName(int slot)
{ {
char buf[16] = {0}; char buf[16] = {0};
@ -2397,15 +2442,12 @@ static uint64_t G_Signature(int sig_epi, int sig_map)
return s; return s;
} }
static void G_DoSaveGame(void) static void DoSaveGame(char *name)
{ {
char *name = NULL;
char name2[VERSIONSIZE]; char name2[VERSIONSIZE];
char *description; char *description;
int length, i; int length, i;
name = G_SaveGameName(savegameslot);
description = savedescription; description = savedescription;
save_p = savebuffer = Z_Malloc(savegamesize, PU_STATIC, 0); save_p = savebuffer = Z_Malloc(savegamesize, PU_STATIC, 0);
@ -2511,11 +2553,22 @@ static void G_DoSaveGame(void)
if (name) free(name); if (name) free(name);
MN_SetQuickSaveSlot(savegameslot);
drs_skip_frame = true; drs_skip_frame = true;
} }
static void G_DoSaveGame(void)
{
char *name = G_SaveGameName(savegameslot);
DoSaveGame(name);
MN_SetQuickSaveSlot(savegameslot);
}
static void G_DoSaveAutoSave(void)
{
char *name = G_AutoSaveName();
DoSaveGame(name);
}
static void CheckSaveVersion(const char *str, saveg_compat_t ver) static void CheckSaveVersion(const char *str, saveg_compat_t ver)
{ {
if (strncmp((char *) save_p, str, strlen(str)) == 0) if (strncmp((char *) save_p, str, strlen(str)) == 0)
@ -2524,7 +2577,7 @@ static void CheckSaveVersion(const char *str, saveg_compat_t ver)
} }
} }
static void G_DoLoadGame(void) static boolean DoLoadGame(boolean do_load_autosave)
{ {
int length, i; int length, i;
char vcheck[VERSIONSIZE]; char vcheck[VERSIONSIZE];
@ -2562,8 +2615,12 @@ static void G_DoLoadGame(void)
// killough 2/22/98: Friendly savegame version difference message // killough 2/22/98: Friendly savegame version difference message
if (!forced_loadgame && saveg_compat != saveg_mbf && saveg_compat < saveg_woof600) if (!forced_loadgame && saveg_compat != saveg_mbf && saveg_compat < saveg_woof600)
{ {
G_LoadGameErr("Different Savegame Version!!!\n\nAre you sure?"); const char *msg = "Different Savegame Version!!!\n\nAre you sure?";
return; if (do_load_autosave)
G_LoadAutoSaveErr(msg);
else
G_LoadGameErr(msg);
return false;
} }
save_p += VERSIONSIZE; save_p += VERSIONSIZE;
@ -2595,9 +2652,12 @@ static void G_DoLoadGame(void)
if (save_p[sizeof checksum]) if (save_p[sizeof checksum])
strcat(strcat(msg,"Wads expected:\n\n"), (char *) save_p); strcat(strcat(msg,"Wads expected:\n\n"), (char *) save_p);
strcat(msg, "\nAre you sure?"); strcat(msg, "\nAre you sure?");
if (do_load_autosave)
G_LoadAutoSaveErr(msg);
else
G_LoadGameErr(msg); G_LoadGameErr(msg);
free(msg); free(msg);
return; return false;
} }
} }
@ -2723,15 +2783,86 @@ static void G_DoLoadGame(void)
if (demorecording) // So this can only possibly be a -recordfrom command. if (demorecording) // So this can only possibly be a -recordfrom command.
G_BeginRecording();// Start the -recordfrom, since the game was loaded. G_BeginRecording();// Start the -recordfrom, since the game was loaded.
I_Printf(VB_INFO, "G_DoLoadGame: Slot %02d, Time ", 10 * savepage + savegameslot); return true;
}
static void PrintLevelTimes(void)
{
if (totalleveltimes) if (totalleveltimes)
I_Printf(VB_INFO, "(%d:%02d) ", ((totalleveltimes + leveltime) / TICRATE) / 60, {
I_Printf(VB_INFO, "(%d:%02d) ",
((totalleveltimes + leveltime) / TICRATE) / 60,
((totalleveltimes + leveltime) / TICRATE) % 60); ((totalleveltimes + leveltime) / TICRATE) % 60);
}
I_Printf(VB_INFO, "%d:%05.2f", leveltime / TICRATE / 60, I_Printf(VB_INFO, "%d:%05.2f", leveltime / TICRATE / 60,
(float)(leveltime % (60 * TICRATE)) / TICRATE); (float)(leveltime % (60 * TICRATE)) / TICRATE);
}
static void G_DoLoadGame(void)
{
if (DoLoadGame(false))
{
const int slot_num = 10 * savepage + savegameslot;
I_Printf(VB_INFO, "G_DoLoadGame: Slot %02d, Time ", slot_num);
PrintLevelTimes();
MN_SetQuickSaveSlot(savegameslot); MN_SetQuickSaveSlot(savegameslot);
}
}
static void G_DoLoadAutoSave(void)
{
if (DoLoadGame(true))
{
I_Printf(VB_INFO, "G_DoLoadGame: Auto Save, Time ");
PrintLevelTimes();
}
}
boolean G_AutoSaveEnabled(void)
{
return autosave;
}
//
// G_LoadAutoSaveDeathUse
// Loads the auto save if it's more recent than the current save slot.
// Returns true if the auto save is loaded.
//
boolean G_LoadAutoSaveDeathUse(void)
{
struct stat st;
char *auto_path = G_AutoSaveName();
time_t auto_time = (M_stat(auto_path, &st) != -1 ? st.st_mtime : 0);
boolean result = (auto_time > 0);
if (result)
{
if (savegameslot >= 0)
{
char *save_path = G_SaveGameName(savegameslot);
time_t save_time = (M_stat(save_path, &st) != -1 ? st.st_mtime : 0);
free(save_path);
result = (auto_time > save_time);
}
if (result)
{
G_LoadAutoSave(auto_path);
}
}
free(auto_path);
return result;
}
static void CheckSaveAutoSave(void)
{
if (save_autosave)
{
save_autosave = false;
gameaction = ga_saveautosave;
}
} }
boolean clean_screenshot; boolean clean_screenshot;
@ -2812,11 +2943,19 @@ void G_Ticker(void)
case ga_reloadlevel: case ga_reloadlevel:
G_ReloadLevel(); G_ReloadLevel();
break; break;
case ga_loadautosave:
G_DoLoadAutoSave();
break;
case ga_saveautosave:
G_DoSaveAutoSave();
break;
default: // killough 9/29/98 default: // killough 9/29/98
gameaction = ga_nothing; gameaction = ga_nothing;
break; break;
} }
CheckSaveAutoSave();
// killough 10/6/98: allow games to be saved during demo // killough 10/6/98: allow games to be saved during demo
// playback, by the playback user (not by demo itself) // playback, by the playback user (not by demo itself)
@ -4674,6 +4813,8 @@ void G_BindGameVariables(void)
"Maximum number of player corpses (< 0 = No limit)"); "Maximum number of player corpses (< 0 = No limit)");
BIND_NUM_GENERAL(death_use_action, 0, 0, 2, BIND_NUM_GENERAL(death_use_action, 0, 0, 2,
"Use-button action upon death (0 = Default; 1 = Load save; 2 = Nothing)"); "Use-button action upon death (0 = Default; 1 = Load save; 2 = Nothing)");
BIND_BOOL_GENERAL(autosave, true,
"Auto save at the beginning of a map, after completing the previous one.");
} }
void G_BindEnemVariables(void) void G_BindEnemVariables(void)

View File

@ -46,9 +46,14 @@ void G_DeathMatchSpawnPlayer(int playernum);
void G_InitNew(skill_t skill, int episode, int map); void G_InitNew(skill_t skill, int episode, int map);
void G_DeferedInitNew(skill_t skill, int episode, int map); void G_DeferedInitNew(skill_t skill, int episode, int map);
void G_DeferedPlayDemo(char *demo); void G_DeferedPlayDemo(char *demo);
void G_LoadAutoSave(char *name);
void G_LoadGame(char *name, int slot, boolean is_command); // killough 5/15/98 void G_LoadGame(char *name, int slot, boolean is_command); // killough 5/15/98
void G_ForcedLoadAutoSave(void);
void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames void G_ForcedLoadGame(void); // killough 5/15/98: forced loadgames
void G_SaveAutoSave(char *description);
void G_SaveGame(int slot, char *description); // Called by M_Responder. void G_SaveGame(int slot, char *description); // Called by M_Responder.
boolean G_AutoSaveEnabled(void);
boolean G_LoadAutoSaveDeathUse(void);
void G_RecordDemo(char *name); // Only called by startup code. void G_RecordDemo(char *name); // Only called by startup code.
void G_BeginRecording(void); void G_BeginRecording(void);
void G_PlayDemo(char *name); void G_PlayDemo(char *name);
@ -58,6 +63,7 @@ void G_WorldDone(void);
void G_Ticker(void); void G_Ticker(void);
void G_ScreenShot(void); void G_ScreenShot(void);
void G_ReloadDefaults(boolean keep_demover); // killough 3/1/98: loads game defaults void G_ReloadDefaults(boolean keep_demover); // killough 3/1/98: loads game defaults
char *G_AutoSaveName(void);
char *G_SaveGameName(int); // killough 3/22/98: sets savegame filename char *G_SaveGameName(int); // killough 3/22/98: sets savegame filename
char *G_MBFSaveGameName(int); // MBF savegame filename char *G_MBFSaveGameName(int); // MBF savegame filename
void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters void G_SetFastParms(int); // killough 4/10/98: sets -fast parameters

View File

@ -117,8 +117,13 @@ backdrop_t menu_backdrop;
#define M_X_LOADSAVE 80 #define M_X_LOADSAVE 80
#define M_Y_LOADSAVE 34 #define M_Y_LOADSAVE 34
#define M_Y_AUTOSAVE 26
#define M_LOADSAVE_WIDTH (24 * 8 + 8) // [FG] c.f. M_DrawSaveLoadBorder() #define M_LOADSAVE_WIDTH (24 * 8 + 8) // [FG] c.f. M_DrawSaveLoadBorder()
#define LOADGRAPHIC_Y 8
#define AUTOGRAPHIC_Y 2
static int loadsave_title_y = LOADGRAPHIC_Y;
static char savegamestrings[10][SAVESTRINGSIZE]; static char savegamestrings[10][SAVESTRINGSIZE];
// [FG] support up to 8 pages of savegames // [FG] support up to 8 pages of savegames
@ -181,7 +186,7 @@ short whichSkull; // which skull to draw (he blinks)
char skullName[2][/*8*/ 9] = {"M_SKULL1", "M_SKULL2"}; char skullName[2][/*8*/ 9] = {"M_SKULL1", "M_SKULL2"};
static menu_t SaveDef, LoadDef; static menu_t SaveDef, LoadDef, LoadAutoSaveDef;
static menu_t *currentMenu; // current menudef static menu_t *currentMenu; // current menudef
// end of externs added for setup menus // end of externs added for setup menus
@ -206,6 +211,7 @@ static void M_MusicVol(int choice);
static void M_FinishReadThis(int choice); static void M_FinishReadThis(int choice);
static void M_FinishHelp(int choice); // killough 10/98 static void M_FinishHelp(int choice); // killough 10/98
static void M_LoadAutoSaveSelect(int choice);
static void M_LoadSelect(int choice); static void M_LoadSelect(int choice);
static void M_SaveSelect(int choice); static void M_SaveSelect(int choice);
static void M_ReadSaveStrings(void); static void M_ReadSaveStrings(void);
@ -732,8 +738,15 @@ enum
load_end load_end
} load_e; } load_e;
#define SAVE_LOAD_RECT_Y(m_y, n) ((m_y) + (n) * LINEHEIGHT - 7)
#define SAVE_LOAD_RECT(n) \ #define SAVE_LOAD_RECT(n) \
{M_X_LOADSAVE, M_Y_LOADSAVE + (n) * LINEHEIGHT - 7, M_LOADSAVE_WIDTH, LINEHEIGHT} {M_X_LOADSAVE, SAVE_LOAD_RECT_Y(M_Y_LOADSAVE, n), M_LOADSAVE_WIDTH, \
LINEHEIGHT}
#define AUTO_SAVE_RECT(n) \
{M_X_LOADSAVE, SAVE_LOAD_RECT_Y(M_Y_AUTOSAVE, n), M_LOADSAVE_WIDTH, \
LINEHEIGHT}
// The definitions of the Load Game screen // The definitions of the Load Game screen
@ -761,39 +774,76 @@ static menu_t LoadDef =
0 0
}; };
#define LOADGRAPHIC_Y 8 enum
{
autosave_page = load_end,
autosave_end
} autosave_e;
static menuitem_t LoadAutoSaveMenu[] = {
// Auto save slot.
{1, "", M_LoadAutoSaveSelect, 'a', NULL, AUTO_SAVE_RECT(0)},
// Regular save slots.
{1, "", M_LoadSelect, '1', NULL, AUTO_SAVE_RECT(1)},
{1, "", M_LoadSelect, '2', NULL, AUTO_SAVE_RECT(2)},
{1, "", M_LoadSelect, '3', NULL, AUTO_SAVE_RECT(3)},
{1, "", M_LoadSelect, '4', NULL, AUTO_SAVE_RECT(4)},
{1, "", M_LoadSelect, '5', NULL, AUTO_SAVE_RECT(5)},
{1, "", M_LoadSelect, '6', NULL, AUTO_SAVE_RECT(6)},
{1, "", M_LoadSelect, '7', NULL, AUTO_SAVE_RECT(7)},
{1, "", M_LoadSelect, '8', NULL, AUTO_SAVE_RECT(8)},
// Save page navigation.
{-1, "", NULL, 0, NULL, AUTO_SAVE_RECT(9), MF_PAGE}
};
static menu_t LoadAutoSaveDef =
{
autosave_end,
&MainDef,
LoadAutoSaveMenu,
M_DrawLoad,
M_X_LOADSAVE,
M_Y_AUTOSAVE,
};
// [FG] draw a snapshot of the n'th savegame into a separate window, // [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 // or fill window with solid color and "n/a" if snapshot not available
static int snapshot_width, snapshot_height; static int snapshot_width, snapshot_height;
static void M_DrawBorderedSnapshot(int n) static void M_DrawBorderedSnapshot(int slot)
{ {
const char *txt = "n/a";
const int snapshot_x =
MAX(video.deltaw + SaveDef.x + SKULLXOFF - snapshot_width - 8, 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 // [FG] a snapshot window smaller than 80*48 px is considered too small
if (snapshot_width < SCREENWIDTH / 4) if (snapshot_width < SCREENWIDTH / 4)
{ {
return; return;
} }
if (!MN_DrawSnapshot(n, snapshot_x, snapshot_y, snapshot_width, const int x =
snapshot_height)) video.deltaw + currentMenu->x + SKULLXOFF - snapshot_width - 8;
const int y = (currentMenu->numitems * LINEHEIGHT - snapshot_height) * slot
/ currentMenu->numitems;
const int snapshot_x = MAX(8, x);
const int snapshot_y = currentMenu->y + MAX(0, y);
const boolean draw_shot = MN_DrawSnapshot(slot, snapshot_x, snapshot_y,
snapshot_width, snapshot_height);
const boolean is_autosave = (currentMenu == &LoadAutoSaveDef && slot == 0);
const char *txt;
if (!draw_shot || is_autosave)
{ {
txt = (is_autosave ? "Auto Save" : "N/A");
WriteText(snapshot_x + (snapshot_width - MN_StringWidth(txt)) / 2 WriteText(snapshot_x + (snapshot_width - MN_StringWidth(txt)) / 2
- video.deltaw, - video.deltaw,
snapshot_y + snapshot_height / 2 - MN_StringHeight(txt) / 2, snapshot_y + snapshot_height / 2 - MN_StringHeight(txt) / 2,
txt); txt);
} }
txt = MN_GetSavegameTime(n); txt = MN_GetSavegameTime(slot);
MN_DrawString(snapshot_x + snapshot_width / 2 - MN_GetPixelWidth(txt) / 2 MN_DrawString(snapshot_x + snapshot_width / 2 - MN_GetPixelWidth(txt) / 2
- video.deltaw, - video.deltaw,
snapshot_y + snapshot_height + MN_StringHeight(txt), CR_GOLD, snapshot_y + snapshot_height + MN_StringHeight(txt), CR_GOLD,
@ -807,26 +857,49 @@ static void M_DrawBorderedSnapshot(int n)
static boolean delete_verify = false; static boolean delete_verify = false;
static void M_DeleteGame(int i) static void DeleteAutoSave(void)
{ {
char *name = G_SaveGameName(i); char *name = G_AutoSaveName();
M_remove(name); M_remove(name);
free(name);
}
if (i == quickSaveSlot) static void DeleteSaveGame(int slot)
{
char *name = G_SaveGameName(slot);
M_remove(name);
free(name);
if (slot == quickSaveSlot)
{ {
quickSaveSlot = -1; quickSaveSlot = -1;
} }
if (i == savegameslot) if (slot == savegameslot)
{ {
savegameslot = -1; savegameslot = -1;
} }
}
M_ReadSaveStrings(); static void M_DeleteGame(int choice)
{
int slot = choice;
if (name) if (currentMenu == &LoadAutoSaveDef)
{ {
free(name); if (slot == 0)
{
DeleteAutoSave();
}
else
{
slot--;
DeleteSaveGame(slot);
}
}
else
{
DeleteSaveGame(slot);
} }
} }
@ -834,7 +907,8 @@ static void M_DeleteGame(int i)
static void M_DrawSaveLoadBottomLine(void) static void M_DrawSaveLoadBottomLine(void)
{ {
char pagestr[16]; char pagestr[16];
const int y = LoadDef.y + LINEHEIGHT * load_page; const int x = currentMenu->x;
const int y = currentMenu->y + LINEHEIGHT * (currentMenu->numitems - 1);
// [crispy] force status bar refresh // [crispy] force status bar refresh
inhelpscreens = true; inhelpscreens = true;
@ -844,21 +918,38 @@ static void M_DrawSaveLoadBottomLine(void)
int flags = currentMenu->menuitems[index].flags; int flags = currentMenu->menuitems[index].flags;
byte *cr = (flags & MF_PAGE) ? cr_bright : NULL; byte *cr = (flags & MF_PAGE) ? cr_bright : NULL;
M_DrawSaveLoadBorder(LoadDef.x, y, cr); M_DrawSaveLoadBorder(x, y, cr);
if (savepage > 0) if (savepage > 0)
{ {
MN_DrawString(LoadDef.x, y, CR_GOLD, "<-"); MN_DrawString(x, y, CR_GOLD, "<-");
} }
if (savepage < savepage_max) if (savepage < savepage_max)
{ {
MN_DrawString(LoadDef.x + (SAVESTRINGSIZE - 2) * 8, y, CR_GOLD, "->"); MN_DrawString(x + (SAVESTRINGSIZE - 2) * 8, y, CR_GOLD, "->");
} }
M_snprintf(pagestr, sizeof(pagestr), "page %d/%d", savepage + 1, M_snprintf(pagestr, sizeof(pagestr), "page %d/%d", savepage + 1,
savepage_max + 1); savepage_max + 1);
MN_DrawString(LoadDef.x + M_LOADSAVE_WIDTH / 2 - MN_StringWidth(pagestr) / 2, MN_DrawString(x + M_LOADSAVE_WIDTH / 2 - MN_StringWidth(pagestr) / 2, y,
y, CR_GOLD, pagestr); CR_GOLD, pagestr);
}
static void M_DrawSaveLoadBorders(void)
{
const int num_slots = currentMenu->numitems - 1;
const int x = currentMenu->x;
for (int i = 0; i < num_slots; i++)
{
const int y = currentMenu->y + LINEHEIGHT * i;
const menuitem_t *item = &currentMenu->menuitems[i];
byte *cr = (item->flags & MF_HILITE) ? cr_bright : NULL;
M_DrawSaveLoadBorder(x, y, cr);
WriteText(x, y, savegamestrings[i]);
}
} }
// //
@ -867,22 +958,13 @@ static void M_DrawSaveLoadBottomLine(void)
static void M_DrawLoad(void) static void M_DrawLoad(void)
{ {
int i;
// jff 3/15/98 use symbolic load position // jff 3/15/98 use symbolic load position
MN_DrawTitle(72, LOADGRAPHIC_Y, "M_LOADG", "Load Game"); MN_DrawTitle(M_X_CENTER, loadsave_title_y, "M_LOADG", "Load Game");
for (i = 0; i < load_page; i++) M_DrawSaveLoadBorders();
{
menuitem_t *item = &currentMenu->menuitems[i];
byte *cr = (item->flags & MF_HILITE) ? cr_bright : NULL;
M_DrawSaveLoadBorder(LoadDef.x, LoadDef.y + LINEHEIGHT * i, cr);
WriteText(LoadDef.x, LoadDef.y + LINEHEIGHT * i, savegamestrings[i]);
}
int index = (menu_input == mouse_mode ? highlight_item : itemOn); int index = (menu_input == mouse_mode ? highlight_item : itemOn);
if (index < load_page) if (index < currentMenu->numitems - 1)
{ {
M_DrawBorderedSnapshot(index); M_DrawBorderedSnapshot(index);
} }
@ -913,12 +995,28 @@ static void M_DrawSaveLoadBorder(int x, int y, byte *cr)
// User wants to load this game // User wants to load this game
// //
static void M_LoadAutoSaveSelect(int choice)
{
saveg_compat = saveg_woof510;
char *name = G_AutoSaveName();
G_LoadAutoSave(name);
free(name);
MN_ClearMenus();
// Auto save slot doesn't exist for save menu, so don't change lastOn.
//SaveDef.lastOn = choice;
}
static void M_LoadSelect(int choice) static void M_LoadSelect(int choice)
{ {
char *name = NULL; // killough 3/22/98 char *name = NULL; // killough 3/22/98
int slot = choice;
name = G_SaveGameName(choice); if (currentMenu == &LoadAutoSaveDef)
{
slot--;
}
name = G_SaveGameName(slot);
saveg_compat = saveg_woof510; saveg_compat = saveg_woof510;
if (M_access(name, F_OK) != 0) if (M_access(name, F_OK) != 0)
@ -927,11 +1025,11 @@ static void M_LoadSelect(int choice)
{ {
free(name); free(name);
} }
name = G_MBFSaveGameName(choice); name = G_MBFSaveGameName(slot);
saveg_compat = saveg_mbf; saveg_compat = saveg_mbf;
} }
G_LoadGame(name, choice, false); // killough 3/16/98, 5/15/98: add slot, cmd G_LoadGame(name, slot, false); // killough 3/16/98, 5/15/98: add slot, cmd
MN_ClearMenus(); MN_ClearMenus();
if (name) if (name)
@ -940,13 +1038,23 @@ static void M_LoadSelect(int choice)
} }
// [crispy] save the last game you loaded // [crispy] save the last game you loaded
SaveDef.lastOn = choice; SaveDef.lastOn = slot;
} }
// //
// killough 5/15/98: add forced loadgames // killough 5/15/98: add forced loadgames
// //
static void M_VerifyForcedLoadAutoSave(int ch)
{
if (ch == 'y')
{
G_ForcedLoadAutoSave();
}
free(messageString);
MN_ClearMenus();
}
static void M_VerifyForcedLoadGame(int ch) static void M_VerifyForcedLoadGame(int ch)
{ {
if (ch == 'y') if (ch == 'y')
@ -957,6 +1065,11 @@ static void M_VerifyForcedLoadGame(int ch)
MN_ClearMenus(); MN_ClearMenus();
} }
void MN_ForcedLoadAutoSave(const char *msg)
{
M_StartMessage(strdup(msg), M_VerifyForcedLoadAutoSave, true);
}
void MN_ForcedLoadGame(const char *msg) void MN_ForcedLoadGame(const char *msg)
{ {
M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above M_StartMessage(strdup(msg), M_VerifyForcedLoadGame, true); // free()'d above
@ -984,7 +1097,15 @@ static void M_LoadGame(int choice)
return; return;
} }
if (G_AutoSaveEnabled() && savepage == 0)
{
SetNextMenu(&LoadAutoSaveDef);
}
else
{
SetNextMenu(&LoadDef); SetNextMenu(&LoadDef);
}
M_ReadSaveStrings(); M_ReadSaveStrings();
} }
@ -1019,18 +1140,102 @@ static menu_t SaveDef =
0 0
}; };
static void SetLoadSlotStatus(int slot, int status)
{
if (currentMenu == &LoadAutoSaveDef)
{
if (slot > 0)
{
LoadDef.menuitems[slot - 1].status = status;
}
LoadAutoSaveDef.menuitems[slot].status = status;
}
else
{
LoadDef.menuitems[slot].status = status;
LoadAutoSaveDef.menuitems[slot + 1].status = status;
}
}
static void EmptySaveString(char *name, boolean is_autosave)
{
if (is_autosave)
{
M_snprintf(name, SAVESTRINGSIZE, "%s (Auto)", s_EMPTYSTRING);
}
else
{
M_snprintf(name, SAVESTRINGSIZE, "%s", s_EMPTYSTRING);
}
}
static void M_ReadSaveString(char *name, int menu_slot, int save_slot,
boolean is_autosave)
{
FILE *fp = M_fopen(name, "rb");
MN_ReadSavegameTime(menu_slot, name);
free(name);
MN_ResetSnapshot(menu_slot);
if (!fp)
{
if (!is_autosave)
{
// Ty 03/27/98 - externalized:
name = G_MBFSaveGameName(save_slot);
fp = M_fopen(name, "rb");
free(name);
}
if (!fp)
{
EmptySaveString(savegamestrings[menu_slot], is_autosave);
SetLoadSlotStatus(menu_slot, 0);
return;
}
}
// [FG] check return value
if (!fread(&savegamestrings[menu_slot], SAVESTRINGSIZE, 1, fp))
{
fclose(fp);
EmptySaveString(savegamestrings[menu_slot], is_autosave);
SetLoadSlotStatus(menu_slot, 0);
return;
}
if (!MN_ReadSnapshot(menu_slot, fp))
{
MN_ResetSnapshot(menu_slot);
}
fclose(fp);
SetLoadSlotStatus(menu_slot, 1);
}
static void UpdateRectX(menu_t *menu, int x)
{
for (int i = 0; i < menu->numitems; i++)
{
menu->menuitems[i].rect.x = x;
}
}
// //
// M_ReadSaveStrings // M_ReadSaveStrings
// read the strings from the savegame files // read the strings from the savegame files
// //
static void M_ReadSaveStrings(void) static void M_ReadSaveStrings(void)
{ {
int i;
// [FG] shift savegame descriptions a bit to the right // [FG] shift savegame descriptions a bit to the right
// to make room for the snapshots on the left // to make room for the snapshots on the left
SaveDef.x = LoadDef.x = const int x = M_X_LOADSAVE + MIN(M_LOADSAVE_WIDTH / 2, video.deltaw);
M_X_LOADSAVE + MIN(M_LOADSAVE_WIDTH / 2, video.deltaw); SaveDef.x = LoadDef.x = LoadAutoSaveDef.x = x;
UpdateRectX(&SaveDef, x);
UpdateRectX(&LoadDef, x);
UpdateRectX(&LoadAutoSaveDef, x);
// [FG] fit the snapshots into the resulting space // [FG] fit the snapshots into the resulting space
snapshot_width = MIN((video.deltaw + SaveDef.x + 2 * SKULLXOFF) & ~7, snapshot_width = MIN((video.deltaw + SaveDef.x + 2 * SKULLXOFF) & ~7,
@ -1038,51 +1243,22 @@ static void M_ReadSaveStrings(void)
snapshot_height = MIN((snapshot_width * SCREENHEIGHT / SCREENWIDTH) & ~7, snapshot_height = MIN((snapshot_width * SCREENHEIGHT / SCREENWIDTH) & ~7,
SCREENHEIGHT / 2); SCREENHEIGHT / 2);
for (i = 0; i < load_page; i++) int start_slot = 0;
{
FILE *fp; // killough 11/98: change to use stdio
char *name = G_SaveGameName(i); // killough 3/22/98 if (currentMenu == &LoadAutoSaveDef)
fp = M_fopen(name, "rb");
MN_ReadSavegameTime(i, name);
if (name)
{ {
free(name); char *name = G_AutoSaveName();
M_ReadSaveString(name, 0, 0, true);
start_slot = 1;
} }
MN_ResetSnapshot(i); const int num_slots = currentMenu->numitems - 1;
if (!fp) for (int menu_slot = start_slot; menu_slot < num_slots; menu_slot++)
{ // Ty 03/27/98 - externalized:
name = G_MBFSaveGameName(i);
fp = M_fopen(name, "rb");
if (name)
{ {
free(name); const int save_slot = menu_slot - start_slot;
} char *name = G_SaveGameName(save_slot);
if (!fp) M_ReadSaveString(name, menu_slot, save_slot, false);
{
strcpy(&savegamestrings[i][0], s_EMPTYSTRING);
LoadMenu[i].status = 0;
continue;
}
}
// [FG] check return value
if (!fread(&savegamestrings[i], SAVESTRINGSIZE, 1, fp))
{
strcpy(&savegamestrings[i][0], s_EMPTYSTRING);
LoadMenu[i].status = 0;
fclose(fp);
continue;
}
if (!MN_ReadSnapshot(i, fp))
{
MN_ResetSnapshot(i);
}
fclose(fp);
LoadMenu[i].status = 1;
} }
} }
@ -1094,25 +1270,19 @@ static void M_DrawSave(void)
int i; int i;
// jff 3/15/98 use symbolic load position // jff 3/15/98 use symbolic load position
MN_DrawTitle(72, LOADGRAPHIC_Y, "M_SAVEG", "Save Game"); MN_DrawTitle(M_X_CENTER, loadsave_title_y, "M_SAVEG", "Save Game");
for (i = 0; i < load_page; i++) M_DrawSaveLoadBorders();
{
menuitem_t *item = &currentMenu->menuitems[i];
byte *cr = (item->flags & MF_HILITE) ? cr_bright : NULL;
M_DrawSaveLoadBorder(LoadDef.x, LoadDef.y + LINEHEIGHT * i, cr);
WriteText(LoadDef.x, LoadDef.y + LINEHEIGHT * i, savegamestrings[i]);
}
if (saveStringEnter) if (saveStringEnter)
{ {
i = MN_StringWidth(savegamestrings[saveSlot]); i = MN_StringWidth(savegamestrings[saveSlot]);
WriteText(LoadDef.x + i, LoadDef.y + LINEHEIGHT * saveSlot, "_"); WriteText(currentMenu->x + i, currentMenu->y + LINEHEIGHT * saveSlot,
"_");
} }
int index = (menu_input == mouse_mode ? highlight_item : itemOn); int index = (menu_input == mouse_mode ? highlight_item : itemOn);
if (index < load_page) if (index < currentMenu->numitems - 1)
{ {
M_DrawBorderedSnapshot(index); M_DrawBorderedSnapshot(index);
} }
@ -1138,7 +1308,7 @@ void MN_SetQuickSaveSlot(int slot)
} }
// [FG] generate a default save slot name when the user saves to an empty slot // [FG] generate a default save slot name when the user saves to an empty slot
static void SetDefaultSaveName(int slot) static void SetDefaultSaveName(char *name, const char *append)
{ {
char *maplump = MAPNAME(gameepisode, gamemap); char *maplump = MAPNAME(gameepisode, gamemap);
int maplumpnum = W_CheckNumForName(maplump); int maplumpnum = W_CheckNumForName(maplump);
@ -1158,16 +1328,31 @@ static void SetDefaultSaveName(int slot)
*ext = '\0'; *ext = '\0';
} }
M_snprintf(savegamestrings[slot], SAVESTRINGSIZE, "%s (%s)", maplump, if (append)
wadname); {
M_snprintf(name, SAVESTRINGSIZE, "%s (%s) (%s)", maplump, wadname,
append);
}
else
{
M_snprintf(name, SAVESTRINGSIZE, "%s (%s)", maplump, wadname);
}
free(wadname); free(wadname);
} }
else else
{ {
M_snprintf(savegamestrings[slot], SAVESTRINGSIZE, "%s", maplump); if (append)
{
M_snprintf(name, SAVESTRINGSIZE, "%s (%s)", maplump, append);
}
else
{
M_snprintf(name, SAVESTRINGSIZE, "%s", maplump);
}
} }
M_StringToUpper(savegamestrings[slot]); M_StringToUpper(name);
} }
// [FG] override savegame name if it already starts with a map identifier // [FG] override savegame name if it already starts with a map identifier
@ -1188,16 +1373,22 @@ boolean MN_StartsWithMapIdentifier(char *str)
return false; return false;
} }
void M_SaveAutoSave(void)
{
char autosave_string[SAVESTRINGSIZE];
SetDefaultSaveName(autosave_string, "Auto");
G_SaveAutoSave(autosave_string);
}
static boolean GamepadSave(int choice) static boolean GamepadSave(int choice)
{ {
if (menu_input == pad_mode) if (menu_input == pad_mode)
{ {
// Immediately save game using a default name. // Immediately save game using a default name.
saveSlot = choice; SetDefaultSaveName(savegamestrings[choice], NULL);
savegamestrings[choice][0] = 0;
SetDefaultSaveName(choice);
M_DoSave(choice); M_DoSave(choice);
LoadDef.lastOn = choice; LoadDef.lastOn = choice;
LoadAutoSaveDef.lastOn = choice + 1;
return true; return true;
} }
@ -1224,12 +1415,13 @@ static void M_SaveSelect(int choice)
|| MN_StartsWithMapIdentifier(savegamestrings[choice])) || MN_StartsWithMapIdentifier(savegamestrings[choice]))
{ {
savegamestrings[choice][0] = 0; savegamestrings[choice][0] = 0;
SetDefaultSaveName(choice); SetDefaultSaveName(savegamestrings[choice], NULL);
} }
saveCharIndex = strlen(savegamestrings[choice]); saveCharIndex = strlen(savegamestrings[choice]);
// [crispy] load the last game you saved // [crispy] load the last game you saved
LoadDef.lastOn = choice; LoadDef.lastOn = choice;
LoadAutoSaveDef.lastOn = choice + 1;
} }
// //
@ -1449,7 +1641,7 @@ static void M_QuickSaveResponse(int ch)
{ {
if (MN_StartsWithMapIdentifier(savegamestrings[quickSaveSlot])) if (MN_StartsWithMapIdentifier(savegamestrings[quickSaveSlot]))
{ {
SetDefaultSaveName(quickSaveSlot); SetDefaultSaveName(savegamestrings[quickSaveSlot], NULL);
} }
M_DoSave(quickSaveSlot); M_DoSave(quickSaveSlot);
M_StartSound(sfx_swtchx); M_StartSound(sfx_swtchx);
@ -1472,8 +1664,8 @@ static void M_QuickSave(void)
if (quickSaveSlot < 0) if (quickSaveSlot < 0)
{ {
MN_StartControlPanel(); MN_StartControlPanel();
M_ReadSaveStrings();
SetNextMenu(&SaveDef); SetNextMenu(&SaveDef);
M_ReadSaveStrings();
quickSaveSlot = -2; // means to pick a slot now quickSaveSlot = -2; // means to pick a slot now
return; return;
} }
@ -1514,8 +1706,8 @@ static void M_QuickLoad(void)
{ {
// [crispy] allow quickload before quicksave // [crispy] allow quickload before quicksave
MN_StartControlPanel(); MN_StartControlPanel();
M_ReadSaveStrings();
SetNextMenu(&LoadDef); SetNextMenu(&LoadDef);
M_ReadSaveStrings();
quickSaveSlot = -2; // means to pick a slot now quickSaveSlot = -2; // means to pick a slot now
return; return;
} }
@ -2010,6 +2202,36 @@ void MN_BackSecondary(void)
} }
} }
static void UpdateRectY(menu_t *menu, int m_y)
{
for (int i = 0; i < menu->numitems; i++)
{
menu->menuitems[i].rect.y = SAVE_LOAD_RECT_Y(m_y, i);
}
}
void M_ResetAutoSave(void)
{
int m_y;
if (G_AutoSaveEnabled())
{
loadsave_title_y = AUTOGRAPHIC_Y;
m_y = M_Y_AUTOSAVE;
}
else
{
loadsave_title_y = LOADGRAPHIC_Y;
m_y = M_Y_LOADSAVE;
}
LoadDef.y = m_y;
UpdateRectY(&LoadDef, m_y);
SaveDef.y = m_y;
UpdateRectY(&SaveDef, m_y);
}
// //
// M_Init // M_Init
// //
@ -2029,6 +2251,7 @@ void M_Init(void)
messageString = NULL; messageString = NULL;
messageLastMenuActive = menuactive; messageLastMenuActive = menuactive;
quickSaveSlot = -1; quickSaveSlot = -1;
M_ResetAutoSave();
int lumpnum = W_CheckNumForName("DBIGFONT"); int lumpnum = W_CheckNumForName("DBIGFONT");
if (lumpnum > 0) if (lumpnum > 0)
@ -2467,9 +2690,31 @@ static void ClearHighlightedItems(void)
} }
} }
static void M_UpdateLoadMenu(void)
{
if (G_AutoSaveEnabled()
&& (currentMenu == &LoadDef || currentMenu == &LoadAutoSaveDef))
{
if (savepage == 0 && currentMenu == &LoadDef)
{
SetNextMenu(&LoadAutoSaveDef);
}
else if (savepage != 0 && currentMenu == &LoadAutoSaveDef)
{
SetNextMenu(&LoadDef);
}
}
}
static boolean AnyLoadSaveMenu(void)
{
return (currentMenu == &LoadDef || currentMenu == &SaveDef
|| currentMenu == &LoadAutoSaveDef);
}
static boolean SaveLoadResponder(menu_action_t action, int ch) static boolean SaveLoadResponder(menu_action_t action, int ch)
{ {
if (currentMenu != &LoadDef && currentMenu != &SaveDef) if (!AnyLoadSaveMenu())
{ {
return false; return false;
} }
@ -2481,6 +2726,7 @@ static boolean SaveLoadResponder(menu_action_t action, int ch)
if (M_ToUpper(ch) == 'Y' || action == MENU_ENTER) if (M_ToUpper(ch) == 'Y' || action == MENU_ENTER)
{ {
M_DeleteGame(old_menu_input == mouse_mode ? highlight_item : itemOn); M_DeleteGame(old_menu_input == mouse_mode ? highlight_item : itemOn);
M_ReadSaveStrings();
M_StartSound(sfx_itemup); M_StartSound(sfx_itemup);
delete_verify = false; delete_verify = false;
} }
@ -2501,6 +2747,7 @@ static boolean SaveLoadResponder(menu_action_t action, int ch)
{ {
savepage--; savepage--;
quickSaveSlot = -1; quickSaveSlot = -1;
M_UpdateLoadMenu();
M_ReadSaveStrings(); M_ReadSaveStrings();
M_StartSound(sfx_pstop); M_StartSound(sfx_pstop);
} }
@ -2512,6 +2759,7 @@ static boolean SaveLoadResponder(menu_action_t action, int ch)
{ {
savepage++; savepage++;
quickSaveSlot = -1; quickSaveSlot = -1;
M_UpdateLoadMenu();
M_ReadSaveStrings(); M_ReadSaveStrings();
M_StartSound(sfx_pstop); M_StartSound(sfx_pstop);
} }
@ -2627,6 +2875,14 @@ static boolean MouseResponder(void)
return false; return false;
} }
static boolean AllowDeleteSaveGame(void)
{
return (((currentMenu == &LoadDef || currentMenu == &SaveDef)
&& LoadDef.menuitems[itemOn].status)
|| (currentMenu == &LoadAutoSaveDef
&& LoadAutoSaveDef.menuitems[itemOn].status));
}
boolean M_Responder(event_t *ev) boolean M_Responder(event_t *ev)
{ {
int ch; int ch;
@ -3036,9 +3292,9 @@ boolean M_Responder(event_t *ev)
if (action == MENU_CLEAR) if (action == MENU_CLEAR)
{ {
if (currentMenu == &LoadDef || currentMenu == &SaveDef) if (AnyLoadSaveMenu())
{ {
if (LoadMenu[itemOn].status) if (AllowDeleteSaveGame())
{ {
M_StartSound(sfx_itemup); M_StartSound(sfx_itemup);
currentMenu->lastOn = itemOn; currentMenu->lastOn = itemOn;

View File

@ -57,6 +57,7 @@ void M_Init(void);
void MN_StartControlPanel(void); void MN_StartControlPanel(void);
void MN_ForcedLoadAutoSave(const char *msg);
void MN_ForcedLoadGame(const char *msg); // killough 5/15/98: forced loadgames void MN_ForcedLoadGame(const char *msg); // killough 5/15/98: forced loadgames
void MN_Trans(void); // killough 11/98: reset translucency void MN_Trans(void); // killough 11/98: reset translucency
void MN_SetupResetMenu(void); void MN_SetupResetMenu(void);
@ -87,8 +88,12 @@ extern int savepage;
extern const char *default_skill_strings[]; extern const char *default_skill_strings[];
void M_ResetAutoSave(void);
void MN_SetQuickSaveSlot(int slot); void MN_SetQuickSaveSlot(int slot);
void M_SaveAutoSave(void);
void MN_InitMenuStrings(void); void MN_InitMenuStrings(void);
boolean MN_StartsWithMapIdentifier(char *str); boolean MN_StartsWithMapIdentifier(char *str);

View File

@ -3289,17 +3289,20 @@ static setup_menu_t gen_settings6[] = {
{"Screen wipe effect", S_CHOICE | S_STRICT, OFF_CNTR_X, M_SPC, {"Screen wipe effect", S_CHOICE | S_STRICT, OFF_CNTR_X, M_SPC,
{"screen_melt"}, .strings_id = str_screen_melt}, {"screen_melt"}, .strings_id = str_screen_melt},
{"On death action", S_CHOICE, OFF_CNTR_X, M_SPC, {"death_use_action"},
.strings_id = str_death_use_action},
{"Demo progress bar", S_ONOFF, OFF_CNTR_X, M_SPC, {"demobar"}},
{"Screen flashes", S_ONOFF | S_STRICT, OFF_CNTR_X, M_SPC, {"Screen flashes", S_ONOFF | S_STRICT, OFF_CNTR_X, M_SPC,
{"palette_changes"}}, {"palette_changes"}},
{"Invulnerability effect", S_CHOICE | S_STRICT, OFF_CNTR_X, M_SPC, {"Invulnerability effect", S_CHOICE | S_STRICT, OFF_CNTR_X, M_SPC,
{"invul_mode"}, .strings_id = str_invul_mode, .action = R_InvulMode}, {"invul_mode"}, .strings_id = str_invul_mode, .action = R_InvulMode},
{"Demo progress bar", S_ONOFF, OFF_CNTR_X, M_SPC, {"demobar"}},
{"On death action", S_CHOICE, OFF_CNTR_X, M_SPC, {"death_use_action"},
.strings_id = str_death_use_action},
{"Auto save", S_ONOFF, OFF_CNTR_X, M_SPC, {"autosave"},
.action = M_ResetAutoSave},
{"Organize save files", S_ONOFF | S_PRGWARN, OFF_CNTR_X, M_SPC, {"Organize save files", S_ONOFF | S_PRGWARN, OFF_CNTR_X, M_SPC,
{"organize_savefiles"}}, {"organize_savefiles"}},

View File

@ -322,6 +322,8 @@ void P_DeathThink (player_t* player)
{ {
activate_death_use_reload = 1; activate_death_use_reload = 1;
if (!G_AutoSaveEnabled() || !G_LoadAutoSaveDeathUse())
{
if (savegameslot >= 0) if (savegameslot >= 0)
{ {
char *file = G_SaveGameName(savegameslot); char *file = G_SaveGameName(savegameslot);
@ -329,8 +331,11 @@ void P_DeathThink (player_t* player)
free(file); free(file);
} }
else else
{
player->playerstate = PST_REBORN; player->playerstate = PST_REBORN;
} }
}
}
} }
// //