aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/script_patches.cpp122
-rw-r--r--engines/sci/engine/scriptdebug.cpp84
-rw-r--r--engines/sci/engine/scriptdebug.h4
-rw-r--r--engines/sci/engine/selector.cpp17
-rw-r--r--engines/sci/engine/vm.cpp16
-rw-r--r--engines/sci/engine/workarounds.cpp3
-rw-r--r--engines/sci/graphics/video32.cpp4
-rw-r--r--engines/sci/resource.cpp5
-rw-r--r--engines/sci/resource_audio.cpp41
9 files changed, 226 insertions, 70 deletions
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index fd01a0b541..2a23d26615 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -147,6 +147,7 @@ static const char *const selectorNameTable[] = {
#ifdef ENABLE_SCI32
"newWith", // SCI2 array script
"posn", // SCI2 benchmarking script
+ "printLang", // GK2
"view", // RAMA benchmarking, GK1, QFG4
"fade", // Shivers
"test", // Torin
@@ -260,6 +261,7 @@ enum ScriptPatcherSelectors {
,
SELECTOR_newWith,
SELECTOR_posn,
+ SELECTOR_printLang,
SELECTOR_view,
SELECTOR_fade,
SELECTOR_test,
@@ -3673,6 +3675,66 @@ static const uint16 gk2WagnerPaintingMessagePatch[] = {
PATCH_END
};
+// The game-over rooms 665 and 666 draw a pic over everything by setting the
+// default plane's priority to 202, but this is already inventoryBorderPlane's
+// priority. In our interpreter this causes a border fragment to be drawn above
+// the pics. This worked by luck in Sierra's interpreter because it sorts on
+// memory ID when planes have the same priority. In ScummVM the renderer
+// guarantees a sort order based on the creation order of the planes. The
+// default plane is created first and drawn before inventoryBorderPlane.
+//
+// We fix this by increasing the plane priority in the game-over rooms.
+//
+// Applies to: All versions
+// Responsible methods: gabeNews:init, uDie:init
+// Fixes bug: #11298
+static const uint16 gk2GameOverPrioritySignature[] = {
+ 0x39, SIG_SELECTOR8(priority), // pushi priority
+ SIG_MAGICDWORD,
+ 0x78, // push1
+ 0x38, SIG_UINT16(0x00ca), // pushi 00ca
+ 0x81, 0x03, // lag 03
+ 0x4a, SIG_UINT16(0x0012), // send 12 [ Plane ... priority: 202 ]
+ SIG_END
+};
+
+static const uint16 gk2GameOverPriorityPatch[] = {
+ PATCH_ADDTOOFFSET(+3),
+ 0x38, PATCH_UINT16(0x00cb), // pushi 00cb [ priority: 203 ]
+ PATCH_END
+};
+
+// GK2 fans have created patches that add subtitles to the entire game. There
+// are at least English and Spanish patch sets. Sierra added the subtitle
+// feature solely for the Portuguese version. The fan patches include these
+// subtitle scripts, replace the Portuguese resources and embedded script
+// strings, and configure Sierra's interpreter to use the Portuguese language
+// through RESOURCE.CFG. This sets GK2:printLang which the scripts test for
+// Portuguese in order to activate subtitles.
+//
+// The subtitle patches are compatible with ScummVM except for the requirement
+// that GK2:printLang equals Portuguese (351) since we don't use RESOURCE.CFG.
+// We fix this by patching the GK2:printLang tests to always activate subtitles
+// when a sync resource is present for synchronizing text to video playback.
+//
+// Applies to: PC versions with a subtitle fan-patch applied
+// Responsible methods: Any that test GK2:printLang for Portuguese
+// Fixes bugs: #9677, #11282
+static const uint16 gk2SubtitleCompatibilitySignature[] = {
+ SIG_MAGICDWORD,
+ 0x39, SIG_SELECTOR8(printLang), // pushi printLang
+ 0x76, // push0
+ 0x81, 0x01, // lag 01
+ 0x4a, SIG_UINT16(0x0004), // send 04 [ GK2 printLang? ]
+ SIG_END
+};
+
+static const uint16 gk2SubtitleCompatibilityPatch[] = {
+ 0x34, PATCH_UINT16(0x015f), // ldi 015f [ K_LANG_PORTUGUESE ]
+ 0x33, 0x03, // jmp 03
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry gk2Signatures[] = {
{ true, 0, "disable volume reset on startup", 1, gk2VolumeResetSignature, gk2VolumeResetPatch },
@@ -3682,6 +3744,8 @@ static const SciScriptPatcherEntry gk2Signatures[] = {
{ true, 23, "fix inventory scroll direction (no line numbers)", 1, gk2InventoryScrollDirSignature2, gk2InventoryScrollDirPatch2 },
{ true, 37, "fix sound manager lockup", 1, gk2SoundManagerLockupSignature1, gk2SoundManagerLockupPatch1 },
{ true, 37, "fix sound manager lockup (no line numbers)", 1, gk2SoundManagerLockupSignature2, gk2SoundManagerLockupPatch2 },
+ { true, 665, "fix game-over priority", 1, gk2GameOverPrioritySignature, gk2GameOverPriorityPatch },
+ { true, 666, "fix game-over priority", 1, gk2GameOverPrioritySignature, gk2GameOverPriorityPatch },
{ true, 800, "fix neuschwanstein hint (1/3)", 1, gk2NeuschwansteinHintSignature1, gk2NeuschwansteinHintPatch },
{ true, 800, "fix neuschwanstein hint (2/3)", 1, gk2NeuschwansteinHintSignature2, gk2NeuschwansteinHintPatch },
{ true, 800, "fix neuschwanstein hint (3/3)", 1, gk2NeuschwansteinHintSignature3, gk2NeuschwansteinHintPatch },
@@ -3695,6 +3759,13 @@ static const SciScriptPatcherEntry gk2Signatures[] = {
{ true, 64990, "increase number of save games (1/2)", 1, sci2NumSavesSignature1, sci2NumSavesPatch1 },
{ true, 64990, "increase number of save games (2/2)", 1, sci2NumSavesSignature2, sci2NumSavesPatch2 },
{ true, 64990, "disable change directory button", 1, sci2ChangeDirSignature, sci2ChangeDirPatch },
+ { false, 0, "subtitle patch compatibility", 3, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 11, "subtitle patch compatibility", 7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 12, "subtitle patch compatibility", 5, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 91, "subtitle patch compatibility", 7, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 200, "subtitle patch compatibility", 1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 1300, "subtitle patch compatibility", 1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
+ { false, 64924, "subtitle patch compatibility", 1, gk2SubtitleCompatibilitySignature, gk2SubtitleCompatibilityPatch },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -17013,12 +17084,57 @@ static const uint16 sq1vgaPatchSpiderDroidTiming[] = {
PATCH_END
};
+// The Russian version of SQ1VGA has mangled class names in its scripts. This
+// isn't a problem in Sierra's interpreter since this is just metadata, but our
+// feature detection code looks up several classes by name and requires them to
+// exist. We fix this by patching the Motion, Rm, and Sound strings back to
+// their original values.
+//
+// Applies to: Russian PC Floppy
+// Fixes bug: #10156
+static const uint16 sq1vgaSignatureRussianMotionName[] = {
+ SIG_MAGICDWORD,
+ 0x2A, 0x4D, 0x6F, 0x74, 0x69, // *Motion.
+ 0x6F, 0x6E, 0x20,
+ SIG_END
+};
+
+static const uint16 sq1vgaPatchRussianMotionName[] = {
+ 0x4D, 0x6F, 0x74, 0x69, 0x6F, // Motion
+ 0x6E, 0x00,
+ PATCH_END
+};
+static const uint16 sq1vgaSignatureRussianRmName[] = {
+ SIG_MAGICDWORD,
+ 0x2a, 0x52, 0x6d, 0x00, // *Rm
+ SIG_END
+};
+
+static const uint16 sq1vgaPatchRussianRmName[] = {
+ 0x52, 0x6d, 0x00, // Rm
+ PATCH_END
+};
+
+static const uint16 sq1vgaSignatureRussianSoundName[] = {
+ SIG_MAGICDWORD,
+ 0x87, 0xa2, 0xe3, 0xaa, 0x00, 0x00, // ....
+ SIG_END
+};
+
+static const uint16 sq1vgaPatchRussianSoundName[] = {
+ 0x53, 0x6f, 0x75, 0x63, 0x64, // Sound
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry sq1vgaSignatures[] = {
{ true, 45, "Ulence Flats: timepod graphic glitch", 1, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch },
{ true, 45, "Ulence Flats: force field generator glitch", 1, sq1vgaSignatureUlenceFlatsGeneratorGlitch, sq1vgaPatchUlenceFlatsGeneratorGlitch },
{ true, 58, "Sarien armory droid zapping ego first time", 1, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard },
{ true, 704, "spider droid timing issue", 1, sq1vgaSignatureSpiderDroidTiming, sq1vgaPatchSpiderDroidTiming },
+ { true, 989, "rename russian Sound class", 1, sq1vgaSignatureRussianSoundName, sq1vgaPatchRussianSoundName },
+ { true, 992, "rename russian Motion class", 1, sq1vgaSignatureRussianMotionName, sq1vgaPatchRussianMotionName },
+ { true, 994, "rename russian Rm class", 1, sq1vgaSignatureRussianRmName, sq1vgaPatchRussianRmName },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -18531,6 +18647,12 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
enablePatch(signatureTable, "Mac: skip broken hop singh scene");
}
break;
+ case GID_GK2:
+ // Enable subtitle compatibility if a sync resource is present
+ if (g_sci->getResMan()->testResource(ResourceId(kResourceTypeSync, 10))) {
+ enablePatch(signatureTable, "subtitle patch compatibility");
+ }
+ break;
case GID_KQ5:
if (g_sci->_features->useAltWinGMSound()) {
// See the explanation in the kq5SignatureWinGMSignals comment
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 7a1fe66d35..2f0dd008fc 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -945,32 +945,34 @@ void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr arg
} // switch
}
-void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, reg_t curValue, reg_t newValue, SegManager *segMan, BreakpointType breakpointType) {
+void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, Selector selector, reg_t curValue, reg_t newValue, SegManager *segMan, BreakpointType breakpointType) {
const Object *var_container = obj;
if (!obj->isClass() && getSciVersion() != SCI_VERSION_3)
var_container = segMan->getObject(obj->getSuperClassSelector());
- uint16 varSelector;
- if (getSciVersion() == SCI_VERSION_3) {
- varSelector = index;
- } else {
- index >>= 1;
-
- if (index >= var_container->getVarCount()) {
- // TODO: error, warning, debug?
- return;
+ if (selector == NULL_SELECTOR) {
+ if (getSciVersion() == SCI_VERSION_3) {
+ selector = index;
}
+ else {
+ index >>= 1;
+
+ if (index >= var_container->getVarCount()) {
+ // TODO: error, warning, debug?
+ return;
+ }
- varSelector = var_container->getVarSelector(index);
+ selector = var_container->getVarSelector(index);
+ }
}
- if (g_sci->checkSelectorBreakpoint(breakpointType, objp, varSelector)) {
+ if (g_sci->checkSelectorBreakpoint(breakpointType, objp, selector)) {
// checkSelectorBreakpoint has already triggered the breakpoint.
// We just output the relevant data here.
Console *con = g_sci->getSciDebugger();
const char *objectName = segMan->getObjectName(objp);
- const char *selectorName = g_sci->getKernel()->getSelectorName(varSelector).c_str();
+ const char *selectorName = g_sci->getKernel()->getSelectorName(selector).c_str();
if (breakpointType == BREAK_SELECTORWRITE) {
con->debugPrintf("Write to selector (%s:%s): change %04x:%04x to %04x:%04x\n",
objectName, selectorName,
@@ -986,27 +988,11 @@ void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, reg_t curV
}
}
-void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result) {
- if (s->abortScriptProcessing != kAbortNone) {
- return;
- }
-
- Kernel *kernel = g_sci->getKernel();
- if (!kernelSubCall) {
- debugN("k%s: ", kernelCall->name);
- } else {
- int callNameLen = strlen(kernelCall->name);
- if (strncmp(kernelCall->name, kernelSubCall->name, callNameLen) == 0) {
- const char *subCallName = kernelSubCall->name + callNameLen;
- debugN("k%s(%s): ", kernelCall->name, subCallName);
- } else {
- debugN("k%s(%s): ", kernelCall->name, kernelSubCall->name);
- }
- }
+static void logParameters(const KernelFunction *kernelCall, EngineState *s, int argc, reg_t *argv) {
for (int parmNr = 0; parmNr < argc; parmNr++) {
if (parmNr)
debugN(", ");
- uint16 regType = kernel->findRegType(argv[parmNr]);
+ uint16 regType = g_sci->getKernel()->findRegType(argv[parmNr]);
if (regType & SIG_TYPE_NULL)
debugN("0");
else if (regType & SIG_TYPE_UNINITIALIZED)
@@ -1043,7 +1029,7 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke
// TODO: Any other segment types which could
// use special handling?
- if (kernelCall->function == &kSaid) {
+ if (kernelCall != nullptr && kernelCall->function == &kSaid) {
SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]);
if (saidSpec.isRaw) {
debugN(" ('");
@@ -1064,12 +1050,46 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke
}
}
}
+}
+
+void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result) {
+ if (s->abortScriptProcessing != kAbortNone) {
+ return;
+ }
+
+ if (!kernelSubCall) {
+ debugN("k%s: ", kernelCall->name);
+ } else {
+ int callNameLen = strlen(kernelCall->name);
+ if (strncmp(kernelCall->name, kernelSubCall->name, callNameLen) == 0) {
+ const char *subCallName = kernelSubCall->name + callNameLen;
+ debugN("k%s(%s): ", kernelCall->name, subCallName);
+ } else {
+ debugN("k%s(%s): ", kernelCall->name, kernelSubCall->name);
+ }
+ }
+
+ logParameters(kernelCall, s, argc, argv);
+
if (result.isPointer())
debugN(" = %04x:%04x\n", PRINT_REG(result));
else
debugN(" = %d\n", result.getOffset());
}
+void logExportCall(uint16 script, uint16 pubfunct, EngineState *s, int argc, reg_t *argv) {
+ if (s->abortScriptProcessing != kAbortNone) {
+ return;
+ }
+
+ debugN("script %d, export %d: ", script, pubfunct);
+
+ if (argc > 1) {
+ argv++;
+ logParameters(nullptr, s, argc, argv);
+ }
+ debugN("\n");
+}
void logBacktrace() {
Console *con = g_sci->getSciDebugger();
diff --git a/engines/sci/engine/scriptdebug.h b/engines/sci/engine/scriptdebug.h
index 5e927efaf1..3d54b327d3 100644
--- a/engines/sci/engine/scriptdebug.h
+++ b/engines/sci/engine/scriptdebug.h
@@ -31,10 +31,12 @@ extern const char *opcodeNames[];
void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr argp, ObjVarRef &varp, reg_t funcp, SegManager *segMan, SelectorType selectorType);
-void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, reg_t curValue, reg_t newValue, SegManager *segMan, BreakpointType breakpointType);
+void debugPropertyAccess(Object *obj, reg_t objp, unsigned int index, Selector selector, reg_t curValue, reg_t newValue, SegManager *segMan, BreakpointType breakpointType);
void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result);
+void logExportCall(uint16 script, uint16 pubfunct, EngineState *s, int argc, reg_t *argv);
+
void logBacktrace();
bool printObject(reg_t obj);
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 6196495954..1a63b4dee1 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -23,6 +23,7 @@
#include "sci/sci.h"
#include "sci/engine/features.h"
#include "sci/engine/kernel.h"
+#include "sci/engine/scriptdebug.h"
#include "sci/engine/state.h"
#include "sci/engine/selector.h"
@@ -246,8 +247,14 @@ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
if (lookupSelector(segMan, object, selectorId, &address, NULL) != kSelectorVariable)
return NULL_REG;
- else
- return *address.getPointer(segMan);
+
+ if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
+ reg_t curValue = *address.getPointer(segMan);
+ debugPropertyAccess(segMan->getObject(object), object, 0, selectorId,
+ curValue, NULL_REG, segMan, BREAK_SELECTORREAD);
+ }
+
+ return *address.getPointer(segMan);
}
#ifdef ENABLE_SCI32
@@ -271,6 +278,12 @@ void writeSelector(SegManager *segMan, reg_t object, Selector selectorId, reg_t
error("Selector '%s' of object could not be written to. Address %04x:%04x, %s", g_sci->getKernel()->getSelectorName(selectorId).c_str(), PRINT_REG(object), origin.toString().c_str());
}
+ if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
+ reg_t curValue = *address.getPointer(segMan);
+ debugPropertyAccess(segMan->getObject(object), object, 0, selectorId,
+ curValue, value, segMan, BREAK_SELECTORWRITE);
+ }
+
*address.getPointer(segMan) = value;
#ifdef ENABLE_SCI32
updateInfoFlagViewVisible(segMan->getObject(object), address.varindex);
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index d5bcb63ce4..e8808a715c 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -222,7 +222,9 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
}
// Check if a breakpoint is set on this method
- g_sci->checkExportBreakpoint(script, pubfunct);
+ if (g_sci->checkExportBreakpoint(script, pubfunct)) {
+ logExportCall(script, pubfunct, s, argc, argp);
+ }
uint32 exportAddr = scr->validateExportFunc(pubfunct, false);
if (!exportAddr)
@@ -1133,7 +1135,7 @@ void run_vm(EngineState *s) {
case op_pToa: // 0x31 (49)
// Property To Accumulator
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
validate_property(s, obj, opparams[0]), NULL_REG,
s->_segMan, BREAK_SELECTORREAD);
}
@@ -1145,7 +1147,7 @@ void run_vm(EngineState *s) {
// Accumulator To Property
reg_t &opProperty = validate_property(s, obj, opparams[0]);
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
opProperty, s->r_acc,
s->_segMan, BREAK_SELECTORWRITE);
}
@@ -1162,7 +1164,7 @@ void run_vm(EngineState *s) {
// Property To Stack
reg_t value = validate_property(s, obj, opparams[0]);
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
value, NULL_REG,
s->_segMan, BREAK_SELECTORREAD);
}
@@ -1176,7 +1178,7 @@ void run_vm(EngineState *s) {
reg_t newValue = POP32();
reg_t &opProperty = validate_property(s, obj, opparams[0]);
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
opProperty, newValue,
s->_segMan, BREAK_SELECTORWRITE);
}
@@ -1198,7 +1200,7 @@ void run_vm(EngineState *s) {
reg_t oldValue = opProperty;
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORREAD) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
oldValue, NULL_REG,
s->_segMan, BREAK_SELECTORREAD);
}
@@ -1209,7 +1211,7 @@ void run_vm(EngineState *s) {
opProperty -= 1;
if (g_sci->_debugState._activeBreakpointTypes & BREAK_SELECTORWRITE) {
- debugPropertyAccess(obj, s->xs->objp, opparams[0],
+ debugPropertyAccess(obj, s->xs->objp, opparams[0], NULL_SELECTOR,
oldValue, opProperty,
s->_segMan, BREAK_SELECTORWRITE);
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index ba11883cbc..71046a83cf 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -1247,6 +1247,9 @@ static const SciMessageWorkaroundEntry messageWorkarounds[] = {
// audio36 for the the other has the wrong tuple, which we fix in the audio36 workarounds.
{ GID_GK1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 420, 2, 32, 3, 1, { MSG_WORKAROUND_REMAP, 420, 2, 32, 0, 1, 0, 0, 0, NULL } },
{ GID_GK1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 420, 2, 32, 0, 1, { MSG_WORKAROUND_REMAP, 420, 2, 32, 2, 1, 0, 0, 0, NULL } },
+ // Clicking one of Gabriel's letters on Gerde in room 120 after getting his address in some versions
+ { GID_GK2, SCI_MEDIA_ALL, K_LANG_NONE, -1, 120, 18, 63, 0, 1, { MSG_WORKAROUND_REMAP, 120, 18, 44, 0, 1, 0, 0, 0, NULL } },
+ { GID_GK2, SCI_MEDIA_ALL, K_LANG_NONE, -1, 120, 18, 64, 0, 1, { MSG_WORKAROUND_REMAP, 120, 18, 44, 0, 1, 0, 0, 0, NULL } },
// Clicking any item other than the dagger on theater vent in room 11853
{ GID_GK2, SCI_MEDIA_ALL, K_LANG_NONE, -1, 1185, 4, 0, 0, 1, { MSG_WORKAROUND_REMAP, 1185, 4, 62, 0, 1, 0, 0, 0, NULL } },
// Asking Yvette about Tut in act 2 party in floppy version - bug #10723
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 567660d97a..be62ba7882 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -936,7 +936,9 @@ void VMDPlayer::closeOverlay() {
}
#endif
- g_sci->_gfxFrameout->frameOut(true, _drawRect);
+ if (!_leaveLastFrame && _leaveScreenBlack) {
+ g_sci->_gfxFrameout->frameOut(true, _drawRect);
+ }
}
void VMDPlayer::initComposited() {
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 779bd0acb2..a716a1230d 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -993,6 +993,11 @@ void ResourceManager::init() {
_mapVersion = _volVersion;
}
+ if ((_volVersion == kResVersionSci3) && (_mapVersion < kResVersionSci2)) {
+ warning("Detected volume version is too high for detected map version. Setting volume version to map version");
+ _volVersion = _mapVersion;
+ }
+
debugC(1, kDebugLevelResMan, "resMan: Detected resource map version %d: %s", _mapVersion, versionDescription(_mapVersion));
debugC(1, kDebugLevelResMan, "resMan: Detected volume version %d: %s", _volVersion, versionDescription(_volVersion));
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index c825196d93..73e10eb1ee 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -513,36 +513,23 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
continue;
}
+ // GK2 has invalid audio36 map entries on CD 1 of the German
+ // version and CD 6 of all versions. All are safe to ignore
+ // because their content doesn't apply to the disc's chapter.
if (g_sci->getGameId() == GID_GK2) {
- // At least version 1.00 of the US release, and the German
- // release, of GK2 have multiple invalid audio36 map entries on
- // CD 6
- if (map->_volumeNumber == 6 && offset + syncSize >= srcSize) {
- bool skip;
- switch (g_sci->getLanguage()) {
- case Common::EN_ANY:
- skip = (map->_mapNumber == 22 || map->_mapNumber == 160);
- break;
- case Common::DE_DEU:
- skip = (map->_mapNumber == 22);
- break;
- default:
- skip = false;
- }
-
- if (skip) {
- continue;
- }
+ // Map 2020 on CD 1 only exists in localized versions and
+ // contains inventory messages from later chapters.
+ if (map->_volumeNumber == 1 &&
+ map->_mapNumber == 2020) {
+ continue;
}
- // Map 2020 on CD 1 of the German release of GK2 is invalid.
- // This content does not appear to ever be used by the game (it
- // does not even exist in the US release), and there is a
- // correct copy of it on CD 6, so just ignore the bad copy on
- // CD 1
- if (g_sci->getLanguage() == Common::DE_DEU &&
- map->_volumeNumber == 1 &&
- map->_mapNumber == 2020) {
+ // Maps 22 and 160 on CD 6 appear in various broken forms
+ // in English and apparently every localized version.
+ // These messages are for Grace's notebook and castle
+ // secret passage rooms which aren't in chapter 6.
+ if (map->_volumeNumber == 6 &&
+ (map->_mapNumber == 22 || map->_mapNumber == 160)) {
continue;
}
}