[Scummvm-cvs-logs] SF.net SVN: scummvm:[47850] scummvm/trunk/engines/sci

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Wed Feb 3 12:02:43 CET 2010


Revision: 47850
          http://scummvm.svn.sourceforge.net/scummvm/?rev=47850&view=rev
Author:   thebluegr
Date:     2010-02-03 11:02:43 +0000 (Wed, 03 Feb 2010)

Log Message:
-----------
Placed all the game feature detection code in a separate class

Modified Paths:
--------------
    scummvm/trunk/engines/sci/console.cpp
    scummvm/trunk/engines/sci/engine/game.cpp
    scummvm/trunk/engines/sci/engine/kernel32.cpp
    scummvm/trunk/engines/sci/engine/kevent.cpp
    scummvm/trunk/engines/sci/engine/kgraphics.cpp
    scummvm/trunk/engines/sci/engine/kmovement.cpp
    scummvm/trunk/engines/sci/engine/ksound.cpp
    scummvm/trunk/engines/sci/engine/savegame.cpp
    scummvm/trunk/engines/sci/engine/script.cpp
    scummvm/trunk/engines/sci/engine/state.cpp
    scummvm/trunk/engines/sci/engine/state.h
    scummvm/trunk/engines/sci/engine/vm.cpp
    scummvm/trunk/engines/sci/module.mk
    scummvm/trunk/engines/sci/sci.cpp

Added Paths:
-----------
    scummvm/trunk/engines/sci/engine/features.cpp
    scummvm/trunk/engines/sci/engine/features.h

Modified: scummvm/trunk/engines/sci/console.cpp
===================================================================
--- scummvm/trunk/engines/sci/console.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/console.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -417,11 +417,11 @@
 	DebugPrintf("\n");
 	DebugPrintf("Detected features:\n");
 	DebugPrintf("------------------\n");
-	DebugPrintf("Sound type: %s\n", getSciVersionDesc(s->detectDoSoundType()).c_str());
-	DebugPrintf("Graphics functions type: %s\n", getSciVersionDesc(s->detectGfxFunctionsType()).c_str());
-	DebugPrintf("Lofs type: %s\n", getSciVersionDesc(s->detectLofsType()).c_str());
-	DebugPrintf("Move count type: %s\n", (s->detectMoveCountType() == kIncrementMoveCount) ? "increment" : "ignore");
-	DebugPrintf("SetCursor type: %s\n", getSciVersionDesc(s->detectSetCursorType()).c_str());
+	DebugPrintf("Sound type: %s\n", getSciVersionDesc(s->_features->detectDoSoundType()).c_str());
+	DebugPrintf("Graphics functions type: %s\n", getSciVersionDesc(s->_features->detectGfxFunctionsType()).c_str());
+	DebugPrintf("Lofs type: %s\n", getSciVersionDesc(s->_features->detectLofsType()).c_str());
+	DebugPrintf("Move count type: %s\n", (s->_features->detectMoveCountType() == kIncrementMoveCount) ? "increment" : "ignore");
+	DebugPrintf("SetCursor type: %s\n", getSciVersionDesc(s->_features->detectSetCursorType()).c_str());
 	DebugPrintf("View type: %s\n", viewTypeDesc[s->resMan->getViewType()]);
 	DebugPrintf("Resource volume version: %s\n", s->resMan->getVolVersionDesc());
 	DebugPrintf("Resource map version: %s\n", s->resMan->getMapVersionDesc());
@@ -1592,7 +1592,7 @@
 		return true;
 	}
 
