ZDoom-style saves

git-svn-id: https://svn.eduke32.com/eduke32@6569 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
hendricks266 2017-12-18 11:24:53 +00:00
parent 29a0fffd5b
commit d9b0479343
15 changed files with 443 additions and 247 deletions

View file

@ -775,18 +775,6 @@ void G_CheckCommandLine(int32_t argc, char const * const * argv)
if (*c) if (*c)
G_AddCon(c); G_AddCon(c);
break; break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
ud.warp_on = 2 + (*c) - '0';
break;
case 'z': case 'z':
c++; c++;
g_scriptDebug = Batoi(c); g_scriptDebug = Batoi(c);

View file

@ -204,7 +204,7 @@ void G_OpenDemoWrite(void)
if (g_demo_filePtr == NULL) if (g_demo_filePtr == NULL)
return; return;
i=sv_saveandmakesnapshot(g_demo_filePtr, -1, demorec_diffs_cvar, demorec_diffcompress_cvar, i=sv_saveandmakesnapshot(g_demo_filePtr, nullptr, -1, demorec_diffs_cvar, demorec_diffcompress_cvar,
demorec_synccompress_cvar|(demorec_seeds_cvar<<1)); demorec_synccompress_cvar|(demorec_seeds_cvar<<1));
if (i) if (i)
{ {

View file

@ -4842,7 +4842,7 @@ FAKE_F3:
g_doQuickSave = 0; g_doQuickSave = 0;
if (g_lastSaveSlot == -1) if (!g_lastusersave.isValid())
goto FAKE_F2; goto FAKE_F2;
KB_FlushKeyboardQueue(); KB_FlushKeyboardQueue();
@ -4857,16 +4857,19 @@ FAKE_F3:
G_DrawRooms(myconnectindex,65536); G_DrawRooms(myconnectindex,65536);
g_screenCapture = 0; g_screenCapture = 0;
if (g_lastSaveSlot >= 0) if (g_lastusersave.isValid())
{ {
savebrief_t & sv = g_lastusersave;
// dirty hack... char 127 in last position indicates an auto-filled name // dirty hack... char 127 in last position indicates an auto-filled name
if (ud.savegame[g_lastSaveSlot][MAXSAVEGAMENAME] == 127) if (sv.name[MAXSAVEGAMENAME] == 127)
{ {
Bstrncpy(&ud.savegame[g_lastSaveSlot][0], g_mapInfo[ud.volume_number * MAXLEVELS + ud.level_number].name, MAXSAVEGAMENAME); strncpy(sv.name, g_mapInfo[ud.volume_number * MAXLEVELS + ud.level_number].name, MAXSAVEGAMENAME);
ud.savegame[g_lastSaveSlot][MAXSAVEGAMENAME] = 127; sv.name[MAXSAVEGAMENAME] = 127;
} }
G_SavePlayerMaybeMulti(g_lastSaveSlot); g_quickload = &sv;
G_SavePlayerMaybeMulti(sv);
} }
} }
@ -4898,14 +4901,14 @@ FAKE_F3:
g_doQuickSave = 0; g_doQuickSave = 0;
if (g_lastSaveSlot == -1) if (g_quickload == nullptr || !g_quickload->isValid())
goto FAKE_F3; goto FAKE_F3;
else if (g_lastSaveSlot >= 0) else if (g_quickload->isValid())
{ {
KB_FlushKeyboardQueue(); KB_FlushKeyboardQueue();
KB_ClearKeysDown(); KB_ClearKeysDown();
S_PauseSounds(1); S_PauseSounds(1);
G_LoadPlayerMaybeMulti(g_lastSaveSlot); G_LoadPlayerMaybeMulti(*g_quickload);
} }
} }
@ -5922,8 +5925,6 @@ static void G_Startup(void)
// initprintf("Loading palette/lookups...\n"); // initprintf("Loading palette/lookups...\n");
G_LoadLookups(); G_LoadLookups();
ReadSaveGameHeaders();
screenpeek = myconnectindex; screenpeek = myconnectindex;
Bfflush(NULL); Bfflush(NULL);
@ -6532,7 +6533,10 @@ int app_main(int argc, char const * const * argv)
Menu_Init(); Menu_Init();
} }
if (ud.warp_on > 1 && (!g_netServer && ud.multimode < 2)) #if 0
// previously, passing -0 through -9 on the command line would load the save in that slot #
// this code should be reusable for a new parameter that takes a filename, if desired
if (/* havesavename */ && (!g_netServer && ud.multimode < 2))
{ {
clearview(0L); clearview(0L);
//g_player[myconnectindex].ps->palette = palette; //g_player[myconnectindex].ps->palette = palette;
@ -6542,9 +6546,10 @@ int app_main(int argc, char const * const * argv)
menutext_center(105,"Loading saved game..."); menutext_center(105,"Loading saved game...");
nextpage(); nextpage();
if (G_LoadPlayer(ud.warp_on-2)) if (G_LoadPlayer(/* savefile */))
ud.warp_on = 0; /* havesavename = false; */
} }
#endif
FX_StopAllSounds(); FX_StopAllSounds();
S_ClearSoundLocks(); S_ClearSoundLocks();
@ -6721,21 +6726,20 @@ MAIN_LOOP_RESTART:
} }
// handle CON_SAVE and CON_SAVENN // handle CON_SAVE and CON_SAVENN
if (g_requestedSaveSlot != -1) if (g_saveRequested)
{ {
g_lastSaveSlot = g_requestedSaveSlot;
OSD_Printf("Saving to slot %d\n", g_requestedSaveSlot);
KB_FlushKeyboardQueue(); KB_FlushKeyboardQueue();
g_screenCapture = 1; g_screenCapture = 1;
G_DrawRooms(myconnectindex, 65536); G_DrawRooms(myconnectindex, 65536);
g_screenCapture = 0; g_screenCapture = 0;
G_SavePlayerMaybeMulti(g_requestedSaveSlot); G_SavePlayerMaybeMulti(g_lastautosave);
g_quickload = &g_lastautosave;
g_requestedSaveSlot = -1; OSD_Printf("Saved: %s\n", g_lastautosave.path);
g_saveRequested = false;
} }
G_DoCheats(); G_DoCheats();

View file

