From 260a2019b6c57646ef32274c2fb197658f542803 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 17 Aug 2009 15:49:22 +0000 Subject: SCI: Add autodetection for DoSound. Cleanup. svn-id: r43482 --- engines/sci/engine/kernel.cpp | 87 ++++++++++++----------------------------- engines/sci/engine/kernel.h | 14 +------ engines/sci/engine/ksound.cpp | 23 ++++++----- engines/sci/engine/savegame.cpp | 3 +- engines/sci/engine/state.cpp | 75 +++++++++++++++++++++++++++++++++++ engines/sci/engine/state.h | 15 +++++++ engines/sci/resource.cpp | 2 +- engines/sci/resource.h | 3 +- engines/sci/sci.cpp | 3 +- 9 files changed, 136 insertions(+), 89 deletions(-) (limited to 'engines') diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 6d027d5788..e5a4377d2d 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -370,8 +370,8 @@ static const char *argtype_description[] = { Kernel::Kernel(ResourceManager *resmgr) : _resmgr(resmgr) { memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t - detectSciFeatures(); // must be called before loadSelectorNames() loadSelectorNames(); + detectSciFeatures(); mapSelectors(); // Map a few special selectors for later use loadOpcodes(); loadKernelNames(); @@ -382,61 +382,30 @@ Kernel::~Kernel() { } void Kernel::detectSciFeatures() { - // FIXME Much of this is unreliable + SciVersion version = _resmgr->sciVersion(); - Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0); - - Common::StringList staticSelectorTable; - - if (!r) { // No such resource? - staticSelectorTable = checkStaticSelectorNames(); - if (staticSelectorTable.empty()) - error("Kernel: Could not retrieve selector names"); - } - - int count = staticSelectorTable.empty() ? READ_LE_UINT16(r->data) + 1 : staticSelectorTable.size(); // Counter is slightly off features = 0; // Initialize features based on SCI version - switch (_resmgr->sciVersion()) { - case SCI_VERSION_0_EARLY: - features |= kFeatureOldScriptHeader; - /* Fallthrough */ - case SCI_VERSION_0_LATE: - features |= kFeatureOldGfxFunctions; - break; - default: - break; - } - for (int i = 0; i < count; i++) { - Common::String tmp; - - if (staticSelectorTable.empty()) { - int offset = READ_LE_UINT16(r->data + 2 + i * 2); - int len = READ_LE_UINT16(r->data + offset); - - tmp = Common::String((const char *)r->data + offset + 2, len); - } else { - tmp = staticSelectorTable[i]; - } - - if (tmp == "motionCue") - features &= ~kFeatureOldGfxFunctions; + // Script header and graphics functions + if (version == SCI_VERSION_0_EARLY) { + features |= kFeatureOldScriptHeader | kFeatureOldGfxFunctions; + } else if (version == SCI_VERSION_0_LATE) { + if (findSelector("motionCue") == -1) + features |= kFeatureOldGfxFunctions; + } - if (tmp == "egoMoveSpeed" && _resmgr->sciVersion() < SCI_VERSION_1_1) + // Lofs absolute/relative + if (version >= SCI_VERSION_1_MIDDLE && version < SCI_VERSION_1_1) { + // Assume all games use absolute lofs + features |= kFeatureLofsAbsolute; + } else if (version == SCI_VERSION_1_EARLY) { + // Use heuristic + if (findSelector("egoMoveSpeed") != -1) features |= kFeatureLofsAbsolute; - - if (tmp == "setVol") - features |= kFeatureSci1Sound; - - if (tmp == "nodePtr") - features |= kFeatureSci01Sound; } - if (features & kFeatureSci1Sound) - features &= ~kFeatureSci01Sound; - printf("Kernel auto-detected features:\n"); printf("Graphics functions: "); @@ -445,19 +414,13 @@ void Kernel::detectSciFeatures() { else printf("new\n"); - printf("lofs parameters: "); - if (features & kFeatureLofsAbsolute) - printf("absolute\n"); - else - printf("relative\n"); - - printf("Sound functions: "); - if (features & kFeatureSci1Sound) - printf("SCI1\n"); - else if (features & kFeatureSci01Sound) - printf("SCI01\n"); - else - printf("SCI0\n"); + if (version < SCI_VERSION_1_1) { + printf("lofs parameters: "); + if (features & kFeatureLofsAbsolute) + printf("absolute\n"); + else + printf("relative\n"); + } } void Kernel::loadSelectorNames() { @@ -473,7 +436,7 @@ void Kernel::loadSelectorNames() { for (uint32 i = 0; i < staticSelectorTable.size(); i++) { _selectorNames.push_back(staticSelectorTable[i]); - if (features & kFeatureOldScriptHeader) + if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY) _selectorNames.push_back(staticSelectorTable[i]); } @@ -492,7 +455,7 @@ void Kernel::loadSelectorNames() { // Early SCI versions used the LSB in the selector ID as a read/write // toggle. To compensate for that, we add every selector name twice. - if (features & kFeatureOldScriptHeader) + if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY) _selectorNames.push_back(tmp); } } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index bb5563a876..8be51549f6 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -60,9 +60,7 @@ struct KernelFuncWithSignature { enum AutoDetectedFeatures { kFeatureOldScriptHeader = 1 << 0, kFeatureOldGfxFunctions = 1 << 1, - kFeatureLofsAbsolute = 1 << 2, - kFeatureSci01Sound = 1 << 3, - kFeatureSci1Sound = 1 << 4 + kFeatureLofsAbsolute = 1 << 2 }; class Kernel { @@ -119,16 +117,6 @@ public: */ bool hasLofsAbsolute() const { return (features & kFeatureLofsAbsolute); } - /** - * Determines if the game is using SCI01 sound functions - */ - bool usesSci01SoundFunctions() const { return (features & kFeatureSci01Sound); } - - /** - * Determines if the game is using SCI1 sound functions - */ - bool usesSci1SoundFunctions() const { return (features & kFeatureSci1Sound); } - // Script dissection/dumping functions void dissectScript(int scriptNumber, Vocabulary *vocab); void dumpScriptObject(char *data, int seeker, int objsize); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 38baeafad8..44b2404e41 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -204,7 +204,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their } -reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t obj = (argc > 1) ? argv[1] : NULL_REG; uint16 command = argv[0].toUint16(); SongHandle handle = FROBNICATE_HANDLE(obj); @@ -383,7 +383,7 @@ reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) { } -reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint16 command = argv[0].toUint16(); reg_t obj = (argc > 1) ? argv[1] : NULL_REG; SongHandle handle = FROBNICATE_HANDLE(obj); @@ -673,7 +673,7 @@ reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } -reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { +reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) { uint16 command = argv[0].toUint16(); reg_t obj = (argc > 1) ? argv[1] : NULL_REG; SongHandle handle = FROBNICATE_HANDLE(obj); @@ -988,12 +988,17 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) { * Used for synthesized music playback */ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { - if (((SciEngine*)g_engine)->getKernel()->usesSci1SoundFunctions()) - return kDoSound_SCI1(s, funct_nr, argc, argv); - else if (((SciEngine*)g_engine)->getKernel()->usesSci01SoundFunctions()) - return kDoSound_SCI01(s, funct_nr, argc, argv); - else - return kDoSound_SCI0(s, funct_nr, argc, argv); + switch(s->detectDoSoundType()) { + case EngineState::kDoSoundTypeSci0: + return kDoSoundSci0(s, funct_nr, argc, argv); + case EngineState::kDoSoundTypeSci1Early: + return kDoSoundSci1Early(s, funct_nr, argc, argv); + case EngineState::kDoSoundTypeSci1Late: + return kDoSoundSci1Late(s, funct_nr, argc, argv); + default: + warning("Unknown DoSound type"); + return NULL_REG; + } } /** diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 1768695244..b53e9d522c 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -701,8 +701,7 @@ static void reconstruct_sounds(EngineState *s) { Song *seeker; SongIteratorType it_type; - if (((SciEngine *)g_engine)->getKernel()->usesSci01SoundFunctions() - || ((SciEngine *)g_engine)->getKernel()->usesSci1SoundFunctions()) + if (s->_version > SCI_VERSION_01) it_type = SCI_SONG_ITERATOR_TYPE_SCI1; else it_type = SCI_SONG_ITERATOR_TYPE_SCI0; diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index fd45ef5834..c45868ca56 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -24,6 +24,8 @@ */ #include "sci/engine/state.h" +#include "sci/engine/vm.h" +#include "sci/console.h" // For parse_reg_t namespace Sci { @@ -116,6 +118,8 @@ EngineState::EngineState(ResourceManager *res, SciVersion version, uint32 flags) successor = 0; speedThrottler = new SpeedThrottler(version); + + _doSoundType = kDoSoundTypeUnknown; } EngineState::~EngineState() { @@ -242,4 +246,75 @@ Common::String EngineState::strSplit(const char *str, const char *sep) { return retval; } +EngineState::DoSoundType EngineState::detectDoSoundType() { + if (_doSoundType == kDoSoundTypeUnknown) { + reg_t soundClass; + const uint checkBytes = 6; // Number of bytes to check + + if (!parse_reg_t(this, "?Sound", &soundClass)) { + reg_t fptr; + + Object *obj = obj_get(this, soundClass); + SelectorType sel = lookup_selector(this, soundClass, ((SciEngine*)g_engine)->getKernel()->_selectorMap.play, NULL, &fptr); + + if (obj && (sel == kSelectorMethod)) { + Script *script = seg_manager->getScript(fptr.segment); + + if (fptr.offset > checkBytes) { + // Go to the last portion of Sound::init, should be right before the play function + fptr.offset -= checkBytes; + byte *buf = script->buf + fptr.offset; + + // Check the call to DoSound's INIT_HANDLE function. + // It's either subfunction 0, 5 or 6, depending on the version of DoSound. + uint sum = 0; + for (uint i = 0; i < checkBytes; i++) + sum += buf[i]; + + switch(sum) { + case 0x1B2: // SCI0 + case 0x1AE: // SCI01 + _doSoundType = kDoSoundTypeSci0; + break; + case 0x13D: + _doSoundType = kDoSoundTypeSci1Early; + break; + case 0x13E: + _doSoundType = kDoSoundTypeSci1Late; + } + } + } + } + + if (_doSoundType == kDoSoundTypeUnknown) { + warning("DoSound detection failed, taking an educated guess"); + + if (_version >= SCI_VERSION_1_MIDDLE) + _doSoundType = kDoSoundTypeSci1Late; + else if (_version > SCI_VERSION_01) + _doSoundType = kDoSoundTypeSci1Early; + else + _doSoundType = kDoSoundTypeSci0; + } + + debugCN(1, kDebugLevelSound, "Detected DoSound type: "); + + switch(_doSoundType) { + case kDoSoundTypeSci0: + debugC(1, kDebugLevelSound, "SCI0"); + break; + case kDoSoundTypeSci1Early: + debugC(1, kDebugLevelSound, "SCI1 Early"); + break; + case kDoSoundTypeSci1Late: + debugC(1, kDebugLevelSound, "SCI1 Late"); + break; + default: + break; + } + } + + return _doSoundType; +} + } // End of namespace Sci diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index c8e9139f27..a3983f6ae4 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -163,6 +163,14 @@ struct EngineState : public Common::Serializable { public: EngineState(ResourceManager *res, SciVersion version, uint32 flags); virtual ~EngineState(); + + enum DoSoundType { + kDoSoundTypeUnknown, + kDoSoundTypeSci0, + kDoSoundTypeSci1Early, + kDoSoundTypeSci1Late + }; + virtual void saveLoadWithSerializer(Common::Serializer &ser); kLanguage getLanguage(); @@ -272,6 +280,12 @@ public: */ Common::String strSplit(const char *str, const char *sep = "\r----------\r"); + /** + * Autodetects the DoSound type + * @return DoSound type + */ + DoSoundType detectDoSoundType(); + /* Debugger data: */ Breakpoint *bp_list; /**< List of breakpoints */ int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */ @@ -301,6 +315,7 @@ public: EngineState *successor; /**< Successor of this state: Used for restoring */ private: + DoSoundType _doSoundType; kLanguage charToLanguage(const char c) const; Common::String getLanguageString(const char *str, kLanguage lang) const; }; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index ef31fcdd7d..7b201d0506 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -1480,7 +1480,7 @@ SciVersion ResourceManager::detectSciVersion() { // If this turns out to be unreliable, we could do some pic resource checks instead. return SCI_VERSION_1_EARLY; case kResVersionSci1Middle: - return SCI_VERSION_1_LATE; + return SCI_VERSION_1_MIDDLE; case kResVersionSci1Late: if (_viewType == kViewVga11) { // SCI1.1 resources, assume SCI1.1 diff --git a/engines/sci/resource.h b/engines/sci/resource.h index d38cff87df..0a5336fd3f 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -52,7 +52,8 @@ enum SciVersion { SCI_VERSION_01, // KQ1 and multilingual games (S.old.*) SCI_VERSION_1_EGA, // EGA with parser, QFG2 SCI_VERSION_1_EARLY, // KQ5. (EGA/VGA) - SCI_VERSION_1_LATE, // ECO1, LSL1, LSL5. (EGA/VGA) + SCI_VERSION_1_MIDDLE, // LSL1, JONESCD. (EGA?/VGA) + SCI_VERSION_1_LATE, // ECO1, LSL5. (EGA/VGA) SCI_VERSION_1_1, // KQ6, ECO2 SCI_VERSION_32 // GK }; diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index b799af9e83..64e89a638e 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -44,13 +44,14 @@ namespace Sci { class GfxDriver; // FIXME: error-prone -const char *versionNames[9] = { +const char *versionNames[10] = { "Autodetect", "SCI0 Early", "SCI0 Late", "SCI01", "SCI1 EGA", "SCI1 Early", + "SCI1 Middle", "SCI1 Late", "SCI1.1", "SCI32" -- cgit v1.2.3