-	SoundResource *soundRes = new SoundResource(number, _engine->getResourceManager(), _engine->_gamestate->detectDoSoundType());
+	SoundResource *soundRes = new SoundResource(number, _engine->getResourceManager(), _engine->_gamestate->_features->detectDoSoundType());
 
 	if (!soundRes) {
 		DebugPrintf("Not a sound resource!\n");

Added: scummvm/trunk/engines/sci/engine/features.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/features.cpp	                        (rev 0)
+++ scummvm/trunk/engines/sci/engine/features.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -0,0 +1,520 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/engine/features.h"
+#include "sci/engine/script.h"
+#include "sci/engine/selector.h"
+#include "sci/engine/vm.h"
+
+namespace Sci {
+
+GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan), _kernel(kernel) {
+	_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
+	_usesCdTrack = Common::File::exists("cdaudio.map");
+}
+
+void GameFeatures::setGameInfo(reg_t gameObj, Common::String gameId) {
+	_gameObj = gameObj;
+	_gameId = gameId;
+}
+
+bool GameFeatures::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
+		assert(!_gameId.empty());
+		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 GameFeatures::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 GameFeatures::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 GameFeatures::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 GameFeatures::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 GameFeatures::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 GameFeatures::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


Property changes on: scummvm/trunk/engines/sci/engine/features.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/sci/engine/features.h
===================================================================
--- scummvm/trunk/engines/sci/engine/features.h	                        (rev 0)
+++ scummvm/trunk/engines/sci/engine/features.h	2010-02-03 11:02:43 UTC (rev 47850)
@@ -0,0 +1,121 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCI_INCLUDE_FEATURES_H
+#define SCI_INCLUDE_FEATURES_H
+
+#include "sci/resource.h"
+#include "sci/engine/seg_manager.h"
+
+namespace Sci {
+
+enum FeatureDetection {
+	kDetectGfxFunctions = 0,
+	kDetectMoveCountType = 1,
+	kDetectSoundType = 2,
+	kDetectSetCursorType = 3,
+	kDetectLofsType = 4,
+	kDetectSci21KernelTable = 5
+};
+
+class GameFeatures {
+public:
+	GameFeatures(SegManager *segMan, Kernel *kernel);
+	~GameFeatures() {}
+
+	void setGameInfo(reg_t gameObj, Common::String gameId);
+
+	/**
+	 * Autodetects the DoSound type
+	 * @return DoSound type, SCI_VERSION_0_EARLY / SCI_VERSION_0_LATE /
+	 *                       SCI_VERSION_1_EARLY / SCI_VERSION_1_LATE
+	 */
+	SciVersion detectDoSoundType();
+
+	/**
+	 * Autodetects the SetCursor type
+	 * @return SetCursor type, SCI_VERSION_0_EARLY / SCI_VERSION_1_1
+	 */
+	SciVersion detectSetCursorType();
+
+	/**
+	 * Autodetects the Lofs type
+	 * @return Lofs type, SCI_VERSION_0_EARLY / SCI_VERSION_1_MIDDLE / SCI_VERSION_1_1
+	 */
+	SciVersion detectLofsType();
+
+	/**
+	 * Autodetects the graphics functions used
+	 * @return Graphics functions type, SCI_VERSION_0_EARLY / SCI_VERSION_0_LATE
+	 */
+	SciVersion detectGfxFunctionsType();
+	
+#ifdef ENABLE_SCI32
+	/**
+	 * Autodetects the kernel functions used in SCI2.1
+	 * @return Graphics functions type, SCI_VERSION_2 / SCI_VERSION_2_1
+	 */
+	SciVersion detectSci21KernelType();
+#endif
+
+	/**
+	 * Applies to all versions before 0.000.502
+	 * Old SCI versions used to interpret the third DrawPic() parameter inversely,
+	 * with the opposite default value (obviously).
+	 * Also, they used 15 priority zones from 42 to 200 instead of 14 priority
+	 * zones from 42 to 190.
+	 */
+	bool usesOldGfxFunctions() { return detectGfxFunctionsType() == SCI_VERSION_0_EARLY; }
+
+	/**
+	 * Autodetects the Bresenham routine used in the actor movement functions
+	 * @return Move count type, kIncrementMoveCnt / kIgnoreMoveCnt
+	 */
+	MoveCountType detectMoveCountType();
+
+	bool handleMoveCount() { return detectMoveCountType() == kIncrementMoveCount; }
+
+	bool usesCdTrack() { return _usesCdTrack; }
+
+private:
+	bool autoDetectFeature(FeatureDetection featureDetection, int methodNum = -1);
+
+	SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType;
+#ifdef ENABLE_SCI32
+	SciVersion _sci21KernelType;
+#endif
+
+	MoveCountType _moveCountType;
+	bool _usesCdTrack;
+
+	SegManager *_segMan;
+	Kernel *_kernel;
+	reg_t _gameObj;
+	Common::String _gameId;
+};
+
+} // End of namespace Sci
+
+#endif // SCI_INCLUDE_ENGINE_H


Property changes on: scummvm/trunk/engines/sci/engine/features.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/sci/engine/game.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/game.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/game.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -221,7 +221,7 @@
 	s->_breakpoints.clear(); // No breakpoints defined
 	s->_activeBreakpointTypes = 0;
 
-	if (s->detectLofsType() == SCI_VERSION_1_MIDDLE)
+	if (s->_features->detectLofsType() == SCI_VERSION_1_MIDDLE)
 		s->_segMan->setExportAreWide(true);
 	else
 		s->_segMan->setExportAreWide(false);
@@ -280,7 +280,7 @@
 
 #ifdef USE_OLD_MUSIC_FUNCTIONS
 	if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND)
