aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp125
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/detection.cpp2
-rw-r--r--engines/sci/detection_tables.h2
-rw-r--r--engines/sci/engine/features.h11
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h1
-rw-r--r--engines/sci/engine/kstring.cpp12
-rw-r--r--engines/sci/engine/kvideo.cpp5
-rw-r--r--engines/sci/engine/message.cpp12
-rw-r--r--engines/sci/engine/message.h2
-rw-r--r--engines/sci/engine/savegame.cpp25
-rw-r--r--engines/sci/engine/script_patches.cpp19
-rw-r--r--engines/sci/engine/segment.h13
-rw-r--r--engines/sci/engine/workarounds.cpp16
-rw-r--r--engines/sci/engine/workarounds.h1
-rw-r--r--engines/sci/graphics/celobj32.cpp28
-rw-r--r--engines/sci/graphics/lists32.h7
-rw-r--r--engines/sci/graphics/palette32.h1
-rw-r--r--engines/sci/graphics/screen.cpp5
-rw-r--r--engines/sci/graphics/text32.cpp2
-rw-r--r--engines/sci/graphics/transitions32.cpp2
-rw-r--r--engines/sci/graphics/video32.cpp161
-rw-r--r--engines/sci/graphics/video32.h18
-rw-r--r--engines/sci/parser/vocabulary.cpp2
-rw-r--r--engines/sci/resource.cpp32
-rw-r--r--engines/sci/resource.h1
-rw-r--r--engines/sci/sci.cpp4
28 files changed, 333 insertions, 178 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 8737c8b954..83f1271252 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -53,6 +53,7 @@
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
#include "sci/graphics/paint32.h"
+#include "sci/graphics/palette32.h"
#include "video/coktel_decoder.h"
#endif
@@ -228,6 +229,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("view_listnode", WRAP_METHOD(Console, cmdViewListNode));
registerCmd("view_reference", WRAP_METHOD(Console, cmdViewReference));
registerCmd("vr", WRAP_METHOD(Console, cmdViewReference)); // alias
+ registerCmd("dump_reference", WRAP_METHOD(Console, cmdDumpReference));
+ registerCmd("dr", WRAP_METHOD(Console, cmdDumpReference)); // alias
registerCmd("view_object", WRAP_METHOD(Console, cmdViewObject));
registerCmd("vo", WRAP_METHOD(Console, cmdViewObject)); // alias
registerCmd("active_object", WRAP_METHOD(Console, cmdViewActiveObject));
@@ -446,6 +449,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf(" value_type - Determines the type of a value\n");
debugPrintf(" view_listnode - Examines the list node at the given address\n");
debugPrintf(" view_reference / vr - Examines an arbitrary reference\n");
+ debugPrintf(" dump_reference / dr - Dumps an arbitrary reference to disk\n");
debugPrintf(" view_object / vo - Examines the object at the given address\n");
debugPrintf(" active_object - Shows information on the currently active object or class\n");
debugPrintf(" acc_object - Shows information on the object or class at the address indexed by the accumulator\n");
@@ -2843,6 +2847,125 @@ bool Console::cmdViewReference(int argc, const char **argv) {
return true;
}
+bool Console::cmdDumpReference(int argc, const char **argv) {
+ if (argc < 2) {
+ debugPrintf("Dumps an arbitrary reference to disk.\n");
+ debugPrintf("Usage: %s <start address> [<end address>]\n", argv[0]);
+ debugPrintf("Where <start address> is the starting address to dump\n");
+ debugPrintf("<end address>, if provided, is the address where the dump ends\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ reg_t reg = NULL_REG;
+ reg_t reg_end = NULL_REG;
+
+ if (parse_reg_t(_engine->_gamestate, argv[1], &reg, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ if (argc > 2) {
+ if (parse_reg_t(_engine->_gamestate, argv[2], &reg_end, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+ }
+
+ if (reg.getSegment() == 0 && reg.getOffset() == 0) {
+ debugPrintf("Register is null.\n");
+ return true;
+ }
+
+ if (g_sci->getKernel()->findRegType(reg) != SIG_TYPE_REFERENCE) {
+ debugPrintf("%04x:%04x is not a reference\n", PRINT_REG(reg));
+ return true;
+ }
+
+ if (reg_end.getSegment() != reg.getSegment() && reg_end != NULL_REG) {
+ debugPrintf("Ending segment different from starting segment. Assuming no bound on dump.\n");
+ reg_end = NULL_REG;
+ }
+
+ Common::DumpFile out;
+ Common::String outFileName;
+ uint32 bytesWritten;
+
+ switch (_engine->_gamestate->_segMan->getSegmentType(reg.getSegment())) {
+#ifdef ENABLE_SCI32
+ case SEG_TYPE_BITMAP: {
+ outFileName = Common::String::format("%04x_%04x.tga", PRINT_REG(reg));
+ out.open(outFileName);
+ SciBitmap &bitmap = *_engine->_gamestate->_segMan->lookupBitmap(reg);
+ const Color *color = g_sci->_gfxPalette32->getCurrentPalette().colors;
+ const uint16 numColors = ARRAYSIZE(g_sci->_gfxPalette32->getCurrentPalette().colors);
+
+ out.writeByte(0); // image id length
+ out.writeByte(1); // color map type (present)
+ out.writeByte(1); // image type (uncompressed color-mapped)
+ out.writeSint16LE(0); // index of first color map entry
+ out.writeSint16LE(numColors); // number of color map entries
+ out.writeByte(24); // number of bits per color entry (RGB24)
+ out.writeSint16LE(0); // bottom-left x-origin
+ out.writeSint16LE(bitmap.getHeight() - 1); // bottom-left y-origin
+ out.writeSint16LE(bitmap.getWidth()); // width
+ out.writeSint16LE(bitmap.getHeight()); // height
+ out.writeByte(8); // bits per pixel
+ out.writeByte(1 << 5); // origin of pixel data (top-left)
+
+ bytesWritten = 18;
+
+ for (int i = 0; i < numColors; ++i) {
+ out.writeByte(color->b);
+ out.writeByte(color->g);
+ out.writeByte(color->r);
+ ++color;
+ }
+
+ bytesWritten += numColors * 3;
+ bytesWritten += out.write(bitmap.getPixels(), bitmap.getWidth() * bitmap.getHeight());
+ break;
+ }
+#endif
+
+ default: {
+ const SegmentRef block = _engine->_gamestate->_segMan->dereference(reg);
+ uint32 size = block.maxSize;
+
+ if (size == 0) {
+ debugPrintf("Size of reference is zero.\n");
+ return true;
+ }
+
+ if (reg_end.getSegment() != 0 && (size < reg_end.getOffset() - reg.getOffset())) {
+ debugPrintf("Block end out of bounds (size %d). Resetting.\n", size);
+ reg_end = NULL_REG;
+ }
+
+ if (reg_end.getSegment() != 0 && (size >= reg_end.getOffset() - reg.getOffset())) {
+ size = reg_end.getOffset() - reg.getOffset();
+ }
+
+ if (reg_end.getSegment() != 0) {
+ debugPrintf("Block size less than or equal to %d\n", size);
+ }
+
+ outFileName = Common::String::format("%04x_%04x.dmp", PRINT_REG(reg));
+ out.open(outFileName);
+ bytesWritten = out.write(block.raw, size);
+ break;
+ }
+ }
+
+ out.finalize();
+ out.close();
+
+ debugPrintf("Wrote %u bytes to %s\n", bytesWritten, outFileName.c_str());
+ return true;
+}
+
bool Console::cmdViewObject(int argc, const char **argv) {
if (argc != 2) {
debugPrintf("Examines the object at the given address.\n");
@@ -4530,7 +4653,7 @@ int Console::printObject(reg_t pos) {
uint i;
if (!obj) {
- debugPrintf("[%04x:%04x]: Not an object.", PRINT_REG(pos));
+ debugPrintf("[%04x:%04x]: Not an object.\n", PRINT_REG(pos));
return 1;
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 0b87a4408b..d4b17ee802 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -163,6 +163,7 @@ private:
bool cmdValueType(int argc, const char **argv);
bool cmdViewListNode(int argc, const char **argv);
bool cmdViewReference(int argc, const char **argv);
+ bool cmdDumpReference(int argc, const char **argv);
bool cmdViewObject(int argc, const char **argv);
bool cmdViewActiveObject(int argc, const char **argv);
bool cmdViewAccumulatorObject(int argc, const char **argv);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 83f1d30916..a00da7c5fd 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -556,7 +556,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
s_fallbackDesc.guiOptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
if (allFiles.contains("resource.map") || allFiles.contains("Data1")
- || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
+ || allFiles.contains("resmap.000") || allFiles.contains("resmap.001")) {
foundResMap = true;
}
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 22d2b6f308..4a3d13cbed 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -3398,7 +3398,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by alonzotg in bug report #3206006)
+ // Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy v1.001 Int#0.000.566 (supplied by alonzotg in bug report #3206006)
{"qfg1", "", {
{"resource.map", 0, "85512508ed4e4ef1e3b309adabceeda9", 6486},
{"resource.000", 0, "481b034132106390cb5160fe61dd5f58", 80334},
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 15c80a7277..36b0d06360 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -117,6 +117,17 @@ public:
inline bool hasNewPaletteCode() const {
return getSciVersion() >= SCI_VERSION_2_1_MIDDLE || g_sci->getGameId() == GID_KQ7;
}
+
+ inline bool VMDOpenStopsAudio() const {
+ // Of the games that use VMDs:
+ // Yes: Phant1, Shivers, Torin
+ // No: SQ6
+ // TODO: Optional extra flag to kPlayVMD which defaults to Yes: PQ:SWAT
+ // TODO: SCI3, GK2 (GK2's VMD code is closer to SCI3 than SCI21)
+ return getSciVersion() == SCI_VERSION_2_1_MIDDLE &&
+ g_sci->getGameId() != GID_SQ6 &&
+ g_sci->getGameId() != GID_GK2;
+ }
#endif
/**
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index cce9a223d3..03c8a673a8 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -466,6 +466,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDIgnorePalettes(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDGetStatus(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 6e88112992..8093147cb4 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -466,6 +466,7 @@ static const SciKernelMapSubEntry kPlayVMD_subops[] = {
{ SIG_SINCE_SCI21, 0, MAP_CALL(PlayVMDOpen), "r(i)(i)", NULL },
{ SIG_SINCE_SCI21, 1, MAP_CALL(PlayVMDInit), "ii(i)(i)(ii)", NULL },
{ SIG_SINCE_SCI21, 6, MAP_CALL(PlayVMDClose), "", NULL },
+ { SIG_SINCE_SCI21, 7, MAP_CALL(PlayVMDIgnorePalettes), "", NULL },
{ SIG_SINCE_SCI21, 10, MAP_CALL(PlayVMDGetStatus), "", NULL },
{ SIG_SINCE_SCI21, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL },
{ SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL },
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 6ec61343b0..74c1f99778 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -733,11 +733,12 @@ namespace {
}
bool isSignedType(const char type) {
- return type == 'd' || type == 'i';
+ // For whatever reason, %d ends up being treated as unsigned in SSCI
+ return type == 'i';
}
bool isUnsignedType(const char type) {
- return strchr("uxXoc", type);
+ return strchr("duxXoc", type);
}
bool isStringType(const char type) {
@@ -805,8 +806,11 @@ Common::String format(const Common::String &source, int argc, const reg_t *argv)
continue;
}
- assert(argIndex < argc);
- out += readPlaceholder(in, argv[argIndex++]);
+ if (argIndex < argc) {
+ out += readPlaceholder(in, argv[argIndex++]);
+ } else {
+ out += readPlaceholder(in, NULL_REG);
+ }
} else {
out += *in++;
}
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 83a02883af..11378d7647 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -428,6 +428,11 @@ reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_video32->getVMDPlayer().close());
}
+reg_t kPlayVMDIgnorePalettes(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().ignorePalettes();
+ return s->r_acc;
+}
+
reg_t kPlayVMDGetStatus(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_video32->getVMDPlayer().getStatus());
}
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index b0615b4213..26ab9b47a5 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -333,12 +333,14 @@ void MessageState::popCursorStack() {
error("Message: attempt to pop from empty stack");
}
-int MessageState::hexDigitToInt(char h) {
+int MessageState::hexDigitToWrongInt(char h) {
+ // Hex digits above 9 are incorrectly interpreted by SSCI as 11-16 instead
+ // of 10-15 because of a never-fixed typo
if ((h >= 'A') && (h <= 'F'))
- return h - 'A' + 10;
+ return h - 'A' + 11;
if ((h >= 'a') && (h <= 'f'))
- return h - 'a' + 10;
+ return h - 'a' + 11;
if ((h >= '0') && (h <= '9'))
return h - '0';
@@ -355,8 +357,8 @@ bool MessageState::stringHex(Common::String &outStr, const Common::String &inStr
if (index + 2 >= inStr.size())
return false;
- int digit1 = hexDigitToInt(inStr[index + 1]);
- int digit2 = hexDigitToInt(inStr[index + 2]);
+ int digit1 = hexDigitToWrongInt(inStr[index + 1]);
+ int digit2 = hexDigitToWrongInt(inStr[index + 2]);
// Check for hex
if ((digit1 == -1) || (digit2 == -1))
diff --git a/engines/sci/engine/message.h b/engines/sci/engine/message.h
index ff76534d2d..5847e4767e 100644
--- a/engines/sci/engine/message.h
+++ b/engines/sci/engine/message.h
@@ -73,7 +73,7 @@ private:
bool getRecord(CursorStack &stack, bool recurse, MessageRecord &record);
void outputString(reg_t buf, const Common::String &str);
Common::String processString(const char *s);
- int hexDigitToInt(char h);
+ int hexDigitToWrongInt(char h);
bool stringHex(Common::String &outStr, const Common::String &inStr, uint &index);
bool stringLit(Common::String &outStr, const Common::String &inStr, uint &index);
bool stringStage(Common::String &outStr, const Common::String &inStr, uint &index);
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 2e4da46b70..720f6783ee 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -643,20 +643,33 @@ void SoundCommandParser::reconstructPlayList() {
_music->_mutex.unlock();
for (MusicList::iterator i = songs.begin(); i != songs.end(); ++i) {
- initSoundResource(*i);
+ MusicEntry *entry = *i;
+ initSoundResource(entry);
- if ((*i)->status == kSoundPlaying) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && entry->isSample) {
+ const reg_t &soundObj = entry->soundObj;
+
+ if ((int)readSelectorValue(_segMan, soundObj, SELECTOR(loop)) != -1 &&
+ readSelector(_segMan, soundObj, SELECTOR(handle)) != NULL_REG) {
+
+ writeSelector(_segMan, soundObj, SELECTOR(handle), NULL_REG);
+ processPlaySound(soundObj, entry->playBed);
+ }
+ } else
+#endif
+ if (entry->status == kSoundPlaying) {
// WORKAROUND: PQ3 (German?) scripts can set volume negative in the
// sound object directly without going through DoSound.
// Since we re-read this selector when re-playing the sound after loading,
// this will lead to unexpected behaviour. As a workaround we
// sync the sound object's selectors here. (See bug #5501)
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(loop), (*i)->loop);
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(priority), (*i)->priority);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(loop), entry->loop);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(priority), entry->priority);
if (_soundVersion >= SCI_VERSION_1_EARLY)
- writeSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol), (*i)->volume);
+ writeSelectorValue(_segMan, entry->soundObj, SELECTOR(vol), entry->volume);
- processPlaySound((*i)->soundObj, (*i)->playBed);
+ processPlaySound(entry->soundObj, entry->playBed);
}
}
}
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 5ac4b758ba..5f3370bad5 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -2190,8 +2190,27 @@ static const SciScriptPatcherEntry larry6Signatures[] = {
#pragma mark -
#pragma mark Leisure Suit Larry 6 Hires
+// When entering room 270 (diving board) from room 230, a typo in the game
+// script means that `setScale` is called accidentally instead of `setScaler`.
+// In SSCI this did not do much because the first argument happened to be
+// smaller than the y-position of `ego`, but in ScummVM the first argument is
+// larger and so a debug message "y value less than vanishingY" is displayed.
+static const uint16 larry6HiresSignatureSetScale[] = {
+ SIG_MAGICDWORD,
+ 0x38, SIG_UINT16(0x14b), // pushi 014b (setScale)
+ 0x38, SIG_UINT16(0x05), // pushi 0005
+ 0x51, 0x2c, // class 2c (Scaler)
+ SIG_END
+};
+
+static const uint16 larry6HiresPatchSetScale[] = {
+ 0x38, SIG_UINT16(0x14f), // pushi 014f (setScaler)
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry larry6HiresSignatures[] = {
+ { true, 270, "fix incorrect setScale call", 1, larry6HiresSignatureSetScale, larry6HiresPatchSetScale },
{ true, 64990, "increase number of save games", 1, sci2NumSavesSignature1, sci2NumSavesPatch1 },
{ true, 64990, "increase number of save games", 1, sci2NumSavesSignature2, sci2NumSavesPatch2 },
{ true, 64990, "disable change directory button", 1, sci2ChangeDirSignature, sci2ChangeDirPatch },
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index 361c1cb895..e8f0be3a79 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -552,8 +552,17 @@ public:
case kArrayTypeID:
return ((reg_t *)_data)[index];
case kArrayTypeByte:
- case kArrayTypeString:
- return make_reg(0, ((byte *)_data)[index]);
+ case kArrayTypeString: {
+ int16 value;
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ value = ((int8 *)_data)[index];
+ } else {
+ value = ((uint8 *)_data)[index];
+ }
+
+ return make_reg(0, value);
+ }
default:
error("Invalid array type %d", _type);
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index dabf79a54b..4e9c59b225 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -399,6 +399,7 @@ const SciWorkaroundEntry kAbs_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kArraySetElements_workarounds[] = {
+ { GID_GK1, 302, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when erasing a letter on the wall in St Louis Cemetery
{ GID_PHANTASMAGORIA,902, 64918, 0, "Str", "callKernel", NULL, 0, { WORKAROUND_FAKE, 0 } }, // tries to set an element of a string array to the ego object when starting a new game and selecting a chapter above 1
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -684,21 +685,6 @@ const SciWorkaroundEntry kNewWindow_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
-const SciWorkaroundEntry kNumCels_workarounds[] = {
- { GID_GK1, 460, 64998, -1, "GKEgo", "lastCel", NULL, -1, { WORKAROUND_FAKE, 5 } }, // when Gabriel clicks "ask" on the bartender from a distance
- { GID_GK1, 808, 64998, -1, "sDJEnters", "changeState", NULL, -1, { WORKAROUND_FAKE, 6 } }, //
- { GID_GK2, 470, 64998, -1, "pLookieLoos", "lastCel", NULL, -1, { WORKAROUND_FAKE, 50 } }, // random background movement in the crime scene in Munich city centre
- { GID_GK2, 470, 64998, -1, "pNewsCrew", "lastCel", NULL, -1, { WORKAROUND_FAKE, 18 } }, // random background movement in the crime scene in Munich city centre
- { GID_GK2, 470, 64998, -1, "pLeberGroup", "lastCel", NULL, -1, { WORKAROUND_FAKE, 22 } }, // random background movement in the crime scene in Munich city centre
- { GID_SQ6, 270, 64998, -1, "offWorld", "lastCel", NULL, -1, { WORKAROUND_FAKE, 3 } }, // when exiting the kidnapping room
- { GID_SQ6, 320, 64998, -1, "wandererB", "lastCel", NULL, -1, { WORKAROUND_FAKE, 8 } }, // random background movement on Polysorbate LX street 3
- { GID_SQ6, 340, 64998, -1, "wandererB", "lastCel", NULL, -1, { WORKAROUND_FAKE, 8 } }, // random background movement on Polysorbate LX street 1
- { GID_SQ6, 530, 64998, -1, "monitors", "lastCel", NULL, -1, { WORKAROUND_FAKE, 5 } }, // random background movement during cutscene
- { GID_SQ6, 680, 64998, -1, "ego", "lastCel", NULL, -1, { WORKAROUND_FAKE, 44 } }, // when double-clicking hand icon on blockage
- SCI_WORKAROUNDENTRY_TERMINATOR
-};
-
-// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kPalVarySetPercent_workarounds[] = {
{ GID_GK1, 370, 370, 0, "graceComeOut", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // there's an extra parameter in GK1, when changing chapters. This extra parameter seems to be a bug or just unimplemented functionality, as there's no visible change from the original in the chapter change room
SCI_WORKAROUNDENTRY_TERMINATOR
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index c50a7fb04e..2d72ae5811 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -85,7 +85,6 @@ extern const SciWorkaroundEntry kIsObject_workarounds[];
extern const SciWorkaroundEntry kMemory_workarounds[];
extern const SciWorkaroundEntry kMoveCursor_workarounds[];
extern const SciWorkaroundEntry kNewWindow_workarounds[];
-extern const SciWorkaroundEntry kNumCels_workarounds[];
extern const SciWorkaroundEntry kPalVarySetPercent_workarounds[];
extern const SciWorkaroundEntry kRandom_workarounds[];
extern const SciWorkaroundEntry kReadNumber_workarounds[];
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index 430500ce1e..09ea05bd59 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -800,7 +800,7 @@ int16 CelObjView::getNumLoops(const GuiResourceId viewId) {
return resource->data[2];
}
-int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
+int16 CelObjView::getNumCels(const GuiResourceId viewId, int16 loopNo) {
const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, viewId), false);
if (!resource) {
@@ -813,25 +813,15 @@ int16 CelObjView::getNumCels(const GuiResourceId viewId, const int16 loopNo) {
// Every version of SCI32 has a logic error in this function that causes
// random memory to be read if a script requests the cel count for one
- // past the maximum loop index. At least GK1 room 800 does this, and gets
- // stuck in an infinite loop because the game script expects this method
- // to return a non-zero value.
- // The scope of this bug means it is likely to pop up in other games, so we
- // explicitly trap the bad condition here and report it so that any other
- // game scripts relying on this broken behavior can be fixed as well
+ // past the maximum loop index. For example, GK1 room 808 does this, and
+ // gets stuck in an infinite loop because the game script expects this
+ // method to return a non-zero value.
+ // This bug is triggered in basically every SCI32 game and appears to be
+ // universally fixable simply by always using the next lowest loop instead.
if (loopNo == loopCount) {
- SciCallOrigin origin;
- SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kNumCels_workarounds, &origin);
- switch (solution.type) {
- case WORKAROUND_NONE:
- error("[CelObjView::getNumCels]: loop number %d is equal to loop count in view %u, %s", loopNo, viewId, origin.toString().c_str());
- case WORKAROUND_FAKE:
- return (int16)solution.value;
- case WORKAROUND_IGNORE:
- return 0;
- case WORKAROUND_STILLCALL:
- break;
- }
+ const SciCallOrigin origin = g_sci->getEngineState()->getCurrentCallOrigin();
+ debugC(kDebugLevelWorkarounds, "Workaround: kNumCels loop %d -> loop %d in view %u, %s", loopNo, loopNo - 1, viewId, origin.toString().c_str());
+ --loopNo;
}
if (loopNo > loopCount || loopNo < 0) {
diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h
index 4f74c77325..ff0bc6ceae 100644
--- a/engines/sci/graphics/lists32.h
+++ b/engines/sci/graphics/lists32.h
@@ -170,6 +170,13 @@ public:
}
/**
+ * The maximum number of elements the container is able to hold.
+ */
+ size_type max_size() const {
+ return N;
+ }
+
+ /**
* The number of populated slots in the array. The size
* of the array will only go down once `pack` is called.
*/
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index 81e9bbbfd3..c4cfb35096 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -23,7 +23,6 @@
#ifndef SCI_GRAPHICS_PALETTE32_H
#define SCI_GRAPHICS_PALETTE32_H
-#include "sci/graphics/palette.h"
namespace Sci {
#pragma mark HunkPalette
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 23e92ef6a9..de6df39bb9 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -84,11 +84,6 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) {
}
}
- if (_resMan->detectHires()) {
- _scriptWidth = 640;
- _scriptHeight = 480;
- }
-
// if not yet set, set those to script-width/height
if (!_width)
_width = _scriptWidth;
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index d142ff75c3..7375fdeffd 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -527,7 +527,7 @@ int16 GfxText32::getTextWidth(const uint index, uint length) const {
--length;
}
} else {
- width += font->getCharWidth(currentChar);
+ width += font->getCharWidth((unsigned char)currentChar);
}
if (length > 0) {
diff --git a/engines/sci/graphics/transitions32.cpp b/engines/sci/graphics/transitions32.cpp
index ddcb50b140..bad0185179 100644
--- a/engines/sci/graphics/transitions32.cpp
+++ b/engines/sci/graphics/transitions32.cpp
@@ -778,7 +778,7 @@ bool GfxTransitions32::processPixelDissolve21Mid(const PlaneShowStyle &showStyle
int seq = 1;
uint iteration = 0;
- const uint numIterationsPerTick = ARRAYSIZE(g_sci->_gfxFrameout->_showList);
+ const uint numIterationsPerTick = g_sci->_gfxFrameout->_showList.max_size();
clearShowRects();
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 1db66644c8..bf0c990015 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -28,6 +28,7 @@
#include "engine.h" // for Engine, g_engine
#include "engines/util.h" // for initGraphics
#include "sci/console.h" // for Console
+#include "sci/engine/features.h" // for GameFeatures
#include "sci/engine/state.h" // for EngineState
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/event.h" // for SciEvent, EventManager, SCI_...
@@ -39,10 +40,12 @@
#include "sci/graphics/plane32.h" // for Plane, PlanePictureCodes::kP...
#include "sci/graphics/screen_item32.h" // for ScaleInfo, ScreenItem, Scale...
#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion
-#include "sci/graphics/video32.h"
+#include "sci/sound/audio32.h" // for Audio32
#include "sci/video/seq_decoder.h" // for SEQDecoder
#include "video/avi_decoder.h" // for AVIDecoder
#include "video/coktel_decoder.h" // for AdvancedVMDDecoder
+#include "sci/graphics/video32.h"
+
namespace Graphics { struct Surface; }
namespace Sci {
@@ -68,7 +71,8 @@ void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const
// mechanism that is very similar to that used by the VMD player, which
// allows the SEQ to be drawn into a bitmap ScreenItem and displayed using
// the normal graphics system.
- _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
@@ -163,49 +167,37 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
_pixelDouble = false;
if (!width || !height) {
- width = _decoder->getWidth();
- height = _decoder->getHeight();
- } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
- // KQ7 1.51 provides an explicit width and height when it wants scaling,
- // though the width and height it provides are not scaled
- _pixelDouble = true;
- width *= 2;
- height *= 2;
- }
-
- // QFG4CD gives non-multiple-of-2 values for width and height,
- // which would normally be OK except the source video is a pixel bigger
- // in each dimension
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ const Ratio screenToScriptX(scriptWidth, screenWidth);
+ const Ratio screenToScriptY(scriptHeight, screenHeight);
+ width = (_decoder->getWidth() * screenToScriptX).toInt();
+ height = (_decoder->getHeight() * screenToScriptY).toInt();
+ }
+
+ // QFG4CD gives non-multiple-of-2 values for width and height of the intro
+ // video, which would normally be OK except the source video is a pixel
+ // bigger in each dimension so it just causes part of the video to get cut
+ // off
width = (width + 1) & ~1;
height = (height + 1) & ~1;
- _drawRect.left = x;
- _drawRect.top = y;
- _drawRect.right = x + width;
- _drawRect.bottom = y + height;
-
- // SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the
- // one play routine which automatically pixel-doubles in hi-res mode
- if (getSciVersion() == SCI_VERSION_2) {
- // This is somewhat of a hack; credits.avi from GK1 is not
- // rendered correctly in SSCI because it is a 640x480 video, but the
- // game script gives the wrong dimensions. Since this is the only
- // high-resolution AVI ever used, just set the draw rectangle to draw
- // the entire screen
- if (_decoder->getWidth() > 320) {
- _drawRect.left = 0;
- _drawRect.top = 0;
- _drawRect.right = 320;
- _drawRect.bottom = 200;
- }
-
- // In hi-res mode, video will be pixel doubled, so the origin (which
- // corresponds to the correct position without pixel doubling) needs to
- // be corrected
- if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() <= 320) {
- _drawRect.left /= 2;
- _drawRect.top /= 2;
- }
+ // GK1 CREDITS.AVI is not rendered correctly in SSCI because it is a 640x480
+ // video and the game script gives the wrong dimensions.
+ // Since this is the only high-resolution AVI ever used by any SCI game,
+ // just set the draw rectangle to draw across the entire screen
+ if (g_sci->getGameId() == GID_GK1 && _decoder->getWidth() > 320) {
+ _drawRect.left = 0;
+ _drawRect.top = 0;
+ _drawRect.right = 320;
+ _drawRect.bottom = 200;
+ } else {
+ _drawRect.left = x;
+ _drawRect.top = y;
+ _drawRect.right = x + width;
+ _drawRect.bottom = y + height;
}
init();
@@ -222,8 +214,8 @@ AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) {
_drawRect.top = y;
_drawRect.right = x + _decoder->getWidth() * 2;
_drawRect.bottom = y + _decoder->getHeight() * 2;
-
_pixelDouble = true;
+
init();
return kIOSuccess;
@@ -233,42 +225,38 @@ void AVIPlayer::init() {
int16 xRes;
int16 yRes;
- bool useScreenDimensions = false;
- if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) {
- useScreenDimensions = true;
- }
-
- // KQ7 1.51 gives video position in screen coordinates, not game
- // coordinates, because in SSCI they are passed to Video for Windows, which
- // renders as an overlay on the game video. Because we put the video into a
- // ScreenItem instead of rendering directly to the hardware surface, the
- // coordinates need to be converted to game script coordinates
- if (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY) {
- useScreenDimensions = !_pixelDouble;
- // This y-translation is arbitrary, based on what roughly centers the
- // videos in the game window
- _drawRect.translate(-_drawRect.left / 2, -_drawRect.top * 2 / 3);
- }
-
- if (useScreenDimensions) {
+ // GK1 CREDITS.AVI or KQ7 1.51 half-size videos
+ if ((g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) ||
+ (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY && _drawRect.width() <= 160)) {
xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
} else {
xRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ const Ratio videoRatio(_decoder->getWidth(), _decoder->getHeight());
+ const Ratio screenRatio(4, 3);
+
+ // Videos that already have a 4:3 aspect ratio should not receive any
+ // aspect ratio correction
+ if (videoRatio == screenRatio) {
+ yRes = 240;
+ } else {
+ yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ }
}
_plane = new Plane(_drawRect);
g_sci->_gfxFrameout->addPlane(*_plane);
if (_decoder->getPixelFormat().bytesPerPixel == 1) {
- _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
celInfo.bitmap = _bitmap;
- _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo());
+ _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(), ScaleInfo());
g_sci->_gfxFrameout->addScreenItem(*_screenItem);
g_sci->_gfxFrameout->frameOut(true);
} else {
@@ -384,7 +372,7 @@ void AVIPlayer::renderFrame() const {
const uint8 *end = (const uint8 *)surface->getPixels() + surface->w * surface->h;
while (source != end) {
- uint8 value = *source++;
+ const uint8 value = *source++;
*target++ = value == 0 ? 255 : value;
}
} else {
@@ -414,12 +402,19 @@ void AVIPlayer::renderFrame() const {
} else {
assert(surface->format.bytesPerPixel == 4);
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
Common::Rect drawRect(_drawRect);
+ mulru(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 1);
if (_pixelDouble) {
const uint32 *source = (const uint32 *)surface->getPixels();
uint32 *target = (uint32 *)_scaleBuffer;
- // target pitch here is in uint32s, not bytes
+ // target pitch here is in uint32s, not bytes, because the surface
+ // bpp is 4
const uint16 pitch = surface->pitch / 2;
for (int y = 0; y < surface->h; ++y) {
for (int x = 0; x < surface->w; ++x) {
@@ -434,17 +429,12 @@ void AVIPlayer::renderFrame() const {
target += pitch;
}
- g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height());
+ g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, drawRect.left, drawRect.top, _drawRect.width(), _drawRect.height());
} else {
- const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
- const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
- const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
-
- mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight));
-
g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h);
}
+
+ g_system->updateScreen();
}
}
@@ -500,6 +490,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_isOpen(false),
_isInitialized(false),
+ _yieldFrame(0),
_yieldInterval(0),
_lastYieldedFrameNo(0),
@@ -512,6 +503,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_blackLines(false),
_leaveScreenBlack(false),
_leaveLastFrame(false),
+ _ignorePalettes(false),
_blackoutPlane(nullptr),
@@ -538,6 +530,10 @@ VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFl
error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
}
+ if (g_sci->_features->VMDOpenStopsAudio()) {
+ g_sci->_audio32->stop(kAllChannels);
+ }
+
if (_decoder->loadFile(fileName)) {
if (flags & kOpenFlagMute) {
_decoder->setVolume(0);
@@ -571,6 +567,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
_decoder->close();
_isOpen = false;
_isInitialized = false;
+ _ignorePalettes = false;
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
@@ -625,12 +622,12 @@ VMDPlayer::VMDStatus VMDPlayer::getStatus() const {
VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
assert(lastFrameNo >= -1);
- const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+ const int32 maxFrameNo = _decoder->getFrameCount() - 1;
- if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
- _decoder->setEndFrame(MIN<int32>(lastFrameNo, maxFrameNo));
+ if (flags & kEventFlagToFrame) {
+ _yieldFrame = MIN<int32>(lastFrameNo, maxFrameNo);
} else {
- _decoder->setEndFrame(maxFrameNo);
+ _yieldFrame = maxFrameNo;
}
if (flags & kEventFlagYieldToVM) {
@@ -705,6 +702,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
reg_t bitmapId;
SciBitmap &vmdBitmap = *_segMan->allocateBitmap(&bitmapId, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
+ vmdBitmap.getBuffer().fillRect(Common::Rect(vmdRect.width(), vmdRect.height()), 0);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
@@ -767,6 +765,11 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int currentFrameNo = _decoder->getCurFrame();
+ if (currentFrameNo == _yieldFrame) {
+ stopFlag = kEventFlagEnd;
+ break;
+ }
+
if (_yieldInterval > 0 &&
currentFrameNo != _lastYieldedFrameNo &&
(currentFrameNo % _yieldInterval) == 0
@@ -826,7 +829,7 @@ void VMDPlayer::renderFrame() const {
// we are just submitting it directly here because the decoder exposes
// this information a little bit differently than the one in SSCI
const bool dirtyPalette = _decoder->hasDirtyPalette();
- if (dirtyPalette) {
+ if (dirtyPalette && !_ignorePalettes) {
Palette palette;
palette.timestamp = g_sci->getTickCount();
for (uint16 i = 0; i < _startColor; ++i) {
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
index 75b8fb2d21..4fc627e674 100644
--- a/engines/sci/graphics/video32.h
+++ b/engines/sci/graphics/video32.h
@@ -326,6 +326,12 @@ private:
bool _isInitialized;
/**
+ * For VMDs played with the `kEventFlagToFrame` flag,
+ * the target frame for yielding back to the SCI VM.
+ */
+ int32 _yieldFrame;
+
+ /**
* For VMDs played with the `kEventFlagYieldToVM` flag,
* the number of frames that should be rendered until
* yielding back to the SCI VM.
@@ -347,6 +353,13 @@ private:
#pragma mark -
#pragma mark VMDPlayer - Rendering
+public:
+ /**
+ * Causes the VMD player to ignore all palettes in
+ * the currently playing video.
+ */
+ void ignorePalettes() { _ignorePalettes = true; }
+
private:
/**
* The location of the VMD plane, in game script
@@ -408,6 +421,11 @@ private:
bool _leaveLastFrame;
/**
+ * Whether or not palettes from the VMD should be ignored.
+ */
+ bool _ignorePalettes;
+
+ /**
* Renders a frame of video to the output bitmap.
*/
void renderFrame() const;
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index a09ba8f3ce..a0f958167d 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -365,7 +365,7 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) {
}
}
}
- } while (changed && loopCount < 10);
+ } while (changed && loopCount++ < 10);
return ret;
}
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 8826b0625a..5b57eed123 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -2459,38 +2459,6 @@ void ResourceManager::detectSciVersion() {
}
}
-bool ResourceManager::detectHires() {
- // SCI 1.1 and prior is never hires
- if (getSciVersion() <= SCI_VERSION_1_1)
- return false;
-
-#ifdef ENABLE_SCI32
- for (int i = 0; i < 32768; i++) {
- Resource *res = findResource(ResourceId(kResourceTypePic, i), 0);
-
- if (res) {
- if (READ_SCI11ENDIAN_UINT16(res->data) == 0x0e) {
- // SCI32 picture
- uint16 width = READ_SCI11ENDIAN_UINT16(res->data + 10);
- uint16 height = READ_SCI11ENDIAN_UINT16(res->data + 12);
- // Surely lowres (e.g. QFG4CD)
- if ((width == 320) && ((height == 190) || (height == 200)))
- return false;
- // Surely hires
- if ((width >= 600) || (height >= 400))
- return true;
- }
- }
- }
-
- // We haven't been able to find hires content
-
- return false;
-#else
- error("no sci32 support");
-#endif
-}
-
bool ResourceManager::detectFontExtended() {
Resource *res = findResource(ResourceId(kResourceTypeFont, 0), 0);
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 70db5909b7..928d571dbc 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -424,7 +424,6 @@ private:
public:
#endif
- bool detectHires();
// Detects, if standard font of current game includes extended characters (>0x80)
bool detectFontExtended();
// Detects, if SCI1.1 game uses palette merging
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 246c031c06..e89d05217c 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -1166,7 +1166,9 @@ void SciEngine::syncIngameAudioOptions() {
void SciEngine::updateScummVMAudioOptions() {
// Update ScummVM's speech/subtitles settings for SCI1.1 CD games,
// depending on the in-game settings
- if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
+ if ((isCD() && getSciVersion() == SCI_VERSION_1_1) ||
+ getSciVersion() >= SCI_VERSION_2) {
+
uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType].getOffset();
switch (ingameSetting) {