diff options
Diffstat (limited to 'engines/sci/engine/state.cpp')
-rw-r--r-- | engines/sci/engine/state.cpp | 483 |
1 files changed, 3 insertions, 480 deletions
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index dbbbb9d499..89078e6381 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -40,6 +40,8 @@ EngineState::EngineState(ResourceManager *res, Kernel *kernel, Vocabulary *voc, sfx_init_flags = 0; #endif + _features = new GameFeatures(_segMan, _kernel); + restarting_flags = 0; last_wait_time = 0; @@ -72,24 +74,13 @@ EngineState::EngineState(ResourceManager *res, Kernel *kernel, Vocabulary *voc, _throttleLastTime = 0; _throttleTrigger = false; - _setCursorType = SCI_VERSION_NONE; - _doSoundType = SCI_VERSION_NONE; - _lofsType = SCI_VERSION_NONE; - _gfxFunctionsType = SCI_VERSION_NONE; - _moveCountType = kMoveCountUninitialized; - -#ifdef ENABLE_SCI32 - _sci21KernelType = SCI_VERSION_NONE; -#endif - _memorySegmentSize = 0; - _usesCdTrack = Common::File::exists("cdaudio.map"); - _soundCmd = 0; } EngineState::~EngineState() { + delete _features; delete _msgState; } @@ -218,472 +209,4 @@ Common::String EngineState::strSplit(const char *str, const char *sep) { return retval; } -bool EngineState::autoDetectFeature(FeatureDetection featureDetection, int methodNum) { - Common::String objName; - Selector slc = 0; - reg_t objAddr; - bool foundTarget = false; - - // Get address of target script - switch (featureDetection) { - case kDetectGfxFunctions: - objName = "Rm"; - objAddr = _segMan->findObjectByName(objName); - slc = _kernel->_selectorCache.overlay; - break; - case kDetectMoveCountType: - objName = "Motion"; - objAddr = _segMan->findObjectByName(objName); - slc = _kernel->_selectorCache.doit; - break; - case kDetectSoundType: - objName = "Sound"; - objAddr = _segMan->findObjectByName(objName); - slc = _kernel->_selectorCache.play; - break; - case kDetectSetCursorType: - objName = "Game"; - objAddr = _segMan->findObjectByName(objName); - // KQ5CD overrides the default setCursor selector of the Game object, - // so we need to handle this separately - // KQ5 PC floppy is early SCI1, Amiga middle SCI1, and CD late SCI1 - if (_gameId == "kq5" && getSciVersion() == SCI_VERSION_1_LATE) - objAddr = _gameObj; - slc = _kernel->_selectorCache.setCursor; - break; - case kDetectLofsType: - objName = "Game"; - objAddr = _segMan->findObjectByName(objName); - break; -#ifdef ENABLE_SCI32 - case kDetectSci21KernelTable: - objName = "Sound"; - objAddr = _segMan->findObjectByName(objName); - slc = _kernel->_selectorCache.play; - break; -#endif - default: - warning("autoDetectFeature: invalid featureDetection value %x", featureDetection); - return false; - } - - reg_t addr; - if (objAddr.isNull()) { - warning("autoDetectFeature: %s object couldn't be found", objName.c_str()); - return false; - } - - if (methodNum == -1) { - if (lookup_selector(_segMan, objAddr, slc, NULL, &addr) != kSelectorMethod) { - warning("autoDetectFeature: target selector is not a method of object %s", objName.c_str()); - return false; - } - } else { - addr = _segMan->getObject(objAddr)->getFunction(methodNum); - } - - uint16 offset = addr.offset; - Script *script = _segMan->getScript(addr.segment); - uint16 intParam = 0xFFFF; - - do { - uint16 kFuncNum; - int opsize = script->_buf[offset++]; - uint opcode = opsize >> 1; - int i = 0; - byte argc; - - if (featureDetection == kDetectLofsType) { - if (opcode == op_lofsa || opcode == op_lofss) { - uint16 lofs; - - // Load lofs operand - if (opsize & 1) { - if (offset >= script->_bufSize) - break; - lofs = script->_buf[offset++]; - } else { - if ((uint32)offset + 1 >= (uint32)script->_bufSize) - break; - lofs = READ_LE_UINT16(script->_buf + offset); - offset += 2; - } - - // Check for going out of bounds when interpreting as abs/rel - if (lofs >= script->_bufSize) - _lofsType = SCI_VERSION_0_EARLY; - - if ((signed)offset + (int16)lofs < 0) - _lofsType = SCI_VERSION_1_MIDDLE; - - if ((signed)offset + (int16)lofs >= (signed)script->_bufSize) - _lofsType = SCI_VERSION_1_MIDDLE; - - if (_lofsType != SCI_VERSION_NONE) - return true; - - // If we reach here, we haven't been able to deduce the lofs parameter - // type, but we have advanced the offset pointer already. So move on - // to the next opcode - continue; - } - } - - if (featureDetection == kDetectSoundType) { - // The play method of the Sound object pushes the DoSound command - // that it'll use just before it calls DoSound. We intercept that here - // in order to check what sound semantics are used, cause the position - // of the sound commands has changed at some point during SCI1 middle - if (opcode == op_pushi) { - // Load the pushi parameter - if (opsize & 1) { - if (offset >= script->_bufSize) - break; - intParam = script->_buf[offset++]; - } else { - if ((uint32)offset + 1 >= (uint32)script->_bufSize) - break; - intParam = READ_LE_UINT16(script->_buf + offset); - offset += 2; - } - - continue; - } - } - - while (g_opcode_formats[opcode][i]) { - switch (g_opcode_formats[opcode][i++]) { - case Script_Invalid: - break; - case Script_SByte: - case Script_Byte: - offset++; - break; - case Script_Word: - case Script_SWord: - offset += 2; - break; - case Script_SVariable: - case Script_Variable: - case Script_Property: - case Script_Global: - case Script_Local: - case Script_Temp: - case Script_Param: - if (opsize & 1) - kFuncNum = script->_buf[offset++]; - else { - kFuncNum = 0xffff & (script->_buf[offset] | (script->_buf[offset + 1] << 8)); - offset += 2; - } - - if (opcode == op_callk) { - argc = script->_buf[offset++]; - - switch (featureDetection) { - case kDetectGfxFunctions: - if (kFuncNum == 8) { // kDrawPic (SCI0 - SCI11) - // If kDrawPic is called with 6 parameters from the - // overlay selector, the game is using old graphics functions. - // Otherwise, if it's called with 8 parameters, it's using new - // graphics functions - _gfxFunctionsType = (argc == 8) ? SCI_VERSION_0_LATE : SCI_VERSION_0_EARLY; - return true; - } - break; - case kDetectMoveCountType: - // Games which ignore move count call kAbs before calling kDoBresen - if (_kernel->getKernelName(kFuncNum) == "Abs") { - foundTarget = true; - } else if (_kernel->getKernelName(kFuncNum) == "DoBresen") { - _moveCountType = foundTarget ? kIgnoreMoveCount : kIncrementMoveCount; - return true; - } - break; - case kDetectSoundType: - // Late SCI1 games call kIsObject before kDoSound - if (kFuncNum == 6) { // kIsObject (SCI0-SCI11) - foundTarget = true; - } else if (kFuncNum == 45) { // kDoSound (SCI1) - // First, check which DoSound function is called by the play method of - // the Sound object - switch (intParam) { - case 1: - _doSoundType = SCI_VERSION_0_EARLY; - break; - case 7: - _doSoundType = SCI_VERSION_1_EARLY; - break; - case 8: - _doSoundType = SCI_VERSION_1_LATE; - break; - default: - // Unknown case... should never happen. We fall back to - // alternative detection here, which works in general, apart from - // some transitive games like Jones CD - _doSoundType = foundTarget ? SCI_VERSION_1_LATE : SCI_VERSION_1_EARLY; - break; - } - - if (_doSoundType != SCI_VERSION_NONE) - return true; - } - break; - case kDetectSetCursorType: - // Games with colored mouse cursors call kIsObject before kSetCursor - if (kFuncNum == 6) { // kIsObject (SCI0-SCI11) - foundTarget = true; - } else if (kFuncNum == 40) { // kSetCursor (SCI0-SCI11) - _setCursorType = foundTarget ? SCI_VERSION_1_1 : SCI_VERSION_0_EARLY; - return true; - } - break; -#ifdef ENABLE_SCI32 - case kDetectSci21KernelTable: - if (kFuncNum == 0x40) { - _sci21KernelType = SCI_VERSION_2; - return true; - } else if (kFuncNum == 0x75) { - _sci21KernelType = SCI_VERSION_2_1; - return true; - } - break; -#endif - default: - break; - } - } - break; - - case Script_Offset: - case Script_SRelative: - offset++; - if (!opsize & 1) - offset++; - break; - case Script_End: - offset = 0; // exit loop - break; - default: - warning("opcode %02x: Invalid", opcode); - - } - } - } while (offset > 0); - - // Some games, like KQ5CD, never actually call SetCursor inside Game::setCursor - // but call isObject. Cover this case here, if we're actually reading the selector - // itself, and not iterating through the Game object (i.e. when the selector - // dictionary is missing) - if (featureDetection == kDetectSetCursorType && methodNum == -1 && foundTarget) { - _setCursorType = SCI_VERSION_1_1; - return true; - } - - return false; // not found -} - -SciVersion EngineState::detectDoSoundType() { - if (_doSoundType == SCI_VERSION_NONE) { - if (getSciVersion() == SCI_VERSION_0_EARLY) { - // This game is using early SCI0 sound code (different headers than SCI0 late) - _doSoundType = SCI_VERSION_0_EARLY; - } else if (_kernel->_selectorCache.nodePtr == -1) { - // No nodePtr selector, so this game is definitely using newer - // SCI0 sound code (i.e. SCI_VERSION_0_LATE) - _doSoundType = SCI_VERSION_0_LATE; - } else { - if (getSciVersion() >= SCI_VERSION_1_LATE) { - // All SCI1 late games use the newer doSound semantics - _doSoundType = SCI_VERSION_1_LATE; - } else { - if (!autoDetectFeature(kDetectSoundType)) { - warning("DoSound detection failed, taking an educated guess"); - - if (getSciVersion() >= SCI_VERSION_1_MIDDLE) - _doSoundType = SCI_VERSION_1_LATE; - else if (getSciVersion() > SCI_VERSION_01) - _doSoundType = SCI_VERSION_1_EARLY; - } - } - } - - debugC(1, kDebugLevelSound, "Detected DoSound type: %s", getSciVersionDesc(_doSoundType).c_str()); - } - - return _doSoundType; -} - -SciVersion EngineState::detectSetCursorType() { - if (_setCursorType == SCI_VERSION_NONE) { - if (getSciVersion() <= SCI_VERSION_01) { - // SCI0/SCI01 games never use cursor views - _setCursorType = SCI_VERSION_0_EARLY; - } else if (getSciVersion() >= SCI_VERSION_1_EARLY && getSciVersion() <= SCI_VERSION_1_MIDDLE) { - // SCI1 early/SCI1 middle games never use cursor views - _setCursorType = SCI_VERSION_0_EARLY; - } else if (getSciVersion() >= SCI_VERSION_1_1) { - // SCI1.1 games always use cursor views - _setCursorType = SCI_VERSION_1_1; - } else { // SCI1 late game, detect cursor semantics - bool found = false; - - if (_kernel->_selectorCache.setCursor == -1) { - // Find which function of the Game object calls setCursor - - Object *obj = _segMan->getObject(_gameObj); - for (uint m = 0; m < obj->getMethodCount(); m++) { - found = autoDetectFeature(kDetectSetCursorType, m); - if (found) - break; - } - } else { - found = autoDetectFeature(kDetectSetCursorType); - } - - if (!found) { - // Quite normal in several demos which don't have a cursor - warning("SetCursor detection failed, taking an educated guess"); - - if (getSciVersion() >= SCI_VERSION_1_1) - _setCursorType = SCI_VERSION_1_1; - else - _setCursorType = SCI_VERSION_0_EARLY; - } - } - - debugC(1, kDebugLevelGraphics, "Detected SetCursor type: %s", getSciVersionDesc(_setCursorType).c_str()); - } - - return _setCursorType; -} - -SciVersion EngineState::detectLofsType() { - if (_lofsType == SCI_VERSION_NONE) { - // This detection only works (and is only needed) for SCI 1 - if (getSciVersion() <= SCI_VERSION_01) { - _lofsType = SCI_VERSION_0_EARLY; - return _lofsType; - } - - if (getSciVersion() >= SCI_VERSION_1_1) { - _lofsType = SCI_VERSION_1_1; - return _lofsType; - } - - // Find a function of the game object which invokes lofsa/lofss - reg_t gameClass = _segMan->findObjectByName("Game"); - Object *obj = _segMan->getObject(gameClass); - bool found = false; - - for (uint m = 0; m < obj->getMethodCount(); m++) { - found = autoDetectFeature(kDetectLofsType, m); - - if (found) - break; - } - - if (!found) { - warning("Lofs detection failed, taking an educated guess"); - - if (getSciVersion() >= SCI_VERSION_1_MIDDLE) - _lofsType = SCI_VERSION_1_MIDDLE; - else - _lofsType = SCI_VERSION_0_EARLY; - } - - debugC(1, kDebugLevelVM, "Detected Lofs type: %s", getSciVersionDesc(_lofsType).c_str()); - } - - return _lofsType; -} - -SciVersion EngineState::detectGfxFunctionsType() { - if (_gfxFunctionsType == SCI_VERSION_NONE) { - // This detection only works (and is only needed) for SCI0 games - if (getSciVersion() >= SCI_VERSION_01) { - _gfxFunctionsType = SCI_VERSION_0_LATE; - return _gfxFunctionsType; - } - - if (getSciVersion() > SCI_VERSION_0_EARLY) { - // Check if the game is using an overlay - bool found = false; - - if (_kernel->_selectorCache.overlay == -1) { - // No overlay selector found, check if any method of the Rm object - // is calling kDrawPic, as the overlay selector might be missing in demos - - Object *obj = _segMan->getObject(_segMan->findObjectByName("Rm")); - for (uint m = 0; m < obj->getMethodCount(); m++) { - found = autoDetectFeature(kDetectGfxFunctions, m); - if (found) - break; - } - } - - if (_kernel->_selectorCache.overlay == -1 && !found) { - // No overlay selector found, therefore the game is definitely - // using old graphics functions - _gfxFunctionsType = SCI_VERSION_0_EARLY; - } else if (_kernel->_selectorCache.overlay == -1 && found) { - // Detection already done above - } else { // _kernel->_selectorCache.overlay != -1 - // An in-between case: The game does not have a shiftParser - // selector, but it does have an overlay selector, so it uses an - // overlay. Therefore, check it to see how it calls kDrawPic to - // determine the graphics functions type used - - if (!autoDetectFeature(kDetectGfxFunctions)) { - warning("Graphics functions detection failed, taking an educated guess"); - - // Try detecting the graphics function types from the existence of the motionCue - // selector (which is a bit of a hack) - if (_kernel->findSelector("motionCue") != -1) - _gfxFunctionsType = SCI_VERSION_0_LATE; - else - _gfxFunctionsType = SCI_VERSION_0_EARLY; - } - } - } else { // (getSciVersion() == SCI_VERSION_0_EARLY) - // Old SCI0 games always used old graphics functions - _gfxFunctionsType = SCI_VERSION_0_EARLY; - } - - debugC(1, kDebugLevelVM, "Detected graphics functions type: %s", getSciVersionDesc(_gfxFunctionsType).c_str()); - } - - return _gfxFunctionsType; -} - -#ifdef ENABLE_SCI32 -SciVersion EngineState::detectSci21KernelType() { - if (_sci21KernelType == SCI_VERSION_NONE) - if (!autoDetectFeature(kDetectSci21KernelTable)) - error("Could not detect the SCI2.1 kernel table type"); - - debugC(1, kDebugLevelVM, "Detected SCI2.1 kernel type: %s", getSciVersionDesc(_sci21KernelType).c_str()); - - return _sci21KernelType; -} -#endif - -MoveCountType EngineState::detectMoveCountType() { - if (_moveCountType == kMoveCountUninitialized) { - // SCI0/SCI01 games always increment move count - if (getSciVersion() <= SCI_VERSION_01) { - _moveCountType = kIncrementMoveCount; - } else { - if (!autoDetectFeature(kDetectMoveCountType)) { - warning("Move count autodetection failed"); - _moveCountType = kIncrementMoveCount; // Most games do this, so best guess - } - } - - debugC(1, kDebugLevelVM, "Detected move count handling: %s", (_moveCountType == kIncrementMoveCount) ? "increment" : "ignore"); - } - - return _moveCountType; -} - } // End of namespace Sci |