-		game_init_sound(s, 0, s->detectDoSoundType());
+		game_init_sound(s, 0, s->_features->detectDoSoundType());
 #endif
 
 	// Load game language into printLang property of game object
@@ -296,7 +296,7 @@
 #ifdef USE_OLD_MUSIC_FUNCTIONS
 		s->_sound.sfx_exit();
 		// Reinit because some other code depends on having a valid state
-		game_init_sound(s, SFX_STATE_FLAG_NOSOUND, s->detectDoSoundType());
+		game_init_sound(s, SFX_STATE_FLAG_NOSOUND, s->_features->detectDoSoundType());
 #else
 		s->_audio->stopAllAudio();
 		s->_soundCmd->clearPlayList();

Modified: scummvm/trunk/engines/sci/engine/kernel32.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kernel32.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/kernel32.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -382,7 +382,7 @@
 	// This is interesting because they all have the same interpreter version (2.100.002), yet
 	// they would not be compatible with other games of the same interpreter.
 
-	if (s->detectSci21KernelType() == SCI_VERSION_2) {
+	if (s->_features->detectSci21KernelType() == SCI_VERSION_2) {
 		_kernelNames = Common::StringList(sci2_default_knames, kKernelEntriesGk2Demo);
 		// OnMe is IsOnMe here, but they should be compatible
 		_kernelNames[0x23] = "Robot"; // Graph in SCI2

Modified: scummvm/trunk/engines/sci/engine/kevent.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kevent.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/kevent.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -151,7 +151,7 @@
 	}
 
 #ifndef USE_OLD_MUSIC_FUNCTIONS
-	if (s->detectDoSoundType() <= SCI_VERSION_0_LATE) {
+	if (s->_features->detectDoSoundType() <= SCI_VERSION_0_LATE) {
 		// If we're running a SCI0 game, update the sound cues, to compensate
 		// for the fact that SCI0 does not poll to update the sound cues itself,
 		// like SCI01 and later do with cmdUpdateSoundCues. kGetEvent is called

Modified: scummvm/trunk/engines/sci/engine/kgraphics.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kgraphics.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/kgraphics.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -190,7 +190,7 @@
 }
 
 reg_t kSetCursor(EngineState *s, int argc, reg_t *argv) {
-	switch (s->detectSetCursorType()) {
+	switch (s->_features->detectSetCursorType()) {
 	case SCI_VERSION_0_EARLY:
 		return kSetCursorSci0(s, argc, argv);
 	case SCI_VERSION_1_1:
@@ -553,7 +553,7 @@
 	if (argc >= 3) {
 		if (!argv[2].isNull())
 			addToFlag = true;
-		if (!s->usesOldGfxFunctions())
+		if (!s->_features->usesOldGfxFunctions())
 			addToFlag = !addToFlag;
 	}
 	if (argc >= 4)

Modified: scummvm/trunk/engines/sci/engine/kmovement.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kmovement.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/kmovement.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -267,7 +267,7 @@
 
 	//printf("movecnt %d, move speed %d\n", movcnt, max_movcnt);
 
-	if (s->handleMoveCount()) {
+	if (s->_features->handleMoveCount()) {
 		if (max_movcnt > movcnt) {
 			++movcnt;
 			PUT_SEL32V(segMan, mover, b_movCnt, movcnt); // Needed for HQ1/Ogre?

Modified: scummvm/trunk/engines/sci/engine/ksound.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/ksound.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/ksound.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -90,7 +90,7 @@
 reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
 	// JonesCD uses different functions based on the cdaudio.map file
 	// to use red book tracks.
-	if (s->usesCdTrack())
+	if (s->_features->usesCdTrack())
 		return kDoCdAudio(s, argc, argv);
 
 	Audio::Mixer *mixer = g_system->getMixer();

Modified: scummvm/trunk/engines/sci/engine/savegame.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/savegame.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -976,7 +976,7 @@
 
 #ifdef USE_OLD_MUSIC_FUNCTIONS
 	temp = retval->_sound._songlib;
-	retval->_sound.sfx_init(retval->resMan, s->sfx_init_flags, s->detectDoSoundType());
+	retval->_sound.sfx_init(retval->resMan, s->sfx_init_flags, s->_features->detectDoSoundType());
 	retval->sfx_init_flags = s->sfx_init_flags;
 	retval->_sound._songlib.freeSounds();
 	retval->_sound._songlib = temp;
@@ -1008,6 +1008,8 @@
 	retval->successor = NULL;
 	retval->_gameId = s->_gameId;
 
+	retval->_features->setGameInfo(retval->_gameObj, retval->_gameId);
+
 #ifdef USE_OLD_MUSIC_FUNCTIONS
 	retval->_sound._it = NULL;
 	retval->_sound._flags = s->_sound._flags;
@@ -1028,7 +1030,7 @@
 	} else {
 #endif
 		retval->_gui->resetEngineState(retval);
-		retval->_gui->init(retval->usesOldGfxFunctions());
+		retval->_gui->init(retval->_features->usesOldGfxFunctions());
 #ifdef ENABLE_SCI32
 	}
 #endif

Modified: scummvm/trunk/engines/sci/engine/script.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/script.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/script.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -95,7 +95,7 @@
 // constructor (?) of a VirtualMachine or a ScriptManager class.
 void script_adjust_opcode_formats(EngineState *s) {
 	// TODO: Check that this is correct
-	if (s->detectLofsType() != SCI_VERSION_0_EARLY) {
+	if (s->_features->detectLofsType() != SCI_VERSION_0_EARLY) {
 		g_opcode_formats[op_lofsa][0] = Script_Offset;
 		g_opcode_formats[op_lofss][0] = Script_Offset;
 	}

Modified: scummvm/trunk/engines/sci/engine/state.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/state.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/state.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -40,6 +40,8 @@
 	sfx_init_flags = 0;
 #endif
 
+	_features = new GameFeatures(_segMan, _kernel);
+
 	restarting_flags = 0;
 
 	last_wait_time = 0;
@@ -72,24 +74,13 @@
 	_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 @@
 	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

Modified: scummvm/trunk/engines/sci/engine/state.h
===================================================================
--- scummvm/trunk/engines/sci/engine/state.h	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/state.h	2010-02-03 11:02:43 UTC (rev 47850)
@@ -37,6 +37,7 @@
 
 #include "sci/sci.h"
 #include "sci/resource.h"
+#include "sci/engine/features.h"
 #include "sci/engine/seg_manager.h"
 
 #include "sci/parser/vocabulary.h"
@@ -113,15 +114,6 @@
 	K_LANG_PORTUGUESE = 351
 };
 
-enum FeatureDetection {
-	kDetectGfxFunctions = 0,
-	kDetectMoveCountType = 1,
-	kDetectSoundType = 2,
-	kDetectSetCursorType = 3,
-	kDetectLofsType = 4,
-	kDetectSci21KernelTable = 5
-};
-
 class FileHandle {
 public:
 	Common::String _name;
@@ -151,6 +143,8 @@
 
 	Common::String _gameId; /**< Designation of the primary object (which inherits from Game) */
 
+	GameFeatures *_features;
+
 	/* Non-VM information */
 
 	GfxAnimate *_gfxAnimate; // Animate for 16-bit gfx
@@ -257,75 +251,6 @@
 
 private:
 	kLanguage charToLanguage(const char c) const;
-
-
-public:
-	// TODO: The following methods and member variables deal with (detecting)
-	// features and capabilities the active game expects to find in the engine.
-	// It should likely be moved to a separate class.
-
-	/**
-	 * Autodetects the DoSound type
-	 * @return DoSound type, SCI_VERSION_0_EARLY / SCI_VERSION_0_LATE /
-	 *                       SCI_VERSION_1_EARLY / SCI_VERSION_1_LATE
-	 */
-	SciVersion detectDoSoundType();
-
-	/**
-	 * Autodetects the SetCursor type
-	 * @return SetCursor type, SCI_VERSION_0_EARLY / SCI_VERSION_1_1
-	 */
-	SciVersion detectSetCursorType();
-
-	/**
-	 * Autodetects the Lofs type
-	 * @return Lofs type, SCI_VERSION_0_EARLY / SCI_VERSION_1_MIDDLE / SCI_VERSION_1_1
-	 */
-	SciVersion detectLofsType();
-
-	/**
-	 * Autodetects the graphics functions used
-	 * @return Graphics functions type, SCI_VERSION_0_EARLY / SCI_VERSION_0_LATE
-	 */
-	SciVersion detectGfxFunctionsType();
-	
-#ifdef ENABLE_SCI32
-	/**
-	 * Autodetects the kernel functions used in SCI2.1
-	 * @return Graphics functions type, SCI_VERSION_2 / SCI_VERSION_2_1
-	 */
-	SciVersion detectSci21KernelType();
-#endif
-
-	/**
-	 * Applies to all versions before 0.000.502
-	 * Old SCI versions used to interpret the third DrawPic() parameter inversely,
-	 * with the opposite default value (obviously).
-	 * Also, they used 15 priority zones from 42 to 200 instead of 14 priority
-	 * zones from 42 to 190.
-	 */
-	bool usesOldGfxFunctions() { return detectGfxFunctionsType() == SCI_VERSION_0_EARLY; }
-
-	/**
-	 * Autodetects the Bresenham routine used in the actor movement functions
-	 * @return Move count type, kIncrementMoveCnt / kIgnoreMoveCnt
-	 */
-	MoveCountType detectMoveCountType();
-
-	bool handleMoveCount() { return detectMoveCountType() == kIncrementMoveCount; }
-
-	bool usesCdTrack() { return _usesCdTrack; }
-
-private:
-	bool autoDetectFeature(FeatureDetection featureDetection, int methodNum = -1);
-
-	SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType;
-#ifdef ENABLE_SCI32
-	SciVersion _sci21KernelType;
-#endif
-
-	MoveCountType _moveCountType;
-	bool _usesCdTrack;
 };
 
 } // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/vm.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/vm.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/engine/vm.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -1361,7 +1361,7 @@
 		case op_lofsa: // 0x39 (57)
 			s->r_acc.segment = scriptState.xs->addr.pc.segment;
 
-			switch (s->detectLofsType()) {
+			switch (s->_features->detectLofsType()) {
 			case SCI_VERSION_1_1:
 				s->r_acc.offset = opparams[0] + local_script->_scriptSize;
 				break;
@@ -1383,7 +1383,7 @@
 		case op_lofss: // 0x3a (58)
 			r_temp.segment = scriptState.xs->addr.pc.segment;
 
-			switch (s->detectLofsType()) {
+			switch (s->_features->detectLofsType()) {
 			case SCI_VERSION_1_1:
 				r_temp.offset = opparams[0] + local_script->_scriptSize;
 				break;

Modified: scummvm/trunk/engines/sci/module.mk
===================================================================
--- scummvm/trunk/engines/sci/module.mk	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/module.mk	2010-02-03 11:02:43 UTC (rev 47850)
@@ -7,6 +7,7 @@
 	event.o \
 	resource.o \
 	sci.o \
+	engine/features.o \
 	engine/game.o \
 	engine/gc.o \
 	engine/kernel.o \

Modified: scummvm/trunk/engines/sci/sci.cpp
===================================================================
--- scummvm/trunk/engines/sci/sci.cpp	2010-02-03 10:36:14 UTC (rev 47849)
+++ scummvm/trunk/engines/sci/sci.cpp	2010-02-03 11:02:43 UTC (rev 47850)
@@ -209,8 +209,10 @@
 	assert(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value != 0);
 	strcpy(_gamestate->sys_strings->_strings[SYS_STRING_SAVEDIR]._value, "");
 
-	SciVersion soundVersion = _gamestate->detectDoSoundType();
+	_gamestate->_features->setGameInfo(_gamestate->_gameObj, _gamestate->_gameId);
 
+	SciVersion soundVersion = _gamestate->_features->detectDoSoundType();
+
 	_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
 
 	screen->unditherSetState(ConfMan.getBool("undither"));
@@ -229,7 +231,7 @@
 		_gamestate->_gui32->init();
 	else
 #endif
-		_gamestate->_gui->init(_gamestate->usesOldGfxFunctions());
+		_gamestate->_gui->init(_gamestate->_features->usesOldGfxFunctions());
 
 	debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()).c_str());
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list