aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm
diff options
context:
space:
mode:
authorJohannes Schickel2014-07-05 13:35:34 +0200
committerJohannes Schickel2014-07-05 13:35:34 +0200
commitb77412a9a07e58a21dd430e28cf34210d4648fd0 (patch)
treea0ca26a89ddcfb81e8da4e8361352e1e62e926e6 /engines/scumm
parent48564efc8812aef644144cb368d65a8d14a4397f (diff)
parent53d3ee07df6eea863e93620ab4a406eb24fbfef1 (diff)
downloadscummvm-rg350-b77412a9a07e58a21dd430e28cf34210d4648fd0.tar.gz
scummvm-rg350-b77412a9a07e58a21dd430e28cf34210d4648fd0.tar.bz2
scummvm-rg350-b77412a9a07e58a21dd430e28cf34210d4648fd0.zip
Merge pull request #470 from bluegr/Lucasarts_Steam
SCUMM: Add support for Steam versions of Indy 3, Indy 4, Loom and Dig
Diffstat (limited to 'engines/scumm')
-rw-r--r--engines/scumm/cdda.cpp120
-rw-r--r--engines/scumm/cdda.h58
-rw-r--r--engines/scumm/detection.cpp29
-rw-r--r--engines/scumm/detection.h2
-rw-r--r--engines/scumm/detection_tables.h20
-rw-r--r--engines/scumm/file.cpp39
-rw-r--r--engines/scumm/file.h28
-rw-r--r--engines/scumm/module.mk1
-rw-r--r--engines/scumm/saveload.cpp2
-rw-r--r--engines/scumm/scumm-md5.h10
-rw-r--r--engines/scumm/scumm.cpp47
-rw-r--r--engines/scumm/sound.cpp66
-rw-r--r--engines/scumm/sound.h7
13 files changed, 406 insertions, 23 deletions
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: