[Scummvm-cvs-logs] scummvm master -> 82165bb6f63290635cedb41b3a8dff1a5d1f5745

m-kiewitz m_kiewitz at users.sourceforge.net
Tue Feb 23 20:17:17 CET 2016


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
82165bb6f6 SCI: Improve kAnimate fastcast detection, Remove EQ1 hack


Commit: 82165bb6f63290635cedb41b3a8dff1a5d1f5745
    https://github.com/scummvm/scummvm/commit/82165bb6f63290635cedb41b3a8dff1a5d1f5745
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-02-23T20:17:18+01:00

Commit Message:
SCI: Improve kAnimate fastcast detection, Remove EQ1 hack

- Add "kAnimate fast cast state" to "version" debug command
- Make it possible for script patcher signatures to get fully
used outside of the regular script patcher
- Remove previous fastcast detections and replace them with
a signature heuristic
- Remove object name checking, when fastcast global is set
- Heuristic detects "fast cast" support incorrectly for multilingual
KQ5, but it seems the game never sets the global, so it won't
matter. KQ5 CD (also SCI1 late) has fastcast support.
- Remove hack in GfxView::draw
- Add lots of comments to ScriptPatcher class

This fixes EcoQuest 1 Floppy showing the anemone on top of the
message box (see bug #5170)

Changed paths:
    engines/sci/console.cpp
    engines/sci/engine/script_patches.cpp
    engines/sci/engine/script_patches.h
    engines/sci/graphics/animate.cpp
    engines/sci/graphics/animate.h
    engines/sci/graphics/view.cpp
    engines/sci/sci.cpp
    engines/sci/sci.h



diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index a395552..cbc6dfa 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -491,6 +491,9 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
 		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()]);
+	if (getSciVersion() <= SCI_VERSION_1_1) {
+		debugPrintf("kAnimate fastCast enabled: %s\n", g_sci->_gfxAnimate->isFastCastEnabled() ? "yes" : "no");
+	}
 	debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no");
 	debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");
 	debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc());
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index fe64752..0ddc8d3 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -3615,20 +3615,20 @@ bool ScriptPatcher::verifySignature(uint32 byteOffset, const uint16 *signatureDa
 }
 
 // will return -1 if no match was found, otherwise an offset to the start of the signature match
-int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) {
+int32 ScriptPatcher::findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize) {
 	if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay
 		return -1;
 
-	const uint32 magicDWord = runtimeEntry->magicDWord; // is platform-specific BE/LE form, so that the later match will work
+	// magicDWord is in platform-specific BE/LE form, so that the later match will work, this was done for performance
 	const uint32 searchLimit = scriptSize - 3;
 	uint32 DWordOffset = 0;
 	// first search for the magic DWORD
 	while (DWordOffset < searchLimit) {
 		if (magicDWord == READ_UINT32(scriptData + DWordOffset)) {
 			// magic DWORD found, check if actual signature matches
-			uint32 offset = DWordOffset + runtimeEntry->magicOffset;
+			uint32 offset = DWordOffset + magicOffset;
 
-			if (verifySignature(offset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize))
+			if (verifySignature(offset, signatureData, patchDescription, scriptData, scriptSize))
 				return offset;
 		}
 		DWordOffset++;
@@ -3637,22 +3637,146 @@ int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, SciS
 	return -1;
 }
 
-// This method calculates the magic DWORD for each entry in the signature table
-//  and it also initializes the selector table for selectors used in the signatures/patches of the current game
-void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
-	const SciScriptPatcherEntry *curEntry = patchTable;
-	SciScriptPatcherRuntimeEntry *curRuntimeEntry;
+int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize) {
+	return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize);
+}
+
+// Attention: Magic DWord is returns using platform specific byte order. This is done on purpose for performance.
+void ScriptPatcher::calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset) {
 	Selector curSelector = -1;
-	int step;
 	int magicOffset;
 	byte magicDWord[4];
 	int magicDWordLeft = 0;
-	const uint16 *curData;
 	uint16 curWord;
 	uint16 curCommand;
 	uint32 curValue;
 	byte byte1 = 0;
 	byte byte2 = 0;
+
+	memset(magicDWord, 0, sizeof(magicDWord));
+
+	curWord = *signatureData;
+	magicOffset = 0;
+	while (curWord != SIG_END) {
+		curCommand = curWord & SIG_COMMANDMASK;
+		curValue   = curWord & SIG_VALUEMASK;
+		switch (curCommand) {
+		case SIG_MAGICDWORD: {
+			if (magicDWordIncluded) {
+				if ((calculatedMagicDWord) || (magicDWordLeft))
+					error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", signatureDescription);
+				magicDWordLeft = 4;
+				calculatedMagicDWordOffset = magicOffset;
+			} else {
+				error("Script-Patcher: Magic-DWORD sequence found in patch data\nFaulty patch: '%s'", signatureDescription);
+			}
+			break;
+		}
+		case SIG_CODE_ADDTOOFFSET: {
+			magicOffset -= curValue;
+			if (magicDWordLeft)
+				error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", signatureDescription);
+			break;
+		}
+		case SIG_CODE_UINT16:
+		case SIG_CODE_SELECTOR16: {
+			// UINT16 or 1
+			switch (curCommand) {
+			case SIG_CODE_UINT16: {
+				signatureData++; curWord = *signatureData;
+				if (curWord & SIG_COMMANDMASK)
+					error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", signatureDescription);
+				if (!_isMacSci11) {
+					byte1 = curValue;
+					byte2 = curWord & SIG_BYTEMASK;
+				} else {
+					byte1 = curWord & SIG_BYTEMASK;
+					byte2 = curValue;
+				}
+				break;
+			}
+			case SIG_CODE_SELECTOR16: {
+				curSelector = _selectorIdTable[curValue];
+				if (curSelector == -1) {
+					curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
+					_selectorIdTable[curValue] = curSelector;
+				}
+				if (!_isMacSci11) {
+					byte1 = curSelector & 0x00FF;
+					byte2 = curSelector >> 8;
+				} else {
+					byte1 = curSelector >> 8;
+					byte2 = curSelector & 0x00FF;
+				}
+				break;
+			}
+			}
+			magicOffset -= 2;
+			if (magicDWordLeft) {
+				// Remember current word for Magic DWORD
+				magicDWord[4 - magicDWordLeft] = byte1;
+				magicDWordLeft--;
+				if (magicDWordLeft) {
+					magicDWord[4 - magicDWordLeft] = byte2;
+					magicDWordLeft--;
+				}
+				if (!magicDWordLeft) {
+					// Magic DWORD is now known, convert to platform specific byte order
+					calculatedMagicDWord = READ_LE_UINT32(magicDWord);
+				}
+			}
+			break;
+		}
+		case SIG_CODE_BYTE:
+		case SIG_CODE_SELECTOR8: {
+			if (curCommand == SIG_CODE_SELECTOR8) {
+				curSelector = _selectorIdTable[curValue];
+				if (curSelector == -1) {
+					curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
+					_selectorIdTable[curValue] = curSelector;
+					if (curSelector != -1) {
+						if (curSelector & 0xFF00)
+							error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", signatureDescription);
+					}
+				}
+				curValue = curSelector;
+			}
+			magicOffset--;
+			if (magicDWordLeft) {
+				// Remember current byte for Magic DWORD
+				magicDWord[4 - magicDWordLeft] = (byte)curValue;
+				magicDWordLeft--;
+				if (!magicDWordLeft) {
+					calculatedMagicDWord = READ_LE_UINT32(magicDWord);
+				}
+			}
+			break;
+		}
+		case PATCH_CODE_GETORIGINALBYTEADJUST: {
+			signatureData++; // skip over extra uint16
+			break;
+		}
+		default:
+			break;
+		}
+		signatureData++;
+		curWord = *signatureData;
+	}
+
+	if (magicDWordLeft)
+		error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", signatureDescription);
+	if (magicDWordIncluded) {
+		if (!calculatedMagicDWord) {
+			error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", signatureDescription);
+		}
+	}
+}
+
+// This method calculates the magic DWORD for each entry in the signature table
+//  and it also initializes the selector table for selectors used in the signatures/patches of the current game
+void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
+	const SciScriptPatcherEntry *curEntry = patchTable;
+	SciScriptPatcherRuntimeEntry *curRuntimeEntry;
 	int patchEntryCount = 0;
 
 	// Count entries and allocate runtime data
