diff options
Diffstat (limited to 'engines/glk/detection.cpp')
-rw-r--r-- | engines/glk/detection.cpp | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/engines/glk/detection.cpp b/engines/glk/detection.cpp new file mode 100644 index 0000000000..9266825fa2 --- /dev/null +++ b/engines/glk/detection.cpp @@ -0,0 +1,323 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "glk/gargoyle.h" + +#include "base/plugins.h" +#include "common/md5.h" +#include "common/memstream.h" +#include "common/savefile.h" +#include "common/str-array.h" +#include "common/system.h" +#include "engines/advancedDetector.h" +#include "graphics/colormasks.h" +#include "graphics/surface.h" + +#define MAX_SAVES 99 + +namespace Gargoyle { + +struct GargoyleGameDescription { + ADGameDescription _desc; + Common::String _filename; + InterpreterType _interpType; + Common::String _md5; +}; + +const Common::String &GargoyleEngine::getFilename() const { + return _gameDescription->_filename; +} +uint32 GargoyleEngine::getFeatures() const { + return _gameDescription->_desc.flags; +} + +bool GargoyleEngine::isDemo() const { + return (bool)(_gameDescription->_desc.flags & ADGF_DEMO); +} + +Common::Language GargoyleEngine::getLanguage() const { + return _gameDescription->_desc.language; +} + +InterpreterType GargoyleEngine::getInterpreterType() const { + return _gameDescription->_interpType; +} + +const Common::String &GargoyleEngine::getGameMD5() const { + return _gameDescription->_md5; +} + +} // End of namespace Gargoyle + +#include "glk/frotz/detection_tables.h" +#define ZCODE(ID, NAME) { ID, Gargoyle::Frotz::NAME##_DESC } + +static const PlainGameDescriptor gargoyleGames[] = { + {"zcode", "Zcode Games" }, + {"scottadams", "Scott Adams Games"}, + + // Infocom/Z-code games + ZCODE("amfv", AMFV), + ZCODE("arthur", ARTHUR), + ZCODE("ballyhoo", BALLYHOO), + ZCODE("beyondzork", BEYONDZORK), + ZCODE("borderzone", BORDERZONE), + ZCODE("bureaucracy", BUREAUCRACY), + ZCODE("cutthroats", CUTTHROATS), + ZCODE("deadline", DEADLINE), + ZCODE("enchanter", ENCHANTER), + ZCODE("hhgttg", HHGTTG), + ZCODE("hijinx", HIJINX), + ZCODE("infidel", INFIDEL), + ZCODE("journey", JOURNEY), + ZCODE("lgop", LGOP), + ZCODE("lgop2", LGOP2), + ZCODE("lurking", LURKING), + ZCODE("minizork1", MINIZORK1), + ZCODE("moonmist", MOONMIST), + ZCODE("nordbert", NORDBERT), + ZCODE("planetfall", PLANETFALL), + ZCODE("plundered", PLUNDERED), + ZCODE("sampler1", SAMPLER1), + ZCODE("sampler2", SAMPLER2), + ZCODE("seastalker", SEASTALKER), + ZCODE("sherlockriddle", SHERLOCKRIDDLE), + ZCODE("shogun", SHOGUN), + ZCODE("sorcerer", SORCERER), + ZCODE("spellbreaker", SPELLBREAKER), + ZCODE("starcross", STARCROSS), + ZCODE("stationfall", STATIONFALL), + ZCODE("suspect", SUSPECT), + ZCODE("suspended", SUSPENDED), + ZCODE("trinity", TRINITY), + ZCODE("wishbringer", WISHBRINGER), + ZCODE("witness", WITNESS), + ZCODE("zork0", ZORK0), + ZCODE("zork1", ZORK1), + ZCODE("zork2", ZORK2), + ZCODE("zork3", ZORK3), + ZCODE("ztuu", ZTUU), + + // Scott Adams games + { "adventureland", "Adventureland" }, + { "pirateadventure", "Pirate Adventure" }, + { "missionimpossible", "Mission Impossible" }, + { "voodoocastle", "Voodoo Castle" }, + { "thecount", "The Count" }, + { "strangeodyssey", "Strange Odyssey" }, + { "mysteryfunhouse", "Mystery Fun House" }, + { "pyramidofdoom", "Pyramid Of Doom" }, + { "ghosttown", "Ghost Town" }, + { "savageisland1", "Savage Island, Part 1" }, + { "savageisland2", "Savage Island, Part 2" }, + { "goldenvoyage", "The Golden Voyage" }, + { "adventure13", "Adventure 13" }, + { "adventure14", "Adventure 14" }, + { "buckaroobonzai", "Buckaroo Banzai" }, + { "marveladventure", "Marvel Adventure #1" }, + { "scottsampler", "Adventure International's Mini-Adventure Sampler" }, + {0, 0} +}; + +#include "common/config-manager.h" +#include "common/file.h" +#include "glk/detection_tables.h" +#include "glk/frotz/detection.h" +#include "glk/frotz/frotz.h" +#include "glk/scott/detection.h" +#include "glk/scott/scott.h" + +class GargoyleMetaEngine : public AdvancedMetaEngine { +public: + GargoyleMetaEngine() : AdvancedMetaEngine(Gargoyle::gameDescriptions, sizeof(Gargoyle::GargoyleGameDescription), gargoyleGames) { + _maxScanDepth = 3; + } + + virtual const char *getName() const { + return "ScummGlk Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "ScummGlk Engine (c) 2018"; + } + + virtual bool hasFeature(MetaEngineFeature f) const override; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override; + virtual SaveStateList listSaves(const char *target) const; + virtual int getMaximumSaveSlot() const; + virtual void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + + virtual DetectedGames detectGames(const Common::FSList &fslist) const override; + + virtual ADDetectedGames detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const override; +}; + +bool GargoyleMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportCreationDate) || + (f == kSavesSupportPlayTime) || + (f == kSimpleSavesNames); +} + +bool Gargoyle::GargoyleEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +bool GargoyleMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + const Gargoyle::GargoyleGameDescription *gd = (const Gargoyle::GargoyleGameDescription *)desc; + + switch (gd->_interpType) { + case Gargoyle::INTERPRETER_FROTZ: + *engine = new Gargoyle::Frotz::Frotz(syst, gd); + break; + case Gargoyle::INTERPRETER_SCOTT: + *engine = new Gargoyle::Scott::Scott(syst, gd); + break; + default: + error("Unknown interpreter"); + } + + return gd != 0; +} + +SaveStateList GargoyleMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String saveDesc; + Common::String pattern = Common::String::format("%s.0##", target); + Gargoyle::SavegameHeader header; + + filenames = saveFileMan->listSavefiles(pattern); + + 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_SAVES) { + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); + + if (in) { + if (Gargoyle::FileStream::readSavegameHeader(in, header)) + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + + delete in; + } + } + } + + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + return saveList; +} + +int GargoyleMetaEngine::getMaximumSaveSlot() const { + return MAX_SAVES; +} + +void GargoyleMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String filename = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(filename); +} + +SaveStateDescriptor GargoyleMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String filename = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename); + + if (in) { + Gargoyle::SavegameHeader header; + if (Gargoyle::FileStream::readSavegameHeader(in, header)) { + // Create the return descriptor + SaveStateDescriptor desc(slot, header._saveName); + desc.setSaveDate(header._year, header._month, header._day); + desc.setSaveTime(header._hour, header._minute); + desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME); + + delete in; + return desc; + } + } + + return SaveStateDescriptor(); +} + +DetectedGames GargoyleMetaEngine::detectGames(const Common::FSList &fslist) const { + DetectedGames detectedGames; + Gargoyle::Frotz::FrotzMetaEngine::detectGames(fslist, detectedGames); + Gargoyle::Scott::ScottMetaEngine::detectGames(fslist, detectedGames); + + return detectedGames; +} + +static Gargoyle::GargoyleGameDescription gameDescription; + +ADDetectedGames GargoyleMetaEngine::detectGame(const Common::FSNode &parent, const FileMap &allFiles, Common::Language language, Common::Platform platform, const Common::String &extra) const { + static char gameId[100]; + strcpy(gameId, ConfMan.get("gameid").c_str()); + Common::String filename = ConfMan.get("filename"); + + Common::FSList fslist; + DetectedGames detectedGames; + fslist.push_back(parent.getChild(filename)); + ADDetectedGames results; + Common::File f; + + // Check each sub-engine for any detected games + if (Gargoyle::Frotz::FrotzMetaEngine::detectGames(fslist, detectedGames)) + gameDescription._interpType = Gargoyle::INTERPRETER_FROTZ; + else if (Gargoyle::Scott::ScottMetaEngine::detectGames(fslist, detectedGames)) + gameDescription._interpType = Gargoyle::INTERPRETER_SCOTT; + else + // No match found, so return no results + return results; + + // Set up the game description and return it + if (f.open(parent.getChild(filename))) { + DetectedGame gd = detectedGames.front(); + + gameDescription._desc.gameId = gameId; + gameDescription._desc.language = gd.language; + gameDescription._desc.platform = gd.platform; + gameDescription._desc.guiOptions = GUIO4(GUIO_NOSPEECH, GUIO_NOSFX, GUIO_NOMUSIC, GUIO_NOSUBTITLES); + gameDescription._filename = filename; + gameDescription._md5 = Common::computeStreamMD5AsString(f, 5000); + + ADDetectedGame dg((ADGameDescription *)&gameDescription); + results.push_back(dg); + } + + return results; +} + +#if PLUGIN_ENABLED_DYNAMIC(GLK) +REGISTER_PLUGIN_DYNAMIC(GLK, PLUGIN_TYPE_ENGINE, GargoyleMetaEngine); +#else +REGISTER_PLUGIN_STATIC(GLK, PLUGIN_TYPE_ENGINE, GargoyleMetaEngine); +#endif |