From 3fd26de37978a404e228f9500883936c979da032 Mon Sep 17 00:00:00 2001 From: Jussi Pitkanen Date: Wed, 25 May 2011 16:27:35 +0300 Subject: AGI: Detect the bootable floppy version of Donald Duck's Playground Also create a framework into which more booter games can be added. --- engines/agi/agi.h | 22 ++++++++++++++++++ engines/agi/detection.cpp | 53 ++++++++++++++++++++++++++++++++++++++++-- engines/agi/detection_tables.h | 35 +++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 0155caf11d..2bc11449b9 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -646,6 +646,28 @@ public: virtual int loadWords(const char *) = 0; }; +class AgiLoader_v1 : public AgiLoader { +private: + AgiEngine *_vm; + Common::String _dsk0Name; + Common::String _dsk1Name; + +public: + AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) { + _vm = vm; + _dsk0Name = dsk0; + _dsk1Name = dsk1; + } + + virtual int init() { return 0; } + virtual int deinit() { return 0; } + virtual int detectGame() { return 0; } + virtual int loadResource(int, int) { return 0; } + virtual int unloadResource(int, int) { return 0; } + virtual int loadObjects(const char *) { return 0; } + virtual int loadWords(const char *) { return 0; } +}; + class AgiLoader_v2 : public AgiLoader { private: AgiEngine *_vm; diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 93fcd2d283..854658cc57 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -28,6 +28,7 @@ #include "engines/advancedDetector.h" #include "common/config-manager.h" #include "common/file.h" +#include "common/md5.h" #include "common/savefile.h" #include "common/textconsole.h" #include "graphics/thumbnail.h" @@ -47,6 +48,9 @@ struct AGIGameDescription { int gameType; uint32 features; uint16 version; + + Common::String dsk0Name; + Common::String dsk1Name; }; uint32 AgiBase::getGameID() const { @@ -290,7 +294,9 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const { typedef Common::HashMap IntMap; + typedef Common::HashMap NodeMap; IntMap allFiles; + NodeMap allNodes; bool matchedUsingFilenames = false; bool matchedUsingWag = false; int wagFileCount = 0; @@ -317,7 +323,8 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX if (file->isDirectory()) continue; Common::String filename = file->getName(); filename.toLowercase(); - allFiles[filename] = true; // Save the filename in a hash table + allFiles[filename] = true; // Save the filename in a hash table + allNodes[filename] = *file; // ...and also the FSNode if (filename.hasSuffix(".wag")) { // Save latest found *.wag file's path (Can be used to open the file, the name can't) @@ -420,6 +427,46 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX warning("More than one (%d) *.wag files found. WAG files ignored", wagFileCount); } + // Try to detect disk images of AGI v1 and AGI v2.001 booter games + if (!matchedUsingFilenames && !matchedUsingWag) { + int index = -1; + + for (IntMap::const_iterator f = allFiles.begin(); f != allFiles.end(); ++f) { + if (f->_key.hasSuffix(".dsk") || f->_key.hasSuffix(".img")) { + Common::File file; + file.open(allNodes[f->_key]); + Common::String md5str = Common::computeStreamMD5AsString(file, detectionParams.md5Bytes); + debug(3, "Agi::fallbackDetector: disk image (%s) found with md5 sum (%s) ", f->_key.c_str(), md5str.c_str()); + + for (int i = 0; !booterDescription[i].md5str_dsk0.empty(); i++) { + if (booterDescription[i].md5str_dsk0 == md5str) { + index = i; + g_fallbackDesc.dsk0Name = f->_key; + } + if (booterDescription[i].md5str_dsk1 == md5str) { + index = i; + g_fallbackDesc.dsk1Name = f->_key; + } + } + } + } + + if (index >= 0) { + if ((booterDescription[index].md5str_dsk0.empty() == g_fallbackDesc.dsk0Name.empty()) && + (booterDescription[index].md5str_dsk1.empty() == g_fallbackDesc.dsk1Name.empty())) { + g_fallbackDesc.gameID = booterDescription[index].gameID; + g_fallbackDesc.gameType = booterDescription[index].gameType; + g_fallbackDesc.features = booterDescription[index].features; + g_fallbackDesc.version = booterDescription[index].version; + + g_fallbackDesc.desc.gameid = booterDescription[index].id.c_str(); + g_fallbackDesc.desc.extra = booterDescription[index].extra.c_str(); + + return (const ADGameDescription *)&g_fallbackDesc; + } + } + } + // Check that the AGI interpreter version is a supported one if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) { warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version); @@ -477,7 +524,9 @@ int AgiEngine::agiDetectGame() { assert(_gameDescription != NULL); - if (getVersion() <= 0x2999) { + if (getVersion() <= 0x2001) { + _loader = new AgiLoader_v1(this, _gameDescription->dsk0Name, _gameDescription->dsk1Name); + } else if (getVersion() <= 0x2999) { _loader = new AgiLoader_v2(this); } else { _loader = new AgiLoader_v3(this); diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h index cd3edf50c6..ade45243f7 100644 --- a/engines/agi/detection_tables.h +++ b/engines/agi/detection_tables.h @@ -38,6 +38,8 @@ using Common::GUIO_NONE; interp, \ features, \ ver, \ + "", \ + "" \ } #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \ @@ -54,6 +56,8 @@ using Common::GUIO_NONE; interp, \ features, \ ver, \ + "", \ + "" \ } #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2) @@ -197,6 +201,8 @@ static const AGIGameDescription gameDescriptions[] = { GType_V3, GF_MACGOLDRUSH, 0x3149, + "", + "" }, @@ -515,6 +521,8 @@ static const AGIGameDescription gameDescriptions[] = { GType_V2, 0, 0x2936, + "", + "" }, @@ -660,6 +668,8 @@ static const AGIGameDescription gameDescriptions[] = { GType_V2, GF_AGDS, 0x2440, + "", + "" }, { @@ -677,6 +687,8 @@ static const AGIGameDescription gameDescriptions[] = { GType_V2, 0, 0x2440, + "", + "" }, FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE), @@ -832,6 +844,8 @@ static const AGIGameDescription gameDescriptions[] = { GType_V3, GF_FANMADE, 0x3149, + "", + "", }, FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3), @@ -839,7 +853,7 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Voodoo Girl - Queen of the Darned (v1.2 2002 Mar 29)", "11d0417b7b886f963d0b36789dac4c8f"), FANMADE("Wizaro (v0.1)", "abeec1eda6eaf8dbc52443ea97ff140c"), - { AD_TABLE_END_MARKER, 0, 0, 0, 0 } + { AD_TABLE_END_MARKER, 0, 0, 0, 0, "", "" } }; /** @@ -860,6 +874,25 @@ static AGIGameDescription g_fallbackDesc = { GType_V2, GF_FANMADE, 0x2917, + "", + "" +}; + +/** + * Detection table for booter games. + */ +static const struct { + Common::String md5str_dsk0; + Common::String md5str_dsk1; + Common::String id; + Common::String extra; + int gameID; + int gameType; + uint32 features; + uint16 version; +} booterDescription[] = { + { "f323f10abf8140ffb2668b09af2e7b87", "", "ddp", "booter", GID_DDP, GType_V2, ADGF_NO_FLAGS, 0x2001 }, + { "", "", "", "", 0, 0, 0, 0 } }; } // End of namespace Agi -- cgit v1.2.3