@@ -3666,120 +3790,14 @@ void ScriptPatcher::initSignature(const SciScriptPatcherEntry *patchTable) {
 	curRuntimeEntry = _runtimeTable;
 	while (curEntry->signatureData) {
 		// process signature
-		memset(magicDWord, 0, sizeof(magicDWord));
-
 		curRuntimeEntry->active = curEntry->defaultActive;
 		curRuntimeEntry->magicDWord = 0;
 		curRuntimeEntry->magicOffset = 0;
 
-		for (step = 0; step < 2; step++) {
-			switch (step) {
-			case 0: curData = curEntry->signatureData; break;
-			case 1: curData = curEntry->patchData; break;
-			}
-
-			curWord = *curData;
-			magicOffset = 0;
-			while (curWord != SIG_END) {
-				curCommand = curWord & SIG_COMMANDMASK;
-				curValue   = curWord & SIG_VALUEMASK;
-				switch (curCommand) {
-				case SIG_MAGICDWORD: {
-					if (step == 0) {
-						if ((curRuntimeEntry->magicDWord) || (magicDWordLeft))
-							error("Script-Patcher: Magic-DWORD specified multiple times in signature\nFaulty patch: '%s'", curEntry->description);
-						magicDWordLeft = 4;
-						curRuntimeEntry->magicOffset = magicOffset;
-					}
-					break;
-				}
-				case SIG_CODE_ADDTOOFFSET: {
-					magicOffset -= curValue;
-					if (magicDWordLeft)
-						error("Script-Patcher: Magic-DWORD contains AddToOffset command\nFaulty patch: '%s'", curEntry->description);
-					break;
-				}
-				case SIG_CODE_UINT16:
-				case SIG_CODE_SELECTOR16: {
-					// UINT16 or 1
-					switch (curCommand) {
-					case SIG_CODE_UINT16: {
-						curData++; curWord = *curData;
-						if (curWord & SIG_COMMANDMASK)
-							error("Script-Patcher: signature entry inconsistent\nFaulty patch: '%s'", curEntry->description);
-						if (!_isMacSci11) {
-							byte1 = curValue;
-							byte2 = curWord & SIG_BYTEMASK;
-						} else {
-							byte1 = curWord & SIG_BYTEMASK;
-							byte2 = curValue;
-						}
-						break;
-					}
-					case SIG_CODE_SELECTOR16: {
-						curSelector = _selectorIdTable[curValue];
-						if (curSelector == -1) {
-							curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
-							_selectorIdTable[curValue] = curSelector;
-						}
-						if (!_isMacSci11) {
-							byte1 = curSelector & 0x00FF;
-							byte2 = curSelector >> 8;
-						} else {
-							byte1 = curSelector >> 8;
-							byte2 = curSelector & 0x00FF;
-						}
-						break;
-					}
-					}
-					magicOffset -= 2;
-					if (magicDWordLeft) {
-						// Remember current word for Magic DWORD
-						magicDWord[4 - magicDWordLeft] = byte1;
-						magicDWordLeft--;
-						if (magicDWordLeft) {
-							magicDWord[4 - magicDWordLeft] = byte2;
-							magicDWordLeft--;
-						}
-						if (!magicDWordLeft) {
-							curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord);
-						}
-					}
-					break;
-				}
-				case SIG_CODE_BYTE:
-				case SIG_CODE_SELECTOR8: {
-					if (curCommand == SIG_CODE_SELECTOR8) {
-						curSelector = _selectorIdTable[curValue];
-						if (curSelector == -1) {
-							curSelector = g_sci->getKernel()->findSelector(selectorNameTable[curValue]);
-							_selectorIdTable[curValue] = curSelector;
-							if (curSelector != -1) {
-								if (curSelector & 0xFF00)
-									error("Script-Patcher: 8 bit selector required, game uses 16 bit selector\nFaulty patch: '%s'", curEntry->description);
-							}
-						}
-						curValue = curSelector;
-					}
-					magicOffset--;
-					if (magicDWordLeft) {
-						// Remember current byte for Magic DWORD
-						magicDWord[4 - magicDWordLeft] = (byte)curValue;
-						magicDWordLeft--;
-						if (!magicDWordLeft) {
-							curRuntimeEntry->magicDWord = READ_LE_UINT32(magicDWord);
-						}
-					}
-				}
-				}
-				curData++;
-				curWord = *curData;
-			}
-		}
-		if (magicDWordLeft)
-			error("Script-Patcher: Magic-DWORD beyond End-Of-Signature\nFaulty patch: '%s'", curEntry->description);
-		if (!curRuntimeEntry->magicDWord)
-			error("Script-Patcher: Magic-DWORD not specified in signature\nFaulty patch: '%s'", curEntry->description);
+		// We verify the signature data and remember the calculated magic DWord from the signature data
+		calculateMagicDWordAndVerify(curEntry->description, curEntry->signatureData, true, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset);
+		// We verify the patch data
+		calculateMagicDWordAndVerify(curEntry->description, curEntry->patchData, false, curRuntimeEntry->magicDWord, curRuntimeEntry->magicOffset);
 
 		curEntry++; curRuntimeEntry++;
 	}
