mirror of https://github.com/stella-emu/stella.git
Added state saving and loading using the F9, F10, and F11 keys. The
game state is stored in a 'state' sub-directory of the current working directory or in a 'state' sub-directory of the directory specified by the 'STELLA_HOME' environment variable if it is set. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@163 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
7ca813cc1b
commit
8d530f38a2
|
@ -8,18 +8,19 @@
|
||||||
// SS SS tt ee ll ll aa aa
|
// SS SS tt ee ll ll aa aa
|
||||||
// SSSS ttt eeeee llll llll aaaaa
|
// SSSS ttt eeeee llll llll aaaaa
|
||||||
//
|
//
|
||||||
// Copyright (c) 1995-2002 by Bradford W. Mott
|
// Copyright (c) 1995-2003 by Bradford W. Mott
|
||||||
//
|
//
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: mainDOS.cxx,v 1.8 2002-11-13 03:47:55 bwmott Exp $
|
// $Id: mainDOS.cxx,v 1.9 2003-01-08 05:19:07 bwmott Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <go32.h>
|
#include <go32.h>
|
||||||
#include <dpmi.h>
|
#include <dpmi.h>
|
||||||
#include <sys/farptr.h>
|
#include <sys/farptr.h>
|
||||||
#include <sys/nearptr.h>
|
#include <sys/nearptr.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <dos.h>
|
#include <dos.h>
|
||||||
#include <pc.h>
|
#include <pc.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -88,6 +89,8 @@ bool theUseModeXFlag = false;
|
||||||
// Pointer to the joysticks object
|
// Pointer to the joysticks object
|
||||||
PCJoysticks* theJoysticks;
|
PCJoysticks* theJoysticks;
|
||||||
|
|
||||||
|
#define MESSAGE_INTERVAL 2
|
||||||
|
|
||||||
// Mouse IRQ
|
// Mouse IRQ
|
||||||
#define MOUSE_BIOS 0x33
|
#define MOUSE_BIOS 0x33
|
||||||
|
|
||||||
|
@ -110,6 +113,122 @@ _go32_dpmi_seginfo theOldKeyboardHandler;
|
||||||
_go32_dpmi_seginfo theKeyboardHandler;
|
_go32_dpmi_seginfo theKeyboardHandler;
|
||||||
static void keyboardInterruptServiceRoutine(void);
|
static void keyboardInterruptServiceRoutine(void);
|
||||||
|
|
||||||
|
// Indicates the current state to use for state saving
|
||||||
|
static uInt32 theCurrentState = 0;
|
||||||
|
|
||||||
|
// The locations for various required files
|
||||||
|
static string theHomeDir;
|
||||||
|
static string theStateDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Changes the current state slot.
|
||||||
|
*/
|
||||||
|
void changeState(uInt32 change)
|
||||||
|
{
|
||||||
|
// Calculate new state slot
|
||||||
|
theCurrentState = (theCurrentState + ((change == 0) ? 9 : 1)) % 10;
|
||||||
|
|
||||||
|
// Print appropriate message
|
||||||
|
ostringstream buf;
|
||||||
|
buf << "Changed to slot " << theCurrentState;
|
||||||
|
string message = buf.str();
|
||||||
|
theConsole->mediaSource().showMessage(message,
|
||||||
|
MESSAGE_INTERVAL * theDesiredFrameRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Saves state of the current game in the current slot.
|
||||||
|
*/
|
||||||
|
void saveState()
|
||||||
|
{
|
||||||
|
ostringstream buf;
|
||||||
|
string md5 = theConsole->properties().get("Cartridge.MD5");
|
||||||
|
|
||||||
|
string sub1 = theStateDir + '\\' + md5.substr(0, 8);
|
||||||
|
string sub2 = sub1 + '\\' + md5.substr(8, 8);
|
||||||
|
string sub3 = sub2 + '\\' + md5.substr(16, 8);
|
||||||
|
buf << sub3 << '\\' << md5.substr(24, 8) << ".st" << theCurrentState;
|
||||||
|
string filename = buf.str();
|
||||||
|
|
||||||
|
// If needed create the sub-directory corresponding to the characters
|
||||||
|
// of the MD5 checksum
|
||||||
|
if(access(sub1.c_str(), F_OK) != 0)
|
||||||
|
{
|
||||||
|
if(mkdir(sub1.c_str(), S_IWUSR) != 0)
|
||||||
|
{
|
||||||
|
theConsole->mediaSource().showMessage(string() = "Error Saving State",
|
||||||
|
MESSAGE_INTERVAL * theDesiredFrameRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(access(sub2.c_str(), F_OK) != 0)
|
||||||
|
{
|
||||||
|
if(mkdir(sub2.c_str(), S_IWUSR) != 0)
|
||||||
|
{
|
||||||
|
theConsole->mediaSource().showMessage(string() = "Error Saving State",
|
||||||
|
MESSAGE_INTERVAL * theDesiredFrameRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(access(sub3.c_str(), F_OK) != 0)
|
||||||
|
{
|
||||||
|
if(mkdir(sub3.c_str(), S_IWUSR) != 0)
|
||||||
|
{
|
||||||
|
theConsole->mediaSource().showMessage(string() = "Error Saving State",
|
||||||
|
MESSAGE_INTERVAL * theDesiredFrameRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a state save using the System
|
||||||
|
int result = theConsole->system().saveState(filename, md5);
|
||||||
|
|
||||||
|
// Print appropriate message
|
||||||
|
buf.str("");
|
||||||
|
if(result == 1)
|
||||||
|
buf << "State " << theCurrentState << " saved";
|
||||||
|
else if(result == 2)
|
||||||
|
buf << "Error saving state " << theCurrentState;
|
||||||
|
else if(result == 3)
|
||||||
|
buf << "Invalid state " << theCurrentState << " file";
|
||||||
|
|
||||||
|
string message = buf.str();
|
||||||
|
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
|
||||||
|
theDesiredFrameRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Loads state from the current slot for the current game.
|
||||||
|
*/
|
||||||
|
void loadState()
|
||||||
|
{
|
||||||
|
ostringstream buf;
|
||||||
|
string md5 = theConsole->properties().get("Cartridge.MD5");
|
||||||
|
|
||||||
|
string sub1 = theStateDir + '\\' + md5.substr(0, 8);
|
||||||
|
string sub2 = sub1 + '\\' + md5.substr(8, 8);
|
||||||
|
string sub3 = sub2 + '\\' + md5.substr(16, 8);
|
||||||
|
buf << sub3 << '\\' << md5.substr(24, 8) << ".st" << theCurrentState;
|
||||||
|
string filename = buf.str();
|
||||||
|
|
||||||
|
// Do a state load using the System
|
||||||
|
int result = theConsole->system().loadState(filename, md5);
|
||||||
|
|
||||||
|
// Print appropriate message
|
||||||
|
buf.str("");
|
||||||
|
if(result == 1)
|
||||||
|
buf << "State " << theCurrentState << " loaded";
|
||||||
|
else if(result == 2)
|
||||||
|
buf << "Error loading state " << theCurrentState;
|
||||||
|
else if(result == 3)
|
||||||
|
buf << "Invalid state " << theCurrentState << " file";
|
||||||
|
|
||||||
|
string message = buf.str();
|
||||||
|
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
|
||||||
|
theDesiredFrameRate);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This routine should be called once the console is create to setup
|
This routine should be called once the console is create to setup
|
||||||
|
@ -510,6 +629,47 @@ void updateEventsUsingKeyboardState()
|
||||||
theQuitIndicator = true;
|
theQuitIndicator = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle switching save state slots
|
||||||
|
static bool changedState = false;
|
||||||
|
if((theKeyboardKeyState[SCAN_F10]) && !changedState)
|
||||||
|
{
|
||||||
|
if(theKeyboardKeyState[SCAN_LSHIFT] || theKeyboardKeyState[SCAN_RSHIFT])
|
||||||
|
{
|
||||||
|
changeState(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
changeState(1);
|
||||||
|
}
|
||||||
|
changedState = true;
|
||||||
|
}
|
||||||
|
else if(!theKeyboardKeyState[SCAN_F10])
|
||||||
|
{
|
||||||
|
changedState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool savedState = false;
|
||||||
|
if(!savedState && theKeyboardKeyState[SCAN_F9])
|
||||||
|
{
|
||||||
|
saveState();
|
||||||
|
savedState = true;
|
||||||
|
}
|
||||||
|
else if(!theKeyboardKeyState[SCAN_F9])
|
||||||
|
{
|
||||||
|
savedState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool loadedState = false;
|
||||||
|
if(!loadedState && theKeyboardKeyState[SCAN_F11])
|
||||||
|
{
|
||||||
|
loadState();
|
||||||
|
loadedState = true;
|
||||||
|
}
|
||||||
|
else if(!theKeyboardKeyState[SCAN_F11])
|
||||||
|
{
|
||||||
|
loadedState = false;
|
||||||
|
}
|
||||||
|
|
||||||
// First we clear all of the keyboard events
|
// First we clear all of the keyboard events
|
||||||
for(unsigned int k = 0; k < sizeof(list) / sizeof(Switches); ++k)
|
for(unsigned int k = 0; k < sizeof(list) / sizeof(Switches); ++k)
|
||||||
{
|
{
|
||||||
|
@ -697,6 +857,53 @@ static void keyboardInterruptServiceRoutine(void)
|
||||||
outp(0x20, 0x20);
|
outp(0x20, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Ensure that the necessary directories are created for Stella under
|
||||||
|
STELLA_HOME or the current working directory if STELLA_HOME is not
|
||||||
|
defined.
|
||||||
|
|
||||||
|
Required directories are $STELLA_HOME/state.
|
||||||
|
This must be called before any other function.
|
||||||
|
*/
|
||||||
|
bool setupDirs()
|
||||||
|
{
|
||||||
|
// Get the directory to use
|
||||||
|
theHomeDir = getenv("STELLA_HOME");
|
||||||
|
if(theHomeDir == "")
|
||||||
|
{
|
||||||
|
theHomeDir = ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing backslash
|
||||||
|
if((theHomeDir.length() >= 1) &&
|
||||||
|
(theHomeDir[theHomeDir.length() - 1] == '\\'))
|
||||||
|
{
|
||||||
|
theHomeDir = theHomeDir.substr(0, theHomeDir.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create state saving directory if needed
|
||||||
|
theStateDir = theHomeDir + "\\state";
|
||||||
|
if(access(theStateDir.c_str(), F_OK) != 0)
|
||||||
|
{
|
||||||
|
if(mkdir(theStateDir.c_str(), S_IWUSR) != 0)
|
||||||
|
{
|
||||||
|
cerr << "ERROR: Creating state save directory "
|
||||||
|
<< theStateDir << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(access(theStateDir.c_str(), R_OK | W_OK | X_OK | D_OK) != 0)
|
||||||
|
{
|
||||||
|
cerr << "ERROR: Access not allowed to the state save directory "
|
||||||
|
<< theStateDir << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Display a usage message and exit the program
|
Display a usage message and exit the program
|
||||||
*/
|
*/
|
||||||
|
@ -704,7 +911,7 @@ void usage()
|
||||||
{
|
{
|
||||||
static const char* message[] = {
|
static const char* message[] = {
|
||||||
"",
|
"",
|
||||||
"Stella for DOS version 1.2.1",
|
"Stella for DOS version 1.3",
|
||||||
"",
|
"",
|
||||||
"Usage: stella [option ...] file",
|
"Usage: stella [option ...] file",
|
||||||
"",
|
"",
|
||||||
|
@ -818,6 +1025,12 @@ void handleCommandLineArguments(int argc, char* argv[])
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
// First set up the directories where Stella will find RC and state files
|
||||||
|
if(!setupDirs())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle the command line arguments
|
// Handle the command line arguments
|
||||||
handleCommandLineArguments(argc, argv);
|
handleCommandLineArguments(argc, argv);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue