diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/cge/cge.h | 23 | ||||
-rw-r--r-- | engines/cge/cge_main.cpp | 314 |
2 files changed, 253 insertions, 84 deletions
diff --git a/engines/cge/cge.h b/engines/cge/cge.h index 9894cc07bc..2d67b2218a 100644 --- a/engines/cge/cge.h +++ b/engines/cge/cge.h @@ -25,7 +25,9 @@ #include "cge/general.h" #include "common/random.h" +#include "common/savefile.h" #include "common/serializer.h" +#include "common/str.h" #include "engines/engine.h" #include "gui/debugger.h" #include "graphics/surface.h" @@ -56,11 +58,27 @@ enum CallbackType { #define POCKET_NX 8 +#define CGE_SAVEGAME_VERSION 1 + +struct SavegameHeader { + uint8 version; + Common::String saveName; + Graphics::Surface *thumbnail; + int saveYear, saveMonth, saveDay; + int saveHour, saveMinutes; + int totalFrames; +}; + class CGEEngine : public Engine { private: uint32 _lastFrame; void tick(); void syncHeader(Common::Serializer &s); + bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header); + void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream, bool tiny = false); + bool savegameExists(int slotNumber); + Common::String generateSaveName(int slot); public: CGEEngine(OSystem *syst, const ADGameDescription *gameDescription); ~CGEEngine(); @@ -83,6 +101,7 @@ public: bool _game; int _now; int _lev; + char _usrFnam[15]; Common::RandomSource _randomSource; byte * _mini; @@ -100,7 +119,7 @@ public: void quit(); void resetQSwitch(); void optionTouch(int opt, uint16 mask); - void loadGame(XFile &file, bool tiny); + bool loadGame(int slotNumber, SavegameHeader *header = NULL, bool tiny = false); void setMapBrick(int x, int z); void switchMapping(); void loadSprite(const char *fname, int ref, int cav, int col, int row, int pos); @@ -129,7 +148,7 @@ public: void setIRQ(); void setDMA(); void mainLoop(); - void saveGame(Common::WriteStream *file); + void saveGame(int slotNumber, const Common::String &desc); void switchMusic(); void selectPocket(int n); void expandSprite(Sprite *spr); diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp index b43360c0b5..3ea82e3099 100644 --- a/engines/cge/cge_main.cpp +++ b/engines/cge/cge_main.cpp @@ -30,6 +30,9 @@ #include "common/savefile.h" #include "common/serializer.h" #include "common/str.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" #include "cge/general.h" #include "cge/sound.h" #include "cge/startup.h" @@ -86,7 +89,8 @@ Snail *_snail_; // 1.01 - 17VII95 - default savegame with sound ON // coditionals EVA for 2-month evaluation version -static char _usrFnam[15] = "\0ɱ%^þúȼ´ ÇÉ"; +const char *SAVEGAME_STR = "SCUMMVM_CGE"; +#define SAVEGAME_STR_SIZE 11 //-------------------------------------------------------------------------- @@ -137,84 +141,237 @@ void CGEEngine::syncHeader(Common::Serializer &s) { } } -void CGEEngine::loadGame(XFile &file, bool tiny = false) { - Sprite *spr; - int i; +bool CGEEngine::loadGame(int slotNumber, SavegameHeader *header, bool tiny) { + Common::MemoryReadStream *readStream; + SavegameHeader saveHeader; - // Read the data into a data buffer - int size = file.size() - file.mark(); - byte *dataBuffer = (byte *)malloc(size); - file.read(dataBuffer, size); - Common::MemoryReadStream readStream(dataBuffer, size, DisposeAfterUse::YES); - Common::Serializer s(&readStream, NULL); + if (slotNumber == -1) { + // Loading the data for the initial game state + SVG0FILE file = SVG0FILE(SVG0NAME); + int size = file.size(); + byte *dataBuffer = (byte *)malloc(size); + file.read(dataBuffer, size); + readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES); - // Synchronise header data - syncHeader(s); + } else { + // Open up the savgame file + Common::String slotName = generateSaveName(slotNumber); + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName); + + // Read the data into a data buffer + int size = saveFile->size(); + byte *dataBuffer = (byte *)malloc(size); + saveFile->read(dataBuffer, size); + readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES); + } - if (Startup::_core < CORE_HIG) - _music = false; + // Check to see if it's a ScummVM savegame or not + char buffer[SAVEGAME_STR_SIZE + 1]; + readStream->read(buffer, SAVEGAME_STR_SIZE + 1); - if (Startup::_soundOk == 1 && Startup::_mode == 0) { - _sndDrvInfo.Vol2._d = _volume[0]; - _sndDrvInfo.Vol2._m = _volume[1]; - sndSetVolume(); - } + if (strncmp(buffer, SAVEGAME_STR, SAVEGAME_STR_SIZE + 1) != 0) { + // It's not, so rewind back to the start + readStream->seek(0); - if (! tiny) { // load sprites & pocket - while (readStream.pos() < readStream.size()) { - Sprite S(this, NULL); - S.sync(s); - - S._prev = S._next = NULL; - spr = (scumm_stricmp(S._file + 2, "MUCHA") == 0) ? new Fly(this, NULL) - : new Sprite(this, NULL); - if (spr == NULL) - error("No core"); - *spr = S; - _vga->_spareQ->append(spr); + if (header) + // Header wanted where none exists, so return false + return false; + } else { + // Found header + if (!readSavegameHeader(readStream, saveHeader)) { + delete readStream; + return false; } - for (i = 0; i < POCKET_NX; i++) { - register int r = _pocref[i]; - delete _pocket[i]; - _pocket[i] = (r < 0) ? NULL : _vga->_spareQ->locate(r); + if (header) { + *header = saveHeader; + delete readStream; + return true; } + + // Delete the thumbnail + delete saveHeader.thumbnail; + + // If we're loading the auto-save slot, load the name + if (slotNumber == 0) + strncpy(_usrFnam, saveHeader.saveName.c_str(), 8); } + + // Get in the savegame + syncGame(readStream, NULL, tiny); + + delete readStream; + return true; +} + +/** + * Returns true if a given savegame exists + */ +bool CGEEngine::savegameExists(int slotNumber) { + Common::String slotName = generateSaveName(slotNumber); + + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName); + bool result = saveFile != NULL; + delete saveFile; + return result; } +/** + * Support method that generates a savegame name + * @param slot Slot number + */ +Common::String CGEEngine::generateSaveName(int slot) { + return Common::String::format("%s.%03d", _targetName.c_str(), slot); +} void CGEEngine::saveSound() { + warning("STUB: CGEEngine::saveSound"); + /* Convert to saving any such needed data in ScummVM configuration file + CFile cfg(usrPath(progName(CFG_EXT)), WRI); if (!cfg._error) cfg.write(&_sndDrvInfo, sizeof(_sndDrvInfo) - sizeof(_sndDrvInfo.Vol2)); + */ +} + +void CGEEngine::saveGame(int slotNumber, const Common::String &desc) { + // Set up the serializer + Common::String slotName = generateSaveName(slotNumber); + Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName); + + // Write out the ScummVM savegame header + SavegameHeader header; + header.saveName = desc; + header.version = CGE_SAVEGAME_VERSION; + writeSavegameHeader(saveFile, header); + + // Write out the data of the savegame + syncGame(NULL, saveFile); + + // Finish writing out game data + saveFile->finalize(); + delete saveFile; } +void CGEEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) { + // Write out a savegame header + out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1); + + out->writeByte(CGE_SAVEGAME_VERSION); + + // Write savegame name + out->write(header.saveName.c_str(), header.saveName.size() + 1); + + // Get the active palette + uint8 thumbPalette[256 * 3]; + g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256); + + // Create a thumbnail and save it + Graphics::Surface *thumb = new Graphics::Surface(); + Graphics::Surface *s = _vga->_page[1]; + ::createThumbnail(thumb, (const byte *)s->pixels, SCR_WID, SCR_HIG, thumbPalette); + Graphics::saveThumbnail(*out, *thumb); + delete thumb; + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); +} -void CGEEngine::saveGame(Common::WriteStream *file) { +void CGEEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream, bool tiny) { Sprite *spr; int i; - for (i = 0; i < POCKET_NX; i++) { - register Sprite *s = _pocket[i]; - _pocref[i] = (s) ? s->_ref : -1; - } + Common::Serializer s(readStream, writeStream); - _volume[0] = _sndDrvInfo.Vol2._d; - _volume[1] = _sndDrvInfo.Vol2._m; + if (s.isSaving()) { + for (i = 0; i < POCKET_NX; i++) { + register Sprite *s = _pocket[i]; + _pocref[i] = (s) ? s->_ref : -1; + } - Common::Serializer s(NULL, file); + _volume[0] = _sndDrvInfo.Vol2._d; + _volume[1] = _sndDrvInfo.Vol2._m; + } // Synchronise header data syncHeader(s); - // Loop through saving the sprite data - for (spr = _vga->_spareQ->first(); spr; spr = spr->_next) { - if ((spr->_ref >= 1000) && !s.err()) - spr->sync(s); + if (s.isSaving()) { + // Loop through saving the sprite data + for (spr = _vga->_spareQ->first(); spr; spr = spr->_next) { + if ((spr->_ref >= 1000) && !s.err()) + spr->sync(s); + } + } else { + // Loading game + if (Startup::_core < CORE_HIG) + _music = false; + + if (Startup::_soundOk == 1 && Startup::_mode == 0) { + _sndDrvInfo.Vol2._d = _volume[0]; + _sndDrvInfo.Vol2._m = _volume[1]; + sndSetVolume(); + } + + if (! tiny) { // load sprites & pocket + while (readStream->pos() < readStream->size()) { + Sprite S(this, NULL); + S.sync(s); + + S._prev = S._next = NULL; + spr = (scumm_stricmp(S._file + 2, "MUCHA") == 0) ? new Fly(this, NULL) + : new Sprite(this, NULL); + if (spr == NULL) + error("No core"); + *spr = S; + _vga->_spareQ->append(spr); + } + + for (i = 0; i < POCKET_NX; i++) { + register int r = _pocref[i]; + delete _pocket[i]; + _pocket[i] = (r < 0) ? NULL : _vga->_spareQ->locate(r); + } + } } +} + +bool CGEEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { + header.thumbnail = NULL; + + // Get the savegame version + header.version = in->readByte(); + if (header.version > CGE_SAVEGAME_VERSION) + return false; + + // Read in the string + header.saveName.clear(); + char ch; + while ((ch = (char)in->readByte()) != '\0') header.saveName += ch; + + // Get the thumbnail + header.thumbnail = new Graphics::Surface(); + if (!Graphics::loadThumbnail(*in, *header.thumbnail)) { + delete header.thumbnail; + header.thumbnail = NULL; + return false; + } + + // Read in save date/time + header.saveYear = in->readSint16LE(); + header.saveMonth = in->readSint16LE(); + header.saveDay = in->readSint16LE(); + header.saveHour = in->readSint16LE(); + header.saveMinutes = in->readSint16LE(); + + return true; - // Finish writing out game data - file->finalize(); } void CGEEngine::heroCover(int cvr) { @@ -483,9 +640,7 @@ void CGEEngine::qGame() { saveSound(); // Write out the user's progress - Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(Common::String(_usrFnam)); - saveGame(saveFile); - delete saveFile; + saveGame(0, _usrFnam); _vga->sunset(); _finis = true; @@ -773,6 +928,7 @@ void CGEEngine::takeName() { if (GetText::_ptr) SNPOST_(SNKILL, -1, 0, GetText::_ptr); else { + memset(_usrFnam, 0, 15); GetText *tn = new GetText(this, _text->getText(GETNAME_PROMPT), _usrFnam, 8); if (tn) { tn->setName(_text->getText(GETNAME_TITLE)); @@ -1290,25 +1446,15 @@ void CGEEngine::tick() { void CGEEngine::loadUser() { // set scene - if (Startup::_mode == 0) { // user .SVG file found - CFile cfile = CFile(usrPath(_usrFnam), REA, RCrypt); - loadGame(cfile); + if (Startup::_mode == 0) { + // user .SVG file found - load it from slot 0 + loadGame(0, NULL); } else { if (Startup::_mode == 1) { - SVG0FILE file = SVG0FILE(SVG0NAME); - loadGame(file); + // Load initial game state savegame + loadGame(-1, NULL); } else { - // TODO: I think this was only used by the original developers to create the initial - // game state savegame. Verify this is the case, and if so remove this block - loadScript(progName(INI_EXT)); - _music = true; - - Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving( - Common::String(SVG0NAME)); - saveGame(saveFile); - delete saveFile; - - error("Ok [%s]", SVG0NAME); + error("Creating setup savegames not supported"); } } loadScript(progName(IN0_EXT)); @@ -1533,17 +1679,22 @@ bool CGEEngine::showTitle(const char *name) { _vga->copyPage(0, 1); _vga->_showQ->append(_mouse); //Mouse.On(); - _heart->_enable = true; - for (takeName(); GetText::_ptr;) { - mainLoop(); - if (_eventManager->_quitFlag) - return false; - } - _heart->_enable = false; - if (_keyboard->last() == Enter && *_usrFnam) + + // For ScummVM, skip prompting for name if a savegame in slot 0 already exists + if (savegameExists(0)) { + strcpy(_usrFnam, "User"); usr_ok = true; - if (usr_ok) - strcat(_usrFnam, SVG_EXT); + } else { + _heart->_enable = true; + for (takeName(); GetText::_ptr;) { + mainLoop(); + if (_eventManager->_quitFlag) + return false; + } + _heart->_enable = false; + if (_keyboard->last() == Enter && *_usrFnam) + usr_ok = true; + } //Mouse.Off(); _vga->_showQ->clear(); _vga->copyPage(0, 2); @@ -1551,10 +1702,9 @@ bool CGEEngine::showTitle(const char *name) { } if (usr_ok && Startup::_mode == 0) { - const char *n = usrPath(_usrFnam); - if (CFile::exist(n)) { - CFile file = CFile(n, REA, RCrypt); - loadGame(file, true); // only system vars + if (savegameExists(0)) { + // Load the savegame + loadGame(0, NULL, true); // only system vars _vga->setColors(Vga::_sysPal, 64); _vga->update(); if (_flag[3]) { //flag FINIS |