diff --git a/engines/sci/engine/script_patches.h b/engines/sci/engine/script_patches.h
index d15fce3..645e094 100644
--- a/engines/sci/engine/script_patches.h
+++ b/engines/sci/engine/script_patches.h
@@ -90,13 +90,32 @@ public:
 	ScriptPatcher();
 	~ScriptPatcher();
 
+	// Calculates the magic DWord for fast search and verifies signature/patch data
+	// Returns the magic DWord in platform-specific byte-order. This is done on purpose for performance.
+	void calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset);
+
+	// Called when a script is loaded to check for signature matches and apply patches in such cases
 	void processScript(uint16 scriptNr, byte *scriptData, const uint32 scriptSize);
+
+	// Verifies, if a given signature matches the given script data (pointed to by additional byte offset)
 	bool verifySignature(uint32 byteOffset, const uint16 *signatureData, const char *signatureDescription, const byte *scriptData, const uint32 scriptSize);
 
+	// searches for a given signature inside script data
+	// returns -1 in case it was not found or an offset to the matching data
+	int32 findSignature(uint32 magicDWord, int magicOffset, const uint16 *signatureData, const char *patchDescription, const byte *scriptData, const uint32 scriptSize);
+
 private:
+	// Initializes a patch table and creates run time information for it (for enabling/disabling), also calculates magic DWORD)
 	void initSignature(const SciScriptPatcherEntry *patchTable);
+
+	// Enables a patch inside the patch table (used for optional patches like CD+Text support for KQ6 & LB2)
 	void enablePatch(const SciScriptPatcherEntry *patchTable, const char *searchDescription);
-	int32 findSignature(const SciScriptPatcherEntry *patchEntry, SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize);
+
+	// Searches for a given signature entry inside script data
+	// returns -1 in case it was not found or an offset to the matching data
+	int32 findSignature(const SciScriptPatcherEntry *patchEntry, const SciScriptPatcherRuntimeEntry *runtimeEntry, const byte *scriptData, const uint32 scriptSize);
+
+	// Applies a patch to a given script + offset (overwrites parts)
 	void applyPatch(const SciScriptPatcherEntry *patchEntry, byte *scriptData, const uint32 scriptSize, int32 signatureOffset);
 
 	Selector *_selectorIdTable;
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index fdd81a8..9827839 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -28,6 +28,7 @@
 #include "sci/sci.h"
 #include "sci/event.h"
 #include "sci/engine/kernel.h"
+#include "sci/engine/script_patches.h"
 #include "sci/engine/state.h"
 #include "sci/engine/selector.h"
 #include "sci/engine/vm.h"
@@ -44,8 +45,8 @@
 
 namespace Sci {
 
-GfxAnimate::GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions)
-	: _s(state), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) {
+GfxAnimate::GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions)
+	: _s(state), _scriptPatcher(scriptPatcher), _cache(cache), _ports(ports), _paint16(paint16), _screen(screen), _palette(palette), _cursor(cursor), _transitions(transitions) {
 	init();
 }
 
