aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter van Niftrik2009-08-30 14:53:58 +0000
committerWalter van Niftrik2009-08-30 14:53:58 +0000
commit3e543d2518ee7c6197db2a58721bcb70f0cbfb90 (patch)
treed539b6b04cbb1daf917d073ad921ae1a53e90ee5
parentdceadc9ba09e39ec1f1e060ccdc5b766c367e77c (diff)
downloadscummvm-rg350-3e543d2518ee7c6197db2a58721bcb70f0cbfb90.tar.gz
scummvm-rg350-3e543d2518ee7c6197db2a58721bcb70f0cbfb90.tar.bz2
scummvm-rg350-3e543d2518ee7c6197db2a58721bcb70f0cbfb90.zip
SCI: Add lofs detection.
svn-id: r43824
-rw-r--r--engines/sci/engine/game.cpp2
-rw-r--r--engines/sci/engine/kernel.cpp18
-rw-r--r--engines/sci/engine/kernel.h10
-rw-r--r--engines/sci/engine/script.cpp9
-rw-r--r--engines/sci/engine/script.h2
-rw-r--r--engines/sci/engine/state.cpp127
-rw-r--r--engines/sci/engine/state.h12
-rw-r--r--engines/sci/engine/static_selectors.cpp4
-rw-r--r--engines/sci/engine/vm.cpp28
-rw-r--r--engines/sci/engine/vm.h1
-rw-r--r--engines/sci/sci.cpp3
11 files changed, 163 insertions, 53 deletions
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index 6f36e40440..d7fd5c99d9 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -226,7 +226,7 @@ int script_init_engine(EngineState *s) {
s->bp_list = NULL; // No breakpoints defined
s->have_bp = 0;
- if (((SciEngine*)g_engine)->getKernel()->hasLofsAbsolute())
+ if (s->detectLofsType() == SCI_VERSION_1_MIDDLE)
s->segmentManager->setExportWidth(1);
else
s->segmentManager->setExportWidth(0);
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index ebb1dfdb65..15d37a55fd 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -401,16 +401,6 @@ void Kernel::detectSciFeatures() {
features |= kFeatureOldGfxFunctions;
}
- // Lofs absolute/relative
- if (version >= SCI_VERSION_1_MIDDLE && version < SCI_VERSION_1_1) {
- // Assume all games use absolute lofs
- features |= kFeatureLofsAbsolute;
- } else if (version == SCI_VERSION_1_EARLY) {
- // Use heuristic
- if (_selectorMap.egoMoveSpeed != -1)
- features |= kFeatureLofsAbsolute;
- }
-
printf("Kernel auto-detected features:\n");
printf("Graphics functions: ");
@@ -418,14 +408,6 @@ void Kernel::detectSciFeatures() {
printf("old\n");
else
printf("new\n");
-
- if (version < SCI_VERSION_1_1) {
- printf("lofs parameters: ");
- if (features & kFeatureLofsAbsolute)
- printf("absolute\n");
- else
- printf("relative\n");
- }
}
void Kernel::loadSelectorNames() {
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index a780d04cf7..29228baee7 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -54,8 +54,7 @@ struct KernelFuncWithSignature {
enum AutoDetectedFeatures {
kFeatureOldScriptHeader = 1 << 0,
- kFeatureOldGfxFunctions = 1 << 1,
- kFeatureLofsAbsolute = 1 << 2
+ kFeatureOldGfxFunctions = 1 << 1
};
class Kernel {
@@ -95,13 +94,6 @@ public:
*/
bool usesOldGfxFunctions() const { return (features & kFeatureOldGfxFunctions); }
- /**
- * Applies to all SCI1 versions after 1.000.200
- * In late SCI1 versions, the argument of lofs[as] instructions
- * is absolute rather than relative.
- */
- bool hasLofsAbsolute() const { return (features & kFeatureLofsAbsolute); }
-
// Script dissection/dumping functions
void dissectScript(int scriptNumber, Vocabulary *vocab);
void dumpScriptObject(char *data, int seeker, int objsize);
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 4dacd6b505..3a2d01f61f 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -88,14 +88,16 @@ opcode_format g_opcode_formats[128][4] = {
};
#undef END
-void script_adjust_opcode_formats(SciVersion version) {
+void script_adjust_opcode_formats(EngineState *s) {
// TODO: Check that this is correct
- if ((version >= SCI_VERSION_1_1) || ((SciEngine*)g_engine)->getKernel()->hasLofsAbsolute()) {
+ if (s->detectLofsType() != SCI_VERSION_0_EARLY) {
g_opcode_formats[op_lofsa][0] = Script_Offset;
g_opcode_formats[op_lofss][0] = Script_Offset;
}
-
+
#ifdef ENABLE_SCI32
+ SciVersion version = s->resourceManager->sciVersion();
+
// In SCI32, some arguments are now words instead of bytes
if (version >= SCI_VERSION_2) {
g_opcode_formats[op_calle][2] = Script_Word;
@@ -240,7 +242,6 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(subtitleLang);
FIND_SELECTOR(parseLang);
FIND_SELECTOR(motionCue);
- FIND_SELECTOR(egoMoveSpeed);
FIND_SELECTOR(setCursor);
}
diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h
index dd5980eafe..62c5596d55 100644
--- a/engines/sci/engine/script.h
+++ b/engines/sci/engine/script.h
@@ -202,7 +202,7 @@ enum sci_opcodes { /* FIXME */
extern opcode_format g_opcode_formats[128][4];
-void script_adjust_opcode_formats(SciVersion version);
+void script_adjust_opcode_formats(EngineState *s);
void script_free_breakpoints(EngineState *s);
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index ca4190df8e..e562f8cd4a 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -25,6 +25,7 @@
#include "sci/engine/state.h"
#include "sci/engine/vm.h"
+#include "sci/engine/script.h"
#include "sci/console.h" // For parse_reg_t
namespace Sci {
@@ -121,6 +122,7 @@ EngineState::EngineState(ResourceManager *res, uint32 flags)
_setCursorType = SCI_VERSION_AUTODETECT;
_doSoundType = SCI_VERSION_AUTODETECT;
+ _lofsType = SCI_VERSION_AUTODETECT;
}
EngineState::~EngineState() {
@@ -334,10 +336,133 @@ SciVersion EngineState::detectSetCursorType() {
_setCursorType = SCI_VERSION_0_EARLY;
}
- debugC(0, kDebugLevelGraphics, "Detected SetCursor type: %s", ((SciEngine *)g_engine)->getSciVersionDesc(_setCursorType).c_str());
+ debugC(1, kDebugLevelGraphics, "Detected SetCursor type: %s", ((SciEngine *)g_engine)->getSciVersionDesc(_setCursorType).c_str());
}
return _setCursorType;
}
+SciVersion EngineState::detectLofsType() {
+ if (_lofsType == SCI_VERSION_AUTODETECT) {
+ SciVersion version = segmentManager->sciVersion(); // FIXME: for VM_OBJECT_READ_FUNCTION
+
+ // This detection only works (and is only needed) pre-SCI1.1
+ if (version >= SCI_VERSION_1_1) {
+ _lofsType = SCI_VERSION_1_1;
+ return _lofsType;
+ }
+
+ reg_t gameClass;
+ Object *obj = NULL;
+
+ if (!parse_reg_t(this, "?Game", &gameClass))
+ obj = obj_get(segmentManager, gameClass);
+
+ bool couldBeAbs = true;
+ bool couldBeRel = true;
+
+ // Check methods of the Game class for lofs operations
+ if (obj) {
+ for (int m = 0; m < obj->methods_nr; m++) {
+ reg_t fptr = VM_OBJECT_READ_FUNCTION(obj, m);
+
+ Script *script = segmentManager->getScript(fptr.segment);
+
+ if ((script == NULL) || (script->buf == NULL))
+ continue;
+
+ uint offset = fptr.offset;
+ bool done = false;
+
+ while (!done) {
+ // Read opcode
+ if (offset >= script->buf_size)
+ break;
+
+ byte opcode = script->buf[offset++];
+ byte opnumber = opcode >> 1;
+
+ if ((opnumber == 0x39) || (opnumber == 0x3a)) {
+ uint16 lofs;
+
+ // Load lofs operand
+ if (opcode & 1) {
+ if (offset >= script->buf_size)
+ break;
+ lofs = script->buf[offset++];
+ } else {
+ if (offset + 1 >= script->buf_size)
+ break;
+ lofs = READ_LE_UINT16(script->buf + offset);
+ offset += 2;
+ }
+
+ // Check for going out of bounds when interpreting as abs/rel
+ if (lofs >= script->buf_size)
+ couldBeAbs = false;
+
+ if ((signed)offset + (int16)lofs < 0)
+ couldBeRel = false;
+
+ if ((signed)offset + (int16)lofs >= (signed)script->buf_size)
+ couldBeRel = false;
+
+ continue;
+ }
+
+ // Skip operands for non-lofs 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:
+ done = true;
+ break;
+ case Script_Invalid:
+ default:
+ warning("opcode %02x: Invalid", opcode);
+ }
+ }
+ }
+ }
+ }
+
+ if (couldBeRel == couldBeAbs) {
+ warning("Lofs detection failed, taking an educated guess");
+
+ if (version >= SCI_VERSION_1_MIDDLE)
+ _lofsType = SCI_VERSION_1_MIDDLE;
+
+ _lofsType = SCI_VERSION_0_EARLY;
+ } else if (couldBeAbs) {
+ _lofsType = SCI_VERSION_1_MIDDLE;
+ } else {
+ _lofsType = SCI_VERSION_0_EARLY;
+ }
+
+ debugC(1, kDebugLevelVM, "Detected Lofs type: %s", ((SciEngine *)g_engine)->getSciVersionDesc(_lofsType).c_str());
+ }
+
+ return _lofsType;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index c822f88c41..c394e5d197 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -274,16 +274,22 @@ public:
/**
* Autodetects the DoSound type
- * @return DoSound type
+ * @return DoSound type, SCI_VERSION_0_EARLY / SCI_VERSION_1_EARLY / SCI_VERSION_1_LATE
*/
SciVersion detectDoSoundType();
/**
* Autodetects the SetCursor type
- * @return SetCursor type
+ * @return SetCursor type, SCI_VERSION_0_EARLY / SCI_VERSION_1_1
*/
SciVersion detectSetCursorType();
+ /**
+ * Autodetects the Lofs type
+ * @return Lofs type, SCI_VERSION_0_EARLY / SCI_VERSION_1_MIDDLE / SCI_VERSION_1_1
+ */
+ SciVersion detectLofsType();
+
/* Debugger data: */
Breakpoint *bp_list; /**< List of breakpoints */
int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */
@@ -314,7 +320,7 @@ public:
Common::String getLanguageString(const char *str, kLanguage lang) const;
private:
- SciVersion _doSoundType, _setCursorType;
+ SciVersion _doSoundType, _setCursorType, _lofsType;
kLanguage charToLanguage(const char c) const;
int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const;
};
diff --git a/engines/sci/engine/static_selectors.cpp b/engines/sci/engine/static_selectors.cpp
index 047eb4112c..a26dd16b8f 100644
--- a/engines/sci/engine/static_selectors.cpp
+++ b/engines/sci/engine/static_selectors.cpp
@@ -120,7 +120,7 @@ static const SelectorRemap lsl1_demo_selectors[] = {
{ "cue", 136 }, { "owner", 150 }, { "setVol", 156 },
{ "completed", 210 }, { "motionCue", 213 }, { "cycler", 215 },
{ "setTarget", 221 }, { "distance", 224 }, { "canBeHere", 232 },
- { "syncTime", 247 }, { "syncCue", 248 }, { "egoMoveSpeed", 370 }
+ { "syncTime", 247 }, { "syncCue", 248 }
};
// Taken from Space Quest 1 VGA (Demo)
@@ -133,7 +133,7 @@ static const SelectorRemap lsl5_demo_selectors[] = {
{ "moveDone", 100 }, { "init", 103 }, { "dispose", 104 },
{ "caller", 133 }, { "cue", 135 }, { "owner", 149 },
{ "flags", 150 }, { "completed", 207 }, { "motionCue", 210 },
- { "cycler", 212 }, { "distance", 221 }, { "egoMoveSpeed", 357 }
+ { "cycler", 212 }, { "distance", 221 }
};
// A macro for loading one of the above tables in the function below
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index acd251f191..8e09e56a68 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -1160,13 +1160,15 @@ void run_vm(EngineState *s, int restoring) {
case 0x39: // lofsa
s->r_acc.segment = scriptState.xs->addr.pc.segment;
- if (s->resourceManager->sciVersion() >= SCI_VERSION_1_1) {
+ switch (s->detectLofsType()) {
+ case SCI_VERSION_1_1:
s->r_acc.offset = opparams[0] + local_script->script_size;
- } else {
- if (((SciEngine*)g_engine)->getKernel()->hasLofsAbsolute())
- s->r_acc.offset = opparams[0];
- else
- s->r_acc.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ break;
+ case SCI_VERSION_1_MIDDLE:
+ s->r_acc.offset = opparams[0];
+ break;
+ default:
+ s->r_acc.offset = scriptState.xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
@@ -1180,13 +1182,15 @@ void run_vm(EngineState *s, int restoring) {
case 0x3a: // lofss
r_temp.segment = scriptState.xs->addr.pc.segment;
- if (s->resourceManager->sciVersion() >= SCI_VERSION_1_1) {
+ switch (s->detectLofsType()) {
+ case SCI_VERSION_1_1:
r_temp.offset = opparams[0] + local_script->script_size;
- } else {
- if (((SciEngine*)g_engine)->getKernel()->hasLofsAbsolute())
- r_temp.offset = opparams[0];
- else
- r_temp.offset = scriptState.xs->addr.pc.offset + opparams[0];
+ break;
+ case SCI_VERSION_1_MIDDLE:
+ r_temp.offset = opparams[0];
+ break;
+ default:
+ r_temp.offset = scriptState.xs->addr.pc.offset + opparams[0];
}
#ifndef DISABLE_VALIDATIONS
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index f828de42e7..f4bc0d142f 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -190,7 +190,6 @@ struct selector_map_t {
Selector flags;
Selector motionCue; /**< Used to determine if a game is using old gfx functions or not */
- Selector egoMoveSpeed; /**< Used to determine if a game is using absolute lofs parameters */
Selector points; /**< Used by AvoidPath() */
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index a0fad0adb2..9164e60108 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -136,7 +136,6 @@ Common::Error SciEngine::run() {
_kernel = new Kernel(_resourceManager);
_vocabulary = new Vocabulary(_resourceManager);
- script_adjust_opcode_formats(_resourceManager->sciVersion());
_gamestate = new EngineState(_resourceManager, flags);
@@ -149,6 +148,8 @@ Common::Error SciEngine::run() {
return Common::kUnknownError;
}
+ script_adjust_opcode_formats(_gamestate);
+
// Set the savegame dir (actually, we set it to a fake value,
// since we cannot let the game control where saves are stored)
script_set_gamestate_save_dir(_gamestate, "/");