aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sci.cpp
diff options
context:
space:
mode:
authormd52011-03-04 00:20:28 +0200
committermd52011-03-04 00:25:23 +0200
commit1bdc6db980ffb72c4466d3b1a37f631f78ef59b9 (patch)
tree93900c73fde9883c8f6d36392fdf9d834fb253f8 /engines/sci/sci.cpp
parent9cc12cfc97028e71ebaede1db67a076e408edaeb (diff)
downloadscummvm-rg350-1bdc6db980ffb72c4466d3b1a37f631f78ef59b9.tar.gz
scummvm-rg350-1bdc6db980ffb72c4466d3b1a37f631f78ef59b9.tar.bz2
scummvm-rg350-1bdc6db980ffb72c4466d3b1a37f631f78ef59b9.zip
SCI21: Now replacing save/restore dialogs in SCI2.1 and newer games
Diffstat (limited to 'engines/sci/sci.cpp')
-rw-r--r--engines/sci/sci.cpp57
1 files changed, 42 insertions, 15 deletions
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 657a7b9ee2..de33a59647 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -265,8 +265,6 @@ Common::Error SciEngine::run() {
// Initialize all graphics related subsystems
initGraphics();
- debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()));
-
// Patch in our save/restore code, so that dialogs are replaced
patchGameSaveRestore();
setLauncherLanguage();
@@ -425,7 +423,7 @@ static byte patchGameRestoreSave[] = {
0x76, // push0
0x38, 0xff, 0xff, // pushi -1
0x76, // push0
- 0x43, 0xff, 0x06, // callk kRestoreGame/kSaveGame (will get fixed directly)
+ 0x43, 0xff, 0x06, // callk kRestoreGame/kSaveGame (will get changed afterwards)
0x48, // ret
};
@@ -435,7 +433,18 @@ static byte patchGameRestoreSaveSci2[] = {
0x76, // push0
0x38, 0xff, 0xff, // pushi -1
0x76, // push0
- 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get fixed directly)
+ 0x43, 0xff, 0x06, 0x00, // callk kRestoreGame/kSaveGame (will get changed afterwards)
+ 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
};
@@ -449,6 +458,15 @@ static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, by
patchPtr[8] = id;
}
+static void patchGameSaveRestoreCodeSci21(SegManager *segMan, reg_t methodAddress, byte id, bool doRestore) {
+ Script *script = segMan->getScript(methodAddress.segment);
+ byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset));
+ memcpy(patchPtr, patchGameRestoreSaveSci21, sizeof(patchGameRestoreSaveSci21));
+ if (doRestore)
+ patchPtr[2] = 0x78; // push1
+ patchPtr[9] = id;
+}
+
void SciEngine::patchGameSaveRestore() {
SegManager *segMan = _gamestate->_segMan;
const Object *gameObject = segMan->getObject(_gameObjectAddress);
@@ -478,23 +496,28 @@ void SciEngine::patchGameSaveRestore() {
kernelIdRestore = kernelNr;
if (kernelName == "SaveGame")
kernelIdSave = kernelNr;
+ if (kernelName == "Save")
+ kernelIdSave = kernelIdRestore = kernelNr;
}
- // TODO: This feature does not yet work with the SCI2.1 middle and newer
- // kernel functions (i.e. kSave)
- if (!kernelIdRestore || !kernelIdSave)
- return;
-
// Search for gameobject superclass ::restore
uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount();
for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) {
uint16 selectorId = gameSuperObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
- if (methodName == "restore")
- patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore);
+ if (methodName == "restore") {
+ if (kernelIdSave != kernelIdRestore)
+ 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
- patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
+ if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
+ if (kernelIdSave != kernelIdRestore)
+ patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
+ else
+ patchGameSaveRestoreCodeSci21(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave, false);
+ }
}
}
@@ -504,8 +527,12 @@ void SciEngine::patchGameSaveRestore() {
uint16 selectorId = gameObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "save") {
- if (_gameId != GID_FAIRYTALES) // Fairy Tales saves automatically without a dialog
- patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave);
+ if (_gameId != GID_FAIRYTALES) { // Fairy Tales saves automatically without a dialog
+ if (kernelIdSave != kernelIdRestore)
+ patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave);
+ else
+ patchGameSaveRestoreCodeSci21(segMan, gameObject->getFunction(methodNr), kernelIdSave, false);
+ }
break;
}
}