aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/console.cpp15
-rw-r--r--engines/sci/detection.cpp12
-rw-r--r--engines/sci/detection_tables.h348
-rw-r--r--engines/sci/engine/file.cpp261
-rw-r--r--engines/sci/engine/file.h46
-rw-r--r--engines/sci/engine/kernel.cpp6
-rw-r--r--engines/sci/engine/kernel.h20
-rw-r--r--engines/sci/engine/kernel_tables.h35
-rw-r--r--engines/sci/engine/kfile.cpp109
-rw-r--r--engines/sci/engine/kgraphics32.cpp117
-rw-r--r--engines/sci/engine/kmisc.cpp3
-rw-r--r--engines/sci/engine/kvideo.cpp153
-rw-r--r--engines/sci/engine/savegame.cpp11
-rw-r--r--engines/sci/engine/script_patches.cpp168
-rw-r--r--engines/sci/engine/state.cpp6
-rw-r--r--engines/sci/engine/state.h5
-rw-r--r--engines/sci/graphics/celobj32.cpp31
-rw-r--r--engines/sci/graphics/celobj32.h12
-rw-r--r--engines/sci/graphics/controls32.cpp2
-rw-r--r--engines/sci/graphics/cursor.h2
-rw-r--r--engines/sci/graphics/frameout.cpp57
-rw-r--r--engines/sci/graphics/frameout.h19
-rw-r--r--engines/sci/graphics/paint32.cpp2
-rw-r--r--engines/sci/graphics/palette.h10
-rw-r--r--engines/sci/graphics/palette32.cpp278
-rw-r--r--engines/sci/graphics/palette32.h160
-rw-r--r--engines/sci/graphics/plane32.cpp9
-rw-r--r--engines/sci/graphics/plane32.h7
-rw-r--r--engines/sci/graphics/screen_item32.cpp16
-rw-r--r--engines/sci/graphics/screen_item32.h12
-rw-r--r--engines/sci/graphics/video32.cpp406
-rw-r--r--engines/sci/graphics/video32.h312
-rw-r--r--engines/sci/module.mk1
-rw-r--r--engines/sci/sci.cpp36
-rw-r--r--engines/sci/sci.h4
-rw-r--r--engines/sci/sound/audio32.cpp49
-rw-r--r--engines/sci/sound/audio32.h2
-rw-r--r--engines/sci/sound/music.cpp3
-rw-r--r--engines/sci/sound/soundcmd.cpp2
39 files changed, 2016 insertions, 731 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 2c74fe4b0c..6898745858 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -497,8 +497,10 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
if (getSciVersion() <= SCI_VERSION_1_1) {
debugPrintf("kAnimate fastCast enabled: %s\n", g_sci->_gfxAnimate->isFastCastEnabled() ? "yes" : "no");
}
- debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no");
- debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");
+ if (getSciVersion() < SCI_VERSION_2) {
+ debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no");
+ debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");
+ }
debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc());
debugPrintf("Resource map version: %s\n", g_sci->getResMan()->getMapVersionDesc());
debugPrintf("Contains selector vocabulary (vocab.997): %s\n", hasVocab997 ? "yes" : "no");
@@ -1620,7 +1622,7 @@ bool Console::cmdParserNodes(int argc, const char **argv) {
bool Console::cmdSetPalette(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("Sets a palette resource\n");
+ debugPrintf("Sets a palette resource (SCI16)\n");
debugPrintf("Usage: %s <resourceId>\n", argv[0]);
debugPrintf("where <resourceId> is the number of the palette resource to set\n");
return true;
@@ -1628,6 +1630,13 @@ bool Console::cmdSetPalette(int argc, const char **argv) {
uint16 resourceId = atoi(argv[1]);
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ debugPrintf("This SCI version does not support this command\n");
+ return true;
+ }
+#endif
+
_engine->_gfxPalette16->kernelSetFromResource(resourceId, true);
return true;
}
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 6b945d6f62..8691c37b3e 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -107,6 +107,7 @@ static const PlainGameDescriptor s_sciGameTitles[] = {
{"pq4", "Police Quest IV: Open Season"}, // floppy is SCI2, CD SCI2.1
{"qfg4", "Quest for Glory IV: Shadows of Darkness"}, // floppy is SCI2, CD SCI2.1
// === SCI2.1 games ========================================================
+ {"hoyle5", "Hoyle Classic Games"},
{"chest", "Inside the Chest"}, // aka Behind the Developer's Shield
{"gk2", "The Beast Within: A Gabriel Knight Mystery"},
{"kq7", "King's Quest VII: The Princeless Bride"},
@@ -157,6 +158,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = {
{ "hoyle2", GID_HOYLE2 },
{ "hoyle3", GID_HOYLE3 },
{ "hoyle4", GID_HOYLE4 },
+ { "hoyle5", GID_HOYLE5 },
{ "iceman", GID_ICEMAN },
{ "inndemo", GID_INNDEMO },
{ "islandbrain", GID_ISLANDBRAIN },
@@ -397,6 +399,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
},
{
+ GAMEOPTION_ENABLE_BLACK_LINED_VIDEO,
+ {
+ _s("Enable black-lined video"),
+ _s("Draw black lines over videos to increase their apparent sharpness"),
+ "enable_black_lined_video",
+ false
+ }
+ },
+
+ {
GAMEOPTION_PREFER_DIGITAL_SFX,
{
_s("Prefer digital sound effects"),
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 2595616f71..f205609e20 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -30,6 +30,7 @@ namespace Sci {
#define GAMEOPTION_SQ4_SILVER_CURSORS GUIO_GAMEOPTIONS6
#define GAMEOPTION_EGA_UNDITHER GUIO_GAMEOPTIONS7
#define GAMEOPTION_HIGH_RESOLUTION_GRAPHICS GUIO_GAMEOPTIONS8
+#define GAMEOPTION_ENABLE_BLACK_LINED_VIDEO GUIO_GAMEOPTIONS9
// SCI3 games have a different script format (in CSC files) and are currently unsupported
#define ENABLE_SCI3_GAMES
@@ -729,13 +730,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+#define GUIO_GK1_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK1_CD GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK1_MAC GUIO_GK1_FLOPPY
+
// Gabriel Knight - English DOS Floppy
// SCI interpreter version 2.000.000
{"gk1", "", {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS Floppy (supplied my markcoolio in bug report #2723777)
// SCI interpreter version 2.000.000
@@ -743,7 +753,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "65e8c14092e4c9b3b3538b7602c8c5ec", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS Floppy
// SCI interpreter version 2.000.000, VERSION file reports "1.0\nGabriel Knight\n11/22/10:33 pm\n\x1A"
@@ -751,7 +761,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ef41df08cf2c1f680216cdbeed0f8311", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - German DOS Floppy (supplied my markcoolio in bug report #2723775)
// SCI interpreter version 2.000.000
@@ -759,7 +769,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ad6508b0296b25c07b1f58828dc33696", 10789},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13077029},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - French DOS Floppy (supplied my kervala in bug report #3611487)
// SCI interpreter version 2.000.000
@@ -767,7 +777,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "236e36cc847cdeafdd5e5fa8cba916ed", 10801},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13033072},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "01.100.000"
@@ -775,7 +785,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - English Windows CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "01.100.000"
@@ -783,7 +793,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - German DOS CD (from Tobis87)
// SCI interpreter version 2.000.000
@@ -791,7 +801,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - Spanish DOS CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995"
@@ -799,7 +809,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - French DOS CD (from Hkz)
// VERSION file reports "1.000.000, May 3, 1994"
@@ -807,7 +817,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "55f909ba93a2515042a08d8a2da8414e", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13325145},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - German Windows CD (from Tobis87)
// SCI interpreter version 2.000.000
@@ -815,7 +825,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - Spanish Windows CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995"
@@ -823,7 +833,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - English Macintosh
{"gk1", "", {
@@ -832,7 +842,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data3", 0, "f25068b408b09275d8b698866462f578", 3677599},
{"Data4", 0, "1cceebbe411b26c860a74f91c337fdf3", 3230086},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_GK1_MAC },
+
+#define GUIO_GK2_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK2 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK2_MAC GUIO_GK2
// Gabriel Knight 2 - English Windows Non-Interactive Demo
// Executable scanning reports "2.100.002"
@@ -840,7 +862,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "e0effce11c4908f4b91838741716c83d", 1351},
{"resource.000", 0, "d04cfc7f04b6f74d13025378be49ec2b", 4640330},
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) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_GK2_DEMO },
// Gabriel Knight 2 - English DOS (GOG version) - ressci.* merged in ressci.000
// using Enrico Rolfi's HD/DVD installer: http://gkpatches.vogons.zetafleet.com/
@@ -848,7 +870,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "b996fa1e57389a1e179a00a0049de1f4", 8110},
{"ressci.000", 0, "a19fc3604c6e5407abcf03d59ee87217", 168522221},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - English DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.1"
@@ -866,7 +888,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.006", 0, "ce9359037277b7d7976da185c2fa0aad", 2977},
{"ressci.006", 0, "8e44e03890205a7be12f45aaba9644b4", 60659424},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - French DOS (6-CDs Sierra Originals reedition)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -884,7 +906,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.006", 0, "11b2e722170b8c93fdaa5428e2c7676f", 3001},
{"ressci.006", 0, "4037d941aec39d2e654e20960429aefc", 60568486},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - English Macintosh
// NOTE: This only contains disc 1 files (as well as the persistent file:
@@ -896,7 +918,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data4", 0, "8b843c62eb53136a855d6e0087e3cb0d", 5889553},
{"Data5", 0, "f9fcf9ab2eb13b2125c33a1cda03a093", 14349984},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_GK2_MAC },
#endif // ENABLE_SCI32
@@ -1110,13 +1132,27 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+#ifdef ENABLE_SCI32
+#define GUIO_HOYLE5_DEMO GUIO3(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+
+ // Hoyle 5 (Hoyle Classic Games) - Windows demo
+ {"hoyle5", "Demo", {
+ {"ressci.000", 0, "98a39ae535dd01714ac313f8ba925045", 7260363},
+ {"resmap.000", 0, "10267a1542a73d527e50f0340549088b", 4900},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_HOYLE5_DEMO },
+
+#endif // ENABLE_SCI32
+
// ImagiNation Network (INN) Demo
// SCI interpreter version 1.001.097
{"inndemo", "", {
{"resource.000", 0, "535b1b920441ec73f42eaa4ccfd47b89", 514578},
{"resource.map", 0, "333daf27c3e8a6d274a3e0061ed7cd5c", 1545},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Jones in the Fast Lane EGA - English DOS
// SCI interpreter version 1.000.172 (not 100% sure FIXME)
@@ -1709,6 +1745,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
#ifdef ENABLE_SCI32
+#define GUIO_KQ7_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_KQ7 GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// King's Quest 7 - English Windows (from the King's Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.4"
@@ -1716,7 +1761,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "2be9ab94429c721af8e05c507e048a15", 18697},
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 203882535},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English Windows-interpreter-only (supplied by m_kiewitz)
// SCI interpreter version 2.100.002, VERSION file reports "1.51"
@@ -1725,7 +1770,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
{"resource.aud", 0, "c2a988a16053eb98c7b73a75139902a0", 217716879},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - German Windows-interpreter-only (supplied by markcoolio in bug report #2727402)
// SCI interpreter version 2.100.002, VERSION file reports "1.51"
@@ -1735,7 +1780,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
{"resource.aud", 0, "3f17bcaf8a9ff6a6c2d4de1a2078fdcc", 258119621},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English Windows (from abevi)
// VERSION 1.65c
@@ -1743,7 +1788,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
{"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English DOS (from FRG)
// SCI interpreter version 2.100.002, VERSION file reports "2.00b"
@@ -1751,7 +1796,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English Windows (from FRG)
// SCI interpreter version 2.100.002, VERSION file reports "2.00b"
@@ -1759,7 +1804,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - Spanish DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "2.00"
@@ -1767,7 +1812,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "0b62693cbe87e3aaca3e8655a437f27f", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English DOS Non-Interactive Demo
// SCI interpreter version 2.100.002
@@ -1775,7 +1820,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "b44f774108d63faa1d021101221c5a54", 1690},
{"resource.000", 0, "d9659d2cf0c269c6a9dc776707f5bea0", 2433827},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_KQ7_DEMO },
// King's Quest 7 - English Windows Demo (from DrMcCoy)
// SCI interpreter version 2.100.002
@@ -1783,7 +1828,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "38e627a37a975aea40cc72b0518b0709", 18412},
{"resource.000", 0, "bad61d50aaa64298fa57a7c6ccd3bccf", 84020382},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7_DEMO },
// King's Questions mini-game from the King's Quest Collection
// SCI interpreter version 2.000.000
@@ -2473,13 +2518,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_LSL6HIRES GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Larry 6 - English/German DOS CD - HIRES
// SCI interpreter version 2.100.002
{"lsl6hires", "Hi-res", {
{"resource.map", 0, "0c0804434ea62278dd15032b1947426c", 8872},
{"resource.000", 0, "9a9f4870504444cda863dd14d077a680", 18520872},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
// Larry 6 - German DOS CD - HIRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2487,7 +2538,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "badfdf446ffed569a310d2c63a249421", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18534274},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
// Larry 6 - French DOS CD - HIRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2495,7 +2546,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "d184e9aa4f2d4b5670ddb3669db82cda", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18538987},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
+
+#define GUIO_LSL7_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_LSL7 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// Larry 7 - English DOS Demo (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2503,7 +2565,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "5cc6159688b2dc03790a67c90ccc67f9", 10195878},
{"resmap.000", 0, "6a2b2811eef82e87cde91cf1de845af8", 2695},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LSL7_DEMO },
#ifdef ENABLE_SCI3_GAMES
// Larry 7 - English DOS CD (from spookypeanut)
@@ -2512,7 +2574,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "eae93e1b1d1ccc58b4691c371281c95d", 8188},
{"ressci.000", 0, "89353723488219e25589165d73ed663e", 66965678},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - German DOS (from Tobis87)
// SCI interpreter version 3.000.000
@@ -2520,7 +2582,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "c11e6bfcfc2f2d05da47e5a7df3e9b1a", 8188},
{"ressci.000", 0, "a8c6817bb94f332ff498a71c8b47f893", 66971724},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - French DOS (provided by richiefs in bug report #2670691)
// SCI interpreter version 3.000.000
@@ -2528,7 +2590,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "4407849fd52fe3efb0c30fba60cd5cd4", 8206},
{"ressci.000", 0, "dc37c3055fffbefb494ff22b145d377b", 66964472},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - Italian DOS CD (from glorifindel)
// SCI interpreter version 3.000.000
@@ -2536,7 +2598,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "9852a97141f789413f29bf956052acdb", 8212},
{"ressci.000", 0, "440b9fed89590abb4e4386ed6f948ee2", 67140181},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - Spanish DOS (from the Leisure Suit Larry Collection)
// Executable scanning reports "3.000.000", VERSION file reports "1.0s"
@@ -2544,16 +2606,28 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "8f3d603e1acc834a5d598b30cdfc93f3", 8188},
{"ressci.000", 0, "32792f9bc1bf3633a88b382bb3f6e40d", 67071418},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
#endif
+#define GUIO_LIGHTHOUSE_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_LIGHTHOUSE GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Lighthouse - English Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.00"
{"lighthouse", "Demo", {
{"resource.map", 0, "543124606352bfa5e07696ddf2a669be", 64},
{"resource.000", 0, "5d7714416b612463d750fb9c5690c859", 28952},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LIGHTHOUSE_DEMO },
#ifdef ENABLE_SCI3_GAMES
// Lighthouse - English Windows Demo
@@ -2562,7 +2636,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "3bdee7a16926975a4729f75cf6b80a92", 1525},
{"ressci.000", 0, "3c585827fa4a82f4c04a56a0bc52ccee", 11494351},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - English DOS (from jvprat)
// Executable scanning reports "3.000.000", VERSION file reports "1.1"
@@ -2572,7 +2646,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "c68db5333f152fea6ca2dfc75cad8b34", 7573},
{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94628315},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - Japanese DOS (from m_kiewitz)
// Executable scanning reports "3.000.000", VERSION file reports "1.0C"
@@ -2582,7 +2656,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "723fc742c623d8933e5753a264324cb0", 7657},
{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94627469},
AD_LISTEND},
- Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - Spanish DOS (from jvprat)
// Executable scanning reports "3.000.000", VERSION file reports "1.1"
@@ -2592,7 +2666,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "e7dc85884a2417e2eff9de0c63dd65fa", 7630},
{"ressci.002", 0, "3c8d627c555b0e3e4f1d9955bc0f0df4", 94631127},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
#endif // ENABLE_SCI3_GAMES
#endif // ENABLE_SCI32
@@ -2714,13 +2788,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::JA_JPN, Common::kPlatformFMTowns, ADGF_ADDENGLISH, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_MOTHERGOOSEHIRES GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Mixed-Up Mother Goose Deluxe - English Windows/DOS CD (supplied by markcoolio in bug report #2723810)
// Executable scanning reports "2.100.002"
{"mothergoosehires", "", {
{"resource.map", 0, "5159a1578c4306bfe070a3e4d8c2e1d3", 4741},
{"resource.000", 0, "1926925c95d82f0999590e93b02887c5", 15150768},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_MOTHERGOOSEHIRES },
// Mixed-Up Mother Goose Deluxe - Multilingual Windows CD (English/French/German/Spanish)
// Executable scanning reports "2.100.002"
@@ -2728,7 +2808,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "ef611af561898dcfea87846919ebf3eb", 4969},
{"ressci.000", 0, "227685bc59d90821978d330713e44a7a", 17205800},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_MOTHERGOOSEHIRES },
#endif // ENABLE_SCI32
// Ms. Astro Chicken - English DOS
@@ -2740,6 +2820,20 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_PHANTASMAGORIA_DEMO GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PHANTASMAGORIA GUIO_PHANTASMAGORIA_DEMO
+#define GUIO_PHANTASMAGORIA_MAC GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Phantasmagoria - English DOS/Windows (from csnover)
// Windows executable scanning reports "2.100.002" - "Aug 06 1995"
// DOS executable scanning reports "2.100.002" - "May 24 1995"
@@ -2760,7 +2854,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.007", 0, "aa8175cfc93242af6f5e65bdceaafc0d", 7972},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - English DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.100.000UK"
@@ -2780,7 +2874,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.007", 0, "afbd16ea77869a720afa1c5371de107d", 7972},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - German DOS/Windows
// Windows executable scanning reports "unknown" - "Sep 19 1995 09:39:48"
@@ -2803,7 +2897,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.007", 0, "06309b8043aecb85bd507b15d16cb544", 7984},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 26898681},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - French DOS
// Supplied by Kervala in bug #6574
@@ -2822,7 +2916,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107},
{"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - English DOS Demo
// Executable scanning reports "2.100.002"
@@ -2830,7 +2924,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.001", 0, "416138651ea828219ca454cae18341a3", 11518},
{"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_PHANTASMAGORIA_DEMO },
// Phantasmagoria - English DOS/Windows (GOG version) - ressci.* merged in ressci.000
// Windows executable scanning reports "2.100.002" - "Sep 19 1995 15:09:43"
@@ -2841,7 +2935,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "cd5967f9b9586e3380645961c0765be3", 116822037},
{"resmap.000", 0, "3cafc1c6a53945c1f3babbfd6380c64c", 16468},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - English Macintosh
// NOTE: This only contains disc 1 files (as well as the two persistent files:
@@ -2857,9 +2951,16 @@ static const struct ADGameDescription SciGameDescriptions[] = {
// Data8-12 are empty
{"Data13", 0, "6d2c450fca19a69b5af74ed5b03c0a17", 14923328},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_PHANTASMAGORIA_MAC },
#ifdef ENABLE_SCI3_GAMES
+
+#define GUIO_PHANTASMAGORIA2 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+
// Some versions of Phantasmagoria 2 were heavily censored.
// Censored versions (data files are currently unknown to us): UK, Australia, first English release in Germany
@@ -2879,7 +2980,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942},
{"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
// Phantasmagoria 2 - English DOS (GOG version) (supplied by littleboy in patch #1360)
// Note: Fully uncensored, basically the US release, but ressci.* merged into ressci.000
@@ -2890,7 +2991,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481},
{"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
// Phantasmagoria 2 - German DOS/Windows (supplied by AReim1982)
// Note: Fully uncensored, but one scene is missing probably because of a mastering error (Curtis + Therese meeting near water cooler)
@@ -2910,7 +3011,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.005", 0, "2fc48a4a5a73b726994f189da51a8b2a", 1954},
{"ressci.005", 0, "e94005890d22dd3b7f605a2a7c025803", 68232146},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
#endif // ENABLE_SCI3_GAMES
#endif // ENABLE_SCI32
@@ -3142,13 +3243,23 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_PQ4_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PQ4_CD GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Police Quest 4 - English DOS CD (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.100.000"
{"pq4", "CD", {
{"resource.map", 0, "379dfe80ed6bd16c47e4b950c4722eac", 11374},
{"resource.000", 0, "fd316a09b628b7032248139003369022", 18841068},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_PQ4_CD },
// Police Quest 4 - German DOS CD (German text, English speech)
// Supplied by markcoolio in bug report #3392955
@@ -3156,7 +3267,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a398076371ed0e1e706c8f9fb9fc7ac5", 11386},
{"resource.000", 0, "6ff21954e0a2c5992279e7eb787c8d56", 18918747},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_PQ4_CD },
// Police Quest 4 - English DOS
// SCI interpreter version 2.000.000 (a guess?)
@@ -3164,7 +3275,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "aed9643158ccf01b71f359db33137f82", 9895},
{"resource.000", 0, "da383857b3be1e4514daeba2524359e0", 15141432},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
// Police Quest 4 - French DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
@@ -3172,7 +3283,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "008030846edcc7c5c7a812c7f4ae4ceb", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730153},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
// Police Quest 4 - German DOS (supplied by markcoolio in bug report #2723840)
// SCI interpreter version 2.000.000 (a guess?)
@@ -3180,7 +3291,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "2393ee728ab930b2762cb5889f9b5aff", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730155},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
+
+#define GUIO_PQSWAT_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PQSWAT GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// Police Quest: SWAT - English DOS/Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "0.001.200"
@@ -3188,7 +3310,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8c96733ef94c21526792f7ca4e3f2120", 1648},
{"resource.000", 0, "d8892f1b8c56c8f7704325460f49b300", 3676175},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_PQSWAT_DEMO },
// Police Quest: SWAT - English DOS (from GOG.com)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -3196,7 +3318,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "1c2563fee189885e29d9348f37306d94", 12175},
{"ressci.000", 0, "b2e1826ca81ce2e7e764587f5a14eee9", 127149181},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQSWAT },
// Police Quest: SWAT - English Windows (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -3211,7 +3333,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.004", 0, "4228038906f041623e65789500b22285", 6835},
{"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PQSWAT },
#endif // ENABLE_SCI32
// Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784)
@@ -3569,13 +3691,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_QFG4_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_QFG4_CD GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by markcool in bug report #2723852)
// SCI interpreter version 2.000.000 (a guess?)
{"qfg4", "", {
{"resource.map", 0, "685bdb1ed47bbbb0e5e25db392da83ce", 9301},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11004993},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
@@ -3583,7 +3714,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "d10a4cc177d2091d744e2ad8c049b0ae", 9295},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11003589},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 1.1 Floppy - German DOS (supplied by markcool in bug report #2723850)
// Executable scanning reports "2.000.000", VERSION file reports "1.1"
@@ -3591,7 +3722,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "9e0abba8746f40565bc7eb5720522ecd", 9301},
{"resource.000", 0, "57f22cdc54eeb35fce1f26b31b5c3ee1", 11076197},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 CD - English DOS/Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -3599,7 +3730,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "aba367f2102e81782d961b14fbe3d630", 10246},
{"resource.000", 0, "263dce4aa34c49d3ad29bec889007b1c", 11571394},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_QFG4_CD },
+
+#define GUIO_RAMA_DEMO GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_RAMA GUIO_RAMA_DEMO
// RAMA - English DOS/Windows Demo
// Executable scanning reports "2.100.002", VERSION file reports "000.000.008"
@@ -3607,7 +3745,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.001", 0, "775304e9b2a545156be4d94209550094", 1393},
{"ressci.001", 0, "259437fd75fdf51e8207fda8c01fa4fd", 2334384},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_RAMA_DEMO },
#ifdef ENABLE_SCI3_GAMES
// RAMA - English Windows (from jvprat)
@@ -3620,7 +3758,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "31ef4c0621711585d031f0ae81707251", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6860492},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - English Windows (from Quietust, in bug report #2850645)
{"rama", "", {
@@ -3631,7 +3769,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "48841e4b84ef1b98b48d43566fda9e13", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6870356},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - German Windows CD (from farmboy0, in pull request 397)
{"rama", "", {
@@ -3642,7 +3780,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "222096000bd83a1d56577114a452cccf", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6954219},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - Italian Windows CD (from glorifindel)
// SCI interpreter version 3.000.000 (a guess?)
@@ -3650,23 +3788,29 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70611091},
{"resmap.001", 0, "70ba2ff04a2b7fb2c52420ba7fbd47c2", 8338},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
#endif // ENABLE_SCI3_GAMES
+#define GUIO_SHIVERS_DEMO GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_SHIVERS GUIO_SHIVERS_DEMO
+
// Shivers - English Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.02"
{"shivers", "", {
{"resmap.000", 0, "f2ead37749ed8f6535a2445a7d05a0cc", 46525},
{"ressci.000", 0, "4294c6d7510935f2e0a52e302073c951", 262654836},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers - German Windows (from Tobis87)
{"shivers", "", {
{"resmap.000", 0, "f483d0a1f78334c18052e92785c3086e", 46537},
{"ressci.000", 0, "6751b144671e2deed919eb9d284b07eb", 262390692},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers - English Windows Demo
// Executable scanning reports "2.100.002"
@@ -3674,7 +3818,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "d9e0bc5eddefcbe47f528760085d8927", 1186},
{"ressci.000", 0, "3a93c6340b54e07e65d0e5583354d186", 10505469},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers 2 doesn't contain SCI scripts. The whole game logic has
// been reimplemented from SCI in native code placed in DLL files.
@@ -3692,7 +3836,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "d8659188b84beaef076bd869837cd530", 634},
{"ressci.000", 0, "7fbac0807a044c9543e8ac376d200e59", 4925003},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Shivers 2 - English Windows (from abevi)
// VERSION.TXT Version 1.0 (3/25/97)
@@ -3700,7 +3844,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "a79d03d6eb75be0a79324f14e3d2ace4", 95346793},
{"resmap.001", 0, "a4804d436d90c4ec2e46b537f5e954db", 6268},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#endif
@@ -4232,13 +4376,25 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::RU_RUS, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_SQ6_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_SQ6 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Space Quest 6 - English DOS/Win3.11 CD (from the Space Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
{"sq6", "", {
{"resource.map", 0, "6dddfa3a8f3a3a513ec9dfdfae955005", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - English DOS/Win3.11 CD ver 1.11 (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4246,7 +4402,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "e0615d6e4e10e37ae42e6a2a95aaf145", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - French DOS/Win3.11 CD (from French magazine Joystick - September 1997)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -4254,7 +4410,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3c831625931d5079b73ae8c275f52c95", 10534},
{"resource.000", 0, "4195ca940f759424f62b90e262cc1737", 40932397},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723884)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4262,7 +4418,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "664d797415484f85c90b1b45aedc7686", 10534},
{"resource.000", 0, "ba87ba91e5bdabb4169dd0df75777722", 40933685},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - English DOS/Win3.11 Interactive Demo (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4270,7 +4426,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "368f07b07433db3f819fa3fa0e5efee5", 2572},
{"resource.000", 0, "ab12724e078dea34b624e0d2a38dcd7c", 2272050},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_SQ6_DEMO },
#endif // ENABLE_SCI32
// The Island of Dr. Brain - English DOS CD (from jvprat)
@@ -4298,13 +4454,23 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_TORIN_DEMO GUIO3(GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+#define GUIO_TORIN GUIO4(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+#define GUIO_TORIN_MAC GUIO_TORIN
+
// Torin's Passage - English Windows Interactive Demo
// SCI interpreter version 2.100.002
{"torin", "Demo", {
{"resmap.000", 0, "9a3e172cde9963d0a969f26469318cec", 3403},
{"ressci.000", 0, "db3e290481c35c3224e9602e71e4a1f1", 5073868},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN_DEMO },
// Torin's Passage (Multilingual) - English Windows CD
// SCI interpreter version 2.100.002
@@ -4312,7 +4478,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - Spanish Windows CD (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -4321,7 +4487,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
// TODO: depend on one of the patches?
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - French Windows CD
// SCI interpreter version 2.100.002
@@ -4329,7 +4495,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - German Windows CD (from m_kiewitz)
// SCI interpreter version 2.100.002
@@ -4338,7 +4504,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "e55c3097329b3c53752301e01c6af2fb", 9787},
{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56127540},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - German Windows CD
// SCI interpreter version 2.100.002
@@ -4346,7 +4512,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - Italian Windows CD (from glorifindel)
// SCI interpreter version 2.100.002
@@ -4354,7 +4520,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - French Windows (from LePhilousophe)
// SCI interpreter version 2.100.002
@@ -4362,7 +4528,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "66ed46e3e56f487e688d52f05b33d0ba", 9787},
{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56126981},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - Russian Windows CD (SoftClub official translate)
// SCI interpreter version 2.100.002
@@ -4372,7 +4538,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{ "ressci.000", 0, "e672da099fb1663b87c78abc6c8ba2a4", 130622695 },
{ "resmap.000", 0, "643859f8f2be8e7701611e29b3b65208", 9799 },
AD_LISTEND },
- Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - English Macintosh
{"torin", "", {
@@ -4384,7 +4550,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data6", 0, "b639487c83d1dae0e001e700f3631566", 7594881},
{"Data7", 0, "2afd9b5434102b89610916b904c3f73a", 7627374},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN_MAC },
#endif // ENABLE_SCI32
// SCI Fanmade Games
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 0b1001bfda..156f6f51f7 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -22,6 +22,7 @@
#include "common/savefile.h"
#include "common/stream.h"
+#include "common/memstream.h"
#include "sci/sci.h"
#include "sci/engine/file.h"
@@ -32,6 +33,112 @@
namespace Sci {
+#ifdef ENABLE_SCI32
+/**
+ * A MemoryWriteStreamDynamic with additional read functionality.
+ * The read and write functions share a single stream position.
+ */
+class MemoryDynamicRWStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream {
+protected:
+ bool _eos;
+public:
+ MemoryDynamicRWStream(DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) : MemoryWriteStreamDynamic(disposeMemory), _eos(false) { }
+
+ uint32 read(void *dataPtr, uint32 dataSize);
+
+ bool eos() const { return _eos; }
+ int32 pos() const { return _pos; }
+ int32 size() const { return _size; }
+ void clearErr() { _eos = false; Common::MemoryWriteStreamDynamic::clearErr(); }
+ bool seek(int32 offs, int whence = SEEK_SET) { return Common::MemoryWriteStreamDynamic::seek(offs, whence); }
+
+};
+
+uint32 MemoryDynamicRWStream::read(void *dataPtr, uint32 dataSize)
+{
+ // Read at most as many bytes as are still available...
+ if (dataSize > _size - _pos) {
+ dataSize = _size - _pos;
+ _eos = true;
+ }
+ memcpy(dataPtr, _ptr, dataSize);
+
+ _ptr += dataSize;
+ _pos += dataSize;
+
+ return dataSize;
+}
+
+/**
+ * A MemoryDynamicRWStream intended to re-write a file.
+ * It reads the contents of `inFile` in the constructor, and writes back
+ * the changes to `fileName` in the destructor (and when calling commit() ).
+ */
+class SaveFileRewriteStream : public MemoryDynamicRWStream {
+public:
+ SaveFileRewriteStream(Common::String fileName,
+ Common::SeekableReadStream *inFile,
+ bool truncate, bool compress);
+ virtual ~SaveFileRewriteStream();
+
+ virtual uint32 write(const void *dataPtr, uint32 dataSize) { _changed = true; return MemoryDynamicRWStream::write(dataPtr, dataSize); }
+
+ void commit(); //< Save back to disk
+
+protected:
+ Common::String _fileName;
+ bool _compress;
+ bool _changed;
+};
+
+SaveFileRewriteStream::SaveFileRewriteStream(Common::String fileName,
+ Common::SeekableReadStream *inFile,
+ bool truncate,
+ bool compress)
+: MemoryDynamicRWStream(DisposeAfterUse::YES),
+ _fileName(fileName), _compress(compress)
+{
+ if (!truncate && inFile) {
+ unsigned int s = inFile->size();
+ ensureCapacity(s);
+ inFile->read(_data, s);
+ _changed = false;
+ } else {
+ _changed = true;
+ }
+}
+
+SaveFileRewriteStream::~SaveFileRewriteStream() {
+ commit();
+}
+
+void SaveFileRewriteStream::commit() {
+ // Write contents of buffer back to file
+
+ if (_changed) {
+ Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName, _compress);
+ outFile->write(_data, _size);
+ delete outFile;
+ _changed = false;
+ }
+}
+
+#endif
+
+uint findFreeFileHandle(EngineState *s) {
+ // Find a free file handle
+ uint handle = 1; // Ignore _fileHandles[0]
+ while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
+ handle++;
+
+ if (handle == s->_fileHandles.size()) {
+ // Hit size limit => Allocate more space
+ s->_fileHandles.resize(s->_fileHandles.size() + 1);
+ }
+
+ return handle;
+}
+
/*
* Note on how file I/O is implemented: In ScummVM, one can not create/write
* arbitrary data files, simply because many of our target platforms do not
@@ -91,6 +198,27 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
break;
}
+#ifdef ENABLE_SCI32
+ if (mode != _K_FILE_MODE_OPEN_OR_FAIL && (
+ (g_sci->getGameId() == GID_PHANTASMAGORIA && filename == "phantsg.dir") ||
+ (g_sci->getGameId() == GID_PQSWAT && filename == "swat.dat"))) {
+ debugC(kDebugLevelFile, " -> file_open opening %s for rewriting", wrappedName.c_str());
+
+ inFile = saveFileMan->openForLoading(wrappedName);
+ // If no matching savestate exists: fall back to reading from a regular
+ // file
+ if (!inFile)
+ inFile = SearchMan.createReadStreamForMember(englishName);
+
+ SaveFileRewriteStream *stream;
+ stream = new SaveFileRewriteStream(wrappedName, inFile, mode == _K_FILE_MODE_CREATE, isCompressed);
+
+ delete inFile;
+
+ inFile = stream;
+ outFile = stream;
+ } else
+#endif
if (mode == _K_FILE_MODE_OPEN_OR_FAIL) {
// Try to open file, abort if not possible
inFile = saveFileMan->openForLoading(wrappedName);
@@ -126,15 +254,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
return SIGNAL_REG;
}
- // Find a free file handle
- uint handle = 1; // Ignore _fileHandles[0]
- while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
- handle++;
-
- if (handle == s->_fileHandles.size()) {
- // Hit size limit => Allocate more space
- s->_fileHandles.resize(s->_fileHandles.size() + 1);
- }
+ uint handle = findFreeFileHandle(s);
s->_fileHandles[handle]._in = inFile;
s->_fileHandles[handle]._out = outFile;
@@ -252,8 +372,12 @@ FileHandle::~FileHandle() {
}
void FileHandle::close() {
- delete _in;
- delete _out;
+ // NB: It is possible _in and _out are both non-null, but
+ // then they point to the same object.
+ if (_in)
+ delete _in;
+ else
+ delete _out;
_in = 0;
_out = 0;
_name.clear();
@@ -365,119 +489,4 @@ reg_t DirSeeker::nextFile(SegManager *segMan) {
return _outbuffer;
}
-
-#ifdef ENABLE_SCI32
-
-VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) {
- Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName);
-
- _bufferSize = inFile->size();
- _buffer = new char[_bufferSize];
- inFile->read(_buffer, _bufferSize);
- _ptr = _buffer;
- delete inFile;
-}
-
-VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) {
- _bufferSize = initialSize;
- _buffer = new char[_bufferSize];
- _ptr = _buffer;
-}
-
-VirtualIndexFile::~VirtualIndexFile() {
- close();
-
- _bufferSize = 0;
- delete[] _buffer;
- _buffer = 0;
-}
-
-uint32 VirtualIndexFile::read(char *buffer, uint32 size) {
- uint32 curPos = _ptr - _buffer;
- uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos);
- char *localPtr = buffer;
-
- for (uint32 i = 0; i < finalSize; i++)
- *localPtr++ = *_ptr++;
-
- return finalSize;
-}
-
-uint32 VirtualIndexFile::write(const char *buffer, uint32 size) {
- _changed = true;
- uint32 curPos = _ptr - _buffer;
-
- // Check if the buffer needs to be resized
- if (curPos + size >= _bufferSize) {
- _bufferSize = curPos + size + 1;
- char *tmp = _buffer;
- _buffer = new char[_bufferSize];
- _ptr = _buffer + curPos;
- memcpy(_buffer, tmp, _bufferSize);
- delete[] tmp;
- }
-
- for (uint32 i = 0; i < size; i++)
- *_ptr++ = *buffer++;
-
- return size;
-}
-
-uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) {
- uint32 startPos = _ptr - _buffer;
- uint32 bytesRead = 0;
- char *localPtr = buffer;
-
- // This is not a full-blown implementation of readLine, but it
- // suffices for Phantasmagoria
- while (startPos + bytesRead < size) {
- bytesRead++;
-
- if (*_ptr == 0 || *_ptr == 0x0A) {
- _ptr++;
- *localPtr = 0;
- return bytesRead;
- } else {
- *localPtr++ = *_ptr++;
- }
- }
-
- return bytesRead;
-}
-
-bool VirtualIndexFile::seek(int32 offset, int whence) {
- uint32 startPos = _ptr - _buffer;
- assert(offset >= 0);
-
- switch (whence) {
- case SEEK_CUR:
- assert(startPos + offset < _bufferSize);
- _ptr += offset;
- break;
- case SEEK_SET:
- assert(offset < (int32)_bufferSize);
- _ptr = _buffer + offset;
- break;
- case SEEK_END:
- assert((int32)_bufferSize - offset >= 0);
- _ptr = _buffer + (_bufferSize - offset);
- break;
- }
-
- return true;
-}
-
-void VirtualIndexFile::close() {
- if (_changed && !_fileName.empty()) {
- Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName);
- outFile->write(_buffer, _bufferSize);
- delete outFile;
- }
-
- // Maintain the buffer, and seek to the beginning of it
- _ptr = _buffer;
-}
-
-#endif
-
} // End of namespace Sci
diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h
index 54627d5228..982d7b7823 100644
--- a/engines/sci/engine/file.h
+++ b/engines/sci/engine/file.h
@@ -43,7 +43,6 @@ enum {
#define VIRTUALFILE_HANDLE_START 32000
#define VIRTUALFILE_HANDLE_SCI32SAVE 32100
-#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
#define VIRTUALFILE_HANDLE_SCIAUDIO 32300
#define VIRTUALFILE_HANDLE_END 32300
@@ -93,50 +92,7 @@ private:
void addAsVirtualFiles(Common::String title, Common::String fileMask);
};
-
-#ifdef ENABLE_SCI32
-
-/**
- * An implementation of a virtual file that supports basic read and write
- * operations simultaneously.
- *
- * This class has been initially implemented for Phantasmagoria, which has its
- * own custom save/load code. The load code keeps checking for the existence
- * of the save index file and keeps closing and reopening it for each save
- * slot. This is notoriously slow and clumsy, and introduces noticeable delays,
- * especially for non-desktop systems. Also, its game scripts request to open
- * the index file for reading and writing with the same parameters
- * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover,
- * the game scripts reopen the index file for writing in order to update it
- * and seek within it. We do not support seeking in writeable streams, and the
- * fact that our saved games are ZIP files makes this operation even more
- * expensive. Finally, the savegame index file is supposed to be expanded when
- * a new save slot is added.
- * For the aforementioned reasons, this class has been implemented, which offers
- * the basic functionality needed by the game scripts in Phantasmagoria.
- */
-class VirtualIndexFile {
-public:
- VirtualIndexFile(Common::String fileName);
- VirtualIndexFile(uint32 initialSize);
- ~VirtualIndexFile();
-
- uint32 read(char *buffer, uint32 size);
- uint32 readLine(char *buffer, uint32 size);
- uint32 write(const char *buffer, uint32 size);
- bool seek(int32 offset, int whence);
- void close();
-
-private:
- char *_buffer;
- uint32 _bufferSize;
- char *_ptr;
-
- Common::String _fileName;
- bool _changed;
-};
-
-#endif
+uint findFreeFileHandle(EngineState *s);
} // End of namespace Sci
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 2fc338b618..2afb8b73d1 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -885,8 +885,8 @@ void Kernel::loadKernelNames(GameFeatures *features) {
// how kDoSound is called from Sound::play().
// Known games that use this:
// GK2 demo
- // KQ7 1.4
- // PQ4 SWAT demo
+ // KQ7 1.4/1.51
+ // PQ:SWAT demo
// LSL6
// PQ4CD
// QFG4CD
@@ -897,7 +897,7 @@ void Kernel::loadKernelNames(GameFeatures *features) {
_kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo);
// OnMe is IsOnMe here, but they should be compatible
- _kernelNames[0x23] = "Robot"; // Graph in SCI2
+ _kernelNames[0x23] = g_sci->getGameId() == GID_LSL6HIRES ? "Empty" : "Robot"; // Graph in SCI2
_kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2
} else {
// Normal SCI2.1 kernel table
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index d95e228045..5ff4f932be 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -441,6 +441,15 @@ reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv);
reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv);
reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv);
+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 kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv);
+
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
reg_t kArray(EngineState *s, int argc, reg_t *argv);
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
@@ -538,8 +547,17 @@ reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv);
-reg_t kPalCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv);
+reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv);
reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv);
+
+reg_t kPalCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv);
+
reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv);
reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv);
reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index dacaafe757..8a1176eed8 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -291,12 +291,13 @@ static const SciKernelMapSubEntry kPalVary_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalette_subops[] = {
- { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
+ { SIG_SCI16, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
{ SIG_SCI16, 2, MAP_CALL(PaletteSetFlag), "iii", NULL },
{ SIG_SCI16, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds },
#ifdef ENABLE_SCI32
+ { SIG_SCI32, 1, MAP_CALL(PaletteSetFromResource32), "i(i)", NULL },
{ SIG_SCI32, 2, MAP_CALL(PaletteSetFade), "iii", NULL },
- { SIG_SCI32, 3, MAP_CALL(PaletteFindColor), "iii", NULL },
+ { SIG_SCI32, 3, MAP_CALL(PaletteFindColor32), "iii", NULL },
#endif
{ SIG_SCI16, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
{ SIG_SCI16, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
@@ -335,6 +336,16 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
#ifdef ENABLE_SCI32
// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kPalCycle_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(PalCycleSetCycle), "iii(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(PalCycleDoCycle), "i(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(PalCyclePause), "(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(PalCycleOn), "(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(PalCycleOff), "(i)", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kSave_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL },
{ SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL },
@@ -412,6 +423,22 @@ static const SciKernelMapSubEntry kList_subops[] = {
SCI_SUBOPENTRY_TERMINATOR
};
+// There are a lot of subops to PlayVMD, but only a few of them are ever
+// actually used by games
+// version, subId, function-mapping, signature, workarounds
+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, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL },
+ { SIG_SINCE_SCI21, 17, MAP_DUMMY(PlayVMDStartBlob), "", NULL },
+ { SIG_SINCE_SCI21, 18, MAP_DUMMY(PlayVMDStopBlobs), "", NULL },
+ { SIG_SINCE_SCI21, 21, MAP_CALL(PlayVMDSetBlackoutArea), "iiii", NULL },
+ { SIG_SINCE_SCI21, 23, MAP_CALL(PlayVMDRestrictPalette), "ii", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kRemapColors_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
@@ -746,7 +773,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL },
{ MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL },
- { MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
+ { MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL },
// SCI2 Empty functions
@@ -792,7 +819,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
{ MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
{ MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
- { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL },
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL },
{ MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index d604bb85d0..4508a481a0 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -29,6 +29,7 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
+#include "common/memstream.h"
#include "gui/saveload.h"
@@ -263,19 +264,6 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- if (s->_virtualIndexFile) {
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
- } else {
- Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH);
- Common::String wrappedName = g_sci->wrapFilename(englishName);
- if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) {
- s->_virtualIndexFile = new VirtualIndexFile(wrappedName);
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
- }
- }
- }
-
// Shivers is trying to store savegame descriptions and current spots in
// separate .SG files, which are hardcoded in the scripts.
// Essentially, there is a normal save file, created by the executable
@@ -313,18 +301,18 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
listSavegames(saves);
int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START);
- if (!s->_virtualIndexFile) {
- // Make the virtual file buffer big enough to avoid having it grow dynamically.
- // 50 bytes should be more than enough.
- s->_virtualIndexFile = new VirtualIndexFile(50);
- }
+ int size = strlen(saves[savegameNr].name) + 2;
+ char *buf = (char *)malloc(size);
+ strcpy(buf, saves[savegameNr].name);
+ buf[size - 1] = 0; // Spot description (empty)
- s->_virtualIndexFile->seek(0, SEEK_SET);
- s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name));
- s->_virtualIndexFile->write("\0", 1);
- s->_virtualIndexFile->write("\0", 1); // Spot description (empty)
- s->_virtualIndexFile->seek(0, SEEK_SET);
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
+ uint handle = findFreeFileHandle(s);
+
+ s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buf, size, DisposeAfterUse::YES);
+ s->_fileHandles[handle]._out = nullptr;
+ s->_fileHandles[handle]._name = "";
+
+ return make_reg(0, handle);
}
}
#endif
@@ -349,13 +337,6 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
uint16 handle = argv[0].toUint16();
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->close();
- return SIGNAL_REG;
- }
-#endif
-
if (handle >= VIRTUALFILE_HANDLE_START) {
// it's a virtual handle? ignore it
return SIGNAL_REG;
@@ -381,17 +362,9 @@ reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) {
char *buf = new char[size];
debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- bytesRead = s->_virtualIndexFile->read(buf, size);
- } else {
-#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f)
- bytesRead = f->_in->read(buf, size);
-#ifdef ENABLE_SCI32
- }
-#endif
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f)
+ bytesRead = f->_in->read(buf, size);
// TODO: What happens if less bytes are read than what has
// been requested? (i.e. if bytesRead is non-zero, but still
@@ -411,20 +384,11 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
s->_segMan->memcpy((byte *)buf, argv[1], size);
debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->write(buf, size);
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f) {
+ f->_out->write(buf, size);
success = true;
- } else {
-#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f) {
- f->_out->write(buf, size);
- success = true;
- }
-#ifdef ENABLE_SCI32
}
-#endif
delete[] buf;
if (success)
@@ -463,13 +427,6 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
const Common::String wrappedName = g_sci->wrapFilename(name);
result = saveFileMan->removeSavefile(wrappedName);
}
-
-#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- delete s->_virtualIndexFile;
- s->_virtualIndexFile = 0;
- }
-#endif
} else {
const Common::String wrappedName = g_sci->wrapFilename(name);
result = saveFileMan->removeSavefile(wrappedName);
@@ -488,12 +445,7 @@ reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize);
uint32 bytesRead;
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE)
- bytesRead = s->_virtualIndexFile->readLine(buf, maxsize);
- else
-#endif
- bytesRead = fgets_wrapper(s, buf, maxsize, handle);
+ bytesRead = fgets_wrapper(s, buf, maxsize, handle);
s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
delete[] buf;
@@ -520,13 +472,6 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->write(str.c_str(), str.size());
- return NULL_REG;
- }
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f) {
@@ -547,11 +492,6 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
uint16 whence = argv[2].toUint16();
debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE)
- return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f && f->_in) {
@@ -591,14 +531,6 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
Common::String name = s->_segMan->getString(argv[0]);
-#ifdef ENABLE_SCI32
- // Cache the file existence result for the Phantasmagoria
- // save index file, as the game scripts keep checking for
- // its existence.
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
- return TRUE_REG;
-#endif
-
bool exists = false;
if (g_sci->getGameId() == GID_PEPPER) {
@@ -611,6 +543,9 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
+ // TODO: It may apparently be worth caching the existence of
+ // phantsg.dir, and possibly even keeping it open persistently
+
// Check for regular file
exists = Common::File::exists(name);
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 019a06930c..9cfe53255b 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -790,6 +790,19 @@ reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv) {
+ const GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->loadPalette(paletteId);
+ return s->r_acc;
+}
+
+reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) {
+ const uint8 r = argv[0].toUint16();
+ const uint8 g = argv[1].toUint16();
+ const uint8 b = argv[2].toUint16();
+ return make_reg(0, g_sci->_gfxPalette32->matchColor(r, g, b));
+}
+
reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) {
uint16 fromColor = argv[0].toUint16();
uint16 toColor = argv[1].toUint16();
@@ -862,67 +875,57 @@ reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
}
-enum {
- kSetCycle = 0,
- kDoCycle = 1,
- kCyclePause = 2,
- kCycleOn = 3,
- kCycleOff = 4
-};
-
reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
- // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen)
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- switch (argv[0].toUint16()) {
- case kSetCycle: {
- uint16 fromColor = argv[1].toUint16();
- uint16 toColor = argv[2].toUint16();
- int16 direction = argv[3].toSint16();
- uint16 delay = (argc == 4 ? 0 : argv[4].toUint16());
-
- g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay);
- }
- break;
- case kDoCycle: {
- uint16 fromColor = argv[1].toUint16();
- int16 speed = (argc == 2) ? 1 : argv[2].toSint16();
- g_sci->_gfxPalette32->doCycle(fromColor, speed);
- }
- break;
- case kCyclePause: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllPause();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cyclePause(fromColor);
- }
- }
- break;
- case kCycleOn: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllOn();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cycleOn(fromColor);
- }
- }
- break;
- case kCycleOff: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllOff();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cycleOff(fromColor);
- }
- break;
- }
- default:
- // In SCI2.1 there are no values above 4, so should never get here;
- // SCI just returns early if this ever happens.
- assert(false);
- break;
+reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) {
+ const uint16 fromColor = argv[0].toUint16();
+ const uint16 toColor = argv[1].toUint16();
+ const int16 direction = argv[2].toSint16();
+ const uint16 delay = argc > 3 ? argv[3].toUint16() : 0;
+
+ g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay);
+ return s->r_acc;
+}
+
+reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv) {
+ const uint16 fromColor = argv[0].toUint16();
+ const int16 speed = argc > 1 ? argv[1].toSint16() : 1;
+
+ g_sci->_gfxPalette32->doCycle(fromColor, speed);
+ return s->r_acc;
+}
+
+reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllPause();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cyclePause(fromColor);
}
+ return s->r_acc;
+}
+reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllOn();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cycleOn(fromColor);
+ }
+ return s->r_acc;
+}
+
+reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllOff();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cycleOff(fromColor);
+ }
return s->r_acc;
}
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index 065625f85f..0d6831139a 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -409,6 +409,9 @@ reg_t kGetConfig(EngineState *s, int argc, reg_t *argv) {
} else if (setting == "startroom") {
// Debug setting in LSL7, specifies the room to start from.
s->_segMan->strcpy(data, "");
+ } else if (setting == "game") {
+ // Hoyle 5 Demo startup.
+ s->_segMan->strcpy(data, "");
} else {
error("GetConfig: Unknown configuration setting %s", setting.c_str());
}
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 8db0c542eb..1096e78cca 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -40,7 +40,8 @@
#include "video/qt_decoder.h"
#include "sci/video/seq_decoder.h"
#ifdef ENABLE_SCI32
-#include "video/coktel_decoder.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/video32.h"
#include "sci/video/robot_decoder.h"
#endif
@@ -289,113 +290,73 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
}
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
- uint16 operation = argv[0].toUint16();
- Video::VideoDecoder *videoDecoder = 0;
- bool reshowCursor = g_sci->_gfxCursor->isVisible();
- Common::String warningMsg;
-
- switch (operation) {
- case 0: // init
- s->_videoState.reset();
- s->_videoState.fileName = s->_segMan->derefString(argv[1]);
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- if (argc > 2 && argv[2] != NULL_REG)
- warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2]));
- break;
- case 1:
- {
- // Set VMD parameters. Called with a maximum of 6 parameters:
- //
- // x, y, flags, gammaBoost, gammaFirst, gammaLast
- //
- // gammaBoost boosts palette colors in the range gammaFirst to
- // gammaLast, but only if bit 4 in flags is set. Percent value such that
- // 0% = no amplification These three parameters are optional if bit 4 is
- // clear. Also note that the x, y parameters play subtle games if used
- // with subfx 21. The subtleness has to do with creation of temporary
- // planes and positioning relative to such planes.
-
- uint16 flags = argv[3].getOffset();
- Common::String flagspec;
-
- if (argc > 3) {
- if (flags & kDoubled)
- flagspec += "doubled ";
- if (flags & kDropFrames)
- flagspec += "dropframes ";
- if (flags & kBlackLines)
- flagspec += "blacklines ";
- if (flags & kUnkBit3)
- flagspec += "bit3 ";
- if (flags & kGammaBoost)
- flagspec += "gammaboost ";
- if (flags & kHoldBlackFrame)
- flagspec += "holdblack ";
- if (flags & kHoldLastFrame)
- flagspec += "holdlast ";
- if (flags & kUnkBit7)
- flagspec += "bit7 ";
- if (flags & kStretch)
- flagspec += "stretch";
-
- warning("VMDFlags: %s", flagspec.c_str());
-
- s->_videoState.flags = flags;
- }
+reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv) {
+ const Common::String fileName = s->_segMan->getString(argv[0]);
+ // argv[1] is an optional cache size argument which we do not use
+ // const uint16 cacheSize = argc > 1 ? CLIP<int16>(argv[1].toSint16(), 16, 1024) : 0;
+ const VMDPlayer::OpenFlags flags = argc > 2 ? (VMDPlayer::OpenFlags)argv[2].toUint16() : VMDPlayer::kOpenFlagNone;
- warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset());
- s->_videoState.x = argv[1].getOffset();
- s->_videoState.y = argv[2].getOffset();
+ return make_reg(0, g_sci->_video32->getVMDPlayer().open(fileName, flags));
+}
- if (argc > 4 && flags & 16)
- warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset());
- break;
+reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv) {
+ const int16 x = argv[0].toSint16();
+ const int16 y = argv[1].toSint16();
+ const VMDPlayer::PlayFlags flags = argc > 2 ? (VMDPlayer::PlayFlags)argv[2].toUint16() : VMDPlayer::kPlayFlagNone;
+ int16 boostPercent;
+ int16 boostStartColor;
+ int16 boostEndColor;
+ if (argc > 5 && (flags & VMDPlayer::kPlayFlagBoost)) {
+ boostPercent = argv[3].toSint16();
+ boostStartColor = argv[4].toSint16();
+ boostEndColor = argv[5].toSint16();
+ } else {
+ boostPercent = 0;
+ boostStartColor = -1;
+ boostEndColor = -1;
}
- case 6: // Play
- videoDecoder = new Video::AdvancedVMDDecoder();
- if (s->_videoState.fileName.empty()) {
- // Happens in Lighthouse
- warning("kPlayVMD: Empty filename passed");
- return s->r_acc;
- }
+ g_sci->_video32->getVMDPlayer().init(x, y, flags, boostPercent, boostStartColor, boostEndColor);
- if (!videoDecoder->loadFile(s->_videoState.fileName)) {
- warning("Could not open VMD %s", s->_videoState.fileName.c_str());
- break;
- }
+ return make_reg(0, 0);
+}
- if (reshowCursor)
- g_sci->_gfxCursor->kernelHide();
+reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, g_sci->_video32->getVMDPlayer().close());
+}
- playVideo(videoDecoder, s->_videoState);
+reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv) {
+ const VMDPlayer::EventFlags flags = (VMDPlayer::EventFlags)argv[0].toUint16();
+ const int16 lastFrameNo = argc > 1 ? argv[1].toSint16() : -1;
+ const int16 yieldInterval = argc > 2 ? argv[2].toSint16() : -1;
+ return make_reg(0, g_sci->_video32->getVMDPlayer().kernelPlayUntilEvent(flags, lastFrameNo, yieldInterval));
+}
- if (reshowCursor)
- g_sci->_gfxCursor->kernelShow();
- break;
- case 23: // set video palette range
- s->_vmdPalStart = argv[1].toUint16();
- s->_vmdPalEnd = argv[2].toUint16();
- break;
- case 14:
- // Takes an additional integer parameter (e.g. 3)
- case 16:
- // Takes an additional parameter, usually 0
- case 21:
- // Looks to be setting the video size and position. Called with 4 extra integer
- // parameters (e.g. 86, 41, 235, 106)
- default:
- warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().setShowCursor((bool)argv[0].toUint16());
+ return s->r_acc;
+}
- for (int i = 0; i < argc; i++) {
- warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
- warningMsg += (i == argc - 1 ? ")" : ", ");
- }
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- warning("%s", warningMsg.c_str());
- break;
- }
+ Common::Rect blackoutArea;
+ blackoutArea.left = MAX((int16)0, argv[0].toSint16());
+ blackoutArea.top = MAX((int16)0, argv[1].toSint16());
+ blackoutArea.right = MIN(scriptWidth, (int16)(argv[2].toSint16() + 1));
+ blackoutArea.bottom = MIN(scriptHeight, (int16)(argv[3].toSint16() + 1));
+ g_sci->_video32->getVMDPlayer().setBlackoutArea(blackoutArea);
+ return s->r_acc;
+}
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().restrictPalette(argv[0].toUint16(), argv[1].toUint16());
return s->r_acc;
}
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 0972aec4a4..31fb848a2c 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -398,8 +398,13 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
_segMan->saveLoadWithSerializer(s);
g_sci->_soundCmd->syncPlayList(s);
- // NOTE: This will be GfxPalette32 for SCI32 engine games
- g_sci->_gfxPalette16->saveLoadWithSerializer(s);
+
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ g_sci->_gfxPalette32->saveLoadWithSerializer(s);
+ } else
+#endif
+ g_sci->_gfxPalette16->saveLoadWithSerializer(s);
}
void Vocabulary::saveLoadWithSerializer(Common::Serializer &s) {
@@ -767,7 +772,7 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint16LE(_varyFromColor);
s.syncAsSint16LE(_varyToColor);
s.syncAsUint16LE(_varyNumTimesPaused);
- s.syncAsByte(_versionUpdated);
+ s.syncAsByte(_needsUpdate);
s.syncAsSint32LE(_varyTime);
s.syncAsUint32LE(_varyLastTick);
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 70436e1269..e6eed0b4b7 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -1453,6 +1453,167 @@ static const SciScriptPatcherEntry kq6Signatures[] = {
};
// ===========================================================================
+
+// King's Quest 7 has really weird subtitles. It seems as if the subtitles were
+// not fully finished.
+//
+// Method kqMessager::findTalker in script 0 tries to figure out, which class to use for
+// displaying subtitles. It uses the "talker" data of the given message to do that.
+// Strangely this "talker" data seems to be quite broken.
+// For example chapter 2 starts with a cutscene.
+// Troll king: "Welcome, most beautiful of princesses!" - talker 6
+// Which is followed by the princess going
+// "Hmm?" - which is set to talker 99, normally the princess is talker 7.
+//
+// Talker 99 is seen as unknown and thus treated as "narrator", which makes
+// the scripts put the text at the top of the game screen and even use a
+// different font.
+//
+// In other cases, when the player character thinks to himself talker 99
+// is also used. In such situations it may make somewhat sense to do so,
+// but putting the text at the top of the screen is also irritating to the player.
+// It's really weird.
+//
+// The scripts also put the regular text in the middle of the screen, blocking
+// animations.
+//
+// And for certain rooms, the subtitle box may use another color
+// like for example pink/purple at the start of chapter 5.
+//
+// We fix all of that (hopefully - lots of testing is required).
+// We put the text at the bottom of the play screen.
+// We also make the scripts use the regular KQTalker instead of KQNarrator.
+// And we also make the subtitle box use color 255, which is fixed white.
+//
+// Applies to at least: PC CD 1.4 English, 1.51 English, 1.51 German, 2.00 English
+// Patched method: KQNarrator::init (script 31)
+static const uint16 kq7SignatureSubtitleFix1[] = {
+ SIG_MAGICDWORD,
+ 0x39, 0x25, // pushi 25h (fore)
+ 0x78, // push1
+ 0x39, 0x06, // pushi 06 - sets back to 6
+ 0x39, 0x26, // pushi 26 (back)
+ 0x78, // push1
+ 0x78, // push1 - sets back to 1
+ 0x39, 0x2a, // pushi 2Ah (font)
+ 0x78, // push1
+ 0x89, 0x16, // lsg global[16h] - sets font to global[16h]
+ 0x7a, // push2 (y)
+ 0x78, // push1
+ 0x76, // push0 - sets y to 0
+ 0x54, SIG_UINT16(0x0018), // self 18h
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix1[] = {
+ 0x33, 0x12, // jmp [skip special init code]
+ PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+// Patched method: Narrator::init (script 64928)
+static const uint16 kq7SignatureSubtitleFix2[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x5a, // lsg global[5a]
+ 0x35, 0x02, // ldi 02
+ 0x12, // and
+ 0x31, 0x1e, // bnt [skip audio volume code]
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+ 0x76, // push0
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x04, 0x00, // send 04
+ 0x65, 0x32, // aTop curVolume
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+ 0x78, // push1
+ 0x67, 0x32, // pTos curVolume
+ 0x35, 0x02, // ldi 02
+ 0x06, // mul
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x08, // div
+ 0x36, // push
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x06, 0x00, // send 06
+ // end of volume code
+ 0x35, 0x01, // ldi 01
+ 0x65, 0x28, // aTop initialized
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix2[] = {
+ PATCH_ADDTOOFFSET(+5), // skip to bnt
+ 0x31, 0x1b, // bnt [skip audio volume code]
+ PATCH_ADDTOOFFSET(+15), // right after "aTop curVolume / pushi masterVolume / push1"
+ 0x7a, // push2
+ 0x06, // mul (saves 3 bytes in total)
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x08, // div
+ 0x36, // push
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x06, 0x00, // send 06
+ // end of volume code
+ 0x35, 118, // ldi 118d
+ 0x65, 0x16, // aTop y
+ 0x78, // push1 (saves 1 byte)
+ 0x69, 0x28, // sTop initialized
+ PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+// Patched method: Narrator::say (script 64928)
+static const uint16 kq7SignatureSubtitleFix3[] = {
+ SIG_MAGICDWORD,
+ 0x63, 0x28, // pToa initialized
+ 0x18, // not
+ 0x31, 0x07, // bnt [skip init code]
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi init (008Eh for 2.00, 0093h for 1.51)
+ 0x76, // push0
+ 0x54, SIG_UINT16(0x0004), // self 04
+ // end of init code
+ 0x8f, 0x00, // lsp param[0]
+ 0x35, 0x01, // ldi 01
+ 0x1e, // gt?
+ 0x31, 0x08, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x31, 0x04, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x33, 0x02, // jmp [over set acc to 0 code]
+ 0x35, 0x00, // ldi 00
+ 0x65, 0x18, // aTop caller
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix3[] = {
+ PATCH_ADDTOOFFSET(+2), // skip over "pToa initialized code"
+ 0x2f, 0x0c, // bt [skip init code] - saved 1 byte
+ 0x38,
+ PATCH_GETORIGINALBYTE(+6),
+ PATCH_GETORIGINALBYTE(+7), // pushi (init)
+ 0x76, // push0
+ 0x54, PATCH_UINT16(0x0004), // self 04
+ // additionally set background color here (5 bytes)
+ 0x34, PATCH_UINT16(255), // pushi 255d
+ 0x65, 0x2e, // aTop back
+ // end of init code
+ 0x8f, 0x00, // lsp param[0]
+ 0x35, 0x01, // ldi 01 - this may get optimized to get another byte
+ 0x1e, // gt?
+ 0x31, 0x04, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x2f, 0x02, // bt [over set acc to 0 code]
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry kq7Signatures[] = {
+ { true, 31, "subtitle fix 1/3", 1, kq7SignatureSubtitleFix1, kq7PatchSubtitleFix1 },
+ { true, 64928, "subtitle fix 2/3", 1, kq7SignatureSubtitleFix2, kq7PatchSubtitleFix2 },
+ { true, 64928, "subtitle fix 3/3", 1, kq7SignatureSubtitleFix3, kq7PatchSubtitleFix3 },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
// Script 210 in the German version of Longbow handles the case where Robin
// hands out the scroll to Marion and then types his name using the hand code.
// The German version script contains a typo (probably a copy/paste error),
@@ -1506,9 +1667,9 @@ static const uint16 longbowPatchShowHandCode[] = {
// that's why I rather patched the code, that uses the locals for a lookup.
// Which means it doesn't matter anymore when those locals are overwritten.
//
-// Applies to at least: English PC floppy, German PC floppy (not tested), English Amiga floppy
+// Applies to at least: English PC floppy, German PC floppy, English Amiga floppy
// Responsible method: export 2 of script 225
-// Fixes bug: #6571
+// Fixes bug: #6751
static const uint16 longbowSignatureBerryBushFix[] = {
0x89, 0x70, // lsg global[70h]
0x35, 0x03, // ldi 03h
@@ -4453,6 +4614,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3
case GID_KQ6:
signatureTable = kq6Signatures;
break;
+ case GID_KQ7:
+ signatureTable = kq7Signatures;
+ break;
case GID_LAURABOW:
signatureTable = laurabow1Signatures;
break;
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index fda78317b5..2c85907628 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -70,9 +70,6 @@ static const uint16 s_halfWidthSJISMap[256] = {
EngineState::EngineState(SegManager *segMan)
: _segMan(segMan),
-#ifdef ENABLE_SCI32
- _virtualIndexFile(0),
-#endif
_dirseeker() {
reset(false);
@@ -80,9 +77,6 @@ EngineState::EngineState(SegManager *segMan)
EngineState::~EngineState() {
delete _msgState;
-#ifdef ENABLE_SCI32
- delete _virtualIndexFile;
-#endif
}
void EngineState::reset(bool isRestoring) {
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index cf9a753f5c..dd8d76f002 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -131,10 +131,6 @@ public:
int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween
int16 _lastSaveNewId; // last newly created filename-id by kSaveGame
-#ifdef ENABLE_SCI32
- VirtualIndexFile *_virtualIndexFile;
-#endif
-
// see detection.cpp / SciEngine::loadGameState()
bool _delayedRestoreGame; // boolean, that triggers delayed restore (triggered by ScummVM menu)
int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu)
@@ -205,6 +201,7 @@ public:
uint16 _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
+ // TODO: Excise video code from the state manager
VideoState _videoState;
uint16 _vmdPalStart, _vmdPalEnd;
bool _syncedAudioOptions;
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index f8cd5fd171..48de054a31 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -83,9 +83,11 @@ const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio
#pragma mark -
#pragma mark CelObj
+bool CelObj::_drawBlackLines = false;
void CelObj::init() {
CelObj::deinit();
+ _drawBlackLines = false;
_nextCacheId = 1;
_scaler = new CelScaler();
_cache = new CelCache;
@@ -407,6 +409,7 @@ void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Re
const Common::Point &scaledPosition = screenItem._scaledPosition;
const Ratio &scaleX = screenItem._ratioX;
const Ratio &scaleY = screenItem._ratioY;
+ _drawBlackLines = screenItem._drawBlackLines;
if (_remap) {
// NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
@@ -488,6 +491,8 @@ void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Re
}
}
}
+
+ _drawBlackLines = false;
}
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) {
@@ -565,12 +570,7 @@ uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const {
void CelObj::submitPalette() const {
if (_hunkPaletteOffset) {
- Palette palette;
-
- byte *res = getResPointer();
- // NOTE: In SCI engine this uses HunkPalette::Init.
- // TODO: Use a better size value
- g_sci->_gfxPalette32->createFromData(res + _hunkPaletteOffset, 999999, &palette);
+ HunkPalette palette(getResPointer() + _hunkPaletteOffset);
g_sci->_gfxPalette32->submit(palette);
}
}
@@ -627,7 +627,7 @@ void CelObj::putCopyInCache(const int cacheIndex) const {
#pragma mark -
#pragma mark CelObj - Drawing
-template<typename MAPPER, typename SCALER>
+template<typename MAPPER, typename SCALER, bool DRAW_BLACK_LINES>
struct RENDERER {
MAPPER &_mapper;
SCALER &_scaler;
@@ -645,6 +645,12 @@ struct RENDERER {
const int16 targetWidth = targetRect.width();
const int16 targetHeight = targetRect.height();
for (int16 y = 0; y < targetHeight; ++y) {
+ if (DRAW_BLACK_LINES && (y % 2) == 0) {
+ memset(targetPixel, 0, targetWidth);
+ targetPixel += targetWidth + skipStride;
+ continue;
+ }
+
_scaler.setTarget(targetRect.left, targetRect.top + y);
for (int16 x = 0; x < targetWidth; ++x) {
@@ -661,7 +667,7 @@ void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common
MAPPER mapper;
SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaledPosition);
- RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
+ RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
renderer.draw(target, targetRect, scaledPosition);
}
@@ -670,8 +676,13 @@ void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common
MAPPER mapper;
SCALER scaler(*this, targetRect, scaledPosition, scaleX, scaleY);
- RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
- renderer.draw(target, targetRect, scaledPosition);
+ if (_drawBlackLines) {
+ RENDERER<MAPPER, SCALER, true> renderer(mapper, scaler, _transparentColor);
+ renderer.draw(target, targetRect, scaledPosition);
+ } else {
+ RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
+ renderer.draw(target, targetRect, scaledPosition);
+ }
}
void dummyFill(Buffer &target, const Common::Rect &targetRect) {
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index e405592b5f..eb6ce3a3c9 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -228,6 +228,18 @@ class ScreenItem;
class CelObj {
protected:
/**
+ * When true, every second line of the cel will be
+ * rendered as a black line.
+ *
+ * @see ScreenItem::_drawBlackLines
+ * @note Using a static member because otherwise this
+ * would otherwise need to be copied down through
+ * several calls. (SSCI did similar, using a global
+ * variable.)
+ */
+ static bool _drawBlackLines;
+
+ /**
* When true, this cel will be horizontally mirrored
* when it is drawn. This is an internal flag that is
* set by draw methods based on the combination of the
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index 4cbb4541df..6b91bb4679 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -459,7 +459,7 @@ void ScrollWindow::hide() {
return;
}
- g_sci->_gfxFrameout->deleteScreenItem(_screenItem, _plane);
+ g_sci->_gfxFrameout->deleteScreenItem(*_screenItem, _plane);
_screenItem = nullptr;
g_sci->_gfxFrameout->frameOut(true);
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index 8d125c45b3..5125469cfe 100644
--- a/engines/sci/graphics/cursor.h
+++ b/engines/sci/graphics/cursor.h
@@ -25,6 +25,8 @@
#include "common/array.h"
#include "common/hashmap.h"
+#include "sci/sci.h"
+#include "sci/graphics/helpers.h"
namespace Sci {
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index c0feea8999..7bb9a4f5cf 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -115,6 +115,7 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
}
switch (g_sci->getGameId()) {
+ case GID_HOYLE5:
case GID_GK2:
case GID_LIGHTHOUSE:
case GID_LSL7:
@@ -278,20 +279,52 @@ bool GfxFrameout::checkForFred(const reg_t object) {
#pragma mark -
#pragma mark Screen items
-void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, Plane *plane) {
- if (screenItem->_created == 0) {
- screenItem->_created = 0;
- screenItem->_updated = 0;
- screenItem->_deleted = getScreenCount();
+void GfxFrameout::addScreenItem(ScreenItem &screenItem) const {
+ Plane *plane = _planes.findByObject(screenItem._plane);
+ if (plane == nullptr) {
+ error("GfxFrameout::addScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+ }
+ plane->_screenItemList.add(&screenItem);
+}
+
+void GfxFrameout::updateScreenItem(ScreenItem &screenItem) const {
+ // TODO: In SCI3+ this will need to go through Plane
+// Plane *plane = _planes.findByObject(screenItem._plane);
+// if (plane == nullptr) {
+// error("GfxFrameout::updateScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+// }
+
+ screenItem.update();
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem) {
+ Plane *plane = _planes.findByObject(screenItem._plane);
+ if (plane == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+ }
+ if (plane->_screenItemList.findByObject(screenItem._object) == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItem._object), PRINT_REG(screenItem._plane));
+ }
+ deleteScreenItem(screenItem, *plane);
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, Plane &plane) {
+ if (screenItem._created == 0) {
+ screenItem._created = 0;
+ screenItem._updated = 0;
+ screenItem._deleted = getScreenCount();
} else {
- plane->_screenItemList.erase(screenItem);
- plane->_screenItemList.pack();
+ plane._screenItemList.erase(&screenItem);
+ plane._screenItemList.pack();
}
}
-void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, const reg_t planeObject) {
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, const reg_t planeObject) {
Plane *plane = _planes.findByObject(planeObject);
- deleteScreenItem(screenItem, plane);
+ if (plane == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItem._object));
+ }
+ deleteScreenItem(screenItem, *plane);
}
void GfxFrameout::kernelAddScreenItem(const reg_t object) {
@@ -364,7 +397,7 @@ void GfxFrameout::kernelDeleteScreenItem(const reg_t object) {
return;
}
- deleteScreenItem(screenItem, plane);
+ deleteScreenItem(*screenItem, *plane);
}
#pragma mark -
@@ -540,7 +573,7 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseR
// _robot->frameAlmostVisible();
// }
- _palette->updateHardware();
+ _palette->updateHardware(!shouldShowBits);
if (shouldShowBits) {
showBits();
@@ -1111,7 +1144,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
_palette->submit(nextPalette);
_palette->updateFFrame();
- _palette->updateHardware();
+ _palette->updateHardware(false);
showBits();
_frameNowVisible = true;
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index cc62c61d22..99658ede6a 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -202,14 +202,29 @@ private:
public:
/**
+ * Adds a screen item.
+ */
+ void addScreenItem(ScreenItem &screenItem) const;
+
+ /**
+ * Updates a screen item.
+ */
+ void updateScreenItem(ScreenItem &screenItem) const;
+
+ /**
+ * Deletes a screen item.
+ */
+ void deleteScreenItem(ScreenItem &screenItem);
+
+ /**
* Deletes a screen item from the given plane.
*/
- void deleteScreenItem(ScreenItem *screenItem, Plane *plane);
+ void deleteScreenItem(ScreenItem &screenItem, Plane &plane);
/**
* Deletes a screen item from the given plane.
*/
- void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
+ void deleteScreenItem(ScreenItem &screenItem, const reg_t plane);
void kernelAddScreenItem(const reg_t object);
void kernelUpdateScreenItem(const reg_t object);
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index bfd46484e9..74eb1629d0 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -81,7 +81,7 @@ void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t plan
}
_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
- g_sci->_gfxFrameout->deleteScreenItem(screenItem, plane);
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
}
void GfxPaint32::plotter(int x, int y, int color, void *data) {
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 7335dc59d0..2178de8a91 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -51,7 +51,7 @@ public:
bool setAmiga();
void modifyAmigaPalette(byte *data);
void setEGA();
- virtual void set(Palette *sciPal, bool force, bool forceRealMerge = false);
+ void set(Palette *sciPal, bool force, bool forceRealMerge = false);
bool insert(Palette *newPalette, Palette *destPalette);
bool merge(Palette *pFrom, bool force, bool forceRealMerge);
uint16 matchColor(byte r, byte g, byte b);
@@ -63,11 +63,11 @@ public:
void drewPicture(GuiResourceId pictureId);
- virtual bool kernelSetFromResource(GuiResourceId resourceId, bool force);
+ bool kernelSetFromResource(GuiResourceId resourceId, bool force);
void kernelSetFlag(uint16 fromColor, uint16 toColor, uint16 flag);
void kernelUnsetFlag(uint16 fromColor, uint16 toColor, uint16 flag);
void kernelSetIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette);
- virtual int16 kernelFindColor(uint16 r, uint16 g, uint16 b);
+ int16 kernelFindColor(uint16 r, uint16 g, uint16 b);
bool kernelAnimate(byte fromColor, byte toColor, int speed);
void kernelAnimateSet();
reg_t kernelSave();
@@ -81,7 +81,7 @@ public:
int16 kernelPalVaryGetCurrentStep();
int16 kernelPalVaryChangeTarget(GuiResourceId resourceId);
void kernelPalVaryChangeTicks(uint16 ticks);
- virtual void kernelPalVaryPause(bool pause);
+ void kernelPalVaryPause(bool pause);
void kernelPalVaryDeinit();
void palVaryUpdate();
void palVaryPrepareForTransition();
@@ -89,7 +89,7 @@ public:
Palette _sysPalette;
- virtual void saveLoadWithSerializer(Common::Serializer &s);
+ void saveLoadWithSerializer(Common::Serializer &s);
void palVarySaveLoadPalette(Common::Serializer &s, Palette *palette);
byte findMacIconBarColor(byte r, byte g, byte b);
diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp
index 0840e82a40..2a98c237b0 100644
--- a/engines/sci/graphics/palette32.cpp
+++ b/engines/sci/graphics/palette32.cpp
@@ -27,19 +27,109 @@
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/resource.h"
+#include "sci/util.h"
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/screen.h"
namespace Sci {
-GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen)
- : GfxPalette(resMan, screen),
+#pragma mark HunkPalette
+
+HunkPalette::HunkPalette(byte *rawPalette) :
+ _version(0),
+ // NOTE: The header size in palettes is garbage. In at least KQ7 2.00b and
+ // Phant1, the 999.pal sets this value to 0. In most other palettes it is
+ // set to 14, but the *actual* size of the header structure used in SSCI is
+ // 13, which is reflected by `kHunkPaletteHeaderSize`.
+ // _headerSize(rawPalette[0]),
+ _numPalettes(rawPalette[10]),
+ _data(nullptr) {
+ assert(_numPalettes == 0 || _numPalettes == 1);
+ if (_numPalettes) {
+ _data = rawPalette;
+ _version = getEntryHeader().version;
+ }
+}
+
+void HunkPalette::setVersion(const uint32 version) {
+ if (_numPalettes != _data[10]) {
+ error("Invalid HunkPalette");
+ }
+
+ if (_numPalettes) {
+ const EntryHeader header = getEntryHeader();
+ if (header.version != _version) {
+ error("Invalid HunkPalette");
+ }
+
+ WRITE_SCI11ENDIAN_UINT32(getPalPointer() + kEntryVersionOffset, version);
+ _version = version;
+ }
+}
+
+const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const {
+ const byte *const data = getPalPointer();
+
+ EntryHeader header;
+ header.startColor = data[10];
+ header.numColors = READ_SCI11ENDIAN_UINT16(data + 14);
+ header.used = data[16];
+ header.sharedUsed = data[17];
+ header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset);
+
+ return header;
+}
+
+const Palette HunkPalette::toPalette() const {
+ Palette outPalette;
+
+ for (int16 i = 0; i < ARRAYSIZE(outPalette.colors); ++i) {
+ outPalette.colors[i].used = false;
+ outPalette.colors[i].r = 0;
+ outPalette.colors[i].g = 0;
+ outPalette.colors[i].b = 0;
+ }
+
+ if (_numPalettes) {
+ const EntryHeader header = getEntryHeader();
+ byte *data = getPalPointer() + kEntryHeaderSize;
+
+ int16 end = header.startColor + header.numColors;
+ assert(end <= 256);
+
+ if (header.sharedUsed) {
+ for (int16 i = header.startColor; i < end; ++i) {
+ outPalette.colors[i].used = header.used;
+ outPalette.colors[i].r = *data++;
+ outPalette.colors[i].g = *data++;
+ outPalette.colors[i].b = *data++;
+ }
+ } else {
+ for (int16 i = header.startColor; i < end; ++i) {
+ outPalette.colors[i].used = *data++;
+ outPalette.colors[i].r = *data++;
+ outPalette.colors[i].g = *data++;
+ outPalette.colors[i].b = *data++;
+ }
+ }
+ }
+
+ return outPalette;
+}
+
+
+#pragma mark -
+#pragma mark GfxPalette32
+
+GfxPalette32::GfxPalette32(ResourceManager *resMan)
+ : _resMan(resMan),
// Palette versioning
_version(1),
- _versionUpdated(false),
- _sourcePalette(_sysPalette),
- _nextPalette(_sysPalette),
+ _needsUpdate(false),
+ _currentPalette(),
+ _sourcePalette(),
+ _nextPalette(),
// Clut
_clutTable(nullptr),
// Palette varying
@@ -55,102 +145,91 @@ GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen)
// Palette cycling
_cyclers(),
_cycleMap() {
- _varyPercent = _varyTargetPercent;
- for (int i = 0, len = ARRAYSIZE(_fadeTable); i < len; ++i) {
- _fadeTable[i] = 100;
- }
- // NOTE: In SCI engine, the palette manager constructor loads
- // the default palette, but in ScummVM this initialisation
- // is performed by SciEngine::run; see r49523 for details
+ _varyPercent = _varyTargetPercent;
+ for (int i = 0, len = ARRAYSIZE(_fadeTable); i < len; ++i) {
+ _fadeTable[i] = 100;
+ }
+
+ loadPalette(999);
}
GfxPalette32::~GfxPalette32() {
+#ifdef ENABLE_SCI3_GAMES
unloadClut();
+#endif
varyOff();
cycleAllOff();
}
inline void mergePaletteInternal(Palette *const to, const Palette *const from) {
- for (int i = 0, len = ARRAYSIZE(to->colors); i < len; ++i) {
+ // The last color is always white, so it is not copied.
+ // (Some palettes try to set the last color, which causes
+ // churning in the palettes when they are merged)
+ for (int i = 0, len = ARRAYSIZE(to->colors) - 1; i < len; ++i) {
if (from->colors[i].used) {
to->colors[i] = from->colors[i];
}
}
}
-void GfxPalette32::submit(Palette &palette) {
- // TODO: The resource manager in SCI32 retains raw data of palettes from
- // the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and
- // the version number for submitted palettes is set in the raw palette
- // data in memory as an int at an offset
- // `rawData + *rawData[0x0a] * 2 + 31`. However, ScummVM does not retain
- // resource data like this, so this versioning code, while accurate to
- // the original engine, does not do much.
- // (Hopefully this was an optimisation mechanism in SCI engine and not a
- // clever thing to keep the same palette submitted many times from
- // overwriting other palette entries.)
- if (palette.timestamp == _version) {
+void GfxPalette32::submit(const Palette &palette) {
+ const Palette oldSourcePalette(_sourcePalette);
+ mergePaletteInternal(&_sourcePalette, &palette);
+
+ if (!_needsUpdate && _sourcePalette != oldSourcePalette) {
+ ++_version;
+ _needsUpdate = true;
+ }
+}
+
+void GfxPalette32::submit(HunkPalette &hunkPalette) {
+ if (hunkPalette.getVersion() == _version) {
return;
}
- Palette oldSourcePalette(_sourcePalette);
+ const Palette oldSourcePalette(_sourcePalette);
+ const Palette palette = hunkPalette.toPalette();
mergePaletteInternal(&_sourcePalette, &palette);
- if (!_versionUpdated && _sourcePalette != oldSourcePalette) {
+ if (!_needsUpdate && oldSourcePalette != _sourcePalette) {
++_version;
- _versionUpdated = true;
+ _needsUpdate = true;
}
- // Technically this information is supposed to be persisted through a
- // HunkPalette object; right now it would just be lost once the temporary
- // palette was destroyed.
- palette.timestamp = _version;
+ hunkPalette.setVersion(_version);
}
-bool GfxPalette32::kernelSetFromResource(GuiResourceId resourceId, bool force) {
- // TODO: In SCI32, palettes that come from resources come in as
- // HunkPalette objects, not SOLPalette objects. The HunkPalettes
- // have some extra persistence stuff associated with them, such that
- // when they are passed to GfxPalette32::submit, they would get the
- // version number of GfxPalette32 assigned to them.
- Palette palette;
+bool GfxPalette32::loadPalette(const GuiResourceId resourceId) {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
- if (createPaletteFromResourceInternal(resourceId, &palette)) {
- submit(palette);
- return true;
+ if (!palResource) {
+ return false;
}
- return false;
+ HunkPalette palette(palResource->data);
+ submit(palette);
+ return true;
}
-// In SCI32 engine this method is SOLPalette::Match(Rgb24 *)
-// and is called as PaletteMgr.Current().Match(color)
-int16 GfxPalette32::kernelFindColor(uint16 r, uint16 g, uint16 b) {
- // SQ6 SCI32 engine takes the 16-bit r, g, b arguments from the
- // VM and puts them into al, ah, dl. For compatibility, make sure
- // to discard any high bits here too
- r = r & 0xFF;
- g = g & 0xFF;
- b = b & 0xFF;
+int16 GfxPalette32::matchColor(const uint8 r, const uint8 g, const uint8 b) {
int16 bestIndex = 0;
int bestDifference = 0xFFFFF;
int difference;
- // SQ6 DOS really does check only the first 236 entries
- for (int i = 0, channelDifference; i < 236; ++i) {
- difference = _sysPalette.colors[i].r - r;
+ for (int i = 0, channelDifference; i < g_sci->_gfxRemap32->getStartColor(); ++i) {
+ difference = _currentPalette.colors[i].r - r;
difference *= difference;
if (bestDifference <= difference) {
continue;
}
- channelDifference = _sysPalette.colors[i].g - g;
+ channelDifference = _currentPalette.colors[i].g - g;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
}
- channelDifference = _sysPalette.colors[i].b - b;
+ channelDifference = _currentPalette.colors[i].b - b;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
@@ -162,56 +241,56 @@ int16 GfxPalette32::kernelFindColor(uint16 r, uint16 g, uint16 b) {
return bestIndex;
}
-// TODO: set is overridden for the time being to send palettes coming from
-// various draw methods like GfxPicture::drawSci32Vga and GfxView::draw to
-// _nextPalette instead of _sysPalette. In the SCI32 engine, CelObj palettes
-// (which are stored as Hunk palettes) are submitted by GraphicsMgr::FrameOut
-// to PaletteMgr::Submit by way of calls to CelObj::SubmitPalette.
-// GfxPalette::set is very similar to GfxPalette32::submit, except that SCI32
-// does not do any fancy best-fit merging and so does not accept arguments
-// like `force` and `forceRealMerge`.
-void GfxPalette32::set(Palette *newPalette, bool force, bool forceRealMerge) {
- submit(*newPalette);
-}
-
bool GfxPalette32::updateForFrame() {
applyAll();
- _versionUpdated = false;
- return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
+ _needsUpdate = false;
+ return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _currentPalette);
}
void GfxPalette32::updateFFrame() {
for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) {
_nextPalette.colors[i] = _sourcePalette.colors[i];
}
- _versionUpdated = false;
- g_sci->_gfxRemap32->remapAllTables(_nextPalette != _sysPalette);
+ _needsUpdate = false;
+ g_sci->_gfxRemap32->remapAllTables(_nextPalette != _currentPalette);
}
-void GfxPalette32::updateHardware() {
- if (_sysPalette == _nextPalette) {
+void GfxPalette32::updateHardware(const bool updateScreen) {
+ if (_currentPalette == _nextPalette) {
return;
}
byte bpal[3 * 256];
- for (int i = 0; i < ARRAYSIZE(_sysPalette.colors); ++i) {
- _sysPalette.colors[i] = _nextPalette.colors[i];
+ for (int i = 0; i < ARRAYSIZE(_currentPalette.colors) - 1; ++i) {
+ _currentPalette.colors[i] = _nextPalette.colors[i];
// NOTE: If the brightness option in the user configuration file is set,
// SCI engine adjusts palette brightnesses here by mapping RGB values to values
// in some hard-coded brightness tables. There is no reason on modern hardware
// to implement this, unless it is discovered that some game uses a non-standard
// brightness setting by default
- if (_sysPalette.colors[i].used) {
- bpal[i * 3 ] = _sysPalette.colors[i].r;
- bpal[i * 3 + 1] = _sysPalette.colors[i].g;
- bpal[i * 3 + 2] = _sysPalette.colors[i].b;
- }
+
+ // All color entries MUST be copied, not just "used" entries, otherwise
+ // uninitialised memory from bpal makes its way into the system palette.
+ // This would not normally be a problem, except that games sometimes use
+ // unused palette entries. e.g. Phant1 title screen references palette
+ // entries outside its own palette, so will render garbage colors where
+ // the game expects them to be black
+ bpal[i * 3 ] = _currentPalette.colors[i].r;
+ bpal[i * 3 + 1] = _currentPalette.colors[i].g;
+ bpal[i * 3 + 2] = _currentPalette.colors[i].b;
}
+ // The last color must always be white
+ bpal[255 * 3 ] = 255;
+ bpal[255 * 3 + 1] = 255;
+ bpal[255 * 3 + 2] = 255;
+
g_system->getPaletteManager()->setPalette(bpal, 0, 256);
- g_sci->getEventManager()->updateScreen();
+ if (updateScreen) {
+ g_sci->getEventManager()->updateScreen();
+ }
}
void GfxPalette32::applyAll() {
@@ -223,6 +302,7 @@ void GfxPalette32::applyAll() {
#pragma mark -
#pragma mark Colour look-up
+#ifdef ENABLE_SCI3_GAMES
bool GfxPalette32::loadClut(uint16 clutId) {
// loadClut() will load a color lookup table from a clu file and set
// the palette found in the file. This is to be used with Phantasmagoria 2.
@@ -272,27 +352,20 @@ void GfxPalette32::unloadClut() {
delete[] _clutTable;
_clutTable = nullptr;
}
+#endif
#pragma mark -
#pragma mark Varying
-inline bool GfxPalette32::createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const {
- Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, paletteId), false);
+inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId resourceId) const {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
if (!palResource) {
- return false;
+ error("Could not load vary palette %d", resourceId);
}
- createFromData(palResource->data, palResource->size, out);
- return true;
-}
-
-inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId paletteId) const {
- Palette palette;
- if (!createPaletteFromResourceInternal(paletteId, &palette)) {
- error("Could not load vary target %d", paletteId);
- }
- return palette;
+ HunkPalette rawPalette(palResource->data);
+ return rawPalette.toPalette();
}
inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int time) {
@@ -316,8 +389,6 @@ inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int tim
}
}
-// TODO: This gets called *a lot* in at least the first scene
-// of SQ6. Optimisation would not be the worst idea in the world.
void GfxPalette32::kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor) {
Palette palette = getPaletteFromResourceInternal(paletteId);
setVary(&palette, percent, time, fromColor, toColor);
@@ -585,18 +656,15 @@ void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const in
// SCI engine overrides the first oldest cycler that it finds where
// “oldest” is determined by the difference between the tick and now
if (cycler == nullptr) {
- int maxUpdateDelta = -1;
- // Optimization: Unlike actual SCI (SQ6) engine, we call
- // getTickCount only once and store it, instead of calling it
- // twice on each iteration through the loop
const uint32 now = g_sci->getTickCount();
+ uint32 minUpdateDelta = 0xFFFFFFFF;
for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) {
PalCycler *candidate = _cyclers[cyclerIndex];
- const int32 updateDelta = now - candidate->lastUpdateTick;
- if (updateDelta >= maxUpdateDelta) {
- maxUpdateDelta = updateDelta;
+ const uint32 updateDelta = now - candidate->lastUpdateTick;
+ if (updateDelta < minUpdateDelta) {
+ minUpdateDelta = updateDelta;
cycler = candidate;
}
}
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index 7dda53e5c1..dc2158022f 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -26,6 +26,118 @@
#include "sci/graphics/palette.h"
namespace Sci {
+
+/**
+ * HunkPalette represents a raw palette resource
+ * read from disk.
+ */
+class HunkPalette {
+public:
+ HunkPalette(byte *rawPalette);
+
+ /**
+ * Gets the version of the palette.
+ */
+ uint32 getVersion() const { return _version; }
+
+ /**
+ * Sets the version of the palette.
+ */
+ void setVersion(const uint32 version);
+
+ /**
+ * Converts the hunk palette to a standard
+ * palette.
+ */
+ const Palette toPalette() const;
+
+private:
+ enum {
+ /**
+ * The size of the HunkPalette header.
+ */
+ kHunkPaletteHeaderSize = 13,
+
+ /**
+ * The size of a palette entry header.
+ */
+ kEntryHeaderSize = 22,
+
+ /**
+ * The offset of the hunk palette version
+ * within the palette entry header.
+ */
+ kEntryVersionOffset = 18
+ };
+
+ /**
+ * The header for a palette inside the
+ * HunkPalette.
+ */
+ struct EntryHeader {
+ /**
+ * The start color.
+ */
+ uint8 startColor;
+
+ /**
+ * The number of palette colors in this
+ * entry.
+ */
+ uint16 numColors;
+
+ /**
+ * The default `used` flag.
+ */
+ bool used;
+
+ /**
+ * Whether or not all palette entries
+ * share the same `used` value in
+ * `defaultFlag`.
+ */
+ bool sharedUsed;
+
+ /**
+ * The palette version.
+ */
+ uint32 version;
+ };
+
+ /**
+ * The version number from the last time this
+ * palette was submitted to GfxPalette32.
+ */
+ uint32 _version;
+
+ /**
+ * The number of palettes stored in the hunk
+ * palette. In SCI32 games this is always 1.
+ */
+ uint8 _numPalettes;
+
+ /**
+ * The raw palette data for this hunk palette.
+ */
+ byte *_data;
+
+ /**
+ * Returns a struct that describes the palette
+ * held by this HunkPalette. The entry header
+ * is reconstructed on every call from the raw
+ * palette data.
+ */
+ const EntryHeader getEntryHeader() const;
+
+ /**
+ * Returns a pointer to the palette data within
+ * the hunk palette.
+ */
+ byte *getPalPointer() const {
+ return _data + kHunkPaletteHeaderSize + (2 * _numPalettes);
+ }
+};
+
enum PalCyclerDirection {
PalCycleBackward = 0,
PalCycleForward = 1
@@ -72,28 +184,29 @@ struct PalCycler {
uint16 numTimesPaused;
};
-class GfxPalette32 : public GfxPalette {
+class GfxPalette32 {
public:
- GfxPalette32(ResourceManager *resMan, GfxScreen *screen);
+ GfxPalette32(ResourceManager *resMan);
~GfxPalette32();
private:
- // NOTE: currentPalette in SCI engine is called _sysPalette
- // here.
+ ResourceManager *_resMan;
/**
* The palette revision version. Increments once per game
- * loop that changes the source palette. TODO: Possibly
- * other areas also change _version, double-check once it
- * is all implemented.
+ * loop that changes the source palette.
*/
uint32 _version;
/**
- * Whether or not the palette manager version was updated
- * during this loop.
+ * Whether or not the hardware palette needs updating.
+ */
+ bool _needsUpdate;
+
+ /**
+ * The currently displayed palette.
*/
- bool _versionUpdated;
+ Palette _currentPalette;
/**
* The unmodified source palette loaded by kPalette. Additional
@@ -104,7 +217,7 @@ private:
/**
* The palette to be used when the hardware is next updated.
- * On update, _nextPalette is transferred to _sysPalette.
+ * On update, _nextPalette is transferred to _currentPalette.
*/
Palette _nextPalette;
@@ -112,24 +225,33 @@ private:
Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const;
public:
- virtual void saveLoadWithSerializer(Common::Serializer &s) override;
+ void saveLoadWithSerializer(Common::Serializer &s);
inline const Palette &getNextPalette() const { return _nextPalette; };
- inline const Palette &getCurrentPalette() const { return _sysPalette; };
+ inline const Palette &getCurrentPalette() const { return _currentPalette; };
- bool kernelSetFromResource(GuiResourceId resourceId, bool force) override;
- int16 kernelFindColor(uint16 r, uint16 g, uint16 b) override;
- void set(Palette *newPalette, bool force, bool forceRealMerge = false) override;
+ /**
+ * Loads a palette into GfxPalette32 with the given resource
+ * ID.
+ */
+ bool loadPalette(const GuiResourceId resourceId);
+
+ /**
+ * Finds the nearest color in the current palette matching the
+ * given RGB value.
+ */
+ int16 matchColor(const uint8 r, const uint8 g, const uint8 b);
/**
* Submits a palette to display. Entries marked as “used” in the
* submitted palette are merged into the existing entries of
* _sourcePalette.
*/
- void submit(Palette &palette);
+ void submit(const Palette &palette);
+ void submit(HunkPalette &palette);
bool updateForFrame();
void updateFFrame();
- void updateHardware();
+ void updateHardware(const bool updateScreen = true);
void applyAll();
#pragma mark -
@@ -213,7 +335,7 @@ public:
void kernelPalVarySetTarget(const GuiResourceId paletteId);
void kernelPalVarySetStart(const GuiResourceId paletteId);
void kernelPalVaryMergeStart(const GuiResourceId paletteId);
- virtual void kernelPalVaryPause(bool pause) override;
+ void kernelPalVaryPause(bool pause);
void setVary(const Palette *const targetPalette, const int16 percent, const int time, const int16 fromColor, const int16 toColor);
void setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate);
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index 175875c414..aa629e4081 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -47,6 +47,7 @@ uint16 Plane::_nextObjectId = 20000;
Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) :
_pictureId(pictureId),
_mirrored(false),
+_type(kPlaneTypeColored),
_back(0),
_priorityChanged(0),
_object(make_reg(0, _nextObjectId++)),
@@ -63,6 +64,7 @@ _gameRect(gameRect) {
}
Plane::Plane(reg_t object) :
+_type(kPlaneTypeColored),
_priorityChanged(false),
_object(object),
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
@@ -93,6 +95,7 @@ _moved(0) {
Plane::Plane(const Plane &other) :
_pictureId(other._pictureId),
_mirrored(other._mirrored),
+_type(other._type),
_back(other._back),
_object(other._object),
_priority(other._priority),
@@ -595,8 +598,10 @@ void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectLi
Common::Rect outRects[4];
const Common::Rect &r2 = *higherEraseList[i];
int splitCount = splitRects(r2, r, outRects);
- while (splitCount--) {
- higherEraseList.add(outRects[splitCount]);
+ if (splitCount > 0) {
+ while (splitCount--) {
+ higherEraseList.add(outRects[splitCount]);
+ }
}
higherEraseList.erase_at(i);
}
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index a1739264e8..3981a2b319 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -150,6 +150,11 @@ private:
public:
/**
+ * The type of the plane.
+ */
+ PlaneType _type;
+
+ /**
* The color to use when erasing the plane. Only
* applies to planes of type kPlaneTypeColored.
*/
@@ -186,8 +191,6 @@ public:
*/
int _redrawAllCount;
- PlaneType _type;
-
/**
* Flags indicating the state of the plane.
* - `created` is set when the plane is first created,
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index ebaf132890..7383dc222e 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -42,7 +42,8 @@ _pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
SegManager *segMan = g_sci->getEngineState()->_segMan;
setFromObject(segMan, object, true, true);
@@ -62,7 +63,8 @@ _pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) :
_plane(plane),
@@ -77,7 +79,8 @@ _pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
if (celInfo.type == kCelTypeColor) {
_insetRect = rect;
}
@@ -97,7 +100,8 @@ _pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
ScreenItem::ScreenItem(const ScreenItem &other) :
_plane(other._plane),
@@ -108,7 +112,8 @@ _celObj(nullptr),
_object(other._object),
_mirrorX(other._mirrorX),
_scaledPosition(other._scaledPosition),
-_screenRect(other._screenRect) {
+_screenRect(other._screenRect),
+_drawBlackLines(other._drawBlackLines) {
if (other._useInsetRect) {
_insetRect = other._insetRect;
}
@@ -134,6 +139,7 @@ void ScreenItem::operator=(const ScreenItem &other) {
}
_scale = other._scale;
_scaledPosition = other._scaledPosition;
+ _drawBlackLines = other._drawBlackLines;
}
ScreenItem::~ScreenItem() {
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index caa7a9d725..3d9d5ef3d7 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -64,12 +64,12 @@ private:
*/
static uint16 _nextObjectId;
+public:
/**
* The parent plane of this screen item.
*/
reg_t _plane;
-public:
/**
* Scaling data used to calculate the final screen
* dimensions of the screen item as well as the scaling
@@ -180,7 +180,7 @@ public:
* plane is a pic type and its picture resource ID has
* changed
*/
- int _created, _updated, _deleted; // ?
+ int _created, _updated, _deleted;
/**
* For screen items that represent picture cels, this
@@ -214,6 +214,14 @@ public:
Common::Rect _screenRect;
/**
+ * Whether or not the screen item should be drawn
+ * with black lines drawn every second line. This is
+ * used when pixel doubling videos to improve apparent
+ * sharpness at the cost of your eyesight.
+ */
+ bool _drawBlackLines;
+
+ /**
* Initialises static Plane members.
*/
static void init();
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
new file mode 100644
index 0000000000..dfddac1036
--- /dev/null
+++ b/engines/sci/graphics/video32.cpp
@@ -0,0 +1,406 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "audio/mixer.h"
+#include "common/config-manager.h"
+#include "sci/console.h"
+#include "sci/event.h"
+#include "sci/graphics/cursor.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/text32.h"
+#include "sci/graphics/video32.h"
+#include "sci/sci.h"
+#include "video/coktel_decoder.h"
+
+namespace Sci {
+
+#pragma mark VMDPlayer
+
+VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
+ _segMan(segMan),
+ _eventMan(eventMan),
+ _decoder(new Video::AdvancedVMDDecoder(Audio::Mixer::kSFXSoundType)),
+
+ _isOpen(false),
+ _isInitialized(false),
+ _yieldInterval(0),
+ _lastYieldedFrameNo(0),
+
+ _plane(nullptr),
+ _screenItem(nullptr),
+ _planeIsOwned(true),
+ _priority(0),
+ _doublePixels(false),
+ _stretchVertical(false),
+ _blackLines(false),
+ _leaveScreenBlack(false),
+ _leaveLastFrame(false),
+
+ _blackoutPlane(nullptr),
+
+ _startColor(0),
+ _endColor(255),
+ _blackPalette(false),
+
+ _boostPercent(100),
+ _boostStartColor(0),
+ _boostEndColor(255),
+
+ _showCursor(false) {}
+
+VMDPlayer::~VMDPlayer() {
+ close();
+ delete _decoder;
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+
+VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFlags flags) {
+ if (_isOpen) {
+ error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
+ }
+
+ if (_decoder->loadFile(fileName)) {
+ if (flags & kOpenFlagMute) {
+ _decoder->setVolume(0);
+ }
+ _isOpen = true;
+ return kIOSuccess;
+ } else {
+ return kIOError;
+ }
+}
+
+void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor) {
+ _x = getSciVersion() >= SCI_VERSION_3 ? x : (x & ~1);
+ _y = y;
+ _doublePixels = flags & kPlayFlagDoublePixels;
+ _blackLines = ConfMan.getBool("enable_black_lined_video") && (flags & kPlayFlagBlackLines);
+ _boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
+ _boostStartColor = CLIP<int16>(boostStartColor, 0, 255);
+ _boostEndColor = CLIP<int16>(boostEndColor, 0, 255);
+ _leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
+ _leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
+ _blackPalette = flags & kPlayFlagBlackPalette;
+ _stretchVertical = flags & kPlayFlagStretchVertical;
+}
+
+VMDPlayer::IOStatus VMDPlayer::close() {
+ if (!_isOpen) {
+ return kIOSuccess;
+ }
+
+ _decoder->close();
+ _isOpen = false;
+ _isInitialized = false;
+
+ if (!_planeIsOwned && _screenItem != nullptr) {
+ g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
+ _screenItem = nullptr;
+ } else if (_plane != nullptr) {
+ g_sci->_gfxFrameout->deletePlane(*_plane);
+ _plane = nullptr;
+ }
+
+ if (!_leaveLastFrame && _leaveScreenBlack) {
+ // This call *actually* deletes the plane/screen item
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+
+ if (_blackoutPlane != nullptr) {
+ g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
+ _blackoutPlane = nullptr;
+ }
+
+ if (!_leaveLastFrame && !_leaveScreenBlack) {
+ // This call *actually* deletes the blackout plane
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+
+ if (!_showCursor) {
+ g_sci->_gfxCursor->kernelShow();
+ }
+
+ _lastYieldedFrameNo = 0;
+ _planeIsOwned = true;
+ _priority = 0;
+ return kIOSuccess;
+}
+
+VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
+ assert(lastFrameNo >= -1);
+
+ const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+
+ if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
+ _decoder->setEndFrame(MIN((int32)lastFrameNo, maxFrameNo));
+ } else {
+ _decoder->setEndFrame(maxFrameNo);
+ }
+
+ if (flags & kEventFlagYieldToVM) {
+ _yieldInterval = 3;
+ if (yieldInterval == -1 && !(flags & kEventFlagToFrame)) {
+ _yieldInterval = lastFrameNo;
+ } else if (yieldInterval != -1) {
+ _yieldInterval = MIN((int32)yieldInterval, maxFrameNo);
+ }
+ } else {
+ _yieldInterval = maxFrameNo;
+ }
+
+ return playUntilEvent(flags);
+}
+
+VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
+ // Flushing all the keyboard and mouse events out of the event manager to
+ // avoid letting any events queued from before the video started from
+ // accidentally activating an event callback
+ for (;;) {
+ const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_QUIT);
+ if (event.type == SCI_EVENT_NONE) {
+ break;
+ } else if (event.type == SCI_EVENT_QUIT) {
+ return kEventFlagEnd;
+ }
+ }
+
+ _decoder->pauseVideo(false);
+
+ if (flags & kEventFlagReverse) {
+ // NOTE: This flag may not work properly since SSCI does not care
+ // if a video has audio, but the VMD decoder does.
+ const bool success = _decoder->setReverse(true);
+ assert(success);
+ _decoder->setVolume(0);
+ }
+
+ if (!_isInitialized) {
+ _isInitialized = true;
+
+ if (!_showCursor) {
+ g_sci->_gfxCursor->kernelHide();
+ }
+
+ Common::Rect vmdRect(_x,
+ _y,
+ _x + _decoder->getWidth(),
+ _y + _decoder->getHeight());
+ ScaleInfo vmdScaleInfo;
+
+ if (!_blackoutRect.isEmpty() && _planeIsOwned) {
+ _blackoutPlane = new Plane(_blackoutRect);
+ g_sci->_gfxFrameout->addPlane(*_blackoutPlane);
+ }
+
+ if (_doublePixels) {
+ vmdScaleInfo.x = 256;
+ vmdScaleInfo.y = 256;
+ vmdScaleInfo.signal = kScaleSignalDoScaling32;
+ vmdRect.right += vmdRect.width();
+ vmdRect.bottom += vmdRect.height();
+ } else if (_stretchVertical) {
+ vmdScaleInfo.y = 256;
+ vmdScaleInfo.signal = kScaleSignalDoScaling32;
+ vmdRect.bottom += vmdRect.height();
+ }
+
+ 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;
+
+ BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
+
+ if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
+ mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
+ }
+
+ CelInfo32 vmdCelInfo;
+ vmdCelInfo.bitmap = vmdBitmap.getObject();
+ _decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
+
+ if (_planeIsOwned) {
+ _x = 0;
+ _y = 0;
+ _plane = new Plane(vmdRect, kPlanePicColored);
+ if (_priority) {
+ _plane->_priority = _priority;
+ }
+ g_sci->_gfxFrameout->addPlane(*_plane);
+ _screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(), vmdScaleInfo);
+ } else {
+ _screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(_x, _y), vmdScaleInfo);
+ if (_priority) {
+ _screenItem->_priority = _priority;
+ }
+ }
+
+ if (_blackLines) {
+ _screenItem->_drawBlackLines = true;
+ }
+
+ // NOTE: There was code for positioning the screen item using insetRect
+ // here, but none of the game scripts seem to use this functionality.
+
+ g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+
+ _decoder->start();
+ }
+
+ EventFlags stopFlag = kEventFlagNone;
+ while (!g_engine->shouldQuit()) {
+ if (_decoder->endOfVideo()) {
+ stopFlag = kEventFlagEnd;
+ break;
+ }
+
+ g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
+ g_sci->getEngineState()->_throttleTrigger = true;
+ if (_decoder->needsUpdate()) {
+ renderFrame();
+ }
+
+ const int currentFrameNo = _decoder->getCurFrame();
+
+ if (_yieldInterval > 0 &&
+ currentFrameNo != _lastYieldedFrameNo &&
+ (currentFrameNo % _yieldInterval) == 0
+ ) {
+ _lastYieldedFrameNo = currentFrameNo;
+ stopFlag = kEventFlagYieldToVM;
+ break;
+ }
+
+ SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+ if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) {
+ stopFlag = kEventFlagMouseDown;
+ break;
+ }
+
+ event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+ if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) {
+ bool stop = false;
+ if (getSciVersion() < SCI_VERSION_3) {
+ while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)),
+ event.type != SCI_EVENT_NONE) {
+ if (event.character == SCI_KEY_ESC) {
+ stop = true;
+ break;
+ }
+ }
+ } else {
+ stop = (event.character == SCI_KEY_ESC);
+ }
+
+ if (stop) {
+ stopFlag = kEventFlagEscapeKey;
+ break;
+ }
+ }
+
+ // TODO: Hot rectangles
+ if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
+ warning("Hot rectangles not implemented in VMD player");
+ stopFlag = kEventFlagHotRectangle;
+ break;
+ }
+ }
+
+ _decoder->pauseVideo(true);
+ return stopFlag;
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
+
+void VMDPlayer::renderFrame() const {
+ // This writes directly to the CelObjMem we already created,
+ // so no need to take its return value
+ _decoder->decodeNextFrame();
+
+ // NOTE: Normally this would write a hunk palette at the end of the
+ // video bitmap that CelObjMem would read out and submit, but instead
+ // 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) {
+ Palette palette;
+ palette.timestamp = g_sci->getTickCount();
+ if (_blackPalette) {
+ for (uint16 i = _startColor; i <= _endColor; ++i) {
+ palette.colors[i].r = palette.colors[i].g = palette.colors[i].b = 0;
+ palette.colors[i].used = true;
+ }
+ } else {
+ fillPalette(palette);
+ }
+
+ g_sci->_gfxPalette32->submit(palette);
+ g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+ g_sci->_gfxFrameout->frameOut(true);
+
+ if (_blackPalette) {
+ fillPalette(palette);
+ g_sci->_gfxPalette32->submit(palette);
+ g_sci->_gfxPalette32->updateForFrame();
+ g_sci->_gfxPalette32->updateHardware();
+ }
+ } else {
+ g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+ g_sci->getSciDebugger()->onFrame();
+ g_sci->_gfxFrameout->frameOut(true);
+ g_sci->_gfxFrameout->throttle();
+ }
+}
+
+void VMDPlayer::fillPalette(Palette &palette) const {
+ const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+ for (uint16 i = _startColor; i <= _endColor; ++i) {
+ int16 r = *vmdPalette++;
+ int16 g = *vmdPalette++;
+ int16 b = *vmdPalette++;
+
+ if (_boostPercent != 100 && i >= _boostStartColor && i <= _boostEndColor) {
+ r = CLIP<int16>(r * _boostPercent / 100, 0, 255);
+ g = CLIP<int16>(g * _boostPercent / 100, 0, 255);
+ b = CLIP<int16>(b * _boostPercent / 100, 0, 255);
+ }
+
+ palette.colors[i].r = r;
+ palette.colors[i].g = g;
+ palette.colors[i].b = b;
+ palette.colors[i].used = true;
+ }
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Palette
+
+void VMDPlayer::restrictPalette(const uint8 startColor, const uint8 endColor) {
+ _startColor = startColor;
+ _endColor = endColor;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
new file mode 100644
index 0000000000..cf863ba41d
--- /dev/null
+++ b/engines/sci/graphics/video32.h
@@ -0,0 +1,312 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_VIDEO32_H
+#define SCI_GRAPHICS_VIDEO32_H
+
+namespace Video { class AdvancedVMDDecoder; }
+namespace Sci {
+class Plane;
+class ScreenItem;
+class SegManager;
+
+#pragma mark VMDPlayer
+
+/**
+ * VMDPlayer is used to play VMD videos.
+ */
+class VMDPlayer {
+public:
+ enum OpenFlags {
+ kOpenFlagNone = 0,
+ kOpenFlagMute = 1
+ };
+
+ enum IOStatus {
+ kIOSuccess = 0,
+ kIOError = 0xFFFF
+ };
+
+ enum PlayFlags {
+ kPlayFlagNone = 0,
+ kPlayFlagDoublePixels = 1,
+ kPlayFlagBlackLines = 4,
+ kPlayFlagBoost = 0x10,
+ kPlayFlagLeaveScreenBlack = 0x20,
+ kPlayFlagLeaveLastFrame = 0x40,
+ kPlayFlagBlackPalette = 0x80,
+ kPlayFlagStretchVertical = 0x100
+ };
+
+ enum EventFlags {
+ kEventFlagNone = 0,
+ kEventFlagEnd = 1,
+ kEventFlagEscapeKey = 2,
+ kEventFlagMouseDown = 4,
+ kEventFlagHotRectangle = 8,
+ kEventFlagToFrame = 0x10,
+ kEventFlagYieldToVM = 0x20,
+ kEventFlagReverse = 0x80
+ };
+
+ VMDPlayer(SegManager *segMan, EventManager *eventMan);
+ ~VMDPlayer();
+
+private:
+ SegManager *_segMan;
+ EventManager *_eventMan;
+ Video::AdvancedVMDDecoder *_decoder;
+
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+public:
+ /**
+ * Opens a stream to a VMD resource.
+ */
+ IOStatus open(const Common::String &fileName, const OpenFlags flags);
+
+ /**
+ * Initializes the VMD rendering parameters for the
+ * current VMD. This must be called after `open`.
+ */
+ void init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor);
+
+ /**
+ * Stops playback and closes the currently open VMD stream.
+ */
+ IOStatus close();
+
+ // NOTE: Was WaitForEvent in SSCI
+ EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval);
+
+private:
+ /**
+ * Whether or not a VMD stream has been opened with
+ * `open`.
+ */
+ bool _isOpen;
+
+ /**
+ * Whether or not a VMD player has been initialised
+ * with `init`.
+ */
+ bool _isInitialized;
+
+ /**
+ * For VMDs played with the `kEventFlagYieldToVM` flag,
+ * the number of frames that should be rendered until
+ * yielding back to the SCI VM.
+ */
+ int32 _yieldInterval;
+
+ /**
+ * For VMDs played with the `kEventFlagYieldToVM` flag,
+ * the last frame when control of the main thread was
+ * yielded back to the SCI VM.
+ */
+ int _lastYieldedFrameNo;
+
+ /**
+ * Plays the VMD until an event occurs (e.g. user
+ * presses escape, clicks, etc.).
+ */
+ EventFlags playUntilEvent(const EventFlags flags);
+
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
+private:
+ /**
+ * The location of the VMD plane, in game script
+ * coordinates.
+ */
+ int16 _x, _y;
+
+ /**
+ * The plane where the VMD will be drawn.
+ */
+ Plane *_plane;
+
+ /**
+ * The screen item representing the VMD surface.
+ */
+ ScreenItem *_screenItem;
+
+ // TODO: planeIsOwned and priority are used in SCI3+ only
+
+ /**
+ * If true, the plane for this VMD was set
+ * externally and is not owned by this VMDPlayer.
+ */
+ bool _planeIsOwned;
+
+ /**
+ * The screen priority of the video.
+ * @see ScreenItem::_priority
+ */
+ int _priority;
+
+ /**
+ * Whether or not the video should be pixel doubled.
+ */
+ bool _doublePixels;
+
+ /**
+ * Whether or not the video should be pixel doubled
+ * vertically only.
+ */
+ bool _stretchVertical;
+
+ /**
+ * Whether or not black lines should be rendered
+ * across the video.
+ */
+ bool _blackLines;
+
+ /**
+ * Whether or not the playback area of the VMD
+ * should be left black at the end of playback.
+ */
+ bool _leaveScreenBlack;
+
+ /**
+ * Whether or not the area of the VMD should be left
+ * displaying the final frame of the video.
+ */
+ bool _leaveLastFrame;
+
+ /**
+ * Renders a frame of video to the output bitmap.
+ */
+ void renderFrame() const;
+
+ /**
+ * Fills the given palette with RGB values from
+ * the VMD palette, applying brightness boost if
+ * it is enabled.
+ */
+ void fillPalette(Palette &palette) const;
+
+#pragma mark -
+#pragma mark VMDPlayer - Blackout
+public:
+ /**
+ * Sets the area of the screen that should be blacked out
+ * during VMD playback.
+ */
+ void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
+
+private:
+ /**
+ * The dimensions of the blackout plane.
+ */
+ Common::Rect _blackoutRect;
+
+ /**
+ * An optional plane that will be used to black out
+ * areas of the screen outside of the VMD surface.
+ */
+ Plane *_blackoutPlane;
+
+#pragma mark -
+#pragma mark VMDPlayer - Palette
+public:
+ /**
+ * Restricts use of the system palette by VMD playback to
+ * the given range of palette indexes.
+ */
+ void restrictPalette(const uint8 startColor, const uint8 endColor);
+
+private:
+ /**
+ * The first color in the system palette that the VMD
+ * can write to.
+ */
+ uint8 _startColor;
+
+ /**
+ * The last color in the system palette that the VMD
+ * can write to.
+ */
+ uint8 _endColor;
+
+ /**
+ * If true, video frames are rendered after a blank
+ * palette is submitted to the palette manager,
+ * which is then restored after the video pixels
+ * have already been rendered.
+ */
+ bool _blackPalette;
+
+#pragma mark -
+#pragma mark VMDPlayer - Brightness boost
+private:
+ /**
+ * The amount of brightness boost for the video.
+ * Values above 100 increase brightness; values below
+ * 100 reduce it.
+ */
+ int16 _boostPercent;
+
+ /**
+ * The first color in the palette that should be
+ * brightness boosted.
+ */
+ uint8 _boostStartColor;
+
+ /**
+ * The last color in the palette that should be
+ * brightness boosted.
+ */
+ uint8 _boostEndColor;
+
+#pragma mark -
+#pragma mark VMDPlayer - Mouse cursor
+public:
+ /**
+ * Sets whether or not the mouse cursor should be drawn.
+ * This does not have any effect during playback, but can
+ * be used to prevent the mouse cursor from being shown
+ * again after the video has finished.
+ */
+ void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
+
+private:
+ /**
+ * Whether or not the mouse cursor should be shown
+ * during playback.
+ */
+ bool _showCursor;
+};
+
+class Video32 {
+public:
+ Video32(SegManager *segMan, EventManager *eventMan) :
+ _VMDPlayer(segMan, eventMan) {}
+
+ VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
+
+private:
+ VMDPlayer _VMDPlayer;
+};
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 5d54e2a52c..1511356747 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -91,6 +91,7 @@ MODULE_OBJS += \
graphics/remap32.o \
graphics/screen_item32.o \
graphics/text32.o \
+ graphics/video32.o \
sound/audio32.o \
sound/decoders/sol.o \
video/robot_decoder.o
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 41fa144b06..f9481bb301 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -69,7 +69,9 @@
#include "sci/graphics/palette32.h"
#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
+#include "sci/graphics/video32.h"
#include "sci/sound/audio32.h"
+// TODO: Move this to video32
#include "sci/video/robot_decoder.h"
#endif
@@ -92,6 +94,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
_sync = nullptr;
#ifdef ENABLE_SCI32
_audio32 = nullptr;
+ _video32 = nullptr;
#endif
_features = 0;
_resMan = 0;
@@ -164,9 +167,7 @@ SciEngine::~SciEngine() {
DebugMan.clearAllDebugChannels();
#ifdef ENABLE_SCI32
- // _gfxPalette32 is the same as _gfxPalette16
- // and will be destroyed when _gfxPalette16 is
- // destroyed
+ delete _gfxPalette32;
delete _gfxControls32;
delete _gfxPaint32;
delete _gfxText32;
@@ -277,15 +278,20 @@ Common::Error SciEngine::run() {
if (getGameId() == GID_CHRISTMAS1990)
_vocabulary = new Vocabulary(_resMan, false);
+ _gamestate = new EngineState(segMan);
+ _eventMan = new EventManager(_resMan->detectFontExtended());
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
_audio32 = new Audio32(_resMan);
} else
#endif
_audio = new AudioPlayer(_resMan);
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ _video32 = new Video32(segMan, _eventMan);
+ }
+#endif
_sync = new Sync(_resMan, segMan);
- _gamestate = new EngineState(segMan);
- _eventMan = new EventManager(_resMan->detectFontExtended());
// Create debugger console. It requires GFX and _gamestate to be initialized
_console = new Console(this);
@@ -358,6 +364,17 @@ Common::Error SciEngine::run() {
}
}
+ if (getGameId() == GID_KQ7 && ConfMan.getBool("subtitles")) {
+ showScummVMDialog("Subtitles are enabled, but subtitling in King's"
+ " Quest 7 was unfinished and disabled in the release"
+ " version of the game. ScummVM allows the subtitles"
+ " to be re-enabled, but because they were removed from"
+ " the original game, they do not always render"
+ " properly or reflect the actual game speech."
+ " This is not a ScummVM bug -- it is a problem with"
+ " the game's assets.");
+ }
+
// Show a warning if the user has selected a General MIDI device, no GM patch exists
// (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided
// after market patches for in their "General MIDI Utility".
@@ -698,8 +715,7 @@ void SciEngine::initGraphics() {
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
- _gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
- _gfxPalette16 = _gfxPalette32;
+ _gfxPalette32 = new GfxPalette32(_resMan);
_gfxRemap32 = new GfxRemap32();
} else {
#endif
@@ -748,8 +764,10 @@ void SciEngine::initGraphics() {
}
#endif
- // Set default (EGA, amiga or resource 999) palette
- _gfxPalette16->setDefault();
+ if (getSciVersion() < SCI_VERSION_2) {
+ // Set default (EGA, amiga or resource 999) palette
+ _gfxPalette16->setDefault();
+ }
}
void SciEngine::initStackBaseWithSelector(Selector selector) {
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 3216fa13b9..0020d25b91 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -80,9 +80,11 @@ class GfxText32;
class GfxTransitions;
#ifdef ENABLE_SCI32
+// TODO: Move RobotDecoder to Video32
class RobotDecoder;
class GfxFrameout;
class Audio32;
+class Video32;
#endif
// our engine debug levels
@@ -138,6 +140,7 @@ enum SciGameId {
GID_HOYLE2,
GID_HOYLE3,
GID_HOYLE4,
+ GID_HOYLE5,
GID_ICEMAN,
GID_INNDEMO,
GID_ISLANDBRAIN,
@@ -371,6 +374,7 @@ public:
#ifdef ENABLE_SCI32
Audio32 *_audio32;
+ Video32 *_video32;
RobotDecoder *_robotDecoder;
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
#endif
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
index 4689d13d7d..0cf8e3cb13 100644
--- a/engines/sci/sound/audio32.cpp
+++ b/engines/sci/sound/audio32.cpp
@@ -124,10 +124,10 @@ Audio32::Audio32(ResourceManager *resMan) :
_attenuatedMixing(true),
- _monitoredChannelIndex(-1),
- _monitoredBuffer(nullptr),
- _monitoredBufferSize(0),
- _numMonitoredSamples(0) {
+ _monitoredChannelIndex(-1),
+ _monitoredBuffer(nullptr),
+ _monitoredBufferSize(0),
+ _numMonitoredSamples(0) {
if (getSciVersion() < SCI_VERSION_3) {
_channels.resize(5);
@@ -146,19 +146,13 @@ Audio32::Audio32(ResourceManager *resMan) :
default:
break;
}
- } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
- switch (g_sci->getGameId()) {
- // 1.51 uses the non-standard attenuation, but 2.00b
+ } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
+ // KQ7 1.51 uses the non-standard attenuation, but 2.00b
// does not, which is strange.
- case GID_KQ7:
- _useModifiedAttenuation = true;
- default:
- break;
- }
+ _useModifiedAttenuation = true;
}
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
- _mixer->pauseHandle(_handle, true);
}
Audio32::~Audio32() {
@@ -240,16 +234,16 @@ int Audio32::writeAudioInternal(Audio::RewindableAudioStream *const sourceStream
int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
Common::StackLock lock(_mutex);
+ if (_pausedAtTick != 0 || _numActiveChannels == 0) {
+ return 0;
+ }
+
// ResourceManager is not thread-safe so we need to
// avoid calling into it from the audio thread, but at
// the same time we need to be able to clear out any
// finished channels on a regular basis
_inAudioThread = true;
- // The system mixer should not try to get data when
- // Audio32 is paused
- assert(_pausedAtTick == 0 && _numActiveChannels > 0);
-
freeUnusedChannels();
// The caller of `readBuffer` is a rate converter,
@@ -359,6 +353,16 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
maxSamplesWritten = _numMonitoredSamples;
}
} else if (!channel.stream->endOfStream() || channel.loop) {
+ if (_monitoredChannelIndex != -1) {
+ // Audio that is not on the monitored channel is silent
+ // when the monitored channel is active, but the stream still
+ // needs to be read in order to ensure that sound effects sync
+ // up once the monitored channel is turned off. The easiest
+ // way to guarantee this is to just do the normal channel read,
+ // but set the channel volume to zero so nothing is mixed in
+ leftVolume = rightVolume = 0;
+ }
+
const int channelSamplesWritten = writeAudioInternal(channel.stream, channel.converter, buffer, numSamples, leftVolume, rightVolume, channel.loop);
if (channelSamplesWritten > maxSamplesWritten) {
maxSamplesWritten = channelSamplesWritten;
@@ -652,7 +656,6 @@ uint16 Audio32::play(int16 channelIndex, const ResourceId resourceId, const bool
if (_numActiveChannels == 1) {
_startedAtTick = now;
- _mixer->pauseHandle(_handle, false);
}
return channel.duration;
@@ -683,7 +686,6 @@ bool Audio32::resume(const int16 channelIndex) {
_startedAtTick += now - _pausedAtTick;
_pausedAtTick = 0;
- _mixer->pauseHandle(_handle, false);
return true;
} else if (channelIndex == kRobotChannel) {
for (int i = 0; i < _numActiveChannels; ++i) {
@@ -720,7 +722,6 @@ bool Audio32::pause(const int16 channelIndex) {
if (channelIndex == kAllChannels) {
if (_pausedAtTick == 0) {
_pausedAtTick = now;
- _mixer->pauseHandle(_handle, true);
didPause = true;
}
} else if (channelIndex == kRobotChannel) {
@@ -773,9 +774,6 @@ int16 Audio32::stop(const int16 channelIndex) {
// NOTE: SSCI stops the DSP interrupt and frees the
// global decompression buffer here if there are no
// more active channels
- if (_numActiveChannels == 0) {
- _mixer->pauseHandle(_handle, true);
- }
return oldNumChannels;
}
@@ -891,17 +889,15 @@ reg_t Audio32::kernelPlay(const bool autoPlay, const int argc, const reg_t *cons
#pragma mark Effects
int16 Audio32::getVolume(const int16 channelIndex) const {
- Common::StackLock lock(_mutex);
if (channelIndex < 0 || channelIndex >= _numActiveChannels) {
return _mixer->getChannelVolume(_handle) * kMaxVolume / Audio::Mixer::kMaxChannelVolume;
}
+ Common::StackLock lock(_mutex);
return getChannel(channelIndex).volume;
}
void Audio32::setVolume(const int16 channelIndex, int16 volume) {
- Common::StackLock lock(_mutex);
-
volume = MIN((int16)kMaxVolume, volume);
if (channelIndex == kAllChannels) {
ConfMan.setInt("sfx_volume", volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume);
@@ -909,6 +905,7 @@ void Audio32::setVolume(const int16 channelIndex, int16 volume) {
_mixer->setChannelVolume(_handle, volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume);
g_engine->syncSoundSettings();
} else if (channelIndex != kNoExistingChannel) {
+ Common::StackLock lock(_mutex);
getChannel(channelIndex).volume = volume;
}
}
diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h
index 42211eb890..b0c1ba1998 100644
--- a/engines/sci/sound/audio32.h
+++ b/engines/sci/sound/audio32.h
@@ -108,7 +108,7 @@ struct AudioChannel {
/**
* The end volume of a fade.
*/
- uint32 fadeTargetVolume;
+ int fadeTargetVolume;
/**
* Whether or not the channel should be stopped and
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 3f34ecc2f8..487d30e840 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -354,12 +354,14 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
pSnd->pStreamAud = Audio::makeRawStream(channelData + track->digitalSampleStart,
track->digitalSampleSize - track->digitalSampleStart - endPart,
track->digitalSampleRate, flags, DisposeAfterUse::NO);
+ assert(pSnd->pStreamAud);
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
pSnd->soundType = Audio::Mixer::kSFXSoundType;
pSnd->hCurrentAud = Audio::SoundHandle();
pSnd->playBed = false;
pSnd->overridePriority = false;
+ pSnd->isSample = true;
} else {
// play MIDI track
Common::StackLock lock(_mutex);
@@ -659,6 +661,7 @@ void SciMusic::soundKill(MusicEntry *pSnd) {
pSnd->pStreamAud = NULL;
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
+ pSnd->isSample = false;
}
_mutex.lock();
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index c3c159de55..b9a764c93a 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -722,7 +722,7 @@ reg_t SoundCommandParser::kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc) {
// SSCI unconditionally sets volume if it is digital audio
if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) {
_music->soundSetVolume(musicSlot, value);
- } else
+ }
#endif
if (musicSlot->volume != value) {
musicSlot->volume = value;