diff options
Diffstat (limited to 'engines/sci/engine')
-rw-r--r-- | engines/sci/engine/kernel.cpp | 8 | ||||
-rw-r--r-- | engines/sci/engine/kernel.h | 12 | ||||
-rw-r--r-- | engines/sci/engine/kernel_tables.h | 876 | ||||
-rw-r--r-- | engines/sci/engine/kfile.cpp | 33 | ||||
-rw-r--r-- | engines/sci/engine/kgraphics.cpp | 264 | ||||
-rw-r--r-- | engines/sci/engine/kmisc.cpp | 39 | ||||
-rw-r--r-- | engines/sci/engine/kparse.cpp | 15 | ||||
-rw-r--r-- | engines/sci/engine/kpathing.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/kscripts.cpp | 1 | ||||
-rw-r--r-- | engines/sci/engine/kstring.cpp | 32 | ||||
-rw-r--r-- | engines/sci/engine/kvideo.cpp | 2 | ||||
-rw-r--r-- | engines/sci/engine/savegame.cpp | 112 | ||||
-rw-r--r-- | engines/sci/engine/savegame.h | 17 | ||||
-rw-r--r-- | engines/sci/engine/script.cpp | 7 | ||||
-rw-r--r-- | engines/sci/engine/script.h | 23 | ||||
-rw-r--r-- | engines/sci/engine/script_patches.cpp | 230 | ||||
-rw-r--r-- | engines/sci/engine/seg_manager.cpp | 20 | ||||
-rw-r--r-- | engines/sci/engine/segment.h | 2 | ||||
-rw-r--r-- | engines/sci/engine/state.h | 1 | ||||
-rw-r--r-- | engines/sci/engine/static_selectors.cpp | 32 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 17 | ||||
-rw-r--r-- | engines/sci/engine/workarounds.cpp | 14 |
22 files changed, 1052 insertions, 707 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index ff327a0049..b1ee6abaff 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -88,6 +88,14 @@ const Common::String &Kernel::getKernelName(uint number) const { return _kernelNames[number]; } +int Kernel::findKernelFuncPos(Common::String kernelFuncName) { + for (uint32 i = 0; i < _kernelNames.size(); i++) + if (_kernelNames[i] == kernelFuncName) + return i; + + return -1; +} + int Kernel::findSelector(const char *selectorName) const { for (uint pos = 0; pos < _selectorNames.size(); ++pos) { if (_selectorNames[pos] == selectorName) diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index dedc836b32..9833f91a5e 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -151,6 +151,7 @@ public: uint getSelectorNamesSize() const; const Common::String &getSelectorName(uint selector); + int findKernelFuncPos(Common::String kernelFuncName); uint getKernelNamesSize() const; const Common::String &getKernelName(uint number) const; @@ -278,7 +279,6 @@ private: /******************** Kernel functions ********************/ -// New kernel functions reg_t kStrLen(EngineState *s, int argc, reg_t *argv); reg_t kGetFarText(EngineState *s, int argc, reg_t *argv); reg_t kReadNumber(EngineState *s, int argc, reg_t *argv); @@ -420,6 +420,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 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); @@ -444,13 +445,14 @@ reg_t kAddPlane(EngineState *s, int argc, reg_t *argv); reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv); reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv); reg_t kRepaintPlane(EngineState *s, int argc, reg_t *argv); +reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv); reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv); reg_t kFrameOut(EngineState *s, int argc, reg_t *argv); +reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv); // kOnMe for SCI2, kIsOnMe for SCI2.1 reg_t kListIndexOf(EngineState *s, int argc, reg_t *argv); reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv); reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv); reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv); -reg_t kOnMe(EngineState *s, int argc, reg_t *argv); reg_t kInPolygon(EngineState *s, int argc, reg_t *argv); // SCI2.1 Kernel Functions @@ -459,13 +461,15 @@ reg_t kSave(EngineState *s, int argc, reg_t *argv); reg_t kList(EngineState *s, int argc, reg_t *argv); reg_t kRobot(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv); -reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv); reg_t kCD(EngineState *s, int argc, reg_t *argv); reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv); - reg_t kAddBefore(EngineState *s, int argc, reg_t *argv); 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 kWinDLL(EngineState *s, int argc, reg_t *argv); +reg_t kPrintDebug(EngineState *s, int argc, reg_t *argv); #endif reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 29e2a38ad4..724ceee878 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -27,6 +27,7 @@ #define SCI_ENGINE_KERNEL_TABLES_H #include "sci/engine/workarounds.h" +#include "sci/engine/vm.h" // for opcode_formats namespace Sci { @@ -81,201 +82,197 @@ struct SciKernelMapSubEntry { #define SIG_EVERYWHERE SIG_SCIALL, SIGFOR_ALL #define MAP_CALL(_name_) #_name_, k##_name_ +#define MAP_EMPTY(_name_) #_name_, kEmpty +#define MAP_DUMMY(_name_) #_name_, kDummy // version, subId, function-mapping, signature, workarounds 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, 3, MAP_CALL(DoSoundDispose), "o", NULL }, - { SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL }, - { SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL }, - { SIG_SOUNDSCI0, 6, MAP_CALL(DoSoundPause), "i", NULL }, - { SIG_SOUNDSCI0, 7, MAP_CALL(DoSoundResumeAfterRestore), "", NULL }, - { SIG_SOUNDSCI0, 8, MAP_CALL(DoSoundMasterVolume), "(i)", NULL }, - { SIG_SOUNDSCI0, 9, MAP_CALL(DoSoundUpdate), "o", NULL }, - { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "o", kDoSoundFade_workarounds }, - { SIG_SOUNDSCI0, 11, MAP_CALL(DoSoundGetPolyphony), "", NULL }, - { 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, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL }, - { SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL }, - { SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL }, - { SIG_SOUNDSCI1EARLY, 6, MAP_CALL(DoSoundDispose), NULL, NULL }, - { SIG_SOUNDSCI1EARLY, 7, MAP_CALL(DoSoundPlay), "oi", NULL }, - // ^^ TODO: In SCI1-SCI1.1 DoSound (play) is called by 2 methods of the Sound object: play and - // playBed. The methods are the same, apart from the second integer parameter: it's 0 in - // play and 1 in playBed, to distinguish the caller. It's passed on, we should find out what - // it actually does internally - { SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL }, - { SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL }, - { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds }, - { SIG_SOUNDSCI1EARLY, 11, MAP_CALL(DoSoundUpdateCues), "o", NULL }, - { SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL }, - { SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundReverb), "i", NULL }, - { SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL }, - { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(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, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL }, - { SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL }, - { SIG_SOUNDSCI1LATE, 6, MAP_CALL(DoSoundInit), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 7, MAP_CALL(DoSoundDispose), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 8, MAP_CALL(DoSoundPlay), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 9, MAP_CALL(DoSoundStop), NULL, NULL }, - { 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, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL }, - { SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL }, - { SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL }, - { SIG_SOUNDSCI1LATE, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 18, MAP_CALL(DoSoundSendMidi), "oiii(i)", NULL }, - { SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundReverb), NULL, NULL }, - { SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL }, + { 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, 3, MAP_CALL(DoSoundDispose), "o", NULL }, + { SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL }, + { SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL }, + { SIG_SOUNDSCI0, 6, MAP_CALL(DoSoundPause), "i", NULL }, + { SIG_SOUNDSCI0, 7, MAP_CALL(DoSoundResumeAfterRestore), "", NULL }, + { SIG_SOUNDSCI0, 8, MAP_CALL(DoSoundMasterVolume), "(i)", NULL }, + { SIG_SOUNDSCI0, 9, MAP_CALL(DoSoundUpdate), "o", NULL }, + { SIG_SOUNDSCI0, 10, MAP_CALL(DoSoundFade), "o", kDoSoundFade_workarounds }, + { SIG_SOUNDSCI0, 11, MAP_CALL(DoSoundGetPolyphony), "", NULL }, + { 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, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL }, + { SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL }, + { SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL }, + { SIG_SOUNDSCI1EARLY, 6, MAP_CALL(DoSoundDispose), NULL, NULL }, + { SIG_SOUNDSCI1EARLY, 7, MAP_CALL(DoSoundPlay), "oi", NULL }, + // ^^ TODO: In SCI1-SCI1.1 DoSound (play) is called by 2 methods of the Sound object: play and + // playBed. The methods are the same, apart from the second integer parameter: it's 0 in + // play and 1 in playBed, to distinguish the caller. It's passed on, we should find out what + // it actually does internally + { SIG_SOUNDSCI1EARLY, 8, MAP_CALL(DoSoundStop), NULL, NULL }, + { SIG_SOUNDSCI1EARLY, 9, MAP_CALL(DoSoundPause), "[o0]i", NULL }, + { SIG_SOUNDSCI1EARLY, 10, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds }, + { SIG_SOUNDSCI1EARLY, 11, MAP_CALL(DoSoundUpdateCues), "o", NULL }, + { SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL }, + { SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundReverb), "i", NULL }, + { SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL }, + { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(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, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL }, + { SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL }, + { SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL }, + { SIG_SOUNDSCI1LATE, 6, MAP_CALL(DoSoundInit), NULL, NULL }, + { SIG_SOUNDSCI1LATE, 7, MAP_CALL(DoSoundDispose), NULL, NULL }, + { SIG_SOUNDSCI1LATE, 8, MAP_CALL(DoSoundPlay), NULL, NULL }, + { SIG_SOUNDSCI1LATE, 9, MAP_CALL(DoSoundStop), NULL, NULL }, + { 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, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL }, + { SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL }, + { SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL }, + { SIG_SOUNDSCI1LATE, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL }, + { SIG_SOUNDSCI1LATE, 18, MAP_CALL(DoSoundSendMidi), "oiii(i)", NULL }, + { SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundReverb), 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 }, - // ^^ 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, NULL }, - { 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(DoSoundReverb), NULL, NULL }, - { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL }, + { 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 }, + // ^^ 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, NULL }, + { 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(DoSoundReverb), NULL, NULL }, + { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL }, #endif - SCI_SUBOPENTRY_TERMINATOR + SCI_SUBOPENTRY_TERMINATOR }; // 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 - { SIG_SCIALL, 2, MAP_CALL(GraphGetColorCount), "", NULL }, - // 3 - set palette via resource - { SIG_SCIALL, 4, MAP_CALL(GraphDrawLine), "iiiii(i)(i)", kGraphDrawLine_workarounds }, - // 5 - nop - // 6 - draw pattern - { SIG_SCIALL, 7, MAP_CALL(GraphSaveBox), "iiiii", kGraphSaveBox_workarounds }, - { SIG_SCIALL, 8, MAP_CALL(GraphRestoreBox), "[r0!]", kGraphRestoreBox_workarounds }, - // ^ this may get called with invalid references, we check them within restoreBits() and sierra sci behaves the same - { SIG_SCIALL, 9, MAP_CALL(GraphFillBoxBackground), "iiii", NULL }, - { SIG_SCIALL, 10, MAP_CALL(GraphFillBoxForeground), "iiii", kGraphFillBoxForeground_workarounds }, - { SIG_SCIALL, 11, MAP_CALL(GraphFillBoxAny), "iiiiii(i)(i)", kGraphFillBoxAny_workarounds }, - { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", kGraphUpdateBox_workarounds }, // kq6 hires - { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", kGraphUpdateBox_workarounds }, - { SIG_SCIALL, 13, MAP_CALL(GraphRedrawBox), "iiii", kGraphRedrawBox_workarounds }, - { SIG_SCIALL, 14, MAP_CALL(GraphAdjustPriority), "ii", NULL }, - { SIG_SCI11, 15, MAP_CALL(GraphSaveUpscaledHiresBox), "iiii", NULL }, // kq6 hires - SCI_SUBOPENTRY_TERMINATOR + { SIG_SCI32, 1, MAP_CALL(StubNull), "", NULL }, // called by gk1 sci32 right at the start + { SIG_SCIALL, 2, MAP_CALL(GraphGetColorCount), "", NULL }, + // 3 - set palette via resource + { SIG_SCIALL, 4, MAP_CALL(GraphDrawLine), "iiiii(i)(i)", kGraphDrawLine_workarounds }, + // 5 - nop + // 6 - draw pattern + { SIG_SCIALL, 7, MAP_CALL(GraphSaveBox), "iiiii", kGraphSaveBox_workarounds }, + { SIG_SCIALL, 8, MAP_CALL(GraphRestoreBox), "[r0!]", kGraphRestoreBox_workarounds }, + // ^ this may get called with invalid references, we check them within restoreBits() and sierra sci behaves the same + { SIG_SCIALL, 9, MAP_CALL(GraphFillBoxBackground), "iiii", NULL }, + { SIG_SCIALL, 10, MAP_CALL(GraphFillBoxForeground), "iiii", kGraphFillBoxForeground_workarounds }, + { SIG_SCIALL, 11, MAP_CALL(GraphFillBoxAny), "iiiiii(i)(i)", kGraphFillBoxAny_workarounds }, + { SIG_SCI11, 12, MAP_CALL(GraphUpdateBox), "iiii(i)(r0)", kGraphUpdateBox_workarounds }, // kq6 hires + { SIG_SCIALL, 12, MAP_CALL(GraphUpdateBox), "iiii(i)", kGraphUpdateBox_workarounds }, + { SIG_SCIALL, 13, MAP_CALL(GraphRedrawBox), "iiii", kGraphRedrawBox_workarounds }, + { SIG_SCIALL, 14, MAP_CALL(GraphAdjustPriority), "ii", NULL }, + { SIG_SCI11, 15, MAP_CALL(GraphSaveUpscaledHiresBox), "iiii", NULL }, // kq6 hires + SCI_SUBOPENTRY_TERMINATOR }; // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kPalVary_subops[] = { - { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL }, - { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL }, - { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL }, - { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL }, - { SIG_SCIALL, 3, MAP_CALL(PalVaryDeinit), "", NULL }, - { SIG_SCIALL, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL }, - { SIG_SCIALL, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL }, - { SIG_SCIALL, 6, MAP_CALL(PalVaryPauseResume), "i", NULL }, - { SIG_SCI32, 8, MAP_CALL(PalVaryUnknown), "i", NULL }, - SCI_SUBOPENTRY_TERMINATOR + { SIG_SCI21, 0, MAP_CALL(PalVaryInit), "ii(i)(i)(i)", NULL }, + { SIG_SCIALL, 0, MAP_CALL(PalVaryInit), "ii(i)(i)", NULL }, + { SIG_SCIALL, 1, MAP_CALL(PalVaryReverse), "(i)(i)(i)", NULL }, + { SIG_SCIALL, 2, MAP_CALL(PalVaryGetCurrentStep), "", NULL }, + { SIG_SCIALL, 3, MAP_CALL(PalVaryDeinit), "", NULL }, + { SIG_SCIALL, 4, MAP_CALL(PalVaryChangeTarget), "i", NULL }, + { SIG_SCIALL, 5, MAP_CALL(PalVaryChangeTicks), "i", NULL }, + { SIG_SCIALL, 6, MAP_CALL(PalVaryPauseResume), "i", NULL }, + { SIG_SCI32, 8, MAP_CALL(PalVaryUnknown), "i", NULL }, + SCI_SUBOPENTRY_TERMINATOR }; // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kPalette_subops[] = { - { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL }, - { SIG_SCIALL, 2, MAP_CALL(PaletteSetFlag), "iii", NULL }, - { SIG_SCIALL, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds }, - { SIG_SCIALL, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL }, - { SIG_SCIALL, 5, MAP_CALL(PaletteFindColor), "iii", NULL }, - { SIG_SCIALL, 6, MAP_CALL(PaletteAnimate), "i*", NULL }, - { SIG_SCIALL, 7, MAP_CALL(PaletteSave), "", NULL }, - { SIG_SCIALL, 8, MAP_CALL(PaletteRestore), "[r0]", NULL }, - SCI_SUBOPENTRY_TERMINATOR + { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL }, + { SIG_SCIALL, 2, MAP_CALL(PaletteSetFlag), "iii", NULL }, + { SIG_SCIALL, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds }, + { SIG_SCIALL, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL }, + { SIG_SCIALL, 5, MAP_CALL(PaletteFindColor), "iii", NULL }, + { SIG_SCIALL, 6, MAP_CALL(PaletteAnimate), "i*", NULL }, + { SIG_SCIALL, 7, MAP_CALL(PaletteSave), "", NULL }, + { SIG_SCIALL, 8, MAP_CALL(PaletteRestore), "[r0]", NULL }, + SCI_SUBOPENTRY_TERMINATOR }; static const SciKernelMapSubEntry kFileIO_subops[] = { - { SIG_SCI32, 0, MAP_CALL(FileIOOpen), "r(i)", NULL }, - { SIG_SCIALL, 0, MAP_CALL(FileIOOpen), "ri", NULL }, - { SIG_SCIALL, 1, MAP_CALL(FileIOClose), "i", NULL }, - { SIG_SCIALL, 2, MAP_CALL(FileIOReadRaw), "iri", NULL }, - { SIG_SCIALL, 3, MAP_CALL(FileIOWriteRaw), "iri", NULL }, - { SIG_SCIALL, 4, MAP_CALL(FileIOUnlink), "r", NULL }, - { SIG_SCIALL, 5, MAP_CALL(FileIOReadString), "rii", NULL }, - { SIG_SCIALL, 6, MAP_CALL(FileIOWriteString), "ir", NULL }, - { SIG_SCIALL, 7, MAP_CALL(FileIOSeek), "iii", NULL }, - { SIG_SCIALL, 8, MAP_CALL(FileIOFindFirst), "rri", NULL }, - { SIG_SCIALL, 9, MAP_CALL(FileIOFindNext), "r", NULL }, - { SIG_SCIALL, 10, MAP_CALL(FileIOExists), "r", NULL }, - { SIG_SINCE_SCI11, 11, MAP_CALL(FileIORename), "rr", NULL }, + { SIG_SCI32, 0, MAP_CALL(FileIOOpen), "r(i)", NULL }, + { SIG_SCIALL, 0, MAP_CALL(FileIOOpen), "ri", NULL }, + { SIG_SCIALL, 1, MAP_CALL(FileIOClose), "i", NULL }, + { SIG_SCIALL, 2, MAP_CALL(FileIOReadRaw), "iri", NULL }, + { SIG_SCIALL, 3, MAP_CALL(FileIOWriteRaw), "iri", NULL }, + { SIG_SCIALL, 4, MAP_CALL(FileIOUnlink), "r", NULL }, + { SIG_SCIALL, 5, MAP_CALL(FileIOReadString), "rii", NULL }, + { SIG_SCIALL, 6, MAP_CALL(FileIOWriteString), "ir", NULL }, + { SIG_SCIALL, 7, MAP_CALL(FileIOSeek), "iii", NULL }, + { SIG_SCIALL, 8, MAP_CALL(FileIOFindFirst), "rri", NULL }, + { SIG_SCIALL, 9, MAP_CALL(FileIOFindNext), "r", NULL }, + { SIG_SCIALL, 10, MAP_CALL(FileIOExists), "r", NULL }, + { SIG_SINCE_SCI11, 11, MAP_CALL(FileIORename), "rr", NULL }, #ifdef ENABLE_SCI32 - { SIG_SCI32, 13, MAP_CALL(FileIOReadByte), "i", NULL }, - { SIG_SCI32, 14, MAP_CALL(FileIOWriteByte), "ii", NULL }, - { SIG_SCI32, 15, MAP_CALL(FileIOReadWord), "i", NULL }, - { SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL }, - { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo + { SIG_SCI32, 13, MAP_CALL(FileIOReadByte), "i", NULL }, + { SIG_SCI32, 14, MAP_CALL(FileIOWriteByte), "ii", NULL }, + { SIG_SCI32, 15, MAP_CALL(FileIOReadWord), "i", NULL }, + { SIG_SCI32, 16, MAP_CALL(FileIOWriteWord), "ii", NULL }, + { SIG_SCI32, 19, MAP_CALL(Stub), "r", NULL }, // for Torin / Torin demo #endif - SCI_SUBOPENTRY_TERMINATOR + SCI_SUBOPENTRY_TERMINATOR }; #ifdef ENABLE_SCI32 // version, subId, function-mapping, signature, workarounds static const SciKernelMapSubEntry kList_subops[] = { - { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL }, - { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL }, - { SIG_SCI21, 2, MAP_CALL(NewNode), ".", NULL }, - { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL }, - { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL }, - { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL }, - { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL }, - { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL }, - { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL }, - { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL }, - { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL }, - { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln.", NULL }, - { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL }, - { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL }, - { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL }, - { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL }, - { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL }, - { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL }, - // FIXME: This doesn't seem to be ListIndexOf. In Torin demo, an index is - // passed as a second parameter instead of an object. Thus, it seems to - // be something like ListAt instead... If we swap the two subops though, - // Torin demo crashes complaining that it tried to send to a non-object, - // therefore the semantics might be different here (signature was l[o0]) - // In SQ6 object is passed right when skipping the intro - { SIG_SCI21, 18, MAP_CALL(StubNull), "l[io]", NULL }, - { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL }, - { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL }, - { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL }, - { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL }, - SCI_SUBOPENTRY_TERMINATOR + { SIG_SCI21, 0, MAP_CALL(NewList), "", NULL }, + { SIG_SCI21, 1, MAP_CALL(DisposeList), "l", NULL }, + { SIG_SCI21, 2, MAP_CALL(NewNode), ".(.)", NULL }, + { SIG_SCI21, 3, MAP_CALL(FirstNode), "[l0]", NULL }, + { SIG_SCI21, 4, MAP_CALL(LastNode), "l", NULL }, + { SIG_SCI21, 5, MAP_CALL(EmptyList), "l", NULL }, + { SIG_SCI21, 6, MAP_CALL(NextNode), "n", NULL }, + { SIG_SCI21, 7, MAP_CALL(PrevNode), "n", NULL }, + { SIG_SCI21, 8, MAP_CALL(NodeValue), "[n0]", NULL }, + { SIG_SCI21, 9, MAP_CALL(AddAfter), "lnn.", NULL }, + { SIG_SCI21, 10, MAP_CALL(AddToFront), "ln.", NULL }, + { SIG_SCI21, 11, MAP_CALL(AddToEnd), "ln(.)", NULL }, + { SIG_SCI21, 12, MAP_CALL(AddBefore), "ln.", NULL }, + { SIG_SCI21, 13, MAP_CALL(MoveToFront), "ln", NULL }, + { SIG_SCI21, 14, MAP_CALL(MoveToEnd), "ln", NULL }, + { SIG_SCI21, 15, MAP_CALL(FindKey), "l.", NULL }, + { SIG_SCI21, 16, MAP_CALL(DeleteKey), "l.", NULL }, + { SIG_SCI21, 17, MAP_CALL(ListAt), "li", NULL }, + { SIG_SCI21, 18, MAP_CALL(ListIndexOf) , "l[io]", NULL }, + { SIG_SCI21, 19, MAP_CALL(ListEachElementDo), "li(.*)", NULL }, + { SIG_SCI21, 20, MAP_CALL(ListFirstTrue), "li(.*)", NULL }, + { SIG_SCI21, 21, MAP_CALL(ListAllTrue), "li(.*)", NULL }, + { SIG_SCI21, 22, MAP_CALL(Sort), "ooo", NULL }, + SCI_SUBOPENTRY_TERMINATOR }; #endif @@ -294,202 +291,299 @@ struct SciKernelMapEntry { // name, version/platform, signature, sub-signatures, workarounds static SciKernelMapEntry s_kernelMap[] = { - { MAP_CALL(Abs), SIG_EVERYWHERE, "i", NULL, kAbs_workarounds }, - { MAP_CALL(AddAfter), SIG_EVERYWHERE, "lnn", NULL, NULL }, - { MAP_CALL(AddMenu), SIG_EVERYWHERE, "rr", NULL, NULL }, - { MAP_CALL(AddToEnd), SIG_EVERYWHERE, "ln", NULL, NULL }, - { MAP_CALL(AddToFront), SIG_EVERYWHERE, "ln", NULL, NULL }, - { MAP_CALL(AddToPic), SIG_EVERYWHERE, "[il](iiiiii)", NULL, NULL }, - { MAP_CALL(Animate), SIG_EVERYWHERE, "(l0)(i)", NULL, NULL }, - { MAP_CALL(AssertPalette), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL }, - { MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, + { MAP_CALL(Abs), SIG_EVERYWHERE, "i", NULL, kAbs_workarounds }, + { MAP_CALL(AddAfter), SIG_EVERYWHERE, "lnn", NULL, NULL }, + { MAP_CALL(AddMenu), SIG_EVERYWHERE, "rr", NULL, NULL }, + { MAP_CALL(AddToEnd), SIG_EVERYWHERE, "ln", NULL, NULL }, + { MAP_CALL(AddToFront), SIG_EVERYWHERE, "ln", NULL, NULL }, + { MAP_CALL(AddToPic), SIG_EVERYWHERE, "[il](iiiiii)", NULL, NULL }, + { MAP_CALL(Animate), SIG_EVERYWHERE, "(l0)(i)", NULL, NULL }, + { MAP_CALL(AssertPalette), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL }, + { MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, #ifdef ENABLE_SCI32 - { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL }, + { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL }, #endif - { MAP_CALL(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, - { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds }, - { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds }, - { MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL }, - { MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL }, - { MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(CheckSaveGame), SIG_EVERYWHERE, ".*", NULL, NULL }, - { MAP_CALL(Clone), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(CoordPri), SIG_EVERYWHERE, "i(i)", NULL, NULL }, - { MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL }, - { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop - { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, kDisplay_workarounds }, - // ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro - // restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same - { MAP_CALL(DirLoop), SIG_EVERYWHERE, "oi", NULL, kDirLoop_workarounds }, - { MAP_CALL(DisposeClone), SIG_EVERYWHERE, "o", NULL, NULL }, - { 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(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL }, - { MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL }, - { MAP_CALL(DoSync), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop - { MAP_CALL(DrawCel), SIG_SCI11, SIGFOR_PC, "iiiii(i)(i)([ri])", NULL, NULL }, // reference for kq6 hires - { MAP_CALL(DrawCel), SIG_EVERYWHERE, "iiiii(i)(i)", NULL, NULL }, - { MAP_CALL(DrawControl), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(DrawMenuBar), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(DrawPic), SIG_EVERYWHERE, "i(i)(i)(i)", NULL, NULL }, - { MAP_CALL(DrawStatus), SIG_EVERYWHERE, "[r0](i)(i)", NULL, NULL }, - { MAP_CALL(EditControl), SIG_EVERYWHERE, "[o0][o0]", NULL, NULL }, - { MAP_CALL(Empty), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(EmptyList), SIG_EVERYWHERE, "l", NULL, NULL }, - { MAP_CALL(FClose), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(FGets), SIG_EVERYWHERE, "rii", NULL, NULL }, - { MAP_CALL(FOpen), SIG_EVERYWHERE, "ri", NULL, NULL }, - { MAP_CALL(FPuts), SIG_EVERYWHERE, "ir", NULL, NULL }, - { MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", kFileIO_subops, NULL }, - { MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds }, - { MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL }, - { MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(Format), SIG_EVERYWHERE, "r(.*)", NULL, NULL }, - { MAP_CALL(GameIsRestarting), SIG_EVERYWHERE, "(i)", NULL, NULL }, - { MAP_CALL(GetAngle), SIG_EVERYWHERE, "iiii", NULL, kGetAngle_workarounds }, - { MAP_CALL(GetCWD), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(GetDistance), SIG_EVERYWHERE, "ii(i)(i)(i)(i)", NULL, NULL }, - { MAP_CALL(GetEvent), SIG_SCIALL, SIGFOR_MAC, "io(i*)", NULL, NULL }, - { MAP_CALL(GetEvent), SIG_EVERYWHERE, "io", NULL, NULL }, - { MAP_CALL(GetFarText), SIG_EVERYWHERE, "ii[r0]", NULL, NULL }, - { MAP_CALL(GetMenu), SIG_EVERYWHERE, "i.", NULL, NULL }, - { MAP_CALL(GetMessage), SIG_EVERYWHERE, "iiir", NULL, NULL }, - { MAP_CALL(GetPort), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(GetSaveDir), SIG_SCI32, SIGFOR_ALL, "(r*)", NULL, NULL }, - { MAP_CALL(GetSaveDir), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL }, - { MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL }, - { MAP_CALL(GlobalToLocal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL }, - { MAP_CALL(GlobalToLocal), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(Graph), SIG_EVERYWHERE, NULL, kGraph_subops, NULL }, - { MAP_CALL(HaveMouse), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(HiliteControl), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(InitBresen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, - { MAP_CALL(Intersections), SIG_EVERYWHERE, "iiiiriiiri", NULL, NULL }, - { MAP_CALL(IsItSkip), SIG_EVERYWHERE, "iiiii", NULL, NULL }, - { MAP_CALL(IsObject), SIG_EVERYWHERE, ".", NULL, kIsObject_workarounds }, - { MAP_CALL(Joystick), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop - { MAP_CALL(LastNode), SIG_EVERYWHERE, "l", NULL, NULL }, - { MAP_CALL(Load), SIG_EVERYWHERE, "ii(i*)", NULL, NULL }, - { MAP_CALL(LocalToGlobal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL }, - { MAP_CALL(LocalToGlobal), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(Lock), SIG_EVERYWHERE, "ii(i)", NULL, NULL }, - { MAP_CALL(MapKeyToDir), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(Memory), SIG_EVERYWHERE, "i(.*)", NULL, kMemory_workarounds }, // subop - { MAP_CALL(MemoryInfo), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(MemorySegment), SIG_EVERYWHERE, "ir(i)", NULL, NULL }, // subop - { MAP_CALL(MenuSelect), SIG_EVERYWHERE, "o(i)", NULL, NULL }, - { MAP_CALL(MergePoly), SIG_EVERYWHERE, "rli", NULL, NULL }, - { MAP_CALL(Message), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop - { MAP_CALL(MoveCursor), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(NewList), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(NewNode), SIG_EVERYWHERE, "..", NULL, NULL }, - { MAP_CALL(NewWindow), SIG_SCIALL, SIGFOR_MAC, ".*", NULL, NULL }, - { MAP_CALL(NewWindow), SIG_SCI0, SIGFOR_ALL, "iiii[r0]i(i)(i)(i)", NULL, NULL }, - { MAP_CALL(NewWindow), SIG_SCI1, SIGFOR_ALL, "iiii[ir]i(i)(i)([ir])(i)(i)(i)(i)", NULL, NULL }, - { MAP_CALL(NewWindow), SIG_SCI11, SIGFOR_ALL, "iiiiiiii[r0]i(i)(i)(i)", NULL, kNewWindow_workarounds }, - { MAP_CALL(NextNode), SIG_EVERYWHERE, "n", NULL, NULL }, - { MAP_CALL(NodeValue), SIG_EVERYWHERE, "[n0]", NULL, NULL }, - { MAP_CALL(NumCels), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(NumLoops), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(OnControl), SIG_EVERYWHERE, "ii(i)(i)(i)", NULL, NULL }, - { MAP_CALL(PalVary), SIG_EVERYWHERE, "i(i*)", kPalVary_subops, NULL }, - { MAP_CALL(Palette), SIG_EVERYWHERE, "i(.*)", kPalette_subops, NULL }, - { MAP_CALL(Parse), SIG_EVERYWHERE, "ro", NULL, NULL }, - { MAP_CALL(PicNotValid), SIG_EVERYWHERE, "(i)", NULL, NULL }, - { MAP_CALL(Platform), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(Portrait), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop - { MAP_CALL(PrevNode), SIG_EVERYWHERE, "n", NULL, NULL }, - { 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, NULL }, - { MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL }, - { MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL }, - { MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(RestoreGame), SIG_EVERYWHERE, "[r0]i[r0]", NULL, NULL }, - { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL }, - { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r)", NULL, NULL }, - { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL }, - { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL }, - // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why - { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL }, - { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds }, - { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL }, - { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL }, - { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, - { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, - { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds }, - { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL }, - { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL }, + { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds }, + { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds }, + { MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL }, + { MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL }, + { MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL }, + { MAP_CALL(CheckSaveGame), SIG_EVERYWHERE, ".*", NULL, NULL }, + { MAP_CALL(Clone), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(CoordPri), SIG_EVERYWHERE, "i(i)", NULL, NULL }, + { MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL }, + { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop + { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, kDisplay_workarounds }, + // ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro + // restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same + { MAP_CALL(DirLoop), SIG_EVERYWHERE, "oi", NULL, kDirLoop_workarounds }, + { MAP_CALL(DisposeClone), SIG_EVERYWHERE, "o", NULL, NULL }, + { 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(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL }, + { MAP_CALL(DoSync), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop + { MAP_CALL(DrawCel), SIG_SCI11, SIGFOR_PC, "iiiii(i)(i)([ri])", NULL, NULL }, // reference for kq6 hires + { MAP_CALL(DrawCel), SIG_EVERYWHERE, "iiiii(i)(i)", NULL, NULL }, + { MAP_CALL(DrawControl), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(DrawMenuBar), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(DrawPic), SIG_EVERYWHERE, "i(i)(i)(i)", NULL, NULL }, + { MAP_CALL(DrawStatus), SIG_EVERYWHERE, "[r0](i)(i)", NULL, NULL }, + { MAP_CALL(EditControl), SIG_EVERYWHERE, "[o0][o0]", NULL, NULL }, + { MAP_CALL(Empty), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(EmptyList), SIG_EVERYWHERE, "l", NULL, NULL }, + { MAP_CALL(FClose), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(FGets), SIG_EVERYWHERE, "rii", NULL, NULL }, + { MAP_CALL(FOpen), SIG_EVERYWHERE, "ri", NULL, NULL }, + { MAP_CALL(FPuts), SIG_EVERYWHERE, "ir", NULL, NULL }, + { MAP_CALL(FileIO), SIG_EVERYWHERE, "i(.*)", kFileIO_subops, NULL }, + { MAP_CALL(FindKey), SIG_EVERYWHERE, "l.", NULL, kFindKey_workarounds }, + { MAP_CALL(FirstNode), SIG_EVERYWHERE, "[l0]", NULL, NULL }, + { MAP_CALL(FlushResources), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(Format), SIG_EVERYWHERE, "r(.*)", NULL, NULL }, + { MAP_CALL(GameIsRestarting), SIG_EVERYWHERE, "(i)", NULL, NULL }, + { MAP_CALL(GetAngle), SIG_EVERYWHERE, "iiii", NULL, kGetAngle_workarounds }, + { MAP_CALL(GetCWD), SIG_EVERYWHERE, "r", NULL, NULL }, + { MAP_CALL(GetDistance), SIG_EVERYWHERE, "ii(i)(i)(i)(i)", NULL, NULL }, + { MAP_CALL(GetEvent), SIG_SCIALL, SIGFOR_MAC, "io(i*)", NULL, NULL }, + { MAP_CALL(GetEvent), SIG_EVERYWHERE, "io", NULL, NULL }, + { MAP_CALL(GetFarText), SIG_EVERYWHERE, "ii[r0]", NULL, NULL }, + { MAP_CALL(GetMenu), SIG_EVERYWHERE, "i.", NULL, NULL }, + { MAP_CALL(GetMessage), SIG_EVERYWHERE, "iiir", NULL, NULL }, + { MAP_CALL(GetPort), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(GetSaveDir), SIG_SCI32, SIGFOR_ALL, "(r*)", NULL, NULL }, + { MAP_CALL(GetSaveDir), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL }, + { MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL }, + { MAP_CALL(GlobalToLocal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL }, + { MAP_CALL(GlobalToLocal), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(Graph), SIG_EVERYWHERE, NULL, kGraph_subops, NULL }, + { MAP_CALL(HaveMouse), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(HiliteControl), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(InitBresen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(Intersections), SIG_EVERYWHERE, "iiiiriiiri", NULL, NULL }, + { MAP_CALL(IsItSkip), SIG_EVERYWHERE, "iiiii", NULL, NULL }, + { MAP_CALL(IsObject), SIG_EVERYWHERE, ".", NULL, kIsObject_workarounds }, + { MAP_CALL(Joystick), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop + { MAP_CALL(LastNode), SIG_EVERYWHERE, "l", NULL, NULL }, + { MAP_CALL(Load), SIG_EVERYWHERE, "ii(i*)", NULL, NULL }, + { MAP_CALL(LocalToGlobal), SIG_SCI32, SIGFOR_ALL, "oo", NULL, NULL }, + { MAP_CALL(LocalToGlobal), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(Lock), SIG_EVERYWHERE, "ii(i)", NULL, NULL }, + { MAP_CALL(MapKeyToDir), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(Memory), SIG_EVERYWHERE, "i(.*)", NULL, kMemory_workarounds }, // subop + { MAP_CALL(MemoryInfo), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(MemorySegment), SIG_EVERYWHERE, "ir(i)", NULL, NULL }, // subop + { MAP_CALL(MenuSelect), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(MergePoly), SIG_EVERYWHERE, "rli", NULL, NULL }, + { MAP_CALL(Message), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop + { MAP_CALL(MoveCursor), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(NewList), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(NewNode), SIG_EVERYWHERE, "..", NULL, NULL }, + { MAP_CALL(NewWindow), SIG_SCIALL, SIGFOR_MAC, ".*", NULL, NULL }, + { MAP_CALL(NewWindow), SIG_SCI0, SIGFOR_ALL, "iiii[r0]i(i)(i)(i)", NULL, NULL }, + { MAP_CALL(NewWindow), SIG_SCI1, SIGFOR_ALL, "iiii[ir]i(i)(i)([ir])(i)(i)(i)(i)", NULL, NULL }, + { MAP_CALL(NewWindow), SIG_SCI11, SIGFOR_ALL, "iiiiiiii[r0]i(i)(i)(i)", NULL, kNewWindow_workarounds }, + { MAP_CALL(NextNode), SIG_EVERYWHERE, "n", NULL, NULL }, + { MAP_CALL(NodeValue), SIG_EVERYWHERE, "[n0]", NULL, NULL }, + { MAP_CALL(NumCels), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(NumLoops), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(OnControl), SIG_EVERYWHERE, "ii(i)(i)(i)", NULL, NULL }, + { MAP_CALL(PalVary), SIG_EVERYWHERE, "i(i*)", kPalVary_subops, NULL }, + { MAP_CALL(Palette), SIG_EVERYWHERE, "i(.*)", kPalette_subops, NULL }, + { MAP_CALL(Parse), SIG_EVERYWHERE, "ro", NULL, NULL }, + { MAP_CALL(PicNotValid), SIG_EVERYWHERE, "(i)", NULL, NULL }, + { MAP_CALL(Platform), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Portrait), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop + { MAP_CALL(PrevNode), SIG_EVERYWHERE, "n", NULL, NULL }, + { 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, NULL }, + { MAP_CALL(RemapColors), SIG_EVERYWHERE, "i(i)(i)(i)(i)(i)", NULL, NULL }, + { MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL }, + { MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL }, + { MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(RestoreGame), SIG_EVERYWHERE, "[r0]i[r0]", NULL, NULL }, + { MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL }, + { MAP_CALL(SaveGame), SIG_EVERYWHERE, "[r0]i[r0](r)", NULL, NULL }, + { MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL }, + { MAP_CALL(SetCursor), SIG_SCI21, SIGFOR_ALL, "i(i)([io])(i*)", NULL, NULL }, + // TODO: SCI2.1 may supply an object optionally (mother goose sci21 right on startup) - find out why + { MAP_CALL(SetCursor), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(iiiiii)", NULL, NULL }, + { MAP_CALL(SetCursor), SIG_EVERYWHERE, "i(i)(i)(i)(i)", NULL, kSetCursor_workarounds }, + { MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL }, + { MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL }, + { MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, + { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL }, + { MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds }, + { MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL }, + { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL }, + { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Show), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL }, - { MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL }, - { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds }, - { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, kStrCat_workarounds }, - { MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL }, - { MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL }, - { MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, NULL }, - { MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL }, - { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL }, - { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL }, - { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL }, - { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL }, - { MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL }, - { "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL }, - { "SinMult", kTimesSin, SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(TimesTan), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ri]", NULL, kUnLoad_workarounds }, - { MAP_CALL(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL }, - { MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL }, + { MAP_CALL(Sqrt), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(StrAt), SIG_EVERYWHERE, "ri(i)", NULL, kStrAt_workarounds }, + { MAP_CALL(StrCat), SIG_EVERYWHERE, "rr", NULL, kStrCat_workarounds }, + { MAP_CALL(StrCmp), SIG_EVERYWHERE, "rr(i)", NULL, NULL }, + { MAP_CALL(StrCpy), SIG_EVERYWHERE, "r[r0](i)", NULL, NULL }, + { MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL }, + { MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, NULL }, + { MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL }, + { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL }, + { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL }, + { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL }, + { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL }, + { MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL }, + { "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL }, + { "SinMult", kTimesSin, SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(TimesTan), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ri]", NULL, kUnLoad_workarounds }, + { MAP_CALL(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL }, + { MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL }, + + // Unimplemented SCI0-SCI1.1 unused functions, always mapped to kDummy + { MAP_DUMMY(InspectObj), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ShowSends), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ShowObjs), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ShowFree), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(StackUsage), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(Profiler), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ShiftScreen), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ListOps), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ATan), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(Record), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(PlayBack), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(DbugStr), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + + // ======================================================================================================= #ifdef ENABLE_SCI32 - // SCI2 Kernel Functions - { MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, - { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL }, - { MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL }, - { MAP_CALL(ListAllTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL }, - { MAP_CALL(ListAt), SIG_EVERYWHERE, "li", NULL, NULL }, - { 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 }, - { MAP_CALL(OnMe), SIG_EVERYWHERE, "iio(.*)", NULL, NULL }, - { MAP_CALL(RepaintPlane), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL }, - { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, + // SCI2 Kernel Functions + // TODO: whoever knows his way through those calls, fix the signatures. + { MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, + { MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL }, + { MAP_CALL(IsHiRes), SIG_EVERYWHERE, "", NULL, NULL }, + { MAP_CALL(ListAllTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL }, + { MAP_CALL(ListAt), SIG_EVERYWHERE, "li", NULL, NULL }, + { 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 }, + { "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL }, + { MAP_CALL(RepaintPlane), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(SetShowStyle), SIG_EVERYWHERE, "ioiiiii([ri])(i)", NULL, NULL }, + { MAP_CALL(String), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(UpdatePlane), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL }, + + // SCI2 unmapped functions - TODO! + // SetScroll + // AddMagnify // most probably similar to the SCI1.1 functions. We need a test case + // DeleteMagnify + // EditText + // DisposeTextBitmap + // VibrateMouse - used in QFG4 floppy + // PalCycle + // ObjectIntersect - used in QFG4 floppy + + // SCI2 empty functions + + // Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable + // memory") are available. We have our own memory manager and garbage collector, thus we ignore this call. + { MAP_EMPTY(Purge), SIG_EVERYWHERE, "i", NULL, NULL }, + + // Unused SCI2 unused functions, always mapped to kDummy + { MAP_DUMMY(InspectObject), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // Profiler (same as SCI0-SCI1.1) + // Record (same as SCI0-SCI1.1) + // PlayBack (same as SCI0-SCI1.1) + { MAP_DUMMY(MonoOut), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(SetFatalStr), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(IntegrityChecking),SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(CheckIntegrity), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(MarkMemory), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(GetHighItemPri), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(ShowStylePercent), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(InvertRect), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(MakeSaveCatName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - // SCI2.1 Kernel Functions - { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iio(.*)", NULL, NULL }, - { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, - { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, - { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(Save), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL }, - { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL } + // SCI2.1 Kernel Functions + { MAP_CALL(CD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL }, + { MAP_CALL(List), SIG_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, + { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, + { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Save), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL }, + { MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL }, + { MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(WinDLL), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(PrintDebug), SIG_EVERYWHERE, "ri", NULL, NULL }, + + // SCI2.1 unmapped functions - TODO! + // SetLanguage + // FindSelector + // FindClass + // CelRect + // BaseLineSpan + // CelInfo + // Bitmap + // CelLink + // MovePlaneItems + // Font + // ScrollWindow + // AddLine + // DeleteLine + // UpdateLine + // AddPolygon + // DeletePolygon + // UpdatePolygon + // GetConfig + // Table + // LoadChunk + // SetPalStyleRange + // NewRoom + // Priority + // MorphOn + // SetHotRectangles + // DeletePic + + // SCI2.1 empty functions + + // SetWindowsOption is used to set Windows specific options, like for example the title bar visibility of + // the game window in Phantasmagoria 2. We ignore these settings completely. + { MAP_EMPTY(SetWindowsOption), SIG_EVERYWHERE, "ii", NULL, NULL }, + + // Unused SCI2.1 unused functions, always mapped to kDummy + { MAP_DUMMY(GetSierraProfileInt), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_DUMMY(GetSierraProfileString), SIG_EVERYWHERE, "(.*)", NULL, NULL }, #endif + + { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL } }; /** Default kernel name table. */ @@ -575,20 +669,20 @@ static const char *s_defaultKernelNames[] = { /*0x4a*/ "ReadNumber", /*0x4b*/ "BaseSetter", /*0x4c*/ "DirLoop", - /*0x4d*/ "CanBeHere", // CantBeHere in newer SCI versions + /*0x4d*/ "CanBeHere", // CantBeHere in newer SCI versions /*0x4e*/ "OnControl", /*0x4f*/ "InitBresen", /*0x50*/ "DoBresen", - /*0x51*/ "Platform", // DoAvoider (SCI0) + /*0x51*/ "Platform", // DoAvoider (SCI0) /*0x52*/ "SetJump", - /*0x53*/ "SetDebug", - /*0x54*/ "Dummy", // InspectObj - /*0x55*/ "Dummy", // ShowSends - /*0x56*/ "Dummy", // ShowObjs - /*0x57*/ "Dummy", // ShowFree + /*0x53*/ "SetDebug", // for debugging + /*0x54*/ "InspectObj", // for debugging + /*0x55*/ "ShowSends", // for debugging + /*0x56*/ "ShowObjs", // for debugging + /*0x57*/ "ShowFree", // for debugging /*0x58*/ "MemoryInfo", - /*0x59*/ "Dummy", // StackUsage - /*0x5a*/ "Dummy", // Profiler + /*0x59*/ "StackUsage", // for debugging + /*0x5a*/ "Profiler", // for debugging /*0x5b*/ "GetMenu", /*0x5c*/ "SetMenu", /*0x5d*/ "GetSaveFiles", @@ -609,33 +703,33 @@ static const char *s_defaultKernelNames[] = { /*0x6c*/ "Graph", /*0x6d*/ "Joystick", // End of kernel function table for SCI0 - /*0x6e*/ "Dummy", // ShiftScreen + /*0x6e*/ "ShiftScreen", // never called? /*0x6f*/ "Palette", /*0x70*/ "MemorySegment", /*0x71*/ "Intersections", // MoveCursor (SCI1 late), PalVary (SCI1.1) /*0x72*/ "Memory", - /*0x73*/ "Dummy", // ListOps + /*0x73*/ "ListOps", // never called? /*0x74*/ "FileIO", /*0x75*/ "DoAudio", /*0x76*/ "DoSync", /*0x77*/ "AvoidPath", - /*0x78*/ "Sort", // StrSplit (SCI01) - /*0x79*/ "Dummy", // ATan + /*0x78*/ "Sort", // StrSplit (SCI01) + /*0x79*/ "ATan", // never called? /*0x7a*/ "Lock", /*0x7b*/ "StrSplit", - /*0x7c*/ "GetMessage", // Message (SCI1.1) + /*0x7c*/ "GetMessage", // Message (SCI1.1) /*0x7d*/ "IsItSkip", /*0x7e*/ "MergePoly", /*0x7f*/ "ResCheck", /*0x80*/ "AssertPalette", /*0x81*/ "TextColors", /*0x82*/ "TextFonts", - /*0x83*/ "Dummy", // Record - /*0x84*/ "Dummy", // PlayBack + /*0x83*/ "Record", // for debugging + /*0x84*/ "PlayBack", // for debugging /*0x85*/ "ShowMovie", /*0x86*/ "SetVideoMode", /*0x87*/ "SetQuitStr", - /*0x88*/ "Dummy" // DbugStr + /*0x88*/ "DbugStr" // for debugging }; #ifdef ENABLE_SCI32 @@ -679,7 +773,7 @@ static const char *sci2_default_knames[] = { /*0x21*/ "DeleteMagnify", /*0x22*/ "IsHiRes", /*0x23*/ "Graph", - /*0x24*/ "InvertRect", + /*0x24*/ "InvertRect", // only in SCI2, not used in any SCI2 game /*0x25*/ "TextSize", /*0x26*/ "Message", /*0x27*/ "TextColors", @@ -701,8 +795,8 @@ static const char *sci2_default_knames[] = { /*0x37*/ "RestoreGame", /*0x38*/ "RestartGame", /*0x39*/ "GameIsRestarting", - /*0x3a*/ "MakeSaveCatName", - /*0x3b*/ "MakeSaveFileName", + /*0x3a*/ "MakeSaveCatName", // only in SCI2, not used in any SCI2 game + /*0x3b*/ "MakeSaveFileName", // only in SCI2, not used in any SCI2 game /*0x3c*/ "GetSaveFiles", /*0x3d*/ "GetSaveDir", /*0x3e*/ "CheckSaveGame", @@ -758,13 +852,13 @@ static const char *sci2_default_knames[] = { /*0x70*/ "InPolygon", /*0x71*/ "MergePoly", /*0x72*/ "SetDebug", - /*0x73*/ "InspectObject", + /*0x73*/ "InspectObject", // for debugging /*0x74*/ "MemoryInfo", - /*0x75*/ "Profiler", - /*0x76*/ "Record", - /*0x77*/ "PlayBack", - /*0x78*/ "MonoOut", - /*0x79*/ "SetFatalStr", + /*0x75*/ "Profiler", // for debugging + /*0x76*/ "Record", // for debugging + /*0x77*/ "PlayBack", // for debugging + /*0x78*/ "MonoOut", // for debugging + /*0x79*/ "SetFatalStr", // for debugging /*0x7a*/ "GetCWD", /*0x7b*/ "ValidPath", /*0x7c*/ "FileIO", @@ -776,12 +870,12 @@ static const char *sci2_default_knames[] = { /*0x82*/ "Array", /*0x83*/ "String", /*0x84*/ "RemapColors", - /*0x85*/ "IntegrityChecking", - /*0x86*/ "CheckIntegrity", + /*0x85*/ "IntegrityChecking", // for debugging + /*0x86*/ "CheckIntegrity", // for debugging /*0x87*/ "ObjectIntersect", - /*0x88*/ "MarkMemory", - /*0x89*/ "TextWidth", - /*0x8a*/ "PointSize", + /*0x88*/ "MarkMemory", // for debugging + /*0x89*/ "TextWidth", // for debugging(?), only in SCI2, not used in any SCI2 game + /*0x8a*/ "PointSize", // for debugging(?), only in SCI2, not used in any SCI2 game // GK2 Demo (and similar) only kernel functions /*0x8b*/ "AddLine", @@ -935,7 +1029,7 @@ static const char *sci21_default_knames[] = { /*0x7c*/ "SetQuitStr", /*0x7d*/ "GetConfig", /*0x7e*/ "Table", - /*0x7f*/ "WinHelp", // Windows only + /*0x7f*/ "WinHelp", // Windows only /*0x80*/ "Dummy", /*0x81*/ "Dummy", /*0x82*/ "Dummy", @@ -957,8 +1051,8 @@ static const char *sci21_default_knames[] = { /*0x92*/ "PlayVMD", /*0x93*/ "SetHotRectangles", /*0x94*/ "MulDiv", - /*0x95*/ "GetSierraProfileInt", // Windows only - /*0x96*/ "GetSierraProfileString", // Windows only + /*0x95*/ "GetSierraProfileInt", // , Windows only + /*0x96*/ "GetSierraProfileString", // , Windows only /*0x97*/ "SetWindowsOption", // Windows only /*0x98*/ "GetWindowsOption", // Windows only /*0x99*/ "WinDLL", // Windows only diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index e08f27cdf7..3b41c851e1 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -28,6 +28,7 @@ #include "common/file.h" #include "common/str.h" #include "common/savefile.h" +#include "common/translation.h" #include "gui/saveload.h" @@ -421,7 +422,7 @@ static void listSavegames(Common::Array<SavegameDesc> &saves) { Common::SeekableReadStream *in; if ((in = saveFileMan->openForLoading(filename))) { SavegameMetadata meta; - if (!get_savegame_metadata(in, &meta) || meta.savegame_name.empty()) { + if (!get_savegame_metadata(in, &meta) || meta.name.empty()) { // invalid delete in; continue; @@ -430,17 +431,17 @@ static void listSavegames(Common::Array<SavegameDesc> &saves) { SavegameDesc desc; desc.id = strtol(filename.end() - 3, NULL, 10); - desc.date = meta.savegame_date; + desc.date = meta.saveDate; // We need to fix date in here, because we save DDMMYYYY instead of // YYYYMMDD, so sorting wouldn't work desc.date = ((desc.date & 0xFFFF) << 16) | ((desc.date & 0xFF0000) >> 8) | ((desc.date & 0xFF000000) >> 24); - desc.time = meta.savegame_time; - desc.version = meta.savegame_version; + desc.time = meta.saveTime; + desc.version = meta.version; - if (meta.savegame_name.lastChar() == '\n') - meta.savegame_name.deleteLastChar(); + if (meta.name.lastChar() == '\n') + meta.name.deleteLastChar(); - Common::strlcpy(desc.name, meta.savegame_name.c_str(), SCI_MAX_SAVENAME_LENGTH); + Common::strlcpy(desc.name, meta.name.c_str(), SCI_MAX_SAVENAME_LENGTH); debug(3, "Savegame in file %s ok, id %d", filename.c_str(), desc.id); @@ -495,7 +496,7 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) { // Find saved-game if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END)) - error("kCheckSaveGame: called with invalid savegameId!"); + error("kCheckSaveGame: called with invalid savegameId"); uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; int savegameNr = findSavegame(saves, savegameId); if (savegameNr == -1) @@ -573,10 +574,18 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { g_sci->_soundCmd->pauseAll(true); // pause music const EnginePlugin *plugin = NULL; EngineMan.findGame(g_sci->getGameIdStr(), &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save"); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); dialog->setSaveMode(true); savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); game_description = dialog->getResultString(); + if (game_description.empty()) { + // create our own description for the saved game, the user didnt enter it + TimeDate curTime; + g_system->getTimeAndDate(curTime); + curTime.tm_year += 1900; // fixup year + curTime.tm_mon++; // fixup month + game_description = Common::String::printf("%02d.%02d.%04d / %02d:%02d:%02d", curTime.tm_mday, curTime.tm_mon, curTime.tm_year, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); + } delete dialog; g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save) if (savegameId < 0) @@ -636,11 +645,11 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { warning("Error opening savegame \"%s\" for writing", filename.c_str()); } else { if (!gamestate_save(s, out, game_description.c_str(), version.c_str())) { - warning("Saving the game failed."); + warning("Saving the game failed"); } else { out->finalize(); if (out->err()) { - warning("Writing the savegame failed."); + warning("Writing the savegame failed"); } else { s->r_acc = TRUE_REG; // success } @@ -665,7 +674,7 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { g_sci->_soundCmd->pauseAll(true); // pause music const EnginePlugin *plugin = NULL; EngineMan.findGame(g_sci->getGameIdStr(), &plugin); - GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore"); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore")); dialog->setSaveMode(false); savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName()); delete dialog; diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 02891dde9e..282ca0f842 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -129,8 +129,7 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) { g_sci->_gfxCursor->kernelHide(); break; case -1: - // TODO: Special case at least in kq6, check disassembly - // Does something with magCursor, which is set on argc = 10, which we don't support + g_sci->_gfxCursor->kernelClearZoomZone(); break; case -2: g_sci->_gfxCursor->kernelResetMoveZone(); @@ -184,15 +183,10 @@ static reg_t kSetCursorSci11(EngineState *s, int argc, reg_t *argv) { break; case 10: // Freddy pharkas, when using the whiskey glass to read the prescription (bug #3034973) - // magnifier support, disabled using argc == 1, argv == -1 - warning("kSetCursor: unsupported magnifier"); - // we just set the view cursor currently - g_sci->_gfxCursor->kernelSetView(argv[5].toUint16(), argv[6].toUint16(), argv[7].toUint16(), hotspot); - // argv[0] -> 1, 2, 4 -> maybe magnification multiplier - // argv[1-4] -> rect for magnification - // argv[5, 6, 7] -> view resource for cursor - // argv[8] -> picture resource for mag - // argv[9] -> color for magnifier replacement + g_sci->_gfxCursor->kernelSetZoomZone(argv[0].toUint16(), + Common::Rect(argv[1].toUint16(), argv[2].toUint16(), argv[3].toUint16(), argv[4].toUint16()), + argv[5].toUint16(), argv[6].toUint16(), argv[7].toUint16(), + argv[8].toUint16(), argv[9].toUint16()); break; default : error("kSetCursor: Unhandled case: %d arguments given", argc); @@ -347,6 +341,11 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { int maxwidth = (argc > 3) ? argv[3].toUint16() : 0; int font_nr = argv[2].toUint16(); + if (!dest) { + debugC(2, kDebugLevelStrings, "GetTextSize: Empty destination"); + return s->r_acc; + } + Common::String sep_str; const char *sep = NULL; if ((argc > 4) && (argv[4].segment)) { @@ -356,7 +355,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) { dest[0] = dest[1] = NULL_REG; - if (text.empty() || !dest) { // Empty text + if (text.empty()) { // Empty text dest[2] = dest[3] = make_reg(0, 0); debugC(2, kDebugLevelStrings, "GetTextSize: Empty string"); return s->r_acc; @@ -808,6 +807,7 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { alignment = readSelectorValue(s->_segMan, controlObject, SELECTOR(mode)); debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x ('%s') to %d,%d, mode=%d", PRINT_REG(controlObject), text.c_str(), x, y, alignment); g_sci->_gfxControls->kernelDrawText(rect, controlObject, g_sci->strSplit(text.c_str()).c_str(), fontId, alignment, style, hilite); + s->r_acc = g_sci->_gfxText16->allocAndFillReferenceRectArray(); return; case SCI_CONTROLS_TYPE_TEXTEDIT: @@ -903,6 +903,10 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) { reg_t controlObject = argv[0]; Common::String objName = s->_segMan->getObjectName(controlObject); + // Most of the time, we won't return anything to the caller + // but |r| textcodes will trigger creation of rects in memory and will then set s->r_acc + s->r_acc = NULL_REG; + // Disable the "Change Directory" button, as we don't allow the game engine to // change the directory where saved games are placed // "changeDirItem" is used in the import windows of QFG2&3 @@ -941,7 +945,7 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) { } _k_GenericDrawControl(s, controlObject, false); - return NULL_REG; + return s->r_acc; } reg_t kHiliteControl(EngineState *s, int argc, reg_t *argv) { @@ -1191,6 +1195,57 @@ reg_t kShow(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) { + // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now + kStub(s, argc, argv); + + uint16 operation = argv[0].toUint16(); + + switch (operation) { + case 0: { // Initialize remapping to base. 0 turns remapping off. + //int16 unk1 = (argc >= 2) ? argv[1].toSint16() : 0; + } + break; + case 1: { // unknown + // The demo of QFG4 calls this with 1+3 parameters, thus there are differences here + //int16 unk1 = argv[1].toSint16(); + //int16 unk2 = argv[2].toSint16(); + //int16 unk3 = argv[3].toSint16(); + //uint16 unk4 = argv[4].toUint16(); + //uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0; + } + break; + case 2: { // remap by percent + //int16 unk1 = argv[1].toSint16(); + //uint16 percent = argv[2].toUint16(); + //uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0; + } + break; + case 3: { // remap to gray + //int16 unk1 = argv[1].toSint16(); + //int16 percent = argv[2].toSint16(); // 0 - 100 + //uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0; + } + break; + case 4: { // unknown + //int16 unk1 = argv[1].toSint16(); + //uint16 unk2 = argv[2].toUint16(); + //uint16 unk3 = argv[3].toUint16(); + //uint16 unk4 = (argc >= 5) ? argv[4].toUint16() : 0; + } + break; + case 5: { // increment color + //int16 unk1 = argv[1].toSint16(); + //uint16 unk2 = argv[2].toUint16(); + } + break; + default: + break; + } + + return s->r_acc; +} + #ifdef ENABLE_SCI32 reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) { @@ -1211,69 +1266,38 @@ reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) { } reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) { - reg_t viewObj = argv[0]; - - g_sci->_gfxFrameout->kernelAddScreenItem(viewObj); - return NULL_REG; + g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]); + return s->r_acc; } reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) { - //reg_t viewObj = argv[0]; - - //warning("kUpdateScreenItem, object %04x:%04x, view %d, loop %d, cel %d, pri %d", PRINT_REG(viewObj), viewId, loopNo, celNo, priority); - return NULL_REG; + g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]); + return s->r_acc; } reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) { - reg_t viewObj = argv[0]; - - g_sci->_gfxFrameout->kernelDeleteScreenItem(viewObj); - - /* - reg_t viewObj = argv[0]; - uint16 viewId = readSelectorValue(s->_segMan, viewObj, SELECTOR(view)); - int16 loopNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(loop)); - int16 celNo = readSelectorValue(s->_segMan, viewObj, SELECTOR(cel)); - //int16 leftPos = 0; - //int16 topPos = 0; - int16 priority = readSelectorValue(s->_segMan, viewObj, SELECTOR(priority)); - //int16 control = 0; - */ - - // TODO - - //warning("kDeleteScreenItem, view %d, loop %d, cel %d, pri %d", viewId, loopNo, celNo, priority); - return NULL_REG; + g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]); + return s->r_acc; } reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) { - reg_t planeObj = argv[0]; - - g_sci->_gfxFrameout->kernelAddPlane(planeObj); - return NULL_REG; + g_sci->_gfxFrameout->kernelAddPlane(argv[0]); + return s->r_acc; } reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) { - reg_t planeObj = argv[0]; - - g_sci->_gfxFrameout->kernelDeletePlane(planeObj); - return NULL_REG; + g_sci->_gfxFrameout->kernelDeletePlane(argv[0]); + return s->r_acc; } reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) { - reg_t planeObj = argv[0]; - - g_sci->_gfxFrameout->kernelUpdatePlane(planeObj); + g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]); return s->r_acc; } reg_t kRepaintPlane(EngineState *s, int argc, reg_t *argv) { - reg_t picObj = argv[0]; - - // TODO - - warning("kRepaintPlane object %04x:%04x", PRINT_REG(picObj)); - return NULL_REG; + g_sci->_gfxFrameout->kernelRepaintPlane(argv[0]); + return s->r_acc; } reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) { @@ -1300,9 +1324,8 @@ reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } -reg_t kOnMe(EngineState *s, int argc, reg_t *argv) { - // Tests if the cursor is on the passed object - +// Tests if the coordinate is on the passed object +reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { uint16 x = argv[0].toUint16(); uint16 y = argv[1].toUint16(); reg_t targetObject = argv[2]; @@ -1335,75 +1358,9 @@ reg_t kOnMe(EngineState *s, int argc, reg_t *argv) { if (g_sci->_gfxCompare->kernelIsItSkip(viewId, loopNo, celNo, Common::Point(x - nsRect.left, y - nsRect.top))) contained = false; } -// these hacks shouldn't be needed anymore -// uint16 itemX = readSelectorValue(s->_segMan, targetObject, SELECTOR(x)); -// uint16 itemY = readSelectorValue(s->_segMan, targetObject, SELECTOR(y)); - - // If top and left are negative, we need to adjust coordinates by - // the item's x and y (e.g. happens in GK1, day 1, with detective - // Mosely's hotspot in his office) - -// if (nsRect.left < 0) -// nsRect.translate(itemX, 0); -// -// if (nsRect.top < 0) -// nsRect.translate(0, itemY); - -// // HACK: nsLeft and nsTop can be invalid, so try and fix them here -// // using x and y (e.g. with the inventory screen in GK1) -// if (nsRect.left == itemY && nsRect.top == itemX) { -// // Swap the values, as they're inversed (eh???) -// nsRect.left = itemX; -// nsRect.top = itemY; -// } - return make_reg(0, contained); } -reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { - // Tests if the cursor is on the passed object, after adjusting the - // coordinates of the object according to the object's plane - - uint16 x = argv[0].toUint16(); - uint16 y = argv[1].toUint16(); - reg_t targetObject = argv[2]; - // TODO: argv[3] - it's usually 0 - Common::Rect nsRect; - - // Get the bounding rectangle of the object - nsRect.left = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsLeft)); - nsRect.top = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsTop)); - nsRect.right = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsRight)); - nsRect.bottom = readSelectorValue(s->_segMan, targetObject, SELECTOR(nsBottom)); - - // Get the object's plane -#if 0 - reg_t planeObject = readSelector(s->_segMan, targetObject, SELECTOR(plane)); - if (!planeObject.isNull()) { - //uint16 itemX = readSelectorValue(s->_segMan, targetObject, SELECTOR(x)); - //uint16 itemY = readSelectorValue(s->_segMan, targetObject, SELECTOR(y)); - uint16 planeResY = readSelectorValue(s->_segMan, planeObject, SELECTOR(resY)); - uint16 planeResX = readSelectorValue(s->_segMan, planeObject, SELECTOR(resX)); - uint16 planeTop = readSelectorValue(s->_segMan, planeObject, SELECTOR(top)); - uint16 planeLeft = readSelectorValue(s->_segMan, planeObject, SELECTOR(left)); - planeTop = (planeTop * g_sci->_gfxScreen->getHeight()) / planeResY; - planeLeft = (planeLeft * g_sci->_gfxScreen->getWidth()) / planeResX; - - // Adjust the bounding rectangle of the object by the object's - // actual X, Y coordinates - nsRect.top = ((nsRect.top * g_sci->_gfxScreen->getHeight()) / planeResY); - nsRect.left = ((nsRect.left * g_sci->_gfxScreen->getWidth()) / planeResX); - nsRect.bottom = ((nsRect.bottom * g_sci->_gfxScreen->getHeight()) / planeResY); - nsRect.right = ((nsRect.right * g_sci->_gfxScreen->getWidth()) / planeResX); - - nsRect.translate(planeLeft, planeTop); - } -#endif - //warning("kIsOnMe: (%d, %d) on object %04x:%04x, parameter %d", argv[0].toUint16(), argv[1].toUint16(), PRINT_REG(argv[2]), argv[3].toUint16()); - - return make_reg(0, nsRect.contains(x, y)); -} - reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { // TODO: argument 0 is usually 0, and arguments 1 and 2 are usually 1 switch (argv[0].toUint16()) { @@ -1460,6 +1417,61 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { return s->r_acc; } +reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) { + uint16 windowsOption = argv[0].toUint16(); + switch (windowsOption) { + case 0: + // Title bar on/off in Phantasmagoria, we return 0 (off) + return NULL_REG; + default: + warning("GetWindowsOption: Unknown option %d", windowsOption); + return NULL_REG; + } +} + +reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) { + switch (argv[0].toUint16()) { + case 1: + // Load a help file + // Maybe in the future we can implement this, but for now this message should suffice + showScummVMDialog("Please use an external viewer to open the game's help file: " + s->_segMan->getString(argv[1])); + break; + case 2: + // Looks like some init function + break; + default: + warning("Unknown kWinHelp subop %d", argv[0].toUint16()); + } + + return s->r_acc; +} + +/** + * Used to programmatically mass set properties of the target plane + */ +reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) { + // TODO: This is all a stub/skeleton, thus we're invoking kStub() for now + kStub(s, argc, argv); + + // showStyle matches the style selector of the associated plane object + uint16 showStyle = argv[0].toUint16(); // 0 - 15 + reg_t planeObj = argv[1]; + //argv[2] + //int16 priority = argv[3].toSint16(); + //argv[4] + //argv[5] + //argv[6] + //argv[7] + //int16 unk8 = (argc >= 9) ? argv[8].toSint16() : 0; + + if (showStyle > 15) { + warning("kSetShowStyle: Illegal style %d for plane %04x:%04x", showStyle, PRINT_REG(planeObj)); + return s->r_acc; + } + + return s->r_acc; +} + #endif } // End of namespace Sci diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index fbe20410de..6d3cd78586 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -180,15 +180,16 @@ enum { reg_t kGetTime(EngineState *s, int argc, reg_t *argv) { TimeDate loc_time; - uint32 elapsedTime; + uint32 elapsedTime = g_engine->getTotalPlayTime(); int retval = 0; // Avoid spurious warning g_system->getTimeAndDate(loc_time); - elapsedTime = g_system->getMillis() - s->gameStartTime; int mode = (argc > 0) ? argv[0].toUint16() : 0; - if (getSciVersion() <= SCI_VERSION_0_LATE && mode > 1) + // Modes 2 and 3 are supported since 0.629. + // This condition doesn't check that exactly, but close enough. + if (getSciVersion() == SCI_VERSION_0_EARLY && mode > 1) error("kGetTime called in SCI0 with mode %d (expected 0 or 1)", mode); switch (mode) { @@ -229,14 +230,18 @@ reg_t kMemory(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case K_MEMORY_ALLOCATE_CRITICAL: { int byteCount = argv[1].toUint16(); - // WORKAROUND: pq3 (multilingual) when plotting crimes - allocates the - // returned bytes from kStrLen on "W" and "E" and wants to put a - // string in there, which doesn't fit of course. That's why we allocate - // one byte more all the time inside that room - if (g_sci->getGameId() == GID_PQ3) { - if (s->currentRoomNumber() == 202) - byteCount++; - } + // WORKAROUND: + // - pq3 (multilingual) room 202 + // when plotting crimes, allocates the returned bytes from kStrLen + // on "W" and "E" and wants to put a string in there, which doesn't + // fit of course. + // - lsl5 (multilingual) room 280 + // allocates memory according to a previous kStrLen for the name of + // the airport ladies (bug #3093818), which isn't enough + + // We always allocate 1 byte more, because of this + byteCount++; + if (!s->_segMan->allocDynmem(byteCount, "kMemory() critical", &s->r_acc)) { error("Critical heap allocation failed"); } @@ -387,6 +392,18 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } +#ifdef ENABLE_SCI32 +reg_t kWinDLL(EngineState *s, int argc, reg_t *argv) { + kStub(s, argc, argv); + + // TODO: This seems to be loading and calling Windows DLLs. We'll probably + // need to either ignore calls made here, or wire each call for each game + // that requests it by hand + + error("kWinDLL called"); +} +#endif + reg_t kEmpty(EngineState *s, int argc, reg_t *argv) { // Placeholder for empty kernel functions which are still called from the // engine scripts (like the empty kSetSynonyms function in SCI1.1). This diff --git a/engines/sci/engine/kparse.cpp b/engines/sci/engine/kparse.cpp index be32b340bb..6a052a582d 100644 --- a/engines/sci/engine/kparse.cpp +++ b/engines/sci/engine/kparse.cpp @@ -93,13 +93,13 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) { reg_t stringpos = argv[0]; Common::String string = s->_segMan->getString(stringpos); char *error; - ResultWordList words; reg_t event = argv[1]; g_sci->checkVocabularySwitch(); Vocabulary *voc = g_sci->getVocabulary(); voc->parser_event = event; reg_t params[2] = { voc->parser_base, stringpos }; + ResultWordListList words; bool res = voc->tokenizeString(words, string.c_str(), &error); voc->parserIsValid = false; /* not valid */ @@ -109,10 +109,15 @@ reg_t kParse(EngineState *s, int argc, reg_t *argv) { s->r_acc = make_reg(0, 1); #ifdef DEBUG_PARSER - debugC(2, kDebugLevelParser, "Parsed to the following blocks:"); - - for (ResultWordList::const_iterator i = words.begin(); i != words.end(); ++i) - debugC(2, kDebugLevelParser, " Type[%04x] Group[%04x]", i->_class, i->_group); + debugC(2, kDebugLevelParser, "Parsed to the following blocks:"); + + for (ResultWordListList::const_iterator i = words.begin(); i != words.end(); ++i) { + debugCN(2, kDebugLevelParser, " "); + for (ResultWordList::const_iterator j = i->begin(); j != i->end(); ++j) { + debugCN(2, kDebugLevelParser, "%sType[%04x] Group[%04x]", j == i->begin() ? "" : " / ", j->_class, j->_group); + } + debugCN(2, kDebugLevelParser, "\n"); + } #endif int syntax_fail = voc->parseGNF(words); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index faf966af92..cfd455e7b6 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -1311,6 +1311,8 @@ static void AStar(PathfindingState *s) { } } + assert(vertex_min != 0); // the vertex cost should never be bigger than HUGE_DISTANCE + // Check if we are done if (vertex_min == s->vertex_end) break; diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index a975ce2988..e7f466f9a2 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -178,6 +178,7 @@ reg_t kClone(EngineState *s, int argc, reg_t *argv) { *cloneObj = *parentObj; // Mark as clone + infoSelector &= ~kInfoFlagClass; // remove class bit writeSelectorValue(s->_segMan, cloneAddr, SELECTOR(_info_), infoSelector | kInfoFlagClone); cloneObj->setSpeciesSelector(cloneObj->getPos()); diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 9254bce9c1..5ea3178ae5 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -275,7 +275,7 @@ reg_t kFormat(EngineState *s, int argc, reg_t *argv) { reg = readSelector(s->_segMan, reg, SELECTOR(data)); #endif - Common::String tempsource = (reg == NULL_REG) ? "" : g_sci->getKernel()->lookupText(reg, + Common::String tempsource = g_sci->getKernel()->lookupText(reg, arguments[paramindex + 1]); int slen = strlen(tempsource.c_str()); int extralen = str_leng - slen; @@ -486,10 +486,12 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) { } #endif - if ((func != K_MESSAGE_NEXT) && (argc < 2)) { - warning("Message: not enough arguments passed to subfunction %d", func); - return NULL_REG; - } +// TODO: Perhaps fix this check, currently doesn't work with PUSH and POP subfunctions +// Pepper uses them to to handle the glossary +// if ((func != K_MESSAGE_NEXT) && (argc < 2)) { +// warning("Message: not enough arguments passed to subfunction %d", func); +// return NULL_REG; +// } MessageTuple tuple; @@ -558,6 +560,12 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } + case K_MESSAGE_PUSH: + s->_msgState->pushCursorStack(); + break; + case K_MESSAGE_POP: + s->_msgState->popCursorStack(); + break; default: warning("Message: subfunction %i invoked (not implemented)", func); } @@ -779,6 +787,20 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } +/** + * Debug function, used in the demo of Shivers. It's marked as a stub + * in the original interpreter, but it gets called by the game scripts. + */ +reg_t kPrintDebug(EngineState *s, int argc, reg_t *argv) { + Common::String debugTemplate = s->_segMan->getString(argv[0]); + char debugString[500]; + + sprintf(debugString, debugTemplate.c_str(), argv[1].toUint16()); + debugC(2, "kPrintDebug: \"%s\"\n", debugString); + + return s->r_acc; +} + #endif } // End of namespace Sci diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index ac6cfb6835..e97ae38702 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -117,7 +117,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { initGraphics(screenWidth, screenHeight, screenWidth > 320, NULL); if (g_system->getScreenFormat().bytesPerPixel == 1) { - error("This video requires >8bpp color to be displayed, but could not switch to RGB color mode."); + error("This video requires >8bpp color to be displayed, but could not switch to RGB color mode"); return NULL_REG; } diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 88f5d29920..4d55febbf9 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -178,24 +178,34 @@ static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) // TODO: It would be a good idea to store a magic number & a header size here, // so that we can implement backward compatibility if the savegame format changes. - s.syncString(obj.savegame_name); + s.syncString(obj.name); s.syncVersion(CURRENT_SAVEGAME_VERSION); - obj.savegame_version = s.getVersion(); - s.syncString(obj.game_version); - s.syncAsSint32LE(obj.savegame_date); - s.syncAsSint32LE(obj.savegame_time); + obj.version = s.getVersion(); + s.syncString(obj.gameVersion); + s.syncAsSint32LE(obj.saveDate); + s.syncAsSint32LE(obj.saveTime); if (s.getVersion() < 22) { - obj.game_object_offset = 0; - obj.script0_size = 0; + obj.gameObjectOffset = 0; + obj.script0Size = 0; } else { - s.syncAsUint16LE(obj.game_object_offset); - s.syncAsUint16LE(obj.script0_size); + s.syncAsUint16LE(obj.gameObjectOffset); + s.syncAsUint16LE(obj.script0Size); + } + + // Playtime + obj.playTime = 0; + if (s.isLoading()) { + if (s.getVersion() >= 26) + s.syncAsUint32LE(obj.playTime); + } else { + obj.playTime = g_engine->getTotalPlayTime() / 1000; + s.syncAsUint32LE(obj.playTime); } } void EngineState::saveLoadWithSerializer(Common::Serializer &s) { Common::String tmp; - s.syncString(tmp, VER(14), VER(23)); // OBSOLETE: Used to be game_version + s.syncString(tmp, VER(14), VER(23)); // OBSOLETE: Used to be gameVersion if (getSciVersion() <= SCI_VERSION_1_1) { // Save/Load picPort as well for SCI0-SCI1.1. Necessary for Castle of Dr. Brain, @@ -520,7 +530,7 @@ void SoundCommandParser::syncPlayList(Common::Serializer &s) { _music->saveLoadWithSerializer(s); } -void SoundCommandParser::reconstructPlayList(int savegame_version) { +void SoundCommandParser::reconstructPlayList(int version) { Common::StackLock lock(_music->_mutex); const MusicList::iterator end = _music->getPlayListEnd(); @@ -566,26 +576,32 @@ void GfxPalette::palVarySaveLoadPalette(Common::Serializer &s, Palette *palette) } void GfxPalette::saveLoadWithSerializer(Common::Serializer &s) { - if (s.getVersion() < 24) - return; - - if (s.isLoading() && _palVaryResourceId != -1) - palVaryRemoveTimer(); - - s.syncAsSint32LE(_palVaryResourceId); - if (_palVaryResourceId != -1) { - palVarySaveLoadPalette(s, &_palVaryOriginPalette); - palVarySaveLoadPalette(s, &_palVaryTargetPalette); - s.syncAsSint16LE(_palVaryStep); - s.syncAsSint16LE(_palVaryStepStop); - s.syncAsSint16LE(_palVaryDirection); - s.syncAsUint16LE(_palVaryTicks); - s.syncAsSint32LE(_palVaryPaused); + if (s.getVersion() >= 25) { + // We need to save intensity of the _sysPalette at least for kq6 when entering the dark cave (room 390) + // from room 340. scripts will set intensity to 60 for this room and restore them when leaving. + // Sierra SCI is also doing this (although obviously not for SCI0->SCI01 games, still it doesn't hurt + // to save it everywhere). ffs. bug #3072868 + s.syncBytes(_sysPalette.intensity, 256); } + if (s.getVersion() >= 24) { + if (s.isLoading() && _palVaryResourceId != -1) + palVaryRemoveTimer(); + + s.syncAsSint32LE(_palVaryResourceId); + if (_palVaryResourceId != -1) { + palVarySaveLoadPalette(s, &_palVaryOriginPalette); + palVarySaveLoadPalette(s, &_palVaryTargetPalette); + s.syncAsSint16LE(_palVaryStep); + s.syncAsSint16LE(_palVaryStepStop); + s.syncAsSint16LE(_palVaryDirection); + s.syncAsUint16LE(_palVaryTicks); + s.syncAsSint32LE(_palVaryPaused); + } - if (s.isLoading() && _palVaryResourceId != -1) { - _palVarySignal = 0; - palVaryInstallTimer(); + if (s.isLoading() && _palVaryResourceId != -1) { + _palVarySignal = 0; + palVaryInstallTimer(); + } } } @@ -675,15 +691,15 @@ bool gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savenam g_system->getTimeAndDate(curTime); SavegameMetadata meta; - meta.savegame_version = CURRENT_SAVEGAME_VERSION; - meta.savegame_name = savename; - meta.game_version = version; - meta.savegame_date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); - meta.savegame_time = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF); + meta.version = CURRENT_SAVEGAME_VERSION; + meta.name = savename; + meta.gameVersion = version; + meta.saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); + meta.saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF); Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false); - meta.script0_size = script0->size; - meta.game_object_offset = g_sci->getGameObject().offset; + meta.script0Size = script0->size; + meta.gameObjectOffset = g_sci->getGameObject().offset; // Checking here again if (s->executionStackBase) { @@ -712,13 +728,13 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { return; } - if ((meta.savegame_version < MINIMUM_SAVEGAME_VERSION) || - (meta.savegame_version > CURRENT_SAVEGAME_VERSION)) { + if ((meta.version < MINIMUM_SAVEGAME_VERSION) || + (meta.version > CURRENT_SAVEGAME_VERSION)) { /* - if (meta.savegame_version < MINIMUM_SAVEGAME_VERSION) + if (meta.version < MINIMUM_SAVEGAME_VERSION) warning("Old savegame version detected, unable to load it"); else - warning("Savegame version is %d, maximum supported is %0d", meta.savegame_version, CURRENT_SAVEGAME_VERSION); + warning("Savegame version is %d, maximum supported is %0d", meta.version, CURRENT_SAVEGAME_VERSION); */ showScummVMDialog("The format of this saved game is obsolete, unable to load it"); @@ -727,9 +743,9 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { return; } - if (meta.game_object_offset > 0 && meta.script0_size > 0) { + if (meta.gameObjectOffset > 0 && meta.script0Size > 0) { Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false); - if (script0->size != meta.script0_size || g_sci->getGameObject().offset != meta.game_object_offset) { + if (script0->size != meta.script0Size || g_sci->getGameObject().offset != meta.gameObjectOffset) { //warning("This saved game was created with a different version of the game, unable to load it"); showScummVMDialog("This saved game was created with a different version of the game, unable to load it"); @@ -755,13 +771,13 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) { // Time state: s->lastWaitTime = g_system->getMillis(); - s->gameStartTime = g_system->getMillis(); s->_screenUpdateTime = g_system->getMillis(); + g_engine->setTotalPlayTime(meta.playTime * 1000); if (g_sci->_gfxPorts) g_sci->_gfxPorts->reset(); - g_sci->_soundCmd->reconstructPlayList(meta.savegame_version); + g_sci->_soundCmd->reconstructPlayList(meta.version); // Message state: delete s->_msgState; @@ -783,12 +799,12 @@ bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata if (stream->eos()) return false; - if ((meta->savegame_version < MINIMUM_SAVEGAME_VERSION) || - (meta->savegame_version > CURRENT_SAVEGAME_VERSION)) { - if (meta->savegame_version < MINIMUM_SAVEGAME_VERSION) + if ((meta->version < MINIMUM_SAVEGAME_VERSION) || + (meta->version > CURRENT_SAVEGAME_VERSION)) { + if (meta->version < MINIMUM_SAVEGAME_VERSION) warning("Old savegame version detected- can't load"); else - warning("Savegame version is %d- maximum supported is %0d", meta->savegame_version, CURRENT_SAVEGAME_VERSION); + warning("Savegame version is %d- maximum supported is %0d", meta->version, CURRENT_SAVEGAME_VERSION); return false; } diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index fc254ba33d..7ab28e126b 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -36,19 +36,20 @@ namespace Sci { struct EngineState; enum { - CURRENT_SAVEGAME_VERSION = 24, + CURRENT_SAVEGAME_VERSION = 26, MINIMUM_SAVEGAME_VERSION = 14 }; // Savegame metadata struct SavegameMetadata { - Common::String savegame_name; - int savegame_version; - Common::String game_version; - int savegame_date; - int savegame_time; - uint16 game_object_offset; - uint16 script0_size; + Common::String name; + int version; + Common::String gameVersion; + int saveDate; + int saveTime; + uint32 playTime; + uint16 gameObjectOffset; + uint16 script0Size; }; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 9561d337ef..da9ab5106d 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -558,6 +558,13 @@ void Script::initialiseObjectsSci11(SegManager *segMan, SegmentId segmentId) { relocate(make_reg(segmentId, READ_SCI11ENDIAN_UINT16(_heapStart))); } +void Script::initialiseObjects(SegManager *segMan, SegmentId segmentId) { + if (getSciVersion() >= SCI_VERSION_1_1) + initialiseObjectsSci11(segMan, segmentId); + else + initialiseObjectsSci0(segMan, segmentId); +} + reg_t Script::findCanonicAddress(SegManager *segMan, reg_t addr) const { addr.offset = 0; return addr; diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index c60cc4b19f..e316fc0c8d 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -159,14 +159,7 @@ public: * @param segMan A reference to the segment manager * @param segmentId The script's segment id */ - void initialiseObjectsSci0(SegManager *segMan, SegmentId segmentId); - - /** - * Initializes the script's objects (SCI1.1+) - * @param segMan A reference to the segment manager - * @param segmentId The script's segment id - */ - void initialiseObjectsSci11(SegManager *segMan, SegmentId segmentId); + void initialiseObjects(SegManager *segMan, SegmentId segmentId); // script lock operations @@ -260,6 +253,20 @@ private: void relocate(reg_t block); bool relocateLocal(SegmentId segment, int location); + + /** + * Initializes the script's objects (SCI0) + * @param segMan A reference to the segment manager + * @param segmentId The script's segment id + */ + void initialiseObjectsSci0(SegManager *segMan, SegmentId segmentId); + + /** + * Initializes the script's objects (SCI1.1+) + * @param segMan A reference to the segment manager + * @param segmentId The script's segment id + */ + void initialiseObjectsSci11(SegManager *segMan, SegmentId segmentId); }; } // End of namespace Sci diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 810e47b379..7317248021 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -32,20 +32,26 @@ namespace Sci { #define PATCH_END 0xFFFF -#define PATCH_ADDTOOFFSET 0x8000 -#define PATCH_GETORIGINALBYTE 0x4000 +#define PATCH_COMMANDMASK 0xF000 +#define PATCH_VALUEMASK 0x0FFF +#define PATCH_ADDTOOFFSET 0xE000 +#define PATCH_GETORIGINALBYTE 0xD000 +#define PATCH_ADJUSTWORD 0xC000 +#define PATCH_ADJUSTWORD_NEG 0xB000 #define PATCH_MAGICDWORD(a, b, c, d) CONSTANT_LE_32(a | (b << 8) | (c << 16) | (d << 24)) +#define PATCH_VALUELIMIT 4096 struct SciScriptSignature { uint16 scriptNr; const char *description; + int16 applyCount; uint32 magicDWord; int magicOffset; const byte *data; const uint16 *patch; }; -#define SCI_SIGNATUREENTRY_TERMINATOR { 0, NULL, 0, 0, NULL, NULL } +#define SCI_SIGNATUREENTRY_TERMINATOR { 0, NULL, 0, 0, 0, NULL, NULL } // signatures are built like this: // - first a counter of the bytes that follow @@ -55,6 +61,51 @@ struct SciScriptSignature { // - rinse and repeat // =========================================================================== +// Castle of Dr. Brain +// cipher::init (script 391) is called on room 380 init. This resets the word +// cipher puzzle. The puzzle sadly operates on some hep strings, which aren't +// saved in our sci. So saving/restoring in this room will break the puzzle +// Because of this issue, we just init the puzzle each time it's accessed. +// this is not 100% sierra behaviour, in fact we will actually reset the puzzle +// during each access which makes it impossible to cheat. +const byte castlebrainSignatureCipherPuzzle[] = { + 22, + 0x35, 0x00, // ldi 00 + 0xa3, 0x26, // sal local[26] + 0xa3, 0x25, // sal local[25] + 0x35, 0x00, // ldi 00 + 0xa3, 0x2a, // sal local[2a] (local is not used) + 0xa3, 0x29, // sal local[29] (local is not used) + 0x35, 0xff, // ldi ff + 0xa3, 0x2c, // sal local[2c] + 0xa3, 0x2b, // sal local[2b] + 0x35, 0x00, // ldi 00 + 0x65, 0x16, // aTop highlightedIcon + 0 +}; + +const uint16 castlebrainPatchCipherPuzzle[] = { + 0x39, 0x6b, // pushi 6b (selector init) + 0x76, // push0 + 0x55, 0x04, // self 04 + 0x35, 0x00, // ldi 00 + 0xa3, 0x25, // sal local[25] + 0xa3, 0x26, // sal local[26] + 0xa3, 0x29, // sal local[29] + 0x65, 0x16, // aTop highlightedIcon + 0x34, 0xff, 0xff, // ldi ffff + 0xa3, 0x2b, // sal local[2b] + 0xa3, 0x2c, // sal local[2c] + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature castlebrainSignatures[] = { + { 391, "cipher puzzle save/restore break", 1, PATCH_MAGICDWORD(0xa3, 0x26, 0xa3, 0x25), -2, castlebrainSignatureCipherPuzzle, castlebrainPatchCipherPuzzle }, + SCI_SIGNATUREENTRY_TERMINATOR +}; + +// =========================================================================== // stayAndHelp::changeState (0) is called when ego swims to the left or right // boundaries of room 660. Normally a textbox is supposed to get on screen // but the call is wrong, so not only do we get an error message the script @@ -114,10 +165,10 @@ const uint16 ecoquest1PatchStayAndHelp[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature ecoquest1Signatures[] = { - { 660, "CD: bad messagebox and freeze", PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp }, - SCI_SIGNATUREENTRY_TERMINATOR + { 660, "CD: bad messagebox and freeze", 1, PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -176,10 +227,10 @@ const uint16 ecoquest2PatchEcorder[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature ecoquest2Signatures[] = { - { 50, "initial text not removed on ecorder", PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -8, ecoquest2SignatureEcorder, ecoquest2PatchEcorder }, - SCI_SIGNATUREENTRY_TERMINATOR + { 50, "initial text not removed on ecorder", 1, PATCH_MAGICDWORD(0x39, 0x64, 0x39, 0x7d), -8, ecoquest2SignatureEcorder, ecoquest2PatchEcorder }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -208,6 +259,33 @@ const uint16 freddypharkasPatchScoreDisposal[] = { PATCH_END }; +// script 235 of freddy pharkas rm235::init and sEnterFrom500::changeState +// disable icon 7+8 of iconbar (CD only). When picking up the cannister after +// placing it down, the scripts will disable all the other icons. This results +// in IconBar::disable doing endless loops even in sierra sci, because there +// is no enabled icon left. We remove disabling of icon 8 (which is help), +// this fixes the issue. +const byte freddypharkasSignatureCannisterHang[] = { + 12, + 0x38, 0xf1, 0x00, // pushi f1 (selector disable) + 0x7a, // push2 + 0x39, 0x07, // pushi 07 + 0x39, 0x08, // pushi 08 + 0x81, 0x45, // lag 45 + 0x4a, 0x08, // send 08 - call IconBar::disable(7, 8) + 0 +}; + +const uint16 freddypharkasPatchCannisterHang[] = { + PATCH_ADDTOOFFSET | +3, + 0x78, // push1 + PATCH_ADDTOOFFSET | +2, + 0x33, 0x00, // ldi 00 (waste 2 bytes) + PATCH_ADDTOOFFSET | +3, + 0x06, // send 06 - call IconBar::disable(7) + PATCH_END +}; + // script 215 of freddy pharkas lowerLadder::doit and highLadder::doit actually // process keyboard-presses when the ladder is on the screen in that room. // They strangely also call kGetEvent. Because the main User::doit also calls @@ -242,13 +320,12 @@ const uint16 freddypharkasPatchLadderEvent[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature freddypharkasSignatures[] = { - { 0, "CD: score early disposal", PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, - // this is not a typo, both lowerLadder::doit and highLadder::doit have the same event code - { 320, "lower ladder event issue", PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, - { 320, "high ladder event issue", PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, - SCI_SIGNATUREENTRY_TERMINATOR + { 0, "CD: score early disposal", 1, PATCH_MAGICDWORD(0x39, 0x0d, 0x43, 0x75), -3, freddypharkasSignatureScoreDisposal, freddypharkasPatchScoreDisposal }, + { 235, "CD: cannister pickup hang", 3, PATCH_MAGICDWORD(0x39, 0x07, 0x39, 0x08), -4, freddypharkasSignatureCannisterHang, freddypharkasPatchCannisterHang }, + { 320, "ladder event issue", 2, PATCH_MAGICDWORD(0x6d, 0x76, 0x38, 0xf5), -1, freddypharkasSignatureLadderEvent, freddypharkasPatchLadderEvent }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -317,12 +394,12 @@ const uint16 gk1PatchDay5PhoneFreeze[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature gk1Signatures[] = { - { 212, "day 5 phone freeze", PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, - { 230, "day 6 police beignet timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, - { 230, "day 6 police sleep timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, - SCI_SIGNATUREENTRY_TERMINATOR + { 212, "day 5 phone freeze", 1, PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, + { 230, "day 6 police beignet timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, + { 230, "day 6 police sleep timer issue", 1, PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -439,10 +516,10 @@ const uint16 kq5PatchCdHarpyVolume[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature kq5Signatures[] = { - { 0, "CD: harpy volume change", PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, - SCI_SIGNATUREENTRY_TERMINATOR + { 0, "CD: harpy volume change", 1, PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -490,10 +567,10 @@ const uint16 larry6PatchDeathDialog[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature larry6Signatures[] = { - { 82, "death dialog memory corruption", PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog }, - SCI_SIGNATUREENTRY_TERMINATOR + { 82, "death dialog memory corruption", 1, PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -521,10 +598,10 @@ const uint16 laurabow2PatchPaintingClosing[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature laurabow2Signatures[] = { - { 560, "painting closing immediately", PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing }, - SCI_SIGNATUREENTRY_TERMINATOR + { 560, "painting closing immediately", 1, PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -563,12 +640,12 @@ const uint16 mothergoose256PatchSaveLimit[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature mothergoose256Signatures[] = { - { 0, "replay save issue", PATCH_MAGICDWORD(0x20, 0x04, 0xa1, 0xb3), -2, mothergoose256SignatureReplay, mothergoose256PatchReplay }, - { 0, "save limit dialog (SCI1.1)", PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, - { 994, "save limit dialog (SCI1)", PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, - SCI_SIGNATUREENTRY_TERMINATOR + { 0, "replay save issue", 1, PATCH_MAGICDWORD(0x20, 0x04, 0xa1, 0xb3), -2, mothergoose256SignatureReplay, mothergoose256PatchReplay }, + { 0, "save limit dialog (SCI1.1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, + { 994, "save limit dialog (SCI1)", 1, PATCH_MAGICDWORD(0xb3, 0x35, 0x0d, 0x20), -1, mothergoose256SignatureSaveLimit, mothergoose256PatchSaveLimit }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -620,11 +697,11 @@ const uint16 qfg1vgaPatchFightEvents[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature qfg1vgaSignatures[] = { - { 215, "fight event issue", PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, - { 216, "weapon master event issue", PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, - SCI_SIGNATUREENTRY_TERMINATOR + { 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, + { 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -650,10 +727,10 @@ const uint16 sq4FloppyPatchEndlessFlight[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature sq4Signatures[] = { - { 298, "Floppy: endless flight", PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, - SCI_SIGNATUREENTRY_TERMINATOR + { 298, "Floppy: endless flight", 1, PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, + SCI_SIGNATUREENTRY_TERMINATOR }; // =========================================================================== @@ -698,26 +775,57 @@ const uint16 sq5PatchScrubbing[] = { PATCH_END }; -// script, description, magic DWORD, adjust +// script, description, magic DWORD, adjust const SciScriptSignature sq5Signatures[] = { - { 119, "scrubbing send crash", PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing }, - SCI_SIGNATUREENTRY_TERMINATOR + { 119, "scrubbing send crash", 1, PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing }, + SCI_SIGNATUREENTRY_TERMINATOR }; // will actually patch previously found signature area void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) { + byte orgData[PATCH_VALUELIMIT]; int32 offset = signatureOffset; uint16 patchWord = *patch; + // Copy over original bytes from script + uint32 orgDataSize = scriptSize - offset; + if (orgDataSize > PATCH_VALUELIMIT) + orgDataSize = PATCH_VALUELIMIT; + memcpy(&orgData, &scriptData[offset], orgDataSize); + while (patchWord != PATCH_END) { - if (patchWord & PATCH_ADDTOOFFSET) { - offset += patchWord & ~PATCH_ADDTOOFFSET; - } else if (patchWord & PATCH_GETORIGINALBYTE) { - // TODO: implement this - // Can be used to patch in some bytes from the original script into another location - } else { - scriptData[offset] = patchWord & 0xFF; + uint16 patchValue = patchWord & PATCH_VALUEMASK; + switch (patchWord & PATCH_COMMANDMASK) { + case PATCH_ADDTOOFFSET: + // add value to offset + offset += patchValue & ~PATCH_ADDTOOFFSET; + break; + case PATCH_GETORIGINALBYTE: + // get original byte from script + if (patchValue >= orgDataSize) + error("patching: can not get requested original byte from script"); + scriptData[offset] = orgData[patchValue]; + offset++; + break; + case PATCH_ADJUSTWORD: { + // Adjust word right before current position + byte *adjustPtr = &scriptData[offset - 2]; + uint16 adjustWord = READ_LE_UINT16(adjustPtr); + adjustWord += patchValue; + WRITE_LE_UINT16(adjustPtr, adjustWord); + break; + } + case PATCH_ADJUSTWORD_NEG: { + // Adjust word right before current position (negative way) + byte *adjustPtr = &scriptData[offset - 2]; + uint16 adjustWord = READ_LE_UINT16(adjustPtr); + adjustWord -= patchValue; + WRITE_LE_UINT16(adjustPtr, adjustWord); + break; + } + default: + scriptData[offset] = patchValue & 0xFF; offset++; } patch++; @@ -766,6 +874,9 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) { const SciScriptSignature *signatureTable = NULL; switch (g_sci->getGameId()) { + case GID_CASTLEBRAIN: + signatureTable = castlebrainSignatures; + break; case GID_ECOQUEST: signatureTable = ecoquest1Signatures; break; @@ -810,12 +921,17 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin if (signatureTable) { while (signatureTable->data) { if (scriptNr == signatureTable->scriptNr) { - int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize); - if (foundOffset != -1) { - // found, so apply the patch - warning("matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset); - applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset); - } + int32 foundOffset = 0; + int16 applyCount = signatureTable->applyCount; + do { + foundOffset = findSignature(signatureTable, scriptData, scriptSize); + if (foundOffset != -1) { + // found, so apply the patch + warning("matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset); + applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset); + } + applyCount--; + } while ((foundOffset != -1) && (applyCount)); } signatureTable++; } diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 7fdd2d25ac..1cbe9a56f4 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -1004,12 +1004,7 @@ int SegManager::instantiateScript(int scriptNum) { scr->load(_resMan); scr->initialiseLocals(this); scr->initialiseClasses(this); - - if (getSciVersion() >= SCI_VERSION_1_1) { - scr->initialiseObjectsSci11(this, segmentId); - } else { - scr->initialiseObjectsSci0(this, segmentId); - } + scr->initialiseObjects(this, segmentId); return segmentId; } @@ -1074,8 +1069,17 @@ void SegManager::uninstantiateScriptSci0(int script_nr) { if (superclass_script == script_nr) { if (scr->getLockers()) scr->decrementLockers(); // Decrease lockers if this is us ourselves - } else - uninstantiateScript(superclass_script); + } else { + if (g_sci->getGameId() == GID_HOYLE3 && (superclass_script == 0 || superclass_script >= 990)) { + // HACK for Hoyle 3: when exiting Checkers or Pachisi, scripts 0, 999 and some others + // are deleted but are never instantiated again. We ignore deletion of these scripts + // here for Hoyle 3 - bug #3038837 + // TODO/FIXME: find out why this happens, seems like there is a problem with the object + // lock code + } else { + uninstantiateScript(superclass_script); + } + } // Recurse to assure that the superclass lockers number gets decreased } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 6eca708e2e..99a41137e9 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -246,7 +246,7 @@ public: reg_t getInfoSelector() const { return _variables[_offset + 2]; } void setInfoSelector(reg_t value) { _variables[_offset + 2] = value; } - reg_t getNameSelector() const { return _variables[_offset + 3]; } + reg_t getNameSelector() const { return _offset + 3 < (uint16)_variables.size() ? _variables[_offset + 3] : NULL_REG; } void setNameSelector(reg_t value) { _variables[_offset + 3] = value; } reg_t getPropDictSelector() const { return _variables[2]; } diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index d0ddd5ca06..e5c9334315 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -125,7 +125,6 @@ public: /* Non-VM information */ - uint32 gameStartTime; /**< The time at which the interpreter was started */ uint32 lastWaitTime; /**< The last time the game invoked Wait() */ uint32 _screenUpdateTime; /**< The last time the game updated the screen */ diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp index a65c35b69c..ed8d4193a9 100644 --- a/engines/sci/engine/static_selectors.cpp +++ b/engines/sci/engine/static_selectors.cpp @@ -155,15 +155,6 @@ Common::StringArray Kernel::checkStaticSelectorNames() { names[i] = sci1Selectors[i - count]; } - for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) { - if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) { - const uint32 slot = selectorRemap->slot; - if (slot >= names.size()) - names.resize(slot + 1); - names[slot] = selectorRemap->name; - } - } - // Now, we need to find out selectors which keep changing place... // We do that by dissecting game objects, and looking for selectors at // specified locations. @@ -184,8 +175,8 @@ Common::StringArray Kernel::checkStaticSelectorNames() { // The init selector is always the first function int initSelectorPos = actorClass->getFuncSelector(0); - if (names.size() < (uint32)initSelectorPos + 1) - names.resize((uint32)initSelectorPos + 1); + if (names.size() < (uint32)initSelectorPos + 2) + names.resize((uint32)initSelectorPos + 2); names[initSelectorPos] = "init"; // dispose comes right after init @@ -253,11 +244,12 @@ Common::StringArray Kernel::checkStaticSelectorNames() { names[275] = "syncCue"; } else if (g_sci->getGameId() == GID_PEPPER) { // Same as above for the non-interactive demo of Pepper - if (names.size() < 265) - names.resize(265); + if (names.size() < 539) + names.resize(539); names[263] = "syncTime"; names[264] = "syncCue"; + names[538] = "startText"; } else if (g_sci->getGameId() == GID_LAURABOW2) { // The floppy of version needs the changeState selector set to match up with the // CD version's workarounds. @@ -265,6 +257,11 @@ Common::StringArray Kernel::checkStaticSelectorNames() { names.resize(251); names[144] = "changeState"; + } else if (g_sci->getGameId() == GID_CNICK_KQ) { + if (names.size() < 447) + names.resize(447); + + names[446] = "say"; } #ifdef ENABLE_SCI32 @@ -275,6 +272,15 @@ Common::StringArray Kernel::checkStaticSelectorNames() { #endif } + for (const SelectorRemap *selectorRemap = sciSelectorRemap; selectorRemap->slot; ++selectorRemap) { + if (getSciVersion() >= selectorRemap->minVersion && getSciVersion() <= selectorRemap->maxVersion) { + const uint32 slot = selectorRemap->slot; + if (slot >= names.size()) + names.resize(slot + 1); + names[slot] = selectorRemap->name; + } + } + return names; } diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index b03b1a8f20..7342f8ca7b 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -207,10 +207,21 @@ static reg_t validate_read_var(reg_t *r, reg_t *stack_base, int type, int max, i // We need to find correct replacements for each situation manually SciTrackOriginReply originReply; SciWorkaroundSolution solution = trackOriginAndFindWorkaround(index, uninitializedReadWorkarounds, &originReply); - if (solution.type == WORKAROUND_NONE) + if (solution.type == WORKAROUND_NONE) { +#ifdef RELEASE_BUILD + // If we are running an official ScummVM release -> fake 0 in unknown cases + warning("Uninitialized read for temp %d from method %s::%s (script %d, room %d, localCall %x)", + index, originReply.objectName.c_str(), originReply.methodName.c_str(), originReply.scriptNr, + g_sci->getEngineState()->currentRoomNumber(), originReply.localCallOffset); + + r[index] = NULL_REG; + break; +#else error("Uninitialized read for temp %d from method %s::%s (script %d, room %d, localCall %x)", index, originReply.objectName.c_str(), originReply.methodName.c_str(), originReply.scriptNr, g_sci->getEngineState()->currentRoomNumber(), originReply.localCallOffset); +#endif + } assert(solution.type == WORKAROUND_FAKE); r[index] = make_reg(0, solution.value); break; @@ -318,10 +329,10 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP // HACK: Temporarily switch to a warning in SCI32 games until we can figure out why Torin has // an invalid exported function. if (getSciVersion() >= SCI_VERSION_2) - warning("Request for invalid exported function 0x%x of script 0x%x", pubfunct, script); + warning("Request for invalid exported function 0x%x of script %d", pubfunct, script); else #endif - error("Request for invalid exported function 0x%x of script 0x%x", pubfunct, script); + error("Request for invalid exported function 0x%x of script %d", pubfunct, script); return NULL; } diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 8e3640c490..d4bab2c671 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -101,12 +101,13 @@ const SciWorkaroundEntry opcodeOrWorkarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_CASTLEBRAIN, 280, 280, 0, "programmer", "dispatchEvent", -1, 0, { WORKAROUND_FAKE, 0xf } }, // pressing 'q' on the computer screen in the robot room, and closing the help dialog that pops up (bug #3039656). Moves the cursor to the view with the ID returned (in this case, the robot hand) - { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname446>", -1, -1, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3 - temps 504 and 505 - { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "<noname183>", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu, like in hoyle 3 - { GID_CNICK_LONGBOW, 0, 0, 0, "RH Budget", "<noname110>", -1, 1, { WORKAROUND_FAKE, 0 } }, // when starting the game + { GID_CNICK_KQ, 200, 0, 1, "Character", "say", -1, -1, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3 - temps 504 and 505 + { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu, like in hoyle 3 + { GID_CNICK_LONGBOW, 0, 0, 0, "RH Budget", "init", -1, 1, { WORKAROUND_FAKE, 0 } }, // when starting the game { GID_ECOQUEST, -1, -1, 0, NULL, "doVerb", -1, 0, { WORKAROUND_FAKE, 0 } }, // almost clicking anywhere triggers this in almost all rooms { GID_FANMADE, 516, 979, 0, "", "export 0", -1, 20, { WORKAROUND_FAKE, 0 } }, // Happens in Grotesteing after the logos { GID_FANMADE, 528, 990, 0, "GDialog", "doit", -1, 4, { WORKAROUND_FAKE, 0 } }, // Happens in Cascade Quest when closing the glossary - bug #3038757 + { GID_FANMADE, 488, 1, 0, "RoomScript", "doit", 0x1f17, 1, { WORKAROUND_FAKE, 0 } }, // Happens in Ocean Battle while playing - bug #3059871 { GID_FREDDYPHARKAS, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu { GID_FREDDYPHARKAS, -1, 31, 0, "quitWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu { GID_FREDDYPHARKAS, 540, 540, 0, "WaverCode", "init", -1, -1, { WORKAROUND_FAKE, 0 } }, // Gun pratice mini-game (bug #3044218) @@ -165,7 +166,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_MOTHERGOOSEHIRES,-1,64950, 1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // right when clicking on a child at the start and probably also later { GID_MOTHERGOOSEHIRES,-1,64950, 1, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // see above { GID_PEPPER, -1, 894, 0, "Package", "doVerb", -1, 3, { WORKAROUND_FAKE, 0 } }, // using the hand on the book in the inventory - bug #3040012 - { GID_PEPPER, 150, 928, 0, "Narrator", "<noname538>", -1, 0, { WORKAROUND_FAKE, 0 } }, // happens during the non-interactive demo of Pepper + { GID_PEPPER, 150, 928, 0, "Narrator", "startText", -1, 0, { WORKAROUND_FAKE, 0 } }, // happens during the non-interactive demo of Pepper { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbd0, 0, { WORKAROUND_FAKE, 0 } }, // hq1: going to the brigands hideout { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbe4, 0, { WORKAROUND_FAKE, 0 } }, // qfg1: going to the brigands hideout { GID_QFG1VGA, 16, 16, 0, "lassoFailed", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // qfg1vga: casting the "fetch" spell in the screen with the flowers, temps 0 and 1 - bug #3053268 @@ -180,6 +181,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_QFG3, 700, 700, -1, "monsterIsDead", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // in the jungle, after winning any fight, bug #3040624 { GID_QFG3, 470, 470, -1, "rm470", "notify", -1, 0, { WORKAROUND_FAKE, 0 } }, // closing the character screen in the Simbani village in the room with the bridge, bug #3040565 { GID_QFG3, 490, 490, -1, "computersMove", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // when finishing awari game, bug #3040579 + { GID_QFG3, 490, 490, -1, "computersMove", "changeState", 0xf53, 4, { WORKAROUND_FAKE, 0 } }, // also when finishing awari game { GID_QFG3, 851, 32, -1, "ProjObj", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // near the end, when throwing the spear of death, bug #3050122 { GID_QFG4, -1, 15, -1, "charInitScreen", "dispatchEvent", -1, 5, { WORKAROUND_FAKE, 0 } }, // floppy version, when viewing the character screen { GID_QFG4, -1, 64917, -1, "controlPlane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, when entering the game menu @@ -336,6 +338,7 @@ const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = { { GID_SQ4, 406, 406, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 410, 410, 0, "swimAfterEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 411, 411, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified + { GID_SQ4, 150, 150, 0, "laserScript", "changeState", 0xb2, 0, { WORKAROUND_STILLCALL, 0 } }, // when visiting the pedestral where Roger Jr. is trapped, before trashing the brain icon in the programming chapter, accidental additional parameter specified - bug #3094235 { GID_SQ4, -1, 704, 0, "shootEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // When shot by Droid in Super Computer Maze (Rooms 500, 505, 510...) - accidental additional parameter specified { GID_KQ5, -1, 981, 0, "myWindow", "dispose", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing any dialog box, accidental additional parameter specified - bug #3036331 { GID_KQ5, -1, 995, 0, "invW", "doit", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing the inventory window, accidental additional parameter specified @@ -366,7 +369,7 @@ const SciWorkaroundEntry kMemory_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kNewWindow_workarounds[] = { - { GID_ECOQUEST, -1, 981, 0, "SysWindow", "<noname178>", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // EcoQuest 1 demo uses an in-between interpreter from SCI1 to SCI1.1. It's SCI1.1, but uses the SCI1 semantics for this call - bug #3035057 + { GID_ECOQUEST, -1, 981, 0, "SysWindow", "open", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // EcoQuest 1 demo uses an in-between interpreter from SCI1 to SCI1.1. It's SCI1.1, but uses the SCI1 semantics for this call - bug #3035057 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -409,6 +412,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { { GID_CASTLEBRAIN, 320, 377, 0, "SWord", "upDate", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after solving the cross-word-puzzle, trying to unload invalid reference { GID_CASTLEBRAIN, 320, 377, 0, "theWord", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // 2nd word puzzle, when exiting before solving, trying to unload invalid reference - bug #3034473 { GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after talking to the dolphin the first time + { GID_ECOQUEST, 380, 69, 0, "lookAtBlackBoard", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // German version, when closing the blackboard closeup in the dolphin room - bug #3098353 { GID_LAURABOW2, 1, 1, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902 { GID_LAURABOW2, 2, 2, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902 { GID_LAURABOW2, 4, 4, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: inside the museum, a 3rd parameter is passed by accident - bug #3034902 |