diff options
Diffstat (limited to 'engines/mohawk')
28 files changed, 2085 insertions, 1546 deletions
diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 389665db39..5dcfff4f90 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -28,9 +28,10 @@ #include "mohawk/myst_scripts.h" #include "mohawk/graphics.h" #include "mohawk/riven.h" +#include "mohawk/riven_external.h" #include "mohawk/livingbooks.h" #include "mohawk/sound.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" namespace Mohawk { @@ -307,6 +308,7 @@ RivenConsole::RivenConsole(MohawkEngine_Riven *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("dumpScript", WRAP_METHOD(RivenConsole, Cmd_DumpScript)); DCmd_Register("listZipCards", WRAP_METHOD(RivenConsole, Cmd_ListZipCards)); DCmd_Register("getRMAP", WRAP_METHOD(RivenConsole, Cmd_GetRMAP)); + DCmd_Register("combos", WRAP_METHOD(RivenConsole, Cmd_Combos)); } RivenConsole::~RivenConsole() { @@ -556,9 +558,11 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) { printf ("==================================\n\n"); Common::SeekableReadStream *cardStream = _vm->getRawData(MKID_BE('CARD'), (uint16)atoi(argv[3])); cardStream->seek(4); - RivenScriptList scriptList = RivenScript::readScripts(_vm, cardStream); - for (uint32 i = 0; i < scriptList.size(); i++) + RivenScriptList scriptList = _vm->_scriptMan->readScripts(cardStream, false); + for (uint32 i = 0; i < scriptList.size(); i++) { scriptList[i]->dumpScript(varNames, xNames, 0); + delete scriptList[i]; + } delete cardStream; } else if (!scumm_stricmp(argv[2], "HSPT")) { printf ("\n\nDumping scripts for %s\'s card %d hotspots!\n", argv[1], (uint16)atoi(argv[3])); @@ -571,9 +575,11 @@ bool RivenConsole::Cmd_DumpScript(int argc, const char **argv) { for (uint16 i = 0; i < hotspotCount; i++) { printf ("Hotspot %d:\n", i); hsptStream->seek(22, SEEK_CUR); // Skip non-script related stuff - RivenScriptList scriptList = RivenScript::readScripts(_vm, hsptStream); - for (uint32 j = 0; j < scriptList.size(); j++) + RivenScriptList scriptList = _vm->_scriptMan->readScripts(hsptStream, false); + for (uint32 j = 0; j < scriptList.size(); j++) { scriptList[j]->dumpScript(varNames, xNames, 1); + delete scriptList[j]; + } } delete hsptStream; @@ -608,6 +614,33 @@ bool RivenConsole::Cmd_GetRMAP(int argc, const char **argv) { return true; } +bool RivenConsole::Cmd_Combos(int argc, const char **argv) { + // In the vain of SCUMM's 'drafts' command, this command will list + // out all combinations needed in Riven, decoded from the variables. + // You'll need to look up the Rebel Tunnel puzzle on your own; the + // solution is constant. + + uint32 teleCombo = *_vm->matchVarToString("tcorrectorder"); + uint32 prisonCombo = *_vm->matchVarToString("pcorrectorder"); + uint32 domeCombo = *_vm->matchVarToString("adomecombo"); + + DebugPrintf("Telescope Combo:\n "); + for (int i = 0; i < 5; i++) + DebugPrintf("%d ", _vm->_externalScriptHandler->getComboDigit(teleCombo, i)); + + DebugPrintf("\nPrison Combo:\n "); + for (int i = 0; i < 5; i++) + DebugPrintf("%d ", _vm->_externalScriptHandler->getComboDigit(prisonCombo, i)); + + DebugPrintf("\nDome Combo:\n "); + for (int i = 1; i <= 25; i++) + if (domeCombo & (1 << (25 - i))) + DebugPrintf("%d ", i); + + DebugPrintf("\n"); + return true; +} + LivingBooksConsole::LivingBooksConsole(MohawkEngine_LivingBooks *vm) : GUI::Debugger(), _vm(vm) { DCmd_Register("playSound", WRAP_METHOD(LivingBooksConsole, Cmd_PlaySound)); DCmd_Register("stopSound", WRAP_METHOD(LivingBooksConsole, Cmd_StopSound)); diff --git a/engines/mohawk/console.h b/engines/mohawk/console.h index 9a30d46225..1806c61027 100644 --- a/engines/mohawk/console.h +++ b/engines/mohawk/console.h @@ -88,6 +88,7 @@ private: bool Cmd_DumpScript(int argc, const char **argv); bool Cmd_ListZipCards(int argc, const char **argv); bool Cmd_GetRMAP(int argc, const char **argv); + bool Cmd_Combos(int argc, const char **argv); }; class LivingBooksConsole : public GUI::Debugger { diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp index a7b1fe7fae..f04338239f 100644 --- a/engines/mohawk/detection.cpp +++ b/engines/mohawk/detection.cpp @@ -117,846 +117,21 @@ static const PlainGameDescriptor mohawkGames[] = { {"ruff", "Ruff's Bone"}, {"newkid", "The New Kid on the Block"}, {"arthurrace", "Arthur's Reading Race"}, + {"arthurbday", "Arthur's Birthday"}, + {"lilmonster", "Little Monster at School"}, #endif {0, 0} }; +#include "mohawk/detection_tables.h" -namespace Mohawk { - -static const MohawkGameDescription gameDescriptions[] = { - // Myst - // English Windows 3.11 - // From clone2727 - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "ae3258c9c90128d274aa6a790b3ad181"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Myst Demo - // English Windows 3.11 - // From CD-ROM Today July, 1994 - { - { - "myst", - "Demo", - AD_ENTRY1("DEMO.DAT", "c39303dd53fb5c4e7f3c23231c606cd0"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_MYST, - GF_DEMO, - 0, - }, - - // Myst - // German Windows 3.11 - // From clone2727 - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "4beb3366ed3f3b9bfb6e81a14a43bdcc"), - Common::DE_DEU, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Myst - // German Windows 3.11 - // From LordHoto - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "e0937cca1ab125e48e30dc3cd5046ddf"), - Common::DE_DEU, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Myst - // Spanish Windows ? - // From jvprat - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "f7e7d7ca69934f1351b5acd4fe4d44c2"), - Common::ES_ESP, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Myst - // Japanese Windows 3.11 - // From clone2727 - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "032c88e3b7e8db4ca475e7b7db9a66bb"), - Common::JA_JPN, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Myst - // French Windows 3.11 - // From Strangerke - { - { - "myst", - "", - AD_ENTRY1("MYST.DAT", "d631d42567a941c67c78f2e491f4ea58"), - Common::FR_FRA, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0, - }, - - // Making of Myst - // English Windows 3.11 - // From clone2727 - { - { - "MakingOfMyst", - "", - AD_ENTRY1("MAKING.DAT", "f6387e8f0f7b8a3e42c95294315d6a0e"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MAKINGOF, - 0, - 0, - }, - - // Making of Myst - // Japanese Windows 3.11 - // From clone2727 - { - { - "MakingOfMyst", - "", - AD_ENTRY1("MAKING.DAT", "03ff62607e64419ab2b6ebf7b7bcdf63"), - Common::JA_JPN, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MAKINGOF, - 0, - 0, - }, - - // Myst Masterpiece Edition - // English Windows - // From clone2727 - { - { - "myst", - "Masterpiece Edition", - AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - GF_ME, - 0, - }, - - // Myst Masterpiece Edition - // English Windows - // From clone2727 - { - { - "myst", - "Masterpiece Edition", - AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - GF_ME, - 0, - }, - - // Myst Masterpiece Edition - // German Windows - // From DrMcCoy (Included in "Myst: Die Trilogie") - { - { - "myst", - "Masterpiece Edition", - AD_ENTRY1("MYST.DAT", "f88e0ace66dbca78eebdaaa1d3314ceb"), - Common::DE_DEU, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - GF_ME, - 0, - }, - - // Riven: The Sequel to Myst - // Version 1.0 (5CD) - // From clone2727 - { - { - "riven", - "", - AD_ENTRY1("a_Data.MHK", "71145fdecbd68a0cfc292c2fbddf8e08"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - 0, - 0, - }, - - // Riven: The Sequel to Myst - // Version 1.03 (5CD) - // From ST - { - { - "riven", - "", - AD_ENTRY1("a_Data.MHK", "d8ccae34a0e3c709135a73f449b783be"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - 0, - 0, - }, - - // Riven: The Sequel to Myst - // Version 1.? (5CD) - // From jvprat - { - { - "riven", - "", - AD_ENTRY1("a_Data.MHK", "249e8c995d191b03ee94c892c0eac775"), - Common::ES_ESP, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - 0, - 0, - }, - - // Riven: The Sequel to Myst - // Version 1.? (DVD, From "Myst 10th Anniversary Edition") - // From Clone2727 - { - { - "riven", - "DVD", - AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - GF_DVD, - 0, - }, - - // Riven: The Sequel to Myst - // Version 1.0 (DVD, From "Myst: Die Trilogie") - // From DrMcCoy - { - { - "riven", - "", - AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"), - Common::DE_DEU, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - GF_DVD, - 0, - }, - - // Riven: The Sequel to Myst - // Version ? (Demo, From "Prince of Persia Collector's Edition") - // From Clone2727 - { - { - "riven", - "Demo", - AD_ENTRY1("a_Data.MHK", "bae6b03bd8d6eb350d35fd13f0e3139f"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_RIVEN, - GF_DEMO, - 0, - }, - -#ifdef DETECT_BRODERBUND_TITLES - { - { - "zoombini", - "", - AD_ENTRY1("ZOOMBINI.MHK", "98b758fec55104c096cfd129048be9a6"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_ZOOMBINI, - GF_HASMIDI, - 0 - }, - - { - { - "csworld", - "v3.0", - AD_ENTRY1("C2K.MHK", "605fe88380848031bbd0ff84ade6fe40"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_CSWORLD, - 0, - 0 - }, - - { - { - "csworld", - "v3.5", - AD_ENTRY1("C2K.MHK", "d4857aeb0f5e2e0c4ac556aa74f38c23"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_CSWORLD, - 0, - 0 - }, - - { - { - "csamtrak", - "", - AD_ENTRY1("AMTRAK.MHK", "2f95301f0bb950d555bb7b0e3b1b7eb1"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_CSAMTRAK, - 0, - 0 - }, - - { - { - "maggiess", - "", - AD_ENTRY1("MAGGIESS.MHK", "08f75fc8c0390e68fdada5ddb35d0355"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MAGGIESS, - 0, - 0 - }, - - { - { - "jamesmath", - "", - AD_ENTRY1("BRODER.MHK", "007299da8b2c6e8ec1cde9598c243024"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_JAMESMATH, - GF_HASMIDI, - 0 - }, - - // This is in the NEWDATA folder, so I assume it's a newer version ;) - { - { - "jamesmath", - "", - AD_ENTRY1("BRODER.MHK", "53c000938a50dca92860fd9b546dd276"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_JAMESMATH, - GF_HASMIDI, - 1 - }, - - { - { - "treehouse", - "", - AD_ENTRY1("MAINROOM.MHK", "12f51894d7f838af639ea9bf1bc8f45b"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_TREEHOUSE, - GF_HASMIDI, - 0 - }, - - { - { - "greeneggs", - "", - AD_ENTRY1("GREEN.LB", "5df8438138186f89e71299d7b4f88d06"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV3, - 0, - 0 - }, - - // 32-bit version of the previous entry - { - { - "greeneggs", - "", - AD_ENTRY1("GREEN32.LB", "5df8438138186f89e71299d7b4f88d06"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV3, - 0, - 0 - }, - - { - { - "1stdegree", - "", - AD_ENTRY1("AL236_1.MHK", "3ba145492a7b8b4dee0ef4222c5639c3"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_1STDEGREE, - GF_HASMIDI, - 0 - }, - - // In The 1st Degree - // French Windows - // From Strangerke - { - { - "1stdegree", - "", - AD_ENTRY1("AL236_1.MHK", "0e0c70b1b702b6ddca61a1192ada1282"), - Common::FR_FRA, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_1STDEGREE, - GF_HASMIDI, - 0 - }, - - { - { - "csusa", - "", - AD_ENTRY1("USAC2K.MHK", "b8c9d3a2586f62bce3a48b50d7a700e9"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_CSUSA, - 0, - 0 - }, - - { - { - "tortoise", - "Demo v1.0", - AD_ENTRY1("TORTOISE.512", "75d9a2f8339e423604a0c6e8177600a6"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "tortoise", - "Demo v1.1", - AD_ENTRY1("TORTOISE.512", "a38c99360e2bea3bfdec418469aef022"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "arthur", - "", - AD_ENTRY1("PAGES.512", "1550a361454ec452fe7d2328aac2003c"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - 0, - 0 - }, - - { - { - "arthur", - "Demo", - AD_ENTRY1("PAGES.512", "a4d68cef197af1416921ca5b2e0c1e31"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "arthur", - "Demo", - AD_ENTRY1("Bookoutline", "7e2691611ff4c7b89c05221736628059"), - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "grandma", - "Demo v1.0", - AD_ENTRY1("PAGES.512", "95d9f4b035bf5d15c57a9189f231b0f8"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "grandma", - "Demo v1.1", - AD_ENTRY1("GRANDMA.512", "72a4d5fb1b3f06b5f75425635d42ce2e"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "grandma", - "Demo", - AD_ENTRY1("Bookoutline", "553c93891b9631d1e1d269599e1efa6c"), - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "ruff", - "Demo", - AD_ENTRY1("RUFF.512", "2ba1aa65177c816e156db648c398d362"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "ruff", - "Demo", - AD_ENTRY1("Ruff's Bone Demo", "22553ac2ceb2a166bdf1def6ad348532"), - Common::EN_ANY, - Common::kPlatformMacintosh, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "newkid", - "Demo v1.0", - AD_ENTRY1("NEWKID.512", "2b9d94763a50d514c04a3af488934f73"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "newkid", - "Demo v1.1", - AD_ENTRY1("NEWKID.512", "41e975b7390c626f8d1058a34f9d9b2e"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_DEMO, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV1, - GF_DEMO, - 0 - }, - - { - { - "arthurrace", - "", - AD_ENTRY1("RACE.LB", "1645f36bcb36e440d928e920aa48c373"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV3, - 0, - 0 - }, - - // 32-bit version of the previous entry - { - { - "arthurrace", - "", - AD_ENTRY1("RACE32.LB", "292a05bc48c1dd9583821a4181a02ef2"), - Common::EN_ANY, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_LIVINGBOOKSV3, - 0, - 0 - }, -#endif - - { AD_TABLE_END_MARKER, 0, 0, 0 } +static const char *directoryGlobs[] = { + "all", + "assets1", + "data", + 0 }; -////////////////////////////// -//Fallback detection -////////////////////////////// - -static const MohawkGameDescription fallbackDescs[] = { - { - { - "myst", - "unknown", - AD_ENTRY1(0, 0), - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - 0, - 0 - }, - - { - { - "MakingOfMyst", - "unknown", - AD_ENTRY1(0, 0), - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MAKINGOF, - 0, - 0 - }, - - { - { - "myst", - "unknown (Masterpiece Edition)", - AD_ENTRY1(0, 0), - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_MYST, - GF_ME, - 0 - }, - - { - { - "riven", - "unknown", - AD_ENTRY1(0, 0), - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - 0, - 0 - }, - - { - { - "riven", - "unknown (DVD)", - AD_ENTRY1(0, 0), - Common::UNK_LANG, - Common::kPlatformWindows, - ADGF_NO_FLAGS, - Common::GUIO_NONE - }, - GType_RIVEN, - GF_DVD, - 0 - } -}; - -static const ADFileBasedFallback fileBased[] = { - { &fallbackDescs[0], { "MYST.DAT", 0 } }, - { &fallbackDescs[1], { "MAKING.DAT", 0 } }, - { &fallbackDescs[2], { "MYST.DAT", "Help.dat", 0 } }, // Help system doesn't exist in original - { &fallbackDescs[3], { "a_Data.MHK", 0 } }, - { &fallbackDescs[4], { "a_Data.MHK", "t_Data1.MHK" , 0 } }, - { 0, { 0 } } -}; - -} // End of namespace Mohawk - static const ADParams detectionParams = { // Pointer to ADGameDescription or its superset structure (const byte *)Mohawk::gameDescriptions, @@ -975,7 +150,11 @@ static const ADParams detectionParams = { // Flags 0, // Additional GUI options (for every game) - Common::GUIO_NONE + Common::GUIO_NONE, + // Maximum directory depth + 2, + // List of directory globs + directoryGlobs }; class MohawkMetaEngine : public AdvancedMetaEngine { diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h new file mode 100644 index 0000000000..7470dbf1dd --- /dev/null +++ b/engines/mohawk/detection_tables.h @@ -0,0 +1,1030 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +namespace Mohawk { + +static const MohawkGameDescription gameDescriptions[] = { + // Myst + // English Windows 3.11 + // From clone2727 + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "ae3258c9c90128d274aa6a790b3ad181"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Myst Demo + // English Windows 3.11 + // From CD-ROM Today July, 1994 + { + { + "myst", + "Demo", + AD_ENTRY1("DEMO.DAT", "c39303dd53fb5c4e7f3c23231c606cd0"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_MYST, + GF_DEMO, + 0, + }, + + // Myst + // German Windows 3.11 + // From clone2727 + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "4beb3366ed3f3b9bfb6e81a14a43bdcc"), + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Myst + // German Windows 3.11 + // From LordHoto + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "e0937cca1ab125e48e30dc3cd5046ddf"), + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Myst + // Spanish Windows ? + // From jvprat + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "f7e7d7ca69934f1351b5acd4fe4d44c2"), + Common::ES_ESP, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Myst + // Japanese Windows 3.11 + // From clone2727 + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "032c88e3b7e8db4ca475e7b7db9a66bb"), + Common::JA_JPN, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Myst + // French Windows 3.11 + // From Strangerke + { + { + "myst", + "", + AD_ENTRY1("MYST.DAT", "d631d42567a941c67c78f2e491f4ea58"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0, + }, + + // Making of Myst + // English Windows 3.11 + // From clone2727 + { + { + "MakingOfMyst", + "", + AD_ENTRY1("MAKING.DAT", "f6387e8f0f7b8a3e42c95294315d6a0e"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MAKINGOF, + 0, + 0, + }, + + // Making of Myst + // Japanese Windows 3.11 + // From clone2727 + { + { + "MakingOfMyst", + "", + AD_ENTRY1("MAKING.DAT", "03ff62607e64419ab2b6ebf7b7bcdf63"), + Common::JA_JPN, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MAKINGOF, + 0, + 0, + }, + + // Myst Masterpiece Edition + // English Windows + // From clone2727 + { + { + "myst", + "Masterpiece Edition", + AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + GF_ME, + 0, + }, + + // Myst Masterpiece Edition + // English Windows + // From clone2727 + { + { + "myst", + "Masterpiece Edition", + AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + GF_ME, + 0, + }, + + // Myst Masterpiece Edition + // German Windows + // From DrMcCoy (Included in "Myst: Die Trilogie") + { + { + "myst", + "Masterpiece Edition", + AD_ENTRY1("MYST.DAT", "f88e0ace66dbca78eebdaaa1d3314ceb"), + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + GF_ME, + 0, + }, + + // Myst Masterpiece Edition + // French Windows + // From gamin (Included in "Myst: La Trilogie") + { + { + "myst", + "Masterpiece Edition", + AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + GF_ME, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.0 (5CD) + // From clone2727 + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "71145fdecbd68a0cfc292c2fbddf8e08"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.03 (5CD) + // From ST + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "d8ccae34a0e3c709135a73f449b783be"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.? (5CD) + // From jvprat + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "249e8c995d191b03ee94c892c0eac775"), + Common::ES_ESP, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.? (DVD, From "Myst 10th Anniversary Edition") + // From Clone2727 + { + { + "riven", + "DVD", + AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + GF_DVD, + 0, + }, + + // Riven: The Sequel to Myst + // Version 1.0 (DVD, From "Myst: Die Trilogie") + // From DrMcCoy + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"), + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + GF_DVD, + 0, + }, + + // Riven: The Sequel to Myst + // Version ? (DVD, From "Myst: La Trilogie") + // From gamin + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + GF_DVD, + 0, + }, + + // Riven: The Sequel to Myst + // Version ? (Demo, From "Prince of Persia Collector's Edition") + // From Clone2727 + { + { + "riven", + "Demo", + AD_ENTRY1("a_Data.MHK", "bae6b03bd8d6eb350d35fd13f0e3139f"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_RIVEN, + GF_DEMO, + 0, + }, + +#ifdef DETECT_BRODERBUND_TITLES + { + { + "zoombini", + "", + AD_ENTRY1("ZOOMBINI.MHK", "98b758fec55104c096cfd129048be9a6"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_ZOOMBINI, + GF_HASMIDI, + 0 + }, + + { + { + "csworld", + "v3.0", + AD_ENTRY1("C2K.MHK", "605fe88380848031bbd0ff84ade6fe40"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_CSWORLD, + 0, + 0 + }, + + { + { + "csworld", + "v3.5", + AD_ENTRY1("C2K.MHK", "d4857aeb0f5e2e0c4ac556aa74f38c23"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_CSWORLD, + 0, + 0 + }, + + { + { + "csamtrak", + "", + AD_ENTRY1("AMTRAK.MHK", "2f95301f0bb950d555bb7b0e3b1b7eb1"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_CSAMTRAK, + 0, + 0 + }, + + { + { + "maggiess", + "", + AD_ENTRY1("MAGGIESS.MHK", "08f75fc8c0390e68fdada5ddb35d0355"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MAGGIESS, + 0, + 0 + }, + + { + { + "jamesmath", + "", + AD_ENTRY1("BRODER.MHK", "007299da8b2c6e8ec1cde9598c243024"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_JAMESMATH, + GF_HASMIDI, + 0 + }, + + // This is in the NEWDATA folder, so I assume it's a newer version ;) + { + { + "jamesmath", + "", + AD_ENTRY1("BRODER.MHK", "53c000938a50dca92860fd9b546dd276"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_JAMESMATH, + GF_HASMIDI, + 1 + }, + + { + { + "treehouse", + "", + AD_ENTRY1("MAINROOM.MHK", "12f51894d7f838af639ea9bf1bc8f45b"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_TREEHOUSE, + GF_HASMIDI, + 0 + }, + + { + { + "greeneggs", + "", + AD_ENTRY1("GREEN.LB", "5df8438138186f89e71299d7b4f88d06"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + // 32-bit version of the previous entry + { + { + "greeneggs", + "", + AD_ENTRY1("GREEN32.LB", "5df8438138186f89e71299d7b4f88d06"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + { + { + "1stdegree", + "", + AD_ENTRY1("AL236_1.MHK", "3ba145492a7b8b4dee0ef4222c5639c3"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_1STDEGREE, + GF_HASMIDI, + 0 + }, + + // In The 1st Degree + // French Windows + // From Strangerke + { + { + "1stdegree", + "", + AD_ENTRY1("AL236_1.MHK", "0e0c70b1b702b6ddca61a1192ada1282"), + Common::FR_FRA, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_1STDEGREE, + GF_HASMIDI, + 0 + }, + + { + { + "csusa", + "", + AD_ENTRY1("USAC2K.MHK", "b8c9d3a2586f62bce3a48b50d7a700e9"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_CSUSA, + 0, + 0 + }, + + { + { + "tortoise", + "Demo v1.0", + AD_ENTRY1("TORTOISE.512", "75d9a2f8339e423604a0c6e8177600a6"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "tortoise", + "Demo v1.1", + AD_ENTRY1("TORTOISE.512", "a38c99360e2bea3bfdec418469aef022"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "tortoise", + "Demo", + AD_ENTRY1("The Tortoise and the Hare Demo", "35d571806838667743c7c15a133e9335"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthur", + "", + AD_ENTRY1("PAGES.512", "1550a361454ec452fe7d2328aac2003c"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + 0 + }, + + { + { + "arthur", + "Demo", + AD_ENTRY1("PAGES.512", "a4d68cef197af1416921ca5b2e0c1e31"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthur", + "Demo v1.1", + AD_ENTRY1("ARTHUR.512", "f19e824e0a2f2745ed698e6aaf44f838"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthur", + "Demo", + AD_ENTRY1("Bookoutline", "7e2691611ff4c7b89c05221736628059"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthur", + "Demo", + AD_ENTRY1("Arthur's Teacher Trouble Demo", "dcbd8af6bf25854df8ad36fd13665d08"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "grandma", + "Demo v1.0", + AD_ENTRY1("PAGES.512", "95d9f4b035bf5d15c57a9189f231b0f8"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "grandma", + "Demo v1.1", + AD_ENTRY1("GRANDMA.512", "72a4d5fb1b3f06b5f75425635d42ce2e"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "grandma", + "Demo", + AD_ENTRY1("Bookoutline", "553c93891b9631d1e1d269599e1efa6c"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "grandma", + "Demo", + AD_ENTRY1("Just Grandma and Me Demo", "552d8729fa77a4a83c88283c7d79bd31"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "ruff", + "Demo", + AD_ENTRY1("RUFF.512", "2ba1aa65177c816e156db648c398d362"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "ruff", + "Demo", + AD_ENTRY1("Ruff's Bone Demo", "22553ac2ceb2a166bdf1def6ad348532"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "newkid", + "Demo v1.0", + AD_ENTRY1("NEWKID.512", "2b9d94763a50d514c04a3af488934f73"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "newkid", + "Demo v1.1", + AD_ENTRY1("NEWKID.512", "41e975b7390c626f8d1058a34f9d9b2e"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "newkid", + "Demo", + AD_ENTRY1("The New Kid on the Block Demo", "7d33237e0ea452a97f2a3acdfb9e1286"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthurrace", + "", + AD_ENTRY1("RACE.LB", "1645f36bcb36e440d928e920aa48c373"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + // 32-bit version of the previous entry + { + { + "arthurrace", + "", + AD_ENTRY1("RACE32.LB", "292a05bc48c1dd9583821a4181a02ef2"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + + { + { + "arthurbday", + "Demo", + AD_ENTRY1("BIRTHDAY.512", "fb73e387cfec65c5c930db068a8f468a"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "arthurbday", + "Demo", + AD_ENTRY1("Arthur's Birthday Demo", "0d974ec635eea615475368e865f1b1c8"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_DEMO, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + GF_DEMO, + 0 + }, + + { + { + "lilmonster", + "", + AD_ENTRY1("MONSTER.512", "e7b24bf8f59106b5c4df51b39eb8c0ef"), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + 0 + }, + + { + { + "lilmonster", + "", + AD_ENTRY1("BookOutline", "970409f9d967d63c05e63113f8e78fe2"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV1, + 0, + 0 + }, +#endif + + { AD_TABLE_END_MARKER, 0, 0, 0 } +}; + +////////////////////////////// +//Fallback detection +////////////////////////////// + +static const MohawkGameDescription fallbackDescs[] = { + { + { + "myst", + "unknown", + AD_ENTRY1(0, 0), + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + 0, + 0 + }, + + { + { + "MakingOfMyst", + "unknown", + AD_ENTRY1(0, 0), + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MAKINGOF, + 0, + 0 + }, + + { + { + "myst", + "unknown (Masterpiece Edition)", + AD_ENTRY1(0, 0), + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_MYST, + GF_ME, + 0 + }, + + { + { + "riven", + "unknown", + AD_ENTRY1(0, 0), + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + 0, + 0 + }, + + { + { + "riven", + "unknown (DVD)", + AD_ENTRY1(0, 0), + Common::UNK_LANG, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + GType_RIVEN, + GF_DVD, + 0 + } +}; + +static const ADFileBasedFallback fileBased[] = { + { &fallbackDescs[0], { "MYST.DAT", 0 } }, + { &fallbackDescs[1], { "MAKING.DAT", 0 } }, + { &fallbackDescs[2], { "MYST.DAT", "Help.dat", 0 } }, // Help system doesn't exist in original + { &fallbackDescs[3], { "a_Data.MHK", 0 } }, + { &fallbackDescs[4], { "a_Data.MHK", "t_Data1.MHK" , 0 } }, + { 0, { 0 } } +}; + +} // End of Namespace Mohawk diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp index c5327dbeea..c09763cbb3 100644 --- a/engines/mohawk/dialogs.cpp +++ b/engines/mohawk/dialogs.cpp @@ -30,6 +30,7 @@ #include "gui/GuiManager.h" #include "common/savefile.h" +#include "common/translation.h" namespace Mohawk { @@ -77,11 +78,11 @@ enum { }; MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, "Zip Mode Activated", kZipCmd, 'Z'); - _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, "Transitions Enabled", kTransCmd, 'T'); + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~T~ransitions Enabled"), 0, kTransCmd); - new GUI::ButtonWidget(this, 95, 160, 120, 25, "OK", GUI::kOKCmd, 'O'); - new GUI::ButtonWidget(this, 225, 160, 120, 25, "Cancel", GUI::kCloseCmd, 'C'); + new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); + new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); } MystOptionsDialog::~MystOptionsDialog() { @@ -111,11 +112,11 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui } RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) { - _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, "Zip Mode Activated", kZipCmd, 'Z'); - _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, "Water Effect Enabled", kWaterCmd, 'W'); + _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd); + _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd); - new GUI::ButtonWidget(this, 95, 160, 120, 25, "OK", GUI::kOKCmd, 'O'); - new GUI::ButtonWidget(this, 225, 160, 120, 25, "Cancel", GUI::kCloseCmd, 'C'); + new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd); + new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd); } RivenOptionsDialog::~RivenOptionsDialog() { diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp index 35691c36aa..1974aec9c2 100644 --- a/engines/mohawk/graphics.cpp +++ b/engines/mohawk/graphics.cpp @@ -78,9 +78,8 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : _vm(vm) { error("Myst requires greater than 256 colors to run"); if (_vm->getFeatures() & GF_ME) { - // We want to delete our own JPEG surfaces, so don't free after use. - _jpegDecoder = new JPEGDecoder(false); - _pictDecoder = new MystPICT(_jpegDecoder); + _jpegDecoder = new Graphics::JPEGDecoder(); + _pictDecoder = new Graphics::PictDecoder(_pixelFormat); } else { _jpegDecoder = NULL; _pictDecoder = NULL; @@ -152,9 +151,10 @@ void MystGraphics::copyImageSectionToScreen(uint16 image, Common::Rect src, Comm if (_vm->getFeatures() & GF_ME && _vm->getPlatform() == Common::kPlatformMacintosh && _pictureFile.picFile.isOpen()) { for (uint32 i = 0; i < _pictureFile.pictureCount; i++) if (_pictureFile.entries[i].id == image) { - if (_pictureFile.entries[i].type == 0) - surface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)); - else if (_pictureFile.entries[i].type == 1) + if (_pictureFile.entries[i].type == 0) { + Graphics::Surface *jpegSurface = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)); + surface->copyFrom(*jpegSurface); + } else if (_pictureFile.entries[i].type == 1) surface = _pictDecoder->decodeImage(new Common::SeekableSubReadStream(&_pictureFile.picFile, _pictureFile.entries[i].offset, _pictureFile.entries[i].offset + _pictureFile.entries[i].size)); else error ("Unknown Picture File type %d", _pictureFile.entries[i].type); @@ -466,27 +466,22 @@ void RivenGraphics::runScheduledTransition() { // transitions were found by hacking scripts. switch (_scheduledTransition) { + case 0: // Swipe Left + case 1: // Swipe Right + case 2: // Swipe Up + case 3: // Swipe Down case 12: // Pan Left - warning ("STUB: Pan left"); - break; case 13: // Pan Right - warning ("STUB: Pan right"); - break; case 14: // Pan Up - warning ("STUB: Pan up"); - break; case 15: // Pan Down - warning ("STUB: Pan down"); - break; case 16: // Dissolve case 17: // Dissolve (tspit CARD 155) - warning ("STUB: Dissolve"); break; default: - if (_scheduledTransition < 12) - error ("Found unused transition %d", _scheduledTransition); + if (_scheduledTransition >= 4 && _scheduledTransition <= 11) + error("Found unused transition %d", _scheduledTransition); else - error ("Found unknown transition %d", _scheduledTransition); + error("Found unknown transition %d", _scheduledTransition); } // For now, just copy the image to screen without doing any transition. @@ -607,19 +602,23 @@ void RivenGraphics::showInventory() { if (_vm->getFeatures() & GF_DEMO || _vm->getCurStack() == aspit) return; - // There are three books and three vars. However, there's only - // a possible two combinations. Either you have only Atrus' - // journal or you have all three books. - // bool hasAtrusBook = *_vm->matchVarToString("aatrusbook") != 0; + // There are three books and three vars. We have three different + // combinations. At the start you have just Atrus' journal. Later, + // you get Catherine's journal and the trap book. Near the end, + // you lose the trap book and have just the two journals. + bool hasCathBook = *_vm->matchVarToString("acathbook") != 0; - // bool hasTrapBook = *_vm->matchVarToString("atrapbook") != 0; + bool hasTrapBook = *_vm->matchVarToString("atrapbook") != 0; if (!hasCathBook) { - drawInventoryImage(101, g_atrusJournalRectSolo); + drawInventoryImage(101, g_atrusJournalRect1); + } else if (!hasTrapBook) { + drawInventoryImage(101, g_atrusJournalRect2); + drawInventoryImage(102, g_cathJournalRect2); } else { - drawInventoryImage(101, g_atrusJournalRect); - drawInventoryImage(102, g_cathJournalRect); - drawInventoryImage(100, g_trapBookRect); + drawInventoryImage(101, g_atrusJournalRect3); + drawInventoryImage(102, g_cathJournalRect3); + drawInventoryImage(100, g_trapBookRect3); } _vm->_system->updateScreen(); diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h index 8d28e1ff4b..dd1764e6d6 100644 --- a/engines/mohawk/graphics.h +++ b/engines/mohawk/graphics.h @@ -27,11 +27,11 @@ #define MOHAWK_GRAPHICS_H #include "mohawk/bitmap.h" -#include "mohawk/jpeg.h" #include "mohawk/livingbooks.h" -#include "mohawk/myst_pict.h" #include "common/file.h" +#include "graphics/pict.h" +#include "graphics/video/codecs/mjpeg.h" namespace Mohawk { @@ -96,16 +96,16 @@ public: void loadExternalPictureFile(uint16 stack); void copyImageSectionToScreen(uint16 image, Common::Rect src, Common::Rect dest); void copyImageToScreen(uint16 image, Common::Rect dest); - void showCursor(void); - void hideCursor(void); + void showCursor(); + void hideCursor(); void changeCursor(uint16); void drawRect(Common::Rect rect, bool active); private: MohawkEngine_Myst *_vm; MystBitmap *_bmpDecoder; - MystPICT *_pictDecoder; - JPEGDecoder *_jpegDecoder; + Graphics::PictDecoder *_pictDecoder; + Graphics::JPEGDecoder *_jpegDecoder; Graphics::PixelFormat _pixelFormat; struct PictureFile { diff --git a/engines/mohawk/jpeg.cpp b/engines/mohawk/jpeg.cpp deleted file mode 100644 index 07ec54dfea..0000000000 --- a/engines/mohawk/jpeg.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/system.h" -#include "graphics/conversion.h" // For YUV2RGB - -#include "mohawk/jpeg.h" - -namespace Mohawk { - -JPEGDecoder::JPEGDecoder(bool freeSurfaceAfterUse) : Graphics::Codec(), _freeSurfaceAfterUse(freeSurfaceAfterUse) { - _jpeg = new Graphics::JPEG(); - _pixelFormat = g_system->getScreenFormat(); - _surface = NULL; -} - -JPEGDecoder::~JPEGDecoder() { - delete _jpeg; - - if (_surface) { - _surface->free(); - delete _surface; - } -} - -Graphics::Surface *JPEGDecoder::decodeImage(Common::SeekableReadStream* stream) { - _jpeg->read(stream); - Graphics::Surface *ySurface = _jpeg->getComponent(1); - Graphics::Surface *uSurface = _jpeg->getComponent(2); - Graphics::Surface *vSurface = _jpeg->getComponent(3); - - Graphics::Surface *destSurface = NULL; - - // If we should free the surface after use, use the internal _surface storage - // (this should be used when using as a Codec, as the Codecs should free their - // surfaces when deleting the Codec object). Otherwise, create a new Surface - // as the destination. - if (_freeSurfaceAfterUse) { - if (!_surface) { - _surface = new Graphics::Surface(); - _surface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel); - } - destSurface = _surface; - } else { - destSurface = new Graphics::Surface(); - destSurface->create(ySurface->w, ySurface->h, _pixelFormat.bytesPerPixel); - } - - assert(destSurface); - - for (uint16 i = 0; i < destSurface->h; i++) { - for (uint16 j = 0; j < destSurface->w; j++) { - byte r = 0, g = 0, b = 0; - Graphics::YUV2RGB(*((byte *)ySurface->getBasePtr(j, i)), *((byte *)uSurface->getBasePtr(j, i)), *((byte *)vSurface->getBasePtr(j, i)), r, g, b); - if (_pixelFormat.bytesPerPixel == 2) - *((uint16 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); - else - *((uint32 *)destSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b); - } - } - - return destSurface; -} - -} // End of namespace Mohawk diff --git a/engines/mohawk/jpeg.h b/engines/mohawk/jpeg.h deleted file mode 100644 index ec87b1e7af..0000000000 --- a/engines/mohawk/jpeg.h +++ /dev/null @@ -1,59 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef MOHAWK_JPEG_H -#define MOHAWK_JPEG_H - -#include "common/scummsys.h" -#include "common/stream.h" - -#include "graphics/video/codecs/codec.h" -#include "graphics/jpeg.h" -#include "graphics/pixelformat.h" - -namespace Mohawk { - -// Mohawk's JPEG Decoder -// Basically a wrapper around JPEG which converts to RGB and also functions -// as a Codec. - -class JPEGDecoder : public Graphics::Codec { -public: - JPEGDecoder(bool freeSurfaceAfterUse); - ~JPEGDecoder(); - - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } - -private: - Graphics::PixelFormat _pixelFormat; - Graphics::JPEG *_jpeg; - Graphics::Surface *_surface; - bool _freeSurfaceAfterUse; -}; - -} // End of namespace Mohawk - -#endif diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk index b224a8b143..bb79d4abac 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -6,11 +6,9 @@ MODULE_OBJS = \ detection.o \ dialogs.o \ graphics.o \ - jpeg.o \ livingbooks.o \ mohawk.o \ myst.o \ - myst_pict.o \ myst_vars.o \ myst_saveload.o \ myst_scripts.o \ @@ -22,13 +20,7 @@ MODULE_OBJS = \ riven_scripts.o \ riven_vars.o \ sound.o \ - video/cinepak.o \ - video/qdm2.o \ - video/qtrle.o \ - video/qt_player.o \ - video/rpza.o \ - video/smc.o \ - video/video.o + video.o # This module can be built as a plugin diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp index 5bde6bbeec..6b4d8bb2d2 100644 --- a/engines/mohawk/mohawk.cpp +++ b/engines/mohawk/mohawk.cpp @@ -35,7 +35,7 @@ #include "mohawk/mohawk.h" #include "mohawk/dialogs.h" #include "mohawk/sound.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" #include "sound/mixer.h" diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index d1ef3b2137..9ff301c129 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -33,7 +33,7 @@ #include "mohawk/dialogs.h" #include "mohawk/resource.h" #include "mohawk/resource_cache.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" namespace Mohawk { diff --git a/engines/mohawk/myst_pict.cpp b/engines/mohawk/myst_pict.cpp deleted file mode 100644 index 794ec9b87f..0000000000 --- a/engines/mohawk/myst_pict.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/system.h" - -#include "mohawk/myst_pict.h" - -namespace Mohawk { - -// The PICT code is based off of the QuickDraw specs: -// http://developer.apple.com/documentation/mac/QuickDraw/QuickDraw-461.html - -MystPICT::MystPICT(JPEGDecoder *jpegDecoder) { - _jpegDecoder = jpegDecoder; - _pixelFormat = g_system->getScreenFormat(); -} - -Graphics::Surface *MystPICT::decodeImage(Common::SeekableReadStream *stream) { - // Skip initial 512 bytes (all 0's) - stream->seek(512, SEEK_CUR); - - // Read in the first part of the header - /* uint16 fileSize = */ stream->readUint16BE(); - - _imageRect.top = stream->readUint16BE(); - _imageRect.left = stream->readUint16BE(); - _imageRect.bottom = stream->readUint16BE(); - _imageRect.right = stream->readUint16BE(); - _imageRect.debugPrint(0, "PICT Rect:"); - - Graphics::Surface *image = new Graphics::Surface(); - image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel); - - // NOTE: This is only a subset of the full PICT format. - // - Only V2 Images Supported - // - JPEG Chunks are Supported - // - DirectBitsRect Chunks are Supported - for (uint32 opNum = 0; !stream->eos() && !stream->err() && stream->pos() < stream->size(); opNum++) { - uint16 opcode = stream->readUint16BE(); - debug(2, "Found PICT opcode %04x", opcode); - - if (opNum == 0 && opcode != 0x0011) - error ("Cannot find PICT version opcode"); - else if (opNum == 1 && opcode != 0x0C00) - error ("Cannot find PICT header opcode"); - - if (opcode == 0x0000) { // Nop - stream->readUint16BE(); // Unknown - } else if (opcode == 0x0001) { // Clip - // Ignore - uint16 clipSize = stream->readUint16BE(); - stream->seek(clipSize - 2, SEEK_CUR); - } else if (opcode == 0x0007) { // PnSize - // Ignore - stream->readUint16BE(); - stream->readUint16BE(); - } else if (opcode == 0x0011) { // VersionOp - uint16 version = stream->readUint16BE(); - if (version != 0x02FF) - error ("Unknown PICT version"); - } else if (opcode == 0x001E) { // DefHilite - // Ignore, Contains no Data - } else if (opcode == 0x009A) { // DirectBitsRect - decodeDirectBitsRect(stream, image); - } else if (opcode == 0x00A1) { // LongComment - stream->readUint16BE(); - uint16 dataSize = stream->readUint16BE(); - stream->seek(dataSize, SEEK_CUR); - } else if (opcode == 0x00FF) { // OpEndPic - stream->readUint16BE(); - break; - } else if (opcode == 0x0C00) { // HeaderOp - /* uint16 version = */ stream->readUint16BE(); - stream->readUint16BE(); // Reserved - /* uint32 hRes = */ stream->readUint32BE(); - /* uint32 vRes = */ stream->readUint32BE(); - Common::Rect origResRect; - origResRect.top = stream->readUint16BE(); - origResRect.left = stream->readUint16BE(); - origResRect.bottom = stream->readUint16BE(); - origResRect.right = stream->readUint16BE(); - stream->readUint32BE(); // Reserved - } else if (opcode == 0x8200) { // CompressedQuickTime - decodeCompressedQuickTime(stream, image); - break; - } else { - error ("Unknown PICT opcode %04x", opcode); - } - } - - return image; -} - -struct DirectBitsRectData { - // PixMap - struct { - uint32 baseAddr; - uint16 rowBytes; - Common::Rect bounds; - uint16 pmVersion; - uint16 packType; - uint32 packSize; - uint32 hRes; - uint32 vRes; - uint16 pixelType; - uint16 pixelSize; - uint16 cmpCount; - uint16 cmpSize; - uint32 planeBytes; - uint32 pmTable; - uint32 pmReserved; - } pixMap; - Common::Rect srcRect; - Common::Rect dstRect; - uint16 mode; -}; - -void MystPICT::decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image) { - static const Graphics::PixelFormat directBitsFormat16 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); - - DirectBitsRectData directBitsData; - directBitsData.pixMap.baseAddr = stream->readUint32BE(); - directBitsData.pixMap.rowBytes = stream->readUint16BE() & 0x3fff; - directBitsData.pixMap.bounds.top = stream->readUint16BE(); - directBitsData.pixMap.bounds.left = stream->readUint16BE(); - directBitsData.pixMap.bounds.bottom = stream->readUint16BE(); - directBitsData.pixMap.bounds.right = stream->readUint16BE(); - directBitsData.pixMap.pmVersion = stream->readUint16BE(); - directBitsData.pixMap.packType = stream->readUint16BE(); - directBitsData.pixMap.packSize = stream->readUint32BE(); - directBitsData.pixMap.hRes = stream->readUint32BE(); - directBitsData.pixMap.vRes = stream->readUint32BE(); - directBitsData.pixMap.pixelType = stream->readUint16BE(); - directBitsData.pixMap.pixelSize = stream->readUint16BE(); - directBitsData.pixMap.cmpCount = stream->readUint16BE(); - directBitsData.pixMap.cmpSize = stream->readUint16BE(); - directBitsData.pixMap.planeBytes = stream->readUint32BE(); - directBitsData.pixMap.pmTable = stream->readUint32BE(); - directBitsData.pixMap.pmReserved = stream->readUint32BE(); - directBitsData.srcRect.top = stream->readUint16BE(); - directBitsData.srcRect.left = stream->readUint16BE(); - directBitsData.srcRect.bottom = stream->readUint16BE(); - directBitsData.srcRect.right = stream->readUint16BE(); - directBitsData.dstRect.top = stream->readUint16BE(); - directBitsData.dstRect.left = stream->readUint16BE(); - directBitsData.dstRect.bottom = stream->readUint16BE(); - directBitsData.dstRect.right = stream->readUint16BE(); - directBitsData.mode = stream->readUint16BE(); - - if (directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32) - error("Unhandled directBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize); - - byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 16) ? 2 : 3; - byte *buffer = new byte[image->w * image->h * bytesPerPixel]; - - // Read in amount of data per row - for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) { - if (directBitsData.pixMap.packType == 1 || directBitsData.pixMap.rowBytes < 8) { // Unpacked, Pad-Byte - error("Pack Type = %d, Row Bytes = %d", directBitsData.pixMap.packType, directBitsData.pixMap.rowBytes); - // TODO - } else if (directBitsData.pixMap.packType == 2) { // Unpacked, No Pad-Byte - error("Pack Type = 2"); - // TODO - } else if (directBitsData.pixMap.packType > 2) { // Packed - uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte(); - decodeDirectBitsLine(buffer + i * image->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), bytesPerPixel); - } - } - - if (bytesPerPixel == 2) { - // Convert from 16-bit to whatever surface we need - for (uint16 y = 0; y < image->h; y++) { - for (uint16 x = 0; x < image->w; x++) { - byte r = 0, g = 0, b = 0; - uint32 color = READ_BE_UINT16(buffer + (y * image->w + x) * bytesPerPixel); - directBitsFormat16.colorToRGB(color, r, g, b); - *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); - } - } - } else { - // Convert from 24-bit (planar!) to whatever surface we need - for (uint16 y = 0; y < image->h; y++) { - for (uint16 x = 0; x < image->w; x++) { - byte r = *(buffer + y * image->w * 3 + x); - byte g = *(buffer + y * image->w * 3 + image->w + x); - byte b = *(buffer + y * image->w * 3 + image->w * 2 + x); - *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b); - } - } - } - - delete[] buffer; -} - -void MystPICT::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) { - uint32 dataDecoded = 0; - byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1; - - while (data->pos() < data->size() && dataDecoded < length) { - byte op = data->readByte(); - - if (op & 0x80) { - uint32 runSize = (op ^ 255) + 2; - uint16 value = (bytesPerDecode == 2) ? data->readUint16BE() : data->readByte(); - - for (uint32 i = 0; i < runSize; i++) { - if (bytesPerDecode == 2) { - WRITE_BE_UINT16(out, value); - out += 2; - } else - *out++ = value; - } - dataDecoded += runSize * bytesPerDecode; - } else { - uint32 runSize = (op + 1) * bytesPerDecode; - for (uint32 i = 0; i < runSize; i++) - *out++ = data->readByte(); - dataDecoded += runSize; - } - } - - // HACK: rowBytes is in 32-bit, but the data is 24-bit... - if (bytesPerPixel == 3) - dataDecoded += length / 4; - - if (length != dataDecoded) - warning("Mismatched DirectBits read (%d/%d)", dataDecoded, length); - - delete data; -} - -// Compressed QuickTime details can be found here: -// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html -// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html -// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same. - -void MystPICT::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) { - uint32 dataSize = stream->readUint32BE(); - uint32 startPos = stream->pos(); - - Graphics::Surface *jpegImage = _jpegDecoder->decodeImage(new Common::SeekableSubReadStream(stream, stream->pos() + 156, stream->pos() + dataSize)); - stream->seek(startPos + dataSize); - - image->copyFrom(*jpegImage); - - jpegImage->free(); - delete jpegImage; -} - -} // End of namespace Mohawk diff --git a/engines/mohawk/myst_pict.h b/engines/mohawk/myst_pict.h deleted file mode 100644 index 0684e3352a..0000000000 --- a/engines/mohawk/myst_pict.h +++ /dev/null @@ -1,57 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef MYST_PICT_H -#define MYST_PICT_H - -#include "common/rect.h" -#include "common/scummsys.h" -#include "common/stream.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" - -#include "mohawk/jpeg.h" - -namespace Mohawk { - -class MystPICT { -public: - MystPICT(JPEGDecoder *jpegDecoder); - ~MystPICT() {} - Graphics::Surface *decodeImage(Common::SeekableReadStream *stream); - -private: - JPEGDecoder *_jpegDecoder; - Common::Rect _imageRect; - Graphics::PixelFormat _pixelFormat; - - void decodeDirectBitsRect(Common::SeekableReadStream *stream, Graphics::Surface *image); - void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel); - void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image); -}; - -} // End of namespace Mohawk - -#endif diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index a453bb0985..2f6d178da8 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -27,7 +27,7 @@ #include "mohawk/graphics.h" #include "mohawk/myst_scripts.h" #include "mohawk/sound.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" #include "gui/message.h" diff --git a/engines/mohawk/resource.cpp b/engines/mohawk/resource.cpp index 62a857b90b..74efd6770f 100644 --- a/engines/mohawk/resource.cpp +++ b/engines/mohawk/resource.cpp @@ -103,7 +103,7 @@ void MohawkArchive::open(Common::SeekableReadStream *stream) { else debug (3, "Type[%02d]: Tag = \'%s\' ResTable Offset = %04x NameTable Offset = %04x", i, tag2str(_types[i].tag), _types[i].resource_table_offset, _types[i].name_table_offset); - //Resource Table + // Resource Table _mhk->seek(_rsrc.abs_offset + _types[i].resource_table_offset); _types[i].resTable.resources = _mhk->readUint16BE(); diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index 0412144034..07b08dc220 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -29,39 +29,50 @@ #include "common/keyboard.h" #include "mohawk/graphics.h" +#include "mohawk/resource.h" #include "mohawk/riven.h" #include "mohawk/riven_external.h" #include "mohawk/riven_saveload.h" #include "mohawk/dialogs.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" namespace Mohawk { -Common::Rect *g_atrusJournalRectSolo; -Common::Rect *g_atrusJournalRect; -Common::Rect *g_cathJournalRect; -Common::Rect *g_trapBookRect; +Common::Rect *g_atrusJournalRect1; +Common::Rect *g_atrusJournalRect2; +Common::Rect *g_cathJournalRect2; +Common::Rect *g_atrusJournalRect3; +Common::Rect *g_cathJournalRect3; +Common::Rect *g_trapBookRect3; MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) { _showHotspots = false; _cardData.hasData = false; _gameOver = false; _activatedSLST = false; + _ignoreNextMouseUp = false; _extrasFile = NULL; + _curStack = aspit; + _hotspots = NULL; - // Attempt to let game run from the CDs - // NOTE: assets2 contains higher quality audio than assets1 - const Common::FSNode gameDataDir(ConfMan.get("path")); + // NOTE: We can never really support CD swapping. All of the music files + // (*_Sounds.mhk) are stored on disc 1. They are copied to the hard drive + // during install and used from there. The same goes for the extras.mhk + // file. The following directories allow Riven to be played directly + // from the DVD. + const Common::FSNode gameDataDir(ConfMan.get("path")); SearchMan.addSubDirectoryMatching(gameDataDir, "all"); SearchMan.addSubDirectoryMatching(gameDataDir, "data"); SearchMan.addSubDirectoryMatching(gameDataDir, "exe"); - SearchMan.addSubDirectoryMatching(gameDataDir, "assets2"); - - g_atrusJournalRectSolo = new Common::Rect(295, 402, 313, 426); - g_atrusJournalRect = new Common::Rect(222, 402, 240, 426); - g_cathJournalRect = new Common::Rect(291, 408, 311, 419); - g_trapBookRect = new Common::Rect(363, 396, 386, 432); + SearchMan.addSubDirectoryMatching(gameDataDir, "assets1"); + + g_atrusJournalRect1 = new Common::Rect(295, 402, 313, 426); + g_atrusJournalRect2 = new Common::Rect(259, 402, 278, 426); + g_cathJournalRect2 = new Common::Rect(328, 408, 348, 419); + g_atrusJournalRect3 = new Common::Rect(222, 402, 240, 426); + g_cathJournalRect3 = new Common::Rect(291, 408, 311, 419); + g_trapBookRect3 = new Common::Rect(363, 396, 386, 432); } MohawkEngine_Riven::~MohawkEngine_Riven() { @@ -70,15 +81,17 @@ MohawkEngine_Riven::~MohawkEngine_Riven() { delete _externalScriptHandler; delete _extrasFile; delete _saveLoad; + delete _scriptMan; delete[] _vars; - delete _loadDialog; delete _optionsDialog; delete _rnd; - delete g_atrusJournalRectSolo; - delete g_atrusJournalRect; - delete g_cathJournalRect; - delete g_trapBookRect; - _cardData.scripts.clear(); + delete[] _hotspots; + delete g_atrusJournalRect1; + delete g_atrusJournalRect2; + delete g_cathJournalRect2; + delete g_atrusJournalRect3; + delete g_cathJournalRect3; + delete g_trapBookRect3; } GUI::Debugger *MohawkEngine_Riven::getDebugger() { @@ -93,9 +106,8 @@ Common::Error MohawkEngine_Riven::run() { _console = new RivenConsole(this); _saveLoad = new RivenSaveLoad(this, _saveFileMan); _externalScriptHandler = new RivenExternal(this); - _loadDialog = new GUI::SaveLoadChooser("Load Game:", "Load"); - _loadDialog->setSaveMode(false); _optionsDialog = new RivenOptionsDialog(this); + _scriptMan = new RivenScriptManager(this); _rnd = new Common::RandomSource(); g_eventRec.registerRandomSource(*_rnd, "riven"); @@ -147,10 +159,15 @@ Common::Error MohawkEngine_Riven::run() { runHotspotScript(_curHotspot, kMouseDownScript); break; case Common::EVENT_LBUTTONUP: - if (_curHotspot >= 0) - runHotspotScript(_curHotspot, kMouseUpScript); - else - checkInventoryClick(); + // See RivenScript::switchCard() for more information on why we sometimes + // disable the next up event. + if (!_ignoreNextMouseUp) { + if (_curHotspot >= 0) + runHotspotScript(_curHotspot, kMouseUpScript); + else + checkInventoryClick(); + } + _ignoreNextMouseUp = false; break; case Common::EVENT_KEYDOWN: switch (event.kbd.keycode) { @@ -233,6 +250,7 @@ void MohawkEngine_Riven::changeToStack(uint16 n) { // Stop any videos playing _video->stopVideos(); + _video->clearMLST(); // Clear the old stack files out for (uint32 i = 0; i < _mhk.size(); i++) @@ -310,7 +328,6 @@ void MohawkEngine_Riven::refreshCard() { _gfx->clearWaterEffects(); _gfx->_activatedPLSTs.clear(); _video->stopVideos(); - _video->_mlstRecords.clear(); _gfx->drawPLST(1); _activatedSLST = false; @@ -333,13 +350,13 @@ void MohawkEngine_Riven::refreshCard() { } void MohawkEngine_Riven::loadCard(uint16 id) { - // NOTE: Do not clear the card scripts because it may delete a currently running script! + // NOTE: The card scripts are cleared by the RivenScriptManager automatically. Common::SeekableReadStream* inStream = getRawData(ID_CARD, id); _cardData.name = inStream->readSint16BE(); _cardData.zipModePlace = inStream->readUint16BE(); - _cardData.scripts = RivenScript::readScripts(this, inStream); + _cardData.scripts = _scriptMan->readScripts(inStream); _cardData.hasData = true; delete inStream; @@ -357,7 +374,10 @@ void MohawkEngine_Riven::loadCard(uint16 id) { } void MohawkEngine_Riven::loadHotspots(uint16 id) { - // NOTE: Do not clear the hotspots because it may delete a currently running script! + // Clear old hotspots + delete[] _hotspots; + + // NOTE: The hotspot scripts are cleared by the RivenScriptManager automatically. Common::SeekableReadStream* inStream = getRawData(ID_HSPT, id); @@ -399,7 +419,7 @@ void MohawkEngine_Riven::loadHotspots(uint16 id) { _hotspots[i].zipModeHotspot = inStream->readUint16BE(); // Read in the scripts now - _hotspots[i].scripts = RivenScript::readScripts(this, inStream); + _hotspots[i].scripts = _scriptMan->readScripts(inStream); } delete inStream; @@ -474,26 +494,37 @@ void MohawkEngine_Riven::checkInventoryClick() { *matchVarToString("returncardid") = _curCard; // See RivenGraphics::showInventory() for an explanation - // of why only this variable is used. + // of the variables' meanings. bool hasCathBook = *matchVarToString("acathbook") != 0; + bool hasTrapBook = *matchVarToString("atrapbook") != 0; // Go to the book if a hotspot contains the mouse if (!hasCathBook) { - if (g_atrusJournalRectSolo->contains(_mousePos)) { + if (g_atrusJournalRect1->contains(_mousePos)) { + _gfx->hideInventory(); + changeToStack(aspit); + changeToCard(5); + } + } else if (!hasTrapBook) { + if (g_atrusJournalRect2->contains(_mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(5); + } else if (g_cathJournalRect2->contains(_mousePos)) { + _gfx->hideInventory(); + changeToStack(aspit); + changeToCard(6); } } else { - if (g_atrusJournalRect->contains(_mousePos)) { + if (g_atrusJournalRect3->contains(_mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(5); - } else if (g_cathJournalRect->contains(_mousePos)) { + } else if (g_cathJournalRect3->contains(_mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(6); - } else if (g_trapBookRect->contains(_mousePos)) { + } else if (g_trapBookRect3->contains(_mousePos)) { _gfx->hideInventory(); changeToStack(aspit); changeToCard(7); @@ -577,7 +608,19 @@ void MohawkEngine_Riven::runHotspotScript(uint16 hotspot, uint16 scriptType) { } void MohawkEngine_Riven::runLoadDialog() { - runDialog(*_loadDialog); + GUI::SaveLoadChooser slc("Load Game:", "Load"); + slc.setSaveMode(false); + + Common::String gameId = ConfMan.get("gameid"); + + const EnginePlugin *plugin = 0; + EngineMan.findGame(gameId, &plugin); + + int slot = slc.runModal(plugin, ConfMan.getActiveDomainName()); + if (slot >= 0) + loadGameState(slot); + + slc.close(); } Common::Error MohawkEngine_Riven::loadGameState(int slot) { @@ -612,4 +655,4 @@ bool ZipMode::operator== (const ZipMode &z) const { return z.name == name && z.id == id; } -} +} // End of namespace Mohawk diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index f014b76fb8..631285455e 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -68,10 +68,12 @@ enum { // Rects for the inventory object positions (initialized in // MohawkEngine_Riven's constructor). -extern Common::Rect *g_atrusJournalRectSolo; -extern Common::Rect *g_atrusJournalRect; -extern Common::Rect *g_cathJournalRect; -extern Common::Rect *g_trapBookRect; +extern Common::Rect *g_atrusJournalRect1; +extern Common::Rect *g_atrusJournalRect2; +extern Common::Rect *g_cathJournalRect2; +extern Common::Rect *g_atrusJournalRect3; +extern Common::Rect *g_cathJournalRect3; +extern Common::Rect *g_trapBookRect3; struct RivenHotspot { uint16 blstID; @@ -111,9 +113,9 @@ public: RivenGraphics *_gfx; RivenExternal *_externalScriptHandler; Common::RandomSource *_rnd; + RivenScriptManager *_scriptMan; Card _cardData; - bool _gameOver; GUI::Debugger *getDebugger(); @@ -127,7 +129,6 @@ private: MohawkArchive *_extrasFile; // We need a separate handle for the extra data RivenConsole *_console; RivenSaveLoad *_saveLoad; - GUI::SaveLoadChooser *_loadDialog; RivenOptionsDialog *_optionsDialog; // Stack/Card-related functions and variables @@ -147,6 +148,10 @@ private: uint32 *_vars; uint32 _varCount; + // Miscellaneous + bool _gameOver; + bool _ignoreNextMouseUp; + public: Common::SeekableReadStream *getExtrasResource(uint32 tag, uint16 id); bool _activatedSLST; @@ -180,6 +185,9 @@ public: uint32 *getLocalVar(uint32 index); uint32 *matchVarToString(Common::String varName); uint32 *matchVarToString(const char *varName); + + void setGameOver() { _gameOver = true; } + void ignoreNextMouseUp() { _ignoreNextMouseUp = true; } }; } // End of namespace Mohawk diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 99afacc5ce..67d621a54c 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -27,7 +27,7 @@ #include "mohawk/riven.h" #include "mohawk/riven_external.h" #include "mohawk/sound.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" #include "gui/message.h" #include "common/events.h" @@ -210,7 +210,28 @@ void RivenExternal::runEndGame(uint16 video) { _vm->_video->playMovieBlocking(video); // TODO: Play until the last frame and then run the credits - _vm->_gameOver = true; + _vm->setGameOver(); +} + +void RivenExternal::runDomeButtonMovie() { + // This command just plays the video of the button moving down and up. + _vm->_video->playMovieBlocking(2); +} + +void RivenExternal::runDomeCheck() { + // Check if we clicked while the golden frame was showing + + VideoHandle video = _vm->_video->findVideoHandle(1); + assert(video != NULL_VID_HANDLE); + + int32 curFrame = _vm->_video->getCurFrame(video); + int32 frameCount = _vm->_video->getFrameCount(video); + + // The final frame of the video is the 'golden' frame (double meaning: the + // frame that is the magic one is the one with the golden symbol) but we + // give a 3 frame leeway in either direction. + if (frameCount - curFrame < 3 || curFrame < 3) + *_vm->matchVarToString("domecheck") = 1; } // ------------------------------------------------------------------------------------ @@ -218,11 +239,13 @@ void RivenExternal::runEndGame(uint16 video) { // ------------------------------------------------------------------------------------ void RivenExternal::xastartupbtnhide(uint16 argc, uint16 *argv) { - // The original game hides the start/setup buttons depending on an ini entry. It's safe to ignore this command. + // The original game hides the start/setup buttons depending on an ini entry. + // It's safe to ignore this command. } void RivenExternal::xasetupcomplete(uint16 argc, uint16 *argv) { - // The original game sets an ini entry to disable the setup button and use the start button only. It's safe to ignore this part of the command. + // The original game sets an ini entry to disable the setup button and use the + // start button only. It's safe to ignore this part of the command. _vm->_sound->stopSound(); _vm->changeToCard(1); } @@ -261,9 +284,14 @@ void RivenExternal::xaatrusbookprevpage(uint16 argc, uint16 *argv) { return; (*page)--; - // TODO: Play the page turning sound + // Play the page turning sound + if (_vm->getFeatures() & GF_DEMO) + _vm->_sound->playSound(4, false); + else + _vm->_sound->playSound(3, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(1); _vm->_gfx->updateScreen(); } @@ -276,9 +304,14 @@ void RivenExternal::xaatrusbooknextpage(uint16 argc, uint16 *argv) { return; (*page)++; - // TODO: Play the page turning sound + // Play the page turning sound + if (_vm->getFeatures() & GF_DEMO) + _vm->_sound->playSound(5, false); + else + _vm->_sound->playSound(4, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(0); _vm->_gfx->updateScreen(); } @@ -326,9 +359,11 @@ void RivenExternal::xacathbookprevpage(uint16 argc, uint16 *argv) { return; (*page)--; - // TODO: Play the page turning sound + // Play the page turning sound + _vm->_sound->playSound(5, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(3); _vm->_gfx->updateScreen(); } @@ -341,9 +376,11 @@ void RivenExternal::xacathbooknextpage(uint16 argc, uint16 *argv) { return; (*page)++; - // TODO: Play the page turning sound + // Play the page turning sound + _vm->_sound->playSound(6, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(2); _vm->_gfx->updateScreen(); } @@ -357,12 +394,20 @@ void RivenExternal::xtrapbookback(uint16 argc, uint16 *argv) { void RivenExternal::xatrapbookclose(uint16 argc, uint16 *argv) { // Close the trap book *_vm->matchVarToString("atrap") = 0; + + // Play the page turning sound + _vm->_sound->playSound(8, false); + _vm->refreshCard(); } void RivenExternal::xatrapbookopen(uint16 argc, uint16 *argv) { // Open the trap book *_vm->matchVarToString("atrap") = 1; + + // Play the page turning sound + _vm->_sound->playSound(9, false); + _vm->refreshCard(); } @@ -414,7 +459,11 @@ void RivenExternal::xblabbookprevpage(uint16 argc, uint16 *argv) { return; (*page)--; + // Play the page turning sound + _vm->_sound->playSound(22, false); + // Now update the screen :) + _vm->_gfx->scheduleTransition(1); _vm->_gfx->updateScreen(); } @@ -427,7 +476,11 @@ void RivenExternal::xblabbooknextpage(uint16 argc, uint16 *argv) { return; (*page)++; + // Play the page turning sound + _vm->_sound->playSound(23, false); + // Now update the screen :) + _vm->_gfx->scheduleTransition(0); _vm->_gfx->updateScreen(); } @@ -514,13 +567,14 @@ void RivenExternal::xbupdateboiler(uint16 argc, uint16 *argv) { if (heat) { if (platform == 0) { _vm->_video->activateMLST(7, _vm->getCurCard()); - // TODO: Play video (non-blocking) + _vm->_video->playMovie(7); } else { _vm->_video->activateMLST(8, _vm->getCurCard()); - // TODO: Play video (non-blocking) + _vm->_video->playMovie(8); } } else { - // TODO: Stop MLST's 7 and 8 + _vm->_video->stopMovie(7); + _vm->_video->stopMovie(8); } _vm->refreshCard(); @@ -627,26 +681,28 @@ void RivenExternal::xbisland190_slidermw(uint16 argc, uint16 *argv) { } void RivenExternal::xbscpbtn(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeButtonMovie(); } void RivenExternal::xbisland_domecheck(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeCheck(); } void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) { // Get the variable for the valve uint32 *valve = _vm->matchVarToString("bvalve"); - Common::Event event; int changeX = 0; int changeY = 0; + bool done = false; // Set the cursor to the closed position _vm->_gfx->changeCursor(2004); _vm->_system->updateScreen(); - for (;;) { + while (!done) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_MOUSEMOVE: @@ -658,30 +714,53 @@ void RivenExternal::xvalvecontrol(uint16 argc, uint16 *argv) { // FIXME: These values for changes in x/y could be tweaked. if (*valve == 0 && changeY <= -10) { *valve = 1; - // TODO: Play movie + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(2); _vm->refreshCard(); } else if (*valve == 1) { if (changeX >= 0 && changeY >= 10) { *valve = 0; - // TODO: Play movie + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(3); _vm->refreshCard(); } else if (changeX <= -10 && changeY <= 10) { *valve = 2; - // TODO: Play movie + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(1); _vm->refreshCard(); } } else if (*valve == 2 && changeX >= 10) { *valve = 1; - // TODO: Play movie + _vm->_gfx->changeCursor(kRivenHideCursor); + _vm->_video->playMovieBlocking(4); _vm->refreshCard(); } - return; + done = true; default: break; } } _vm->_system->delayMillis(10); } + + // If we changed state and the new state is that the valve is flowing to + // the boiler, we need to update the boiler state. + if (*valve == 1) { + if (*_vm->matchVarToString("bidvlv") == 1) { // Check which way the water is going at the boiler + if (*_vm->matchVarToString("bblrarm") == 1) { + // If the pipe is open, make sure the water is drained out + *_vm->matchVarToString("bheat") = 0; + *_vm->matchVarToString("bblrwtr") = 0; + } else { + // If the pipe is closed, fill the boiler again + *_vm->matchVarToString("bheat") = *_vm->matchVarToString("bblrvalve"); + *_vm->matchVarToString("bblrwtr") = 1; + } + } else { + // Have the grating inside the boiler match the switch outside + *_vm->matchVarToString("bblrgrt") = (*_vm->matchVarToString("bblrsw") == 1) ? 0 : 1; + } + } } void RivenExternal::xbchipper(uint16 argc, uint16 *argv) { @@ -723,11 +802,11 @@ void RivenExternal::xgisland25_slidermw(uint16 argc, uint16 *argv) { } void RivenExternal::xgscpbtn(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeButtonMovie(); } void RivenExternal::xgisland1490_domecheck(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeCheck(); } void RivenExternal::xgplateau3160_dopools(uint16 argc, uint16 *argv) { @@ -936,33 +1015,60 @@ void RivenExternal::xjtunnel106_pictfix(uint16 argc, uint16 *argv) { } void RivenExternal::xvga1300_carriage(uint16 argc, uint16 *argv) { - // TODO: This function is supposed to do a lot more, something like this (pseudocode): - - // Show level pull movie - // Set transition up - // Change to up card - // Show movie of carriage coming down - // Set transition down - // Change back to card 276 - // Show movie of carriage coming down - // if jgallows == 0 - // Set up timer - // Enter new input loop - // if you click within the time - // move forward - // set transition right - // change to card right - // show movie of ascending - // change to card 263 - // else - // show movie of carriage ascending only - // else - // show movie of carriage ascending only - - - // For now, if the gallows base is closed, assume ascension and move to that card. - if (*_vm->matchVarToString("jgallows") == 0) - _vm->changeToCard(_vm->matchRMAPToCard(0x17167)); + // Run the gallows's carriage + + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor + _vm->_video->playMovieBlocking(1); // Play handle movie + _vm->_gfx->scheduleTransition(15); // Set pan down transition + _vm->changeToCard(_vm->matchRMAPToCard(0x18e77)); // Change to card facing up + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor (again) + _vm->_video->playMovieBlocking(4); // Play carriage beginning to drop + _vm->_gfx->scheduleTransition(14); // Set pan up transition + _vm->changeToCard(_vm->matchRMAPToCard(0x183a9)); // Change to card looking straight again + _vm->_video->playMovieBlocking(2); + + uint32 *gallows = _vm->matchVarToString("jgallows"); + if (*gallows == 1) { + // If the gallows is open, play the up movie and return + _vm->_video->playMovieBlocking(3); + return; + } + + // Give the player 5 seconds to click (anywhere) + uint32 startTime = _vm->_system->getMillis(); + bool gotClick = false; + while (_vm->_system->getMillis() - startTime <= 5000 && !gotClick) { + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + _vm->_system->updateScreen(); + break; + case Common::EVENT_LBUTTONUP: + gotClick = true; + break; + default: + break; + } + } + + _vm->_system->delayMillis(10); + } + + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor + + if (gotClick) { + _vm->_gfx->scheduleTransition(16); // Schedule dissolve transition + _vm->changeToCard(_vm->matchRMAPToCard(0x18d4d)); // Move forward + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor + _vm->_system->delayMillis(500); // Delay a half second before changing again + _vm->_gfx->scheduleTransition(12); // Schedule pan left transition + _vm->changeToCard(_vm->matchRMAPToCard(0x18ab5)); // Turn right + _vm->_gfx->changeCursor(kRivenHideCursor); // Hide the cursor + _vm->_video->playMovieBlocking(1); // Play carriage ride movie + _vm->changeToCard(_vm->matchRMAPToCard(0x17167)); // We have arrived at the top + } else + _vm->_video->playMovieBlocking(3); // Too slow! } void RivenExternal::xjdome25_resetsliders(uint16 argc, uint16 *argv) { @@ -978,11 +1084,11 @@ void RivenExternal::xjdome25_slidermw(uint16 argc, uint16 *argv) { } void RivenExternal::xjscpbtn(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeButtonMovie(); } void RivenExternal::xjisland3500_domecheck(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeCheck(); } int RivenExternal::jspitElevatorLoop() { @@ -1019,8 +1125,10 @@ int RivenExternal::jspitElevatorLoop() { void RivenExternal::xhandlecontrolup(uint16 argc, uint16 *argv) { int changeLevel = jspitElevatorLoop(); + // If we've moved the handle down, go down a floor if (changeLevel == -1) { - // TODO: Run movie + _vm->_video->playMovieBlocking(1); + _vm->_video->playMovieBlocking(2); _vm->changeToCard(_vm->matchRMAPToCard(0x1e374)); } } @@ -1028,8 +1136,10 @@ void RivenExternal::xhandlecontrolup(uint16 argc, uint16 *argv) { void RivenExternal::xhandlecontroldown(uint16 argc, uint16 *argv) { int changeLevel = jspitElevatorLoop(); + // If we've moved the handle up, go up a floor if (changeLevel == 1) { - // TODO: Run movie + _vm->_video->playMovieBlocking(1); + _vm->_video->playMovieBlocking(2); _vm->changeToCard(_vm->matchRMAPToCard(0x1e374)); } } @@ -1037,11 +1147,29 @@ void RivenExternal::xhandlecontroldown(uint16 argc, uint16 *argv) { void RivenExternal::xhandlecontrolmid(uint16 argc, uint16 *argv) { int changeLevel = jspitElevatorLoop(); + if (changeLevel == 0) + return; + + // Play the handle moving video + if (changeLevel == 1) + _vm->_video->playMovieBlocking(7); + else + _vm->_video->playMovieBlocking(6); + + // If the whark's mouth is open, close it + uint32 *mouthVar = _vm->matchVarToString("jwmouth"); + if (*mouthVar == 1) { + _vm->_video->playMovieBlocking(3); + _vm->_video->playMovieBlocking(8); + *mouthVar = 0; + } + + // Play the elevator video and then change the card if (changeLevel == 1) { - // TODO: Run movie + _vm->_video->playMovieBlocking(5); _vm->changeToCard(_vm->matchRMAPToCard(0x1e597)); - } else if (changeLevel == -1) { - // TODO: Run movie + } else { + _vm->_video->playMovieBlocking(4); _vm->changeToCard(_vm->matchRMAPToCard(0x1e29c)); } } @@ -1172,9 +1300,11 @@ void RivenExternal::xogehnbookprevpage(uint16 argc, uint16 *argv) { return; (*page)--; - // TODO: Play the page turning sound + // Play the page turning sound + _vm->_sound->playSound(12, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(1); _vm->_gfx->updateScreen(); } @@ -1187,13 +1317,15 @@ void RivenExternal::xogehnbooknextpage(uint16 argc, uint16 *argv) { return; (*page)++; - // TODO: Play the page turning sound + // Play the page turning sound + _vm->_sound->playSound(13, false); // Now update the screen :) + _vm->_gfx->scheduleTransition(0); _vm->_gfx->updateScreen(); } -static uint16 getComboDigit(uint32 correctCombo, uint32 digit) { +uint16 RivenExternal::getComboDigit(uint32 correctCombo, uint32 digit) { static const uint32 powers[] = { 100000, 10000, 1000, 100, 10, 1 }; return (correctCombo % powers[digit]) / powers[digit + 1]; } @@ -1258,11 +1390,11 @@ void RivenExternal::xpisland990_elevcombo(uint16 argc, uint16 *argv) { } void RivenExternal::xpscpbtn(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeButtonMovie(); } void RivenExternal::xpisland290_domecheck(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeCheck(); } void RivenExternal::xpisland25_opencard(uint16 argc, uint16 *argv) { @@ -1457,11 +1589,11 @@ void RivenExternal::xtakeit(uint16 argc, uint16 *argv) { } void RivenExternal::xtscpbtn(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeButtonMovie(); } void RivenExternal::xtisland4990_domecheck(uint16 argc, uint16 *argv) { - // TODO: Dome related + runDomeCheck(); } void RivenExternal::xtisland5056_opencard(uint16 argc, uint16 *argv) { diff --git a/engines/mohawk/riven_external.h b/engines/mohawk/riven_external.h index 8270a00854..bdf3fa01bc 100644 --- a/engines/mohawk/riven_external.h +++ b/engines/mohawk/riven_external.h @@ -38,6 +38,7 @@ public: ~RivenExternal(); void runCommand(uint16 argc, uint16 *argv); + uint16 getComboDigit(uint32 correctCombo, uint32 digit); private: MohawkEngine_Riven *_vm; @@ -57,6 +58,8 @@ private: int jspitElevatorLoop(); void runDemoBoundaryDialog(); void runEndGame(uint16 video); + void runDomeCheck(); + void runDomeButtonMovie(); // ----------------------------------------------------- // aspit (Main Menu, Books, Setup) external commands diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp index 3c989838da..d73b4ec0dc 100644 --- a/engines/mohawk/riven_saveload.cpp +++ b/engines/mohawk/riven_saveload.cpp @@ -23,6 +23,7 @@ * */ +#include "mohawk/resource.h" #include "mohawk/riven.h" #include "mohawk/riven_saveload.h" @@ -31,11 +32,9 @@ namespace Mohawk { RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) { - _loadFile = new MohawkArchive(); } RivenSaveLoad::~RivenSaveLoad() { - delete _loadFile; } Common::StringArray RivenSaveLoad::generateSaveGameList() { @@ -63,7 +62,8 @@ static uint16 mapOldStackIDToNew(uint16 oldID) { case 8: return aspit; } - error ("Unknown old stack ID %d", oldID); + + error("Unknown old stack ID %d", oldID); return 0; } @@ -86,7 +86,8 @@ static uint16 mapNewStackIDToOld(uint16 newID) { case tspit: return 4; } - error ("Unknown new stack ID %d", newID); + + error("Unknown new stack ID %d", newID); return 0; } @@ -94,26 +95,28 @@ bool RivenSaveLoad::loadGame(Common::String filename) { if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo return false; - Common::InSaveFile *loadFile; - if (!(loadFile = _saveFileMan->openForLoading(filename.c_str()))) + Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename); + if (!loadFile) return false; - debug (0, "Loading game from \'%s\'", filename.c_str()); - _loadFile->open(loadFile); + debug(0, "Loading game from \'%s\'", filename.c_str()); + + MohawkArchive *mhk = new MohawkArchive(); + mhk->open(loadFile); // First, let's make sure we're using a saved game file from this version of Riven by checking the VERS resource - Common::SeekableReadStream *vers = _loadFile->getRawData(ID_VERS, 1); + Common::SeekableReadStream *vers = mhk->getRawData(ID_VERS, 1); uint32 saveGameVersion = vers->readUint32BE(); delete vers; if ((saveGameVersion == kCDSaveGameVersion && (_vm->getFeatures() & GF_DVD)) || (saveGameVersion == kDVDSaveGameVersion && !(_vm->getFeatures() & GF_DVD))) { - warning ("Incompatible saved game versions. No support for this yet."); - delete _loadFile; + warning("Incompatible saved game versions. No support for this yet."); + delete mhk; return false; } // Now, we'll read in the variable values. - Common::SeekableReadStream *vars = _loadFile->getRawData(ID_VARS, 1); + Common::SeekableReadStream *vars = mhk->getRawData(ID_VARS, 1); Common::Array<uint32> rawVariables; while (!vars->eos()) { @@ -126,7 +129,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { // Next, we set the variables based on the name found by the index in the VARS resource. // TODO: Merge with code in mohawk.cpp for loading names? - Common::SeekableReadStream *names = _loadFile->getRawData(ID_NAME, 1); + Common::SeekableReadStream *names = mhk->getRawData(ID_NAME, 1); uint16 namesCount = names->readUint16BE(); uint16 *stringOffsets = new uint16[namesCount]; @@ -151,9 +154,10 @@ bool RivenSaveLoad::loadGame(Common::String filename) { c = (char)names->readByte(); } - // WORKAROUND: Some versions have two extra variables. However, the saves are - // still compatible with other saves of the same version. Are these used in the - // original interpreter anywhere? (They come from DVD v1.1) + // TODO: Some versions have two extra variables. However, the saves are + // still compatible with other saves of the same version (they come from DVD v1.1). + // There are used in the whark number puzzle. I thought jleftpos and jrightpos were + // for this purpose. if (name == "dropLeftStart" || name == "dropRightStart") continue; @@ -161,11 +165,11 @@ bool RivenSaveLoad::loadGame(Common::String filename) { *var = rawVariables[i]; - if (!scumm_stricmp(name.c_str(), "CurrentStackID")) + if (name.equalsIgnoreCase("CurrentStackID")) stackID = mapOldStackIDToNew(rawVariables[i]); - else if (!scumm_stricmp(name.c_str(), "CurrentCardID")) + else if (name.equalsIgnoreCase("CurrentCardID")) cardID = rawVariables[i]; - else if (!scumm_stricmp(name.c_str(), "ReturnStackID")) + else if (name.equalsIgnoreCase("ReturnStackID")) *var = mapOldStackIDToNew(rawVariables[i]); } @@ -179,7 +183,7 @@ bool RivenSaveLoad::loadGame(Common::String filename) { _vm->_zipModeData.clear(); // Finally, we load in zip mode data. - Common::SeekableReadStream *zips = _loadFile->getRawData(ID_ZIPS, 1); + Common::SeekableReadStream *zips = mhk->getRawData(ID_ZIPS, 1); uint16 zipsRecordCount = zips->readUint16BE(); for (uint16 i = 0; i < zipsRecordCount; i++) { ZipMode zip; @@ -189,10 +193,10 @@ bool RivenSaveLoad::loadGame(Common::String filename) { zip.id = zips->readUint16BE(); _vm->_zipModeData.push_back(zip); } + delete zips; + delete mhk; - delete _loadFile; - _loadFile = NULL; return true; } @@ -211,7 +215,14 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVARSSection() { for (uint32 i = 0; i < _vm->getVarCount(); i++) { stream->writeUint32BE(0); // Unknown stream->writeUint32BE(0); // Unknown - stream->writeUint32BE(_vm->getGlobalVar(i)); + + // Remap returnstackid here because we don't actually want to change + // our internal returnstackid. + uint32 variable = _vm->getGlobalVar(i); + if (_vm->getGlobalVarName(i) == "returnstackid") + variable = mapNewStackIDToOld(variable); + + stream->writeUint32BE(variable); } return stream; @@ -257,17 +268,17 @@ bool RivenSaveLoad::saveGame(Common::String filename) { // Note, this code is still WIP. It works quite well for now. // Make sure we have the right extension - if (!filename.hasSuffix(".rvn") && !filename.hasSuffix(".RVN")) + if (!filename.matchString("*.rvn", true)) filename += ".rvn"; // Convert class variables to variable numbers *_vm->matchVarToString("currentstackid") = mapNewStackIDToOld(_vm->getCurStack()); *_vm->matchVarToString("currentcardid") = _vm->getCurCard(); - *_vm->matchVarToString("returnstackid") = mapNewStackIDToOld(*_vm->matchVarToString("returnstackid")); - Common::OutSaveFile *saveFile; - if (!(saveFile = _saveFileMan->openForSaving(filename.c_str()))) + Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename); + if (!saveFile) return false; + debug (0, "Saving game to \'%s\'", filename.c_str()); Common::MemoryWriteStreamDynamic *versSection = genVERSSection(); @@ -392,7 +403,7 @@ bool RivenSaveLoad::saveGame(Common::String filename) { void RivenSaveLoad::deleteSave(Common::String saveName) { debug (0, "Deleting save file \'%s\'", saveName.c_str()); - _saveFileMan->removeSavefile(saveName.c_str()); + _saveFileMan->removeSavefile(saveName); } } // End of namespace Mohawk diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h index c708f9d35d..9cc9bc3737 100644 --- a/engines/mohawk/riven_saveload.h +++ b/engines/mohawk/riven_saveload.h @@ -29,8 +29,6 @@ #include "common/savefile.h" #include "common/str.h" -#include "mohawk/resource.h" - namespace Mohawk { class MohawkEngine_Riven; @@ -53,7 +51,6 @@ public: private: MohawkEngine_Riven *_vm; Common::SaveFileManager *_saveFileMan; - MohawkArchive *_loadFile; Common::MemoryWriteStreamDynamic *genVERSSection(); Common::MemoryWriteStreamDynamic *genNAMESection(); diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index e809ad9642..1fcaba8ac0 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -28,40 +28,28 @@ #include "mohawk/riven_external.h" #include "mohawk/riven_scripts.h" #include "mohawk/sound.h" -#include "mohawk/video/video.h" +#include "mohawk/video.h" #include "common/stream.h" #include "graphics/cursorman.h" namespace Mohawk { -RivenScript::RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType) - : _vm(vm), _stream(stream), _scriptType(scriptType) { +RivenScript::RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType, uint16 parentStack, uint16 parentCard) + : _vm(vm), _stream(stream), _scriptType(scriptType), _parentStack(parentStack), _parentCard(parentCard) { setupOpcodes(); + _isRunning = false; } RivenScript::~RivenScript() { delete _stream; } -RivenScriptList RivenScript::readScripts(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream) { - RivenScriptList scriptList; - - uint16 scriptCount = stream->readUint16BE(); - for (uint16 i = 0; i < scriptCount; i++) { - uint16 scriptType = stream->readUint16BE(); - uint32 scriptSize = calculateScriptSize(stream); - scriptList.push_back(Common::SharedPtr<RivenScript>(new RivenScript(vm, stream->readStream(scriptSize), scriptType))); - } - - return scriptList; -} - uint32 RivenScript::calculateCommandSize(Common::SeekableReadStream* script) { uint16 command = script->readUint16BE(); uint32 commandSize = 2; if (command == 8) { - if (script->readUint16BE() != 2) + if (script->readUint16BE() != 2) // Arg count? warning ("if-then-else unknown value is not 2"); script->readUint16BE(); // variable to check against uint16 logicBlockCount = script->readUint16BE(); // number of logic blocks @@ -161,7 +149,7 @@ void RivenScript::setupOpcodes() { OPCODE(activateFLST), OPCODE(zipMode), OPCODE(activateMLST), - OPCODE(activateSLSTWithVolume) + OPCODE(empty) // Activate an SLST with a volume parameter (not used) }; _opcodes = riven_opcodes; @@ -239,10 +227,13 @@ void RivenScript::dumpCommands(Common::StringArray varNames, Common::StringArray } void RivenScript::runScript() { + _isRunning = true; + if (_stream->pos() != 0) _stream->seek(0); processCommands(true); + _isRunning = false; } void RivenScript::processCommands(bool runCommands) { @@ -298,13 +289,10 @@ void RivenScript::processCommands(bool runCommands) { // Command 1: draw tBMP resource (tbmp_id, left, top, right, bottom, u0, u1, u2, u3) void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) { - if (argc < 5) { - // Copy the image to the whole screen, ignoring the rest of the parameters + if (argc < 5) // Copy the image to the whole screen, ignoring the rest of the parameters _vm->_gfx->copyImageToScreen(argv[0], 0, 0, 608, 392); - } else { - // Copy the image to a certain part of the screen + else // Copy the image to a certain part of the screen _vm->_gfx->copyImageToScreen(argv[0], argv[1], argv[2], argv[3], argv[4]); - } // Now, update the screen _vm->_gfx->updateScreen(); @@ -313,6 +301,12 @@ void RivenScript::drawBitmap(uint16 op, uint16 argc, uint16 *argv) { // Command 2: go to card (card id) void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) { _vm->changeToCard(argv[0]); + + // WORKAROUND: If we changed card on a mouse down event, + // we want to ignore the next mouse up event so we don't + // change card when lifting the mouse on the next card. + if (_scriptType == kMouseDownScript) + _vm->ignoreNextMouseUp(); } // Command 3: play an SLST from the script @@ -547,9 +541,8 @@ void RivenScript::activateSLST(uint16 op, uint16 argc, uint16 *argv) { // Command 41: activate MLST record and play void RivenScript::activateMLSTAndPlay(uint16 op, uint16 argc, uint16 *argv) { - _vm->_video->enableMovie(argv[0] - 1); _vm->_video->activateMLST(argv[0], _vm->getCurCard()); - // TODO: Play movie (blocking?) + _vm->_video->playMovie(argv[0]); } // Command 43: activate BLST record (card hotspot enabling lists) @@ -608,9 +601,46 @@ void RivenScript::activateMLST(uint16 op, uint16 argc, uint16 *argv) { _vm->_video->activateMLST(argv[0], _vm->getCurCard()); } -// Command 47: activate SLST record with a volume argument -void RivenScript::activateSLSTWithVolume(uint16 op, uint16 argc, uint16 *argv) { - warning("STUB: activateSLSTWithVolume()"); +RivenScriptManager::RivenScriptManager(MohawkEngine_Riven *vm) { + _vm = vm; +} + +RivenScriptManager::~RivenScriptManager() { + for (uint32 i = 0; i < _currentScripts.size(); i++) + delete _currentScripts[i]; +} + +RivenScriptList RivenScriptManager::readScripts(Common::SeekableReadStream *stream, bool garbageCollect) { + if (garbageCollect) + unloadUnusedScripts(); // Garbage collect! + + RivenScriptList scriptList; + + uint16 scriptCount = stream->readUint16BE(); + for (uint16 i = 0; i < scriptCount; i++) { + uint16 scriptType = stream->readUint16BE(); + uint32 scriptSize = RivenScript::calculateScriptSize(stream); + RivenScript *script = new RivenScript(_vm, stream->readStream(scriptSize), scriptType, _vm->getCurStack(), _vm->getCurCard()); + scriptList.push_back(script); + + // Only add it to the scripts that we will free later if it is requested. + // (ie. we don't want to store scripts from the dumpScript console command) + if (garbageCollect) + _currentScripts.push_back(script); + } + + return scriptList; +} + +void RivenScriptManager::unloadUnusedScripts() { + // Free any scripts that aren't part of the current card and aren't running + for (uint32 i = 0; i < _currentScripts.size(); i++) { + if ((_vm->getCurStack() != _currentScripts[i]->getParentStack() || _vm->getCurCard() != _currentScripts[i]->getParentCard()) && !_currentScripts[i]->isRunning()) { + delete _currentScripts[i]; + _currentScripts.remove_at(i); + i--; + } + } } } // End of namespace Mohawk diff --git a/engines/mohawk/riven_scripts.h b/engines/mohawk/riven_scripts.h index a1512af697..5187bbde08 100644 --- a/engines/mohawk/riven_scripts.h +++ b/engines/mohawk/riven_scripts.h @@ -50,19 +50,20 @@ enum { }; class RivenScript; -typedef Common::Array<Common::SharedPtr<RivenScript> > RivenScriptList; class RivenScript { public: - RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType); + RivenScript(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream, uint16 scriptType, uint16 parentStack, uint16 parentCard); ~RivenScript(); void runScript(); void dumpScript(Common::StringArray varNames, Common::StringArray xNames, byte tabs); uint16 getScriptType() { return _scriptType; } + uint16 getParentStack() { return _parentStack; } + uint16 getParentCard() { return _parentCard; } + bool isRunning() { return _isRunning; } - // Read in an array of script objects from a stream - static RivenScriptList readScripts(MohawkEngine_Riven *vm, Common::SeekableReadStream *stream); + static uint32 calculateScriptSize(Common::SeekableReadStream *script); private: typedef void (RivenScript::*OpcodeProcRiven)(uint16 op, uint16 argc, uint16 *argv); @@ -70,18 +71,18 @@ private: OpcodeProcRiven proc; const char *desc; }; - const RivenOpcode* _opcodes; + const RivenOpcode *_opcodes; void setupOpcodes(); MohawkEngine_Riven *_vm; Common::SeekableReadStream *_stream; - uint16 _scriptType; + uint16 _scriptType, _parentStack, _parentCard, _parentHotspot; + bool _isRunning; void dumpCommands(Common::StringArray varNames, Common::StringArray xNames, byte tabs); void processCommands(bool runCommands); - static uint32 calculateCommandSize(Common::SeekableReadStream* script); - static uint32 calculateScriptSize(Common::SeekableReadStream* script); + static uint32 calculateCommandSize(Common::SeekableReadStream *script); DECLARE_OPCODE(empty) { warning ("Unknown Opcode %04x", op); } @@ -120,7 +121,21 @@ private: DECLARE_OPCODE(activateFLST); DECLARE_OPCODE(zipMode); DECLARE_OPCODE(activateMLST); - DECLARE_OPCODE(activateSLSTWithVolume); +}; + +typedef Common::Array<RivenScript*> RivenScriptList; + +class RivenScriptManager { +public: + RivenScriptManager(MohawkEngine_Riven *vm); + ~RivenScriptManager(); + + RivenScriptList readScripts(Common::SeekableReadStream *stream, bool garbageCollect = true); + +private: + void unloadUnusedScripts(); + RivenScriptList _currentScripts; + MohawkEngine_Riven *_vm; }; } // End of namespace Mohawk diff --git a/engines/mohawk/riven_vars.cpp b/engines/mohawk/riven_vars.cpp index 3f7cd5a8b6..b6d2dff315 100644 --- a/engines/mohawk/riven_vars.cpp +++ b/engines/mohawk/riven_vars.cpp @@ -319,6 +319,8 @@ void MohawkEngine_Riven::initVars() { *matchVarToString("bheat") = 1; *matchVarToString("waterenabled") = 1; *matchVarToString("ogehnpage") = 1; + *matchVarToString("bblrsw") = 1; + *matchVarToString("ocage") = 1; // Randomize the telescope combination uint32 *teleCombo = matchVarToString("tcorrectorder"); diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index b84573f011..091bd68021 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -27,12 +27,12 @@ #include "common/util.h" +#include "sound/musicplugin.h" #include "sound/audiostream.h" #include "sound/decoders/mp3.h" #include "sound/decoders/raw.h" #include "sound/decoders/wave.h" - namespace Mohawk { Sound::Sound(MohawkEngine* vm) : _vm(vm) { @@ -79,7 +79,7 @@ void Sound::initMidi() { // Let's get our MIDI parser/driver _midiParser = MidiParser::createParser_SMF(); - _midiDriver = MidiDriver::createMidi(MidiDriver::detectMusicDriver(MDT_ADLIB|MDT_MIDI)); + _midiDriver = MidiDriver::createMidi(MidiDriver::detectDevice(MDT_ADLIB|MDT_MIDI)); // Set up everything! _midiDriver->open(); @@ -233,6 +233,10 @@ void Sound::playSLST(uint16 index, uint16 card) { if (slstRecord.index == index) { playSLST(slstRecord); + delete[] slstRecord.sound_ids; + delete[] slstRecord.volumes; + delete[] slstRecord.balances; + delete[] slstRecord.u2; delete slstStream; return; } @@ -244,6 +248,7 @@ void Sound::playSLST(uint16 index, uint16 card) { } delete slstStream; + // No matching records, assume we need to stop all SLST's stopAllSLST(); } @@ -277,8 +282,11 @@ void Sound::playSLST(SLSTRecord slstRecord) { } void Sound::stopAllSLST() { - for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) + for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) { _vm->_mixer->stopHandle(*_currentSLSTSounds[i].handle); + delete _currentSLSTSounds[i].handle; + } + _currentSLSTSounds.clear(); } @@ -314,6 +322,7 @@ void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16 void Sound::stopSLSTSound(uint16 index, bool fade) { // TODO: Fade out, mixer needs to be extended to get volume on a handle _vm->_mixer->stopHandle(*_currentSLSTSounds[index].handle); + delete _currentSLSTSounds[index].handle; _currentSLSTSounds.remove_at(index); } diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp new file mode 100644 index 0000000000..17456b8ec3 --- /dev/null +++ b/engines/mohawk/video.cpp @@ -0,0 +1,415 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "mohawk/resource.h" +#include "mohawk/video.h" + +#include "common/events.h" +#include "graphics/video/qt_decoder.h" + +namespace Mohawk { + +VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { +} + +VideoManager::~VideoManager() { + stopVideos(); +} + +void VideoManager::pauseVideos() { + for (uint16 i = 0; i < _videoStreams.size(); i++) + if (_videoStreams[i].video) + _videoStreams[i]->pauseVideo(true); +} + +void VideoManager::resumeVideos() { + for (uint16 i = 0; i < _videoStreams.size(); i++) + if (_videoStreams[i].video) + _videoStreams[i]->pauseVideo(false); +} + +void VideoManager::stopVideos() { + for (uint16 i = 0; i < _videoStreams.size(); i++) + delete _videoStreams[i].video; + _videoStreams.clear(); +} + +void VideoManager::playMovie(Common::String filename, uint16 x, uint16 y, bool clearScreen) { + VideoHandle videoHandle = createVideoHandle(filename, x, y, false); + if (videoHandle == NULL_VID_HANDLE) + return; + + // Clear screen if requested + if (clearScreen) { + _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0)); + _vm->_system->updateScreen(); + } + + waitUntilMovieEnds(videoHandle); +} + +void VideoManager::playMovieCentered(Common::String filename, bool clearScreen) { + VideoHandle videoHandle = createVideoHandle(filename, 0, 0, false); + if (videoHandle == NULL_VID_HANDLE) + return; + + // Clear screen if requested + if (clearScreen) { + _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0)); + _vm->_system->updateScreen(); + } + + _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2; + _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2; + + waitUntilMovieEnds(videoHandle); +} + +void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) { + bool continuePlaying = true; + + while (_videoStreams[videoHandle].video && !_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) { + if (updateBackgroundMovies()) + _vm->_system->updateScreen(); + + Common::Event event; + while (_vm->_system->getEventManager()->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_RTL: + case Common::EVENT_QUIT: + continuePlaying = false; + break; + case Common::EVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_SPACE: + _vm->pauseGame(); + break; + case Common::KEYCODE_ESCAPE: + continuePlaying = false; + break; + default: + break; + } + default: + break; + } + } + + // Cut down on CPU usage + _vm->_system->delayMillis(10); + } + + delete _videoStreams[videoHandle].video; + _videoStreams[videoHandle].video = 0; + _videoStreams[videoHandle].id = 0; + _videoStreams[videoHandle].filename.clear(); +} + +void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) { + VideoHandle videoHandle = createVideoHandle(filename, x, y, loop); + if (videoHandle == NULL_VID_HANDLE) + return; + + // Center x if requested + if (x < 0) + _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2; + + // Center y if requested + if (y < 0) + _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2; +} + +bool VideoManager::updateBackgroundMovies() { + bool updateScreen = false; + + for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) { + // Skip deleted videos + if (!_videoStreams[i].video) + continue; + + // Remove any videos that are over + if (_videoStreams[i]->endOfVideo()) { + if (_videoStreams[i].loop) { + _videoStreams[i]->rewind(); + } else { + delete _videoStreams[i].video; + _videoStreams[i].video = 0; + _videoStreams[i].id = 0; + _videoStreams[i].filename.clear(); + continue; + } + } + + // Check if we need to draw a frame + if (_videoStreams[i]->needsUpdate()) { + Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame(); + bool deleteFrame = false; + + if (frame && _videoStreams[i].enabled) { + // Convert from 8bpp to the current screen format if necessary + if (frame->bytesPerPixel == 1) { + Graphics::Surface *newFrame = new Graphics::Surface(); + Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat(); + byte *palette = _videoStreams[i]->getPalette(); + assert(palette); + + newFrame->create(frame->w, frame->h, pixelFormat.bytesPerPixel); + + for (uint16 j = 0; j < frame->h; j++) { + for (uint16 k = 0; k < frame->w; k++) { + byte palIndex = *((byte *)frame->getBasePtr(k, j)); + byte r = palette[palIndex * 3]; + byte g = palette[palIndex * 3 + 1]; + byte b = palette[palIndex * 3 + 2]; + if (pixelFormat.bytesPerPixel == 2) + *((uint16 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); + else + *((uint32 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b); + } + } + + frame = newFrame; + deleteFrame = true; + } + + // Clip the width/height to make sure we stay on the screen (Myst does this a few times) + uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x); + uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y); + _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height); + + // We've drawn something to the screen, make sure we update it + updateScreen = true; + + // Delete the frame if we're using the buffer from the 8bpp conversion + if (deleteFrame) { + frame->free(); + delete frame; + } + } + } + + // Update the audio buffer too + _videoStreams[i]->updateAudioBuffer(); + } + + // Return true if we need to update the screen + return updateScreen; +} + +void VideoManager::activateMLST(uint16 mlstId, uint16 card) { + Common::SeekableReadStream *mlstStream = _vm->getRawData(ID_MLST, card); + uint16 recordCount = mlstStream->readUint16BE(); + + for (uint16 i = 0; i < recordCount; i++) { + MLSTRecord mlstRecord; + mlstRecord.index = mlstStream->readUint16BE(); + mlstRecord.movieID = mlstStream->readUint16BE(); + mlstRecord.code = mlstStream->readUint16BE(); + mlstRecord.left = mlstStream->readUint16BE(); + mlstRecord.top = mlstStream->readUint16BE(); + + for (byte j = 0; j < 2; j++) + if (mlstStream->readUint16BE() != 0) + warning("u0[%d] in MLST non-zero", j); + + if (mlstStream->readUint16BE() != 0xFFFF) + warning("u0[2] in MLST not 0xFFFF"); + + mlstRecord.loop = mlstStream->readUint16BE(); + mlstRecord.volume = mlstStream->readUint16BE(); + mlstRecord.u1 = mlstStream->readUint16BE(); + + if (mlstRecord.u1 != 1) + warning("mlstRecord.u1 not 1"); + + // We've found a match, add it + if (mlstRecord.index == mlstId) { + // Make sure we don't have any duplicates + for (uint32 j = 0; j < _mlstRecords.size(); j++) + if (_mlstRecords[j].index == mlstRecord.index || _mlstRecords[j].code == mlstRecord.code) { + _mlstRecords.remove_at(j); + j--; + } + + _mlstRecords.push_back(mlstRecord); + break; + } + } + + delete mlstStream; +} + +void VideoManager::clearMLST() { + _mlstRecords.clear(); +} + +void VideoManager::playMovie(uint16 id) { + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) { + debug(1, "Play tMOV %d (non-blocking) at (%d, %d) %s", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0 ? "looping" : "non-looping"); + createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0); + return; + } +} + +void VideoManager::playMovieBlocking(uint16 id) { + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) { + debug(1, "Play tMOV %d (blocking) at (%d, %d)", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top); + VideoHandle videoHandle = createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, false); + waitUntilMovieEnds(videoHandle); + return; + } +} + +void VideoManager::stopMovie(uint16 id) { + debug(2, "Stopping movie %d", id); + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) + for (uint16 j = 0; j < _videoStreams.size(); j++) + if (_mlstRecords[i].movieID == _videoStreams[j].id) { + delete _videoStreams[j].video; + _videoStreams[j].video = 0; + _videoStreams[j].id = 0; + _videoStreams[j].filename.clear(); + return; + } +} + +void VideoManager::enableMovie(uint16 id) { + debug(2, "Enabling movie %d", id); + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) + for (uint16 j = 0; j < _videoStreams.size(); j++) + if (_mlstRecords[i].movieID == _videoStreams[j].id) { + _videoStreams[j].enabled = true; + return; + } +} + +void VideoManager::disableMovie(uint16 id) { + debug(2, "Disabling movie %d", id); + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) + for (uint16 j = 0; j < _videoStreams.size(); j++) + if (_mlstRecords[i].movieID == _videoStreams[j].id) { + _videoStreams[j].enabled = false; + return; + } +} + +void VideoManager::disableAllMovies() { + debug(2, "Disabling all movies"); + for (uint16 i = 0; i < _videoStreams.size(); i++) + _videoStreams[i].enabled = false; +} + +VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop) { + // First, check to see if that video is already playing + for (uint32 i = 0; i < _videoStreams.size(); i++) + if (_videoStreams[i].id == id) + return i; + + // Otherwise, create a new entry + VideoEntry entry; + entry.video = new Graphics::QuickTimeDecoder(); + entry.x = x; + entry.y = y; + entry.filename = ""; + entry.id = id; + entry.loop = loop; + entry.enabled = true; + entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id)); + entry->load(_vm->getRawData(ID_TMOV, id)); + + // Search for any deleted videos so we can take a formerly used slot + for (uint32 i = 0; i < _videoStreams.size(); i++) + if (!_videoStreams[i].video) { + _videoStreams[i] = entry; + return i; + } + + // Otherwise, just add it to the list + _videoStreams.push_back(entry); + return _videoStreams.size() - 1; +} + +VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop) { + // First, check to see if that video is already playing + for (uint32 i = 0; i < _videoStreams.size(); i++) + if (_videoStreams[i].filename == filename) + return i; + + // Otherwise, create a new entry + VideoEntry entry; + entry.video = new Graphics::QuickTimeDecoder(); + entry.x = x; + entry.y = y; + entry.filename = filename; + entry.id = 0; + entry.loop = loop; + entry.enabled = true; + + Common::File *file = new Common::File(); + if (!file->open(filename)) { + delete file; + return NULL_VID_HANDLE; + } + + entry->load(file); + + // Search for any deleted videos so we can take a formerly used slot + for (uint32 i = 0; i < _videoStreams.size(); i++) + if (!_videoStreams[i].video) { + _videoStreams[i] = entry; + return i; + } + + // Otherwise, just add it to the list + _videoStreams.push_back(entry); + return _videoStreams.size() - 1; +} + +VideoHandle VideoManager::findVideoHandle(uint16 id) { + for (uint16 i = 0; i < _mlstRecords.size(); i++) + if (_mlstRecords[i].code == id) + for (uint16 j = 0; j < _videoStreams.size(); j++) + if (_videoStreams[j].video && _mlstRecords[i].movieID == _videoStreams[j].id) + return j; + + return NULL_VID_HANDLE; +} + +int32 VideoManager::getCurFrame(const VideoHandle &handle) { + assert(handle != NULL_VID_HANDLE); + return _videoStreams[handle]->getCurFrame(); +} + +uint32 VideoManager::getFrameCount(const VideoHandle &handle) { + assert(handle != NULL_VID_HANDLE); + return _videoStreams[handle]->getFrameCount(); +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h new file mode 100644 index 0000000000..6aa553e26b --- /dev/null +++ b/engines/mohawk/video.h @@ -0,0 +1,114 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef MOHAWK_VIDEO_H +#define MOHAWK_VIDEO_H + +#include "graphics/pixelformat.h" + +namespace Graphics { + class QuickTimeDecoder; +} + +namespace Mohawk { + +class MohawkEngine; + +struct MLSTRecord { + uint16 index; + uint16 movieID; + uint16 code; + uint16 left; + uint16 top; + uint16 u0[3]; + uint16 loop; + uint16 volume; + uint16 u1; +}; + +struct VideoEntry { + Graphics::QuickTimeDecoder *video; + uint16 x; + uint16 y; + bool loop; + Common::String filename; + uint16 id; // Riven only + bool enabled; + + Graphics::QuickTimeDecoder *operator->() const { assert(video); return video; } +}; + +typedef int32 VideoHandle; + +enum { + NULL_VID_HANDLE = -1 +}; + +class VideoManager { +public: + VideoManager(MohawkEngine *vm); + ~VideoManager(); + + // Generic movie functions + void playMovie(Common::String filename, uint16 x = 0, uint16 y = 0, bool clearScreen = false); + void playMovieCentered(Common::String filename, bool clearScreen = true); + void playBackgroundMovie(Common::String filename, int16 x = -1, int16 y = -1, bool loop = false); + bool updateBackgroundMovies(); + void pauseVideos(); + void resumeVideos(); + void stopVideos(); + + // Riven-related functions + void activateMLST(uint16 mlstId, uint16 card); + void clearMLST(); + void enableMovie(uint16 id); + void disableMovie(uint16 id); + void disableAllMovies(); + void playMovie(uint16 id); + void stopMovie(uint16 id); + void playMovieBlocking(uint16 id); + + // Handle functions + VideoHandle findVideoHandle(uint16 id); + int32 getCurFrame(const VideoHandle &handle); + uint32 getFrameCount(const VideoHandle &handle); + +private: + MohawkEngine *_vm; + + // Riven-related variables + Common::Array<MLSTRecord> _mlstRecords; + + // Keep tabs on any videos playing + Common::Array<VideoEntry> _videoStreams; + + VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop); + VideoHandle createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop); + void waitUntilMovieEnds(VideoHandle videoHandle); +}; + +} // End of namespace Mohawk + +#endif |