diff options
Diffstat (limited to 'engines')
32 files changed, 491 insertions, 347 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 1e95393e4d..5cd7b9f7ca 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -483,9 +483,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) { debugPrintf("Move count type: %s\n", (_engine->_features->handleMoveCount()) ? "increment" : "ignore"); debugPrintf("SetCursor type: %s\n", getSciVersionDesc(_engine->_features->detectSetCursorType())); #ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2) - debugPrintf("kString type: %s\n", (_engine->_features->detectSci2StringFunctionType() == kSci2StringFunctionOld) ? "SCI2 (old)" : "SCI2.1 (new)"); - if (getSciVersion() == SCI_VERSION_2_1) + if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)"); #endif debugPrintf("View type: %s\n", viewTypeDesc[g_sci->getResMan()->getViewType()]); @@ -1046,7 +1044,7 @@ bool Console::cmdVerifyScripts(int argc, const char **argv) { if (!script) debugPrintf("Error: script %d couldn't be loaded\n", itr->getNumber()); - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() <= SCI_VERSION_2_1_LATE) { heap = _engine->getResMan()->findResource(ResourceId(kResourceTypeHeap, itr->getNumber()), false); if (!heap) debugPrintf("Error: script %d doesn't have a corresponding heap\n", itr->getNumber()); diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index be062dba64..a993506f7a 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -40,7 +40,6 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan) _moveCountType = kMoveCountUninitialized; #ifdef ENABLE_SCI32 _sci21KernelType = SCI_VERSION_NONE; - _sci2StringFunctionType = kSci2StringFunctionUninitialized; #endif _usesCdTrack = Common::File::exists("cdaudio.map"); if (!ConfMan.getBool("use_cdaudio")) @@ -143,8 +142,8 @@ SciVersion GameFeatures::detectDoSoundType() { // SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources _doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE; #ifdef ENABLE_SCI32 - } else if (getSciVersion() >= SCI_VERSION_2_1) { - _doSoundType = SCI_VERSION_2_1; + } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { + _doSoundType = SCI_VERSION_2_1_EARLY; #endif } else if (SELECTOR(nodePtr) == -1) { // No nodePtr selector, so this game is definitely using newer @@ -271,7 +270,7 @@ SciVersion GameFeatures::detectLofsType() { return _lofsType; } - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { // SCI1.1 type, i.e. we compensate for the fact that the heap is attached // to the end of the script _lofsType = SCI_VERSION_1_1; @@ -475,7 +474,7 @@ bool GameFeatures::autoDetectSci21KernelType() { } warning("autoDetectSci21KernelType(): Sound object not loaded, assuming a SCI2.1 table"); - _sci21KernelType = SCI_VERSION_2_1; + _sci21KernelType = SCI_VERSION_2_1_EARLY; return true; } @@ -514,7 +513,7 @@ bool GameFeatures::autoDetectSci21KernelType() { _sci21KernelType = SCI_VERSION_2; return true; } else if (kFuncNum == 0x75) { - _sci21KernelType = SCI_VERSION_2_1; + _sci21KernelType = SCI_VERSION_2_1_EARLY; return true; } } @@ -532,65 +531,6 @@ SciVersion GameFeatures::detectSci21KernelType() { } return _sci21KernelType; } - -Sci2StringFunctionType GameFeatures::detectSci2StringFunctionType() { - if (_sci2StringFunctionType == kSci2StringFunctionUninitialized) { - if (getSciVersion() <= SCI_VERSION_1_1) { - error("detectSci21StringFunctionType() called from SCI1.1 or earlier"); - } else if (getSciVersion() == SCI_VERSION_2) { - // SCI2 games are always using the old type - _sci2StringFunctionType = kSci2StringFunctionOld; - } else if (getSciVersion() == SCI_VERSION_3) { - // SCI3 games are always using the new type - _sci2StringFunctionType = kSci2StringFunctionNew; - } else { // SCI2.1 - if (!autoDetectSci21StringFunctionType()) - _sci2StringFunctionType = kSci2StringFunctionOld; - else - _sci2StringFunctionType = kSci2StringFunctionNew; - } - } - - debugC(1, kDebugLevelVM, "Detected SCI2 kString type: %s", (_sci2StringFunctionType == kSci2StringFunctionOld) ? "old" : "new"); - - return _sci2StringFunctionType; -} - -bool GameFeatures::autoDetectSci21StringFunctionType() { - // Look up the script address - reg_t addr = getDetectionAddr("Str", SELECTOR(size)); - - if (!addr.getSegment()) - return false; - - uint16 offset = addr.getOffset(); - Script *script = _segMan->getScript(addr.getSegment()); - - while (true) { - int16 opparams[4]; - byte extOpcode; - byte opcode; - offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams); - opcode = extOpcode >> 1; - - // Check for end of script - if (opcode == op_ret || offset >= script->getBufSize()) - break; - - if (opcode == op_callk) { - uint16 kFuncNum = opparams[0]; - - // SCI2.1 games which use the new kString functions call kString(8). - // Earlier ones call the callKernel script function, but not kString - // directly - if (_kernel->getKernelName(kFuncNum) == "String") - return true; - } - } - - return false; // not found a call to kString -} - #endif bool GameFeatures::autoDetectMoveCountType() { diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h index a4d715fee0..1c410267e6 100644 --- a/engines/sci/engine/features.h +++ b/engines/sci/engine/features.h @@ -34,12 +34,6 @@ enum MoveCountType { kIncrementMoveCount }; -enum Sci2StringFunctionType { - kSci2StringFunctionUninitialized, - kSci2StringFunctionOld, - kSci2StringFunctionNew -}; - class GameFeatures { public: GameFeatures(SegManager *segMan, Kernel *kernel); @@ -82,13 +76,6 @@ public: * @return Graphics functions type, SCI_VERSION_2 / SCI_VERSION_2_1 */ SciVersion detectSci21KernelType(); - - /** - * Autodetects the string subfunctions used in SCI2 - SCI3 - * @return string subfunctions type, kSci2StringFunctionOld / kSci2StringFunctionNew - */ - Sci2StringFunctionType detectSci2StringFunctionType(); - #endif /** @@ -132,13 +119,11 @@ private: bool autoDetectMoveCountType(); #ifdef ENABLE_SCI32 bool autoDetectSci21KernelType(); - bool autoDetectSci21StringFunctionType(); #endif SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType, _messageFunctionType; #ifdef ENABLE_SCI32 SciVersion _sci21KernelType; - Sci2StringFunctionType _sci2StringFunctionType; #endif MoveCountType _moveCountType; diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index bfb7bfcd08..c0f2c64995 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -118,7 +118,7 @@ void Kernel::loadSelectorNames() { // Starting with KQ7, Mac versions have a BE name table. GK1 Mac and earlier (and all // other platforms) always use LE. - bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1 + bool isBE = (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY && g_sci->getGameId() != GID_GK1); if (!r) { // No such resource? @@ -863,7 +863,9 @@ void Kernel::loadKernelNames(GameFeatures *features) { _kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesSci2); break; - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: + case SCI_VERSION_2_1_MIDDLE: + case SCI_VERSION_2_1_LATE: if (features->detectSci21KernelType() == SCI_VERSION_2) { // Some early SCI2.1 games use a modified SCI2 kernel table instead of // the SCI2.1 kernel table. We detect which version to use based on diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 57b4d9455b..5d929a36ae 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -414,6 +414,27 @@ reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv); reg_t kArray(EngineState *s, int argc, reg_t *argv); reg_t kListAt(EngineState *s, int argc, reg_t *argv); reg_t kString(EngineState *s, int argc, reg_t *argv); + +reg_t kStringNew(EngineState *s, int argc, reg_t *argv); +reg_t kStringSize(EngineState *s, int argc, reg_t *argv); +reg_t kStringAt(EngineState *s, int argc, reg_t *argv); +reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv); +reg_t kStringFree(EngineState *s, int argc, reg_t *argv); +reg_t kStringFill(EngineState *s, int argc, reg_t *argv); +reg_t kStringCopy(EngineState *s, int argc, reg_t *argv); +reg_t kStringCompare(EngineState *s, int argc, reg_t *argv); +reg_t kStringDup(EngineState *s, int argc, reg_t *argv); +reg_t kStringGetData(EngineState *s, int argc, reg_t *argv); +reg_t kStringLen(EngineState *s, int argc, reg_t *argv); +reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv); +reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv); +reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv); +reg_t kStringTrim(EngineState *s, int argc, reg_t *argv); +reg_t kStringUpper(EngineState *s, int argc, reg_t *argv); +reg_t kStringLower(EngineState *s, int argc, reg_t *argv); +reg_t kStringTrn(EngineState *s, int argc, reg_t *argv); +reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv); + reg_t kMulDiv(EngineState *s, int argc, reg_t *argv); reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv); reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 2cbd79366d..49dfa17554 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -34,6 +34,15 @@ namespace Sci { // . -> any type // i* -> optional multiple integers // .* -> any parameters afterwards (or none) +// +// data types: +// i - regular integer +// o - object +// r - reference +// n - node +// 0 - NULL +// . - any +// ! - invalid reference/offset struct SciKernelMapSubEntry { SciVersion fromVersion; @@ -56,7 +65,8 @@ struct SciKernelMapSubEntry { #define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE #define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1 #define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE -#define SIG_SCI21 SCI_VERSION_2_1, SCI_VERSION_3 +#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3 +#define SIG_UNTIL_SCI21MID SCI_VERSION_2_1_EARLY, SCI_VERSION_2_1_MIDDLE #define SIG_SCI16 SCI_VERSION_NONE, SCI_VERSION_1_1 #define SIG_SCI32 SCI_VERSION_2, SCI_VERSION_NONE @@ -65,7 +75,7 @@ struct SciKernelMapSubEntry { #define SIG_SOUNDSCI0 SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE #define SIG_SOUNDSCI1EARLY SCI_VERSION_1_EARLY, SCI_VERSION_1_EARLY #define SIG_SOUNDSCI1LATE SCI_VERSION_1_LATE, SCI_VERSION_1_LATE -#define SIG_SOUNDSCI21 SCI_VERSION_2_1, SCI_VERSION_3 +#define SIG_SOUNDSCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3 #define SIGFOR_ALL 0x3f #define SIGFOR_DOS 1 << 0 @@ -190,7 +200,7 @@ static const SciKernelMapSubEntry kGraph_subops[] = { // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kPalVary_subops[] = { - { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL }, + { SIG_SINCE_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL }, { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL }, { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL }, { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL }, @@ -246,6 +256,7 @@ static const SciKernelMapSubEntry kFileIO_subops[] = { #ifdef ENABLE_SCI32 +// version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kSave_subops[] = { { SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL }, { SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL }, @@ -261,31 +272,73 @@ static const SciKernelMapSubEntry kSave_subops[] = { // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kList_subops[] = { - { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL }, - { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL }, - { SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL }, - { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL }, - { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL }, - { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL }, - { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL }, - { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL }, - { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL }, - { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL }, - { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL }, - { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL }, - { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL }, - { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL }, - { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL }, - { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL }, - { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL }, - { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL }, - { SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL }, - { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL }, - { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL }, - { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL }, - { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL }, + { SIG_SINCE_SCI21, 0, MAP_CALL(NewList), "", NULL }, + { SIG_SINCE_SCI21, 1, MAP_CALL(DisposeList), "l", NULL }, + { SIG_SINCE_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL }, + { SIG_SINCE_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL }, + { SIG_SINCE_SCI21, 4, MAP_CALL(LastNode), "l", NULL }, + { SIG_SINCE_SCI21, 5, MAP_CALL(EmptyList), "l", NULL }, + { SIG_SINCE_SCI21, 6, MAP_CALL(NextNode), "n", NULL }, + { SIG_SINCE_SCI21, 7, MAP_CALL(PrevNode), "n", NULL }, + { SIG_SINCE_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL }, + { SIG_SINCE_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL }, + { SIG_SINCE_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL }, + { SIG_SINCE_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL }, + { SIG_SINCE_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL }, + { SIG_SINCE_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL }, + { SIG_SINCE_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL }, + { SIG_SINCE_SCI21, 15, MAP_CALL(FindKey), "l.", NULL }, + { SIG_SINCE_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL }, + { SIG_SINCE_SCI21, 17, MAP_CALL(ListAt), "li", NULL }, + { SIG_SINCE_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL }, + { SIG_SINCE_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL }, + { SIG_SINCE_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL }, + { SIG_SINCE_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL }, + { SIG_SINCE_SCI21, 22, MAP_CALL(Sort), "ooo", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kString_subops[] = { + { SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL }, + { SIG_SCI32, 1, MAP_CALL(StringSize), "[or]", NULL }, + { SIG_SCI32, 2, MAP_CALL(StringAt), "[or]i", NULL }, + { SIG_SCI32, 3, MAP_CALL(StringPutAt), "[or]i(i*)", NULL }, + // StringFree accepts invalid references + { SIG_SCI32, 4, MAP_CALL(StringFree), "[or0!]", NULL }, + { SIG_SCI32, 5, MAP_CALL(StringFill), "[or]ii", NULL }, + { SIG_SCI32, 6, MAP_CALL(StringCopy), "[or]i[or]ii", NULL }, + { SIG_SCI32, 7, MAP_CALL(StringCompare), "[or][or](i)", NULL }, + + // =SCI2.1 Early and SCI2.1 Middle= + { SIG_UNTIL_SCI21MID, 8, MAP_CALL(StringDup), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 9, MAP_CALL(StringGetData), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 10, MAP_CALL(StringLen), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 11, MAP_CALL(StringPrintf), "[or](.*)", NULL }, + { SIG_UNTIL_SCI21MID, 12, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL }, + { SIG_UNTIL_SCI21MID, 13, MAP_CALL(StringAtoi), "[or]", NULL }, + // exact functionality of Trim is unknown atm + { SIG_UNTIL_SCI21MID, 14, MAP_CALL(StringTrim), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 15, MAP_CALL(StringUpper), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 16, MAP_CALL(StringLower), "[or]", NULL }, + // the following 2 are unknown atm (happen in Phantasmagoria) + // possibly translate? + { SIG_UNTIL_SCI21MID, 17, MAP_CALL(StringTrn), "[or]", NULL }, + { SIG_UNTIL_SCI21MID, 18, MAP_CALL(StringTrnExclude), "[or]", NULL }, + + // SCI2.1 Late + SCI3 - kStringDup + kStringGetData were removed + { SIG_SCI32, 8, MAP_CALL(StringLen), "[or]", NULL }, + { SIG_SCI32, 9, MAP_CALL(StringPrintf), "[or](.*)", NULL }, + { SIG_SCI32, 10, MAP_CALL(StringPrintfBuf), "[or](.*)", NULL }, + { SIG_SCI32, 11, MAP_CALL(StringAtoi), "[or]", NULL }, + { SIG_SCI32, 12, MAP_CALL(StringTrim), "[or]", NULL }, + { SIG_SCI32, 13, MAP_CALL(StringUpper), "[or]", NULL }, + { SIG_SCI32, 14, MAP_CALL(StringLower), "[or]", NULL }, + { SIG_SCI32, 15, MAP_CALL(StringTrn), "[or]", NULL }, + { SIG_SCI32, 16, MAP_CALL(StringTrnExclude), "[or]", NULL }, SCI_SUBOPENTRY_TERMINATOR }; + #endif struct SciKernelMapEntry { @@ -429,7 +482,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL }, { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r0)", NULL, NULL }, { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL }, - { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL }, + { MAP_CALL(SetCursor), SIG_SINCE_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL }, // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL }, { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds }, @@ -513,7 +566,7 @@ static SciKernelMapEntry s_kernelMap[] = { // our garbage collector (i.e. the SCI0-SCI1.1 semantics). { "Purge", kFlushResources, SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL }, - { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", kString_subops, NULL }, { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL }, @@ -570,7 +623,7 @@ static SciKernelMapEntry s_kernelMap[] = { // SCI2.1 Kernel Functions { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL }, - { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, + { MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index 8e16e0a07a..eb052dd24e 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -58,7 +58,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { // In case we use a simulated event we query the current mouse position mousePos = g_sci->_gfxCursor->getPosition(); #ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x); #endif // Limit the mouse cursor position, if necessary @@ -84,7 +84,7 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) { // For a real event we use its associated mouse position mousePos = curEvent.mousePos; #ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x); #endif // Limit the mouse cursor position, if necessary diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 448e641b63..1d9dae69b7 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -487,7 +487,7 @@ reg_t kMacPlatform(EngineState *s, int argc, reg_t *argv) { // In SCI1, its usage is still unknown // In SCI1.1, it's NOP // In SCI32, it's used for remapping cursor ID's - if (getSciVersion() >= SCI_VERSION_2_1) // Set Mac cursor remap + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) // Set Mac cursor remap g_sci->_gfxCursor->setMacCursorRemapList(argc - 1, argv + 1); else if (getSciVersion() != SCI_VERSION_1_1) warning("Unknown SCI1 kMacPlatform(0) call"); diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index 5c271780dd..303de079aa 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -229,7 +229,7 @@ reg_t kScriptID(EngineState *s, int argc, reg_t *argv) { uint16 address = scr->validateExportFunc(index, true); // Point to the heap for SCI1.1 - SCI2.1 games - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) address += scr->getScriptSize(); // Bugfix for the intro speed in PQ2 version 1.002.011. diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index 6a1708d21a..032191e4c1 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -185,7 +185,7 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { volume = CLIP<int16>(volume, 0, AUDIO_VOLUME_MAX); debugC(kDebugLevelSound, "kDoAudio: set volume to %d", volume); #ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1) { + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { int16 volumePrev = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2; volumePrev = CLIP<int16>(volumePrev, 0, AUDIO_VOLUME_MAX); mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2); diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index eef758a0d9..cd0d6af936 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -674,189 +674,230 @@ reg_t kText(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } -reg_t kString(EngineState *s, int argc, reg_t *argv) { - uint16 op = argv[0].toUint16(); +// TODO: there is an unused second argument, happens at least in LSL6 right during the intro +reg_t kStringNew(EngineState *s, int argc, reg_t *argv) { + reg_t stringHandle; + SciString *string = s->_segMan->allocateString(&stringHandle); + string->setSize(argv[0].toUint16()); - if (g_sci->_features->detectSci2StringFunctionType() == kSci2StringFunctionNew) { - if (op >= 8) // Dup, GetData have been removed - op += 2; - } + // Make sure the first character is a null character + if (string->getSize() > 0) + string->setValue(0, 0); - switch (op) { - case 0: { // New - reg_t stringHandle; - SciString *string = s->_segMan->allocateString(&stringHandle); - string->setSize(argv[1].toUint16()); + return stringHandle; +} - // Make sure the first character is a null character - if (string->getSize() > 0) - string->setValue(0, 0); +reg_t kStringSize(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, s->_segMan->getString(argv[0]).size()); +} - return stringHandle; - } - case 1: // Size - return make_reg(0, s->_segMan->getString(argv[1]).size()); - case 2: { // At (return value at an index) - // Note that values are put in bytes to avoid sign extension - if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) { - SciString *string = s->_segMan->lookupString(argv[1]); - byte val = string->getRawData()[argv[2].toUint16()]; - return make_reg(0, val); - } else { - Common::String string = s->_segMan->getString(argv[1]); - byte val = string[argv[2].toUint16()]; - return make_reg(0, val); - } +// At (return value at an index) +reg_t kStringAt(EngineState *s, int argc, reg_t *argv) { + // Note that values are put in bytes to avoid sign extension + if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) { + SciString *string = s->_segMan->lookupString(argv[0]); + byte val = string->getRawData()[argv[1].toUint16()]; + return make_reg(0, val); + } else { + Common::String string = s->_segMan->getString(argv[0]); + byte val = string[argv[1].toUint16()]; + return make_reg(0, val); } - case 3: { // Atput (put value at an index) - SciString *string = s->_segMan->lookupString(argv[1]); +} - uint32 index = argv[2].toUint16(); - uint32 count = argc - 3; +// Atput (put value at an index) +reg_t kStringPutAt(EngineState *s, int argc, reg_t *argv) { + SciString *string = s->_segMan->lookupString(argv[0]); - if (index + count > 65535) - break; + uint32 index = argv[1].toUint16(); + uint32 count = argc - 2; - if (string->getSize() < index + count) - string->setSize(index + count); + if (index + count > 65535) + return NULL_REG; - for (uint16 i = 0; i < count; i++) - string->setValue(i + index, argv[i + 3].toUint16()); + if (string->getSize() < index + count) + string->setSize(index + count); - return argv[1]; // We also have to return the handle - } - case 4: // Free - // Freeing of strings is handled by the garbage collector - return s->r_acc; - case 5: { // Fill - SciString *string = s->_segMan->lookupString(argv[1]); - uint16 index = argv[2].toUint16(); + for (uint16 i = 0; i < count; i++) + string->setValue(i + index, argv[i + 2].toUint16()); + + return argv[0]; // We also have to return the handle +} + +reg_t kStringFree(EngineState *s, int argc, reg_t *argv) { + // Freeing of strings is handled by the garbage collector + return s->r_acc; +} + +reg_t kStringFill(EngineState *s, int argc, reg_t *argv) { + SciString *string = s->_segMan->lookupString(argv[0]); + uint16 index = argv[1].toUint16(); + + // A count of -1 means fill the rest of the array + uint16 count = argv[2].toSint16() == -1 ? string->getSize() - index : argv[2].toUint16(); + uint16 stringSize = string->getSize(); - // A count of -1 means fill the rest of the array - uint16 count = argv[3].toSint16() == -1 ? string->getSize() - index : argv[3].toUint16(); - uint16 stringSize = string->getSize(); + if (stringSize < index + count) + string->setSize(index + count); - if (stringSize < index + count) - string->setSize(index + count); + for (uint16 i = 0; i < count; i++) + string->setValue(i + index, argv[3].toUint16()); - for (uint16 i = 0; i < count; i++) - string->setValue(i + index, argv[4].toUint16()); + return argv[0]; +} + +reg_t kStringCopy(EngineState *s, int argc, reg_t *argv) { + const char *string2 = 0; + uint32 string2Size = 0; + Common::String string; - return argv[1]; + if (argv[2].getSegment() == s->_segMan->getStringSegmentId()) { + SciString *sstr; + sstr = s->_segMan->lookupString(argv[2]); + string2 = sstr->getRawData(); + string2Size = sstr->getSize(); + } else { + string = s->_segMan->getString(argv[2]); + string2 = string.c_str(); + string2Size = string.size() + 1; } - case 6: { // Cpy - const char *string2 = 0; - uint32 string2Size = 0; - Common::String string; - - if (argv[3].getSegment() == s->_segMan->getStringSegmentId()) { - SciString *sstr; - sstr = s->_segMan->lookupString(argv[3]); - string2 = sstr->getRawData(); - string2Size = sstr->getSize(); - } else { - string = s->_segMan->getString(argv[3]); - string2 = string.c_str(); - string2Size = string.size() + 1; + + uint32 index1 = argv[1].toUint16(); + uint32 index2 = argv[3].toUint16(); + + if (argv[0] == argv[2]) { + // source and destination string are one and the same + if (index1 == index2) { + // even same index? ignore this call + // Happens in KQ7, when starting a chapter + return argv[0]; } + // TODO: this will crash, when setSize() is triggered later + // we need to exactly replicate original interpreter behavior + warning("kString(Copy): source is the same as destination string"); + } - uint32 index1 = argv[2].toUint16(); - uint32 index2 = argv[4].toUint16(); + // The original engine ignores bad copies too + if (index2 > string2Size) + return NULL_REG; - // The original engine ignores bad copies too - if (index2 > string2Size) - break; + // A count of -1 means fill the rest of the array + uint32 count = argv[4].toSint16() == -1 ? string2Size - index2 + 1 : argv[4].toUint16(); +// reg_t strAddress = argv[0]; - // A count of -1 means fill the rest of the array - uint32 count = argv[5].toSint16() == -1 ? string2Size - index2 + 1 : argv[5].toUint16(); - reg_t strAddress = argv[1]; + SciString *string1 = s->_segMan->lookupString(argv[0]); + //SciString *string1 = !argv[1].isNull() ? s->_segMan->lookupString(argv[1]) : s->_segMan->allocateString(&strAddress); - SciString *string1 = s->_segMan->lookupString(argv[1]); - //SciString *string1 = !argv[1].isNull() ? s->_segMan->lookupString(argv[1]) : s->_segMan->allocateString(&strAddress); + if (string1->getSize() < index1 + count) + string1->setSize(index1 + count); - if (string1->getSize() < index1 + count) - string1->setSize(index1 + count); + // Note: We're accessing from c_str() here because the + // string's size ignores the trailing 0 and therefore + // triggers an assert when doing string2[i + index2]. + for (uint16 i = 0; i < count; i++) + string1->setValue(i + index1, string2[i + index2]); - // Note: We're accessing from c_str() here because the - // string's size ignores the trailing 0 and therefore - // triggers an assert when doing string2[i + index2]. - for (uint16 i = 0; i < count; i++) - string1->setValue(i + index1, string2[i + index2]); + return argv[0]; +} - return strAddress; - } - case 7: { // Cmp - Common::String string1 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]); - Common::String string2 = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]); - - if (argc == 4) // Strncmp - return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[3].toUint16())); - else // Strcmp - return make_reg(0, strcmp(string1.c_str(), string2.c_str())); - } - case 8: { // Dup - reg_t stringHandle; +reg_t kStringCompare(EngineState *s, int argc, reg_t *argv) { + Common::String string1 = argv[0].isNull() ? "" : s->_segMan->getString(argv[0]); + Common::String string2 = argv[1].isNull() ? "" : s->_segMan->getString(argv[1]); - SciString *dupString = s->_segMan->allocateString(&stringHandle); + if (argc == 3) // Strncmp + return make_reg(0, strncmp(string1.c_str(), string2.c_str(), argv[2].toUint16())); + else // Strcmp + return make_reg(0, strcmp(string1.c_str(), string2.c_str())); +} - if (argv[1].getSegment() == s->_segMan->getStringSegmentId()) { - *dupString = *s->_segMan->lookupString(argv[1]); - } else { - dupString->fromString(s->_segMan->getString(argv[1])); - } +// was removed for SCI2.1 Late+ +reg_t kStringDup(EngineState *s, int argc, reg_t *argv) { + reg_t stringHandle; - return stringHandle; - } - case 9: // Getdata - if (!s->_segMan->isHeapObject(argv[1])) - return argv[1]; - - return readSelector(s->_segMan, argv[1], SELECTOR(data)); - case 10: // Stringlen - return make_reg(0, s->_segMan->strlen(argv[1])); - case 11: { // Printf - reg_t stringHandle; - s->_segMan->allocateString(&stringHandle); - - reg_t *adjustedArgs = new reg_t[argc]; - adjustedArgs[0] = stringHandle; - memcpy(&adjustedArgs[1], argv + 1, (argc - 1) * sizeof(reg_t)); - - kFormat(s, argc, adjustedArgs); - delete[] adjustedArgs; - return stringHandle; - } - case 12: // Printf Buf - return kFormat(s, argc - 1, argv + 1); - case 13: { // atoi - Common::String string = s->_segMan->getString(argv[1]); - return make_reg(0, (uint16)atoi(string.c_str())); - } - // New subops in SCI2.1 late / SCI3 - case 14: // unknown - warning("kString, subop %d", op); - return NULL_REG; - case 15: { // upper - Common::String string = s->_segMan->getString(argv[1]); + SciString *dupString = s->_segMan->allocateString(&stringHandle); - string.toUppercase(); - s->_segMan->strcpy(argv[1], string.c_str()); - return NULL_REG; + if (argv[0].getSegment() == s->_segMan->getStringSegmentId()) { + *dupString = *s->_segMan->lookupString(argv[0]); + } else { + dupString->fromString(s->_segMan->getString(argv[0])); } - case 16: { // lower - Common::String string = s->_segMan->getString(argv[1]); - string.toLowercase(); - s->_segMan->strcpy(argv[1], string.c_str()); - return NULL_REG; - } - default: - error("Unknown kString subop %d", argv[0].toUint16()); - } + return stringHandle; +} + +// was removed for SCI2.1 Late+ +reg_t kStringGetData(EngineState *s, int argc, reg_t *argv) { + if (!s->_segMan->isHeapObject(argv[0])) + return argv[0]; + + return readSelector(s->_segMan, argv[0], SELECTOR(data)); +} + +reg_t kStringLen(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, s->_segMan->strlen(argv[0])); +} + +reg_t kStringPrintf(EngineState *s, int argc, reg_t *argv) { + reg_t stringHandle; + s->_segMan->allocateString(&stringHandle); + + reg_t *adjustedArgs = new reg_t[argc + 1]; + adjustedArgs[0] = stringHandle; + memcpy(&adjustedArgs[1], argv, argc * sizeof(reg_t)); + + kFormat(s, argc + 1, adjustedArgs); + delete[] adjustedArgs; + return stringHandle; +} + +reg_t kStringPrintfBuf(EngineState *s, int argc, reg_t *argv) { + return kFormat(s, argc, argv); +} +reg_t kStringAtoi(EngineState *s, int argc, reg_t *argv) { + Common::String string = s->_segMan->getString(argv[0]); + return make_reg(0, (uint16)atoi(string.c_str())); +} + +reg_t kStringTrim(EngineState *s, int argc, reg_t *argv) { + warning("kStringTrim (argc = %d)", argc); + return NULL_REG; +} + +reg_t kStringUpper(EngineState *s, int argc, reg_t *argv) { + Common::String string = s->_segMan->getString(argv[0]); + + string.toUppercase(); + s->_segMan->strcpy(argv[0], string.c_str()); + return NULL_REG; +} + +reg_t kStringLower(EngineState *s, int argc, reg_t *argv) { + Common::String string = s->_segMan->getString(argv[0]); + + string.toLowercase(); + s->_segMan->strcpy(argv[0], string.c_str()); return NULL_REG; } +// Possibly kStringTranslate? +reg_t kStringTrn(EngineState *s, int argc, reg_t *argv) { + warning("kStringTrn (argc = %d)", argc); + return NULL_REG; +} + +// Possibly kStringTranslateExclude? +reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv) { + warning("kStringTrnExclude (argc = %d)", argc); + return NULL_REG; +} + +reg_t kString(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + #endif } // End of namespace Sci diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index f925111fc9..6920466711 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -181,7 +181,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { // for the video, so we'll just play it from there for now. #ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1) { + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { // SCI2.1 always has argv[0] as 1, the rest of the arguments seem to // follow SCI1.1/2. if (argv[0].toUint16() != 1) diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp index 640175b20a..5300b72b71 100644 --- a/engines/sci/engine/message.cpp +++ b/engines/sci/engine/message.cpp @@ -182,7 +182,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re #ifdef ENABLE_SCI32 case 5: // v5 seems to be compatible with v4 // SCI32 Mac is different than SCI32 DOS/Win here - if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1) + if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY) reader = new MessageReaderV4_MacSCI32(res->data, res->size); else #endif diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp index eeff45163d..0626c084c1 100644 --- a/engines/sci/engine/object.cpp +++ b/engines/sci/engine/object.cpp @@ -45,7 +45,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme return false; } block[idx].setSegment(segment); // Perform relocation - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) block[idx].incOffset(scriptSize); return true; @@ -63,7 +63,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { for (int i = 0; i < _methodCount * 2 + 2; ++i) { _baseMethod.push_back(READ_SCI11ENDIAN_UINT16(data + READ_LE_UINT16(data + kOffsetFunctionArea) + i * 2)); } - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { _variables.resize(READ_SCI11ENDIAN_UINT16(data + 2)); _baseVars = (const uint16 *)(buf + READ_SCI11ENDIAN_UINT16(data + 4)); _methodCount = READ_SCI11ENDIAN_UINT16(buf + READ_SCI11ENDIAN_UINT16(data + 6)); @@ -75,7 +75,7 @@ void Object::init(byte *buf, reg_t obj_pos, bool initVariables) { } if (initVariables) { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() <= SCI_VERSION_2_1_LATE) { for (uint i = 0; i < _variables.size(); i++) _variables[i] = make_reg(0, READ_SCI11ENDIAN_UINT16(data + (i * 2))); } else { @@ -92,7 +92,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { const byte *buf = 0; uint varnum = 0; - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() <= SCI_VERSION_2_1_LATE) { const Object *obj = getClass(segMan); varnum = getSciVersion() <= SCI_VERSION_1_LATE ? getVarCount() : obj->getVariable(1).toUint16(); buf = (const byte *)obj->_baseVars; diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h index 00fe7c6875..0ae7ed2cab 100644 --- a/engines/sci/engine/object.h +++ b/engines/sci/engine/object.h @@ -79,42 +79,42 @@ public: } reg_t getSpeciesSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _variables[_offset]; else // SCI3 return _speciesSelectorSci3; } void setSpeciesSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) _variables[_offset] = value; else // SCI3 _speciesSelectorSci3 = value; } reg_t getSuperClassSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _variables[_offset + 1]; else // SCI3 return _superClassPosSci3; } void setSuperClassSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) _variables[_offset + 1] = value; else // SCI3 _superClassPosSci3 = value; } reg_t getInfoSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _variables[_offset + 2]; else // SCI3 return _infoSelectorSci3; } void setInfoSelector(reg_t info) { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) _variables[_offset + 2] = info; else // SCI3 _infoSelectorSci3 = info; @@ -123,7 +123,7 @@ public: // No setter for the -info- selector reg_t getNameSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; else // SCI3 return _variables.size() ? _variables[0] : NULL_REG; @@ -132,7 +132,7 @@ public: // No setter for the name selector reg_t getPropDictSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _variables[2]; else // This should never occur, this is called from a SCI1.1 - SCI2.1 only function @@ -140,7 +140,7 @@ public: } void setPropDictSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) _variables[2] = value; else // This should never occur, this is called from a SCI1.1 - SCI2.1 only function @@ -148,14 +148,14 @@ public: } reg_t getClassScriptSelector() const { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) return _variables[4]; else // SCI3 return make_reg(0, READ_SCI11ENDIAN_UINT16(_baseObj + 6)); } void setClassScriptSelector(reg_t value) { - if (getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() < SCI_VERSION_3) _variables[4] = value; else // SCI3 // This should never occur, this is called from a SCI1.1 - SCI2.1 only function diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 93b3a997cc..b464d347bd 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -465,7 +465,7 @@ void Script::syncStringHeap(Common::Serializer &s) { break; } while (1); - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1){ + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE){ // Strings in SCI1.1 come after the object instances byte *buf = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 36e33ccfa6..26a7ff5718 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -84,7 +84,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP if (getSciVersion() == SCI_VERSION_0_EARLY) { _bufSize += READ_LE_UINT16(script->data) * 2; - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { // In SCI1.1 - SCI2.1, the heap was in a separate space from the script. We append // it to the end of the script, and adjust addressing accordingly. // However, since we address the heap with a 16-bit pointer, the @@ -142,7 +142,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP assert(_bufSize >= script->size); memcpy(_buf, script->data, script->size); - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0); assert(heap != 0); @@ -171,7 +171,7 @@ void Script::load(int script_nr, ResourceManager *resMan, ScriptPatcher *scriptP _localsOffset = localsBlock - _buf + 4; _localsCount = (READ_LE_UINT16(_buf + _localsOffset - 2) - 4) >> 1; // half block size } - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { if (READ_LE_UINT16(_buf + 1 + 5) > 0) { // does the script have an export table? _exportTable = (const uint16 *)(_buf + 1 + 5 + 2); _numExports = READ_SCI11ENDIAN_UINT16(_exportTable - 1); @@ -387,7 +387,7 @@ void Script::identifyOffsets() { scriptDataLeft -= blockSize; } while (1); - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { // Strings in SCI1.1 up to SCI2 come after the object instances scriptDataPtr = _heapStart; scriptDataLeft = _heapSize; @@ -668,7 +668,7 @@ static bool relocateBlock(Common::Array<reg_t> &block, int block_location, Segme return false; } block[idx].setSegment(segment); // Perform relocation - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) block[idx].incOffset(scriptSize); return true; @@ -702,7 +702,7 @@ void Script::relocateSci0Sci21(reg_t block) { uint16 heapSize = (uint16)_bufSize; uint16 heapOffset = 0; - if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { heap = _heapStart; heapSize = (uint16)_heapSize; heapOffset = _scriptSize; @@ -930,7 +930,7 @@ void Script::initializeClasses(SegManager *segMan) { if (getSciVersion() <= SCI_VERSION_1_LATE) { seeker = findBlockSCI0(SCI_OBJ_CLASS); mult = 1; - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { seeker = _heapStart + 4 + READ_SCI11ENDIAN_UINT16(_heapStart + 2) * 2; mult = 2; } else if (getSciVersion() == SCI_VERSION_3) { @@ -962,7 +962,7 @@ void Script::initializeClasses(SegManager *segMan) { if (isClass) species = READ_SCI11ENDIAN_UINT16(seeker + 12); classpos += 12; - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { isClass = (READ_SCI11ENDIAN_UINT16(seeker + 14) & kInfoFlagClass); // -info- selector species = READ_SCI11ENDIAN_UINT16(seeker + 10); } else if (getSciVersion() == SCI_VERSION_3) { @@ -1104,7 +1104,7 @@ void Script::initializeObjectsSci3(SegManager *segMan, SegmentId segmentId) { void Script::initializeObjects(SegManager *segMan, SegmentId segmentId) { if (getSciVersion() <= SCI_VERSION_1_LATE) initializeObjectsSci0(segMan, segmentId); - else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) + else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) initializeObjectsSci11(segMan, segmentId); else if (getSciVersion() == SCI_VERSION_3) initializeObjectsSci3(segMan, segmentId); diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp index 188da3d5a2..8aa1697f07 100644 --- a/engines/sci/engine/static_selectors.cpp +++ b/engines/sci/engine/static_selectors.cpp @@ -114,16 +114,16 @@ static const SelectorRemap sciSelectorRemap[] = { { SCI_VERSION_1_1, SCI_VERSION_1_1, "cantBeHere", 54 }, // The following are not really needed. They've only been defined to // ease game debugging. - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-objID-", 4096 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-size-", 4097 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-propDict-", 4098 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-methDict-", 4099 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-classScript-", 4100 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-script-", 4101 }, - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-super-", 4102 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-objID-", 4096 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-size-", 4097 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-propDict-", 4098 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-methDict-", 4099 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-classScript-", 4100 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-script-", 4101 }, + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-super-", 4102 }, // - { SCI_VERSION_1_1, SCI_VERSION_2_1, "-info-", 4103 }, - { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 } + { SCI_VERSION_1_1, SCI_VERSION_2_1_LATE, "-info-", 4103 }, + { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, 0 } }; struct ClassReference { diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index 65a82832cc..cf008c45e1 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -29,7 +29,7 @@ namespace Sci { SegmentId reg_t::getSegment() const { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() < SCI_VERSION_3) { return _segment; } else { // Return the lower 14 bits of the segment @@ -38,7 +38,7 @@ SegmentId reg_t::getSegment() const { } void reg_t::setSegment(SegmentId segment) { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() < SCI_VERSION_3) { _segment = segment; } else { // Set the lower 14 bits of the segment, and preserve the upper 2 ones for the offset @@ -47,7 +47,7 @@ void reg_t::setSegment(SegmentId segment) { } uint32 reg_t::getOffset() const { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() < SCI_VERSION_3) { return _offset; } else { // Return the lower 16 bits from the offset, and the 17th and 18th bits from the segment @@ -56,7 +56,7 @@ uint32 reg_t::getOffset() const { } void reg_t::setOffset(uint32 offset) { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() < SCI_VERSION_3) { _offset = offset; } else { // Store the lower 16 bits in the offset, and the 17th and 18th bits in the segment diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 3c2285a470..716a366b7c 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -130,7 +130,7 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { #ifdef ENABLE_SCI32 if (view->isSci2Hires()) view->adjustToUpscaledCoordinates(y, x); - else if (getSciVersion() == SCI_VERSION_2_1) + else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) _coordAdjuster->fromScriptToDisplay(y, x); #endif @@ -140,7 +140,7 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) { if (view->isSci2Hires()) { view->adjustBackUpscaledCoordinates(celRect.top, celRect.left); view->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); - } else if (getSciVersion() == SCI_VERSION_2_1) { + } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) { _coordAdjuster->fromDisplayToScript(celRect.top, celRect.left); _coordAdjuster->fromDisplayToScript(celRect.bottom, celRect.right); } diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index ccc362dc37..9628e8ac97 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -727,7 +727,7 @@ void GfxFrameout::kernelFrameout() { if (view && view->isSci2Hires()) { view->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x); view->adjustToUpscaledCoordinates(itemEntry->z, dummyX); - } else if (getSciVersion() >= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { _coordAdjuster->fromScriptToDisplay(itemEntry->y, itemEntry->x); _coordAdjuster->fromScriptToDisplay(itemEntry->z, dummyX); } @@ -782,7 +782,7 @@ void GfxFrameout::kernelFrameout() { view->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left); view->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right); g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); - } else if (getSciVersion() >= SCI_VERSION_2_1 && _resMan->detectHires()) { + } else if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) { _coordAdjuster->fromDisplayToScript(nsRect.top, nsRect.left); _coordAdjuster->fromDisplayToScript(nsRect.bottom, nsRect.right); g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index da61ecf4c3..2ee18b5c9a 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -356,7 +356,7 @@ void GfxView::initData(GuiResourceId resourceId) { for (loopNo = 0; loopNo < _loopCount; loopNo++) for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++) _screen->adjustBackUpscaledCoordinates(_loop[loopNo].cel[celNo].scriptWidth, _loop[loopNo].cel[celNo].scriptHeight, _sci2ScaleRes); - } else if (getSciVersion() == SCI_VERSION_2_1) { + } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) { for (loopNo = 0; loopNo < _loopCount; loopNo++) for (celNo = 0; celNo < _loop[loopNo].celCount; celNo++) _coordAdjuster->fromDisplayToScript(_loop[loopNo].cel[celNo].scriptHeight, _loop[loopNo].cel[celNo].scriptWidth); diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 10740a8b7b..ad40ae90f0 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -82,8 +82,12 @@ const char *getSciVersionDesc(SciVersion version) { return "SCI1.1"; case SCI_VERSION_2: return "SCI2"; - case SCI_VERSION_2_1: - return "SCI2.1"; + case SCI_VERSION_2_1_EARLY: + return "Early SCI2.1"; + case SCI_VERSION_2_1_MIDDLE: + return "Middle SCI2.1"; + case SCI_VERSION_2_1_LATE: + return "Late SCI2.1"; case SCI_VERSION_3: return "SCI3"; default: @@ -2121,6 +2125,79 @@ ViewType ResourceManager::detectViewType() { return kViewUnknown; } +// to detect selector "wordFail" in LE vocab resource +static const byte detectSci21EarlySignature[] = { + 10, // size of signature + 0x08, 0x00, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l' +}; + +// to detect selector "wordFail" in BE vocab resource (SCI2.1 Early) +static const byte detectSci21EarlyBESignature[] = { + 10, // size of signature + 0x00, 0x08, 'w', 'o', 'r', 'd', 'F', 'a', 'i', 'l' +}; + +// to detect new kString calling to detect SCI2.1 Late +static const byte detectSci21NewStringSignature[] = { + 8, // size of signature + 0x78, // push1 + 0x78, // push1 + 0x39, 0x09, // pushi 09 + 0x59, 0x01, // rest 01 + 0x43, 0x5c, // callk String +}; + +bool ResourceManager::checkResourceDataForSignature(Resource *resource, const byte *signature) { + byte signatureSize = *signature; + const byte *resourceData = resource->data; + + signature++; // skip over size byte + if (signatureSize < 4) + error("resource signature is too small, internal error"); + if (signatureSize > resource->size) + return false; + + const uint32 signatureDWord = *((uint32 *)signature); + signature += 4; signatureSize -= 4; + + const uint32 searchLimit = resource->size - signatureSize + 1; + uint32 DWordOffset = 0; + while (DWordOffset < searchLimit) { + if (signatureDWord == READ_UINT32(resourceData + DWordOffset)) { + // magic DWORD found, check if the rest matches as well + uint32 offset = DWordOffset + 4; + uint32 signaturePos = 0; + while (signaturePos < signatureSize) { + if (resourceData[offset] != signature[signaturePos]) + break; + offset++; + signaturePos++; + } + if (signaturePos >= signatureSize) + return true; // signature found + } + DWordOffset++; + } + return false; +} + +bool ResourceManager::checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2) { + Resource *resource = findResource(ResourceId(resourceType, resourceNr), false); + + if (resource) { + // resource found and loaded, check for signatures + if (signature1) { + if (checkResourceDataForSignature(resource, signature1)) + return true; + } + if (signature2) { + if (checkResourceDataForSignature(resource, signature2)) + return true; + } + } + return false; +} + void ResourceManager::detectSciVersion() { // We use the view compression to set a preliminary s_sciVersion for the sake of getResourceInfo // Pretend we have a SCI0 game @@ -2180,31 +2257,52 @@ void ResourceManager::detectSciVersion() { // no Mac SCI2 games. Yes, that means that GK1 Mac is SCI2.1 and not SCI2. // TODO: Decide between SCI2.1 and SCI3 - if (res) - s_sciVersion = SCI_VERSION_2_1; - else + if (res) { + s_sciVersion = SCI_VERSION_2_1_EARLY; // we check for SCI2.1 specifics a bit later + } else { s_sciVersion = SCI_VERSION_1_1; - return; + return; + } } // Handle SCI32 versions here - if (_volVersion >= kResVersionSci2) { - Common::List<ResourceId> heaps = listResources(kResourceTypeHeap); - bool hasHeapResources = !heaps.empty(); - - // SCI2.1/3 and SCI1 Late resource maps are the same, except that - // SCI1 Late resource maps have the resource types or'd with - // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that. - if (_mapVersion == kResVersionSci1Late) { - s_sciVersion = SCI_VERSION_2; - return; - } else if (hasHeapResources) { - s_sciVersion = SCI_VERSION_2_1; + if (s_sciVersion != SCI_VERSION_2_1_EARLY) { + if (_volVersion >= kResVersionSci2) { + Common::List<ResourceId> heaps = listResources(kResourceTypeHeap); + bool hasHeapResources = !heaps.empty(); + + // SCI2.1/3 and SCI1 Late resource maps are the same, except that + // SCI1 Late resource maps have the resource types or'd with + // 0x80. We differentiate between SCI2 and SCI2.1/3 based on that. + if (_mapVersion == kResVersionSci1Late) { + s_sciVersion = SCI_VERSION_2; + return; + } else if (hasHeapResources) { + s_sciVersion = SCI_VERSION_2_1_EARLY; // exact SCI2.1 version is checked a bit later + } else { + s_sciVersion = SCI_VERSION_3; + return; + } + } + } + + if (s_sciVersion == SCI_VERSION_2_1_EARLY) { + // we only know that it's SCI2.1, not which exact version it is + + // check, if selector "wordFail" inside vocab 997 exists, if it does it's SCI2.1 Early + if ((checkResourceForSignatures(kResourceTypeVocab, 997, detectSci21EarlySignature, detectSci21EarlyBESignature))) { + // found -> it is SCI2.1 early return; - } else { - s_sciVersion = SCI_VERSION_3; + } + + s_sciVersion = SCI_VERSION_2_1_MIDDLE; + if (checkResourceForSignatures(kResourceTypeScript, 64918, detectSci21NewStringSignature, nullptr)) { + // new kString call detected, it's SCI2.1 late + // TODO: this call seems to be different on Mac + s_sciVersion = SCI_VERSION_2_1_LATE; return; } + return; } // Check for transitive SCI1/SCI1.1 games, like PQ1 here @@ -2537,7 +2635,7 @@ reg_t ResourceManager::findGameObject(bool addSci11ScriptOffset) { int16 offset = !isSci11Mac() ? READ_LE_UINT16(offsetPtr) : READ_BE_UINT16(offsetPtr); return make_reg(1, offset); - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { offsetPtr = script->data + 4 + 2 + 2; // In SCI1.1 - SCI2.1, the heap is appended at the end of the script, @@ -2565,7 +2663,7 @@ Common::String ResourceManager::findSierraGameId() { if (getSciVersion() < SCI_VERSION_1_1) { heap = findResource(ResourceId(kResourceTypeScript, 0), false); - } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) { + } else if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1_LATE) { heap = findResource(ResourceId(kResourceTypeHeap, 0), false); nameSelector += 5; } else if (getSciVersion() == SCI_VERSION_3) { diff --git a/engines/sci/resource.h b/engines/sci/resource.h index ef48998b04..eb5b508254 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -559,6 +559,8 @@ protected: ViewType detectViewType(); bool hasSci0Voc999(); bool hasSci1Voc900(); + bool checkResourceDataForSignature(Resource *resource, const byte *signature); + bool checkResourceForSignatures(ResourceType resourceType, uint16 resourceNr, const byte *signature1, const byte *signature2); void detectSciVersion(); }; diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp index 3a43774492..6869e6379e 100644 --- a/engines/sci/resource_audio.cpp +++ b/engines/sci/resource_audio.cpp @@ -637,7 +637,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers case SCI_VERSION_1_EARLY: case SCI_VERSION_1_LATE: - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: data = resource->data; // Count # of tracks _trackCount = 0; diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 75f485d6c3..f1ab65ef98 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -897,7 +897,9 @@ void SciEngine::syncIngameAudioOptions() { break; #ifdef ENABLE_SCI32 case SCI_VERSION_2: - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: + case SCI_VERSION_2_1_MIDDLE: + case SCI_VERSION_2_1_LATE: // Only use global 90 for some specific games, not all SCI32 games used this method switch (_gameId) { case GID_KQ7: // SCI2.1 diff --git a/engines/sci/sci.h b/engines/sci/sci.h index c6813aa07c..15034d5e94 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -200,7 +200,9 @@ enum SciVersion { SCI_VERSION_1_LATE, // Dr. Brain 1, EcoQuest 1, Longbow, PQ3, SQ1, LSL5, KQ5 CD SCI_VERSION_1_1, // Dr. Brain 2, EcoQuest 1 CD, EcoQuest 2, KQ6, QFG3, SQ4CD, XMAS 1992 and many more SCI_VERSION_2, // GK1, PQ4 floppy, QFG4 floppy - SCI_VERSION_2_1, // GK2, KQ7, LSL6 hires, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin + SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7, LSL6 hires, PQ4, QFG4 floppy + SCI_VERSION_2_1_MIDDLE, // GK2, KQ7, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin + SCI_VERSION_2_1_LATE, // demos of LSL7, Lighthouse, RAMA SCI_VERSION_3 // LSL7, Lighthouse, RAMA, Phantasmagoria 2 }; diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp index fb9a3f17b9..8c029cf502 100644 --- a/engines/sci/sound/audio.cpp +++ b/engines/sci/sound/audio.cpp @@ -217,7 +217,7 @@ static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) { if (b & 8) { #ifdef ENABLE_SCI32 // SCI2.1 reverses the order of the table values here - if (getSciVersion() >= SCI_VERSION_2_1) + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) s -= tableDPCM8[b & 7]; else #endif diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp index baf85de74c..aa464cdc19 100644 --- a/engines/sci/sound/drivers/midi.cpp +++ b/engines/sci/sound/drivers/midi.cpp @@ -1019,7 +1019,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) { if (!isMt32GmPatch(res->data, res->size)) { mapMt32ToGm(res->data, res->size); } else { - if (getSciVersion() <= SCI_VERSION_2_1) { + if (getSciVersion() < SCI_VERSION_3) { error("MT-32 patch has wrong type"); } else { // Happens in the SCI3 interactive demo of Lighthouse diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 9f0d8d150f..21f95f17e0 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -717,7 +717,7 @@ bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) { break; case SCI_VERSION_1_EARLY: case SCI_VERSION_1_LATE: - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: inc = 1; break; default: @@ -862,7 +862,7 @@ void MidiParser_SCI::setMasterVolume(byte masterVolume) { case SCI_VERSION_1_EARLY: case SCI_VERSION_1_LATE: - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: // directly set master volume (global volume is merged with channel volumes) ((MidiPlayer *)_driver)->setVolume(masterVolume); break; @@ -887,7 +887,7 @@ void MidiParser_SCI::setVolume(byte volume) { case SCI_VERSION_1_EARLY: case SCI_VERSION_1_LATE: - case SCI_VERSION_2_1: + case SCI_VERSION_2_1_EARLY: // Send previous channel volumes again to actually update the volume for (int i = 0; i < 15; i++) if (_channelRemap[i] != -1) diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index dca73c3f51..31cf27f7e0 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -73,7 +73,7 @@ void SciMusic::init() { // Default to MIDI in SCI2.1+ games, as many don't have AdLib support. // Also, default to MIDI for Windows versions of SCI1.1 games, as their // soundtrack is written for GM. - if (getSciVersion() >= SCI_VERSION_2_1 || g_sci->_features->useAltWinGMSound()) + if (getSciVersion() >= SCI_VERSION_2_1_EARLY || g_sci->_features->useAltWinGMSound()) deviceFlags |= MDT_PREFER_GM; // Currently our CMS implementation only supports SCI1(.1) diff --git a/engines/sci/util.cpp b/engines/sci/util.cpp index 3a9ed9ca69..c72d3beb19 100644 --- a/engines/sci/util.cpp +++ b/engines/sci/util.cpp @@ -49,7 +49,7 @@ uint16 READ_SCI11ENDIAN_UINT16(const void *ptr) { } uint16 READ_SCI32ENDIAN_UINT16(const void *ptr) { - if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1) + if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_2_1_EARLY) return READ_BE_UINT16(ptr); else return READ_LE_UINT16(ptr); |