aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine')
-rw-r--r--engines/sci/engine/gc.cpp10
-rw-r--r--engines/sci/engine/kernel.h48
-rw-r--r--engines/sci/engine/kernel_tables.h188
-rw-r--r--engines/sci/engine/kfile.cpp50
-rw-r--r--engines/sci/engine/kgraphics.cpp2
-rw-r--r--engines/sci/engine/kgraphics32.cpp476
-rw-r--r--engines/sci/engine/kmisc.cpp12
-rw-r--r--engines/sci/engine/kpathing.cpp2
-rw-r--r--engines/sci/engine/ksound.cpp238
-rw-r--r--engines/sci/engine/savegame.cpp30
-rw-r--r--engines/sci/engine/savegame.h3
-rw-r--r--engines/sci/engine/script_patches.cpp215
-rw-r--r--engines/sci/engine/workarounds.cpp14
-rw-r--r--engines/sci/engine/workarounds.h2
14 files changed, 916 insertions, 374 deletions
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index 70c8c52bf0..b229490570 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -24,6 +24,10 @@
#include "common/array.h"
#include "sci/graphics/ports.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/controls32.h"
+#endif
+
namespace Sci {
//#define GC_DEBUG_CODE
@@ -150,6 +154,12 @@ AddrSet *findAllActiveReferences(EngineState *s) {
}
}
+#ifdef ENABLE_SCI32
+ // Init: ScrollWindows
+ if (g_sci->_gfxControls32)
+ wm.pushArray(g_sci->_gfxControls32->listObjectReferences());
+#endif
+
debugC(kDebugLevelGC, "[GC] -- Finished explicitly loaded scripts, done with root set");
processWorkList(s->_segMan, wm, heap);
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 62566a74b2..1202982986 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -412,7 +412,7 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv);
reg_t kTextColors(EngineState *s, int argc, reg_t *argv);
reg_t kTextFonts(EngineState *s, int argc, reg_t *argv);
reg_t kShow(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
reg_t kDummy(EngineState *s, int argc, reg_t *argv);
reg_t kEmpty(EngineState *s, int argc, reg_t *argv);
reg_t kStub(EngineState *s, int argc, reg_t *argv);
@@ -420,6 +420,26 @@ reg_t kStubNull(EngineState *s, int argc, reg_t *argv);
#ifdef ENABLE_SCI32
// SCI2 Kernel Functions
+reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioStop(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPause(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioResume(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPosition(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioRate(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioVolume(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioGetCapability(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioBitDepth(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioDistort(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioMixing(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioChannels(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPreload(EngineState *s, int argc, reg_t *argv);
+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 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);
@@ -447,19 +467,28 @@ reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowDownArrow(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowHome(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowGo(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowHide(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv);
reg_t kMulDiv(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapColors(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapOff(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv);
-reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv);
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);
@@ -537,6 +566,7 @@ reg_t kMoveToFront(EngineState *s, int argc, reg_t *argv);
reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv);
reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv);
reg_t kWinHelp(EngineState *s, int argc, reg_t *argv);
+reg_t kMessageBox(EngineState *s, int argc, reg_t *argv);
reg_t kGetConfig(EngineState *s, int argc, reg_t *argv);
reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv);
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv);
@@ -558,7 +588,6 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundPlay(EngineState *s, int argc, reg_t *argv);
-reg_t kDoSoundRestore(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundDispose(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundMute(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundStop(EngineState *s, int argc, reg_t *argv);
@@ -573,7 +602,6 @@ reg_t kDoSoundUpdateCues(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSendMidi(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundGlobalReverb(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetHold(EngineState *s, int argc, reg_t *argv);
-reg_t kDoSoundDummy(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundGetAudioCapability(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSuspend(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetVolume(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 0ede307e6b..dacaafe757 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -102,7 +102,7 @@ struct SciKernelMapSubEntry {
static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 0, MAP_CALL(DoSoundInit), "o", NULL },
{ SIG_SOUNDSCI0, 1, MAP_CALL(DoSoundPlay), "o", NULL },
- { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundRestore), "(o)", NULL },
+ { SIG_SOUNDSCI0, 2, MAP_EMPTY(DoSoundRestore), "(o)", NULL },
{ SIG_SOUNDSCI0, 3, MAP_CALL(DoSoundDispose), "o", NULL },
{ SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL },
{ SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL },
@@ -115,7 +115,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
{ SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL },
@@ -128,11 +128,11 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL },
{ SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
{ SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL },
- { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(DoSoundDummy), "", NULL },
+ { SIG_SOUNDSCI1EARLY, 15, MAP_EMPTY(DoSoundDummy), "", NULL },
// ^^ Longbow demo
{ SIG_SOUNDSCI1LATE, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundRestore), "", NULL },
+ { SIG_SOUNDSCI1LATE, 2, MAP_EMPTY(DoSoundRestore), "", NULL },
{ SIG_SOUNDSCI1LATE, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
{ SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
@@ -143,7 +143,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1LATE, 10, MAP_CALL(DoSoundPause), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 11, MAP_CALL(DoSoundFade), "oiiii(i)", kDoSoundFade_workarounds },
{ SIG_SOUNDSCI1LATE, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
{ SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
{ SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
@@ -152,36 +152,97 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundGlobalReverb), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
#ifdef ENABLE_SCI32
- { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
- { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
- { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), NULL, NULL },
- { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), NULL, NULL },
- { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), NULL, NULL },
- { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
- { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o(i)", NULL },
+ { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
+ { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), "(i)", NULL },
+ { SIG_SOUNDSCI21, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), "", NULL },
+ { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
+ { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
+ { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), "o", NULL },
+ { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), "o", NULL },
+ { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o", kDoSoundPlay_workarounds },
// ^^ TODO: if this is really the only change between SCI1LATE AND SCI21, we could rename the
// SIG_SOUNDSCI1LATE #define to SIG_SINCE_SOUNDSCI1LATE and make it being SCI1LATE+. Although
// I guess there are many more changes somewhere
// TODO: Quest for Glory 4 (SCI2.1) uses the old scheme, we need to detect it accordingly
// signature for SCI21 should be "o"
- { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), NULL, NULL },
- { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), NULL, NULL },
- { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), NULL, kDoSoundFade_workarounds },
- { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI21, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
- { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), NULL, NULL },
- { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), NULL, NULL },
- { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
- { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), NULL, NULL },
- { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundGlobalReverb), NULL, NULL },
- { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
+ { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), "o", NULL },
+ { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), "[o0]i", NULL },
+ { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), "oi", NULL },
+ { SIG_SOUNDSCI21, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
+ { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
+ { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
+ { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), "o", NULL },
+ { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), "oiiii", NULL },
+ { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
+ { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), "o", NULL },
#endif
SCI_SUBOPENTRY_TERMINATOR
};
+#ifdef ENABLE_SCI32
+// NOTE: In SSCI, some 'unused' kDoAudio subops are actually
+// called indirectly by kDoSound:
+//
+// kDoSoundGetAudioCapability -> kDoAudioGetCapability
+// kDoSoundPlay -> kDoAudioPlay, kDoAudioStop
+// kDoSoundPause -> kDoAudioPause, kDoAudioResume
+// kDoSoundFade -> kDoAudioFade
+// kDoSoundSetVolume -> kDoAudioVolume
+// kDoSoundSetLoop -> kDoAudioSetLoop
+// kDoSoundUpdateCues -> kDoAudioPosition
+//
+// In ScummVM, logic inside these kernel functions has been
+// moved to methods of Audio32, and direct calls to Audio32
+// are made from kDoSound instead.
+//
+// Some kDoAudio methods are esoteric and appear to be used
+// only by one or two games:
+//
+// kDoAudioMixing: Phantasmagoria (other games call this
+// function, but only to disable the feature)
+// kDoAudioHasSignal: SQ6 TalkRandCycle
+// kDoAudioPan: Rama RegionSFX::pan method
+//
+// Finally, there is a split in SCI2.1mid audio code.
+// QFG4CD & SQ6 do not have opcodes 18 and 19, but they
+// exist in GK2, KQ7 2.00b, Phantasmagoria 1, PQ:SWAT, and
+// Torin. (It is unknown if they exist in MUMG Deluxe or
+// Shivers 1; they are not used in either of these games.)
+
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kDoAudio_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(DoAudioInit), "", NULL },
+ // SCI2 includes a Sync script that would call
+ // kDoAudioWaitForPlay, but SSCI has no opcode 1 until
+ // SCI2.1early
+ { SIG_SINCE_SCI21, 1, MAP_CALL(DoAudioWaitForPlay), "(i)(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(DoAudioPlay), "(i)(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(DoAudioStop), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(DoAudioPause), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 5, MAP_CALL(DoAudioResume), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 6, MAP_CALL(DoAudioPosition), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 7, MAP_CALL(DoAudioRate), "(i)", NULL },
+ { SIG_SCI32, 8, MAP_CALL(DoAudioVolume), "(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 9, MAP_CALL(DoAudioGetCapability), "", NULL },
+ { SIG_SCI32, 10, MAP_CALL(DoAudioBitDepth), "(i)", NULL },
+ { SIG_SCI32, 11, MAP_DUMMY(DoAudioDistort), "(i)", NULL },
+ { SIG_SCI32, 12, MAP_CALL(DoAudioMixing), "(i)", NULL },
+ { SIG_SCI32, 13, MAP_CALL(DoAudioChannels), "(i)", NULL },
+ { SIG_SCI32, 14, MAP_CALL(DoAudioPreload), "(i)", NULL },
+ { SIG_SINCE_SCI21MID, 15, MAP_CALL(DoAudioFade), "(iiii)(i)(i)", NULL },
+ { SIG_SINCE_SCI21MID, 16, MAP_DUMMY(DoAudioFade36), "iiiii(iii)(i)", NULL },
+ { SIG_SINCE_SCI21MID, 17, MAP_CALL(DoAudioHasSignal), "", NULL },
+ { SIG_SINCE_SCI21MID, 18, MAP_EMPTY(DoAudioCritical), "", NULL },
+ { SIG_SINCE_SCI21MID, 19, MAP_CALL(DoAudioSetLoop), "iii(o)", NULL },
+ { SIG_SCI3, 20, MAP_DUMMY(DoAudioPan), "", NULL },
+ { SIG_SCI3, 21, MAP_DUMMY(DoAudioPanOff), "", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+#endif
+
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kGraph_subops[] = {
{ SIG_SCI32, 1, MAP_CALL(StubNull), "", NULL }, // called by gk1 sci32 right at the start
@@ -353,12 +414,12 @@ static const SciKernelMapSubEntry kList_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kRemapColors_subops[] = {
- { SIG_SCI32, 0, MAP_CALL(RemapOff), "(i)", NULL },
- { SIG_SCI32, 1, MAP_CALL(RemapByRange), "iiii(i)", NULL },
- { SIG_SCI32, 2, MAP_CALL(RemapByPercent), "ii(i)", NULL },
- { SIG_SCI32, 3, MAP_CALL(RemapToGray), "ii(i)", NULL },
- { SIG_SCI32, 4, MAP_CALL(RemapToPercentGray), "iii(i)", NULL },
- { SIG_SCI32, 5, MAP_CALL(RemapSetNoMatchRange), "ii", NULL },
+ { SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(RemapColorsByRange), "iiii(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(RemapColorsByPercent), "ii(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(RemapColorsToGray), "ii(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(RemapColorsToPercentGray), "iii(i)", NULL },
+ { SIG_SCI32, 5, MAP_CALL(RemapColorsBlockRange), "ii", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@@ -407,25 +468,30 @@ static const SciKernelMapSubEntry kString_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kScrollWindow_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(ScrollWindowCreate), "oi", NULL },
- { SIG_SCI32, 1, MAP_CALL(ScrollWindowAdd), "o.ii.(.)", NULL },
- { SIG_SCI32, 2, MAP_DUMMY(ScrollWindowClear), "o", NULL },
- { SIG_SCI32, 3, MAP_DUMMY(ScrollWindowPageUp), "o", NULL },
- { SIG_SCI32, 4, MAP_DUMMY(ScrollWindowPageDown), "o", NULL },
- { SIG_SCI32, 5, MAP_DUMMY(ScrollWindowUpArrow), "o", NULL },
- { SIG_SCI32, 6, MAP_DUMMY(ScrollWindowDownArrow), "o", NULL },
- { SIG_SCI32, 7, MAP_DUMMY(ScrollWindowHome), "o", NULL },
- { SIG_SCI32, 8, MAP_DUMMY(ScrollWindowEnd), "o", NULL },
- { SIG_SCI32, 9, MAP_DUMMY(ScrollWindowResize), "o.", NULL },
- { SIG_SCI32, 10, MAP_CALL(ScrollWindowWhere), "oi", NULL },
- { SIG_SCI32, 11, MAP_DUMMY(ScrollWindowGo), "o..", NULL },
- { SIG_SCI32, 12, MAP_DUMMY(ScrollWindowInsert), "o.....", NULL },
- { SIG_SCI32, 13, MAP_DUMMY(ScrollWindowDelete), "o.", NULL },
- { SIG_SCI32, 14, MAP_DUMMY(ScrollWindowModify), "o.....(.)", NULL },
- { SIG_SCI32, 15, MAP_DUMMY(ScrollWindowHide), "o", NULL },
- { SIG_SCI32, 16, MAP_CALL(ScrollWindowShow), "o", NULL },
- { SIG_SCI32, 17, MAP_CALL(ScrollWindowDestroy), "o", NULL },
- { SIG_SCI32, 18, MAP_DUMMY(ScrollWindowText), "o", NULL },
- { SIG_SCI32, 19, MAP_DUMMY(ScrollWindowReconstruct), "o.", NULL },
+ { SIG_SCI32, 1, MAP_CALL(ScrollWindowAdd), "iriii(i)", kScrollWindowAdd_workarounds },
+ { SIG_SCI32, 2, MAP_DUMMY(ScrollWindowClear), "i", NULL },
+ { SIG_SCI32, 3, MAP_CALL(ScrollWindowPageUp), "i", NULL },
+ { SIG_SCI32, 4, MAP_CALL(ScrollWindowPageDown), "i", NULL },
+ { SIG_SCI32, 5, MAP_CALL(ScrollWindowUpArrow), "i", NULL },
+ { SIG_SCI32, 6, MAP_CALL(ScrollWindowDownArrow), "i", NULL },
+ { SIG_SCI32, 7, MAP_CALL(ScrollWindowHome), "i", NULL },
+ { SIG_SCI32, 8, MAP_CALL(ScrollWindowEnd), "i", NULL },
+ { SIG_SCI32, 9, MAP_DUMMY(ScrollWindowResize), "i.", NULL },
+ { SIG_SCI32, 10, MAP_CALL(ScrollWindowWhere), "ii", NULL },
+ { SIG_SCI32, 11, MAP_CALL(ScrollWindowGo), "i..", NULL },
+ { SIG_SCI32, 12, MAP_DUMMY(ScrollWindowInsert), "i.....", NULL },
+ { SIG_SCI32, 13, MAP_DUMMY(ScrollWindowDelete), "i.", NULL },
+ { SIG_SCI32, 14, MAP_CALL(ScrollWindowModify), "iiriii(i)", NULL },
+ { SIG_SCI32, 15, MAP_CALL(ScrollWindowHide), "i", NULL },
+ { SIG_SCI32, 16, MAP_CALL(ScrollWindowShow), "i", NULL },
+ { SIG_SCI32, 17, MAP_CALL(ScrollWindowDestroy), "i", NULL },
+ // LSL6hires uses kScrollWindowText and kScrollWindowReconstruct to try to save
+ // and restore the content of the game's subtitle window, but this feature did not
+ // use the normal save/load functionality of the engine and was actually broken
+ // (all text formatting was missing on restore). Since there is no real reason to
+ // save the subtitle scrollback anyway, we just ignore calls to these two functions.
+ { SIG_SCI32, 18, MAP_EMPTY(ScrollWindowText), "i", NULL },
+ { SIG_SCI32, 19, MAP_EMPTY(ScrollWindowReconstruct), "i.", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@@ -484,7 +550,10 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(DisposeList), SIG_EVERYWHERE, "l", NULL, NULL },
{ MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds },
{ MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL },
- { MAP_CALL(DoAudio), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(DoAudio), SCI_VERSION_NONE, SCI_VERSION_2, SIGFOR_ALL, "i(.*)", NULL, NULL }, // subop
+#ifdef ENABLE_SCI32
+ { "DoAudio", kDoAudio32, SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kDoAudio_subops, NULL },
+#endif
{ MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL },
{ MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL },
@@ -565,9 +634,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(PriCoord), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(Random), SIG_EVERYWHERE, "i(i)(i)", NULL, NULL },
{ MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, kReadNumber_workarounds },
- { "RemapColors", kRemapColors16, SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
+ { MAP_CALL(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
#ifdef ENABLE_SCI32
- { MAP_CALL(RemapColors), SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
+ { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
#endif
{ MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
@@ -659,6 +728,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ListEachElementDo), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
{ MAP_CALL(ListFirstTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
{ MAP_CALL(ListIndexOf), SIG_EVERYWHERE, "l[o0]", NULL, NULL },
+ // kMessageBox is used only by KQ7 1.51
+ { MAP_CALL(MessageBox), SIG_SCI32, SIGFOR_ALL, "rri", NULL, NULL },
{ "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL },
// Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
// memory") are available when the current room changes. This is similar to the SCI0-SCI1.1 FlushResources
@@ -736,9 +807,12 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(SetFontRes), SIG_SCI21EARLY, SIGFOR_ALL, "ii", NULL, NULL },
{ MAP_CALL(Font), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kFont_subops, NULL },
{ MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", kBitmap_subops, NULL },
- { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL },
- { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "[r0]oiiiiiiiii", NULL, NULL },
- { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "[r0]o", NULL, NULL },
+ { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiii(iiiii)", NULL, NULL },
+ // The first argument is a ScreenItem instance ID that is created by the
+ // engine, not the VM; as a result, in ScummVM, this argument looks like
+ // an integer and not an object, although it is an object reference.
+ { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "ioiiii(iiiii)", NULL, NULL },
+ { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "io", NULL, NULL },
// SCI2.1 Empty Functions
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 335763a35f..d604bb85d0 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -806,25 +806,47 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
} else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) {
// virtualId is low, we assume that scripts expect us to create new slot
- if (g_sci->getGameId() == GID_JONES) {
+ switch (g_sci->getGameId()) {
+ case GID_JONES:
// Jones has one save slot only
savegameId = 0;
- } else if (virtualId == s->_lastSaveVirtualId) {
- // if last virtual id is the same as this one, we assume that caller wants to overwrite last save
- savegameId = s->_lastSaveNewId;
- } else {
- uint savegameNr;
- // savegameId is in lower range, scripts expect us to create a new slot
- for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
- for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
- if (savegameId == saves[savegameNr].id)
+ break;
+ case GID_FANMADE: {
+ // Fanmade game, try to identify the game
+ const char *gameName = g_sci->getGameObjectName();
+
+ if (strcmp(gameName, "CascadeQuest") == 0) {
+ // Cascade Quest calls us directly to auto-save and uses slot 99,
+ // put that save into slot 0 (ScummVM auto-save slot) see bug #7007
+ if (virtualId == (SAVEGAMEID_OFFICIALRANGE_START - 1)) {
+ savegameId = 0;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (savegameId < 0) {
+ // savegameId not set yet
+ if (virtualId == s->_lastSaveVirtualId) {
+ // if last virtual id is the same as this one, we assume that caller wants to overwrite last save
+ savegameId = s->_lastSaveNewId;
+ } else {
+ uint savegameNr;
+ // savegameId is in lower range, scripts expect us to create a new slot
+ for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
+ for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
+ if (savegameId == saves[savegameNr].id)
+ break;
+ }
+ if (savegameNr == saves.size()) // Slot not found, seems to be good to go
break;
}
- if (savegameNr == saves.size()) // Slot not found, seems to be good to go
- break;
+ if (savegameId > SAVEGAMESLOT_LAST)
+ error("kSavegame: no more savegame slots available");
}
- if (savegameId > SAVEGAMESLOT_LAST)
- error("kSavegame: no more savegame slots available");
}
} else {
error("kSaveGame: invalid savegameId used");
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 73236b98ed..cae5a09789 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1258,7 +1258,7 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) {
}
// Early variant of the SCI32 kRemapColors kernel function, used in the demo of QFG4
-reg_t kRemapColors16(EngineState *s, int argc, reg_t *argv) {
+reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
uint16 operation = argv[0].toUint16();
switch (operation) {
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 6c51ec4284..019a06930c 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -52,7 +52,9 @@
#include "sci/graphics/controls32.h"
#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class
#include "sci/graphics/frameout.h"
+#include "sci/graphics/paint32.h"
#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
#endif
@@ -133,8 +135,6 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
bool showBits = argc > 0 ? argv[0].toUint16() : true;
g_sci->_gfxFrameout->kernelFrameOut(showBits);
- s->speedThrottler(16);
- s->_throttleTrigger = true;
return s->r_acc;
}
@@ -255,6 +255,10 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+reg_t kMessageBox(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_gfxControls32->kernelMessageBox(s->_segMan->getString(argv[0]), s->_segMan->getString(argv[1]), argv[2].toUint16());
+}
+
/**
* Causes an immediate plane transition with an optional transition
* effect
@@ -361,140 +365,138 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
}
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowCreate");
- kStub(s, argc, argv);
- return argv[0];
+ const reg_t object = argv[0];
+ const uint16 maxNumEntries = argv[1].toUint16();
+
+ SegManager *segMan = s->_segMan;
+ const int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor));
+ const TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
+ const GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font));
+ const int16 backColor = readSelectorValue(segMan, object, SELECTOR(back));
+ const int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore));
+ const reg_t plane = readSelector(segMan, object, SELECTOR(plane));
+
+ Common::Rect rect;
+ rect.left = readSelectorValue(segMan, object, SELECTOR(nsLeft));
+ rect.top = readSelectorValue(segMan, object, SELECTOR(nsTop));
+ rect.right = readSelectorValue(segMan, object, SELECTOR(nsRight)) + 1;
+ rect.bottom = readSelectorValue(segMan, object, SELECTOR(nsBottom)) + 1;
+ const Common::Point position(rect.left, rect.top);
+
+ return g_sci->_gfxControls32->makeScrollWindow(rect, position, plane, foreColor, backColor, fontId, alignment, borderColor, maxNumEntries);
}
reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowAdd");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const Common::String text = s->_segMan->getString(argv[1]);
+ const GuiResourceId fontId = argv[2].toSint16();
+ const int16 color = argv[3].toSint16();
+ const TextAlign alignment = (TextAlign)argv[4].toSint16();
+ const bool scrollTo = argc > 5 ? (bool)argv[5].toUint16() : true;
+
+ return scrollWindow->add(text, fontId, color, alignment, scrollTo);
}
reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowWhere");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const uint16 where = (argv[1].toUint16() * scrollWindow->where()).toInt();
+
+ return make_reg(0, where);
+}
+
+reg_t kScrollWindowGo(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const Ratio scrollTop(argv[1].toSint16(), argv[2].toSint16());
+ scrollWindow->go(scrollTop);
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const reg_t entryId = argv[1];
+ const Common::String newText = s->_segMan->getString(argv[2]);
+ const GuiResourceId fontId = argv[3].toSint16();
+ const int16 color = argv[4].toSint16();
+ const TextAlign alignment = (TextAlign)argv[5].toSint16();
+ const bool scrollTo = argc > 6 ? (bool)argv[6].toUint16() : true;
+
+ return scrollWindow->modify(entryId, newText, fontId, color, alignment, scrollTo);
+}
+
+reg_t kScrollWindowHide(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->hide();
+
+ return s->r_acc;
}
reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowShow");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->show();
+
+ return s->r_acc;
}
-reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowDestroy");
- return kStubNull(s, argc, argv);
+reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageUp();
+
+ return s->r_acc;
}
-#if 0
-reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
- // Used by SQ6 and LSL6 hires for the text area in the bottom of the
- // screen. The relevant scripts also exist in Phantasmagoria 1, but they're
- // unused. This is always called by scripts 64906 (ScrollerWindow) and
- // 64907 (ScrollableWindow).
-
- reg_t kWindow = argv[1];
- uint16 op = argv[0].toUint16();
- switch (op) {
- case 0: // Init
- // TODO: Init reads the nsLeft, nsTop, nsRight, nsBottom,
- // borderColor, fore, back, mode, font, plane selectors
- // from the window in argv[1].
- g_sci->_gfxFrameout->initScrollText(argv[2].toUint16()); // maxItems
- g_sci->_gfxFrameout->clearScrollTexts();
- return argv[1]; // kWindow
- case 1: // Show message, called by ScrollableWindow::addString
- case 14: // Modify message, called by ScrollableWindow::modifyString
- // TODO: The parameters in Modify are shifted by one: the first
- // argument is the handle of the text to modify. The others
- // are as Add.
- {
- Common::String text = s->_segMan->getString(argv[2]);
- uint16 x = 0;
- uint16 y = 0;
- // TODO: argv[3] is font
- // TODO: argv[4] is color
- // TODO: argv[5] is alignment (0 = left, 1 = center, 2 = right)
- // font,color,alignment may also be -1. (Maybe same as previous?)
- // TODO: argv[6] is an optional bool, defaulting to true if not present.
- // If true, the old contents are scrolled out of view.
- // TODO: Return a handle of the inserted text. (Used for modify/insert)
- // This handle looks like it should also be usable by kString.
- g_sci->_gfxFrameout->addScrollTextEntry(text, kWindow, x, y, (op == 14));
- }
- break;
- case 2: // Clear, called by ScrollableWindow::erase
- g_sci->_gfxFrameout->clearScrollTexts();
- break;
- case 3: // Page up, called by ScrollableWindow::scrollTo
- // TODO
- kStub(s, argc, argv);
- break;
- case 4: // Page down, called by ScrollableWindow::scrollTo
- // TODO
- kStub(s, argc, argv);
- break;
- case 5: // Up arrow, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->prevScrollText();
- break;
- case 6: // Down arrow, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->nextScrollText();
- break;
- case 7: // Home, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->firstScrollText();
- break;
- case 8: // End, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->lastScrollText();
- break;
- case 9: // Resize, called by ScrollableWindow::resize and ScrollerWindow::resize
- // TODO: This reads the nsLeft, nsTop, nsRight, nsBottom
- // selectors from the SCI object passed in argv[2].
- kStub(s, argc, argv);
- break;
- case 10: // Where, called by ScrollableWindow::where
- // TODO:
- // Gives the current relative scroll location as a fraction
- // with argv[2] as the denominator. (Return value is the numerator.)
- // Silenced the warnings because of the high amount of console spam
- //kStub(s, argc, argv);
- break;
- case 11: // Go, called by ScrollableWindow::scrollTo
- // TODO:
- // Two arguments provide a fraction: argv[2] is num., argv[3] is denom.
- // Scrolls to the relative location given by the fraction.
- kStub(s, argc, argv);
- break;
- case 12: // Insert, called by ScrollableWindow::insertString
- // 5 extra parameters here:
- // handle of insert location (new string takes that position).
- // text, font, color, alignment
- // TODO
- kStub(s, argc, argv);
- break;
- // case 13 (Delete) is handled below
- // case 14 (Modify) is handled above
- case 15: // Hide, called by ScrollableWindow::hide
- g_sci->_gfxFrameout->toggleScrollText(false);
- break;
- case 16: // Show, called by ScrollableWindow::show
- g_sci->_gfxFrameout->toggleScrollText(true);
- break;
- case 17: // Destroy, called by ScrollableWindow::dispose
- g_sci->_gfxFrameout->clearScrollTexts();
- break;
- case 13: // Delete, unused
- case 18: // Text, unused
- case 19: // Reconstruct, unused
- error("kScrollWindow: Unused subop %d invoked", op);
- break;
- default:
- error("kScrollWindow: unknown subop %d", op);
- break;
- }
+reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageDown();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->upArrow();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowDownArrow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->downArrow();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowHome(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->home();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->end();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxControls32->destroyScrollWindow(argv[0]);
return s->r_acc;
}
-#endif
reg_t kFont(EngineState *s, int argc, reg_t *argv) {
if (!s)
@@ -548,46 +550,31 @@ reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) {
}
reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
- // viewId, loopNo, celNo, displace x, displace y, unused, view x, view y
+ BitmapResource bitmap(argv[0]);
+ CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
- // called e.g. from TiledBitmap::resize() in Torin's Passage, script 64869
- // The tiled view seems to always have 2 loops.
- // These loops need to have 1 cel in loop 0 and 8 cels in loop 1.
+ const int16 x = argc > 4 ? argv[4].toSint16() : 0;
+ const int16 y = argc > 5 ? argv[5].toSint16() : 0;
+ const int16 alignX = argc > 7 ? argv[7].toSint16() : -1;
+ const int16 alignY = argc > 8 ? argv[8].toSint16() : -1;
- return kStubNull(s, argc + 1, argv - 1);
+ Common::Point position(
+ x == -1 ? bitmap.getDisplace().x : x,
+ y == -1 ? bitmap.getDisplace().y : y
+ );
-#if 0
- // tiled surface
- // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage,
- // script 64869
- reg_t hunkId = argv[1]; // obtained from kBitmap(0)
- // The tiled view seems to always have 2 loops.
- // These loops need to have 1 cel in loop 0 and 8 cels in loop 1.
- uint16 viewNum = argv[2].toUint16(); // vTiles selector
- uint16 loop = argv[3].toUint16();
- uint16 cel = argv[4].toUint16();
- uint16 x = argv[5].toUint16();
- uint16 y = argv[6].toUint16();
-
- byte *memoryPtr = s->_segMan->getHunkPointer(hunkId);
- // Get totalWidth, totalHeight
- uint16 totalWidth = READ_LE_UINT16(memoryPtr);
- uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2);
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
-
- GfxView *view = g_sci->_gfxCache->getView(viewNum);
- uint16 tileWidth = view->getWidth(loop, cel);
- uint16 tileHeight = view->getHeight(loop, cel);
- const byte *tileBitmap = view->getBitmap(loop, cel);
- uint16 width = MIN<uint16>(totalWidth - x, tileWidth);
- uint16 height = MIN<uint16>(totalHeight - y, tileHeight);
-
- for (uint16 curY = 0; curY < height; curY++) {
- for (uint16 curX = 0; curX < width; curX++) {
- bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX];
- }
- }
-#endif
+ position.x -= alignX == -1 ? view._displace.x : alignX;
+ position.y -= alignY == -1 ? view._displace.y : alignY;
+
+ Common::Rect drawRect(
+ position.x,
+ position.y,
+ position.x + view._width,
+ position.y + view._height
+ );
+ drawRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
+ view.draw(bitmap.getBuffer(), drawRect, position, view._mirrorX);
+ return s->r_acc;
}
reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
@@ -618,9 +605,8 @@ reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false);
- Buffer bitmapBuffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels());
CelObjMem textCel(textBitmapObject);
- textCel.draw(bitmapBuffer, textRect, Common::Point(textRect.left, textRect.top), false);
+ textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false);
s->_segMan->freeHunkEntry(textBitmapObject);
return s->r_acc;
@@ -637,8 +623,7 @@ reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
argv[4].toSint16() + 1
);
- Buffer buffer(bitmap.getWidth(), bitmap.getHeight(), bitmap.getPixels());
- buffer.fillRect(fillRect, argv[5].toSint16());
+ bitmap.getBuffer().fillRect(fillRect, argv[5].toSint16());
return s->r_acc;
}
@@ -702,46 +687,77 @@ reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
}
reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
- return kStubNull(s, argc, argv); // return 0:0 for now, so that follow up calls won't create signature mismatches
-#if 0
- reg_t plane = argv[0];
- Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16());
- Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16());
- byte priority = (byte)argv[5].toUint16();
- byte color = (byte)argv[6].toUint16();
- byte style = (byte)argv[7].toUint16(); // 0: solid, 1: dashed, 2: pattern
- byte pattern = (byte)argv[8].toUint16();
- byte thickness = (byte)argv[9].toUint16();
-// return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, 0);
- return s->r_acc;
-#endif
+ const reg_t plane = argv[0];
+ const Common::Point startPoint(argv[1].toSint16(), argv[2].toSint16());
+ const Common::Point endPoint(argv[3].toSint16(), argv[4].toSint16());
+
+ int16 priority;
+ uint8 color;
+ LineStyle style;
+ uint16 pattern;
+ uint8 thickness;
+
+ if (argc == 10) {
+ priority = argv[5].toSint16();
+ color = (uint8)argv[6].toUint16();
+ style = (LineStyle)argv[7].toSint16();
+ pattern = argv[8].toUint16();
+ thickness = (uint8)argv[9].toUint16();
+ } else {
+ priority = 1000;
+ color = 255;
+ style = kLineStyleSolid;
+ pattern = 0;
+ thickness = 1;
+ }
+
+ return g_sci->_gfxPaint32->kernelAddLine(plane, startPoint, endPoint, priority, color, style, pattern, thickness);
}
reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) {
- return kStub(s, argc, argv);
+ const reg_t screenItemObject = argv[0];
+ const reg_t planeObject = argv[1];
+ const Common::Point startPoint(argv[2].toSint16(), argv[3].toSint16());
+ const Common::Point endPoint(argv[4].toSint16(), argv[5].toSint16());
+
+ int16 priority;
+ uint8 color;
+ LineStyle style;
+ uint16 pattern;
+ uint8 thickness;
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kUpdateLine: Plane %04x:%04x not found", PRINT_REG(planeObject));
+ }
+
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject);
+ if (screenItem == nullptr) {
+ error("kUpdateLine: Screen item %04x:%04x not found", PRINT_REG(screenItemObject));
+ }
+
+ if (argc == 11) {
+ priority = argv[6].toSint16();
+ color = (uint8)argv[7].toUint16();
+ style = (LineStyle)argv[8].toSint16();
+ pattern = argv[9].toUint16();
+ thickness = (uint8)argv[10].toUint16();
+ } else {
+ priority = screenItem->_priority;
+ color = screenItem->_celInfo.color;
+ style = kLineStyleSolid;
+ pattern = 0;
+ thickness = 1;
+ }
+
+ g_sci->_gfxPaint32->kernelUpdateLine(screenItem, plane, startPoint, endPoint, priority, color, style, pattern, thickness);
-#if 0
- reg_t hunkId = argv[0];
- reg_t plane = argv[1];
- Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16());
- Common::Point endPoint(argv[4].toUint16(), argv[5].toUint16());
- // argv[6] is unknown (a number, usually 200)
- byte color = (byte)argv[7].toUint16();
- byte priority = (byte)argv[8].toUint16();
- byte control = (byte)argv[9].toUint16();
- // argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
-// g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control);
return s->r_acc;
-#endif
}
+
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
- return kStub(s, argc, argv);
-#if 0
- reg_t hunkId = argv[0];
- reg_t plane = argv[1];
-// g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId);
+ g_sci->_gfxPaint32->kernelDeleteLine(argv[0], argv[1]);
return s->r_acc;
-#endif
}
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
@@ -910,57 +926,69 @@ reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
+reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
if (!s)
return make_reg(0, getSciVersion());
error("not supposed to call this");
}
-reg_t kRemapOff(EngineState *s, int argc, reg_t *argv) {
- byte color = (argc >= 1) ? argv[0].toUint16() : 0;
- g_sci->_gfxRemap32->remapOff(color);
+reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxRemap32->remapAllOff();
+ } else {
+ const uint8 color = argv[0].toUint16();
+ g_sci->_gfxRemap32->remapOff(color);
+ }
return s->r_acc;
}
-reg_t kRemapByRange(EngineState *s, int argc, reg_t *argv) {
- byte color = argv[0].toUint16();
- byte from = argv[1].toUint16();
- byte to = argv[2].toUint16();
- byte base = argv[3].toUint16();
- // The last parameter, depth, is unused
- g_sci->_gfxRemap32->setRemappingRange(color, from, to, base);
+reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 from = argv[1].toSint16();
+ const int16 to = argv[2].toSint16();
+ const int16 base = argv[3].toSint16();
+ // NOTE: There is an optional last parameter after `base`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapByRange(color, from, to, base);
return s->r_acc;
}
-reg_t kRemapByPercent(EngineState *s, int argc, reg_t *argv) {
- byte color = argv[0].toUint16();
- byte percent = argv[1].toUint16();
- // The last parameter, depth, is unused
- g_sci->_gfxRemap32->setRemappingPercent(color, percent);
+reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 percent = argv[1].toSint16();
+ // NOTE: There is an optional last parameter after `percent`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapByPercent(color, percent);
return s->r_acc;
}
-reg_t kRemapToGray(EngineState *s, int argc, reg_t *argv) {
- byte color = argv[0].toUint16();
- byte gray = argv[1].toUint16();
- // The last parameter, depth, is unused
- g_sci->_gfxRemap32->setRemappingToGray(color, gray);
+reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 gray = argv[1].toSint16();
+ // NOTE: There is an optional last parameter after `gray`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapToGray(color, gray);
return s->r_acc;
}
-reg_t kRemapToPercentGray(EngineState *s, int argc, reg_t *argv) {
- byte color = argv[0].toUint16();
- byte gray = argv[1].toUint16();
- byte percent = argv[2].toUint16();
- // The last parameter, depth, is unused
- g_sci->_gfxRemap32->setRemappingToPercentGray(color, gray, percent);
+reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 gray = argv[1].toSint16();
+ const int16 percent = argv[2].toSint16();
+ // NOTE: There is an optional last parameter after `percent`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapToPercentGray(color, gray, percent);
return s->r_acc;
}
-reg_t kRemapSetNoMatchRange(EngineState *s, int argc, reg_t *argv) {
- byte from = argv[0].toUint16();
- byte count = argv[1].toUint16();
- g_sci->_gfxRemap32->setNoMatchRange(from, count);
+reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv) {
+ const uint8 from = argv[0].toUint16();
+ const uint8 count = argv[1].toUint16();
+ g_sci->_gfxRemap32->blockRange(from, count);
return s->r_acc;
}
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index f4bb4ff85b..0a5f26476f 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -243,10 +243,18 @@ reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelTime, "GetTime(24h) returns %d", retval);
break;
case KGETTIME_DATE :
- // Year since 1980 (0 = 1980, 1 = 1981, etc.)
- retval = loc_time.tm_mday | ((loc_time.tm_mon + 1) << 5) | (((loc_time.tm_year - 80) & 0x7f) << 9);
+ {
+ // SCI0 late: Year since 1920 (0 = 1920, 1 = 1921, etc)
+ // SCI01 and newer: Year since 1980 (0 = 1980, 1 = 1981, etc)
+ // Atari ST SCI0 late versions use the newer base year.
+ int baseYear = 80;
+ if (getSciVersion() == SCI_VERSION_0_LATE && g_sci->getPlatform() == Common::kPlatformDOS) {
+ baseYear = 20;
+ }
+ retval = loc_time.tm_mday | ((loc_time.tm_mon + 1) << 5) | (((loc_time.tm_year - baseYear) & 0x7f) << 9);
debugC(kDebugLevelTime, "GetTime(date) returns %d", retval);
break;
+ }
default:
error("Attempt to use unknown GetTime mode %d", mode);
break;
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 7ac744f584..06f16299aa 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -326,7 +326,7 @@ static void draw_line(EngineState *s, Common::Point p1, Common::Point p2, int ty
p2.y = CLIP<int16>(p2.y, 0, height - 1);
assert(type >= 0 && type <= 3);
- g_sci->_gfxPaint->kernelGraphDrawLine(p1, p2, poly_colors[type], 255, 255);
+ g_sci->_gfxPaint16->kernelGraphDrawLine(p1, p2, poly_colors[type], 255, 255);
}
static void draw_point(EngineState *s, Common::Point p, int start, int width, int height) {
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 398a623286..ed53b8d52f 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -26,7 +26,11 @@
#include "sci/engine/kernel.h"
#include "sci/engine/vm.h" // for Object
#include "sci/sound/audio.h"
+#ifdef ENABLE_SCI32
+#include "sci/sound/audio32.h"
+#endif
#include "sci/sound/soundcmd.h"
+#include "sci/sound/sync.h"
#include "audio/mixer.h"
#include "common/system.h"
@@ -46,7 +50,6 @@ reg_t kDoSound(EngineState *s, int argc, reg_t *argv) {
CREATE_DOSOUND_FORWARD(DoSoundInit)
CREATE_DOSOUND_FORWARD(DoSoundPlay)
-CREATE_DOSOUND_FORWARD(DoSoundRestore)
CREATE_DOSOUND_FORWARD(DoSoundDispose)
CREATE_DOSOUND_FORWARD(DoSoundMute)
CREATE_DOSOUND_FORWARD(DoSoundStop)
@@ -61,13 +64,41 @@ CREATE_DOSOUND_FORWARD(DoSoundUpdateCues)
CREATE_DOSOUND_FORWARD(DoSoundSendMidi)
CREATE_DOSOUND_FORWARD(DoSoundGlobalReverb)
CREATE_DOSOUND_FORWARD(DoSoundSetHold)
-CREATE_DOSOUND_FORWARD(DoSoundDummy)
CREATE_DOSOUND_FORWARD(DoSoundGetAudioCapability)
CREATE_DOSOUND_FORWARD(DoSoundSuspend)
CREATE_DOSOUND_FORWARD(DoSoundSetVolume)
CREATE_DOSOUND_FORWARD(DoSoundSetPriority)
CREATE_DOSOUND_FORWARD(DoSoundSetLoop)
+#ifdef ENABLE_SCI32
+reg_t kDoSoundPhantasmagoriaMac(EngineState *s, int argc, reg_t *argv) {
+ // Phantasmagoria Mac (and seemingly no other game (!)) uses this
+ // cutdown version of kDoSound.
+
+ switch (argv[0].toUint16()) {
+ case 0:
+ return g_sci->_soundCmd->kDoSoundMasterVolume(argc - 1, argv + 1, s->r_acc);
+ case 2:
+ return g_sci->_soundCmd->kDoSoundInit(argc - 1, argv + 1, s->r_acc);
+ case 3:
+ return g_sci->_soundCmd->kDoSoundDispose(argc - 1, argv + 1, s->r_acc);
+ case 4:
+ return g_sci->_soundCmd->kDoSoundPlay(argc - 1, argv + 1, s->r_acc);
+ case 5:
+ return g_sci->_soundCmd->kDoSoundStop(argc - 1, argv + 1, s->r_acc);
+ case 8:
+ return g_sci->_soundCmd->kDoSoundSetVolume(argc - 1, argv + 1, s->r_acc);
+ case 9:
+ return g_sci->_soundCmd->kDoSoundSetLoop(argc - 1, argv + 1, s->r_acc);
+ case 10:
+ return g_sci->_soundCmd->kDoSoundUpdateCues(argc - 1, argv + 1, s->r_acc);
+ }
+
+ error("Unknown kDoSound Phantasmagoria Mac subop %d", argv[0].toUint16());
+ return s->r_acc;
+}
+#endif
+
reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case kSciAudioPlay: {
@@ -113,7 +144,8 @@ reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) {
}
/**
- * Used for speech playback and digital soundtracks in CD games
+ * Used for speech playback and digital soundtracks in CD games.
+ * This is the SCI16 version; SCI32 is handled separately.
*/
reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// JonesCD uses different functions based on the cdaudio.map file
@@ -184,14 +216,6 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
int16 volume = argv[1].toUint16();
volume = CLIP<int16>(volume, 0, AUDIO_VOLUME_MAX);
debugC(kDebugLevelSound, "kDoAudio: set volume to %d", volume);
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
- int16 volumePrev = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2;
- volumePrev = CLIP<int16>(volumePrev, 0, AUDIO_VOLUME_MAX);
- mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
- return make_reg(0, volumePrev);
- } else
-#endif
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
break;
}
@@ -232,12 +256,6 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
if (getSciVersion() <= SCI_VERSION_1_1) {
debugC(kDebugLevelSound, "kDoAudio: CD audio subop");
return kDoCdAudio(s, argc - 1, argv + 1);
-#ifdef ENABLE_SCI32
- } else {
- // TODO: This isn't CD Audio in SCI32 anymore
- warning("kDoAudio: Unhandled case 10, %d extra arguments passed", argc - 1);
- break;
-#endif
}
// 3 new subops in Pharkas CD (including CD demo). kDoAudio in Pharkas sits at seg026:038C
@@ -286,14 +304,12 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
}
reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
- SegManager *segMan = s->_segMan;
switch (argv[0].toUint16()) {
case kSciAudioSyncStart: {
ResourceId id;
- g_sci->_audio->stopSoundSync();
+ g_sci->_sync->stop();
- // Load sound sync resource and lock it
if (argc == 3) {
id = ResourceId(kResourceTypeSync, argv[2].toUint16());
} else if (argc == 7) {
@@ -304,14 +320,14 @@ reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- g_sci->_audio->setSoundSync(id, argv[1], segMan);
+ g_sci->_sync->start(id, argv[1]);
break;
}
case kSciAudioSyncNext:
- g_sci->_audio->doSoundSync(argv[1], segMan);
+ g_sci->_sync->next(argv[1]);
break;
case kSciAudioSyncStop:
- g_sci->_audio->stopSoundSync();
+ g_sci->_sync->stop();
break;
default:
error("DoSync: Unhandled subfunction %d", argv[0].toUint16());
@@ -321,6 +337,155 @@ reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
+reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, 0);
+}
+
+reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_audio32->kernelPlay(false, argc, argv);
+}
+
+reg_t kDoAudioPlay(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_audio32->kernelPlay(true, argc, argv);
+}
+
+reg_t kDoAudioStop(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->stop(channelIndex));
+}
+
+reg_t kDoAudioPause(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->pause(channelIndex));
+}
+
+reg_t kDoAudioResume(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->resume(channelIndex));
+}
+
+reg_t kDoAudioPosition(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->getPosition(channelIndex));
+}
+
+reg_t kDoAudioRate(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP sampling rate; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const uint16 sampleRate = argv[0].toUint16();
+ if (sampleRate != 0) {
+ g_sci->_audio32->setSampleRate(sampleRate);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getSampleRate());
+}
+
+reg_t kDoAudioVolume(EngineState *s, int argc, reg_t *argv) {
+ const int16 volume = argc > 0 ? argv[0].toSint16() : -1;
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 1, argc > 2 ? argv[2] : NULL_REG);
+
+ if (volume != -1) {
+ g_sci->_audio32->setVolume(channelIndex, volume);
+ }
+
+ return make_reg(0, g_sci->_audio32->getVolume(channelIndex));
+}
+
+reg_t kDoAudioGetCapability(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, 1);
+}
+
+reg_t kDoAudioBitDepth(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP bit depth; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const uint16 bitDepth = argv[0].toUint16();
+ if (bitDepth != 0) {
+ g_sci->_audio32->setBitDepth(bitDepth);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getBitDepth());
+}
+
+reg_t kDoAudioMixing(EngineState *s, int argc, reg_t *argv) {
+ if (argc > 0) {
+ g_sci->_audio32->setAttenuatedMixing(argv[0].toUint16());
+ }
+
+ return make_reg(0, g_sci->_audio32->getAttenuatedMixing());
+}
+
+reg_t kDoAudioChannels(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP stereo output; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const int16 numChannels = argv[0].toSint16();
+ if (numChannels != 0) {
+ g_sci->_audio32->setNumOutputChannels(numChannels);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getNumOutputChannels());
+}
+
+reg_t kDoAudioPreload(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would cause audio
+ // data for new channels to be preloaded to memory when
+ // the channel was initialized; we do not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ g_sci->_audio32->setPreload(argv[0].toUint16());
+ }
+
+ return make_reg(0, g_sci->_audio32->getPreload());
+}
+
+reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv) {
+ if (argc < 4) {
+ return make_reg(0, 0);
+ }
+
+ // NOTE: Sierra did a nightmarish hack here, temporarily replacing
+ // the argc of the kernel arguments with 2 and then restoring it
+ // after findChannelByArgs was called.
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(2, argv, 0, argc > 5 ? argv[5] : NULL_REG);
+
+ const int16 volume = argv[1].toSint16();
+ const int16 speed = argv[2].toSint16();
+ const int16 steps = argv[3].toSint16();
+ const bool stopAfterFade = argc > 4 ? (bool)argv[4].toUint16() : false;
+
+ return make_reg(0, g_sci->_audio32->fadeChannel(channelIndex, volume, speed, steps, stopAfterFade));
+}
+
+reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, g_sci->_audio32->hasSignal());
+}
+
+reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc == 3 ? argv[2] : NULL_REG);
+
+ const bool loop = argv[0].toSint16() != 0 && argv[0].toSint16() != 1;
+
+ g_sci->_audio32->setLoop(channelIndex, loop);
+ return s->r_acc;
+}
reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv) {
// This is used by script 90 of MUMG Deluxe from the main menu to toggle
@@ -335,33 +500,6 @@ reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kDoSoundPhantasmagoriaMac(EngineState *s, int argc, reg_t *argv) {
- // Phantasmagoria Mac (and seemingly no other game (!)) uses this
- // cutdown version of kDoSound.
-
- switch (argv[0].toUint16()) {
- case 0:
- return g_sci->_soundCmd->kDoSoundMasterVolume(argc - 1, argv + 1, s->r_acc);
- case 2:
- return g_sci->_soundCmd->kDoSoundInit(argc - 1, argv + 1, s->r_acc);
- case 3:
- return g_sci->_soundCmd->kDoSoundDispose(argc - 1, argv + 1, s->r_acc);
- case 4:
- return g_sci->_soundCmd->kDoSoundPlay(argc - 1, argv + 1, s->r_acc);
- case 5:
- return g_sci->_soundCmd->kDoSoundStop(argc - 1, argv + 1, s->r_acc);
- case 8:
- return g_sci->_soundCmd->kDoSoundSetVolume(argc - 1, argv + 1, s->r_acc);
- case 9:
- return g_sci->_soundCmd->kDoSoundSetLoop(argc - 1, argv + 1, s->r_acc);
- case 10:
- return g_sci->_soundCmd->kDoSoundUpdateCues(argc - 1, argv + 1, s->r_acc);
- }
-
- error("Unknown kDoSound Phantasmagoria Mac subop %d", argv[0].toUint16());
- return s->r_acc;
-}
-
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 0cc1e752e1..0972aec4a4 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -48,8 +48,9 @@
#include "sci/sound/music.h"
#ifdef ENABLE_SCI32
-#include "sci/graphics/palette32.h"
#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#endif
namespace Sci {
@@ -806,8 +807,33 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint16LE(cycler->numTimesPaused);
}
}
+}
+
+void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 35) {
+ return;
+ }
+
+ s.syncAsByte(_numActiveRemaps);
+ s.syncAsByte(_blockedRangeStart);
+ s.syncAsSint16LE(_blockedRangeCount);
+
+ for (uint i = 0; i < _remaps.size(); ++i) {
+ SingleRemap &singleRemap = _remaps[i];
+ s.syncAsByte(singleRemap._type);
+ if (s.isLoading() && singleRemap._type != kRemapNone) {
+ singleRemap.reset();
+ }
+ s.syncAsByte(singleRemap._from);
+ s.syncAsByte(singleRemap._to);
+ s.syncAsByte(singleRemap._delta);
+ s.syncAsByte(singleRemap._percent);
+ s.syncAsByte(singleRemap._gray);
+ }
- // TODO: _clutTable
+ if (s.isLoading()) {
+ _needsUpdate = true;
+ }
}
#endif
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 459e992e24..43909accf2 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -37,6 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
+ * 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
* 33 - new overridePriority flag in MusicEntry
* 32 - new playBed flag in MusicEntry
@@ -59,7 +60,7 @@ struct EngineState;
*/
enum {
- CURRENT_SAVEGAME_VERSION = 34,
+ CURRENT_SAVEGAME_VERSION = 35,
MINIMUM_SAVEGAME_VERSION = 14
};
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index 66c4184c95..1302cc94ea 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -379,12 +379,40 @@ static const SciScriptPatcherEntry ecoquest2Signatures[] = {
};
// ===========================================================================
+// Fan-made games
+// Attention: Try to make script patches as specific as possible
+
+// CascadeQuest::autosave in script 994 is called various times to auto-save the game.
+// The script use a fixed slot "999" for this purpose. This doesn't work in ScummVM, because we do not let
+// scripts save directly into specific slots, but instead use virtual slots / detect scripts wanting to
+// create a new slot.
+//
+// For this game we patch the code to use slot 99 instead. kSaveGame also checks for Cascade Quest,
+// will then check, if slot 99 is asked for and will then use the actual slot 0, which is the official
+// ScummVM auto-save slot.
+//
+// Responsible method: CascadeQuest::autosave
+// Fixes bug: #7007
+static const uint16 fanmadeSignatureCascadeQuestFixAutoSaving[] = {
+ SIG_MAGICDWORD,
+ 0x38, SIG_UINT16(0x03e7), // pushi 3E7 (999d) -> save game slot 999
+ 0x74, SIG_UINT16(0x06f8), // lofss "AutoSave"
+ 0x89, 0x1e, // lsg global[1E]
+ 0x43, 0x2d, 0x08, // callk SaveGame
+ SIG_END
+};
+
+static const uint16 fanmadePatchCascadeQuestFixAutoSaving[] = {
+ 0x38, PATCH_UINT16((SAVEGAMEID_OFFICIALRANGE_START - 1)), // fix slot
+ PATCH_END
+};
+
// EventHandler::handleEvent in Demo Quest has a bug, and it jumps to the
// wrong address when an incorrect word is typed, therefore leading to an
// infinite loop. This script bug was not apparent in SSCI, probably because
// event handling was slightly different there, so it was never discovered.
// Fixes bug: #5120
-static const uint16 fanmadeSignatureInfiniteLoop[] = {
+static const uint16 fanmadeSignatureDemoQuestInfiniteLoop[] = {
0x38, SIG_UINT16(0x004c), // pushi 004c
0x39, 0x00, // pushi 00
0x87, 0x01, // lap 01
@@ -395,15 +423,16 @@ static const uint16 fanmadeSignatureInfiniteLoop[] = {
SIG_END
};
-static const uint16 fanmadePatchInfiniteLoop[] = {
+static const uint16 fanmadePatchDemoQuestInfiniteLoop[] = {
PATCH_ADDTOOFFSET(+10),
- 0x30, SIG_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
+ 0x30, PATCH_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
PATCH_END
};
-// script, description, signature patch
+// script, description, signature patch
static const SciScriptPatcherEntry fanmadeSignatures[] = {
- { true, 999, "infinite loop on typo", 1, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop },
+ { true, 994, "Cascade Quest: fix auto-saving", 1, fanmadeSignatureCascadeQuestFixAutoSaving, fanmadePatchCascadeQuestFixAutoSaving },
+ { true, 999, "Demo Quest: infinite loop on typo", 1, fanmadeSignatureDemoQuestInfiniteLoop, fanmadePatchDemoQuestInfiniteLoop },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1654,9 +1683,160 @@ static const uint16 laurabow1PatchEasterEggViewFix[] = {
PATCH_END
};
+// When oiling the armor or opening the visor of the armor, the scripts
+// first check if Laura/ego is near the armor and if she is not, they will move her
+// to the armor. After that further code is executed.
+//
+// The current location is checked by a ego::inRect() call.
+//
+// The given rect for the inRect call inside openVisor::changeState was made larger for Atari ST/Amiga versions.
+// We change the PC version to use the same rect.
+//
+// Additionally the coordinate, that Laura is moved to, is 152, 107 and may not be reachable depending on where
+// Laura/ego was, when "use oil on helmet of armor" / "open visor of armor" got entered.
+// Bad coordinates are for example 82, 110, which then cause collisions and effectively an endless loop.
+// Game will effectively "freeze" and the user is only able to restore a previous game.
+// This also happened, when using the original interpreter.
+// We change the destination coordinate to 152, 110, which seems to be reachable all the time.
+//
+// The following patch fixes the rect for the PC version of the game.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: openVisor::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorOpenVisorFix[] = {
+ 0x39, 0x04, // pushi 04
+ SIG_MAGICDWORD,
+ 0x39, 0x6a, // pushi 6a (106d)
+ 0x38, SIG_UINT16(0x96), // pushi 0096 (150d)
+ 0x39, 0x6c, // pushi 6c (108d)
+ 0x38, SIG_UINT16(0x98), // pushi 0098 (152d)
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOpenVisorFix[] = {
+ PATCH_ADDTOOFFSET(+2),
+ 0x39, 0x68, // pushi 68 (104d) (-2)
+ 0x38, SIG_UINT16(0x94), // pushi 0094 (148d) (-2)
+ 0x39, 0x6f, // pushi 6f (111d) (+3)
+ 0x38, SIG_UINT16(0x9a), // pushi 009a (154d) (+2)
+ PATCH_END
+};
+
+// This here fixes the destination coordinate (exact details are above).
+//
+// Applies to at least: English PC Floppy, English Atari ST Floppy, English Amiga Floppy
+// Responsible method: openVisor::changeState, oiling::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorMoveToFix[] = {
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x39, 0x6b, // pushi 6B (107d)
+ 0x38, SIG_UINT16(0x0098), // pushi 98 (152d)
+ 0x7c, // pushSelf
+ 0x81, 0x00, // lag global[0]
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorMoveToFix[] = {
+ PATCH_ADDTOOFFSET(+1),
+ 0x39, 0x6e, // pushi 6E (110d) - adjust x, so that no collision can occur anymore
+ PATCH_END
+};
+
+// In some cases like for example when the player oils the arm of the armor, command input stays
+// disabled, even when the player exits fast enough, so that Laura doesn't die.
+//
+// This is caused by the scripts only enabling control (directional movement), but do not enable command input as well.
+//
+// This bug also happens, when using the original interpreter.
+// And it was fixed for the Atari ST + Amiga versions of the game.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: 2nd subroutine in script 37, called by oiling::changeState(7)
+// Fixes bug: #7154
+static const uint16 laurabow1SignatureArmorOilingArmFix[] = {
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ SIG_MAGICDWORD,
+ 0x72, SIG_UINT16(0x1a5c), // lofsa "Can" - offsets are not skipped to make sure only the PC version gets patched
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x19a1), // lofsa "Visor"
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x194a), // lofsa "note"
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x18f3), // lofsa "valve"
+ 0x4a, 0x04, // send 04
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x02, // ldi 02
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x0014), // bnt [to ret]
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x05, // ldi 05
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x000c), // bnt [to ret]
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x06, // ldi 06
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x0004), // bnt [to ret]
+ // followed by code to call script 0 export to re-enable controls and call setMotion
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOilingArmFix[] = {
+ PATCH_ADDTOOFFSET(+3), // skip over pushi 89h
+ 0x3c, // dup
+ 0x3c, // dup
+ 0x3c, // dup
+ // saves a total of 6 bytes
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x1a59), // lofsa "Can"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x19a1), // lofsa "Visor"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x194d), // lofsa "note"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x18f9), // lofsa "valve" 18f3
+ 0x4a, 0x04, // send 04
+ // new code to enable input as well, needs 9 spare bytes
+ 0x38, SIG_UINT16(0x00e2), // canInput
+ 0x78, // push1
+ 0x78, // push1
+ 0x51, 0x2b, // class User
+ 0x4a, 0x06, // send 06 -> call User::canInput(1)
+ // original code, but changed a bit to save some more bytes
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x02, // ldi 02
+ 0x04, // sub
+ 0x31, 0x12, // bnt [to ret]
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x04, // sub
+ 0x31, 0x0c, // bnt [to ret]
+ 0x78, // push1
+ 0x1a, // eq?
+ 0x2f, 0x08, // bt [to ret]
+ // saves 7 bytes, we only need 3, so waste 4 bytes
+ 0x35, 0x00, // ldi 0
+ 0x35, 0x00, // ldi 0
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry laurabow1Signatures[] = {
- { true, 4, "easter egg view fix", 1, laurabow1SignatureEasterEggViewFix, laurabow1PatchEasterEggViewFix },
+ { true, 4, "easter egg view fix", 1, laurabow1SignatureEasterEggViewFix, laurabow1PatchEasterEggViewFix },
+ { true, 37, "armor open visor fix", 1, laurabow1SignatureArmorOpenVisorFix, laurabow1PatchArmorOpenVisorFix },
+ { true, 37, "armor move to fix", 2, laurabow1SignatureArmorMoveToFix, laurabow1PatchArmorMoveToFix },
+ { true, 37, "allowing input, after oiling arm", 1, laurabow1SignatureArmorOilingArmFix, laurabow1PatchArmorOilingArmFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -2761,7 +2941,7 @@ static const uint16 qfg3PatchImportDialog[] = {
// Teller::doChild. We jump to this call of hero::solvePuzzle to get that same
// behaviour.
// Applies to at least: English, German, Italian, French, Spanish Floppy
-// Responsible method: unknown
+// Responsible method: uhuraTell::doChild
// Fixes bug: #5172
static const uint16 qfg3SignatureWooDialog[] = {
SIG_MAGICDWORD,
@@ -3597,24 +3777,35 @@ static const uint16 sq1vgaSignatureSpiderDroidTiming[] = {
0x30, SIG_UINT16(0x0005), // bnt [further method code]
0x35, 0x00, // ldi 00
0x32, SIG_UINT16(0x0052), // jmp [super-call]
- 0x89, 0xa6, // lsg global[a6]
+ 0x89, 0xa6, // lsg global[a6] <-- flag gets set to 1 when ego went up the skeleton tail, when going down it's set to 2
0x35, 0x01, // ldi 01
0x1a, // eq?
- 0x30, SIG_UINT16(0x0012), // bnt [2nd code], in case global A6 <> 1
+ 0x30, SIG_UINT16(0x0012), // bnt [PChase set code], in case global A6 <> 1
0x81, 0xb5, // lag global[b5]
- 0x30, SIG_UINT16(0x000d), // bnt [2nd code], in case global B5 == 0
+ 0x30, SIG_UINT16(0x000d), // bnt [PChase set code], in case global B5 == 0
0x38, SIG_UINT16(0x008c), // pushi 008c
0x78, // push1
0x72, SIG_UINT16(0x1cb6), // lofsa 1CB6 (moveToPath)
0x36, // push
0x54, 0x06, // self 06
0x32, SIG_UINT16(0x0038), // jmp [super-call]
+ // PChase set call
0x81, 0xb5, // lag global[B5]
0x18, // not
0x30, SIG_UINT16(0x0032), // bnt [super-call], in case global B5 <> 0
+ // followed by:
+ // is spider in current room
+ // is global A6h == 2? -> set PChase
SIG_END
}; // 58 bytes)
+// Global A6h <> 1 (did NOT went up the skeleton)
+// Global B5h = 0 -> set PChase
+// Global B5h <> 0 -> do not do anything
+// Global A6h = 1 (did went up the skeleton)
+// Global B5h = 0 -> set PChase
+// Global B5h <> 0 -> set moveToPath
+
static const uint16 sq1vgaPatchSpiderDroidTiming[] = {
0x63, 0x4e, // pToa script
0x2f, 0x68, // bt [super-call]
@@ -3639,8 +3830,8 @@ static const uint16 sq1vgaPatchSpiderDroidTiming[] = {
0x65, 0x4c, // aTop cycleSpeed
0x65, 0x5e, // aTop moveSpeed
// new code end
- 0x89, 0xb5, // lsg global[B5]
- 0x31, 0x13, // bnt [2nd code chunk]
+ 0x81, 0xb5, // lag global[B5]
+ 0x31, 0x13, // bnt [PChase code chunk]
0x89, 0xa6, // lsg global[A6]
0x35, 0x01, // ldi 01
0x1a, // eq?
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 0cb8ff48d7..073bb93983 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -514,6 +514,14 @@ const SciWorkaroundEntry kDisposeScript_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
+const SciWorkaroundEntry kDoSoundPlay_workarounds[] = {
+ { GID_LSL6HIRES, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ { GID_QFG4, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ { GID_PQ4, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kDoSoundFade_workarounds[] = {
{ GID_KQ5, 213, 989, 0, "globalSound3", "fade", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when bandits leave the secret temple, parameter 4 is an object - bug #5078
{ GID_KQ6, 105, 989, 0, "globalSound", "fade", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // floppy: during intro, parameter 4 is an object
@@ -745,6 +753,12 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = {
SCI_WORKAROUNDENTRY_TERMINATOR
};
+// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
+const SciWorkaroundEntry kScrollWindowAdd_workarounds[] = {
+ { GID_PHANTASMAGORIA, 45, 64907, 0, "ScrollableWindow", "addString", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // ScrollWindow interface passes the last two parameters twice
+};
+
+
SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin) {
// HACK for SCI3: Temporarily ignore this
if (getSciVersion() == SCI_VERSION_3) {
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index 8f519a8c9c..248d37fc6c 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -74,6 +74,7 @@ extern const SciWorkaroundEntry kDeviceInfo_workarounds[];
extern const SciWorkaroundEntry kDisplay_workarounds[];
extern const SciWorkaroundEntry kDirLoop_workarounds[];
extern const SciWorkaroundEntry kDisposeScript_workarounds[];
+extern const SciWorkaroundEntry kDoSoundPlay_workarounds[];
extern const SciWorkaroundEntry kDoSoundFade_workarounds[];
extern const SciWorkaroundEntry kFindKey_workarounds[];
extern const SciWorkaroundEntry kDeleteKey_workarounds[];
@@ -98,6 +99,7 @@ extern const SciWorkaroundEntry kStrAt_workarounds[];
extern const SciWorkaroundEntry kStrCpy_workarounds[];
extern const SciWorkaroundEntry kStrLen_workarounds[];
extern const SciWorkaroundEntry kUnLoad_workarounds[];
+extern const SciWorkaroundEntry kScrollWindowAdd_workarounds[];
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin);