MYST3: Add Autosave Support

This adds autosaving to a save named  Autosave.

Autosaving is enabled if the autosave file
doesn't exist or is an autosave.

The actual autosaving is done on exit or based
on the save interval specified in the config file.
This commit is contained in:
David Fioramonti
2018-05-27 12:44:24 +02:00
committed by Bastien Bouclet
parent 08df1680e8
commit 006aaa2c43
6 changed files with 110 additions and 13 deletions
+23 -9
View File
@@ -209,7 +209,8 @@ int16 GamepadDialog::update() {
Menu::Menu(Myst3Engine *vm) :
_vm(vm),
_saveLoadSpotItem(0) {
_saveLoadSpotItem(0),
_thumbnailValid(false) {
}
Menu::~Menu() {
@@ -295,6 +296,23 @@ void Menu::updateMainMenu(uint16 action) {
}
}
void Menu::saveThumbnail() {
// ... and capture the screen
Graphics::Surface *big = _vm->_gfx->getScreenshot();
Graphics::Surface *thumb = createThumbnail(big);
_vm->_state->setSaveThumbnail(thumb);
big->free();
delete big;
}
bool Menu::getThumbnailValid() {
return _thumbnailValid;
}
void Menu::setThumbnailValid(bool valid) {
_thumbnailValid = valid;
}
void Menu::goToNode(uint16 node) {
if (_vm->_state->getMenuSavedAge() == 0 && _vm->_state->getLocationRoom() != 901) {
// Entering menu, save current location ...
@@ -302,12 +320,8 @@ void Menu::goToNode(uint16 node) {
_vm->_state->setMenuSavedRoom(_vm->_state->getLocationRoom());
_vm->_state->setMenuSavedNode(_vm->_state->getLocationNode());
// ... and capture the screen
Graphics::Surface *big = _vm->_gfx->getScreenshot();
Graphics::Surface *thumb = createThumbnail(big);
_vm->_state->setSaveThumbnail(thumb);
big->free();
delete big;
saveThumbnail();
_thumbnailValid = true;
// Reset some sound variables
if (_vm->_state->getLocationAge() == 6 && _vm->_state->getSoundEdannaUnk587() == 1 && _vm->_state->getSoundEdannaUnk1031()) {
@@ -614,7 +628,7 @@ void PagingMenu::saveMenuSave() {
// Save the state and the thumbnail
Common::OutSaveFile *save = _vm->getSaveFileManager()->openForSaving(fileName);
_vm->_state->setSaveDescription(_saveName);
_vm->_state->save(save);
_vm->_state->save(save,false);
delete save;
// Do next action
@@ -953,7 +967,7 @@ void AlbumMenu::saveMenuSave() {
// Save the state and the thumbnail
Common::OutSaveFile *save = _vm->getSaveFileManager()->openForSaving(fileName);
_vm->_state->setSaveDescription(saveName);
_vm->_state->save(save);
_vm->_state->save(save,false);
delete save;
// Do next action
+8
View File
@@ -63,6 +63,12 @@ public:
void updateMainMenu(uint16 action);
void goToNode(uint16 node);
/*
* Grab a screenshot save it to state and free memory
*/
void saveThumbnail();
bool getThumbnailValid();
void setThumbnailValid(bool value);
virtual void saveLoadAction(uint16 action, uint16 item) = 0;
virtual void setSaveLoadSpotItem(uint16 id, SpotItemFace *spotItem);
@@ -73,6 +79,8 @@ protected:
SpotItemFace *_saveLoadSpotItem;
Common::String _saveLoadAgeName;
bool _thumbnailValid;
uint dialogIdFromType(DialogType type);
uint16 dialogConfirmValue();
uint16 dialogSaveValue();
+45 -1
View File
@@ -71,7 +71,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, const Myst3GameDescription *version) :
_inputSpacePressed(false), _inputEnterPressed(false),
_inputEscapePressed(false), _inputTildePressed(false),
_inputEscapePressedNotConsumed(false),
_interactive(false),
_interactive(false), _lastSaveTime(0),
_menuAction(0), _projectorBackground(0),
_shakeEffect(0), _rotationEffect(0), _backgroundSoundScriptLastRoomId(0),
_transition(0), _frameLimiter(0), _inventoryManualHide(false) {
@@ -210,6 +210,9 @@ Common::Error Myst3Engine::run() {
drawFrame();
}
if (!_menu->getThumbnailValid())
_menu->saveThumbnail(); // Update thumbnail before saving
tryAutoSaving(); //Attempt to autosave before exiting
unloadNode();
_archiveNode->close();
@@ -431,6 +434,7 @@ void Myst3Engine::processInput(bool interactive) {
}
bool shouldInteractWithHoveredElement = false;
_menu->setThumbnailValid(false);
// Process events
Common::Event event;
@@ -538,6 +542,11 @@ void Myst3Engine::processInput(bool interactive) {
interactWithHoveredElement();
}
if (shouldPerformAutoSave(_lastSaveTime)) {
_menu->saveThumbnail(); // Update thumbnail before saving
tryAutoSaving();
}
// Open main menu
// This is not checked directly in the event handling code
// because menu open requests done while in lookOnly mode
@@ -1479,6 +1488,14 @@ void Myst3Engine::dragItem(uint16 statusVar, uint16 movie, uint16 frame, uint16
}
}
bool Myst3Engine::canSaveGameStateCurrently() {
return canLoadGameStateCurrently() && !(_state->getLocationRoom() == 901 && _state->getMenuSavedAge()==0);
}
bool Myst3Engine::canSaveCurrently() {
return canLoadGameStateCurrently() && !(_state->getLocationRoom() == 901 && _state->getMenuSavedAge()==0);
}
bool Myst3Engine::canLoadGameStateCurrently() {
// Loading from the GMM is only possible when the game is interactive
// This is to prevent loading from inner loops. Loading while
@@ -1487,6 +1504,33 @@ bool Myst3Engine::canLoadGameStateCurrently() {
return _interactive;
}
void Myst3Engine::tryAutoSaving() {
if (!canSaveGameStateCurrently()) {
return; // Can't save right now, try again on the next frame
}
_lastSaveTime = _system->getMillis();
Common::String saveName = "Autosave";
Common::String fileName = Saves::buildName(saveName.c_str(),getPlatform());
Common::ScopedPtr<Common::InSaveFile> saveFile(getSaveFileManager()->openForLoading(fileName));
if (!_state->isAutoSaveAllowed(saveFile.get())) {
return; // Can't autosave ever, try again after the next autosave delay
}
// Save the state and the thumbnail
Common::OutSaveFile *save = getSaveFileManager()->openForSaving(fileName);
const Common::String prevSaveName = _state->getSaveDescription();
_state->setSaveDescription(saveName);
if (!_state->save(save,true))
warning("Attempt to autosave has failed.");
_state->setSaveDescription(prevSaveName);
delete save;
}
Common::Error Myst3Engine::loadGameState(int slot) {
Common::StringArray filenames = Saves::list(_saveFileMan, getPlatform());
return loadGameState(filenames[slot], kTransitionNone);
+5
View File
@@ -119,7 +119,10 @@ public:
uint32 getGameLocalizationType() const;
bool isWideScreenModEnabled() const;
bool canSaveGameStateCurrently() override; // Determines autosave saveability
bool canLoadGameStateCurrently() override;
bool canSaveCurrently() override; // Determines GMM saveability
void tryAutoSaving();
Common::Error loadGameState(int slot) override;
Common::Error loadGameState(Common::String fileName, TransitionType transition);
@@ -219,6 +222,8 @@ private:
bool _interactive;
uint32 _lastSaveTime;
uint32 _backgroundSoundScriptLastRoomId;
/**
+19 -1
View File
@@ -25,6 +25,7 @@
#include "engines/myst3/gfx.h"
#include "common/debug-channels.h"
#include "common/ptr.h"
#include "common/savefile.h"
#include "graphics/surface.h"
@@ -77,6 +78,7 @@ GameState::StateData::StateData() {
saveYear = 0;
saveHour = 0;
saveMinute = 0;
autoSave = false;
}
GameState::GameState(const Common::Platform platform, Database *database):
@@ -472,6 +474,7 @@ void GameState::StateData::syncWithSaveGame(Common::Serializer &s) {
s.syncAsUint16LE(saveYear, 149);
s.syncAsByte(saveHour, 149);
s.syncAsByte(saveMinute, 149);
s.syncAsByte(autoSave, 150);
s.syncString(saveDescription, 149);
#ifdef SCUMM_BIG_ENDIAN
@@ -531,7 +534,21 @@ bool GameState::load(Common::InSaveFile *saveFile) {
return true;
}
bool GameState::save(Common::OutSaveFile *saveFile) {
bool GameState::isAutoSaveAllowed(Common::InSaveFile *saveFile) {
// Check if file exists
if (!saveFile) { // The autosave file doesn't exist or is corrupt
return true;
}
// Get autoSave value from saved file
StateData data;
Common::Serializer s = Common::Serializer(saveFile, 0);
data.syncWithSaveGame(s);
return data.autoSave; // The autosave file exists and is either an autosave or not
}
bool GameState::save(Common::OutSaveFile *saveFile, bool autosave) {
Common::Serializer s = Common::Serializer(0, saveFile);
// Update save creation info
@@ -542,6 +559,7 @@ bool GameState::save(Common::OutSaveFile *saveFile) {
_data.saveDay = t.tm_mday;
_data.saveHour = t.tm_hour;
_data.saveMinute = t.tm_min;
_data.autoSave = autosave;
_data.gameRunning = false;
_data.syncWithSaveGame(s);
+10 -2
View File
@@ -53,7 +53,13 @@ public:
void newGame();
bool load(Common::InSaveFile *saveFile);
bool save(Common::OutSaveFile *saveFile);
bool save(Common::OutSaveFile *saveFile, bool autosave);
/*
* Autosaving will be enabled if The autosave file is an autosave or if The autosave file doesn't exist
* The autosave file name is version dependent (PC vs. Xbox)
*/
bool isAutoSaveAllowed(Common::InSaveFile *saveFile);
int32 getVar(uint16 var);
void setVar(uint16 var, int32 value);
@@ -338,6 +344,7 @@ public:
void setSaveThumbnail(Graphics::Surface *thumb);
Common::String formatSaveTime();
void setSaveDescription(const Common::String &description) { _data.saveDescription = description; }
const Common::String getSaveDescription() { return _data.saveDescription; }
Common::Array<uint16> getInventory();
void updateInventory(const Common::Array<uint16> &items);
@@ -379,6 +386,7 @@ public:
uint8 saveHour;
uint8 saveMinute;
bool autoSave;
Common::String saveDescription;
@@ -397,7 +405,7 @@ private:
const Common::Platform _platform;
Database *_db;
static const uint32 kSaveVersion = 149;
static const uint32 kSaveVersion = 150;
StateData _data;