SCI: Cleanup of the save/load dialog patching code and the lofs type detection code

This commit is contained in:
md5 2011-02-28 00:15:47 +02:00
parent d90c7a8314
commit 4d33923436
3 changed files with 35 additions and 68 deletions

View file

@ -285,20 +285,16 @@ SciVersion GameFeatures::detectLofsType() {
} }
// Find a function of the "Game" object (which is the game super class) which invokes lofsa/lofss // Find a function of the "Game" object (which is the game super class) which invokes lofsa/lofss
reg_t gameSuperClass = g_sci->getGameSuperClassAddress(); const Object *gameObject = _segMan->getObject(g_sci->getGameObject());
const Object *gameSuperObject = _segMan->getObject(gameObject->getSuperClassSelector());
bool found = false; bool found = false;
if (!gameSuperClass.isNull()) { if (gameSuperObject) {
Common::String gameSuperClassName = _segMan->getObjectName(gameSuperClass); Common::String gameSuperClassName = _segMan->getObjectName(gameObject->getSuperClassSelector());
const Object *gameSuperObject = _segMan->getObject(gameSuperClass);
if (gameSuperObject) { for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) {
for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) { found = autoDetectLofsType(gameSuperClassName, m);
found = autoDetectLofsType(gameSuperClassName, m); if (found)
if (found) break;
break;
}
} else {
warning("detectLofsType(): Could not get superclass object");
} }
} else { } else {
warning("detectLofsType(): Could not find superclass of game object"); warning("detectLofsType(): Could not find superclass of game object");

View file

@ -213,7 +213,6 @@ Common::Error SciEngine::run() {
// Add the after market GM patches for the specified game, if they exist // Add the after market GM patches for the specified game, if they exist
_resMan->addNewGMPatch(_gameId); _resMan->addNewGMPatch(_gameId);
_gameObjectAddress = _resMan->findGameObject(); _gameObjectAddress = _resMan->findGameObject();
_gameSuperClassAddress = NULL_REG;
SegManager *segMan = new SegManager(_resMan); SegManager *segMan = new SegManager(_resMan);
@ -250,7 +249,6 @@ Common::Error SciEngine::run() {
warning("Could not get game object, aborting..."); warning("Could not get game object, aborting...");
return Common::kUnknownError; return Common::kUnknownError;
} }
_gameSuperClassAddress = gameObject->getSuperClassSelector();
script_adjust_opcode_formats(); script_adjust_opcode_formats();
@ -441,19 +439,24 @@ static byte patchGameRestoreSaveSci2[] = {
0x48, // ret 0x48, // ret
}; };
static void patchGameSaveRestoreCode(SegManager *segMan, reg_t methodAddress, byte id) {
Script *script = segMan->getScript(methodAddress.segment);
byte *patchPtr = const_cast<byte *>(script->getBuf(methodAddress.offset));
if (getSciVersion() <= SCI_VERSION_1_1)
memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
else if (getSciVersion() == SCI_VERSION_2)
memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
// TODO: SCI21/SCI3
patchPtr[8] = id;
}
void SciEngine::patchGameSaveRestore() { void SciEngine::patchGameSaveRestore() {
SegManager *segMan = _gamestate->_segMan; SegManager *segMan = _gamestate->_segMan;
const Object *gameObject = segMan->getObject(_gameObjectAddress); const Object *gameObject = segMan->getObject(_gameObjectAddress);
const uint16 gameMethodCount = gameObject->getMethodCount(); const Object *gameSuperObject = segMan->getObject(gameObject->getSuperClassSelector());
const Object *gameSuperObject = segMan->getObject(_gameSuperClassAddress);
if (!gameSuperObject) if (!gameSuperObject)
gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510 gameSuperObject = gameObject; // happens in KQ5CD, when loading saved games before r54510
const uint16 gameSuperMethodCount = gameSuperObject->getMethodCount();
reg_t methodAddress;
const uint16 kernelCount = _kernel->getKernelNamesSize();
const byte *scriptRestorePtr = NULL;
byte kernelIdRestore = 0; byte kernelIdRestore = 0;
const byte *scriptSavePtr = NULL;
byte kernelIdSave = 0; byte kernelIdSave = 0;
// This feature is currently not supported in SCI21 or SCI3 // This feature is currently not supported in SCI21 or SCI3
@ -473,7 +476,8 @@ void SciEngine::patchGameSaveRestore() {
if (ConfMan.getBool("sci_originalsaveload")) if (ConfMan.getBool("sci_originalsaveload"))
return; return;
for (uint16 kernelNr = 0; kernelNr < kernelCount; kernelNr++) { uint16 kernelNamesSize = _kernel->getKernelNamesSize();
for (uint16 kernelNr = 0; kernelNr < kernelNamesSize; kernelNr++) {
Common::String kernelName = _kernel->getKernelName(kernelNr); Common::String kernelName = _kernel->getKernelName(kernelNr);
if (kernelName == "RestoreGame") if (kernelName == "RestoreGame")
kernelIdRestore = kernelNr; kernelIdRestore = kernelNr;
@ -481,61 +485,30 @@ void SciEngine::patchGameSaveRestore() {
kernelIdSave = kernelNr; kernelIdSave = kernelNr;
} }
// Search for gameobject-superclass ::restore // Search for gameobject superclass ::restore
for (uint16 methodNr = 0; methodNr < gameSuperMethodCount; methodNr++) { uint16 gameSuperObjectMethodCount = gameSuperObject->getMethodCount();
for (uint16 methodNr = 0; methodNr < gameSuperObjectMethodCount; methodNr++) {
uint16 selectorId = gameSuperObject->getFuncSelector(methodNr); uint16 selectorId = gameSuperObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId); Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "restore") { if (methodName == "restore")
methodAddress = gameSuperObject->getFunction(methodNr); patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdRestore);
Script *script = segMan->getScript(methodAddress.segment); else if (methodName == "save") {
scriptRestorePtr = script->getBuf(methodAddress.offset); if (_gameId != GID_FAIRYTALES) // Fairy Tales saves automatically without a dialog
} patchGameSaveRestoreCode(segMan, gameSuperObject->getFunction(methodNr), kernelIdSave);
if (methodName == "save") {
methodAddress = gameSuperObject->getFunction(methodNr);
Script *script = segMan->getScript(methodAddress.segment);
scriptSavePtr = script->getBuf(methodAddress.offset);
} }
} }
// Search for gameobject ::save, if there is one patch that one instead // Search for gameobject ::save, if there is one patch that one too
for (uint16 methodNr = 0; methodNr < gameMethodCount; methodNr++) { uint16 gameObjectMethodCount = gameObject->getMethodCount();
for (uint16 methodNr = 0; methodNr < gameObjectMethodCount; methodNr++) {
uint16 selectorId = gameObject->getFuncSelector(methodNr); uint16 selectorId = gameObject->getFuncSelector(methodNr);
Common::String methodName = _kernel->getSelectorName(selectorId); Common::String methodName = _kernel->getSelectorName(selectorId);
if (methodName == "save") { if (methodName == "save") {
methodAddress = gameObject->getFunction(methodNr); if (_gameId != GID_FAIRYTALES) // Fairy Tales saves automatically without a dialog
Script *script = segMan->getScript(methodAddress.segment); patchGameSaveRestoreCode(segMan, gameObject->getFunction(methodNr), kernelIdSave);
scriptSavePtr = script->getBuf(methodAddress.offset);
break; break;
} }
} }
switch (_gameId) {
case GID_FAIRYTALES: // fairy tales automatically saves w/o dialog
scriptSavePtr = NULL;
default:
break;
}
if (scriptRestorePtr) {
// Now patch in our code
byte *patchPtr = const_cast<byte *>(scriptRestorePtr);
if (getSciVersion() <= SCI_VERSION_1_1)
memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
else if (getSciVersion() == SCI_VERSION_2)
memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
// TODO: SCI21/SCI3
patchPtr[8] = kernelIdRestore;
}
if (scriptSavePtr) {
// Now patch in our code
byte *patchPtr = const_cast<byte *>(scriptSavePtr);
if (getSciVersion() <= SCI_VERSION_1_1)
memcpy(patchPtr, patchGameRestoreSave, sizeof(patchGameRestoreSave));
else if (getSciVersion() == SCI_VERSION_2)
memcpy(patchPtr, patchGameRestoreSaveSci2, sizeof(patchGameRestoreSaveSci2));
// TODO: SCI21/SCI3
patchPtr[8] = kernelIdSave;
}
} }
bool SciEngine::initGame() { bool SciEngine::initGame() {

View file

@ -246,7 +246,6 @@ public:
inline Vocabulary *getVocabulary() const { return _vocabulary; } inline Vocabulary *getVocabulary() const { return _vocabulary; }
inline EventManager *getEventManager() const { return _eventMan; } inline EventManager *getEventManager() const { return _eventMan; }
inline reg_t getGameObject() const { return _gameObjectAddress; } inline reg_t getGameObject() const { return _gameObjectAddress; }
inline reg_t getGameSuperClassAddress() const { return _gameSuperClassAddress; }
Common::RandomSource &getRNG() { return _rng; } Common::RandomSource &getRNG() { return _rng; }
@ -375,7 +374,6 @@ private:
int16 _vocabularyLanguage; int16 _vocabularyLanguage;
EventManager *_eventMan; EventManager *_eventMan;
reg_t _gameObjectAddress; /**< Pointer to the game object */ reg_t _gameObjectAddress; /**< Pointer to the game object */
reg_t _gameSuperClassAddress; // Address of the super class of the game object
Console *_console; Console *_console;
Common::RandomSource _rng; Common::RandomSource _rng;
Common::MacResManager _macExecutable; Common::MacResManager _macExecutable;