@ -132,7 +132,6 @@ extern camera_t g_camera;
#define MAXRIDECULE 10 #define MAXRIDECULE 10
#define MAXRIDECULELENGTH 40 #define MAXRIDECULELENGTH 40
#define MAXSAVEGAMES 10
#define MAXSAVEGAMENAMESTRUCT 32 #define MAXSAVEGAMENAMESTRUCT 32
#define MAXSAVEGAMENAME (MAXSAVEGAMENAMESTRUCT-1) #define MAXSAVEGAMENAME (MAXSAVEGAMENAMESTRUCT-1)
#define MAXPWLOCKOUT 128 #define MAXPWLOCKOUT 128
@ -239,7 +238,6 @@ typedef struct {
char god,warp_on,cashman,eog,showallmap; char god,warp_on,cashman,eog,showallmap;
char show_help,scrollmode,noclip; char show_help,scrollmode,noclip;
char ridecule[MAXRIDECULE][MAXRIDECULELENGTH]; char ridecule[MAXRIDECULE][MAXRIDECULELENGTH];
char savegame[MAXSAVEGAMES][MAXSAVEGAMENAMESTRUCT];
char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME]; char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME];
char display_bonus_screen; char display_bonus_screen;
char show_level_text; char show_level_text;
@ -481,6 +479,10 @@ enum
(((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) \ (((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/" basename, g_modDir, ##__VA_ARGS__) \
: Bsnprintf(buf, size, basename, ##__VA_ARGS__)) >= ((int32_t)size) - 1\ : Bsnprintf(buf, size, basename, ##__VA_ARGS__)) >= ((int32_t)size) - 1\
) )
#define G_ModDirSnprintfLite(buf, size, basename) \
\
((g_modDir[0] != '/') ? Bsnprintf(buf, size, "%s/%s", g_modDir, basename) \
: Bsnprintf(buf, size, basename))
static inline void G_NewGame_EnterLevel(void) static inline void G_NewGame_EnterLevel(void)
{ {

View file

@ -1078,7 +1078,7 @@ static int32_t VM_ResetPlayer(int const playerNum, int32_t vmFlags, int32_t cons
//AddLog("resetplayer"); //AddLog("resetplayer");
if (!g_netServer && ud.multimode < 2 && !(resetFlags & 2)) if (!g_netServer && ud.multimode < 2 && !(resetFlags & 2))
{ {
if (g_lastSaveSlot >= 0 && ud.recstat != 2 && !(resetFlags & 1)) if (g_quickload && g_quickload->isValid() && ud.recstat != 2 && !(resetFlags & 1))
{ {
Menu_Open(playerNum); Menu_Open(playerNum);
KB_ClearKeyDown(sc_Space); KB_ClearKeyDown(sc_Space);
@ -3463,20 +3463,29 @@ nullquote:
{ {
int32_t const requestedSlot = *insptr++; int32_t const requestedSlot = *insptr++;
if ((unsigned)requestedSlot >= MAXSAVEGAMES) if ((unsigned)requestedSlot >= 10)
continue; continue;
g_requestedSaveSlot = requestedSlot; // check if we need to make a new file
if (strcmp(g_lastautosave.path, g_lastusersave.path) == 0 ||
requestedSlot != g_lastAutoSaveArbitraryID)
{
g_lastautosave.reset();
}
if (tw == CON_SAVE || ud.savegame[requestedSlot][0] == 0) g_lastAutoSaveArbitraryID = requestedSlot;
if (tw == CON_SAVE || g_lastautosave.name[0] == 0)
{ {
time_t timeStruct = time(NULL); time_t timeStruct = time(NULL);
struct tm *pTime = localtime(&timeStruct); struct tm *pTime = localtime(&timeStruct);
strftime(ud.savegame[requestedSlot], sizeof(ud.savegame[requestedSlot]), strftime(g_lastautosave.name, sizeof(g_lastautosave.name),
"%d %b %Y %I:%M%p", pTime); "%d %b %Y %I:%M%p", pTime);
} }
g_saveRequested = true;
continue; continue;
} }

View file

@ -59,7 +59,6 @@ int32_t __fastcall VM_GetUserdef(int32_t labelNum)
case USERDEFS_CLIPPING: labelNum = ud.noclip; break; case USERDEFS_CLIPPING: labelNum = ud.noclip; break;
// case USERDEFS_USER_NAME: labelNum= ud.user_name[MAXPLAYERS][32]; break; // case USERDEFS_USER_NAME: labelNum= ud.user_name[MAXPLAYERS][32]; break;
// case USERDEFS_RIDECULE: labelNum= ud.ridecule; break; // case USERDEFS_RIDECULE: labelNum= ud.ridecule; break;
// case USERDEFS_SAVEGAME: labelNum= ud.savegame; break;
// case USERDEFS_PWLOCKOUT: labelNum= ud.pwlockout; break; // case USERDEFS_PWLOCKOUT: labelNum= ud.pwlockout; break;
// case USERDEFS_RTSNAME: labelNum= ud.rtsname; break; // case USERDEFS_RTSNAME: labelNum= ud.rtsname; break;
case USERDEFS_OVERHEAD_ON: labelNum = ud.overhead_on; break; case USERDEFS_OVERHEAD_ON: labelNum = ud.overhead_on; break;
@ -198,7 +197,6 @@ void __fastcall VM_SetUserdef(int32_t const labelNum, int32_t const iSet)
case USERDEFS_CLIPPING: ud.noclip = iSet; break; case USERDEFS_CLIPPING: ud.noclip = iSet; break;
// case USERDEFS_USER_NAME: ud.user_name[MAXPLAYERS][32] = lValue; break; // case USERDEFS_USER_NAME: ud.user_name[MAXPLAYERS][32] = lValue; break;
// case USERDEFS_RIDECULE: ud.ridecule = lValue; break; // case USERDEFS_RIDECULE: ud.ridecule = lValue; break;
// case USERDEFS_SAVEGAME: ud.savegame = lValue; break;
// case USERDEFS_PWLOCKOUT: ud.pwlockout = lValue; break; // case USERDEFS_PWLOCKOUT: ud.pwlockout = lValue; break;
// case USERDEFS_RTSNAME: ud.rtsname = lValue; break; // case USERDEFS_RTSNAME: ud.rtsname = lValue; break;
case USERDEFS_OVERHEAD_ON: ud.overhead_on = iSet; break; case USERDEFS_OVERHEAD_ON: ud.overhead_on = iSet; break;

View file

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "duke3d.h" #include "duke3d.h"
#include "menus.h" #include "menus.h"
#include "savegame.h"
#define gamevars_c_ #define gamevars_c_
@ -1552,7 +1553,7 @@ static void Gv_AddSystemVars(void)
Gv_NewVar("NUMSECTORS",(intptr_t)&numsectors, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR | GAMEVAR_READONLY); Gv_NewVar("NUMSECTORS",(intptr_t)&numsectors, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR | GAMEVAR_READONLY);
Gv_NewVar("Numsprites",(intptr_t)&Numsprites, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR | GAMEVAR_READONLY); Gv_NewVar("Numsprites",(intptr_t)&Numsprites, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR | GAMEVAR_READONLY);
Gv_NewVar("lastsavepos",(intptr_t)&g_lastSaveSlot, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR); Gv_NewVar("lastsavepos",(intptr_t)&g_lastAutoSaveArbitraryID, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR);
# ifdef USE_OPENGL # ifdef USE_OPENGL
Gv_NewVar("rendmode",(intptr_t)&rendmode, GAMEVAR_READONLY | GAMEVAR_INT32PTR | GAMEVAR_SYSTEM); Gv_NewVar("rendmode",(intptr_t)&rendmode, GAMEVAR_READONLY | GAMEVAR_INT32PTR | GAMEVAR_SYSTEM);
@ -1709,7 +1710,7 @@ void Gv_RefreshPointers(void)
aGameVars[Gv_GetVarIndex("NUMSECTORS")].global = (intptr_t)&numsectors; aGameVars[Gv_GetVarIndex("NUMSECTORS")].global = (intptr_t)&numsectors;
aGameVars[Gv_GetVarIndex("Numsprites")].global = (intptr_t)&Numsprites; aGameVars[Gv_GetVarIndex("Numsprites")].global = (intptr_t)&Numsprites;
aGameVars[Gv_GetVarIndex("lastsavepos")].global = (intptr_t)&g_lastSaveSlot; aGameVars[Gv_GetVarIndex("lastsavepos")].global = (intptr_t)&g_lastAutoSaveArbitraryID;
# ifdef USE_OPENGL # ifdef USE_OPENGL
aGameVars[Gv_GetVarIndex("rendmode")].global = (intptr_t)&rendmode; aGameVars[Gv_GetVarIndex("rendmode")].global = (intptr_t)&rendmode;
# endif # endif

View file

@ -94,8 +94,6 @@ int32_t g_actorRespawnTime = 768;
int32_t g_bouncemineRadius = 2500; int32_t g_bouncemineRadius = 2500;
int32_t g_deleteQueueSize = 64; int32_t g_deleteQueueSize = 64;
int32_t g_itemRespawnTime = 768; int32_t g_itemRespawnTime = 768;
int32_t g_lastSaveSlot = -1;
int32_t g_requestedSaveSlot = -1;
int32_t g_morterRadius = 2500; int32_t g_morterRadius = 2500;
int32_t g_numFreezeBounces = 3; int32_t g_numFreezeBounces = 3;

View file

@ -174,8 +174,6 @@ extern int32_t g_bouncemineRadius;
extern int32_t g_deleteQueueSize; extern int32_t g_deleteQueueSize;
extern int32_t g_gametypeCnt; extern int32_t g_gametypeCnt;
extern int32_t g_itemRespawnTime; extern int32_t g_itemRespawnTime;
extern int32_t g_lastSaveSlot;
extern int32_t g_requestedSaveSlot;
extern int32_t g_morterRadius; extern int32_t g_morterRadius;
extern int32_t g_numFreezeBounces; extern int32_t g_numFreezeBounces;
extern int32_t g_pipebombRadius; extern int32_t g_pipebombRadius;

View file

@ -490,7 +490,6 @@ enum
// game.h // game.h
MAXRIDECULE = 10, MAXRIDECULE = 10,
MAXRIDECULELENGTH = 40, MAXRIDECULELENGTH = 40,
MAXSAVEGAMES = 10,
MAXSAVEGAMENAME = 22, MAXSAVEGAMENAME = 22,
MAXPWLOCKOUT = 128, MAXPWLOCKOUT = 128,
MAXRTSNAME = 128, MAXRTSNAME = 128,
@ -589,7 +588,6 @@ typedef struct {
char god,warp_on,cashman,eog,showallmap; char god,warp_on,cashman,eog,showallmap;
char show_help,scrollmode,noclip; char show_help,scrollmode,noclip;
char ridecule[MAXRIDECULE][MAXRIDECULELENGTH]; char ridecule[MAXRIDECULE][MAXRIDECULELENGTH];
char savegame[MAXSAVEGAMES][MAXSAVEGAMENAME];
char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME]; char pwlockout[MAXPWLOCKOUT],rtsname[MAXRTSNAME];
char display_bonus_screen; char display_bonus_screen;
char show_level_text; char show_level_text;

View file

@ -219,7 +219,7 @@ static MenuMenuFormat_t MMF_MouseJoySetupBtns = { { 76<<16,
static MenuMenuFormat_t MMF_FuncList = { { 100<<16, 51<<16, }, 152<<16 }; static MenuMenuFormat_t MMF_FuncList = { { 100<<16, 51<<16, }, 152<<16 };
static MenuMenuFormat_t MMF_ColorCorrect = { { MENU_MARGIN_REGULAR<<16, 86<<16, }, 190<<16 }; static MenuMenuFormat_t MMF_ColorCorrect = { { MENU_MARGIN_REGULAR<<16, 86<<16, }, 190<<16 };
static MenuMenuFormat_t MMF_BigSliders = { { MENU_MARGIN_WIDE<<16, 37<<16, }, 190<<16 }; static MenuMenuFormat_t MMF_BigSliders = { { MENU_MARGIN_WIDE<<16, 37<<16, }, 190<<16 };
static MenuMenuFormat_t MMF_LoadSave = { { 223<<16, 48<<16, }, 320<<16 }; static MenuMenuFormat_t MMF_LoadSave = { { 200<<16, 49<<16, }, 145<<16 };
static MenuMenuFormat_t MMF_NetSetup = { { 36<<16, 38<<16, }, 190<<16 }; static MenuMenuFormat_t MMF_NetSetup = { { 36<<16, 38<<16, }, 190<<16 };
static MenuMenuFormat_t MMF_FileSelectLeft = { { 40<<16, 45<<16, }, 162<<16 }; static MenuMenuFormat_t MMF_FileSelectLeft = { { 40<<16, 45<<16, }, 162<<16 };
static MenuMenuFormat_t MMF_FileSelectRight = { { 164<<16, 45<<16, }, 162<<16 }; static MenuMenuFormat_t MMF_FileSelectRight = { { 164<<16, 45<<16, }, 162<<16 };
@ -242,7 +242,7 @@ static MenuEntryFormat_t MEF_VideoSetup_Apply = { 4<<16, 16<<16, 168<<16 };
static MenuEntryFormat_t MEF_FuncList = { 3<<16, 0, 100<<16 }; static MenuEntryFormat_t MEF_FuncList = { 3<<16, 0, 100<<16 };
static MenuEntryFormat_t MEF_ColorCorrect = { 2<<16, 0, -(240<<16) }; static MenuEntryFormat_t MEF_ColorCorrect = { 2<<16, 0, -(240<<16) };
static MenuEntryFormat_t MEF_BigSliders = { 2<<16, 0, 170<<16 }; static MenuEntryFormat_t MEF_BigSliders = { 2<<16, 0, 170<<16 };
static MenuEntryFormat_t MEF_LoadSave = { 7<<16, -1, 78<<16 }; static MenuEntryFormat_t MEF_LoadSave = { 2<<16, -1, 78<<16 };
static MenuEntryFormat_t MEF_NetSetup = { 4<<16, 0, 112<<16 }; static MenuEntryFormat_t MEF_NetSetup = { 4<<16, 0, 112<<16 };
static MenuEntryFormat_t MEF_NetSetup_Confirm = { 4<<16, 16<<16, 112<<16 }; static MenuEntryFormat_t MEF_NetSetup_Confirm = { 4<<16, 16<<16, 112<<16 };
@ -1110,14 +1110,18 @@ static MenuEntry_t *MEL_SCREENSETUP[] = {
// Save and load will be filled in before every viewing of the save/load screen. // Save and load will be filled in before every viewing of the save/load screen.
static MenuLink_t MEO_LOAD = { MENU_LOADVERIFY, MA_None, }; static MenuLink_t MEO_LOAD = { MENU_LOADVERIFY, MA_None, };
static MenuEntry_t ME_LOAD_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_MinifontSave, &MEF_LoadSave, &MEO_LOAD, Link ); static MenuEntry_t ME_LOAD_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_MinifontSave, &MEF_LoadSave, &MEO_LOAD, Link );
static MenuEntry_t ME_LOAD[MAXSAVEGAMES]; static MenuEntry_t ME_LOAD_EMPTY = MAKE_MENUENTRY( NULL, &MF_MinifontSave, &MEF_LoadSave, nullptr, Dummy );
static MenuEntry_t *MEL_LOAD[MAXSAVEGAMES]; static MenuEntry_t *ME_LOAD;
static MenuEntry_t **MEL_LOAD;
static char const s_NewSaveGame[] = "(New Save Game)";
static MenuString_t MEO_SAVE_TEMPLATE = MAKE_MENUSTRING( NULL, &MF_MinifontSave, MAXSAVEGAMENAME, 0 ); static MenuString_t MEO_SAVE_TEMPLATE = MAKE_MENUSTRING( NULL, &MF_MinifontSave, MAXSAVEGAMENAME, 0 );
static MenuString_t MEO_SAVE[MAXSAVEGAMES]; static MenuString_t MEO_SAVE_NEW = MAKE_MENUSTRING( NULL, &MF_MinifontSave, MAXSAVEGAMENAME, 0 );
static MenuString_t *MEO_SAVE;
static MenuEntry_t ME_SAVE_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_MinifontSave, &MEF_LoadSave, &MEO_SAVE_TEMPLATE, String ); static MenuEntry_t ME_SAVE_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_MinifontSave, &MEF_LoadSave, &MEO_SAVE_TEMPLATE, String );
static MenuEntry_t ME_SAVE[MAXSAVEGAMES]; static MenuEntry_t ME_SAVE_NEW = MAKE_MENUENTRY( s_NewSaveGame, &MF_MinifontSave, &MEF_LoadSave, &MEO_SAVE_NEW, String );
static MenuEntry_t *MEL_SAVE[MAXSAVEGAMES]; static MenuEntry_t *ME_SAVE;
static MenuEntry_t **MEL_SAVE;
static int32_t soundrate, soundvoices; static int32_t soundrate, soundvoices;
static MenuOption_t MEO_SOUND = MAKE_MENUOPTION( &MF_Redfont, &MEOS_OffOn, &ud.config.SoundToggle ); static MenuOption_t MEO_SOUND = MAKE_MENUOPTION( &MF_Redfont, &MEOS_OffOn, &ud.config.SoundToggle );
@ -1221,7 +1225,7 @@ static MenuEntry_t *MEL_PLAYER[] = {
}; };
static MenuString_t MEO_MACROS_TEMPLATE = MAKE_MENUSTRING( NULL, &MF_Bluefont, MAXRIDECULELENGTH, 0 ); static MenuString_t MEO_MACROS_TEMPLATE = MAKE_MENUSTRING( NULL, &MF_Bluefont, MAXRIDECULELENGTH, 0 );
static MenuString_t MEO_MACROS[MAXSAVEGAMES]; static MenuString_t MEO_MACROS[10];
static MenuEntry_t ME_MACROS_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_Bluefont, &MEF_Macros, &MEO_MACROS_TEMPLATE, String ); static MenuEntry_t ME_MACROS_TEMPLATE = MAKE_MENUENTRY( NULL, &MF_Bluefont, &MEF_Macros, &MEO_MACROS_TEMPLATE, String );
static MenuEntry_t ME_MACROS[MAXRIDECULE]; static MenuEntry_t ME_MACROS[MAXRIDECULE];
static MenuEntry_t *MEL_MACROS[MAXRIDECULE]; static MenuEntry_t *MEL_MACROS[MAXRIDECULE];
@ -1299,6 +1303,7 @@ static MenuEntry_t *MEL_NETJOIN[] = {
#define NoTitle NULL #define NoTitle NULL
#define MAKE_MENUMENU(Title, Format, Entries) { Title, Format, Entries, ARRAY_SIZE(Entries), 0, 0, 0 } #define MAKE_MENUMENU(Title, Format, Entries) { Title, Format, Entries, ARRAY_SIZE(Entries), 0, 0, 0 }
#define MAKE_MENUMENU_CUSTOMSIZE(Title, Format, Entries) { Title, Format, Entries, 0, 0, 0, 0 }
static MenuMenu_t M_MAIN = MAKE_MENUMENU( NoTitle, &MMF_Top_Main, MEL_MAIN ); static MenuMenu_t M_MAIN = MAKE_MENUMENU( NoTitle, &MMF_Top_Main, MEL_MAIN );
static MenuMenu_t M_MAIN_INGAME = MAKE_MENUMENU( NoTitle, &MMF_Top_Main, MEL_MAIN_INGAME ); static MenuMenu_t M_MAIN_INGAME = MAKE_MENUMENU( NoTitle, &MMF_Top_Main, MEL_MAIN_INGAME );
@ -1334,8 +1339,8 @@ static MenuMenu_t M_RENDERERSETUP_POLYMER = MAKE_MENUMENU("Polymer Setup", &MMF_
static MenuMenu_t M_COLCORR = MAKE_MENUMENU( "Color Correction", &MMF_ColorCorrect, MEL_COLCORR ); static MenuMenu_t M_COLCORR = MAKE_MENUMENU( "Color Correction", &MMF_ColorCorrect, MEL_COLCORR );
static MenuMenu_t M_SCREENSETUP = MAKE_MENUMENU( "HUD Setup", &MMF_BigOptions, MEL_SCREENSETUP ); static MenuMenu_t M_SCREENSETUP = MAKE_MENUMENU( "HUD Setup", &MMF_BigOptions, MEL_SCREENSETUP );
static MenuMenu_t M_DISPLAYSETUP = MAKE_MENUMENU( "Display Setup", &MMF_BigOptions, MEL_DISPLAYSETUP ); static MenuMenu_t M_DISPLAYSETUP = MAKE_MENUMENU( "Display Setup", &MMF_BigOptions, MEL_DISPLAYSETUP );
static MenuMenu_t M_LOAD = MAKE_MENUMENU( s_LoadGame, &MMF_LoadSave, MEL_LOAD ); static MenuMenu_t M_LOAD = MAKE_MENUMENU_CUSTOMSIZE( s_LoadGame, &MMF_LoadSave, MEL_LOAD );
static MenuMenu_t M_SAVE = MAKE_MENUMENU( s_SaveGame, &MMF_LoadSave, MEL_SAVE ); static MenuMenu_t M_SAVE = MAKE_MENUMENU_CUSTOMSIZE( s_SaveGame, &MMF_LoadSave, MEL_SAVE );
static MenuMenu_t M_SOUND = MAKE_MENUMENU( "Sound Setup", &MMF_BigOptions, MEL_SOUND ); static MenuMenu_t M_SOUND = MAKE_MENUMENU( "Sound Setup", &MMF_BigOptions, MEL_SOUND );
static MenuMenu_t M_ADVSOUND = MAKE_MENUMENU( "Advanced Sound", &MMF_BigOptions, MEL_ADVSOUND ); static MenuMenu_t M_ADVSOUND = MAKE_MENUMENU( "Advanced Sound", &MMF_BigOptions, MEL_ADVSOUND );
static MenuMenu_t M_NETWORK = MAKE_MENUMENU( "Network Game", &MMF_Top_Joystick_Network, MEL_NETWORK ); static MenuMenu_t M_NETWORK = MAKE_MENUMENU( "Network Game", &MMF_Top_Joystick_Network, MEL_NETWORK );
@ -1490,6 +1495,29 @@ static void MenuEntry_LookDisabledOnCondition(MenuEntry_t * const entry, const i
entry->flags &= ~MEF_LookDisabled; entry->flags &= ~MEF_LookDisabled;
} }
static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *currentry, int32_t state, const vec2_t origin, bool actually_draw = true);
static void Menu_EntryFocus(/*MenuEntry_t *entry*/);
static MenuEntry_t *Menu_AdjustForCurrentEntryAssignment(MenuMenu_t *menu)
{
MenuEntry_t *currentry = menu->entrylist[menu->currentEntry];
Menu_EntryFocus(/*currentry*/);
if (currentry->ybottom - menu->scrollPos > klabs(menu->format->bottomcutoff))
menu->scrollPos = currentry->ybottom - klabs(menu->format->bottomcutoff);
else if (currentry->ytop - menu->scrollPos < menu->format->pos.y)
menu->scrollPos = currentry->ytop - menu->format->pos.y;
return currentry;
}
static MenuEntry_t *Menu_AdjustForCurrentEntryAssignmentBlind(MenuMenu_t *menu)
{
M_RunMenu_Menu(nullptr, menu, nullptr, 0, { 0, 0 }, false);
return Menu_AdjustForCurrentEntryAssignment(menu);
}
/* /*
This function prepares data after ART and CON have been processed. This function prepares data after ART and CON have been processed.
It also initializes some data in loops rather than statically at compile time. It also initializes some data in loops rather than statically at compile time.
@ -1606,6 +1634,7 @@ void Menu_Init(void)
MEOSN_NetSkills[g_skillCnt] = MenuSkillNone; MEOSN_NetSkills[g_skillCnt] = MenuSkillNone;
MMF_Top_Skill.pos.y = (58 + (4-g_skillCnt)*6)<<16; MMF_Top_Skill.pos.y = (58 + (4-g_skillCnt)*6)<<16;
M_SKILL.currentEntry = 1; M_SKILL.currentEntry = 1;
Menu_AdjustForCurrentEntryAssignmentBlind(&M_SKILL);
// prepare multiplayer gametypes // prepare multiplayer gametypes
k = -1; k = -1;
@ -1620,20 +1649,6 @@ void Menu_Init(void)
if (NAM_WW2GI) if (NAM_WW2GI)
ME_NETOPTIONS_MONSTERS.name = "Enemies"; ME_NETOPTIONS_MONSTERS.name = "Enemies";
// prepare savegames
for (i = 0; i < MAXSAVEGAMES; ++i)
{
MEL_LOAD[i] = &ME_LOAD[i];
MEL_SAVE[i] = &ME_SAVE[i];
ME_LOAD[i] = ME_LOAD_TEMPLATE;
ME_SAVE[i] = ME_SAVE_TEMPLATE;
ME_SAVE[i].entry = &MEO_SAVE[i];
MEO_SAVE[i] = MEO_SAVE_TEMPLATE;
ME_LOAD[i].name = ud.savegame[i];
MEO_SAVE[i].variable = ud.savegame[i];
}
// prepare text chat macros // prepare text chat macros
for (i = 0; i < MAXRIDECULE; ++i) for (i = 0; i < MAXRIDECULE; ++i)
{ {
@ -1791,6 +1806,7 @@ void Menu_Init(void)
static void Menu_Run(Menu_t *cm, vec2_t origin); static void Menu_Run(Menu_t *cm, vec2_t origin);
static void Menu_BlackRectangle(int32_t x, int32_t y, int32_t width, int32_t height, int32_t orientation);
/* /*
At present, no true difference is planned between Menu_Pre() and Menu_PreDraw(). At present, no true difference is planned between Menu_Pre() and Menu_PreDraw().
@ -2113,24 +2129,36 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
#ifndef EDUKE32_ANDROID_MENU #ifndef EDUKE32_ANDROID_MENU
"\n(Y/N)" "\n(Y/N)"
#endif #endif
, ud.savegame[g_lastSaveSlot]); , g_quickload->name);
mgametextcenter(origin.x, origin.y + (90<<16), tempbuf); mgametextcenter(origin.x, origin.y + (90<<16), tempbuf);
break; break;
case MENU_LOAD: case MENU_LOAD:
{
#if 0
for (i = 0; i <= 108; i += 12) for (i = 0; i <= 108; i += 12)
rotatesprite_fs(origin.x + ((160+64+91-64)<<16), origin.y + ((i+56)<<16), 65536L,0,TEXTBOX,24,0,10); rotatesprite_fs(origin.x + ((160+64+91-64)<<16), origin.y + ((i+56)<<16), 65536L,0,TEXTBOX,24,0,10);
#endif
Menu_BlackRectangle(origin.x + (198<<16), origin.y + (47<<16), 102<<16, 100<<16, 1|32);
rotatesprite_fs(origin.x + (22<<16), origin.y + (97<<16), 65536L,0,WINDOWBORDER2,24,0,10); rotatesprite_fs(origin.x + (22<<16), origin.y + (97<<16), 65536L,0,WINDOWBORDER2,24,0,10);
rotatesprite_fs(origin.x + (180<<16), origin.y + (97<<16), 65536L,1024,WINDOWBORDER2,24,0,10); rotatesprite_fs(origin.x + (180<<16), origin.y + (97<<16), 65536L,1024,WINDOWBORDER2,24,0,10);
rotatesprite_fs(origin.x + (99<<16), origin.y + (50<<16), 65536L,512,WINDOWBORDER1,24,0,10); rotatesprite_fs(origin.x + (99<<16), origin.y + (50<<16), 65536L,512,WINDOWBORDER1,24,0,10);
rotatesprite_fs(origin.x + (103<<16), origin.y + (144<<16), 65536L,1024+512,WINDOWBORDER1,24,0,10); rotatesprite_fs(origin.x + (103<<16), origin.y + (144<<16), 65536L,1024+512,WINDOWBORDER1,24,0,10);
if (ud.savegame[M_LOAD.currentEntry][0]) if (M_LOAD.currentEntry >= (int32_t)g_nummenusaves)
{
mmenutext(origin.x + (72<<16), origin.y + (100<<16), "Empty");
break;
}
menusave_t & msv = g_menusaves[M_LOAD.currentEntry];
if (msv.brief.isValid())
{ {
rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536>>1,512,TILE_LOADSHOT,-32,0,4+10+64); rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536>>1,512,TILE_LOADSHOT,-32,0,4+10+64);
if (g_oldverSavegame[M_LOAD.currentEntry]) if (msv.isOldVer)
{ {
mmenutext(origin.x + (53<<16), origin.y + (70<<16), "Previous"); mmenutext(origin.x + (53<<16), origin.y + (70<<16), "Previous");
mmenutext(origin.x + (58<<16), origin.y + (90<<16), "Version"); mmenutext(origin.x + (58<<16), origin.y + (90<<16), "Version");
@ -2160,13 +2188,16 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
if (savehead.volnum == 0 && savehead.levnum == 7) if (savehead.volnum == 0 && savehead.levnum == 7)
mgametextcenter(origin.x, origin.y + (180<<16), savehead.boardfn); mgametextcenter(origin.x, origin.y + (180<<16), savehead.boardfn);
} }
else
mmenutext(origin.x + (69<<16), origin.y + (70<<16), "Empty");
break; break;
}
case MENU_SAVE: case MENU_SAVE:
{
#if 0
for (i = 0; i <= 108; i += 12) for (i = 0; i <= 108; i += 12)
rotatesprite_fs(origin.x + ((160+64+91-64)<<16), origin.y + ((i+56)<<16), 65536L,0,TEXTBOX,24,0,10); rotatesprite_fs(origin.x + ((160+64+91-64)<<16), origin.y + ((i+56)<<16), 65536L,0,TEXTBOX,24,0,10);
#endif
Menu_BlackRectangle(origin.x + (198<<16), origin.y + (47<<16), 102<<16, 100<<16, 1|32);
rotatesprite_fs(origin.x + (22<<16), origin.y + (97<<16), 65536L,0,WINDOWBORDER2,24,0,10); rotatesprite_fs(origin.x + (22<<16), origin.y + (97<<16), 65536L,0,WINDOWBORDER2,24,0,10);
rotatesprite_fs(origin.x + (180<<16), origin.y + (97<<16), 65536L,1024,WINDOWBORDER2,24,0,10); rotatesprite_fs(origin.x + (180<<16), origin.y + (97<<16), 65536L,1024,WINDOWBORDER2,24,0,10);
@ -2174,31 +2205,36 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
rotatesprite_fs(origin.x + (103<<16), origin.y + (144<<16), 65536L,1024+512,WINDOWBORDER1,24,0,10); rotatesprite_fs(origin.x + (103<<16), origin.y + (144<<16), 65536L,1024+512,WINDOWBORDER1,24,0,10);
j = 0; j = 0;
for (i = 0; i < 10; ++i) for (size_t k = 0; k < g_nummenusaves+1; ++k)
if (((MenuString_t*)M_SAVE.entrylist[i]->entry)->editfield) if (((MenuString_t*)M_SAVE.entrylist[k]->entry)->editfield)
j |= 1; j |= 1;
if (j) if (j)
rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_SAVESHOT,-32,0,4+10+64); rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_SAVESHOT,-32,0,4+10+64);
else if (ud.savegame[M_SAVE.currentEntry][0]) else if (0 < M_SAVE.currentEntry && M_SAVE.currentEntry <= (int32_t)g_nummenusaves)
rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_LOADSHOT,-32,0,4+10+64);
else
mmenutext(origin.x + (69<<16), origin.y + (70<<16), "Empty");
if (ud.savegame[M_SAVE.currentEntry][0] && g_oldverSavegame[M_SAVE.currentEntry])
{ {
mmenutext(origin.x + (53<<16), origin.y + (70<<16), "Previous"); if (g_menusaves[M_SAVE.currentEntry-1].brief.isValid())
mmenutext(origin.x + (58<<16), origin.y + (90<<16), "Version"); {
rotatesprite_fs(origin.x + (101<<16), origin.y + (97<<16), 65536L>>1,512,TILE_LOADSHOT,-32,0,4+10+64);
if (g_menusaves[M_SAVE.currentEntry-1].isOldVer)
{
mmenutext(origin.x + (53<<16), origin.y + (70<<16), "Previous");
mmenutext(origin.x + (58<<16), origin.y + (90<<16), "Version");
#ifndef EDUKE32_SIMPLE_MENU #ifndef EDUKE32_SIMPLE_MENU
Bsprintf(tempbuf,"Saved: %d.%d.%d %d-bit", savehead.majorver, savehead.minorver, Bsprintf(tempbuf,"Saved: %d.%d.%d %d-bit", savehead.majorver, savehead.minorver,
savehead.bytever, 8*savehead.ptrsize); savehead.bytever, 8*savehead.ptrsize);
mgametext(origin.x + (31<<16), origin.y + (104<<16), tempbuf); mgametext(origin.x + (31<<16), origin.y + (104<<16), tempbuf);
Bsprintf(tempbuf,"Our: %d.%d.%d %d-bit", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, Bsprintf(tempbuf,"Our: %d.%d.%d %d-bit", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION,
(int32_t)(8*sizeof(intptr_t))); (int32_t)(8*sizeof(intptr_t)));
mgametext(origin.x + ((31+16)<<16), origin.y + (114<<16), tempbuf); mgametext(origin.x + ((31+16)<<16), origin.y + (114<<16), tempbuf);
#endif #endif
}
}
} }
else
mmenutext(origin.x + (82<<16), origin.y + (100<<16), "New");
if (ud.multimode > 1) if (ud.multimode > 1)
{ {
@ -2211,6 +2247,7 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
if (ud.volume_number == 0 && ud.level_number == 7) if (ud.volume_number == 0 && ud.level_number == 7)
mgametextcenter(origin.x, origin.y + (180<<16), currentboardfilename); mgametextcenter(origin.x, origin.y + (180<<16), currentboardfilename);
break; break;
}
#ifdef EDUKE32_ANDROID_MENU #ifdef EDUKE32_ANDROID_MENU
case MENU_SKILL: case MENU_SKILL:
@ -2223,8 +2260,10 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
#endif #endif
case MENU_LOADVERIFY: case MENU_LOADVERIFY:
{
fade_screen_black(1); fade_screen_black(1);
if (g_oldverSavegame[M_LOAD.currentEntry]) menusave_t & msv = g_menusaves[M_LOAD.currentEntry];
if (msv.isOldVer)
{ {
Bsprintf(tempbuf, "Start new game:\n%s / %s" Bsprintf(tempbuf, "Start new game:\n%s / %s"
#ifndef EDUKE32_ANDROID_MENU #ifndef EDUKE32_ANDROID_MENU
@ -2239,10 +2278,11 @@ static void Menu_PreDraw(MenuID_t cm, MenuEntry_t *entry, const vec2_t origin)
#ifndef EDUKE32_ANDROID_MENU #ifndef EDUKE32_ANDROID_MENU
"\n(Y/N)" "\n(Y/N)"
#endif #endif
, ud.savegame[M_LOAD.currentEntry]); , msv.brief.name);
mgametextcenter(origin.x, origin.y + (90<<16), tempbuf); mgametextcenter(origin.x, origin.y + (90<<16), tempbuf);
} }
break; break;
}
case MENU_SAVEVERIFY: case MENU_SAVEVERIFY:
fade_screen_black(1); fade_screen_black(1);
@ -2619,10 +2659,21 @@ static void Menu_EntryFocus(/*MenuEntry_t *entry*/)
switch (g_currentMenu) switch (g_currentMenu)
{ {
case MENU_LOAD: case MENU_LOAD:
G_LoadSaveHeaderNew(M_LOAD.currentEntry, &savehead); if (M_LOAD.currentEntry < (int32_t)g_nummenusaves)
{
savebrief_t & sv = g_menusaves[M_LOAD.currentEntry].brief;
if (sv.isValid())
G_LoadSaveHeaderNew(sv.path, &savehead);
}
break; break;
case MENU_SAVE: case MENU_SAVE:
G_LoadSaveHeaderNew(M_SAVE.currentEntry, &savehead); if (0 < M_SAVE.currentEntry && M_SAVE.currentEntry <= (int32_t)g_nummenusaves)
{
savebrief_t & sv = g_menusaves[M_SAVE.currentEntry-1].brief;
if (sv.isValid())
G_LoadSaveHeaderNew(sv.path, &savehead);
}
break; break;
default: default:
@ -3131,10 +3182,19 @@ static void Menu_EntryStringActivate(/*MenuEntry_t *entry*/)
switch (g_currentMenu) switch (g_currentMenu)
{ {
case MENU_SAVE: case MENU_SAVE:
if (!save_xxh) if (M_SAVE.currentEntry > 0)
save_xxh = XXH32((uint8_t *)&ud.savegame[M_SAVE.currentEntry][0], MAXSAVEGAMENAME, 0xDEADBEEF); {
if (ud.savegame[M_SAVE.currentEntry][0]) savebrief_t & sv = g_menusaves[M_SAVE.currentEntry-1].brief;
Menu_Change(MENU_SAVEVERIFY); if (!save_xxh)
save_xxh = XXH32((uint8_t *)sv.name, MAXSAVEGAMENAME, 0xDEADBEEF);
if (sv.isValid())
Menu_Change(MENU_SAVEVERIFY);
}
else
{
ME_SAVE_NEW.name = nullptr;
save_xxh = 0;
}
break; break;
default: default:
@ -3142,41 +3202,44 @@ static void Menu_EntryStringActivate(/*MenuEntry_t *entry*/)
} }
} }
static int32_t Menu_EntryStringSubmit(MenuEntry_t *entry, char *input) static int32_t Menu_EntryStringSubmit(/*MenuEntry_t *entry, */char *input)
{ {
MenuString_t *object = (MenuString_t*)entry->entry;
int32_t returnvar = 0; int32_t returnvar = 0;
switch (g_currentMenu) switch (g_currentMenu)
{ {
case MENU_SAVE: case MENU_SAVE:
{
savebrief_t & sv = g_lastusersave = M_SAVE.currentEntry == 0 ? savebrief_t{input} : g_menusaves[M_SAVE.currentEntry-1].brief;
// dirty hack... char 127 in last position indicates an auto-filled name // dirty hack... char 127 in last position indicates an auto-filled name
#ifdef __ANDROID__ #ifdef __ANDROID__
if (1) if (1)
#else #else
if (input[0] == 0 || (ud.savegame[M_SAVE.currentEntry][MAXSAVEGAMENAME] == 127 && if (input[0] == 0 || (sv.name[MAXSAVEGAMENAME] == 127 &&
Bstrncmp(&ud.savegame[M_SAVE.currentEntry][0], input, MAXSAVEGAMENAME) == 0 && strncmp(sv.name, input, MAXSAVEGAMENAME) == 0 &&
save_xxh == XXH32((uint8_t *)&ud.savegame[M_SAVE.currentEntry][0], MAXSAVEGAMENAME, 0xDEADBEEF))) save_xxh == XXH32((uint8_t *)sv.name, MAXSAVEGAMENAME, 0xDEADBEEF)))
#endif #endif
{ {
Bstrncpy(&ud.savegame[M_SAVE.currentEntry][0], g_mapInfo[ud.volume_number * MAXLEVELS + ud.level_number].name, MAXSAVEGAMENAME); strncpy(sv.name, g_mapInfo[ud.volume_number * MAXLEVELS + ud.level_number].name, MAXSAVEGAMENAME);
ud.savegame[M_SAVE.currentEntry][MAXSAVEGAMENAME] = 127; sv.name[MAXSAVEGAMENAME] = 127;
returnvar = -1; returnvar = -1;
} }
else else
{ {
ud.savegame[M_SAVE.currentEntry][MAXSAVEGAMENAME] = 0; strncpy(sv.name, input, MAXSAVEGAMENAME);
Bstrncpy(object->variable, input, object->bufsize); sv.name[MAXSAVEGAMENAME] = 0;
} }
G_SavePlayerMaybeMulti(M_SAVE.currentEntry); G_SavePlayerMaybeMulti(sv);
g_lastSaveSlot = M_SAVE.currentEntry; g_quickload = &sv;
g_player[myconnectindex].ps->gm = MODE_GAME; g_player[myconnectindex].ps->gm = MODE_GAME;
Menu_Change(MENU_CLOSE); Menu_Change(MENU_CLOSE);
save_xxh = 0; save_xxh = 0;
break; break;
}
default: default:
break; break;
@ -3191,7 +3254,7 @@ static void Menu_EntryStringCancel(/*MenuEntry_t *entry*/)
{ {
case MENU_SAVE: case MENU_SAVE:
save_xxh = 0; save_xxh = 0;
ReadSaveGameHeaders(); ME_SAVE_NEW.name = s_NewSaveGame;
break; break;
default: default:
@ -3226,7 +3289,7 @@ static void Menu_Verify(int32_t input)
FX_StopAllSounds(); FX_StopAllSounds();
S_ClearSoundLocks(); S_ClearSoundLocks();
G_LoadPlayerMaybeMulti(g_lastSaveSlot); G_LoadPlayerMaybeMulti(*g_quickload);
} }
else else
{ {
@ -3243,14 +3306,26 @@ static void Menu_Verify(int32_t input)
case MENU_LOADVERIFY: case MENU_LOADVERIFY:
if (input) if (input)
{ {
g_lastSaveSlot = M_LOAD.currentEntry; savebrief_t & sv = g_menusaves[M_LOAD.currentEntry].brief;
if (strcmp(sv.path, g_lastusersave.path) != 0)
{
g_freshload = sv;
g_lastusersave.reset();
g_lastautosave.reset();
g_quickload = &g_freshload;
}
else
{
g_quickload = &g_lastusersave;
}
KB_FlushKeyboardQueue(); KB_FlushKeyboardQueue();
KB_ClearKeysDown(); KB_ClearKeysDown();
Menu_Change(MENU_CLOSE); Menu_Change(MENU_CLOSE);
G_LoadPlayerMaybeMulti(g_lastSaveSlot); G_LoadPlayerMaybeMulti(sv);
} }
break; break;
@ -3258,7 +3333,6 @@ static void Menu_Verify(int32_t input)
if (!input) if (!input)
{ {
save_xxh = 0; save_xxh = 0;
ReadSaveGameHeaders();
((MenuString_t*)M_SAVE.entrylist[M_SAVE.currentEntry]->entry)->editfield = NULL; ((MenuString_t*)M_SAVE.entrylist[M_SAVE.currentEntry]->entry)->editfield = NULL;
} }
@ -3629,6 +3703,7 @@ static void Menu_MaybeSetSelectionToChild(Menu_t * m, MenuID_t id)
if (link->linkID == id) if (link->linkID == id)
{ {
menu->currentEntry = i; menu->currentEntry = i;
Menu_AdjustForCurrentEntryAssignmentBlind(menu);
break; break;
} }
} }
@ -3636,6 +3711,43 @@ static void Menu_MaybeSetSelectionToChild(Menu_t * m, MenuID_t id)
} }
} }
static void Menu_ReadSaveGameHeaders()
{
ReadSaveGameHeaders();
size_t const numloaditems = max(g_nummenusaves, 1), numsaveitems = g_nummenusaves+1;
ME_LOAD = (MenuEntry_t *)realloc(ME_LOAD, g_nummenusaves * sizeof(MenuEntry_t));
MEL_LOAD = (MenuEntry_t **)realloc(MEL_LOAD, numloaditems * sizeof(MenuEntry_t *));
MEO_SAVE = (MenuString_t *)realloc(MEO_SAVE, g_nummenusaves * sizeof(MenuString_t));
ME_SAVE = (MenuEntry_t *)realloc(ME_SAVE, g_nummenusaves * sizeof(MenuEntry_t));
MEL_SAVE = (MenuEntry_t **)realloc(MEL_SAVE, numsaveitems * sizeof(MenuEntry_t *));
MEL_SAVE[0] = &ME_SAVE_NEW;
ME_SAVE_NEW.name = s_NewSaveGame;
for (size_t i = 0; i < g_nummenusaves; ++i)
{
MEL_LOAD[i] = &ME_LOAD[i];
MEL_SAVE[i+1] = &ME_SAVE[i];
ME_LOAD[i] = ME_LOAD_TEMPLATE;
ME_SAVE[i] = ME_SAVE_TEMPLATE;
ME_SAVE[i].entry = &MEO_SAVE[i];
MEO_SAVE[i] = MEO_SAVE_TEMPLATE;
ME_LOAD[i].name = g_menusaves[i].brief.name;
MEO_SAVE[i].variable = g_menusaves[i].brief.name;
}
if (g_nummenusaves == 0)
MEL_LOAD[0] = &ME_LOAD_EMPTY;
M_LOAD.entrylist = MEL_LOAD;
M_LOAD.numEntries = numloaditems;
M_SAVE.entrylist = MEL_SAVE;
M_SAVE.numEntries = numsaveitems;
// lexicographical sorting?
}
static void Menu_AboutToStartDisplaying(Menu_t * m) static void Menu_AboutToStartDisplaying(Menu_t * m)
{ {
switch (m->menuID) switch (m->menuID)
@ -3653,22 +3765,47 @@ static void Menu_AboutToStartDisplaying(Menu_t * m)
case MENU_LOAD: case MENU_LOAD:
if (KXDWN) if (KXDWN)
M_LOAD.title = (g_player[myconnectindex].ps->gm & MODE_GAME) ? s_LoadGame : s_Continue; M_LOAD.title = (g_player[myconnectindex].ps->gm & MODE_GAME) ? s_LoadGame : s_Continue;
for (size_t i = 0; i < MAXSAVEGAMES; ++i)
{
MenuEntry_DisableOnCondition(&ME_LOAD[i], !ud.savegame[i][0] /*|| g_oldverSavegame[i]*/);
MenuEntry_LookDisabledOnCondition(&ME_LOAD[i], g_oldverSavegame[i]);
}
if (g_lastSaveSlot >= 0 && g_previousMenu != MENU_LOADVERIFY) Menu_ReadSaveGameHeaders();
M_LOAD.currentEntry = g_lastSaveSlot;
for (size_t i = 0; i < g_nummenusaves; ++i)
MenuEntry_LookDisabledOnCondition(&ME_LOAD[i], g_menusaves[i].isOldVer);
if (g_quickload && g_quickload->isValid())
{
for (size_t i = 0; i < g_nummenusaves; ++i)
{
if (strcmp(g_menusaves[i].brief.path, g_quickload->path) == 0)
{
M_LOAD.currentEntry = i;
Menu_AdjustForCurrentEntryAssignmentBlind(&M_LOAD);
break;
}
}
}
break; break;
case MENU_SAVE: case MENU_SAVE:
if (g_lastSaveSlot >= 0 && g_previousMenu != MENU_SAVEVERIFY) if (g_previousMenu == MENU_SAVEVERIFY)
M_SAVE.currentEntry = g_lastSaveSlot; break;
for (size_t i = 0; i < MAXSAVEGAMES; ++i) Menu_ReadSaveGameHeaders();
MenuEntry_LookDisabledOnCondition(&ME_SAVE[i], g_oldverSavegame[i]);
if (g_lastusersave.isValid())
{
for (size_t i = 0; i < g_nummenusaves; ++i)
{
if (strcmp(g_menusaves[i].brief.path, g_lastusersave.path) == 0)
{
M_SAVE.currentEntry = i+1;
Menu_AdjustForCurrentEntryAssignmentBlind(&M_SAVE);
break;
}
}
}
for (size_t i = 0; i < g_nummenusaves; ++i)
MenuEntry_LookDisabledOnCondition(&ME_SAVE[i], g_menusaves[i].isOldVer);
if (g_player[myconnectindex].ps->gm&MODE_GAME) if (g_player[myconnectindex].ps->gm&MODE_GAME)
{ {
@ -4162,13 +4299,13 @@ static void Menu_RunInput_EntryRangeDouble_MovementArbitrary(/*MenuEntry_t *entr
static void Menu_RunInput_EntryRangeDouble_Movement(/*MenuEntry_t *entry, */MenuRangeDouble_t *object, MenuMovement_t direction); static void Menu_RunInput_EntryRangeDouble_Movement(/*MenuEntry_t *entry, */MenuRangeDouble_t *object, MenuMovement_t direction);
#endif #endif
static void Menu_RunInput_EntryString_Activate(MenuEntry_t *entry); static void Menu_RunInput_EntryString_Activate(MenuEntry_t *entry);
static void Menu_RunInput_EntryString_Submit(MenuEntry_t *entry, MenuString_t *object); static void Menu_RunInput_EntryString_Submit(/*MenuEntry_t *entry, */MenuString_t *object);
static void Menu_RunInput_EntryString_Cancel(/*MenuEntry_t *entry, */MenuString_t *object); static void Menu_RunInput_EntryString_Cancel(/*MenuEntry_t *entry, */MenuString_t *object);
static void Menu_RunInput_FileSelect_MovementVerify(MenuFileSelect_t *object); static void Menu_RunInput_FileSelect_MovementVerify(MenuFileSelect_t *object);
static void Menu_RunInput_FileSelect_Movement(MenuFileSelect_t *object, MenuMovement_t direction); static void Menu_RunInput_FileSelect_Movement(MenuFileSelect_t *object, MenuMovement_t direction);
static void Menu_RunInput_FileSelect_Select(MenuFileSelect_t *object); static void Menu_RunInput_FileSelect_Select(MenuFileSelect_t *object);
static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *currentry, int32_t state, const vec2_t origin) static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *currentry, int32_t state, const vec2_t origin, bool actually_draw)
{ {
int32_t totalHeight = 0; int32_t totalHeight = 0;
@ -4245,7 +4382,9 @@ static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *current
if (entry->format->width == 0) if (entry->format->width == 0)
status |= MT_XCenter; status |= MT_XCenter;
const int32_t dodraw = entry->type != Spacer && 0 <= y - menu->scrollPos + entry->font->get_yline() && y - menu->scrollPos <= klabs(menu->format->bottomcutoff) - menu->format->pos.y; bool const dodraw = entry->type != Spacer && actually_draw &&
0 <= y - menu->scrollPos + entry->font->get_yline() &&
y - menu->scrollPos <= klabs(menu->format->bottomcutoff) - menu->format->pos.y;
int32_t const height = entry->getHeight(); // max(textsize.y, entry->font->get_yline()); // bluefont Q ruins this int32_t const height = entry->getHeight(); // max(textsize.y, entry->font->get_yline()); // bluefont Q ruins this
status |= MT_YCenter; status |= MT_YCenter;
@ -4763,7 +4902,7 @@ static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *current
{ {
if (entry == currentry && object->editfield != NULL) if (entry == currentry && object->editfield != NULL)
{ {
Menu_RunInput_EntryString_Submit(entry, object); Menu_RunInput_EntryString_Submit(/*entry, */object);
S_PlaySound(PISTOL_BODYHIT); S_PlaySound(PISTOL_BODYHIT);
@ -4797,7 +4936,8 @@ static int32_t M_RunMenu_Menu(Menu_t *cm, MenuMenu_t *menu, MenuEntry_t *current
} }
// draw indicators if applicable // draw indicators if applicable
Menu_RunScrollbar(cm, menu->format, y_upper + totalHeight, &menu->scrollPos, 320<<16, origin); if (actually_draw)
Menu_RunScrollbar(cm, menu->format, y_upper + totalHeight, &menu->scrollPos, 320<<16, origin);
} }
return totalHeight; return totalHeight;
@ -4847,7 +4987,8 @@ static void Menu_RunOptionList(Menu_t *cm, MenuEntry_t *entry, MenuOption_t *obj
if (object->options->entryFormat->width == 0) if (object->options->entryFormat->width == 0)
status |= MT_XCenter; status |= MT_XCenter;
const int32_t dodraw = 0 <= y - object->options->scrollPos + object->options->font->get_yline() && y - object->options->scrollPos <= object->options->menuFormat->bottomcutoff - object->options->menuFormat->pos.y; bool const dodraw = 0 <= y - object->options->scrollPos + object->options->font->get_yline() &&
y - object->options->scrollPos <= object->options->menuFormat->bottomcutoff - object->options->menuFormat->pos.y;
int32_t const height = object->options->font->get_yline(); // max(textsize.y, object->options->font->get_yline()); int32_t const height = object->options->font->get_yline(); // max(textsize.y, object->options->font->get_yline());
status |= MT_YCenter; status |= MT_YCenter;
@ -5263,20 +5404,14 @@ or else this function will recurse infinitely.
*/ */
static MenuEntry_t *Menu_RunInput_Menu_MovementVerify(MenuMenu_t *menu) static MenuEntry_t *Menu_RunInput_Menu_MovementVerify(MenuMenu_t *menu)
{ {
MenuEntry_t *currentry = menu->entrylist[menu->currentEntry]; return Menu_AdjustForCurrentEntryAssignment(menu);
Menu_EntryFocus(/*currentry*/);
if (currentry->ybottom - menu->scrollPos > klabs(menu->format->bottomcutoff))
menu->scrollPos = currentry->ybottom - klabs(menu->format->bottomcutoff);
else if (currentry->ytop - menu->scrollPos < menu->format->pos.y)
menu->scrollPos = currentry->ytop - menu->format->pos.y;
return currentry;
} }
static MenuEntry_t *Menu_RunInput_Menu_Movement(MenuMenu_t *menu, MenuMovement_t direction) static MenuEntry_t *Menu_RunInput_Menu_Movement(MenuMenu_t *menu, MenuMovement_t direction)
{ {
if (menu->numEntries == 1)
return menu->entrylist[menu->currentEntry];
switch (direction) switch (direction)
{ {
case MM_End: case MM_End:
@ -5631,7 +5766,10 @@ static void Menu_RunInput_EntryString_Activate(MenuEntry_t *entry)
{ {
MenuString_t *object = (MenuString_t*)entry->entry; MenuString_t *object = (MenuString_t*)entry->entry;
Bstrncpy(typebuf, object->variable, TYPEBUFSIZE); if (object->variable)
strncpy(typebuf, object->variable, TYPEBUFSIZE);
else
typebuf[0] = '\0';
object->editfield = typebuf; object->editfield = typebuf;
// this limitation is an arbitrary implementation detail // this limitation is an arbitrary implementation detail
@ -5642,10 +5780,13 @@ static void Menu_RunInput_EntryString_Activate(MenuEntry_t *entry)
WithSDL2_StartTextInput(); WithSDL2_StartTextInput();
} }
static void Menu_RunInput_EntryString_Submit(MenuEntry_t *entry, MenuString_t *object) static void Menu_RunInput_EntryString_Submit(/*MenuEntry_t *entry, */MenuString_t *object)
{ {
if (!Menu_EntryStringSubmit(entry, object->editfield)) if (!Menu_EntryStringSubmit(/*entry, */object->editfield))
Bstrncpy(object->variable, object->editfield, object->bufsize); {
if (object->variable)
strncpy(object->variable, object->editfield, object->bufsize);
}
object->editfield = NULL; object->editfield = NULL;
WithSDL2_StopTextInput(); WithSDL2_StopTextInput();
@ -6249,7 +6390,7 @@ static void Menu_RunInput(Menu_t *cm)
} }
else if (hitstate == 1) else if (hitstate == 1)
{ {
Menu_RunInput_EntryString_Submit(currentry, object); Menu_RunInput_EntryString_Submit(/*currentry, */object);
S_PlaySound(PISTOL_BODYHIT); S_PlaySound(PISTOL_BODYHIT);
} }

View file

@ -447,7 +447,6 @@ extern MenuAnimation_t m_animation;
extern MenuID_t g_currentMenu; extern MenuID_t g_currentMenu;
extern Menu_t *m_currentMenu; extern Menu_t *m_currentMenu;
extern int32_t g_lastSaveSlot;
extern int32_t g_quitDeadline; extern int32_t g_quitDeadline;
extern int32_t voting; extern int32_t voting;
int Menu_Change(int32_t cm); int Menu_Change(int32_t cm);

View file

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "anim.h" #include "anim.h"
#include "menus.h" #include "menus.h"
#include "demo.h" #include "demo.h"
#include "savegame.h"
#ifdef LUNATIC #ifdef LUNATIC
# include "lunatic_game.h" # include "lunatic_game.h"
@ -1413,7 +1414,10 @@ end_vol4a:
ud.from_bonus = 0; ud.from_bonus = 0;
ud.last_level = -1; ud.last_level = -1;
g_lastSaveSlot = -1; g_lastAutoSaveArbitraryID = -1;
g_lastautosave.reset();
g_lastusersave.reset();
g_quickload = nullptr;
#ifdef EDUKE32_TOUCH_DEVICES #ifdef EDUKE32_TOUCH_DEVICES
pPlayer->zoom = 360; pPlayer->zoom = 360;

View file

@ -30,9 +30,9 @@ static int32_t g_savedOK;
const char *g_failedVarname; const char *g_failedVarname;
#endif #endif
extern char *bitptr; static OutputFileCounter savecounter;
uint8_t g_oldverSavegame[MAXSAVEGAMES]; extern char *bitptr;
#define BITPTR_POINTER 1 #define BITPTR_POINTER 1
@ -138,64 +138,88 @@ void G_ResetInterpolations(void)
G_SetInterpolation(g_animatePtr[i]); G_SetInterpolation(g_animatePtr[i]);
} }
void ReadSaveGameHeaders(void) savebrief_t g_lastautosave, g_lastusersave, g_freshload;
{ int32_t g_lastAutoSaveArbitraryID = -1;
char fn[16]; bool g_saveRequested;
int32_t fil, i; savebrief_t * g_quickload;
menusave_t * g_menusaves;
size_t g_nummenusaves;
static void ReadSaveGameHeaders_CACHE1D(CACHE1D_FIND_REC *f)
{
savehead_t h; savehead_t h;
EDUKE32_STATIC_ASSERT(sizeof(h.savename) == sizeof(ud.savegame[0])); for (; f != nullptr; f = f->next)
Bstrcpy(fn, "save0.esv");
for (i=0; i<MAXSAVEGAMES; i++)
{ {
int32_t k; char const * fn = f->name;
int32_t fil = kopen4loadfrommod(fn, 0);
fn[4] = i + '0';
fil = kopen4loadfrommod(fn, 0);
if (fil == -1) if (fil == -1)
{
Bmemset(ud.savegame[i], 0, sizeof(ud.savegame[i]));
continue; continue;
}
k = sv_loadheader(fil, i, &h); menusave_t & msv = g_menusaves[g_nummenusaves];
int32_t k = sv_loadheader(fil, 0, &h);
if (k) if (k)
{ {
// old version, signal to menu code // old version, signal to menu code
if (k > 0) if (k > 0)
g_oldverSavegame[i] = 1; msv.isOldVer = 1;
else
continue;
// else h.savename is all zeros (fatal failure, like wrong header // else h.savename is all zeros (fatal failure, like wrong header
// magic or too short header) // magic or too short header)
} }
else
msv.isOldVer = 0;
if (k >= 0) if (k >= 0 && h.savename[0] != '\0')
Bmemcpy(ud.savegame[i], h.savename, sizeof(ud.savegame[i])); {
memcpy(msv.brief.name, h.savename, ARRAY_SIZE(msv.brief.name));
strncpy(msv.brief.path, fn, ARRAY_SIZE(msv.brief.path));
++g_nummenusaves;
}
kclose(fil); kclose(fil);
} }
} }
int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh) static size_t countcache1dfind(CACHE1D_FIND_REC *f)
{ {
char fn[16]; size_t x = 0;
int32_t fil, screenshotofs, i; for (; f != nullptr; f = f->next)
++x;
return x;
}
Bassert(spot < MAXSAVEGAMES); void ReadSaveGameHeaders(void)
{
static char const DefaultPath[] = "/", SavePattern[] = "*.esv";
Bstrcpy(fn, "save0.esv"); CACHE1D_FIND_REC *findfiles_default = klistpath(DefaultPath, SavePattern, CACHE1D_FIND_FILE);
fn[4] = spot + '0';
fil = kopen4loadfrommod(fn, 0); // potentially overallocating but programmatically simple
size_t const numfiles = countcache1dfind(findfiles_default);
g_menusaves = (menusave_t *)Xrealloc(g_menusaves, sizeof(menusave_t) * numfiles);
g_nummenusaves = 0;
ReadSaveGameHeaders_CACHE1D(findfiles_default);
klistfree(findfiles_default);
}
int32_t G_LoadSaveHeaderNew(char const *fn, savehead_t *saveh)
{
int32_t fil = kopen4loadfrommod(fn, 0);
if (fil == -1) if (fil == -1)
return -1; return -1;
i = sv_loadheader(fil, spot, saveh); int32_t i = sv_loadheader(fil, 0, saveh);
if (i < 0) if (i < 0)
goto corrupt; goto corrupt;
int32_t screenshotofs;
if (kread(fil, &screenshotofs, 4) != 4) if (kread(fil, &screenshotofs, 4) != 4)
goto corrupt; goto corrupt;
@ -208,7 +232,7 @@ int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh)
{ {
if (kdfread((char *)waloff[TILE_LOADSHOT], 320, 200, fil) != 200) if (kdfread((char *)waloff[TILE_LOADSHOT], 320, 200, fil) != 200)
{ {
OSD_Printf("G_LoadSaveHeaderNew(%d): failed reading screenshot\n", spot); OSD_Printf("G_LoadSaveHeaderNew(): failed reading screenshot \"%s\"\n", fn);
goto corrupt; goto corrupt;
} }
} }
@ -230,25 +254,17 @@ corrupt:
static void sv_postudload(); static void sv_postudload();
// XXX: keyboard input 'blocked' after load fail? (at least ESC?) // XXX: keyboard input 'blocked' after load fail? (at least ESC?)
int32_t G_LoadPlayer(int32_t spot) int32_t G_LoadPlayer(savebrief_t & sv)
{ {
char fn[16];
int32_t fil, i;
savehead_t h; savehead_t h;
Bassert(spot < MAXSAVEGAMES); int32_t fil = kopen4loadfrommod(sv.path, 0);
Bstrcpy(fn, "save0.esv");
fn[4] = spot + '0';
fil = kopen4loadfrommod(fn, 0);
if (fil == -1) if (fil == -1)
return -1; return -1;
ready2send = 0; ready2send = 0;
i = sv_loadheader(fil, spot, &h); int32_t i = sv_loadheader(fil, 0, &h);
if ((i < 0) || h.numplayers != ud.multimode) if ((i < 0) || h.numplayers != ud.multimode)
{ {
if (i == -4 || i == -3 || i == 1) if (i == -4 || i == -3 || i == 1)
@ -283,12 +299,6 @@ int32_t G_LoadPlayer(int32_t spot)
FX_StopAllSounds(); FX_StopAllSounds();
S_ClearSoundLocks(); S_ClearSoundLocks();
if (spot >= 0 && numplayers==1)
{
Bmemcpy(ud.savegame[spot], h.savename, sizeof(ud.savegame[0]));
ud.savegame[spot][sizeof(ud.savegame[0])-1] = 0;
}
// non-"m_" fields will be loaded from svgm_udnetw // non-"m_" fields will be loaded from svgm_udnetw
ud.m_volume_number = h.volnum; ud.m_volume_number = h.volnum;
ud.m_level_number = h.levnum; ud.m_level_number = h.levnum;
@ -321,12 +331,12 @@ int32_t G_LoadPlayer(int32_t spot)
else else
{ {
// read the rest... // read the rest...
i = sv_loadsnapshot(fil, spot, &h); i = sv_loadsnapshot(fil, 0, &h);
if (i) if (i)
{ {
// in theory, we could load into an initial dump first and trivially // in theory, we could load into an initial dump first and trivially
// recover if things go wrong... // recover if things go wrong...
Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", fn, i); Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", sv.path, i);
G_GameExit(tempbuf); G_GameExit(tempbuf);
} }
} }
@ -395,44 +405,52 @@ static void G_SavePalette(void)
} }
#endif #endif
int32_t G_SavePlayer(int32_t spot) int32_t G_SavePlayer(savebrief_t & sv)
{ {
char fn[16];
FILE *fil;
#ifdef __ANDROID__ #ifdef __ANDROID__
G_SavePalette(); G_SavePalette();
#endif #endif
Bassert(spot < MAXSAVEGAMES);
G_SaveTimers(); G_SaveTimers();
Bstrcpy(fn, "save0.esv");
fn[4] = spot + '0';
// Bstrcpy(mpfn, "edukA_00.esv");
Net_WaitForServer(); Net_WaitForServer();
ready2send = 0; ready2send = 0;
char temp[BMAX_PATH];
errno = 0;
FILE *fil;
if (sv.isValid())
{ {
char temp[BMAX_PATH]; if (G_ModDirSnprintf(temp, sizeof(temp), "%s", sv.path))
if (G_ModDirSnprintf(temp, sizeof(temp), "%s", fn))
{ {
OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", fn); OSD_Printf("G_SavePlayer: file name \"%s\" too long\n", sv.path);
return -1; goto saveproblem;
} }
errno = 0;
fil = fopen(temp, "wb"); fil = fopen(temp, "wb");
if (!fil) }
else
{
static char const SaveName[] = "save0000.esv";
size_t len = G_ModDirSnprintfLite(temp, sizeof(temp), SaveName);
if (len >= sizeof(temp)-1)
{ {
OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n", OSD_Printf("G_SavePlayer: could not form automatic save path\n");
temp, strerror(errno)); goto saveproblem;
return -1;
} }
char * zeros = temp + (len-8);
fil = savecounter.opennextfile(temp, zeros);
savecounter.count++;
// don't copy the mod dir into sv.path
strcpy(sv.path, temp + (len-(ARRAY_SIZE(SaveName)-1)));
}
if (!fil)
{
OSD_Printf("G_SavePlayer: failed opening \"%s\" for writing: %s\n",
temp, strerror(errno));
goto saveproblem;
} }
#ifdef POLYMER #ifdef POLYMER
@ -443,7 +461,7 @@ int32_t G_SavePlayer(int32_t spot)
VM_OnEvent(EVENT_SAVEGAME, g_player[screenpeek].ps->i, screenpeek); VM_OnEvent(EVENT_SAVEGAME, g_player[screenpeek].ps->i, screenpeek);
// SAVE! // SAVE!
sv_saveandmakesnapshot(fil, spot, 0, 0, 0); sv_saveandmakesnapshot(fil, sv.name, 0, 0, 0, 0);
fclose(fil); fclose(fil);
@ -467,41 +485,46 @@ int32_t G_SavePlayer(int32_t spot)
VM_OnEvent(EVENT_POSTSAVEGAME, g_player[screenpeek].ps->i, screenpeek); VM_OnEvent(EVENT_POSTSAVEGAME, g_player[screenpeek].ps->i, screenpeek);
return 0; return 0;
saveproblem:
ready2send = 1;
Net_WaitForServer();
G_RestoreTimers();
ototalclock = totalclock;
return -1;
} }
void G_LoadPlayerMaybeMulti(int32_t slot) void G_LoadPlayerMaybeMulti(savebrief_t & sv)
{ {
if (g_netServer || ud.multimode > 1) if (g_netServer || ud.multimode > 1)
{ {
Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported"); Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Loading Not Yet Supported");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
// G_LoadPlayer(-1-g_lastSaveSlot);
// g_player[myconnectindex].ps->gm = MODE_GAME; // g_player[myconnectindex].ps->gm = MODE_GAME;
} }
else else
{ {
int32_t c = G_LoadPlayer(slot); int32_t c = G_LoadPlayer(sv);
if (c == 0) if (c == 0)
g_player[myconnectindex].ps->gm = MODE_GAME; g_player[myconnectindex].ps->gm = MODE_GAME;
} }
} }
void G_SavePlayerMaybeMulti(int32_t slot) void G_SavePlayerMaybeMulti(savebrief_t & sv)
{ {
Bassert(slot >= 0);
CONFIG_WriteSetup(2); CONFIG_WriteSetup(2);
if (g_netServer || ud.multimode > 1) if (g_netServer || ud.multimode > 1)
{ {
Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported"); Bstrcpy(apStrings[QUOTE_RESERVED4], "Multiplayer Saving Not Yet Supported");
P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps);
// G_SavePlayer(-1-slot);
} }
else else
{ {
G_SavePlayer(slot); G_SavePlayer(sv);
} }
} }
@ -1283,7 +1306,7 @@ static void SV_AllocSnap(int32_t allocinit)
} }
// make snapshot only if spot < 0 (demo) // make snapshot only if spot < 0 (demo)
int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress) int32_t sv_saveandmakesnapshot(FILE *fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress)
{ {
savehead_t h; savehead_t h;
@ -1338,10 +1361,10 @@ int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t
} }
} }
if ((unsigned)spot < MAXSAVEGAMES) if (spot >= 0)
{ {
// savegame // savegame
Bstrncpyz(h.savename, ud.savegame[spot], sizeof(h.savename)); Bstrncpyz(h.savename, name, sizeof(h.savename));
#ifdef __ANDROID__ #ifdef __ANDROID__
Bstrncpyz(h.volname, g_volumeNames[ud.volume_number], sizeof(h.volname)); Bstrncpyz(h.volname, g_volumeNames[ud.volume_number], sizeof(h.volname));
Bstrncpyz(h.skillname, g_skillNames[ud.player_skill], sizeof(h.skillname)); Bstrncpyz(h.skillname, g_skillNames[ud.player_skill], sizeof(h.skillname));
@ -1414,8 +1437,6 @@ int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t
} }
} }
g_oldverSavegame[spot] = 0;
return 0; return 0;
} }

View file

@ -61,19 +61,55 @@ typedef struct
} savehead_t; } savehead_t;
#pragma pack(pop) #pragma pack(pop)
struct savebrief_t
{
savebrief_t() = default;
savebrief_t(char const *n)
{
strncpy(name, n, MAXSAVEGAMENAME);
}
char name[MAXSAVEGAMENAMESTRUCT];
char path[BMAX_PATH];
void reset()
{
name[0] = '\0';
path[0] = '\0';
}
bool isValid() const
{
return path[0] != '\0';
}
};
struct menusave_t
{
savebrief_t brief;
uint8_t isOldVer = 0;
};
extern savebrief_t g_lastautosave, g_lastusersave, g_freshload;
extern int32_t g_lastAutoSaveArbitraryID;
extern bool g_saveRequested;
extern savebrief_t * g_quickload;
extern menusave_t * g_menusaves;
extern size_t g_nummenusaves;
int32_t sv_updatestate(int32_t frominit); int32_t sv_updatestate(int32_t frominit);
int32_t sv_readdiff(int32_t fil); int32_t sv_readdiff(int32_t fil);
uint32_t sv_writediff(FILE *fil); uint32_t sv_writediff(FILE *fil);
int32_t sv_loadheader(int32_t fil, int32_t spot, savehead_t *h); int32_t sv_loadheader(int32_t fil, int32_t spot, savehead_t *h);
int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h); int32_t sv_loadsnapshot(int32_t fil, int32_t spot, savehead_t *h);
int32_t sv_saveandmakesnapshot(FILE *fil, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress); int32_t sv_saveandmakesnapshot(FILE *fil, char const *name, int8_t spot, int8_t recdiffsp, int8_t diffcompress, int8_t synccompress);
void sv_freemem(); void sv_freemem();
int32_t G_SavePlayer(int32_t spot); int32_t G_SavePlayer(savebrief_t & sv);
int32_t G_LoadPlayer(int32_t spot); int32_t G_LoadPlayer(savebrief_t & sv);
int32_t G_LoadSaveHeaderNew(int32_t spot, savehead_t *saveh); int32_t G_LoadSaveHeaderNew(char const *fn, savehead_t *saveh);
void ReadSaveGameHeaders(void); void ReadSaveGameHeaders(void);
void G_SavePlayerMaybeMulti(int32_t slot); void G_SavePlayerMaybeMulti(savebrief_t & sv);
void G_LoadPlayerMaybeMulti(int32_t slot); void G_LoadPlayerMaybeMulti(savebrief_t & sv);
#ifdef YAX_ENABLE #ifdef YAX_ENABLE
extern void sv_postyaxload(void); extern void sv_postyaxload(void);
@ -82,7 +118,6 @@ extern void sv_postyaxload(void);
// XXX: The 'bitptr' decl really belongs into gamedef.h, but we don't want to // XXX: The 'bitptr' decl really belongs into gamedef.h, but we don't want to
// pull all of it in savegame.c? // pull all of it in savegame.c?
extern char *bitptr; extern char *bitptr;
extern uint8_t g_oldverSavegame[MAXSAVEGAMES];
enum enum
{ {