diff options
-rw-r--r-- | devtools/scumm-md5.txt | 8 | ||||
-rw-r--r-- | engines/scumm/cdda.cpp | 120 | ||||
-rw-r--r-- | engines/scumm/cdda.h | 58 | ||||
-rw-r--r-- | engines/scumm/detection.cpp | 29 | ||||
-rw-r--r-- | engines/scumm/detection.h | 2 | ||||
-rw-r--r-- | engines/scumm/detection_tables.h | 20 | ||||
-rw-r--r-- | engines/scumm/file.cpp | 39 | ||||
-rw-r--r-- | engines/scumm/file.h | 28 | ||||
-rw-r--r-- | engines/scumm/module.mk | 1 | ||||
-rw-r--r-- | engines/scumm/saveload.cpp | 2 | ||||
-rw-r--r-- | engines/scumm/scumm-md5.h | 10 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 47 | ||||
-rw-r--r-- | engines/scumm/sound.cpp | 66 | ||||
-rw-r--r-- | engines/scumm/sound.h | 7 |
14 files changed, 414 insertions, 23 deletions
diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt index e458689367..f0cb577237 100644 --- a/devtools/scumm-md5.txt +++ b/devtools/scumm-md5.txt @@ -137,6 +137,8 @@ indy3 Indiana Jones and the Last Crusade 1dd7aa088e09f96d06818aa9a9deabe0 5361 en Mac No AdLib EGA v1.7, 8/17/90 Fingolfin 1875b90fade138c9253a8e967007031a 6295 en DOS VGA VGA IBM 256 color v2.0 from 3 May 90 Peter Eckerlein, Fingolfin + 7fbcff27c323499beaedd605e1ebd47d 561152 en Windows Steam Steam Steam Version Ben Castricum, Filippos Karapetis + a15d6e1e2c52bbd0ff7fa6b63ab7f796 680340 en Mac Steam Steam Steam Version Filippos Karapetis 399b217b0c8d65d0398076da486363a9 6295 de DOS VGA VGA VGA v1.02 from 7 Nov 91 Peter Eckerlein, Fingolfin 17b5d5e6af4ae89d62631641d66d5a05 -1 it DOS VGA VGA IBM 256 color v2.1 from 3 May 01 Andrea Petrucci, Peter Eckerlein 3cce1913a3bc586b51a75c3892ff18dd -1 ru DOS VGA VGA VGA @@ -170,6 +172,8 @@ loom Loom 6f0be328c64d689bb606d22a389e1b0f 5748 en Mac No AdLib EGA v1.2 25 Jan 91 Fingolfin 5d88b9d6a88e6f8e90cded9d01b7f082 8307 en DOS VGA VGA CD Version v1.0 from 10. Feb 92 (Talkie) Peter Eckerlein, Fingolfin + 0354ee0d14cde1264ec762261c04c14a 585728 en Windows Steam Steam Steam Version Ben Castricum, Filippos Karapetis + b4a677bf27c010a747975705108ff1e6 393572 en Mac Steam Steam Steam Version Filippos Karapetis c5d10e190d4b4d59114b824f2fdbd00e 7540 en FM-TOWNS FM-TOWNS - - dhewg, Andrea Petrucci 31b8fda4c8c7413fa6b39997e776eba4 -1 jp FM-TOWNS FM-TOWNS - - khalek, Andrea Petrucci @@ -279,6 +283,8 @@ atlantis Indiana Jones and the Fate of Atlantis d6dd0646404768a63e963891a96daadd 12035 en Mac Floppy Floppy two data files Fingolfin 182344899c2e2998fca0bebcd82aa81a 12035 en DOS - CD - Fingolfin + f3c5d9bf3f091bd1f18dc1013fba5396 638976 en Windows Steam Steam Steam Version Ben Castricum, Filippos Karapetis + 6a8133b63d46f6663fbcbb49d5a2edb1 520548 en Mac Steam Steam Steam Version Filippos Karapetis 1a6e5ae2777a6a33f06ffc0226210934 -1 en Mac - CD - Scott Summers 2d9d46f23cb07bbc90b8ad464d3e4ff8 -1 en Mac - CD Mac bundle Joachim Eberhard 8e9417564f33790815445b2136efa667 11915 jp Mac - CD - Petr Maruska @@ -358,6 +364,8 @@ ft Full Throttle dig The Dig d8323015ecb8b10bf53474f6e6b0ae33 16304 All All - - - Fingolfin + aad201302286c1cfee92321cd406e427 811008 en Windows Steam Steam Steam Version Ben Castricum, Filippos Karapetis + d93cc8be628ed5d3b3a29188fc7105d3 1061296 en Mac Steam Steam Steam Version Filippos Karapetis d62047a6729349ab36f7ee065bf26509 -1 ru All - - - sev 35a2d3040fa512f8232d9e443319d84d 659335495 en Mac - - Mac bundle Fingolfin 21a6592322f92550f144f68a8a4e685e -1 fr Mac - - Mac bundle kaminari diff --git a/engines/scumm/cdda.cpp b/engines/scumm/cdda.cpp new file mode 100644 index 0000000000..adb414ecce --- /dev/null +++ b/engines/scumm/cdda.cpp @@ -0,0 +1,120 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "scumm/cdda.h" +#include "common/stream.h" +#include "audio/audiostream.h" + +namespace Scumm { + + +#pragma mark - +#pragma mark --- CDDA stream --- +#pragma mark - + +#define START_OF_CDDA_DATA 800 +#define BLOCK_SIZE 1177 + +class CDDAStream : public Audio::SeekableAudioStream { +private: + Common::SeekableReadStream *_stream; + DisposeAfterUse::Flag _disposeAfterUse; + byte _shiftLeft; + byte _shiftRight; + uint32 _pos; + Audio::Timestamp _length; + +public: + CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse); + virtual ~CDDAStream(); + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + int getRate() const { return 44100; } + bool endOfData() const { return _stream->eos(); } + bool seek(const Audio::Timestamp &where); + Audio::Timestamp getLength() const { return _length; } +}; + +CDDAStream::CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) : + _stream(stream), _disposeAfterUse(disposeAfterUse), _pos(START_OF_CDDA_DATA) { + _stream->seek(START_OF_CDDA_DATA, SEEK_SET); + // The total size of CDDA.SOU is 289,808,802 bytes or (289808802 - 800) / 1177 = 246226 blocks + // We also deduct the shift values to return the correct length + uint32 blocks = (_stream->size() - START_OF_CDDA_DATA) / BLOCK_SIZE; + _length = Audio::Timestamp(0, (_stream->size() - START_OF_CDDA_DATA - blocks) / (isStereo() ? 2 : 1), getRate()); +} + +CDDAStream::~CDDAStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _stream; +} + +bool CDDAStream::seek(const Audio::Timestamp &where) { + const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); + uint32 blocks = seekSample / 1176; + + // Before seeking, read the shift values from the beginning of that block + _stream->seek(START_OF_CDDA_DATA + blocks * BLOCK_SIZE, SEEK_SET); + byte shiftVal = _stream->readByte(); + _shiftLeft = shiftVal >> 4; + _shiftRight = shiftVal & 0x0F; + + _pos = START_OF_CDDA_DATA + blocks + seekSample; + return _stream->seek(_pos, SEEK_SET); +} + +int CDDAStream::readBuffer(int16 *buffer, const int numSamples) { + int samples; + + for (samples = 0 ; samples < numSamples && !_stream->eos() ; ) { + if (!((_pos - START_OF_CDDA_DATA) % BLOCK_SIZE)) { + byte shiftVal = _stream->readByte(); + _shiftLeft = shiftVal >> 4; + _shiftRight = shiftVal & 0x0F; + _pos++; + } + buffer[samples++] = _stream->readSByte() << _shiftLeft; + buffer[samples++] = _stream->readSByte() << _shiftRight; + _pos += 2; + } + return samples; +} + +#pragma mark - +#pragma mark --- CDDA factory functions --- +#pragma mark - + +Audio::SeekableAudioStream *makeCDDAStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse) { + Audio::SeekableAudioStream *s = new CDDAStream(stream, disposeAfterUse); + if (s && s->endOfData()) { + delete s; + return 0; + } else { + return s; + } + return 0; +} + +} // End of namespace Scumm diff --git a/engines/scumm/cdda.h b/engines/scumm/cdda.h new file mode 100644 index 0000000000..2146777497 --- /dev/null +++ b/engines/scumm/cdda.h @@ -0,0 +1,58 @@ + +/* 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. + * + */ + +/** + * @file + * CD audio decoder used in the Steam versions of Loom + */ + +#ifndef SCUMM_CDDA_H +#define SCUMM_CDDA_H + +#include "common/types.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Audio { +class SeekableAudioStream; +} + +namespace Scumm { + +/** + * Create a new SeekableAudioStream from the CDDA data in the given stream. + * Allows for seeking (which is why we require a SeekableReadStream). + * + * @param stream the SeekableReadStream from which to read the CDDA data + * @param disposeAfterUse whether to delete the stream after use + * @return a new SeekableAudioStream, or NULL, if an error occurred + */ +Audio::SeekableAudioStream *makeCDDAStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse); + +} // End of namespace Audio + +#endif // #ifndef SCUMM_CDDA_H diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index b7a25808a5..55df5926fc 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -79,10 +79,12 @@ Common::String ScummEngine::generateFilename(const int room) const { } else { switch (_filenamePattern.genMethod) { case kGenDiskNum: + case kGenDiskNumSteam: result = Common::String::format(_filenamePattern.pattern, diskNumber); break; case kGenRoomNum: + case kGenRoomNumSteam: result = Common::String::format(_filenamePattern.pattern, room); break; @@ -209,14 +211,30 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { return result; } -static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod) { +static const char *getSteamExeNameFromPattern(Common::String pattern, Common::Platform platform) { + for (const SteamIndexFile *indexFile = steamIndexFiles; indexFile->len; ++indexFile) { + if (platform == indexFile->platform && pattern.equalsIgnoreCase(indexFile->pattern)) + return indexFile->executableName; + } + + error("Unable to find Steam executable from detection pattern"); + return ""; +} + +static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod, Common::Platform platform) { Common::String result; + Common::String patternStr = pattern; switch (genMethod) { case kGenDiskNum: case kGenRoomNum: result = Common::String::format(pattern, 0); break; + + case kGenDiskNumSteam: + case kGenRoomNumSteam: + result = getSteamExeNameFromPattern(pattern, platform); + break; case kGenHEPC: case kGenHEIOS: @@ -528,7 +546,8 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul DetectorResult dr; // Dive one level down since mac indy3/loom has its files split into directories. See Bug #1438631 - composeFileHashMap(fileMD5Map, fslist, 2, directoryGlobs); + // Dive two levels down for Mac Steam games + composeFileHashMap(fileMD5Map, fslist, 3, directoryGlobs); // Iterate over all filename patterns. for (const GameFilenamePattern *gfp = gameFilenamesTable; gfp->gameid; ++gfp) { @@ -540,7 +559,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul // Generate the detectname corresponding to the gfp. If the file doesn't // exist in the directory we are looking at, we can skip to the next // one immediately. - Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod)); + Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod, gfp->platform)); if (!fileMD5Map.contains(file)) continue; @@ -1025,7 +1044,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co Common::FSNode dir(ConfMan.get("path")); if (!dir.isDirectory()) return Common::kPathNotDirectory; - if (!dir.getChildren(fslist, Common::FSNode::kListFilesOnly)) + if (!dir.getChildren(fslist, Common::FSNode::kListAll)) return Common::kNoGameDataFoundError; // Invoke the detector, but fixed to the specified gameid. @@ -1081,7 +1100,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", res.game.gameid, - generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(), + generateFilenameForDetection(res.fp.pattern, res.fp.genMethod, Common::kPlatformUnknown).c_str(), res.md5.c_str()); g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str()); diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h index f714812a9c..0587c3fab1 100644 --- a/engines/scumm/detection.h +++ b/engines/scumm/detection.h @@ -95,7 +95,9 @@ struct GameSettings { enum FilenameGenMethod { kGenDiskNum, + kGenDiskNumSteam, kGenRoomNum, + kGenRoomNumSteam, kGenHEMac, kGenHEMacNoParens, kGenHEPC, diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index c876af1256..1dccbd32a3 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -52,6 +52,8 @@ namespace Scumm { */ static const char *const directoryGlobs[] = { "rooms *", // Mac version of indy3/loom + "Contents", // Mac Steam versions + "MacOS", // Mac Steam versions 0 }; @@ -221,6 +223,7 @@ static const GameSettings gameVariantsTable[] = { {"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, + {"indy3", "Steam", "steam", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "FM-TOWNS", 0, GID_INDY3, 3, 0, MDT_TOWNS, GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)}, {"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)}, @@ -230,6 +233,7 @@ static const GameSettings gameVariantsTable[] = { #endif {"loom", "FM-TOWNS", 0, GID_LOOM, 3, 0, MDT_TOWNS, GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)}, {"loom", "VGA", "vga", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, + {"loom", "Steam", "steam", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, @@ -245,6 +249,7 @@ static const GameSettings gameVariantsTable[] = { {"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)}, {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()}, + {"atlantis", "Steam", "steam", GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()}, {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)}, {"atlantis", "FM-TOWNS", 0, GID_INDY4, 5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO4(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)}, @@ -257,7 +262,8 @@ static const GameSettings gameVariantsTable[] = { #ifdef ENABLE_SCUMM_7_8 {"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, - {"dig", 0, 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, + {"dig", "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, + {"dig", "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, {"comi", 0, 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)}, #endif @@ -422,10 +428,10 @@ static const GameSettings gameVariantsTable[] = { using Common::UNK_LANG; // The following describes how Fingolfin thinks this table might be used one day; -// this is work in progress, so read this with a salt of grain... +// this is work in progress, so read this with a grain of salt... // // The following table maps gameids to possible filename variants for that game. -// This information is used by the detector to determin possible "detect files". +// This information is used by the detector to determine possible "detect files". // It is also later used by the engine creation code to verify the game to be // launched is present. Finally, the correct GameFilenamePattern entry is passed on // to the engine which uses it to locate the files for the game. @@ -451,6 +457,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "zak", "zak1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "V1" }, // ... and zak2.d64 { "indy3", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, + { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "indyloom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, { "indyzak", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, @@ -458,6 +466,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "loom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, { "loom", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, "VGA" }, // Loom CD + { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "pass", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, @@ -471,6 +481,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, + { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "atlantis", "fate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "playfate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "indy4.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" }, @@ -494,6 +506,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { #ifdef ENABLE_SCUMM_7_8 { "dig", "dig.la%d", kGenDiskNum, UNK_LANG, UNK, 0 }, + { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "dig", "thedig.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" }, // Used by an alternate version of the demo { "dig", "The Dig Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "dig", "The Dig Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" }, diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 9c161ff1cc..21b0e594bf 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -29,6 +29,22 @@ namespace Scumm { +// The following table includes all the index files, which are embedded in the +// main game executables in Steam versions. +const SteamIndexFile steamIndexFiles[] = { + { GID_INDY3, Common::kPlatformWindows, "%02d.LFL", "00.LFL", "Indiana Jones and the Last Crusade.exe", 162056, 6295 }, + { GID_INDY3, Common::kPlatformMacintosh, "%02d.LFL", "00.LFL", "The Last Crusade", 150368, 6295 }, + { GID_INDY4, Common::kPlatformWindows, "atlantis.%03d", "ATLANTIS.000", "Indiana Jones and the Fate of Atlantis.exe", 224336, 12035 }, + { GID_INDY4, Common::kPlatformMacintosh, "atlantis.%03d", "ATLANTIS.000", "The Fate of Atlantis", 260224, 12035 }, + { GID_LOOM, Common::kPlatformWindows, "%03d.LFL", "000.LFL", "Loom.exe", 187248, 8307 }, + { GID_LOOM, Common::kPlatformMacintosh, "%03d.LFL", "000.LFL", "Loom", 170464, 8307 }, +#ifdef ENABLE_SCUMM_7_8 + { GID_DIG, Common::kPlatformWindows, "dig.la%d", "DIG.LA0", "The Dig.exe", 340632, 16304 }, + { GID_DIG, Common::kPlatformMacintosh, "dig.la%d", "DIG.LA0", "The Dig", 339744, 16304 }, +#endif + { 0, Common::kPlatformUnknown, "", "", "", 0, 0 } +}; + #pragma mark - #pragma mark --- ScummFile --- #pragma mark - @@ -185,6 +201,29 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { } #pragma mark - +#pragma mark --- ScummSteamFile --- +#pragma mark - +bool ScummSteamFile::open(const Common::String &filename) { + for (const SteamIndexFile *indexFile = steamIndexFiles; indexFile->len; ++indexFile) { + if (indexFile->id == _steamGame.id && indexFile->platform == _steamGame.platform && filename.equalsIgnoreCase(indexFile->indexFileName)) + return openWithSubRange(indexFile->executableName, indexFile->start, indexFile->len); + } + + // Regular non-bundled file + return ScummFile::open(filename); +} + +bool ScummSteamFile::openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen) { + if (ScummFile::open(filename)) { + _subFileStart = subFileStart; + _subFileLen = subFileLen; + seek(0, SEEK_SET); + return true; + } else + return false; +} + +#pragma mark - #pragma mark --- ScummDiskImage --- #pragma mark - diff --git a/engines/scumm/file.h b/engines/scumm/file.h index d6dbc06ddc..f3eaac5d32 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -53,7 +53,7 @@ public: }; class ScummFile : public BaseScummFile { -private: +protected: int32 _subFileStart; int32 _subFileLen; bool _myEos; // Have we read past the end of the subfile? @@ -64,7 +64,7 @@ private: public: ScummFile(); - bool open(const Common::String &filename); + virtual bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); void clearErr() { _myEos = false; BaseScummFile::clearErr(); } @@ -76,6 +76,18 @@ public: uint32 read(void *dataPtr, uint32 dataSize); }; +class ScummSteamFile : public ScummFile { +private: + GameSettings _steamGame; + + bool openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen); + +public: + ScummSteamFile(GameSettings game) : ScummFile(), _steamGame(game) {} + + bool open(const Common::String &filename); +}; + class ScummDiskImage : public BaseScummFile { private: Common::SeekableReadStream *_stream; @@ -120,6 +132,18 @@ public: uint32 read(void *dataPtr, uint32 dataSize); }; +struct SteamIndexFile { + byte id; + Common::Platform platform; + const char *pattern; + const char *indexFileName; + const char *executableName; + int32 start; + int32 len; +}; + +extern const SteamIndexFile steamIndexFiles[]; + } // End of namespace Scumm #endif diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index d43db1e5f1..416a8f7ef9 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -7,6 +7,7 @@ MODULE_OBJS := \ bomp.o \ boxes.o \ camera.o \ + cdda.o \ charset.o \ charset-fontdata.o \ costume.o \ diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 0aaff4c094..7eadb042fb 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1453,7 +1453,7 @@ void ScummEngine::saveOrLoad(Serializer *s) { // forever, then resume playing it. This helps a lot when the audio CD // is used to provide ambient music (see bug #788195). if (s->isLoading() && info.playing && info.numLoops < 0) - _system->getAudioCDManager()->play(info.track, info.numLoops, info.start, info.duration); + _sound->playCDTrackInternal(info.track, info.numLoops, info.start, info.duration); } diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 8accf39129..0eeff57ff7 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Wed Jun 25 09:07:50 2014 + This file was generated by the md5table tool on Wed Jun 25 10:34:07 2014 DO NOT EDIT MANUALLY! */ @@ -17,6 +17,7 @@ static const MD5Table md5table[] = { { "008e76ec3ae58d0add637ea7aa299a2c", "freddi3", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "02cae0e7ff8504f73618391873d5781a", "freddi3", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "0305e850382b812fec6e5998ef88a966", "pajama", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, + { "0354ee0d14cde1264ec762261c04c14a", "loom", "Steam", "Steam", 585728, Common::EN_ANY, Common::kPlatformWindows }, { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformDOS }, { "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, @@ -299,6 +300,7 @@ static const MD5Table md5table[] = { { "69ffe29185b8d71f09f6199f8b2a87cb", "lost", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "6a30a07f353a75cdc602db27d73e1b42", "puttputt", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "6a60d395b78b205c93a956100b1bf5ae", "pajama2", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, + { "6a8133b63d46f6663fbcbb49d5a2edb1", "atlantis", "Steam", "Steam", 520548, Common::EN_ANY, Common::kPlatformMacintosh }, { "6af2419fe3db5c2fdb091ae4e5833770", "puttrace", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b19d0e25cbf720d05822379b8b90ed9", "PuttTime", "HE 90", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b257bb2827dd894b8109a50a1a18b5a", "freddicove", "HE 100", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -357,6 +359,7 @@ static const MD5Table md5table[] = { { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformDOS }, { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "7fbcff27c323499beaedd605e1ebd47d", "indy3", "Steam", "Steam", 561152, Common::EN_ANY, Common::kPlatformWindows }, { "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "822807c3cd3b43a925cab2767ca6b453", "BluesTreasureHunt", "", "Disc 1", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -439,6 +442,7 @@ static const MD5Table md5table[] = { { "a095616d2d23ccf43b8e257711202cba", "football2002", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "a095e33061606d231ff37dca4c64c8ac", "pajama", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "a0a7dea72003933b8b3f8b99b9f7ddeb", "loom", "No AdLib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, + { "a15d6e1e2c52bbd0ff7fa6b63ab7f796", "indy3", "Steam", "Steam", 680340, Common::EN_ANY, Common::kPlatformMacintosh }, { "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown }, { "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "a22af0ad0e3126d19d22707b0267a37d", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -467,6 +471,7 @@ static const MD5Table md5table[] = { { "aa8a0cb65f3afbbe2c14c3f9f92775a3", "monkey", "CD", "CD", 8955, Common::FR_FRA, Common::kPlatformDOS }, { "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No AdLib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, + { "aad201302286c1cfee92321cd406e427", "dig", "Steam", "Steam", 811008, Common::EN_ANY, Common::kPlatformWindows }, { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformDOS }, { "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -480,6 +485,7 @@ static const MD5Table md5table[] = { { "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformDOS }, { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS }, { "b47be81e39a9710f6f595f7b527b60f8", "puttrace", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, + { "b4a677bf27c010a747975705108ff1e6", "loom", "Steam", "Steam", 393572, Common::EN_ANY, Common::kPlatformMacintosh }, { "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformDOS }, { "b628506f7def772e40de0aa5440fb8e1", "activity", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -569,6 +575,7 @@ static const MD5Table md5table[] = { { "d7b247c26bf1f01f8f7daf142be84de3", "balloon", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown }, { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, + { "d93cc8be628ed5d3b3a29188fc7105d3", "dig", "Steam", "Steam", 1061296, Common::EN_ANY, Common::kPlatformMacintosh }, { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformDOS }, { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "FM-TOWNS", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, { "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformDOS }, @@ -629,6 +636,7 @@ static const MD5Table md5table[] = { { "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown }, { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformDOS }, { "f2ec78e50bdc63b70044e9758be10914", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformMacintosh }, + { "f3c5d9bf3f091bd1f18dc1013fba5396", "atlantis", "Steam", "Steam", 638976, Common::EN_ANY, Common::kPlatformWindows }, { "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows }, { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 34c231e5d4..8c0325934d 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -1026,6 +1026,35 @@ Common::Error ScummEngine::init() { } #endif + // Extra directories needed for the Steam versions + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) { + if (_game.platform == Common::kPlatformWindows) { + switch (_game.id) { + case GID_INDY3 : + SearchMan.addSubDirectoryMatching(gameDataDir, "indy3"); + break; + case GID_INDY4 : + SearchMan.addSubDirectoryMatching(gameDataDir, "atlantis"); + break; + case GID_LOOM : + SearchMan.addSubDirectoryMatching(gameDataDir, "loom"); + break; +#ifdef ENABLE_SCUMM_7_8 + case GID_DIG : + SearchMan.addSubDirectoryMatching(gameDataDir, "dig"); + SearchMan.addSubDirectoryMatching(gameDataDir, "dig/video"); + break; +#endif + default: + break; + } + } else { + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/MacOS"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources/video"); + } + } // The kGenUnchanged method is only used for 'container files', i.e. files // that contain the real game files bundled together in an archive format. @@ -1126,15 +1155,25 @@ Common::Error ScummEngine::init() { error("Couldn't find known subfile inside container file '%s'", _containerFile.c_str()); _fileHandle->close(); - } else { error("kGenUnchanged used with unsupported platform"); } } else { - // Regular access, no container file involved - _fileHandle = new ScummFile(); + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) { + // Steam game versions have the index file embedded in the main executable + _fileHandle = new ScummSteamFile(_game); + } else { + // Regular access, no container file involved + _fileHandle = new ScummFile(); + } } + // Steam Win and Mac versions share the same DOS data files. We show Windows or Mac + // for the platform the detector, but internally we force the platform to DOS, so that + // the code for handling the original DOS data files is used. + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) + _game.platform = Common::kPlatformDOS; + // Load CJK font, if present // Load it earlier so _useCJKMode variable could be set loadCJKFont(); @@ -1218,7 +1257,7 @@ Common::Error ScummEngine::init() { void ScummEngine::setupScumm() { // On some systems it's not safe to run CD audio games from the CD. - if (_game.features & GF_AUDIOTRACKS) { + if (_game.features & GF_AUDIOTRACKS && !Common::File::exists("CDDA.SOU")) { checkCD(); int cd_num = ConfMan.getInt("cdrom"); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 01bdefc7c0..21bf565a4e 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -27,6 +27,7 @@ #include "common/substream.h" #include "scumm/actor.h" +#include "scumm/cdda.h" #include "scumm/file.h" #include "scumm/imuse/imuse.h" #include "scumm/imuse_digi/dimuse.h" @@ -36,8 +37,6 @@ #include "scumm/sound.h" #include "scumm/util.h" -#include "backends/audiocd/audiocd.h" - #include "audio/decoders/adpcm.h" #include "audio/decoders/flac.h" #include "audio/mididrv.h" @@ -89,11 +88,21 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer) memset(_mouthSyncTimes, 0, sizeof(_mouthSyncTimes)); _musicType = MDT_NONE; + + _loomSteamCD.playing = false; + _loomSteamCD.track = 0; + _loomSteamCD.start = 0; + _loomSteamCD.duration = 0; + _loomSteamCD.numLoops = 0; + _loomSteamCD.volume = Audio::Mixer::kMaxChannelVolume; + _loomSteamCD.balance = 0; + + _isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU"); } Sound::~Sound() { stopCDTimer(); - g_system->getAudioCDManager()->stop(); + stopCD(); free(_offsetTable); } @@ -1033,7 +1042,7 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) { // Play it if (!_soundsPaused) - g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration); + playCDTrackInternal(track, numLoops, startFrame, duration); // Start the timer after starting the track. Starting an MP3 track is // almost instantaneous, but a CD player may take some time. Hopefully @@ -1041,16 +1050,59 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) { startCDTimer(); } +void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) { + _loomSteamCD.track = track; + _loomSteamCD.numLoops = numLoops; + _loomSteamCD.start = startFrame; + _loomSteamCD.duration = duration; + + if (!_isLoomSteam) { + g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration); + } else { + // Stop any currently playing track + _mixer->stopHandle(_loomSteamCDAudioHandle); + + Common::File *cddaFile = new Common::File(); + if (cddaFile->open("CDDA.SOU")) { + Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75); + Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75); + Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES); + + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle, + Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops)); + } else { + delete cddaFile; + } + } +} + void Sound::stopCD() { - g_system->getAudioCDManager()->stop(); + if (!_isLoomSteam) + g_system->getAudioCDManager()->stop(); + else + _mixer->stopHandle(_loomSteamCDAudioHandle); } int Sound::pollCD() const { - return g_system->getAudioCDManager()->isPlaying(); + if (!_isLoomSteam) + return g_system->getAudioCDManager()->isPlaying(); + else + return _mixer->isSoundHandleActive(_loomSteamCDAudioHandle); } void Sound::updateCD() { - g_system->getAudioCDManager()->updateCD(); + if (!_isLoomSteam) + g_system->getAudioCDManager()->updateCD(); +} + +AudioCDManager::Status Sound::getCDStatus() { + if (!_isLoomSteam) + return g_system->getAudioCDManager()->getStatus(); + else { + AudioCDManager::Status info = _loomSteamCD; + _loomSteamCD.playing = _mixer->isSoundHandleActive(_loomSteamCDAudioHandle); + return info; + } } void Sound::saveLoadWithSerializer(Serializer *ser) { diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h index a96d2b8ed5..a479ad5731 100644 --- a/engines/scumm/sound.h +++ b/engines/scumm/sound.h @@ -27,6 +27,7 @@ #include "audio/audiostream.h" #include "audio/mididrv.h" #include "audio/mixer.h" +#include "backends/audiocd/audiocd.h" #include "scumm/saveload.h" namespace Audio { @@ -86,6 +87,10 @@ protected: int16 _currentCDSound; int16 _currentMusic; + Audio::SoundHandle _loomSteamCDAudioHandle; + bool _isLoomSteam; + AudioCDManager::Status _loomSteamCD; + public: Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on @@ -119,9 +124,11 @@ public: void stopCDTimer(); void playCDTrack(int track, int numLoops, int startFrame, int duration); + void playCDTrackInternal(int track, int numLoops, int startFrame, int duration); void stopCD(); int pollCD() const; void updateCD(); + AudioCDManager::Status getCDStatus(); int getCurrentCDSound() const { return _currentCDSound; } // Used by the save/load system: |