diff options
Diffstat (limited to 'engines/sci/engine')
-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 |
5 files changed, 49 insertions, 25 deletions
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 |