diff --git a/src/d_main.c b/src/d_main.c index 0fbb7dd31..89d530890 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -712,6 +712,7 @@ void D_StartTitle(void) botskin = 0; cv_debug = 0; emeralds = 0; + lastmaploaded = 0; // In case someone exits out at the same time they start a time attack run, // reset modeattacking diff --git a/src/dehacked.c b/src/dehacked.c index 9465d154c..814f7d65a 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1329,6 +1329,13 @@ static void readlevelheader(MYFILE *f, INT32 num) else mapheaderinfo[num-1]->levelflags &= ~LF_NOZONE; } + else if (fastcmp(word, "SAVEGAME")) + { + if (i || word2[0] == 'T' || word2[0] == 'Y') + mapheaderinfo[num-1]->levelflags |= LF_SAVEGAME; + else + mapheaderinfo[num-1]->levelflags &= ~LF_SAVEGAME; + } // Individual triggers for menu flags else if (fastcmp(word, "HIDDEN")) @@ -7043,6 +7050,7 @@ struct { {"LF_NOSSMUSIC",LF_NOSSMUSIC}, {"LF_NORELOAD",LF_NORELOAD}, {"LF_NOZONE",LF_NOZONE}, + {"LF_SAVEGAME",LF_SAVEGAME}, // And map flags {"LF2_HIDEINMENU",LF2_HIDEINMENU}, {"LF2_HIDEINSTATS",LF2_HIDEINSTATS}, diff --git a/src/doomstat.h b/src/doomstat.h index a3b07c9cb..a24bad79d 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -41,7 +41,8 @@ extern INT16 maptol; extern UINT8 globalweather; extern INT32 curWeather; extern INT32 cursaveslot; -extern INT16 lastmapsaved; +//extern INT16 lastmapsaved; +extern INT16 lastmaploaded; extern boolean gamecomplete; #define PRECIP_NONE 0 @@ -263,6 +264,7 @@ typedef struct #define LF_NOSSMUSIC 4 ///< Disable Super Sonic music #define LF_NORELOAD 8 ///< Don't reload level on death #define LF_NOZONE 16 ///< Don't include "ZONE" on level title +#define LF_SAVEGAME 32 ///< Save the game upon loading this level #define LF2_HIDEINMENU 1 ///< Hide in the multiplayer menu #define LF2_HIDEINSTATS 2 ///< Hide in the statistics screen diff --git a/src/g_game.c b/src/g_game.c index 7769555ba..1a2a2aac6 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -77,7 +77,8 @@ INT16 maptol; UINT8 globalweather = 0; INT32 curWeather = PRECIP_NONE; INT32 cursaveslot = -1; // Auto-save 1p savegame slot -INT16 lastmapsaved = 0; // Last map we auto-saved at +//INT16 lastmapsaved = 0; // Last map we auto-saved at +INT16 lastmaploaded = 0; // Last map the game loaded boolean gamecomplete = false; UINT16 mainwads = 0; diff --git a/src/m_menu.c b/src/m_menu.c index e4a8ef1a2..dc74ae5d2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6661,7 +6661,7 @@ static void M_ChoosePlayer(INT32 choice) if (startmap != spstage_start) cursaveslot = -1; - lastmapsaved = 0; + //lastmapsaved = 0; gamecomplete = false; G_DeferedInitNew(ultmode, G_BuildMapName(startmap), (UINT8)skinnum, false, fromlevelselect); diff --git a/src/p_saveg.c b/src/p_saveg.c index 3853dc7e6..2d3412e65 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -3159,7 +3159,8 @@ static inline void P_ArchiveMisc(void) else WRITEINT16(save_p, gamemap); - lastmapsaved = gamemap; + //lastmapsaved = gamemap; + lastmaploaded = gamemap; WRITEUINT16(save_p, (botskin ? (emeralds|(1<<10)) : emeralds)+357); WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); @@ -3184,7 +3185,8 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) if(!mapheaderinfo[gamemap-1]) P_AllocMapHeader(gamemap-1); - lastmapsaved = gamemap; + //lastmapsaved = gamemap; + lastmaploaded = gamemap; tokenlist = 0; token = 0; diff --git a/src/p_setup.c b/src/p_setup.c index 6a933809a..03b133da2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2547,6 +2547,21 @@ static void P_LoadNightsGhosts(void) free(gpath); } +static boolean CanSaveLevel(INT32 mapnum) +{ + if (ultimatemode) // never save in ultimate (probably redundant with cursaveslot also being checked) + return false; + + if (G_IsSpecialStage(mapnum) // don't save in special stages + || mapnum == lastmaploaded) // don't save if the last map loaded was this one + return false; + + // Any levels that have the savegame flag can save normally. + // If the game is complete for this save slot, then any level can save! + // On the other side of the spectrum, if lastmaploaded is 0, then the save file has only just been created and needs to save ASAP! + return (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME || gamecomplete || !lastmaploaded); +} + /** Loads a level from a lump or external wad. * * \param skipprecip If true, don't spawn precipitation. @@ -2997,11 +3012,11 @@ boolean P_SetupLevel(boolean skipprecip) P_RunCachedActions(); if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || players[consoleplayer].lives <= 0) - && (!modifiedgame || savemoddata) && cursaveslot >= 0 && !ultimatemode - && !(mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) - && (!G_IsSpecialStage(gamemap)) && gamemap != lastmapsaved && (mapheaderinfo[gamemap-1]->actnum < 2 || gamecomplete)) + && (!modifiedgame || savemoddata) && cursaveslot >= 0 && CanSaveLevel(gamemap)) G_SaveGame((UINT32)cursaveslot); + lastmaploaded = gamemap; // HAS to be set after saving!! + if (savedata.lives > 0) { players[consoleplayer].continues = savedata.continues;