aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippos Karapetis2009-10-09 16:15:56 +0000
committerFilippos Karapetis2009-10-09 16:15:56 +0000
commit4011e948e71b8bf03493caeede8c2018e6d756a0 (patch)
treea713ac73a90b101798819fc1c097c2b62e884c0b
parentc26e283d1bdec6cec36050cd37a147fc5a2e4e6e (diff)
downloadscummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.tar.gz
scummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.tar.bz2
scummvm-rg350-4011e948e71b8bf03493caeede8c2018e6d756a0.zip
Finished the automatic detection of the graphics functions used in SCI0 games. Also, introduced a new helper function to detect the offset of a ret call inside a script, with possible uses in other script detection routines
svn-id: r44828
-rw-r--r--engines/sci/engine/state.cpp157
-rw-r--r--engines/sci/engine/state.h1
2 files changed, 148 insertions, 10 deletions
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index b5d199b718..f187ea34e3 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -264,6 +264,58 @@ int EngineState::methodChecksum(reg_t objAddress, Selector sel, int offset, uint
return sum;
}
+uint16 EngineState::firstRetOffset(reg_t objectAddress) const {
+ Script *script = _segMan->getScript(objectAddress.segment);
+
+ if ((script == NULL) || (script->_buf == NULL))
+ return 0;
+
+ uint16 offset = objectAddress.offset;
+
+ while (offset < script->_bufSize) {
+ byte opcode = script->_buf[offset++];
+ byte opnumber = opcode >> 1;
+
+ if (opnumber == 0x24) // ret
+ return offset - 1;
+
+ // Skip operands for non-ret opcodes
+ for (int i = 0; g_opcode_formats[opnumber][i]; i++) {
+ switch (g_opcode_formats[opnumber][i]) {
+ case Script_Byte:
+ case Script_SByte:
+ offset++;
+ break;
+ case Script_Word:
+ case Script_SWord:
+ offset += 2;
+ break;
+ case Script_Variable:
+ case Script_Property:
+ case Script_Local:
+ case Script_Temp:
+ case Script_Global:
+ case Script_Param:
+ case Script_SVariable:
+ case Script_SRelative:
+ case Script_Offset:
+ offset++;
+ if (!(opcode & 1))
+ offset++;
+ break;
+ case Script_End:
+ return offset;
+ break;
+ case Script_Invalid:
+ default:
+ warning("opcode %02x: Invalid", opcode);
+ }
+ } // end for
+ } // end while
+
+ return 0;
+}
+
SciVersion EngineState::detectDoSoundType() {
if (_doSoundType == SCI_VERSION_AUTODETECT) {
reg_t soundClass = _segMan->findObjectByName("Sound");
@@ -472,16 +524,101 @@ SciVersion EngineState::detectGfxFunctionsType() {
_gfxFunctionsType = SCI_VERSION_0_EARLY;
} else {
// An in-between case: The game does not have a shiftParser
- // selector, but it does have an overlay selector. Therefore,
- // check it to see how it calls kDisplay to determine the
- // graphics functions type used
-
- // TODO: Finish this!
- // For now, we're using the old hack of detecting for the motionCue selector
- if (_kernel->findSelector("motionCue") != -1)
- _gfxFunctionsType = SCI_VERSION_0_LATE;
- else
- _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ // selector, but it does have an overlay selector, so it uses an
+ // overlay. Therefore, check it to see how it calls kDrawPic to
+ // determine the graphics functions type used
+
+ reg_t roomObjAddr = _segMan->findObjectByName("Rm");
+
+ bool found = false;
+
+ if (!roomObjAddr.isNull()) {
+ reg_t addr;
+
+ if (lookup_selector(_segMan, roomObjAddr, _kernel->_selectorCache.overlay, NULL, &addr) == kSelectorMethod) {
+ uint16 offset = addr.offset;
+ byte *scr = _segMan->getScript(addr.segment)->_buf;
+ do {
+ uint16 kFuncNum;
+ int opsize = scr[offset++];
+ uint opcode = opsize >> 1;
+ int i = 0;
+
+ while (g_opcode_formats[opcode][i]) {
+ switch (g_opcode_formats[opcode][i++]) {
+ case Script_Invalid:
+ break;
+ case Script_SByte:
+ case Script_Byte:
+ offset++;
+ break;
+ case Script_Word:
+ case Script_SWord:
+ offset += 2;
+ break;
+ case Script_SVariable:
+ case Script_Variable:
+ case Script_Property:
+ case Script_Global:
+ case Script_Local:
+ case Script_Temp:
+ case Script_Param:
+ if (opsize & 1)
+ kFuncNum = scr[offset++];
+ else {
+ kFuncNum = 0xffff & (scr[offset] | (scr[offset + 1] << 8));
+ offset += 2;
+ }
+
+ if (opcode == op_callk) {
+ if (kFuncNum == 8) { // kDrawPic
+ // Now get the number of parameters
+ byte argc = scr[offset++];
+ // If kDrawPic is called with 6 parameters from the
+ // overlay selector, the game is using old graphics functions.
+ // Otherwise, if it's called with 8 parameters, it's using new
+ // graphics functions
+ if (argc == 6) {
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ found = true;
+ } else if (argc == 8) {
+ _gfxFunctionsType = SCI_VERSION_0_LATE;
+ found = true;
+ } else {
+ warning("overlay selector calling kDrawPic with %d parameters", argc);
+ }
+ }
+ }
+ break;
+
+ case Script_Offset:
+ case Script_SRelative:
+ offset++;
+ if (!opsize & 1)
+ offset++;
+ break;
+ case Script_End:
+ offset = 0; // exit loop
+ break;
+ default:
+ warning("opcode %02x: Invalid", opcode);
+
+ }
+ }
+ } while (offset > 0 && !found);
+ }
+ }
+
+ if (!found) {
+ warning("Graphics functions detection failed, taking an educated guess");
+
+ // Try detecting the graphics function types from the existence of the motionCue
+ // selector (which is a bit of a hack)
+ if (_kernel->findSelector("motionCue") != -1)
+ _gfxFunctionsType = SCI_VERSION_0_LATE;
+ else
+ _gfxFunctionsType = SCI_VERSION_0_EARLY;
+ }
}
}
} else { // (getSciVersion() == SCI_VERSION_0_EARLY)
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 3a6bc7e510..fdce259ca8 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -318,6 +318,7 @@ private:
SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType;
kLanguage charToLanguage(const char c) const;
int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const;
+ uint16 firstRetOffset(reg_t objectAddress) const;
};
/**