2019-11-29 23:49:50 +00:00
/*
* * loadsavemenu . cpp
* * The load game and save game menus
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2001 - 2010 Randy Heit
* * Copyright 2010 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# include "menu/menu.h"
# include "version.h"
# include "m_png.h"
# include "filesystem.h"
# include "v_text.h"
# include "d_event.h"
# include "gstrings.h"
# include "d_gui.h"
# include "v_draw.h"
# include "files.h"
# include "resourcefile.h"
# include "sjson.h"
# include "cmdlib.h"
# include "files.h"
# include "savegamehelp.h"
# include "i_specialpaths.h"
2019-11-30 18:23:54 +00:00
# include "c_dispatch.h"
2019-11-29 23:49:50 +00:00
# include "../../platform/win32/i_findfile.h" // This is a temporary direct path. Needs to be fixed when stuff gets cleaned up.
FSavegameManager savegameManager ;
2019-11-30 21:46:00 +00:00
void FSavegameManager : : LoadGame ( FSaveGameNode * node )
2019-11-30 18:23:54 +00:00
{
if ( gi - > LoadGame ( node ) )
2019-11-30 21:46:00 +00:00
{
}
}
void FSavegameManager : : SaveGame ( FSaveGameNode * node , bool ok4q , bool forceq )
{
if ( gi - > SaveGame ( node ) )
2019-11-30 18:23:54 +00:00
{
FString fn = node - > Filename ;
FString desc = node - > SaveTitle ;
NotifyNewSave ( fn , desc , ok4q , forceq ) ;
}
}
2019-11-29 23:49:50 +00:00
//=============================================================================
//
// Save data maintenance
//
//=============================================================================
void FSavegameManager : : ClearSaveGames ( )
{
for ( unsigned i = 0 ; i < SaveGames . Size ( ) ; i + + )
{
if ( ! SaveGames [ i ] - > bNoDelete )
delete SaveGames [ i ] ;
}
SaveGames . Clear ( ) ;
}
FSavegameManager : : ~ FSavegameManager ( )
{
ClearSaveGames ( ) ;
}
//=============================================================================
//
// Save data maintenance
//
//=============================================================================
int FSavegameManager : : RemoveSaveSlot ( int index )
{
int listindex = SaveGames [ 0 ] - > bNoDelete ? index - 1 : index ;
if ( listindex < 0 ) return index ;
remove ( SaveGames [ index ] - > Filename . GetChars ( ) ) ;
UnloadSaveData ( ) ;
FSaveGameNode * file = SaveGames [ index ] ;
if ( quickSaveSlot = = SaveGames [ index ] )
{
quickSaveSlot = nullptr ;
}
if ( ! file - > bNoDelete ) delete file ;
if ( LastSaved = = listindex ) LastSaved = - 1 ;
else if ( LastSaved > listindex ) LastSaved - - ;
if ( LastAccessed = = listindex ) LastAccessed = - 1 ;
else if ( LastAccessed > listindex ) LastAccessed - - ;
SaveGames . Delete ( index ) ;
if ( ( unsigned ) index > = SaveGames . Size ( ) ) index - - ;
ExtractSaveData ( index ) ;
return index ;
}
//=============================================================================
//
//
//
//=============================================================================
int FSavegameManager : : InsertSaveNode ( FSaveGameNode * node )
{
if ( SaveGames . Size ( ) = = 0 )
{
return SaveGames . Push ( node ) ;
}
if ( node - > bOldVersion )
{ // Add node at bottom of list
return SaveGames . Push ( node ) ;
}
else
{ // Add node at top of list
unsigned int i ;
for ( i = 0 ; i < SaveGames . Size ( ) ; i + + )
{
if ( SaveGames [ i ] - > bOldVersion | | node - > SaveTitle . CompareNoCase ( SaveGames [ i ] - > SaveTitle ) < = 0 )
{
break ;
}
}
SaveGames . Insert ( i , node ) ;
return i ;
}
}
//=============================================================================
//
// M_ReadSaveStrings
//
// Find savegames and read their titles
//
//=============================================================================
void FSavegameManager : : ReadSaveStrings ( )
{
if ( SaveGames . Size ( ) = = 0 )
{
void * filefirst ;
findstate_t c_file ;
FString filter ;
LastSaved = LastAccessed = - 1 ;
quickSaveSlot = nullptr ;
filter = G_BuildSaveName ( " * " ) ;
filefirst = I_FindFirst ( filter . GetChars ( ) , & c_file ) ;
if ( filefirst ! = ( ( void * ) ( - 1 ) ) )
{
do
{
// I_FindName only returns the file's name and not its full path
FString filepath = G_BuildSaveName ( I_FindName ( & c_file ) ) ;
FResourceFile * savegame = FResourceFile : : OpenResourceFile ( filepath , true , true ) ;
if ( savegame ! = nullptr )
{
FResourceLump * info = savegame - > FindLump ( " info.json " ) ;
if ( info = = nullptr )
{
// savegame info not found. This is not a savegame so leave it alone.
delete savegame ;
continue ;
}
auto fr = info - > NewReader ( ) ;
FString title ;
int check = G_ValidateSavegame ( fr , & title ) ;
2019-11-30 21:46:00 +00:00
fr . Close ( ) ;
2019-11-29 23:49:50 +00:00
delete savegame ;
if ( check ! = 0 )
{
FSaveGameNode * node = new FSaveGameNode ;
node - > Filename = filepath ;
node - > bOldVersion = true ;
node - > bMissingWads = false ;
node - > SaveTitle = title ;
InsertSaveNode ( node ) ;
}
}
} while ( I_FindNext ( filefirst , & c_file ) = = 0 ) ;
I_FindClose ( filefirst ) ;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : NotifyNewSave ( const FString & file , const FString & title , bool okForQuicksave , bool forceQuicksave )
{
FSaveGameNode * node ;
if ( file . IsEmpty ( ) )
return ;
ReadSaveStrings ( ) ;
// See if the file is already in our list
for ( unsigned i = 0 ; i < SaveGames . Size ( ) ; i + + )
{
FSaveGameNode * node = SaveGames [ i ] ;
# ifdef __unix__
if ( node - > Filename . Compare ( file ) = = 0 )
# else
if ( node - > Filename . CompareNoCase ( file ) = = 0 )
# endif
{
node - > SaveTitle = title ;
node - > bOldVersion = false ;
node - > bMissingWads = false ;
if ( okForQuicksave )
{
if ( quickSaveSlot = = nullptr | | quickSaveSlot = = ( FSaveGameNode * ) 1 | | forceQuicksave ) quickSaveSlot = node ;
LastAccessed = LastSaved = i ;
}
return ;
}
}
node = new FSaveGameNode ;
node - > SaveTitle = title ;
node - > Filename = file ;
node - > bOldVersion = false ;
node - > bMissingWads = false ;
int index = InsertSaveNode ( node ) ;
if ( okForQuicksave )
{
if ( quickSaveSlot = = nullptr | | quickSaveSlot = = ( FSaveGameNode * ) 1 | | forceQuicksave ) quickSaveSlot = node ;
LastAccessed = LastSaved = index ;
}
else
{
LastAccessed = + + LastSaved ;
}
}
//=============================================================================
//
// Loads the savegame
//
//=============================================================================
void FSavegameManager : : LoadSavegame ( int Selected )
{
2019-11-30 18:23:54 +00:00
savegameManager . LoadGame ( SaveGames [ Selected ] ) ;
2019-11-29 23:49:50 +00:00
if ( quickSaveSlot = = ( FSaveGameNode * ) 1 )
{
quickSaveSlot = SaveGames [ Selected ] ;
}
M_ClearMenus ( ) ;
LastAccessed = Selected ;
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : DoSave ( int Selected , const char * savegamestring )
{
if ( Selected ! = 0 )
{
2019-11-30 18:23:54 +00:00
auto node = * SaveGames [ Selected ] ;
node . SaveTitle = savegamestring ;
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( & node , true , false ) ;
2019-11-29 23:49:50 +00:00
}
else
{
// Find an unused filename and save as that
FString filename ;
int i ;
for ( i = 0 ; ; + + i )
{
filename = G_BuildSaveName ( FStringf ( " save%04d " , i ) ) ;
if ( ! FileExists ( filename ) )
{
break ;
}
}
2019-11-30 18:23:54 +00:00
FSaveGameNode sg { savegamestring , filename } ;
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( & sg , true , false ) ;
2019-11-29 23:49:50 +00:00
}
M_ClearMenus ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
unsigned FSavegameManager : : ExtractSaveData ( int index )
{
FResourceFile * resf ;
FSaveGameNode * node ;
if ( index = = - 1 )
{
if ( SaveGames . Size ( ) > 0 & & SaveGames [ 0 ] - > bNoDelete )
{
index = LastSaved + 1 ;
}
else
{
index = LastAccessed < 0 ? 0 : LastAccessed ;
}
}
UnloadSaveData ( ) ;
if ( ( unsigned ) index < SaveGames . Size ( ) & &
( node = SaveGames [ index ] ) & &
! node - > Filename . IsEmpty ( ) & &
! node - > bOldVersion & &
( resf = FResourceFile : : OpenResourceFile ( node - > Filename . GetChars ( ) , true ) ) ! = nullptr )
{
FResourceLump * info = resf - > FindLump ( " info.json " ) ;
if ( info = = nullptr )
{
// this should not happen because the file has already been verified.
return index ;
}
auto fr = info - > NewReader ( ) ;
auto data = fr . ReadPadded ( 1 ) ;
sjson_context * ctx = sjson_create_context ( 0 , 0 , NULL ) ;
if ( ctx )
{
sjson_node * root = sjson_decode ( ctx , ( const char * ) data . Data ( ) ) ;
FString comment = sjson_get_string ( root , " Creation Time " , " " ) ;
FString pcomment = sjson_get_string ( root , " Comment " , " " ) ;
if ( comment . Len ( ) > 0 ) comment + = " \n " ;
comment + = pcomment ;
SaveCommentString = comment ;
// Extract pic (todo: let the renderer write a proper PNG file instead of a raw canvas dunp of the software renderer - and make it work for all games.)
FResourceLump * pic = resf - > FindLump ( " savepic.png " ) ;
if ( pic ! = nullptr )
{
FileReader picreader ;
picreader . OpenMemoryArray ( [ = ] ( TArray < uint8_t > & array )
{
auto cache = pic - > Lock ( ) ;
array . Resize ( pic - > LumpSize ) ;
memcpy ( & array [ 0 ] , cache , pic - > LumpSize ) ;
pic - > Unlock ( ) ;
return true ;
} ) ;
PNGHandle * png = M_VerifyPNG ( picreader ) ;
if ( png ! = nullptr )
{
SavePic = nullptr ; // not yet implemented: PNGTexture_CreateFromFile(png, node->Filename);
delete png ;
if ( SavePic & & SavePic - > GetWidth ( ) = = 1 & & SavePic - > GetHeight ( ) = = 1 )
{
delete SavePic ;
SavePic = nullptr ;
SavePicData . Clear ( ) ;
}
}
}
}
delete resf ;
}
return index ;
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : UnloadSaveData ( )
{
if ( SavePic ! = nullptr )
{
delete SavePic ;
}
SaveCommentString = " " ;
SavePic = nullptr ;
SavePicData . Clear ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : ClearSaveStuff ( )
{
UnloadSaveData ( ) ;
if ( quickSaveSlot = = ( FSaveGameNode * ) 1 )
{
quickSaveSlot = nullptr ;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool FSavegameManager : : DrawSavePic ( int x , int y , int w , int h )
{
if ( SavePic = = nullptr ) return false ;
DrawTexture ( & twod , SavePic , x , y , DTA_DestWidth , w , DTA_DestHeight , h , DTA_Masked , false , TAG_DONE ) ;
return true ;
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : SetFileInfo ( int Selected )
{
if ( ! SaveGames [ Selected ] - > Filename . IsEmpty ( ) )
{
SaveCommentString . Format ( " File on disk: \n %s " , SaveGames [ Selected ] - > Filename . GetChars ( ) ) ;
}
}
//=============================================================================
//
//
//
//=============================================================================
unsigned FSavegameManager : : SavegameCount ( )
{
return SaveGames . Size ( ) ;
}
//=============================================================================
//
//
//
//=============================================================================
FSaveGameNode * FSavegameManager : : GetSavegame ( int i )
{
return SaveGames [ i ] ;
}
//=============================================================================
//
//
//
//=============================================================================
void FSavegameManager : : InsertNewSaveNode ( )
{
2019-11-30 21:46:00 +00:00
NewSaveNode . SaveTitle = GStrings ( " NEWSAVE " ) ;
2019-11-29 23:49:50 +00:00
NewSaveNode . bNoDelete = true ;
SaveGames . Insert ( 0 , & NewSaveNode ) ;
}
//=============================================================================
//
//
//
//=============================================================================
bool FSavegameManager : : RemoveNewSaveNode ( )
{
if ( SaveGames [ 0 ] = = & NewSaveNode )
{
SaveGames . Delete ( 0 ) ;
return true ;
}
return false ;
}
2019-11-30 18:23:54 +00:00
//=============================================================================
//
//
//
//=============================================================================
CVAR ( Bool , saveloadconfirmation , true , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
CVAR ( Int , autosavenum , 0 , CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
static int nextautosave = - 1 ;
CVAR ( Int , disableautosave , 0 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
CUSTOM_CVAR ( Int , autosavecount , 4 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( self < 1 )
self = 1 ;
}
CVAR ( Int , quicksavenum , 0 , CVAR_NOSET | CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
static int nextquicksave = - 1 ;
CUSTOM_CVAR ( Int , quicksavecount , 4 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( self < 1 )
self = 1 ;
}
void M_Autosave ( )
{
if ( ! gi - > CanSave ( ) ) return ;
FString description ;
FString file ;
// Keep a rotating sets of autosaves
UCVarValue num ;
const char * readableTime ;
int count = autosavecount ! = 0 ? autosavecount : 1 ;
if ( nextautosave = = - 1 )
{
nextautosave = ( autosavenum + 1 ) % count ;
}
num . Int = nextautosave ;
autosavenum . ForceSet ( num , CVAR_Int ) ;
FSaveGameNode sg ;
sg . Filename = G_BuildSaveName ( FStringf ( " auto%04d " , nextautosave ) ) ;
readableTime = myasctime ( ) ;
sg . SaveTitle . Format ( " Autosave %s " , readableTime ) ;
nextautosave = ( nextautosave + 1 ) % count ;
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( & sg , false , false ) ;
2019-11-30 18:23:54 +00:00
}
CCMD ( autosave )
{
if ( disableautosave ) return ;
M_Autosave ( ) ;
}
CCMD ( rotatingquicksave )
{
if ( ! gi - > CanSave ( ) ) return ;
FString description ;
FString file ;
// Keep a rotating sets of quicksaves
UCVarValue num ;
const char * readableTime ;
int count = quicksavecount ! = 0 ? quicksavecount : 1 ;
if ( nextquicksave = = - 1 )
{
nextquicksave = ( quicksavenum + 1 ) % count ;
}
num . Int = nextquicksave ;
quicksavenum . ForceSet ( num , CVAR_Int ) ;
FSaveGameNode sg ;
sg . Filename = G_BuildSaveName ( FStringf ( " quick%04d " , nextquicksave ) ) ;
readableTime = myasctime ( ) ;
sg . SaveTitle . Format ( " Quicksave %s " , readableTime ) ;
nextquicksave = ( nextquicksave + 1 ) % count ;
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( & sg , false , false ) ;
2019-11-30 18:23:54 +00:00
}
//=============================================================================
//
//
//
//=============================================================================
CCMD ( quicksave )
{ // F6
if ( ! gi - > CanSave ( ) ) return ;
if ( savegameManager . quickSaveSlot = = NULL | | savegameManager . quickSaveSlot = = ( FSaveGameNode * ) 1 )
{
M_StartControlPanel ( true ) ;
M_SetMenu ( NAME_SaveGameMenu ) ;
return ;
}
auto slot = savegameManager . quickSaveSlot ;
// [mxd]. Just save the game, no questions asked.
if ( ! saveloadconfirmation )
{
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( savegameManager . quickSaveSlot , true , true ) ;
2019-11-30 18:23:54 +00:00
return ;
}
gi - > MenuSound ( ActivateSound ) ;
FString tempstring = GStrings ( " QSPROMPT " ) ;
tempstring . Substitute ( " %s " , slot - > SaveTitle . GetChars ( ) ) ;
DMenu * newmenu = CreateMessageBoxMenu ( DMenu : : CurrentMenu , tempstring , 0 , INT_MAX , false , NAME_None , [ ] ( bool res )
{
if ( res )
{
2019-11-30 21:46:00 +00:00
savegameManager . SaveGame ( savegameManager . quickSaveSlot , true , true ) ;
2019-11-30 18:23:54 +00:00
}
} ) ;
M_ActivateMenu ( newmenu ) ;
}
//=============================================================================
//
//
//
//=============================================================================
CCMD ( quickload )
{ // F9
#if 0
if ( netgame )
{
M_StartControlPanel ( true ) ;
M_StartMessage ( GStrings ( " QLOADNET " ) , 1 ) ;
return ;
}
# endif
if ( savegameManager . quickSaveSlot = = nullptr | | savegameManager . quickSaveSlot = = ( FSaveGameNode * ) 1 )
{
M_StartControlPanel ( true ) ;
// signal that whatever gets loaded should be the new quicksave
savegameManager . quickSaveSlot = ( FSaveGameNode * ) 1 ;
M_SetMenu ( NAME_LoadGameMenu ) ;
return ;
}
// [mxd]. Just load the game, no questions asked.
if ( ! saveloadconfirmation )
{
savegameManager . LoadGame ( savegameManager . quickSaveSlot ) ;
return ;
}
FString tempstring = GStrings ( " QLPROMPT " ) ;
tempstring . Substitute ( " %s " , savegameManager . quickSaveSlot - > SaveTitle . GetChars ( ) ) ;
M_StartControlPanel ( true ) ;
DMenu * newmenu = CreateMessageBoxMenu ( DMenu : : CurrentMenu , tempstring , 0 , INT_MAX , false , NAME_None , [ ] ( bool res )
{
if ( res )
{
savegameManager . LoadGame ( savegameManager . quickSaveSlot ) ;
}
} ) ;
M_ActivateMenu ( newmenu ) ;
}
#if 0
// Duke
if ( ( buttonMap . ButtonDown ( gamefunc_Quick_Load ) | | g_doQuickSave = = 2 ) & & ( myplayer . gm & MODE_GAME ) )
{
buttonMap . ClearButton ( gamefunc_Quick_Load ) ;
g_doQuickSave = 0 ;
if ( g_quickload = = nullptr | | ! g_quickload - > isValid ( ) )
{
C_DoCommand ( " openloadmenu " ) ;
}
else if ( g_quickload - > isValid ( ) )
{
inputState . keyFlushChars ( ) ;
inputState . ClearKeysDown ( ) ;
if ( G_LoadPlayerMaybeMulti ( * g_quickload ) ! = 0 )
g_quickload - > reset ( ) ;
}
}
if ( ( buttonMap . ButtonDown ( gamefunc_Quick_Save ) | | g_doQuickSave = = 1 ) & & ( myplayer . gm & MODE_GAME ) )
{
buttonMap . ClearButton ( gamefunc_Quick_Save ) ;
g_doQuickSave = 0 ;
if ( ! g_lastusersave . isValid ( ) )
{
C_DoCommand ( " opensavemenu " ) ;
return ;
}
inputState . keyFlushChars ( ) ;
if ( sprite [ myplayer . i ] . extra < = 0 )
{
P_DoQuote ( QUOTE_SAVE_DEAD , & myplayer ) ;
return ;
}
g_screenCapture = 1 ;
G_DrawRooms ( myconnectindex , 65536 ) ;
g_screenCapture = 0 ;
if ( g_lastusersave . isValid ( ) )
{
savebrief_t & sv = g_lastusersave ;
// dirty hack... char 127 in last position indicates an auto-filled name
if ( sv . name [ MAXSAVEGAMENAME ] = = 127 )
{
strncpy ( sv . name , g_mapInfo [ ud . volume_number * MAXLEVELS + ud . level_number ] . name , MAXSAVEGAMENAME ) ;
sv . name [ MAXSAVEGAMENAME ] = 127 ;
}
g_quickload = & sv ;
G_SavePlayerMaybeMulti ( sv ) ;
}
}
// handle CON_SAVE and CON_SAVENN
if ( g_saveRequested )
{
inputState . keyFlushChars ( ) ;
videoNextPage ( ) ;
g_screenCapture = 1 ;
G_DrawRooms ( myconnectindex , 65536 ) ;
g_screenCapture = 0 ;
G_SavePlayerMaybeMulti ( g_lastautosave , true ) ;
g_quickload = & g_lastautosave ;
OSD_Printf ( " Saved: %s \n " , g_lastautosave . path ) ;
g_saveRequested = false ;
}
// RR
if ( ( buttonMap . ButtonDown ( gamefunc_Quick_Load ) | | g_doQuickSave = = 2 ) & & ( ! RRRA | | ud . player_skill ! = 4 ) & & ( ! RR | | RRRA | | ud . player_skill ! = 5 ) & & ( g_player [ myconnectindex ] . ps - > gm & MODE_GAME ) )
{
buttonMap . ClearButton ( gamefunc_Quick_Load ) ;
g_doQuickSave = 0 ;
if ( g_quickload = = nullptr | | ! g_quickload - > isValid ( ) )
{
C_DoCommand ( " openloadmenu " ) ;
}
else if ( g_quickload - > isValid ( ) )
{
inputState . keyFlushChars ( ) ;
inputState . ClearKeysDown ( ) ;
S_PauseSounds ( true ) ;
if ( G_LoadPlayerMaybeMulti ( * g_quickload ) ! = 0 )
g_quickload - > reset ( ) ;
}
}
if ( ( buttonMap . ButtonDown ( gamefunc_Quick_Save ) | | g_doQuickSave = = 1 ) & & ( ! RRRA | | ud . player_skill ! = 4 ) & & ( ! RR | | RRRA | | ud . player_skill ! = 5 ) & & ( g_player [ myconnectindex ] . ps - > gm & MODE_GAME ) )
{
buttonMap . ClearButton ( gamefunc_Quick_Save ) ;
g_doQuickSave = 0 ;
if ( ! g_lastusersave . isValid ( ) )
{
C_DoCommand ( " opensavemenu " ) ;
return ;
}
inputState . keyFlushChars ( ) ;
if ( sprite [ g_player [ myconnectindex ] . ps - > i ] . extra < = 0 )
{
P_DoQuote ( QUOTE_SAVE_DEAD , g_player [ myconnectindex ] . ps ) ;
return ;
}
g_screenCapture = 1 ;
G_DrawRooms ( myconnectindex , 65536 ) ;
g_screenCapture = 0 ;
if ( g_lastusersave . isValid ( ) )
{
savebrief_t & sv = g_lastusersave ;
// dirty hack... char 127 in last position indicates an auto-filled name
if ( sv . name [ MAXSAVEGAMENAME ] = = 127 )
{
strncpy ( sv . name , g_mapInfo [ ud . volume_number * MAXLEVELS + ud . level_number ] . name , MAXSAVEGAMENAME ) ;
sv . name [ MAXSAVEGAMENAME ] = 127 ;
}
g_quickload = & sv ;
G_SavePlayerMaybeMulti ( sv ) ;
}
}
// sw
SWBOOL DoQuickSave ( short save_num )
{
PauseAction ( ) ;
if ( SaveGame ( save_num ) ! = - 1 )
{
QuickLoadNum = save_num ;
LastSaveNum = - 1 ;
return FALSE ;
}
return TRUE ;
}
SWBOOL DoQuickLoad ( )
{
inputState . ClearKeysDown ( ) ;
PauseAction ( ) ;
ReloadPrompt = FALSE ;
if ( LoadGame ( QuickLoadNum ) = = - 1 )
{
return FALSE ;
}
ready2send = 1 ;
LastSaveNum = - 1 ;
return TRUE ;
}
// F6 quick save
if ( inputState . GetKeyStatus ( KEYSC_F6 ) )
{
inputState . ClearKeyStatus ( KEYSC_F6 ) ;
if ( ! TEST ( pp - > Flags , PF_DEAD ) )
{
if ( QuickLoadNum < 0 )
{
inputState . SetKeyStatus ( sc_Escape ) ;
ControlPanelType = ct_savemenu ;
}
else
{
inputState . ClearAllInput ( ) ;
DoQuickSave ( QuickLoadNum ) ;
ResumeAction ( ) ;
}
}
}
// F9 quick load
if ( inputState . GetKeyStatus ( KEYSC_F9 ) )
{
inputState . ClearKeyStatus ( KEYSC_F9 ) ;
if ( ! TEST ( pp - > Flags , PF_DEAD ) )
{
if ( QuickLoadNum < 0 )
{
inputState . SetKeyStatus ( sc_Escape ) ;
ControlPanelType = ct_loadmenu ;
}
else
{
DoQuickLoad ( ) ;
ResumeAction ( ) ;
}
}
}
////////////////////////////////////////////////
// Load Game menu
// This function gets called whenever you
// press enter on one of the load game
// spots.
// I'm figuring it need to do the following:
// . Load the game if there is one by calling: MNU_LoadGameCustom.
////////////////////////////////////////////////
SWBOOL MNU_GetLoadCustom ( void )
{
short load_num ;
load_num = currentmenu - > cursor ;
// no saved game exists - don't do anything
if ( SaveGameDescr [ load_num ] [ 0 ] = = ' \0 ' )
return FALSE ;
if ( InMenuLevel | | DemoMode | | DemoPlaying )
{
LoadSaveMsg ( " Loading... " ) ;
if ( LoadGame ( load_num ) = = - 1 )
return FALSE ;
QuickLoadNum = load_num ;
// the (Quick)Save menu should default to the last loaded game
SaveGameGroup . cursor = load_num ;
ExitMenus ( ) ;
ExitLevel = TRUE ;
LoadGameOutsideMoveLoop = TRUE ;
if ( DemoMode | | DemoPlaying )
LoadGameFromDemo = TRUE ;
return TRUE ;
}
LoadSaveMsg ( " Loading... " ) ;
PauseAction ( ) ;
if ( LoadGame ( load_num ) = = - 1 )
{
ResumeAction ( ) ;
return FALSE ;
}
QuickLoadNum = load_num ;
// the (Quick)Save menu should default to the last loaded game
SaveGameGroup . cursor = load_num ;
ready2send = 1 ;
LastSaveNum = - 1 ;
ExitMenus ( ) ;
if ( DemoMode )
{
ExitLevel = TRUE ;
DemoPlaying = FALSE ;
}
return TRUE ;
}
////////////////////////////////////////////////
// Save Game menu
// This function gets called whenever you
// press enter on one of the save game
// spots.
// I'm figuring it need to do the following:
// . Call MNU_GetInput to allow string input of description.
// . Save the game if there is one by calling: MNU_SaveGameCustom.
////////////////////////////////////////////////
SWBOOL MNU_GetSaveCustom ( void )
{
short save_num ;
extern SWBOOL InMenuLevel , LoadGameOutsideMoveLoop ;
save_num = currentmenu - > cursor ;
if ( InMenuLevel )
return FALSE ;
if ( MenuInputMode )
{
LoadSaveMsg ( " Saving... " ) ;
if ( DoQuickSave ( save_num ) = = FALSE )
{
LoadGameGroup . cursor = save_num ;
}
ResumeAction ( ) ;
ExitMenus ( ) ;
// toggle edit mode
MenuInputMode = FALSE ;
}
else
{
strcpy ( BackupSaveGameDescr , SaveGameDescr [ save_num ] ) ;
// clear keyboard buffer
while ( inputState . keyBufferWaiting ( ) )
{
if ( inputState . keyGetChar ( ) = = 0 )
inputState . keyGetChar ( ) ;
}
// toggle edit mode
MenuInputMode = TRUE ;
}
return TRUE ;
}
// Blood
static void DoQuickLoad ( void )
{
if ( ! gGameMenuMgr . m_bActive )
{
if ( gQuickLoadSlot ! = - 1 )
{
QuickLoadGame ( ) ;
return ;
}
if ( gQuickLoadSlot = = - 1 & & gQuickSaveSlot ! = - 1 )
{
gQuickLoadSlot = gQuickSaveSlot ;
QuickLoadGame ( ) ;
return ;
}
gGameMenuMgr . Push ( & menuLoadGame , - 1 ) ;
}
}
static void DoQuickSave ( void )
{
if ( gGameStarted & & ! gGameMenuMgr . m_bActive & & gPlayer [ myconnectindex ] . pXSprite - > health ! = 0 )
{
if ( gQuickSaveSlot ! = - 1 )
{
QuickSaveGame ( ) ;
return ;
}
gGameMenuMgr . Push ( & menuSaveGame , - 1 ) ;
}
}
if ( gDoQuickSave )
{
inputState . keyFlushScans ( ) ;
switch ( gDoQuickSave )
{
case 1 :
DoQuickSave ( ) ;
break ;
case 2 :
DoQuickLoad ( ) ;
break ;
}
gDoQuickSave = 0 ;
return ;
}
case sc_F6 :
inputState . keyFlushScans ( ) ;
DoQuickSave ( ) ;
break ;
case sc_F9 :
inputState . keyFlushScans ( ) ;
DoQuickLoad ( ) ;
break ;
# endif