@@ -55,16 +56,77 @@ GfxAnimate::~GfxAnimate() {
 void GfxAnimate::init() {
 	_lastCastData.clear();
 
-	_ignoreFastCast = false;
-	// fastCast object is not found in any SCI games prior SCI1
-	if (getSciVersion() <= SCI_VERSION_01)
-		_ignoreFastCast = true;
-	// Also if fastCast object exists at gamestartup, we can assume that the interpreter doesn't do kAnimate aborts
-	//  (found in Larry 1)
-	if (getSciVersion() > SCI_VERSION_0_EARLY) {
-		if (!_s->_segMan->findObjectByName("fastCast").isNull())
-			_ignoreFastCast = true;
+	_fastCastEnabled = false;
+	if (getSciVersion() == SCI_VERSION_1_1) {
+		// Seems to have been available for all SCI1.1 games
+		_fastCastEnabled = true;
+	} else if (getSciVersion() >= SCI_VERSION_1_EARLY) {
+		// fastCast only exists for some games between SCI1 early and SCI1 late
+		// Try to detect it by code signature
+		// It's extremely important, that we only enable it for games that actually need it
+		if (detectFastCast()) {
+			_fastCastEnabled = true;
+		}
+	}
+}
+
+// Signature for fastCast detection
+static const uint16 fastCastSignature[] = {
+	SIG_MAGICDWORD,
+	0x35, 0x00,                      // ldi 00
+	0xa1, 84,                        // sag global[84d]
+	SIG_END
+};
+
+// Fast cast in games:
+
+// SCI1 Early:
+// KQ5 - no fastcast, LSL1 (demo) - no fastcast, Mixed Up Fairy Tales - *has fastcast*, XMas Card 1990 - no fastcast,
+// SQ4Floppy - no fastcast, Mixed Up Mother Goose - no fastcast
+//
+// SCI1 Middle:
+// LSL5 demo - no fastfast, Conquest of the Longbow demo - no fastcast, LSL1 - no fastcast,
+// Astro Chicken II - no fastcast
+//
+// SCI1 Late:
+// Castle of Dr. Brain demo - has fastcast, Castle of Dr. Brain - has fastcast,
+// Conquests of the Longbow - has fastcast, Space Quest 1 EGA - has fastcast,
+// King's Quest 5 multilingual - *NO* fastcast, Police Quest 3 demo - *NO* fastcast,
+// LSL5 multilingual - has fastcast, Police Quest 3 - has fastcast,
+// EcoQuest 1 - has fastcast, Mixed Up Fairy Tales demo - has fastcast,
+// Space Quest 4 multilingual - *NO* fastcast
+//
+// SCI1.1
+// Quest for Glory 3 demo - has fastcast, Police Quest 1 - hast fastcast, Quest for Glory 1 - has fastcast
+// Laura Bow 2 Floppy - has fastcast, Mixed Up Mother Goose - has fastcast, Quest for Glory 3 - has fastcast
+// Island of Dr. Brain - has fastcast, King's Quest 6 - has fastcast, Space Quest 5 - has fastcast
+// Hoyle 4 - has fastcast, Laura Bow 2 CD - has fastcast, Freddy Pharkas CD - has fastcast
+bool GfxAnimate::detectFastCast() {
+	SegManager *segMan = _s->_segMan;
+	const reg_t gameVMObject = g_sci->getGameObject();
+	reg_t gameSuperVMObject = segMan->getObject(gameVMObject)->getSuperClassSelector();
+	uint32 magicDWord = 0; // platform-specific BE/LE for performance
+	int    magicDWordOffset = 0;
+
+	if (gameSuperVMObject.isNull()) {
+		gameSuperVMObject = gameVMObject; // Just in case. According to sci.cpp this may happen in KQ5CD, when loading saved games before r54510
+	}
+
+	Script *objectScript = segMan->getScript(gameSuperVMObject.getSegment());
+	byte *scriptData = const_cast<byte *>(objectScript->getBuf(0));
+	uint32 scriptSize = objectScript->getBufSize();
+
+	_scriptPatcher->calculateMagicDWordAndVerify("fast cast detection", fastCastSignature, true, magicDWord, magicDWordOffset);
+
+	// Signature is found for multilingual King's Quest 5 too, but it looks as if the fast cast global is never set
+	// within that game. Which means even though we detect it as having the capability, it's never actually used.
+	// The original multilingual KQ5 interpreter did have this feature disabled.
+	// Sierra probably used latest system scripts and that's why we detect it.
+	if (_scriptPatcher->findSignature(magicDWord, magicDWordOffset, fastCastSignature, "fast cast detection", scriptData, scriptSize) >= 0) {
+		// Signature found, game seems to use fast cast for kAnimate
+		return true;
 	}
+	return false;
 }
 
 void GfxAnimate::disposeLastCast() {
@@ -80,12 +142,14 @@ bool GfxAnimate::invoke(List *list, int argc, reg_t *argv) {
 	while (curNode) {
 		curObject = curNode->value;
 
-		if (!_ignoreFastCast) {
+		if (_fastCastEnabled) {
 			// Check if the game has a fastCast object set
 			//  if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes.
 			if (!_s->variables[VAR_GLOBAL][84].isNull()) {
-				if (!strcmp(_s->_segMan->getObjectName(_s->variables[VAR_GLOBAL][84]), "fastCast"))
-					return false;
+				// This normally points to an object called "fastCast",
+				// but for example in Eco Quest 1 it may also point to an object called "EventHandler" (see bug #5170)
+				// Original SCI only checked, if this global was not 0.
+				return false;
 			}
 		}
 
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 6c1822c..ac70780 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -87,9 +87,13 @@ class GfxView;
  */
 class GfxAnimate {
 public:
-	GfxAnimate(EngineState *state, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions);
+	GfxAnimate(EngineState *state, ScriptPatcher *scriptPatcher, GfxCache *cache, GfxPorts *ports, GfxPaint16 *paint16, GfxScreen *screen, GfxPalette *palette, GfxCursor *cursor, GfxTransitions *transitions);
 	virtual ~GfxAnimate();
 
+	bool isFastCastEnabled() {
+		return _fastCastEnabled;
+	}
+
 	void disposeLastCast();
 	bool invoke(List *list, int argc, reg_t *argv);
 	void makeSortedList(List *list);
@@ -110,6 +114,7 @@ public:
 
 private:
 	void init();
+	bool detectFastCast();
 
 	void addToPicSetPicNotValid();
 	void animateShowPic();
@@ -119,6 +124,7 @@ private:
 	void setNsRect(GfxView *view, AnimateList::iterator it);
 
 	EngineState *_s;
+	ScriptPatcher *_scriptPatcher;
 	GfxCache *_cache;
 	GfxPorts *_ports;
 	GfxPaint16 *_paint16;
@@ -130,7 +136,7 @@ private:
 	AnimateList _list;
 	AnimateArray _lastCastData;
 
-	bool _ignoreFastCast;
+	bool _fastCastEnabled;
 };
 
 } // End of namespace Sci
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 2ee18b5..4116eda 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -833,19 +833,6 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
 
 	bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left);
 
-	// WORKAROUND: EcoQuest French and German draw the fish and anemone sprites
-	// with priority 15 in scene 440. Afterwards, a dialog is shown on top of
-	// these sprites with priority 15 as well. This is undefined behavior
-	// actually, as the sprites and dialog share the same priority, so in our
-	// implementation the sprites get drawn incorrectly on top of the dialog.
-	// Perhaps this worked by mistake in SSCI because of subtle differences in
-	// how sprites are drawn. We compensate for this by resetting the priority
-	// of all sprites that have a priority of 15 in scene 440 to priority 14,
-	// so that the speech bubble can be drawn correctly on top of them. Fixes
-	// bug #3040625.
-	if (g_sci->getGameId() == GID_ECOQUEST && g_sci->getEngineState()->currentRoomNumber() == 440 && priority == 15)
-		priority = 14;
-
 	if (!_EGAmapping) {
 		for (y = 0; y < height; y++, bitmap += celWidth) {
 			for (x = 0; x < width; x++) {
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index cce0235..577abb2 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -717,7 +717,7 @@ void SciEngine::initGraphics() {
 		_gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16);
 		_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio);
 		_gfxPaint = _gfxPaint16;
-		_gfxAnimate = new GfxAnimate(_gamestate, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions);
+		_gfxAnimate = new GfxAnimate(_gamestate, _scriptPatcher, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions);
 		_gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen);
 		_gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen);
 		_gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor);
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 5c86d92..3945e68 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -282,7 +282,7 @@ public:
 	inline EngineState *getEngineState() const { return _gamestate; }
 	inline Vocabulary *getVocabulary() const { return _vocabulary; }
 	inline EventManager *getEventManager() const { return _eventMan; }
-	inline reg_t getGameObject() const { return _gameObjectAddress; }
+	inline reg_t getGameObject() const { return _gameObjectAddress; } // Gets the game object VM address
 
 	Common::RandomSource &getRNG() { return _rng; }
 






More information about the Scummvm-git-logs mailing list