diff options
author | Paul Gilbert | 2016-06-25 23:07:44 -0400 |
---|---|---|
committer | Paul Gilbert | 2016-07-15 19:25:03 -0400 |
commit | 04afc633794035cfcc0cb7030113d7750a7dbae3 (patch) | |
tree | 13eb89371f23cd0f28a7745a08c64b84b842dbb9 | |
parent | 507924b39d0beb50bacb05f3ad15f66fc113f3a9 (diff) | |
download | scummvm-rg350-04afc633794035cfcc0cb7030113d7750a7dbae3.tar.gz scummvm-rg350-04afc633794035cfcc0cb7030113d7750a7dbae3.tar.bz2 scummvm-rg350-04afc633794035cfcc0cb7030113d7750a7dbae3.zip |
TITANIC: Adding savegame header load/save methods
-rw-r--r-- | engines/titanic/core/project_item.cpp | 128 | ||||
-rw-r--r-- | engines/titanic/core/project_item.h | 35 | ||||
-rw-r--r-- | engines/titanic/support/simple_file.cpp | 31 | ||||
-rw-r--r-- | engines/titanic/support/simple_file.h | 33 | ||||
-rw-r--r-- | engines/titanic/titanic.cpp | 23 | ||||
-rw-r--r-- | engines/titanic/titanic.h | 36 |
6 files changed, 275 insertions, 11 deletions
diff --git a/engines/titanic/core/project_item.cpp b/engines/titanic/core/project_item.cpp index 7546f20936..c6a5c2eb61 100644 --- a/engines/titanic/core/project_item.cpp +++ b/engines/titanic/core/project_item.cpp @@ -22,6 +22,8 @@ #include "common/file.h" #include "common/savefile.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" #include "titanic/game_manager.h" #include "titanic/titanic.h" #include "titanic/core/dont_save_file_item.h" @@ -32,6 +34,13 @@ namespace Titanic { +#define CURRENT_SAVEGAME_VERSION 1 +#define MAX_SAVEGAME_SLOTS 99 +#define MINIMUM_SAVEGAME_VERSION 1 + +static const char *const SAVEGAME_STR = "TNIC"; +#define SAVEGAME_STR_SIZE 4 + void CFileListItem::save(SimpleFile *file, int indent) const { file->writeNumberLine(0, indent); file->writeQuotedLine(_name, indent); @@ -158,6 +167,11 @@ void CProjectItem::loadGame(int slotId) { file.open(newFile); } + // Load the savegame header in + TitanicSavegameHeader header; + readSavegameHeader(&file, header); + delete header._thumbnail; + // Load the contents in CProjectItem *newProject = loadData(&file); file.IsClassStart(); @@ -183,7 +197,7 @@ void CProjectItem::loadGame(int slotId) { postLoad(); } -void CProjectItem::saveGame(int slotId) { +void CProjectItem::saveGame(int slotId, const CString &desc) { CompressedFile file; Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving( Common::String::format("slot%d.gam", slotId)); @@ -192,6 +206,11 @@ void CProjectItem::saveGame(int slotId) { // Signal the game is being saved preSave(); + // Write out the savegame header + TitanicSavegameHeader header; + header._saveName = desc; + writeSavegameHeader(&file, header); + // Save the contents out saveData(&file, this); @@ -411,4 +430,111 @@ CViewItem *CProjectItem::findView(int roomNumber, int nodeNumber, int viewNumber return nullptr; } +SaveStateList CProjectItem::getSavegameList(const Common::String &target) { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String saveDesc; + Common::String pattern = Common::String::format("%s.0??", target.c_str()); + TitanicSavegameHeader header; + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort to get the files in numerical order + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + const char *ext = strrchr(file->c_str(), '.'); + int slot = ext ? atoi(ext + 1) : -1; + + if (slot >= 0 && slot < MAX_SAVEGAME_SLOTS) { + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); + + if (in) { + SimpleFile f; + f.open(in); + if (!readSavegameHeader(&f, header)) + continue; + + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + + header._thumbnail->free(); + delete header._thumbnail; + delete in; + } + } + } + + return saveList; +} + +bool CProjectItem::readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header) { + char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; + header._thumbnail = nullptr; + + // Validate the header Id + file->unsafeRead(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); + if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE)) { + file->seek(-SAVEGAME_STR_SIZE, SEEK_CUR); + header._saveName = "Unnamed"; + return true; + } + + header._version = file->readByte(); + if (header._version < MINIMUM_SAVEGAME_VERSION || header._version > CURRENT_SAVEGAME_VERSION) + return false; + + // Read in the string + header._saveName.clear(); + char ch; + while ((ch = (char)file->readByte()) != '\0') header._saveName += ch; + + // Get the thumbnail + header._thumbnail = Graphics::loadThumbnail(*file); + if (!header._thumbnail) + return false; + + // Read in save date/time + header._year = file->readUint16LE(); + header._month = file->readUint16LE(); + header._day = file->readUint16LE(); + header._hour = file->readUint16LE(); + header._minute = file->readUint16LE(); + header._totalFrames = file->readUint32LE(); + + return true; +} + +void CProjectItem::writeSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header) { + // Write out a savegame header + file->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1); + + file->writeByte(CURRENT_SAVEGAME_VERSION); + + // Write savegame name + file->write(header._saveName.c_str(), header._saveName.size()); + file->writeByte('\0'); + + // Create a thumbnail of the screen and save it out + Graphics::Surface *thumb = createThumbnail(); + Graphics::saveThumbnail(*file, *thumb); + thumb->free(); + delete thumb; + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + file->writeUint16LE(td.tm_year + 1900); + file->writeUint16LE(td.tm_mon + 1); + file->writeUint16LE(td.tm_mday); + file->writeUint16LE(td.tm_hour); + file->writeUint16LE(td.tm_min); + file->writeUint16LE(g_vm->_events->getFrameCounter()); +} + +Graphics::Surface *CProjectItem::createThumbnail() { + Graphics::Surface *thumb = new Graphics::Surface(); + + ::createThumbnailFromScreen(thumb); + return thumb; +} + } // End of namespace Titanic diff --git a/engines/titanic/core/project_item.h b/engines/titanic/core/project_item.h index 0807460852..213fa9d638 100644 --- a/engines/titanic/core/project_item.h +++ b/engines/titanic/core/project_item.h @@ -24,6 +24,9 @@ #define TITANIC_PROJECT_ITEM_H #include "common/scummsys.h" +#include "common/str.h" +#include "engines/savestate.h" +#include "graphics/surface.h" #include "titanic/support/simple_file.h" #include "titanic/core/dont_save_file_item.h" #include "titanic/core/file_item.h" @@ -32,6 +35,16 @@ namespace Titanic { +struct TitanicSavegameHeader { + uint8 _version; + CString _saveName; + Graphics::Surface *_thumbnail; + int _year, _month, _day; + int _hour, _minute; + int _totalFrames; +}; + + class CGameManager; class CPetControl; class CViewItem; @@ -117,6 +130,26 @@ private: * Save project data to the passed file */ void saveData(SimpleFile *file, CTreeItem *item) const; + + /** + * Creates a thumbnail for the current on-screen contents + */ + static Graphics::Surface *createThumbnail(); +public: + /** + * Load a list of savegames + */ + static SaveStateList getSavegameList(const Common::String &target); + + /** + * Write out the header information for a savegame + */ + static void writeSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header); + + /** + * Read in the header information for a savegame + */ + static bool readSavegameHeader(SimpleFile *file, TitanicSavegameHeader &header); public: CLASSDEF CProjectItem(); @@ -159,7 +192,7 @@ public: /** * Save the entire project data to a given savegame slot */ - void saveGame(int slotId); + void saveGame(int slotId, const CString &desc); /** * Clear any currently loaded project diff --git a/engines/titanic/support/simple_file.cpp b/engines/titanic/support/simple_file.cpp index 45b5c8a7cb..e60b7c7485 100644 --- a/engines/titanic/support/simple_file.cpp +++ b/engines/titanic/support/simple_file.cpp @@ -89,12 +89,29 @@ size_t SimpleFile::write(const void *src, size_t count) const { return _outStream->write(src, count); } +void SimpleFile::seek(int offset, int origin) { + assert(_inStream); + _inStream->seek(offset, origin); +} + byte SimpleFile::readByte() { byte b; safeRead(&b, 1); return b; } +uint SimpleFile::readUint16LE() { + uint val; + safeRead(&val, 2); + return READ_LE_UINT16(&val); +} + +uint SimpleFile::readUint32LE() { + uint val; + safeRead(&val, 4); + return READ_LE_UINT32(&val); +} + CString SimpleFile::readString() { char c; CString result; @@ -248,6 +265,20 @@ void SimpleFile::readBuffer(char *buffer, size_t count) { } } +void SimpleFile::writeUint16LE(uint val) { + byte lo = val & 0xff; + byte hi = (val >> 8) & 0xff; + write(&lo, 1); + write(&hi, 1); +} + +void SimpleFile::writeUint32LE(uint val) { + uint16 lo = val & 0xffff; + uint16 hi = (val >> 16) & 0xff; + writeUint16LE(lo); + writeUint16LE(hi); +} + void SimpleFile::writeLine(const CString &str) const { write(str.c_str(), str.size()); write("\r\n", 2); diff --git a/engines/titanic/support/simple_file.h b/engines/titanic/support/simple_file.h index bca96a631a..a83e5922e2 100644 --- a/engines/titanic/support/simple_file.h +++ b/engines/titanic/support/simple_file.h @@ -61,6 +61,9 @@ public: SimpleFile(); virtual ~SimpleFile(); + operator Common::SeekableReadStream &() { return *_inStream; } + operator Common::WriteStream &() { return *_outStream; } + /** * Set up a stream for read access */ @@ -92,11 +95,26 @@ public: virtual size_t write(const void *src, size_t count) const; /** + * Seek + */ + virtual void seek(int offset, int origin); + + /** * Read a byte */ byte readByte(); /** + * Read a 16-bit LE number + */ + uint readUint16LE(); + + /** + * Read a 32-bit LE number + */ + uint readUint32LE(); + + /** * Read a string from the file */ CString readString(); @@ -137,6 +155,21 @@ public: bool scanf(const char *format, ...); /** + * Write out a byte + */ + void writeByte(byte b) { write(&b, 1); } + + /** + * Write out a raw 16-bit LE number + */ + void writeUint16LE(uint val); + + /** + * Write out a raw 32-bit LE number + */ + void writeUint32LE(uint val); + + /** * Write a string line */ void writeLine(const CString &str) const; diff --git a/engines/titanic/titanic.cpp b/engines/titanic/titanic.cpp index 9d44cd6141..ab734d9eeb 100644 --- a/engines/titanic/titanic.cpp +++ b/engines/titanic/titanic.cpp @@ -157,4 +157,27 @@ void TitanicEngine::setRoomNames() { delete r; } + +bool TitanicEngine::canLoadGameStateCurrently() { + return _window->_inputAllowed; +} + +bool TitanicEngine::canSaveGameStateCurrently() { + return _window->_inputAllowed; +} + +Common::Error TitanicEngine::loadGameState(int slot) { + _window->_project->loadGame(slot); + return Common::kNoError; +} + +Common::Error TitanicEngine::saveGameState(int slot, const Common::String &desc) { + _window->_project->saveGame(slot, desc); + return Common::kNoError; +} + +CString TitanicEngine::generateSaveName(int slot) { + return CString::format("%s.%03d", _targetName.c_str(), slot); +} + } // End of namespace Titanic diff --git a/engines/titanic/titanic.h b/engines/titanic/titanic.h index 4391796e51..9acf78cbf2 100644 --- a/engines/titanic/titanic.h +++ b/engines/titanic/titanic.h @@ -73,15 +73,6 @@ enum TitanicDebugChannels { struct TitanicGameDescription; class TitanicEngine; -struct TitanicSavegameHeader { - uint8 _version; - Common::String _saveName; - Graphics::Surface *_thumbnail; - int _year, _month, _day; - int _hour, _minute; - int _totalFrames; -}; - class TitanicEngine : public Engine { private: /** @@ -133,6 +124,27 @@ public: TitanicEngine(OSystem *syst, const TitanicGameDescription *gameDesc); virtual ~TitanicEngine(); + + /** + * Returns true if a savegame can be loaded + */ + virtual bool canLoadGameStateCurrently(); + + /** + * Returns true if the game can be saved + */ + virtual bool canSaveGameStateCurrently(); + + /** + * Called by the GMM to load a savegame + */ + virtual Common::Error loadGameState(int slot); + + /** + * Called by the GMM to save the game + */ + virtual Common::Error saveGameState(int slot, const Common::String &desc); + uint32 getFeatures() const; bool isDemo() const; Common::Language getLanguage() const; @@ -141,6 +153,12 @@ public: * Gets a random number */ uint getRandomNumber(uint max) { return _randomSource.getRandomNumber(max); } + + /** + * Support method that generates a savegame name + * @param slot Slot number + */ + CString generateSaveName(int slot); }; extern TitanicEngine *g_vm; |