diff options
Diffstat (limited to 'engines/sci')
| -rw-r--r-- | engines/sci/detection.cpp | 5 | ||||
| -rw-r--r-- | engines/sci/detection_tables.h | 8 | ||||
| -rw-r--r-- | engines/sci/engine/features.cpp | 6 | ||||
| -rw-r--r-- | engines/sci/engine/script_patches.cpp | 24 | ||||
| -rw-r--r-- | engines/sci/engine/vm_types.cpp | 32 | ||||
| -rw-r--r-- | engines/sci/engine/vm_types.h | 2 | ||||
| -rw-r--r-- | engines/sci/engine/workarounds.cpp | 10 | ||||
| -rw-r--r-- | engines/sci/graphics/picture.cpp | 16 | ||||
| -rw-r--r-- | engines/sci/sci.h | 1 | 
9 files changed, 70 insertions, 34 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 09c348f273..883a4d965b 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -105,9 +105,8 @@ static const PlainGameDescriptor s_sciGameTitles[] = {  	// === SCI2.1 games ========================================================  	{"chest",           "Inside the Chest"},	// aka Behind the Developer's Shield  	{"gk2",             "The Beast Within: A Gabriel Knight Mystery"}, -	// TODO: Inside The Chest/Behind the Developer's Shield  	{"kq7",             "King's Quest VII: The Princeless Bride"}, -	// TODO: King's Questions +	{"kquestions",      "King's Questions"},  	{"lsl6hires",       "Leisure Suit Larry 6: Shape Up or Slip Out!"},  	{"mothergoosehires","Mixed-Up Mother Goose Deluxe"},  	{"phantasmagoria",  "Phantasmagoria"}, @@ -161,6 +160,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = {  	{ "kq5",             GID_KQ5 },  	{ "kq6",             GID_KQ6 },  	{ "kq7",             GID_KQ7 }, +	{ "kquestions",      GID_KQUESTIONS },  	{ "laurabow",        GID_LAURABOW },  	{ "laurabow2",       GID_LAURABOW2 },  	{ "lighthouse",      GID_LIGHTHOUSE }, @@ -242,6 +242,7 @@ static const OldNewIdTableEntry s_oldNewTable[] = {  	// kq5 is the same  	// kq6 is the same  	{ "kq7cd",		"kq7",				SCI_VERSION_NONE     }, +	{ "quizgame-demo", "kquestions",    SCI_VERSION_NONE     },  	{ "mm1",		"laurabow",			SCI_VERSION_NONE     },  	{ "cb1",		"laurabow",			SCI_VERSION_NONE     },  	{ "lb2",		"laurabow2",		SCI_VERSION_NONE     }, diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 7c4638a992..92e77cead9 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1656,6 +1656,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {  		AD_LISTEND},  	 	Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI)	}, +	// King's Questions mini-game from the King's Quest Collection +	// SCI interpreter version 2.000.000 +	{"kquestions", "", { +		{"resource.000", 0, "9b1cddecd4f0720d83661ba7aed28891", 162697}, +		{"resource.map", 0, "93a2251fa64e729d7a7d2fe56b217c8e", 502}, +		AD_LISTEND}, +	 	Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO3(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI)	}, +  #endif // ENABLE_SCI32  	// Laura Bow - English Amiga diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 6005ac50be..c26c787fbd 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -467,9 +467,9 @@ bool GameFeatures::autoDetectSci21KernelType() {  		// seen it happen in the RAMA demo, thus we can assume that the  		// game is using a SCI2.1 table -		// HACK: The Inside the Chest Demo doesn't have sounds at all, but -		// it's using a SCI2 kernel -		if (g_sci->getGameId() == GID_CHEST) { +		// HACK: The Inside the Chest Demo and King's Questions minigame +		// don't have sounds at all, but they're using a SCI2 kernel +		if (g_sci->getGameId() == GID_CHEST || g_sci->getGameId() == GID_KQUESTIONS) {  			_sci21KernelType = SCI_VERSION_2;  			return true;  		} diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 20c5c52178..d4dddb6faf 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -953,10 +953,10 @@ const uint16 qfg1vgaPatchDialogHeader[] = {  // When clicking on the crusher in room 331, Ego approaches him to talk to him,  // an action that is handled by moveToCrusher::changeState in script 331. The -// scripts set Ego to move close to the crusher, but when Ego is running instead +// scripts set Ego to move close to the crusher, but when Ego is sneaking instead  // of walking, the target coordinates specified by script 331 are never reached,  // as Ego is making larger steps, and never reaches the required spot. This is an -// edge case that can occur when Ego is set to run. Normally, when clicking on +// edge case that can occur when Ego is set to sneak. Normally, when clicking on  // the crusher, ego is supposed to move close to position 79, 165. We change it  // to 85, 165, which is not an edge case thus the freeze is avoided.  // Fixes bug #3585189. @@ -976,6 +976,25 @@ const uint16 qfg1vgaPatchMoveToCrusher[] = {  	PATCH_END  }; +// Same pathfinding bug as above, where Ego is set to move to an impossible +// spot when sneaking. In GuardsTrumpet::changeState, we change the final +// location where Ego is moved from 111, 111 to 114, 114. Fixes bug #3604939. +const byte qfg1vgaSignatureMoveToCastleGate[] = { +	7, +	0x51, 0x1f,       // class MoveTo +	0x36,             // push +	0x39, 0x6f,       // pushi 6f (111 - x) +	0x3c,             // dup (111 - y) +	0x7c,             // pushSelf +	0 +}; + +const uint16 qfg1vgaPatchMoveToCastleGate[] = { +	PATCH_ADDTOOFFSET | +3, +	0x39, 0x72,       // pushi 72 (114 - x) +	PATCH_END +}; +  //    script, description,                                      magic DWORD,                                  adjust  const SciScriptSignature qfg1vgaSignatures[] = {  	{    215, "fight event issue",                           1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07),    -1, qfg1vgaSignatureFightEvents,       qfg1vgaPatchFightEvents }, @@ -983,6 +1002,7 @@ const SciScriptSignature qfg1vgaSignatures[] = {  	{    814, "window text temp space",                      1, PATCH_MAGICDWORD(0x3f, 0xba, 0x87, 0x00),     0, qfg1vgaSignatureTempSpace,         qfg1vgaPatchTempSpace },  	{    814, "dialog header offset",                        3, PATCH_MAGICDWORD(0x5b, 0x04, 0x80, 0x36),     0, qfg1vgaSignatureDialogHeader,      qfg1vgaPatchDialogHeader },  	{    331, "moving to crusher",                           1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39),     0, qfg1vgaSignatureMoveToCrusher,     qfg1vgaPatchMoveToCrusher }, +	{     41, "moving to castle gate",                       1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39),     0, qfg1vgaSignatureMoveToCastleGate,  qfg1vgaPatchMoveToCastleGate },  	SCI_SIGNATUREENTRY_TERMINATOR  }; diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index 27015d9be4..5327dd1a2e 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -28,12 +28,12 @@  namespace Sci { -reg_t reg_t::lookForWorkaround(const reg_t right) const { +reg_t reg_t::lookForWorkaround(const reg_t right, const char *operation) const {  	SciTrackOriginReply originReply;  	SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, arithmeticWorkarounds, &originReply);  	if (solution.type == WORKAROUND_NONE) -		error("Invalid arithmetic operation (params: %04x:%04x and %04x:%04x) from method %s::%s (room %d, script %d, localCall %x)", -		PRINT_REG(*this), PRINT_REG(right), originReply.objectName.c_str(), +		error("Invalid arithmetic operation (%s - params: %04x:%04x and %04x:%04x) from method %s::%s (room %d, script %d, localCall %x)", +		operation, PRINT_REG(*this), PRINT_REG(right), originReply.objectName.c_str(),  		originReply.methodName.c_str(), g_sci->getEngineState()->currentRoomNumber(), originReply.scriptNr,  		originReply.localCallOffset);  	assert(solution.type == WORKAROUND_FAKE); @@ -55,7 +55,7 @@ reg_t reg_t::operator+(const reg_t right) const {  		case SEG_TYPE_DYNMEM:  			return make_reg(getSegment(), getOffset() + right.toSint16());  		default: -			return lookForWorkaround(right); +			return lookForWorkaround(right, "addition");  		}  	} else if (isNumber() && right.isPointer()) {  		// Adding a pointer to a number, flip the order @@ -64,7 +64,7 @@ reg_t reg_t::operator+(const reg_t right) const {  		// Normal arithmetics  		return make_reg(0, toSint16() + right.toSint16());  	} else { -		return lookForWorkaround(right); +		return lookForWorkaround(right, "addition");  	}  } @@ -82,14 +82,14 @@ reg_t reg_t::operator*(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toSint16() * right.toSint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "multiplication");  }  reg_t reg_t::operator/(const reg_t right) const {  	if (isNumber() && right.isNumber() && !right.isNull())  		return make_reg(0, toSint16() / right.toSint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "division");  }  reg_t reg_t::operator%(const reg_t right) const { @@ -109,21 +109,21 @@ reg_t reg_t::operator%(const reg_t right) const {  			result += modulo;  		return make_reg(0, result);  	} else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "modulo");  }  reg_t reg_t::operator>>(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toUint16() >> right.toUint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "shift right");  }  reg_t reg_t::operator<<(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toUint16() << right.toUint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "shift left");  }  reg_t reg_t::operator+(int16 right) const { @@ -140,7 +140,7 @@ uint16 reg_t::requireUint16() const {  	else  		// The right parameter is NULL_REG because  		// we're not comparing *this with anything here. -		return lookForWorkaround(NULL_REG).toUint16(); +		return lookForWorkaround(NULL_REG, "require unsigned number").toUint16();  }  int16 reg_t::requireSint16() const { @@ -149,28 +149,28 @@ int16 reg_t::requireSint16() const {  	else  		// The right parameter is NULL_REG because  		// we're not comparing *this with anything here. -		return lookForWorkaround(NULL_REG).toSint16(); +		return lookForWorkaround(NULL_REG, "require signed number").toSint16();  }  reg_t reg_t::operator&(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toUint16() & right.toUint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "bitwise AND");  }  reg_t reg_t::operator|(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toUint16() | right.toUint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "bitwise OR");  }  reg_t reg_t::operator^(const reg_t right) const {  	if (isNumber() && right.isNumber())  		return make_reg(0, toUint16() ^ right.toUint16());  	else -		return lookForWorkaround(right); +		return lookForWorkaround(right, "bitwise XOR");  }  int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { @@ -184,7 +184,7 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {  	} else if (right.pointerComparisonWithInteger(*this)) {  		return -1;  	} else -		return lookForWorkaround(right).toSint16(); +		return lookForWorkaround(right, "comparison").toSint16();  }  bool reg_t::pointerComparisonWithInteger(const reg_t right) const { diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index 9a7589e9a7..22bd8beaa1 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -156,7 +156,7 @@ private:  	 * - a negative number if *this < right  	 */  	int cmp(const reg_t right, bool treatAsUnsigned) const; -	reg_t lookForWorkaround(const reg_t right) const; +	reg_t lookForWorkaround(const reg_t right, const char *operation) const;  	bool pointerComparisonWithInteger(const reg_t right) const;  }; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 6f0b34b457..154ac8f8b4 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -37,6 +37,7 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {  	{ GID_ECOQUEST2,      100,    0,  0,               "Rain", "points",      0xce0,    0, { WORKAROUND_FAKE,   0 } }, // Same as above, for the Spanish version - bug #3313962  	{ GID_FANMADE,        516,  983,  0,             "Wander", "setTarget",      -1,    0, { WORKAROUND_FAKE,   0 } }, // op_mul: The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913  	{ GID_GK1,            800,64992,  0,                "Fwd", "doit",           -1,    0, { WORKAROUND_FAKE,   1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7 +	{ GID_HOYLE4,         700,   -1,  1,               "Code", "doit",           -1,    0, { WORKAROUND_FAKE,   1 } }, // op_add: while bidding in Bridge, an object ("Bid") is added to an object in another segment ("hand3")  	{ GID_ICEMAN,         199,  977,  0,            "Grooper", "doit",           -1,    0, { WORKAROUND_FAKE,   0 } }, // op_add: While dancing with the girl  	{ GID_MOTHERGOOSE256,  -1,  999,  0,              "Event", "new",            -1,    0, { WORKAROUND_FAKE,   0 } }, // op_and: constantly during the game (SCI1 version)  	{ GID_MOTHERGOOSE256,  -1,    4,  0,              "rm004", "doit",           -1,    0, { WORKAROUND_FAKE,   0 } }, // op_or: when going north and reaching the castle (rooms 4 and 37) - bug #3038228 @@ -50,6 +51,7 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = {  //    gameID,           room,script,lvl,          object-name, method-name,    call,index,  workaround  const SciWorkaroundEntry uninitializedReadWorkarounds[] = { +	{ GID_CAMELOT,        40,    40,  0,               "Rm40", "handleEvent",    -1,    0, { WORKAROUND_FAKE,   0 } }, // when looking at the ground at the pool of Siloam - bug #3614968  	{ GID_CASTLEBRAIN,   280,   280,  0,         "programmer", "dispatchEvent",  -1,    0, { WORKAROUND_FAKE, 0xf } }, // pressing 'q' on the computer screen in the robot room, and closing the help dialog that pops up (bug #3039656). Moves the cursor to the view with the ID returned (in this case, the robot hand)  	{ GID_CNICK_KQ,       -1,     0,  1,          "Character", "say",            -1,   -1, { WORKAROUND_FAKE,   0 } }, // checkers/backgammon, like in hoyle 3 - temps 504 and 505 - bug #3606025  	{ GID_CNICK_KQ,       -1,   700,  0,           "gcWindow", "open",           -1,   -1, { WORKAROUND_FAKE,   0 } }, // when entering the control menu, like in hoyle 3 @@ -74,9 +76,11 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {  	{ GID_HOYLE4,         -1,     0,  0,                 NULL, "open",           -1,   -1, { WORKAROUND_FAKE,   0 } }, // when selecting "Control" from the menu (temp vars 0-3) - bug #3039294  	{ GID_HOYLE4,        910,    18,  0,                 NULL, "init",           -1,    0, { WORKAROUND_FAKE,   0 } }, // during tutorial - bug #3042756  	{ GID_HOYLE4,        910,   910,  0,                 NULL, "setup",          -1,    3, { WORKAROUND_FAKE,   0 } }, // when selecting "Tutorial" from the main menu - bug #3039294 -	{ GID_HOYLE4,        700,   718,  0,       "compete_tree", "doit",           -1,   75, { WORKAROUND_FAKE,   0 } }, // when placing a bid in bridge - bug #3292332 -	{ GID_HOYLE4,        700,   716,  0,        "other1_tree", "doit",           -1,   46, { WORKAROUND_FAKE,   0 } }, // sometimes when placing a bid in bridge -	{ GID_HOYLE4,        700,   700,  1,         "BridgeHand", "calcQTS",        -1,    3, { WORKAROUND_FAKE,   0 } }, // sometimes when placing a bid in bridge +	{ GID_HOYLE4,        700,   700,  1,         "BridgeHand", "calcQTS",        -1,    3, { WORKAROUND_FAKE,   0 } }, // when placing a bid in bridge (always) +	{ GID_HOYLE4,        700,   710,  1, "BridgeStrategyPlay", "checkSplitTops", -1,   10, { WORKAROUND_FAKE,   0 } }, // while playing bridge, objects LeadReturn_Trump, SecondSeat_Trump, ThirdSeat_Trump and others - bug #3361925 +	{ GID_HOYLE4,        700,    -1,  1,      "BridgeDefense", "think",          -1,   -1, { WORKAROUND_FAKE,   0 } }, // sometimes while playing bridge, temp var 3, 17 and others, objects LeadReturn_Trump, ThirdSeat_Trump and others +	{ GID_HOYLE4,        700,   730,  1,      "BridgeDefense", "beatTheirBest",  -1,    3, { WORKAROUND_FAKE,   0 } }, // rarely while playing bridge +	{ GID_HOYLE4,        700,    -1,  1,               "Code", "doit",           -1,   -1, { WORKAROUND_FAKE,   0 } }, // when placing a bid in bridge (always), temp var 11, 24, 27, 46, 75, objects compete_tree, compwe_tree, other1_tree, b1 - bugs #3292332 and #3361925  	{ GID_HOYLE4,        300,   300,  0,                   "", "export 2",   0x1d4d,    0, { WORKAROUND_FAKE,   0 } }, // after passing around cards in hearts  	{ GID_HOYLE4,        400,   400,  1,            "GinHand", "calcRuns",       -1,    4, { WORKAROUND_FAKE,   0 } }, // sometimes while playing Gin Rummy (e.g. when knocking and placing a card) - bug #3292334  	{ GID_HOYLE4,        500,    17,  1,          "Character", "say",            -1,  504, { WORKAROUND_FAKE,   0 } }, // sometimes while playing Cribbage (e.g. when the opponent says "Last Card") - bug #3292327 diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index af372640da..91c72456a8 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -236,7 +236,9 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos  	byte *ptr = NULL;  	byte *headerPtr = inbuffer + headerPos;  	byte *rlePtr = inbuffer + rlePos; -	int16 displaceX, displaceY; +	// displaceX, displaceY fields are ignored, and may contain garbage +	// (e.g. pic 261 in Dr. Brain 1 Spanish - bug #3614914) +	//int16 displaceX, displaceY;  	byte priority = _addToFlag ? _priority : 0;  	byte clearColor;  	bool compression = true; @@ -251,8 +253,8 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos  		// Width/height here are always LE, even in Mac versions  		width = READ_LE_UINT16(headerPtr + 0);  		height = READ_LE_UINT16(headerPtr + 2); -		displaceX = (signed char)headerPtr[4]; -		displaceY = (unsigned char)headerPtr[5]; +		//displaceX = (signed char)headerPtr[4]; +		//displaceY = (unsigned char)headerPtr[5];  		if (_resourceType == SCI_PICTURE_TYPE_SCI11)  			// SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise  			clearColor = _screen->getColorWhite(); @@ -262,16 +264,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos  	} else {  		width = READ_SCI11ENDIAN_UINT16(headerPtr + 0);  		height = READ_SCI11ENDIAN_UINT16(headerPtr + 2); -		displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!? -		displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!? +		//displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!? +		//displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!?  		clearColor = headerPtr[8];  		if (headerPtr[9] == 0)  			compression = false;  	}  #endif -	if (displaceX || displaceY) -		error("unsupported embedded cel-data in picture"); +	//if (displaceX || displaceY) +	//	error("unsupported embedded cel-data in picture");  	// We will unpack cel-data into a temporary buffer and then plot it to screen  	//  That needs to be done cause a mirrored picture may be requested diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 3b9844b326..0a75e115fd 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -138,6 +138,7 @@ enum SciGameId {  	GID_KQ5,  	GID_KQ6,  	GID_KQ7, +	GID_KQUESTIONS,  	GID_LAURABOW,  	GID_LAURABOW2,  	GID_LIGHTHOUSE,  | 
