aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sci.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sci.cpp')
-rw-r--r--engines/sci/sci.cpp164
1 files changed, 113 insertions, 51 deletions
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 86c0cffe15..246c031c06 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -128,6 +128,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
DebugMan.addDebugChannel(kDebugLevelScriptPatcher, "ScriptPatcher", "Notifies when scripts are patched");
DebugMan.addDebugChannel(kDebugLevelWorkarounds, "Workarounds", "Notifies when workarounds are triggered");
DebugMan.addDebugChannel(kDebugLevelVideo, "Video", "Video (SEQ, VMD, RBT) debugging");
+ DebugMan.addDebugChannel(kDebugLevelGame, "Game", "Debug calls from game scripts");
DebugMan.addDebugChannel(kDebugLevelGC, "GC", "Garbage Collector debugging");
DebugMan.addDebugChannel(kDebugLevelResMan, "ResMan", "Resource manager debugging");
DebugMan.addDebugChannel(kDebugLevelOnStartup, "OnStartup", "Enter debugger at start of game");
@@ -494,62 +495,89 @@ static byte patchGameRestoreSave[] = {
0x48, // ret
};
+#ifdef ENABLE_SCI32
// SCI2 version: Same as above, but the second parameter to callk is a word
-static byte patchGameRestoreSaveSci2[] = {
- 0x39, 0x03, // pushi 03
- 0x76, // push0
- 0x38, 0xff, 0xff, // pushi -1
- 0x76, // push0
- 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get changed afterwards)
- 0x48, // ret
+// and third parameter is a string reference
+static byte patchGameRestoreSci2[] = {
+ 0x39, 0x03, // pushi 03
+ 0x76, // push0 (game name)
+ 0x38, 0xff, 0xff, // pushi -1 (save number)
+ 0x89, 0x1b, // lsg global[27] (game version)
+ 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame (0xFF will be overwritten by patcher)
+ 0x48, // ret
};
-// SCI21 version: Same as above, but the second parameter to callk is a word
-static byte patchGameRestoreSaveSci21[] = {
- 0x39, 0x04, // pushi 04
- 0x76, // push0 // 0: save, 1: restore (will get changed afterwards)
- 0x76, // push0
- 0x38, 0xff, 0xff, // pushi -1
- 0x76, // push0
- 0x43, 0xff, 0x08, 0x00, // callk kSave (will get changed afterwards)
- 0x48, // ret
+static byte patchGameSaveSci2[] = {
+ 0x39, 0x04, // pushi 04
+ 0x76, // push0 (game name)
+ 0x38, 0xff, 0xff, // pushi -1 (save number)
+ 0x76, // push0 (save description)
+ 0x89, 0x1b, // lsg global[27] (game version)
+ 0x43, 0xff, 0x08, 0x00, // callk kSaveGame (0xFF will be overwritten by patcher)
+ 0x48, // ret
+};
+
+// SCI2.1mid version: Same as above, but with an extra subop parameter
+static byte patchGameRestoreSci21[] = {
+ 0x39, 0x04, // pushi 04
+ 0x78, // push1 (subop)
+ 0x76, // push0 (game name)
+ 0x38, 0xff, 0xff, // pushi -1 (save number)
+ 0x89, 0x1b, // lsg global[27] (game version)
+ 0x43, 0xff, 0x08, 0x00, // callk kSave (0xFF will be overwritten by patcher)
+ 0x48, // ret
};
+static byte patchGameSaveSci21[] = {
+ 0x39, 0x05, // pushi 05
+ 0x76, // push0 (subop)
+ 0x76, // push0 (game name)
+ 0x38, 0xff, 0xff, // pushi -1 (save number)
+ 0x76, // push0 (save description)
+ 0x89, 0x1b, // lsg global[27] (game version)
+ 0x43, 0xff, 0x0a, 0x00, // callk kSave (0xFF will be overwritten by patcher)
+ 0x48, // ret
+};
+#endif
+
static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) {
Script *script = segMan->getScript(methodAddress.getSegment());
byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset()));
- if (getSciVersion() <= SCI_VERSION_1_1) {
- memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
- } else { // SCI2+
- memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
-
- if (g_sci->isBE()) {
- // LE -> BE
- patchPtr[9] = 0x00;
- patchPtr[10] = 0x06;
- }
- }
-
+ memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
patchPtr[8] = id;
}
-static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) {
+#ifdef ENABLE_SCI32
+static void patchGameSaveRestoreCodeSci2(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) {
Script *script = segMan->getScript(methodAddress.getSegment());
byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.getOffset()));
- memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21));
+ int kcallOffset;
- if (doRestore)
- patchPtr[2] = 0x78; // push1
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ if (doRestore) {
+ memcpy(patchPtr, patchGameRestoreSci2, sizeof(patchGameRestoreSci2));
+ kcallOffset = 9;
+ } else {
+ memcpy(patchPtr, patchGameSaveSci2, sizeof(patchGameSaveSci2));
+ kcallOffset = 10;
+ }
+ } else {
+ if (doRestore) {
+ memcpy(patchPtr, patchGameRestoreSci21, sizeof(patchGameRestoreSci21));
+ kcallOffset = 10;
+ } else {
+ memcpy(patchPtr, patchGameSaveSci21, sizeof(patchGameSaveSci21));
+ kcallOffset = 11;
+ }
+ }
+ patchPtr[kcallOffset] = id;
if (g_sci->isBE()) {
- // LE -> BE
- patchPtr[10] = 0x00;
- patchPtr[11] = 0x08;
+ SWAP(patchPtr[kcallOffset + 1], patchPtr[kcallOffset + 2]);
}
-
- patchPtr[9] = id;
}
+#endif
void SciEngine::patchGameSaveRestore() {
SegManager *segMan = _gamestate->_segMan;
@@ -564,9 +592,12 @@ void SciEngine::patchGameSaveRestore() {
case GID_HOYLE1: // gets confused, although the game doesn't support saving/restoring at all
case GID_HOYLE2: // gets confused, see hoyle1
case GID_JONES: // gets confused, when we patch us in, the game is only able to save to 1 slot, so hooking is not required
+ case GID_KQ7: // has custom save/load code
case GID_MOTHERGOOSE: // mother goose EGA saves/restores directly and has no save/restore dialogs
case GID_MOTHERGOOSE256: // mother goose saves/restores directly and has no save/restore dialogs
+ case GID_MOTHERGOOSEHIRES: // has custom save/load code
case GID_PHANTASMAGORIA: // has custom save/load code
+ case GID_PQSWAT: // has custom save/load code
case GID_SHIVERS: // has custom save/load code
return;
default:
@@ -593,17 +624,21 @@ void SciEngine::patchGameSaveRestore() {
uint16 selectorId = gameSuperObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "restore") {
- if (kernelIdSave != kernelIdRestore)
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true);
+ } else
+#endif
patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore);
- else
- patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore, true);
}
else if (methodName == "save") {
if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
- if (kernelIdSave != kernelIdRestore)
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
+ } else
+#endif
patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
- else
- patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
}
}
}
@@ -627,10 +662,12 @@ void SciEngine::patchGameSaveRestore() {
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "save") {
if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
- if (kernelIdSave != kernelIdRestore)
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ patchGameSaveRestoreCodeSci2(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
+ } else
+#endif
patchGameSaveRestoreCode(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave);
- else
- patchGameSaveRestoreCodeSci21(segMan, patchObjectSave->getFunction(methodNr), kernelIdSave, false);
}
break;
}
@@ -955,6 +992,25 @@ int SciEngine::inQfGImportRoom() const {
return 0;
}
+void SciEngine::sleep(uint32 msecs) {
+ uint32 time;
+ const uint32 wakeUpTime = g_system->getMillis() + msecs;
+
+ for (;;) {
+ // let backend process events and update the screen
+ _eventMan->getSciEvent(SCI_EVENT_PEEK);
+ time = g_system->getMillis();
+ if (time + 10 < wakeUpTime) {
+ g_system->delayMillis(10);
+ } else {
+ if (time < wakeUpTime)
+ g_system->delayMillis(wakeUpTime - time);
+ break;
+ }
+
+ }
+}
+
void SciEngine::setLauncherLanguage() {
if (_gameDescription->flags & ADGF_ADDENGLISH) {
// If game is multilingual
@@ -1065,11 +1121,17 @@ void SciEngine::syncIngameAudioOptions() {
bool subtitlesOn = ConfMan.getBool("subtitles");
bool speechOn = !ConfMan.getBool("speech_mute");
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ _gamestate->variables[VAR_GLOBAL][kGlobalVarTextSpeed] = make_reg(0, 8 - ConfMan.getInt("talkspeed") * 8 / 255);
+ }
+#endif
+
if (useGlobal90) {
if (subtitlesOn && !speechOn) {
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 1); // subtitles
+ _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType] = make_reg(0, 1); // subtitles
} else if (!subtitlesOn && speechOn) {
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
+ _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType] = make_reg(0, 2); // speech
} else if (subtitlesOn && speechOn) {
// Is it a game that supports simultaneous speech and subtitles?
switch (_gameId) {
@@ -1090,11 +1152,11 @@ void SciEngine::syncIngameAudioOptions() {
// Phantasmagoria does not support simultaneous speech + subtitles
// Mixed Up Mother Goose Deluxe does not support simultaneous speech + subtitles
#endif // ENABLE_SCI32
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 3); // speech + subtitles
+ _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType] = make_reg(0, 3); // speech + subtitles
break;
default:
// Game does not support speech and subtitles, set it to speech
- _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech
+ _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType] = make_reg(0, 2); // speech
}
}
}
@@ -1105,7 +1167,7 @@ void SciEngine::updateScummVMAudioOptions() {
// Update ScummVM's speech/subtitles settings for SCI1.1 CD games,
// depending on the in-game settings
if (isCD() && getSciVersion() == SCI_VERSION_1_1) {
- uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][90].getOffset();
+ uint16 ingameSetting = _gamestate->variables[VAR_GLOBAL][kGlobalVarMessageType].getOffset();
switch (ingameSetting) {
case 1: