DIRECTOR: LINGO: Add split contexts for main and shared archives

This commit is contained in:
Scott Percival 2020-02-09 00:34:28 +08:00
parent 3c0be1d7a6
commit 189acb438d
7 changed files with 64 additions and 33 deletions

View File

@ -336,7 +336,7 @@ void LC::cb_list() {
void LC::cb_call() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Datum nargs = g_lingo->pop();
if ((nargs.type == ARGC) || (nargs.type == ARGCNORET)) {
@ -351,7 +351,7 @@ void LC::cb_call() {
void LC::cb_globalpush() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Datum result;
result.type = VOID;
@ -374,7 +374,7 @@ void LC::cb_globalpush() {
void LC::cb_globalassign() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Symbol *s = g_lingo->lookupVar(name.c_str(), false);
if (!s) {
@ -397,7 +397,7 @@ void LC::cb_globalassign() {
void LC::cb_objectpush() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
warning("STUB: cb_objectpush(%s)", name.c_str());
Datum result;
result.type = VOID;
@ -407,7 +407,7 @@ void LC::cb_objectpush() {
void LC::cb_varpush() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Datum result;
result.type = VOID;
@ -430,7 +430,7 @@ void LC::cb_varpush() {
void LC::cb_varassign() {
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Symbol *s = g_lingo->lookupVar(name.c_str(), false);
if (!s) {
@ -519,7 +519,7 @@ void LC::cb_v4theentitynamepush() {
}
int nameId = g_lingo->readInt();
Common::String name = g_lingo->_namelist[nameId];
Common::String name = g_lingo->getName(nameId);
Datum id;
id.u.s = NULL;
@ -618,7 +618,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
_currentScriptContext = new ScriptContext;
_currentScriptType = type;
_currentEntityId = id;
_scriptContexts[type][id] = _currentScriptContext;
_archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext;
if (stream.size() < 0x5c) {
warning("Lscr header too small");
@ -667,8 +667,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
stream.seek(globalsOffset);
for (uint16 i = 0; i < globalsCount; i++) {
uint16 index = stream.readUint16();
if (index < _namelist.size()) {
const char *name = _namelist[index].c_str();
if (index < _archives[_archiveIndex].names.size()) {
const char *name = _archives[_archiveIndex].names[index].c_str();
debugC(5, kDebugLoading, "%d: %s", i, name);
g_lingo->lookupVar(name, true, true);
} else {
@ -866,8 +866,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]);
namePointer += 2;
Common::String name;
if (index < _namelist.size()) {
name = _namelist[index];
if (index < _archives[_archiveIndex].names.size()) {
name = _archives[_archiveIndex].names[index];
argMap[j] = index;
} else {
name = Common::String::format("arg_%d", j);
@ -892,8 +892,8 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
uint16 index = (uint16)READ_BE_UINT16(&codeStore[namePointer]);
namePointer += 2;
Common::String name;
if (index < _namelist.size()) {
name = _namelist[index];
if (index < _archives[_archiveIndex].names.size()) {
name = _archives[_archiveIndex].names[index];
varMap[j] = index;
} else {
name = Common::String::format("var_%d", j);
@ -1081,9 +1081,9 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
// Attach to handlers
Symbol *sym = NULL;
if (nameIndex < _namelist.size()) {
debugC(5, kDebugLoading, "Function %d binding: %s()", i, _namelist[nameIndex].c_str());
sym = g_lingo->define(_namelist[nameIndex], argCount, _currentScript);
if (nameIndex < _archives[_archiveIndex].names.size()) {
debugC(5, kDebugLoading, "Function %d binding: %s()", i, _archives[_archiveIndex].names[nameIndex].c_str());
sym = g_lingo->define(_archives[_archiveIndex].names[nameIndex], argCount, _currentScript);
} else {
warning("Function has unknown name id %d, skipping define", nameIndex);
sym = new Symbol;
@ -1095,6 +1095,7 @@ void Lingo::addCodeV4(Common::SeekableSubReadStreamEndian &stream, ScriptType ty
sym->argNames = argNames;
sym->varNames = varNames;
sym->ctx = _currentScriptContext;
sym->archiveIndex = _archiveIndex;
_currentScriptContext->functions.push_back(sym);
}
@ -1135,7 +1136,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) {
stream.seek(offset);
_namelist.clear();
_archives[_archiveIndex].names.clear();
Common::Array<Common::String> names;
for (uint32 i = 0; i < count; i++) {
@ -1144,7 +1145,7 @@ void Lingo::addNamesV4(Common::SeekableSubReadStreamEndian &stream) {
for (uint8 j = 0; j < size; j++) {
name += stream.readByte();
}
_namelist.push_back(name);
_archives[_archiveIndex].names.push_back(name);
debugC(5, kDebugLoading, "%d: \"%s\"", i, name.c_str());
}

View File

@ -270,7 +270,7 @@ void LC::c_symbolpush() {
void LC::c_namepush() {
Datum d;
int i = g_lingo->readInt();
g_lingo->push(Datum(new Common::String(g_lingo->_namelist[i])));
g_lingo->push(Datum(new Common::String(g_lingo->getName(i))));
}
void LC::c_argcpush() {
@ -1310,6 +1310,7 @@ void LC::call(Symbol *sym, int nargs) {
fp->retpc = g_lingo->_pc;
fp->retscript = g_lingo->_currentScript;
fp->retctx = g_lingo->_currentScriptContext;
fp->retarchive = g_lingo->_archiveIndex;
fp->localvars = g_lingo->_localvars;
// Create new set of local variables
@ -1356,6 +1357,9 @@ void LC::call(Symbol *sym, int nargs) {
if (sym->ctx) {
g_lingo->_currentScriptContext = sym->ctx;
}
if (sym->archiveIndex) {
g_lingo->_archiveIndex = sym->archiveIndex;
}
g_lingo->execute(0);
@ -1376,6 +1380,7 @@ void LC::c_procret() {
g_lingo->_currentScript = fp->retscript;
g_lingo->_currentScriptContext = fp->retctx;
g_lingo->_archiveIndex = fp->retarchive;
g_lingo->_pc = fp->retpc;
g_lingo->cleanLocalVars();

View File

@ -275,6 +275,7 @@ Symbol *Lingo::define(Common::String &name, int nargs, ScriptData *code) {
sym->argNames = NULL;
sym->varNames = NULL;
sym->ctx = NULL;
sym->archiveIndex = -1;
if (debugChannelSet(1, kDebugLingoCompile)) {
uint pc = 0;

View File

@ -200,8 +200,8 @@ void Lingo::runMovieScript(LEvent event) {
if (_dontPassEvent)
return;
for (ScriptContextHash::iterator it = _scriptContexts[kMovieScript].begin();
it != _scriptContexts[kMovieScript].end(); ++it) {
for (ScriptContextHash::iterator it = _archives[_archiveIndex].scriptContexts[kMovieScript].begin();
it != _archives[_archiveIndex].scriptContexts[kMovieScript].end(); ++it) {
processEvent(event, kMovieScript, it->_key);
// TODO: How do know which script handles the message?
}
@ -319,7 +319,7 @@ void Lingo::processEvent(LEvent event, ScriptType st, int entityId) {
if (_handlers.contains(ENTITY_INDEX(event, entityId))) {
debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %d), _eventHandler", _eventHandlerTypes[event], scriptType2str(st), entityId);
executeHandler(_eventHandlerTypes[event]); // D4+ Events
} else if (_vm->getVersion() < 4 && event == kEventNone && _scriptContexts[st].contains(entityId)) {
} else if (_vm->getVersion() < 4 && event == kEventNone && getScriptContext(st, entityId)) {
debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %d), script", _eventHandlerTypes[event], scriptType2str(st), entityId);
executeScript(st, entityId, 0); // D3 list of scripts.

View File

@ -75,6 +75,8 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
_dontPassEvent = false;
_archiveIndex = 0;
initEventHandlerTypes();
initBuiltIns();
@ -89,13 +91,23 @@ Lingo::~Lingo() {
}
ScriptContext *Lingo::getScriptContext(ScriptType type, uint16 id) {
if (type >= (int)_scriptContexts->size()) {
if (type >= (int)_archives[_archiveIndex].scriptContexts->size()) {
return NULL;
}
if (!_scriptContexts[type].contains(id)) {
if (!_archives[_archiveIndex].scriptContexts[type].contains(id)) {
return NULL;
}
return _scriptContexts[type][id];
return _archives[_archiveIndex].scriptContexts[type][id];
}
Common::String Lingo::getName(uint16 id) {
Common::String result;
if (id >= _archives[_archiveIndex].names.size()) {
warning("Name id %d not in list", id);
return result;
}
result = _archives[_archiveIndex].names[id];
return result;
}
const char *Lingo::findNextDefinition(const char *s) {
@ -149,7 +161,7 @@ void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
_currentScriptContext = new ScriptContext;
_currentScriptType = type;
_currentEntityId = id;
_scriptContexts[type][id] = _currentScriptContext;
_archives[_archiveIndex].scriptContexts[type][id] = _currentScriptContext;
// FIXME: unpack into seperate functions
_currentScriptFunction = 0;
@ -272,14 +284,14 @@ void Lingo::restartLingo() {
warning("STUB: restartLingo()");
for (int i = 0; i <= kMaxScriptType; i++) {
for (ScriptContextHash::iterator it = _scriptContexts[i].begin(); it != _scriptContexts[i].end(); ++it) {
for (ScriptContextHash::iterator it = _archives[_archiveIndex].scriptContexts[i].begin(); it != _archives[_archiveIndex].scriptContexts[i].end(); ++it) {
for (size_t j = 0; j < it->_value->functions.size(); j++) {
delete it->_value->functions[j];
}
delete it->_value;
}
_scriptContexts[i].clear();
_archives[_archiveIndex].scriptContexts[i].clear();
}
// TODO

View File

@ -88,6 +88,7 @@ struct Symbol { /* symbol table entry */
Common::Array<Common::String> *argNames;
Common::Array<Common::String> *varNames;
ScriptContext *ctx; /* optional script context to execute with */
int archiveIndex; /* optional archive to execute with */
Symbol();
};
@ -140,9 +141,17 @@ struct CFrame { /* proc/func call stack frame */
int retpc; /* where to resume after return */
ScriptData *retscript; /* which script to resume after return */
ScriptContext *retctx; /* which script context to use after return */
int retarchive; /* which archive to use after return */
SymbolHash *localvars;
};
struct LingoArchive {
ScriptContextHash scriptContexts[kMaxScriptType + 1];
Common::Array<Common::String> names;
};
class Lingo {
public:
@ -182,9 +191,10 @@ private:
void runMovieScript(LEvent event);
void processSpriteEvent(LEvent event);
void processEvent(LEvent event, ScriptType st, int entityId);
ScriptContext *getScriptContext(ScriptType type, uint16 id);
public:
ScriptContext *getScriptContext(ScriptType type, uint16 id);
Common::String getName(uint16 id);
ScriptType event2script(LEvent ev);
Symbol *getHandler(Common::String &name);
@ -304,7 +314,6 @@ public:
int _objectEntityId;
Common::Array<int> _labelstack;
Common::Array<Common::String> _namelist;
SymbolHash _builtins;
Common::HashMap<Common::String, bool> _twoWordBuiltins;
@ -341,8 +350,6 @@ public:
Common::HashMap<Common::String, uint32, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _eventHandlerTypeIds;
Common::HashMap<Common::String, Audio::AudioStream *> _audioAliases;
ScriptContextHash _scriptContexts[kMaxScriptType + 1];
SymbolHash _globalvars;
SymbolHash *_localvars;
@ -351,6 +358,9 @@ public:
Common::HashMap<int, LingoV4Bytecode *> _lingoV4;
Common::HashMap<int, LingoV4TheEntity *> _lingoV4TheEntity;
LingoArchive _archives[2];
int _archiveIndex;
uint _pc;
StackData _stack;

View File

@ -305,6 +305,7 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
debug(0, "@@@@ Loading Shared cast '%s'", filename.c_str());
debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
_lingo->_archiveIndex = 1;
_sharedScore = new Score(this);
_sharedScore->setArchive(sharedCast);
@ -409,6 +410,7 @@ void DirectorEngine::loadSharedCastsFrom(Common::String filename) {
}
_sharedScore->loadSpriteImages(true);
_lingo->_archiveIndex = 0;
}
} // End of namespace Director