diff options
| author | Colin Snover | 2016-09-15 08:54:10 -0500 | 
|---|---|---|
| committer | Colin Snover | 2016-09-29 19:39:16 -0500 | 
| commit | 1eb6d90eec4aa2dab3532e9630c81b6b3dbddafb (patch) | |
| tree | c18f725995654edd1bf903fd527719683d1df951 | |
| parent | b5d0fffb8b111c5d8154a37ba9a0d7b18866c7dd (diff) | |
| download | scummvm-rg350-1eb6d90eec4aa2dab3532e9630c81b6b3dbddafb.tar.gz scummvm-rg350-1eb6d90eec4aa2dab3532e9630c81b6b3dbddafb.tar.bz2 scummvm-rg350-1eb6d90eec4aa2dab3532e9630c81b6b3dbddafb.zip | |
SCI32: Implement ScummVM save/load
| -rw-r--r-- | engines/sci/engine/kernel_tables.h | 8 | ||||
| -rw-r--r-- | engines/sci/engine/kfile.cpp | 45 | ||||
| -rw-r--r-- | engines/sci/sci.cpp | 123 | 
3 files changed, 121 insertions, 55 deletions
| diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index c74b3ae1fb..e11326fc47 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -351,8 +351,8 @@ static const SciKernelMapSubEntry kPalCycle_subops[] = {  //    version,         subId, function-mapping,                    signature,              workarounds  static const SciKernelMapSubEntry kSave_subops[] = { -	{ SIG_SCI32,           0, MAP_CALL(SaveGame32),                "rir[r0]",              NULL }, -	{ SIG_SCI32,           1, MAP_CALL(RestoreGame32),             "ri[r0]",               NULL }, +	{ SIG_SCI32,           0, MAP_CALL(SaveGame32),                "[r0]i[r0][r0]",        NULL }, +	{ SIG_SCI32,           1, MAP_CALL(RestoreGame32),             "[r0]i[r0]",            NULL },  	// System script 64994 in several SCI2.1mid games (KQ7 2.00b, Phant1,  	// PQ:SWAT, SQ6, Torin) calls GetSaveDir with an extra unused argument, and  	// it is easier to just handle it here than to bother with creating @@ -754,12 +754,12 @@ static SciKernelMapEntry s_kernelMap[] = {  	{ MAP_CALL(RespondsTo),        SIG_EVERYWHERE,           ".i",                    NULL,            NULL },  	{ MAP_CALL(RestartGame),       SIG_EVERYWHERE,           "",                      NULL,            NULL },  #ifdef ENABLE_SCI32 -	{ "RestoreGame", kRestoreGame32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri[r0]",      NULL,            NULL }, +	{ "RestoreGame", kRestoreGame32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "[r0]i[r0]",   NULL,            NULL },  #endif  	{ MAP_CALL(RestoreGame),       SIG_EVERYWHERE,           "[r0]i[r0]",             NULL,            NULL },  	{ MAP_CALL(Said),              SIG_EVERYWHERE,           "[r0]",                  NULL,            NULL },  #ifdef ENABLE_SCI32 -	{ "SaveGame", kSaveGame32,     SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rir[r0]",       NULL,            NULL }, +	{ "SaveGame", kSaveGame32,     SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "[r0]i[r0][r0]", NULL,            NULL },  #endif  	{ MAP_CALL(SaveGame),          SIG_SCI16, SIGFOR_ALL,    "[r0]i[r0](r0)",         NULL,            NULL },  	{ MAP_CALL(ScriptID),          SIG_EVERYWHERE,           "[io](i)",               NULL,            NULL }, diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 7e5af79b23..50560be7d1 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -1077,10 +1077,32 @@ reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {  #ifdef ENABLE_SCI32  reg_t kSaveGame32(EngineState *s, int argc, reg_t *argv) { -	const Common::String gameName = s->_segMan->getString(argv[0]); -	int16 saveNo = argv[1].toSint16(); -	const Common::String saveDescription = s->_segMan->getString(argv[2]); -	const Common::String gameVersion = argv[3].isNull() ? "" : s->_segMan->getString(argv[3]); +	Common::String gameName = ""; +	int16 saveNo; +	Common::String saveDescription; +	Common::String gameVersion = (argc <= 3 || argv[3].isNull()) ? "" : s->_segMan->getString(argv[3]); + +	if (argv[0].isNull()) { +		// ScummVM call, from a patched Game::save +		g_sci->_soundCmd->pauseAll(true); +		GUI::SaveLoadChooser dialog(_("Save game:"), _("Save"), true); +		saveNo = dialog.runModalWithCurrentTarget(); +		g_sci->_soundCmd->pauseAll(false); + +		if (saveNo < 0) { +			return NULL_REG; +		} + +		saveDescription = dialog.getResultString(); +		if (saveDescription.empty()) { +			saveDescription = dialog.createDefaultSaveDescription(saveNo); +		} +	} else { +		// Native script call +		gameName = s->_segMan->getString(argv[0]); +		saveNo = argv[1].toSint16(); +		saveDescription = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]); +	}  	// Auto-save system used by Torin and LSL7  	if (gameName == "Autosave" || gameName == "Autosv") { @@ -1149,10 +1171,23 @@ reg_t kSaveGame32(EngineState *s, int argc, reg_t *argv) {  }  reg_t kRestoreGame32(EngineState *s, int argc, reg_t *argv) { -	const Common::String gameName = s->_segMan->getString(argv[0]); +	Common::String gameName = "";  	int16 saveNo = argv[1].toSint16();  	const Common::String gameVersion = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]); +	if (argv[0].isNull() && saveNo == -1) { +		// ScummVM call, either from lancher or a patched Game::restore +		g_sci->_soundCmd->pauseAll(true); +		GUI::SaveLoadChooser dialog(_("Restore game:"), _("Restore"), false); +		saveNo = dialog.runModalWithCurrentTarget(); +		g_sci->_soundCmd->pauseAll(false); +		if (saveNo < 0) { +			return s->r_acc; +		} +	} else { +		gameName = s->_segMan->getString(argv[0]); +	} +  	if (gameName == "Autosave" || gameName == "Autosv") {  		if (saveNo == 0) {  			// Autosave slot 0 is the autosave diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index bdfb6ccc9c..f161569598 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -496,61 +496,86 @@ static byte patchGameRestoreSave[] = {  };  // 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  };  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; @@ -595,17 +620,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);  			}  		}  	} @@ -629,10 +658,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;  		} | 
