mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-24 13:13:58 +00:00
SCI: Add lofs detection.
svn-id: r43824
This commit is contained in:
parent
dceadc9ba0
commit
3e543d2518
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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() */
|
||||
|
||||
|
@ -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, "/");
|
||||
|
Loading…
x
Reference in New Issue
Block a user