From c8b1c747242df4d8c596873ee320d64583380be0 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sun, 22 Jul 2012 07:28:17 +0200 Subject: WINTERMUTE: Add in a fallback-detector for unknown games. (flagged as "fangame" for now) This does a minimal engine-startup to open any dcp's and get the proper "startup.settings"-file, and then get the name/caption fields from that file. There are currently no handling of localized strings used there (base_string_table would be the culprit). And, there is also no secondary checks for language (but for that matter, there is no support for chosing language if multiple exist at this point either). --- engines/wintermute/detection.cpp | 62 +++++++++++++++++++++++++++++++++++++-- engines/wintermute/wintermute.cpp | 62 +++++++++++++++++++++++++++++++++++++++ engines/wintermute/wintermute.h | 3 ++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index 285c3ffaeb..5e259f717d 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -32,6 +32,24 @@ #include "engines/wintermute/detection_tables.h" +namespace WinterMute { + +/** + * The fallback game descriptor used by the WinterMute engine's fallbackDetector. + * Contents of this struct are overwritten by the fallbackDetector. (logic copied partially + * from the SCI-engine). + */ +static ADGameDescription s_fallbackDesc = { + "", + "", + AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() +}; +static char s_fallbackGameIdBuf[256]; + class WinterMuteMetaEngine : public AdvancedMetaEngine { public: WinterMuteMetaEngine() : AdvancedMetaEngine(WinterMute::gameDescriptions, sizeof(ADGameDescription), WinterMute::wintermuteGames) { @@ -83,6 +101,44 @@ public: } return detectedGames; }*/ + + + virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { + // Set some defaults + s_fallbackDesc.extra = ""; + s_fallbackDesc.language = Common::UNK_LANG; + s_fallbackDesc.flags = ADGF_UNSTABLE; + s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows + s_fallbackDesc.gameid = "wintermute"; + s_fallbackDesc.guioptions = GUIO0(); + + if (allFiles.contains("data.dcp")) { + Common::String name, caption; + if (WinterMuteEngine::getGameInfo(fslist, name, caption)) { + for (int32 i = 0; i < name.size(); i++) { + // Replace spaces with underscores + if (name[i] == ' ') { + name.setChar('_', (uint32)i); + } + } + // Prefix to avoid collisions with actually known games + name = "wmefan-" + name; + strncpy(s_fallbackGameIdBuf, name.c_str(), sizeof(s_fallbackGameIdBuf) - 1); + s_fallbackDesc.gameid = s_fallbackGameIdBuf; + if (caption != name) { + caption += " (fangame) "; + char *offset = s_fallbackGameIdBuf + name.size() + 1; + uint32 remainingLength = (sizeof(s_fallbackGameIdBuf) - 1) - (name.size() + 1); + strncpy(offset, caption.c_str(), remainingLength); + s_fallbackDesc.extra = offset; + s_fallbackDesc.flags |= ADGF_USEEXTRAASTITLE; + } + return &s_fallbackDesc; + } // Fall through to return 0; + } + return 0; + } + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { assert(syst); assert(engine); @@ -141,8 +197,10 @@ public: } }; +} // end of namespace WinterMute + #if PLUGIN_ENABLED_DYNAMIC(WINTERMUTE) -REGISTER_PLUGIN_DYNAMIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, WinterMuteMetaEngine); +REGISTER_PLUGIN_DYNAMIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, WinterMute::WinterMuteMetaEngine); #else -REGISTER_PLUGIN_STATIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, WinterMuteMetaEngine); +REGISTER_PLUGIN_STATIC(WINTERMUTE, PLUGIN_TYPE_ENGINE, WinterMute::WinterMuteMetaEngine); #endif diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index 69c5df5bc5..9040de66e6 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -29,6 +29,7 @@ #include "common/EventRecorder.h" #include "common/file.h" #include "common/fs.h" +#include "common/tokenizer.h" #include "engines/util.h" #include "engines/wintermute/ad/ad_game.h" @@ -37,12 +38,24 @@ #include "engines/wintermute/base/base_registry.h" #include "engines/wintermute/base/sound/base_sound_manager.h" +#include "engines/wintermute/base/base_file_manager.h" #include "engines/wintermute/base/scriptables/script_engine.h" namespace WinterMute { WinterMuteEngine *g_wintermute; +// Simple constructor for detection - we need to setup the persistence to avoid special-casing in-engine +// This might not be the prettiest solution +WinterMuteEngine::WinterMuteEngine() : Engine(g_system) { + g_wintermute = this; + _classReg = new SystemClassRegistry(); + _classReg->registerClasses(); + + _game = new AdGame(); + _rnd = NULL; +} + WinterMuteEngine::WinterMuteEngine(OSystem *syst, const ADGameDescription *desc) : Engine(syst), _gameDescription(desc) { // Put your engine in a sane state, but do nothing big yet; @@ -74,7 +87,10 @@ WinterMuteEngine::~WinterMuteEngine() { debug("WinterMuteEngine::~WinterMuteEngine"); // Dispose your resources here + delete _classReg; delete _rnd; + delete _game; + g_wintermute = NULL; // Remove all of our debug levels here DebugMan.clearAllDebugChannels(); @@ -320,6 +336,52 @@ int WinterMuteEngine::messageLoop() { void WinterMuteEngine::deinit() { delete _classReg; + _classReg = NULL; +} + +bool WinterMuteEngine::getGameInfo(const Common::FSList &fslist, Common::String &name, Common::String &caption) { + bool retVal = false; + caption = name = "(invalid)"; + + // Quick-fix, instead of possibly breaking the persistence-system, let's just roll with it + WinterMuteEngine *engine = new WinterMuteEngine(); + + engine->_game->initialize1(); + engine->_game->_fileManager->registerPackages(fslist); + if (engine->_game->loadSettings("startup.settings")) { + // We do some manual parsing here, as the engine needs gfx to be initalized to do that. + Common::SeekableReadStream *stream = engine->_game->_fileManager->openFile((engine->_game->_settingsGameFile ? engine->_game->_settingsGameFile : "default.game"), false, false); + while (!stream->eos() && !stream->err()) { + Common::String line = stream->readLine(); + line.trim(); // Get rid of indentation + // Expect "GAME {" or comment, or empty line + if (line.size() == 0 || line[0] == ';' || (line.contains("{"))) + continue; + else { + Common::StringTokenizer token(line, "="); + Common::String key = token.nextToken(); + Common::String value = token.nextToken(); + if (value.size() == 0) + continue; + if (value[0] == '\"') + value.deleteChar(0); + else + continue; // not a string + if (value.lastChar() == '\"') + value.deleteLastChar(); + if (key == "NAME") { + retVal = true; + name = value; + } else if (key == "CAPTION") { + retVal = true; + caption = value; + } + } + } + delete stream; + } + delete engine; + return retVal; } uint32 WinterMuteEngine::randInt(int from, int to) { diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h index b37f495b5e..e850a72196 100644 --- a/engines/wintermute/wintermute.h +++ b/engines/wintermute/wintermute.h @@ -44,6 +44,7 @@ enum { class WinterMuteEngine : public Engine { public: WinterMuteEngine(OSystem *syst, const ADGameDescription *desc); + WinterMuteEngine(); ~WinterMuteEngine(); virtual Common::Error run(); @@ -51,6 +52,8 @@ public: Common::SaveFileManager *getSaveFileMan() { return _saveFileMan; } SystemClassRegistry *getClassRegistry(){ return _classReg; } uint32 randInt(int from, int to); + // For detection-purposes: + static bool getGameInfo(const Common::FSList &fslist, Common::String &name, Common::String &caption); private: int init(); void deinit(); -- cgit v1.2.3