diff options
| -rw-r--r-- | engines/hugo/detection.cpp | 127 | ||||
| -rw-r--r-- | engines/hugo/file.cpp | 103 | ||||
| -rw-r--r-- | engines/hugo/file.h | 4 | ||||
| -rw-r--r-- | engines/hugo/game.h | 2 | ||||
| -rw-r--r-- | engines/hugo/global.h | 3 | ||||
| -rw-r--r-- | engines/hugo/hugo.cpp | 11 | ||||
| -rw-r--r-- | engines/hugo/hugo.h | 44 | ||||
| -rw-r--r-- | engines/hugo/parser.cpp | 6 | ||||
| -rw-r--r-- | engines/hugo/parser_v1d.cpp | 10 | ||||
| -rw-r--r-- | engines/hugo/parser_v1w.cpp | 4 | ||||
| -rw-r--r-- | engines/hugo/parser_v2d.cpp | 10 | ||||
| -rw-r--r-- | engines/hugo/parser_v3d.cpp | 10 | 
12 files changed, 263 insertions, 71 deletions
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp index a4bc5a4c1c..05fe984615 100644 --- a/engines/hugo/detection.cpp +++ b/engines/hugo/detection.cpp @@ -24,6 +24,10 @@   */  #include "engines/advancedDetector.h" +#include "common/system.h" +#include "common/savefile.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h"  #include "hugo/hugo.h" @@ -38,6 +42,11 @@ uint32 HugoEngine::getFeatures() const {  	return _gameDescription->desc.flags;  } +const char *HugoEngine::getGameId() const { +	return _gameDescription->desc.gameid; +} + +  static const PlainGameDescriptor hugoGames[] = {  	// Games  	{"hugo1", "Hugo 1: Hugo's House of Horrors"}, @@ -162,8 +171,12 @@ public:  	}  	bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const; -  	bool hasFeature(MetaEngineFeature f) const; + +	int getMaximumSaveSlot() const; +	SaveStateList listSaves(const char *target) const; +	SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; +	void removeSaveState(const char *target, int slot) const;  };  bool HugoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const { @@ -175,9 +188,117 @@ bool HugoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame  }  bool HugoMetaEngine::hasFeature(MetaEngineFeature f) const { -	return false; +	return +	    (f == kSupportsListSaves) || +	    (f == kSupportsLoadingDuringStartup) || +	    (f == kSupportsDeleteSave) || +	    (f == kSavesSupportMetaInfo) || +	    (f == kSavesSupportThumbnail) || +	    (f == kSavesSupportCreationDate); +} + +int HugoMetaEngine::getMaximumSaveSlot() const { return 99; } + +SaveStateList HugoMetaEngine::listSaves(const char *target) const { +	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); +	Common::StringArray filenames; +	Common::String pattern = target; +	pattern += "-??.SAV"; + +	filenames = saveFileMan->listSavefiles(pattern); +	sort(filenames.begin(), filenames.end());   // Sort (hopefully ensuring we are sorted numerically..) + +	SaveStateList saveList; +	int slotNum = 0; +	for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) { +		// Obtain the last 3 digits of the filename, since they correspond to the save slot +		slotNum = atoi(filename->c_str() + filename->size() - 3); + +		if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) { +			Common::InSaveFile *file = saveFileMan->openForLoading(*filename); +			if (file) { +				int saveVersion = file->readByte(); + +				if (saveVersion != kSavegameVersion) { +					warning("Savegame of incompatible version"); +					delete file; +					continue; +				} + +				// read name +				uint16 nameSize = file->readUint16BE(); +				if (nameSize >= 255) { +					delete file; +					continue; +				} +				char name[256]; +				file->read(name, nameSize); +				name[nameSize] = 0; + +				saveList.push_back(SaveStateDescriptor(slotNum, name)); +				delete file; +			} +		} +	} + +	return saveList;  } +SaveStateDescriptor HugoMetaEngine::querySaveMetaInfos(const char *target, int slot) const { +	Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); +	Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); + +	if (file) { +		int saveVersion = file->readByte(); + +		if (saveVersion != kSavegameVersion) { +			warning("Savegame of incompatible version"); +			delete file; +			return SaveStateDescriptor(); +		} + +		uint32 saveNameLength = file->readUint16BE(); +		char saveName[256]; +		file->read(saveName, saveNameLength); +		saveName[saveNameLength] = 0; + +		SaveStateDescriptor desc(slot, saveName); + +		Graphics::Surface *thumbnail = new Graphics::Surface(); +		assert(thumbnail); +		if (!Graphics::loadThumbnail(*file, *thumbnail)) { +			delete thumbnail; +			thumbnail = 0; +		} +		desc.setThumbnail(thumbnail); + +		desc.setDeletableFlag(true); +		desc.setWriteProtectedFlag(false); + +		uint32 saveDate = file->readUint32BE(); +		uint16 saveTime = file->readUint16BE(); + +		int day = (saveDate >> 24) & 0xFF; +		int month = (saveDate >> 16) & 0xFF; +		int year = saveDate & 0xFFFF; + +		desc.setSaveDate(year, month, day); + +		int hour = (saveTime >> 8) & 0xFF; +		int minutes = saveTime & 0xFF; + +		desc.setSaveTime(hour, minutes); + +		delete file; +		return desc; +	} +	return SaveStateDescriptor(); +} + +void HugoMetaEngine::removeSaveState(const char *target, int slot) const { +	Common::String fileName = Common::String::format("%s-%02d.SAV", target, slot); +	g_system->getSavefileManager()->removeSavefile(fileName); +}  } // End of namespace Hugo  #if PLUGIN_ENABLED_DYNAMIC(HUGO) @@ -195,7 +316,7 @@ void HugoEngine::initGame(const HugoGameDescription *gd) {  	_gameVariant = _gameType - 1 + ((_platform == Common::kPlatformWindows) ? 0 : 3);  	// Generate filename -	_saveFilename = _targetName + "-%d.SAV"; +	_saveFilename = _targetName + "-%02d.SAV";  }  } // End of namespace Hugo diff --git a/engines/hugo/file.cpp b/engines/hugo/file.cpp index 78bcc46e85..e34679fce3 100644 --- a/engines/hugo/file.cpp +++ b/engines/hugo/file.cpp @@ -32,6 +32,9 @@  #include "common/system.h"  #include "common/savefile.h" +#include "common/config-manager.h" +#include "graphics/thumbnail.h" +#include "gui/saveload.h"  #include "hugo/hugo.h"  #include "hugo/file.h" @@ -299,22 +302,61 @@ bool FileManager::fileExists(char *filename) {  /**  * Save game to supplied slot  */ -void FileManager::saveGame(int16 slot, const char *descrip) { +bool FileManager::saveGame(int16 slot, Common::String descrip) {  	debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip); -	// Get full path of saved game file - note test for INITFILE -	Common::String path = Common::String::format(_vm->_saveFilename.c_str(), slot); -	Common::WriteStream *out = _vm->getSaveFileManager()->openForSaving(path); +	const EnginePlugin *plugin = NULL; +	int16 savegameId; +	Common::String savegameDescription; +	EngineMan.findGame(_vm->getGameId(), &plugin); + +	if (slot == -1) { +		GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); +		dialog->setSaveMode(true); +		savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); +		savegameDescription = dialog->getResultString(); +		delete dialog; +	} else { +		savegameId = slot; +		if (!descrip.empty()) { +			savegameDescription = descrip; +		} else { +			savegameDescription = Common::String::format("Quick save #%d", slot); +		} +	} + +	if (savegameId < 0)                             // dialog aborted +		return false; + +	Common::String savegameFile = Common::String::format(_vm->_saveFilename.c_str(), savegameId); +	Common::SaveFileManager *saveMan = g_system->getSavefileManager(); +	Common::OutSaveFile *out = saveMan->openForSaving(savegameFile); +  	if (!out) { -		warning("Can't create file '%s', game not saved", path.c_str()); -		return; +		warning("Can't create file '%s', game not saved", savegameFile.c_str()); +		return false;  	}  	// Write version.  We can't restore from obsolete versions  	out->writeByte(kSavegameVersion); -	// Save description of saved game -	out->write(descrip, DESCRIPLEN); +	if (savegameDescription == "") { +		savegameDescription = "Untitled savegame"; +	} + +	out->writeSint16BE(savegameDescription.size() + 1); +	out->write(savegameDescription.c_str(), savegameDescription.size() + 1); + +	Graphics::saveThumbnail(*out); + +	TimeDate curTime; +	_vm->_system->getTimeAndDate(curTime); + +	uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF); +	uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF); + +	out->writeUint32BE(saveDate); +	out->writeUint16BE(saveTime);  	_vm->_object->saveObjects(out); @@ -365,35 +407,57 @@ void FileManager::saveGame(int16 slot, const char *descrip) {  	out->finalize();  	delete out; + +	return true;  }  /**  * Restore game from supplied slot number  */ -void FileManager::restoreGame(int16 slot) { +bool FileManager::restoreGame(int16 slot) {  	debugC(1, kDebugFile, "restoreGame(%d)", slot); -	// Initialize new-game status -	_vm->initStatus(); +	const EnginePlugin *plugin = NULL; +	int16 savegameId; +	EngineMan.findGame(_vm->getGameId(), &plugin); -	// Get full path of saved game file - note test for INITFILE -	Common::String path; // Full path of saved game +	if (slot == -1) { +		GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); +		dialog->setSaveMode(false); +		savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); +		delete dialog; +	} else { +		savegameId = slot; +	} + +	if (savegameId < 0)                             // dialog aborted +		return false; -	path = Common::String::format(_vm->_saveFilename.c_str(), slot); +	Common::String savegameFile = Common::String::format(_vm->_saveFilename.c_str(), savegameId); +	Common::SaveFileManager *saveMan = g_system->getSavefileManager(); +	Common::InSaveFile *in = saveMan->openForLoading(savegameFile); -	Common::SeekableReadStream *in = _vm->getSaveFileManager()->openForLoading(path);  	if (!in) -		return; +		return false; + +	// Initialize new-game status +	_vm->initStatus();  	// Check version, can't restore from different versions  	int saveVersion = in->readByte();  	if (saveVersion != kSavegameVersion) { -		error("Savegame of incompatible version"); -		return; +		warning("Savegame of incompatible version"); +		delete in; +		return false;  	}  	// Skip over description -	in->seek(DESCRIPLEN, SEEK_CUR); +	int32 saveGameNameSize = in->readSint16BE(); +	in->skip(saveGameNameSize); + +	Graphics::skipThumbnail(*in); + +	in->skip(6);                                    // Skip date & time  	// If hero image is currently swapped, swap it back before restore  	if (_vm->_heroImage != HERO) @@ -446,6 +510,7 @@ void FileManager::restoreGame(int16 slot) {  	_maze.firstScreenIndex = in->readByte();  	delete in; +	return true;  }  /** diff --git a/engines/hugo/file.h b/engines/hugo/file.h index 1f231d0604..4dfd7167c0 100644 --- a/engines/hugo/file.h +++ b/engines/hugo/file.h @@ -63,8 +63,8 @@ public:  	void     readImage(int objNum, object_t *objPtr);  	void     readUIFImages();  	void     readUIFItem(int16 id, byte *buf); -	void     restoreGame(int16 slot); -	void     saveGame(int16 slot, const char *descrip); +	bool     restoreGame(int16 slot); +	bool     saveGame(int16 slot, Common::String descrip);  	virtual void openDatabaseFiles() = 0;  	virtual void closeDatabaseFiles() = 0; diff --git a/engines/hugo/game.h b/engines/hugo/game.h index a4f450bfbf..3c88c4cafa 100644 --- a/engines/hugo/game.h +++ b/engines/hugo/game.h @@ -836,7 +836,6 @@ struct status_t {                                   // Game status (not saved)  	go_t     go_for;                                // Purpose of an automatic route  	int16    go_id;                                 // Index of exit of object walking to  	fpath_t  path;                                  // Alternate path for saved files -	int16    saveSlot;                              // Current slot to save/restore game  	int16    song;                                  // Current song  	int16    cx, cy;                                // Cursor position (dib coords) @@ -847,6 +846,7 @@ struct status_t {                                   // Game status (not saved)  //	bool     mmtimeFl;                              // Multimedia timer supported  //	int16    screenWidth;                           // Desktop screen width  //	uint32   saveTick;                              // Time of last save in ticks +//	int16    saveSlot;                              // Current slot to save/restore game  };  struct config_t {                                   // User's config (saved) diff --git a/engines/hugo/global.h b/engines/hugo/global.h index 43a1e39b8f..d44b5cb44f 100644 --- a/engines/hugo/global.h +++ b/engines/hugo/global.h @@ -47,7 +47,4 @@ namespace Hugo {  // User interface database (Windows Only)  // This file contains, between others, the bitmaps of the fonts used in the application  #define UIF_FILE   "uif.dat" - -static const int kSavegameVersion = 1; -  } // End of namespace Hugo diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp index 06cd7db62b..c3e4658e8b 100644 --- a/engines/hugo/hugo.cpp +++ b/engines/hugo/hugo.cpp @@ -69,6 +69,7 @@ HugoEngine::HugoEngine(OSystem *syst, const HugoGameDescription *gd) : Engine(sy  	_backgroundObjectsSize(0), _screenActsSize(0), _usesSize(0)  { +	_system = syst;  	DebugMan.addDebugChannel(kDebugSchedule, "Schedule", "Script Schedule debug level");  	DebugMan.addDebugChannel(kDebugEngine, "Engine", "Engine debug level");  	DebugMan.addDebugChannel(kDebugDisplay, "Display", "Display debug level"); @@ -915,7 +916,6 @@ void HugoEngine::initStatus() {  	_status.helpFl        = false;                  // Not calling WinHelp()  	_status.doQuitFl      = false;  	_status.path[0]       = 0;                      // Path to write files -	_status.saveSlot      = 0;                      // Slot to save/restore game  	// Initialize every start of new game  	_status.tick            = 0;                    // Tick count @@ -934,6 +934,7 @@ void HugoEngine::initStatus() {  //	_status.mmtime        = false;                  // Multimedia timer support  //	_status.screenWidth   = 0;                      // Desktop screen width  //	_status.saveTick      = 0;                      // Time of last save +//	_status.saveSlot      = 0;                      // Slot to save/restore game  }  /** @@ -1256,4 +1257,12 @@ void HugoEngine::endGame() {  	_status.viewState = V_EXIT;  } +bool HugoEngine::canLoadGameStateCurrently() { +	return true; +} + +bool HugoEngine::canSaveGameStateCurrently() { +	return (_status.viewState == V_PLAY); +} +  } // End of namespace Hugo diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h index d7dd767b6b..903dd5a7bc 100644 --- a/engines/hugo/hugo.h +++ b/engines/hugo/hugo.h @@ -32,6 +32,7 @@  // This include is here temporarily while the engine is being refactored.  #include "hugo/game.h" +#include "hugo/file.h"  #define HUGO_DAT_VER_MAJ 0                          // 1 byte  #define HUGO_DAT_VER_MIN 30                         // 1 byte @@ -59,6 +60,8 @@ class RandomSource;   */  namespace Hugo { +static const int kSavegameVersion = 2; +  enum GameType {  	kGameTypeNone  = 0,  	kGameTypeHugo1, @@ -114,6 +117,8 @@ public:  	HugoEngine(OSystem *syst, const HugoGameDescription *gd);  	~HugoEngine(); +	OSystem *_system; +  	byte   _numVariant;  	byte   _gameVariant;  	byte   _maxInvent; @@ -172,6 +177,7 @@ public:  	const HugoGameDescription *_gameDescription;  	uint32 getFeatures() const; +	const char *HugoEngine::getGameId() const;  	GameType getGameType() const;  	Common::Platform getPlatform() const; @@ -183,17 +189,17 @@ public:  		return *s_Engine;  	} -	void initGame(const HugoGameDescription *gd); -	void initGamePart(const HugoGameDescription *gd); +	bool canLoadGameStateCurrently(); +	bool canSaveGameStateCurrently();  	bool loadHugoDat(); -	int getMouseX() const { -		return _mouseX; -	} -	int getMouseY() const { -		return _mouseY; -	} +	char *useBG(char *name); +	int  deltaX(int x1, int x2, int vx, int y); +	int  deltaY(int x1, int x2, int vy, int y); + +	void initGame(const HugoGameDescription *gd); +	void initGamePart(const HugoGameDescription *gd);  	void boundaryCollision(object_t *obj);  	void clearBoundary(int x1, int x2, int y);  	void endGame(); @@ -204,10 +210,12 @@ public:  	void shutdown();  	void storeBoundary(int x1, int x2, int y); -	char *useBG(char *name); - -	int deltaX(int x1, int x2, int vx, int y); -	int deltaY(int x1, int x2, int vy, int y); +	int getMouseX() const { +		return _mouseX; +	} +	int getMouseY() const { +		return _mouseY; +	}  	overlay_t &getBoundaryOverlay() {  		return _boundary; @@ -242,6 +250,18 @@ public:  	byte getIntroSize() {  		return _introXSize;  	} +	Common::Error saveGameState(int slot, const char *desc) { +		 +		return (_file->saveGame(slot, desc) ? Common::kWritingFailed : Common::kNoError); +	} + +	Common::Error loadGameState(int slot) { +		return (_file->restoreGame(slot) ? Common::kReadingFailed : Common::kNoError); +	} + +	bool hasFeature(EngineFeature f) const { +		return (f == kSupportsRTL) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime); +	}  	FileManager *_file;  	Scheduler *_scheduler; diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp index f23427e690..19d496dfd4 100644 --- a/engines/hugo/parser.cpp +++ b/engines/hugo/parser.cpp @@ -100,13 +100,11 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {  		gameStatus.recallFl = true;  		break;  	case Common::KEYCODE_F4:                        // Save game -		// TODO: Add a proper screen to select saveslot  		if (gameStatus.viewState == V_PLAY) -			_vm->_file->saveGame(gameStatus.saveSlot, "Current game"); +			_vm->_file->saveGame(-1, Common::String());  		break;  	case Common::KEYCODE_F5:                        // Restore game -		// TODO: Add a proper screen to specify saveslot and description -		_vm->_file->restoreGame(gameStatus.saveSlot); +		_vm->_file->restoreGame(-1);  		_vm->_scheduler->restoreScreen(*_vm->_screen_p);  		gameStatus.viewState = V_PLAY;  		break; diff --git a/engines/hugo/parser_v1d.cpp b/engines/hugo/parser_v1d.cpp index 9514f88178..9aab521a18 100644 --- a/engines/hugo/parser_v1d.cpp +++ b/engines/hugo/parser_v1d.cpp @@ -320,18 +320,12 @@ void Parser_v1d::lineHandler() {  		if (gameStatus.gameOverFl)  			Utils::gameOverMsg();  		else -//			_vm->_file->saveOrRestore(true); -			warning("STUB: saveOrRestore()"); -			// HACK: Currently use Win code -			_vm->_file->saveGame(gameStatus.saveSlot, "Current game"); +			_vm->_file->saveGame(-1, Common::String());  		return;  	}  	if (!strcmp("restore", _line)) { -//		_vm->_file->saveOrRestore(false); -		warning("STUB: saveOrRestore()"); -		// HACK: Currently use Win code -		_vm->_file->restoreGame(gameStatus.saveSlot); +		_vm->_file->restoreGame(-1);  		_vm->_scheduler->restoreScreen(*_vm->_screen_p);  		gameStatus.viewState = V_PLAY;  		return; diff --git a/engines/hugo/parser_v1w.cpp b/engines/hugo/parser_v1w.cpp index 4bfdd281ba..236d24b61b 100644 --- a/engines/hugo/parser_v1w.cpp +++ b/engines/hugo/parser_v1w.cpp @@ -369,12 +369,12 @@ void Parser_v1w::lineHandler() {  	// SAVE/RESTORE  	if (!strcmp("save", _line) && gameStatus.viewState == V_PLAY) { -		_vm->_file->saveGame(gameStatus.saveSlot, "Current game"); +		_vm->_file->saveGame(-1, Common::String());  		return;  	}  	if (!strcmp("restore", _line) && (gameStatus.viewState == V_PLAY || gameStatus.viewState == V_IDLE)) { -		_vm->_file->restoreGame(gameStatus.saveSlot); +		_vm->_file->restoreGame(-1);  		_vm->_scheduler->restoreScreen(*_vm->_screen_p);  		gameStatus.viewState = V_PLAY;  		return; diff --git a/engines/hugo/parser_v2d.cpp b/engines/hugo/parser_v2d.cpp index 802f69056b..a0b0db6234 100644 --- a/engines/hugo/parser_v2d.cpp +++ b/engines/hugo/parser_v2d.cpp @@ -75,19 +75,13 @@ void Parser_v2d::lineHandler() {  		if (gameStatus.gameOverFl)  			Utils::gameOverMsg();  		else -//			_vm->_file->saveOrRestore(true); -			warning("STUB: saveOrRestore()"); -			// HACK: Currently use Win code -			_vm->_file->saveGame(gameStatus.saveSlot, "Current game"); +			_vm->_file->saveGame(-1, Common::String());  		return;  	}  	if (!strcmp("restore", _line)) {  		_config.soundFl = false; -//		_vm->_file->saveOrRestore(false); -		warning("STUB: saveOrRestore()"); -		// HACK: Currently use Win code -		_vm->_file->restoreGame(gameStatus.saveSlot); +		_vm->_file->restoreGame(-1);  		_vm->_scheduler->restoreScreen(*_vm->_screen_p);  		gameStatus.viewState = V_PLAY;  		return; diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp index 54c3e830ce..ca78307a44 100644 --- a/engines/hugo/parser_v3d.cpp +++ b/engines/hugo/parser_v3d.cpp @@ -127,19 +127,13 @@ void Parser_v3d::lineHandler() {  		if (gameStatus.gameOverFl)  			Utils::gameOverMsg();  		else -//			_vm->_file->saveOrRestore(true); -			warning("STUB: saveOrRestore()"); -			// HACK: Currently use Win code -			_vm->_file->saveGame(gameStatus.saveSlot, "Current game"); +			_vm->_file->saveGame(-1, Common::String());  		return;  	}  	if (!strcmp("restore", _line)) {  		_config.soundFl = false; -//		_vm->_file->saveOrRestore(false); -		warning("STUB: saveOrRestore()"); -		// HACK: Currently use Win code -		_vm->_file->restoreGame(gameStatus.saveSlot); +		_vm->_file->restoreGame(-1);  		_vm->_scheduler->restoreScreen(*_vm->_screen_p);  		gameStatus.viewState = V_PLAY;  		return;  | 
