mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
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:
committed by
Bastien Bouclet
parent
08df1680e8
commit
006aaa2c43
+23
-9
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user