aboutsummaryrefslogtreecommitdiff
path: root/engines/m4/script.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4/script.cpp')
-rw-r--r--engines/m4/script.cpp1406
1 files changed, 1406 insertions, 0 deletions
diff --git a/engines/m4/script.cpp b/engines/m4/script.cpp
new file mode 100644
index 0000000000..e7026a381d
--- /dev/null
+++ b/engines/m4/script.cpp
@@ -0,0 +1,1406 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/system.h"
+
+#include "m4/m4.h"
+#include "m4/script.h"
+#include "m4/resource.h"
+
+namespace M4 {
+
+enum OpcodeType {
+ opRet = 0,
+ opCall,
+ opCallKernel,
+ opPush,
+ opPush0,
+ opPush1,
+ opPushNeg1,
+ opPop,
+ opMov,
+ opAdd,
+ opSub,
+ opInc,
+ opDec,
+ opCmp,
+ opJmp,
+ opJmpByTable,
+ opJz,
+ opJnz,
+ opJe,
+ opJne,
+ opJl,
+ opJle,
+ opJg,
+ opJge,
+ opXor,
+ opShl,
+ opShr,
+
+ opDebug,
+
+ opInvalid
+};
+
+const char *opcodeNames[] = {
+ "opRet",
+ "opCall",
+ "opCallKernel",
+ "opPush",
+ "opPush0",
+ "opPush1",
+ "opPushNeg1",
+ "opPop",
+ "opMov",
+ "opAdd",
+ "opSub",
+ "opInc",
+ "opDec",
+ "opCmp",
+ "opJmp",
+ "opJmpByTable",
+ "opJz",
+ "opJnz",
+ "opJe",
+ "opJne",
+ "opJl",
+ "opJle",
+ "opJg",
+ "opJge",
+ "opXor",
+ "opShl",
+ "opShr",
+ "opDebug",
+ "opInvalid"
+};
+
+StringTable::StringTable() : _stringsData(NULL) {
+}
+
+StringTable::~StringTable() {
+ if (_stringsData)
+ delete[] _stringsData;
+}
+
+void StringTable::load(Common::File *fd) {
+ int stringSize = fd->readUint32LE();
+ int stringCount = fd->readUint32LE();
+ _stringsData = new char[stringSize];
+ fd->read(_stringsData, stringSize);
+ char *stringPtr = _stringsData;
+ for (int i = 0; i < stringCount; i++) {
+ _strings.push_back((const char*)stringPtr);
+ stringPtr += strlen(stringPtr) + 1;
+ }
+}
+
+SeriesStreamBreakList::~SeriesStreamBreakList() {
+}
+
+void SeriesStreamBreakList::load(Common::File *fd) {
+ uint32 count = fd->readUint32LE();
+ printf("SeriesStreamBreakList::load() count = %d\n", count);
+ for (uint32 i = 0; i < count; i++) {
+ SeriesStreamBreakItem *item = new SeriesStreamBreakItem();
+ item->frameNum = fd->readUint32LE();
+ item->digiName = _inter->loadGlobalString(fd);
+ item->digiChannel = fd->readUint32LE();
+ item->digiVolume = fd->readUint32LE();
+ item->trigger = fd->readUint32LE();
+ item->flags = fd->readUint32LE();
+ item->variable.type = kGameVar;
+ item->variable.value = fd->readUint32LE();
+ item->value = fd->readUint32LE();
+ _items.push_back(item);
+
+ printf("%02d: frameNum = %d; digiName = %s; digiChannel = %d; digiVolume = %d; trigger = %d; flags = %d; variable = %d; value = %d\n",
+ i, item->frameNum, item->digiName, item->digiChannel, item->digiVolume, item->trigger, item->flags, item->variable.value, item->value);
+
+ }
+}
+
+SaidArray::~SaidArray() {
+}
+
+void SaidArray::load(Common::File *fd) {
+ uint32 count = fd->readUint32LE();
+ printf("SaidArray::load() count = %d\n", count);
+ for (uint32 i = 0; i < count; i++) {
+ SaidArrayItem *item = new SaidArrayItem();
+ item->itemName = _inter->loadGlobalString(fd);
+ item->digiNameLook = _inter->loadGlobalString(fd);
+ item->digiNameTake = _inter->loadGlobalString(fd);
+ item->digiNameGear = _inter->loadGlobalString(fd);
+ _items.push_back(item);
+
+ printf("itemName = %s; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
+ item->itemName, item->digiNameLook, item->digiNameTake, item->digiNameGear);
+
+ }
+}
+
+ParserArray::~ParserArray() {
+}
+
+void ParserArray::load(Common::File *fd) {
+ uint32 count = fd->readUint32LE();
+ printf("ParserArray::load() count = %d\n", count);
+ for (uint32 i = 0; i < count; i++) {
+ ParserArrayItem *item = new ParserArrayItem();
+ item->w0 = _inter->loadGlobalString(fd);
+ item->w1 = _inter->loadGlobalString(fd);
+ item->trigger = fd->readUint32LE();
+ item->testVariable.type = kGameVar;
+ item->testVariable.value = fd->readUint32LE();
+ item->testValue = fd->readUint32LE();
+ item->variable.type = kGameVar;
+ item->variable.value = fd->readUint32LE();
+ item->value = fd->readUint32LE();
+ _items.push_back(item);
+
+ printf("w0 = %s; w1 = %s; trigger = %d; testVariable = %d; testValue = %d; variable = %d; value = %d\n",
+ item->w0, item->w1, item->trigger, item->testVariable.value, item->testValue, item->variable.value, item->value);
+
+ }
+}
+
+ScriptFunction::ScriptFunction(ScriptInterpreter *inter) : _inter(inter) {
+}
+
+ScriptFunction::~ScriptFunction() {
+ if (_code)
+ delete _code;
+}
+
+void ScriptFunction::load(Common::File *fd) {
+ printf("ScriptFunction::load()\n");
+ uint32 size = fd->readUint32LE();
+ printf("ScriptFunction::load() size = %d\n", size);
+ _code = fd->readStream(size);
+}
+
+void ScriptFunction::jumpAbsolute(uint32 ofs) {
+ _code->seek(ofs);
+}
+
+void ScriptFunction::jumpRelative(int32 ofs) {
+ _code->seek(ofs, SEEK_CUR);
+}
+
+byte ScriptFunction::readByte() {
+ return _code->readByte();
+}
+
+uint32 ScriptFunction::readUint32() {
+ return _code->readUint32LE();
+}
+
+
+ScriptInterpreter::ScriptInterpreter(M4Engine *vm) : _scriptFile(NULL), _vm(vm) {
+ initScriptKernel();
+ _dataCache = new ScriptDataCache(this);
+ _runningFunction = NULL;
+}
+
+ScriptInterpreter::~ScriptInterpreter() {
+ close();
+ delete _dataCache;
+}
+
+void ScriptInterpreter::open(const char *filename) {
+ if (_scriptFile)
+ close();
+ _scriptFile = new Common::File();
+ _scriptFile->open(filename);
+ if (!_scriptFile->isOpen())
+ error("ScriptInterpreter::open() Error opening %s.", filename);
+
+ _scriptFile->readUint32LE(); // skip magic for now
+ uint32 version = _scriptFile->readUint32LE();
+ if (version != kScriptFileVersion) {
+ error("ScriptInterpreter::open() DAT file version mismatch; requested %li, got %i\n", kScriptFileVersion, version);
+ }
+
+ int functionCount = _scriptFile->readUint32LE();
+ printf("functionCount = %d\n", functionCount);
+ for (int i = 0; i < functionCount; i++) {
+ uint32 offset = _scriptFile->readUint32LE();
+ printf("func(%d) offset = %08X\n", i, offset);
+ uint32 len = _scriptFile->readUint32LE();
+ if (len > 0) {
+ char *funcName = new char[len + 1];
+ _scriptFile->read(funcName, len);
+ funcName[len] = '\0';
+ printf("func(%d) name = %s\n", i, funcName);
+ _functionNames[Common::String(funcName)] = _functions.size();
+ // DEBUG
+ _scriptFunctionNames.push_back(Common::String(funcName));
+ delete[] funcName;
+ }
+ _functions.push_back(new ScriptFunctionEntry(offset));
+ }
+
+ int dataCount = _scriptFile->readUint32LE();
+ printf("dataCount = %d\n", dataCount);
+ for (int i = 0; i < dataCount; i++) {
+ uint32 offset = _scriptFile->readUint32LE();
+ ScriptDataType type = (ScriptDataType)_scriptFile->readUint32LE();
+ printf("data(%d) offset = %08X; type = %d\n", i, offset, type);
+ _data.push_back(new ScriptDataEntry(offset, type));
+ }
+
+ _globalVarCount = _scriptFile->readUint32LE();
+ printf("_globalVarCount = %d\n", _globalVarCount);
+
+ uint32 stringOfs = _scriptFile->readUint32LE();
+ _scriptFile->seek(stringOfs);
+ _constStrings.load(_scriptFile);
+
+ for (int i = 0; i < ARRAYSIZE(_globalVars); i++) {
+ _globalVars[i].type = kInteger;
+ _globalVars[i].value = 0;
+ }
+
+ memset(_logicGlobals, 0, sizeof(_logicGlobals));
+
+ memset(_registers, 0, sizeof(_registers));
+ memset(_stack, 0, sizeof(_stack));
+ _stackPtr = 0;
+
+}
+
+void ScriptInterpreter::close() {
+ if (_scriptFile) {
+ delete _scriptFile;
+ }
+}
+
+void ScriptInterpreter::initScriptKernel() {
+
+#include "m4/scripttab.h"
+
+ _kernelFunctions = kernelFunctions;
+ _kernelFunctionsMax = ARRAYSIZE(kernelFunctions) + 1;
+
+ _kernelVars = kernelVars;
+ _kernelVarsMax = ARRAYSIZE(kernelVars) + 1;
+
+}
+
+
+ScriptFunction *ScriptInterpreter::loadFunction(uint32 index) {
+ //GONE WHILE DEBUGGING assert(index < _functions.size());
+ if (index >= _functions.size()) return NULL;
+ ScriptFunction *scriptFunction;
+ scriptFunction = _functions[index]->func;
+ if (!scriptFunction) {
+ scriptFunction = new ScriptFunction(this);
+ _scriptFile->seek(_functions[index]->offset);
+ scriptFunction->load(_scriptFile);
+ _functions[index]->func = scriptFunction;
+ }
+ return scriptFunction;
+}
+
+ScriptFunction *ScriptInterpreter::loadFunction(const Common::String &name) {
+ FunctionNameMap::iterator iter = _functionNames.find(name);
+ if (iter == _functionNames.end()) {
+ printf("ScriptInterpreter::loadFunction() Function '%s' not found!\n", name.c_str());
+ return NULL;
+ }
+ uint32 funcIndex = (*iter)._value;
+ printf("ScriptInterpreter::loadFunction() index('%s') = %d\n", name.c_str(), funcIndex);
+ return loadFunction(funcIndex);
+}
+
+void ScriptInterpreter::unloadFunctions() {
+ for (uint32 i = 0; i < _functions.size(); i++) {
+ if (_functions[i]->func) {
+ delete _functions[i]->func;
+ _functions[i]->func = NULL;
+ }
+ }
+}
+
+int ScriptInterpreter::runFunction(ScriptFunction *scriptFunction) {
+ bool done = false;
+
+ int oldLocalStackPtr = _localStackPtr;
+ ScriptFunction *oldRunningFunction = _runningFunction;
+
+ // TODO: Also initialize _localStackPtr
+
+ _runningFunction = scriptFunction;
+ _runningFunction->jumpAbsolute(0);
+ while (!done) {
+ byte opcode = _runningFunction->readByte();
+ done = !execOpcode(opcode);
+ fflush(stdout);
+ }
+
+ _localStackPtr = oldLocalStackPtr;
+ _runningFunction = oldRunningFunction;
+
+ return 0;
+}
+
+void ScriptInterpreter::push(const ScriptValue &value) {
+ if (_stackPtr == ARRAYSIZE(_stack))
+ error("ScriptInterpreter::push() Stack overflow!\n");
+ _stack[_stackPtr++] = value;
+}
+
+void ScriptInterpreter::pop(ScriptValue &value) {
+ if (_stackPtr == 0)
+ error("ScriptInterpreter::pop() Stack underflow!\n");
+ value = _stack[_stackPtr--];
+}
+
+void ScriptInterpreter::dumpStack() {
+ printf("ScriptInterpreter::dumpStack()\n");
+ for (int i = 0; i < _stackPtr; i++) {
+ printf("%03d. type = %02d; value = %d\n", i, _stack[i].type, _stack[i].value);
+ }
+}
+
+void ScriptInterpreter::dumpRegisters() {
+ printf("ScriptInterpreter::dumpRegisters()\n");
+ for (int i = 0; i < ARRAYSIZE(_registers); i++) {
+ printf("%03d. type = %02d; value = %d\n", i, _registers[i].type, _registers[i].value);
+ }
+}
+
+void ScriptInterpreter::dumpGlobalVars() {
+ printf("ScriptInterpreter::dumpGlobalVars()\n");
+ for (int i = 0; i < ARRAYSIZE(_globalVars); i++) {
+ if (_globalVars[i].type != -1)
+ printf("%03d. type = %02d; value = %d\n", i, _globalVars[i].type, _globalVars[i].value);
+ }
+}
+
+int ScriptInterpreter::toInteger(const ScriptValue &value) {
+
+ switch (value.type) {
+
+ case kInteger:
+ return value.value;
+
+ default:
+ printf("ScriptInterpreter::toInteger() Invalid type %d!\n", value.type);
+ return 0;
+
+ }
+
+}
+
+const char *ScriptInterpreter::toString(const ScriptValue &value) {
+
+ switch (value.type) {
+
+ case kInteger:
+ return NULL;
+
+ case kConstString:
+ return _constStrings[value.value];
+
+ default:
+ printf("ScriptInterpreter::toString() Invalid type %d!\n", value.type);
+ return NULL;
+
+ }
+
+}
+
+const char *ScriptInterpreter::loadGlobalString(Common::File *fd) {
+ uint32 index = fd->readUint32LE();
+ if (index != 0xFFFFFFFF)
+ return getGlobalString(index);
+ else
+ return NULL;
+}
+
+void ScriptInterpreter::test() {
+}
+
+void ScriptInterpreter::loadValue(ScriptValue &value) {
+
+ value.type = (ScriptValueType)_runningFunction->readByte();
+
+ switch (value.type) {
+
+ case kGameVar:
+ case kInteger:
+ case kConstString:
+ case kDataRef:
+ case kLogicVar:
+ case kLogicVarRef:
+ case kKernelVar:
+ value.value = _runningFunction->readUint32();
+ break;
+
+ case kRegister:
+ value.value = _runningFunction->readByte();
+ break;
+
+ default:
+ printf("ScriptInterpreter::loadValue() Invalid value type %d!\n", value.type);
+
+ }
+
+}
+
+void ScriptInterpreter::copyValue(ScriptValue &destValue, ScriptValue &sourceValue) {
+
+ if (sourceValue.type == -1) {
+ printf("ScriptInterpreter::copyValue() Trying to read uninitialized value!\n");
+ }
+
+ switch (destValue.type) {
+
+ case kGameVar:
+ _globalVars[destValue.value] = sourceValue;
+ break;
+
+ case kRegister:
+ _registers[destValue.value] = sourceValue;
+ break;
+
+ case kLogicVar:
+ // TODO: Move to own method
+ if (sourceValue.type == kInteger) {
+ _logicGlobals[destValue.value] = sourceValue.value;
+ } else {
+ printf("ScriptInterpreter::copyValue() Invalid source value type %d!\n", sourceValue.type);
+ }
+ break;
+
+ case kKernelVar:
+ setKernelVar(destValue.value, sourceValue);
+ break;
+
+ default:
+ printf("ScriptInterpreter::copyValue() Invalid dest value type %d!\n", destValue.type);
+
+ }
+
+}
+
+void ScriptInterpreter::derefValue(ScriptValue &value) {
+
+ switch (value.type) {
+
+ case kGameVar:
+ value = _globalVars[value.value];
+ break;
+
+ case kInteger:
+ case kConstString:
+ case kDataRef:
+ case kLogicVarRef:
+ // These need no dereferencing
+ break;
+
+ case kRegister:
+ value = _registers[value.value];
+ break;
+
+ case kLogicVar:
+ // TODO: Move to own method
+ value = _logicGlobals[value.value];
+ break;
+
+ case kKernelVar:
+ getKernelVar(value.value, value);
+ break;
+
+ default:
+ printf("ScriptInterpreter::derefValue() Invalid value type %d!\n", value.type);
+
+ }
+
+}
+
+void ScriptInterpreter::callKernelFunction(uint32 index) {
+
+ printf("ScriptInterpreter::callKernelFunction() index = %d\n", index);
+
+ if (index > _kernelFunctionsMax) {
+ printf("ScriptInterpreter::callKernelFunction() Invalid kernel functionindex (%d)\n", index);
+ return;
+ }
+
+ printf("ScriptInterpreter::callKernelFunction() name = %s\n", _kernelFunctions[index].desc);
+
+ int args = (this->*(_kernelFunctions[index].proc))();
+ // Now remove values from the stack if the function used any
+ if (args > 4)
+ _stackPtr -= args - 4;
+
+ printf("-------------\n");
+
+}
+
+ScriptValue ScriptInterpreter::getArg(uint32 index) {
+ if (index < 4) {
+ return _registers[index];
+ } else {
+ index -= 4;
+ return _stack[_stackPtr - index - 1];
+ }
+}
+
+void ScriptInterpreter::dumpArgs(uint32 count) {
+ printf("ScriptInterpreter::dumpArgs() ");
+ for (uint32 i = 0; i < count; i++) {
+ ScriptValue argValue = getArg(i);
+ if (argValue.type == kConstString) {
+ printf("'%s'", toString(argValue));
+ } else {
+ printf("%d", argValue.value);
+ }
+ if (i + 1 < count)
+ printf(", ");
+ }
+ printf("\n");
+}
+
+void ScriptInterpreter::callFunction(uint32 index) {
+ // NOTE: This is a temporary hack for script functions not yet in the m4.dat
+ if (index == 0xFFFFFFFF)
+ return;
+ printf("ScriptInterpreter::callFunction() index = %d [%s]\n", index, _scriptFunctionNames[index].c_str());
+ fflush(stdout);
+ ScriptFunction *subFunction = loadFunction(index);
+ if (!subFunction) {
+ // This *should* never happen since the linker checks this
+ printf("ScriptInterpreter::callFunction() Function %d could not be loaded!\n", index);
+ return;
+ }
+ runFunction(subFunction);
+}
+
+bool ScriptInterpreter::execOpcode(byte opcode) {
+
+ printf("opcode = %d (%s)\n", opcode, opcodeNames[opcode]);
+
+ ScriptValue value1, value2, value3;
+ uint32 temp;
+
+ /* TODO: Put all opcodes into separate functions and into an array
+ (but only after all needed opcodes are known and frozen)
+ */
+
+ switch (opcode) {
+
+ case opRet:
+ return false;
+
+ case opPush:
+ loadValue(value1);
+ derefValue(value1);
+ push(value1);
+ return true;
+
+ case opPush0:
+ push(ScriptValue(0));
+ return true;
+
+ case opPush1:
+ push(ScriptValue(1));
+ return true;
+
+ case opPushNeg1:
+ push(ScriptValue(-1));
+ return true;
+
+ case opPop:
+ loadValue(value1);
+ pop(value2);
+ copyValue(value1, value2);
+ return true;
+
+ case opMov:
+ loadValue(value1);
+ loadValue(value2);
+ derefValue(value2);
+ copyValue(value1, value2);
+ return true;
+
+ // Possibly join all jump variants into one opcode
+
+ case opJmp:
+ temp = _runningFunction->readUint32();
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ return true;
+
+ case opJl:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags < 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJle:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags <= 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJg:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags > 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJge:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags >= 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJz:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags == 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJnz:
+ temp = _runningFunction->readUint32();
+ if (_cmpFlags != 0) {
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ }
+ return true;
+
+ case opJmpByTable:
+ temp = _runningFunction->readUint32();
+ printf("-> index = %d\n", _registers[0].value);
+ _runningFunction->jumpRelative(_registers[0].value * 4);
+ temp = _runningFunction->readUint32();
+ printf("-> ofs = %08X\n", temp);
+ _runningFunction->jumpAbsolute(temp);
+ return true;
+
+ case opCmp:
+ loadValue(value1);
+ loadValue(value2);
+ derefValue(value1);
+ derefValue(value2);
+ if (value1.type != kInteger || value2.type != kInteger)
+ warning("ScriptInterpreter::execOpcode() Trying to compare non-integer values (%d, %d, line %d)!\n", value1.type, value2.type, _lineNum);
+ _cmpFlags = value1.value - value2.value;
+ printf("-> cmp %d, %d\n", value1.value, value2.value);
+ printf("-> _cmpFlags = %d\n", _cmpFlags);
+ return true;
+
+ case opCall:
+ temp = _runningFunction->readUint32();
+ callFunction(temp);
+ return true;
+
+ case opCallKernel:
+ temp = _runningFunction->readUint32();
+ callKernelFunction(temp);
+ return true;
+
+ case opInc:
+ loadValue(value1);
+ value2 = value1;
+ derefValue(value2);
+ value2.value++;
+ copyValue(value1, value2);
+ return true;
+
+ case opDec:
+ loadValue(value1);
+ value2 = value1;
+ derefValue(value2);
+ value2.value--;
+ copyValue(value1, value2);
+ return true;
+
+ case opAdd:
+ loadValue(value1);
+ value3 = value1;
+ loadValue(value2);
+ derefValue(value3);
+ derefValue(value2);
+ value3.value += value2.value;
+ copyValue(value1, value3);
+ return true;
+
+ case opSub:
+ loadValue(value1);
+ value3 = value1;
+ loadValue(value2);
+ derefValue(value3);
+ derefValue(value2);
+ value3.value -= value2.value;
+ copyValue(value1, value3);
+ return true;
+
+ case opDebug:
+ _lineNum = (int)_runningFunction->readUint32();
+ return true;
+
+ default:
+ printf("Invalid opcode %d!\n", opcode);
+ return false;
+
+ }
+
+ return false;
+
+}
+
+// Kernel functions
+
+#define STRING(arg) (toString(getArg(arg)))
+#define INTEGER(arg) (toInteger(getArg(arg)))
+#define DATA(arg, T) (toData<T>(getArg(arg)))
+#define RETURN(value) (_registers[0] = (value))
+
+int ScriptInterpreter::o1_handleStreamBreak() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_handlePlayBreak() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_dispatchTriggerOnSoundState() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_getTicks() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_setSoundVolume() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_getSoundStatus() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_getSoundDuration() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_setSeriesFrameRate() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_terminateMachine() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_sendWoodScriptMessage() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_runConversation() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_exportConversationValue() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_exportConversationPointer() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_playBreakSeries() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_hideWalker() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_showWalker() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_walk() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_overrideCrunchTime() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_addBlockingRect() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_setPlayerCommandsAllowed() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_getPlayerCommandsAllowed() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_setPlayerFacingAngle() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_disablePlayerFadeToBlack() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_enablePlayer() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_disablePlayer() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_freshenSentence() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_playerGiveItem() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_moveObject() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_setStopSoundsBetweenRooms() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_backupPalette() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_unloadWilburWalker() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_wilburTalk() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_wilburFinishedTalking() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_preloadSound() {
+ const char *name = STRING(0);
+ int room = INTEGER(1);
+ printf("name = %s; room = %d\n", name, room);
+ return 2;
+}
+
+int ScriptInterpreter::o1_unloadSound() {
+ const char *name = STRING(0);
+ int room = INTEGER(1);
+ printf("name = %s; room = %d\n", name, room);
+ return 2;
+}
+
+int ScriptInterpreter::o1_playSound() {
+ const char *name = STRING(0);
+ int channel = INTEGER(1);
+ int volume = INTEGER(2);
+ int trigger = INTEGER(3);
+ int room = INTEGER(4);
+ printf("name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
+ name, channel, volume, trigger, room);
+
+ Common::String soundName = Common::String(name) + ".raw";
+ _vm->_sound->playVoice(soundName.c_str(), 100);
+
+ // HACK until fixed
+ _vm->_kernel->sendTrigger(trigger);
+
+ return 5;
+}
+
+int ScriptInterpreter::o1_playLoopingSound() {
+ const char *name = STRING(0);
+ int channel = INTEGER(1);
+ int volume = INTEGER(2);
+ int trigger = INTEGER(3);
+ int room = INTEGER(4);
+ printf("name = %s; channel = %d; volume = %d; trigger = %d; room = %d\n",
+ name, channel, volume, trigger, room);
+
+ // HACK until fixed
+ _vm->_kernel->sendTrigger(trigger);
+
+ return 5;
+}
+
+int ScriptInterpreter::o1_stopSound() {
+ int channel = INTEGER(0);
+ printf("channel = %d\n", channel);
+ return 1;
+}
+
+int ScriptInterpreter::o1_fadeSetStart() {
+ // skip arg 0: palette ptr
+ int percent = INTEGER(1);
+ printf("percent = %d\n", percent);
+ return 2;
+}
+
+int ScriptInterpreter::o1_fadeInit() {
+ // skip arg 0: palette ptr
+ int first = INTEGER(1);
+ int last = INTEGER(2);
+ int percent = INTEGER(3);
+ int ticks = INTEGER(4);
+ int trigger = INTEGER(5);
+ printf("first = %d; last = %d; percent = %d; ticks = %d; trigger = %d\n",
+ first, last, percent, ticks, trigger);
+
+ // HACK until palette fading is implemented
+ _vm->_kernel->sendTrigger(trigger);
+
+ return 6;
+}
+
+int ScriptInterpreter::o1_fadeToBlack() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_initPaletteCycle() {
+ int first = INTEGER(0);
+ int last = INTEGER(1);
+ int delay = INTEGER(2);
+ int ticks = INTEGER(3);
+ int trigger = INTEGER(4);
+ printf("first = %d; last = %d; delay = %d; ticks = %d; trigger = %d\n",
+ first, last, delay, ticks, trigger);
+
+ // HACK until palette cycling is implemented
+ _vm->_kernel->sendTrigger(trigger);
+
+ return 5;
+}
+
+int ScriptInterpreter::o1_stopPaletteCycle() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_hasPlayerSaid() {
+ const char *words[3];
+ for (int i = 0; i < 3; i++)
+ words[i] = STRING(i);
+ printf("'%s', '%s', '%s'\n", words[0], words[1], words[2]);
+
+ int result = _vm->_player->said(words[0], words[1], words[2]);
+
+ printf(" -> '%d'\n", result);
+ fflush(stdout);
+
+ RETURN(result);
+ return 3;
+}
+
+int ScriptInterpreter::o1_hasPlayerSaidAny() {
+ const char *words[10];
+ for (int i = 0; i < 10; i++)
+ words[i] = STRING(i);
+
+ printf("'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'\n",
+ words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
+
+ int result = _vm->_player->saidAny(words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
+ printf(" -> '%d'\n", result);
+ fflush(stdout);
+
+ RETURN(result);
+ return 10;
+}
+
+int ScriptInterpreter::o1_updatePlayerInfo() {
+ // skip arg 0: player info struct
+ return 1;
+}
+
+int ScriptInterpreter::o1_playerHotspotWalkOverride() {
+ int x1 = INTEGER(0);
+ int y1 = INTEGER(1);
+ int x2 = INTEGER(2);
+ int y2 = INTEGER(3);
+ printf("(%d, %d); (%d, %d)\n", x1, y1, x2, y2);
+ return 4;
+}
+
+int ScriptInterpreter::o1_playerHasItem() {
+ const char *name = STRING(0);
+ printf("item = '%s'\n", name);
+ // TODO
+ RETURN(0);
+ return 1;
+}
+
+int ScriptInterpreter::o1_setWalkerLocation() {
+ // skip arg 0: walker
+ int x = INTEGER(1);
+ int y = INTEGER(2);
+ printf("x = %d; y = %d\n", x, y);
+ return 3;
+}
+
+int ScriptInterpreter::o1_setWalkerFacing() {
+ // skip arg 0: walker
+ int facing = INTEGER(1);
+ printf("facing = %d\n", facing);
+ return 2;
+}
+
+int ScriptInterpreter::o1_setHotspot() {
+ // skip arg 0: hotspot list
+ const char *name = STRING(1);
+ int value = INTEGER(2);
+ printf("name = '%s' -> %d\n", name, value);
+
+ _vm->_scene->getSceneResources().hotspots->setActive(name, (value != 0));
+
+ return 2;
+}
+
+int ScriptInterpreter::o1_loadConversation() {
+ const char *name = STRING(0);
+ int trigger = INTEGER(1);
+ int flag = INTEGER(2);
+
+ // TODO; just to show something
+ _vm->_converse->startConversation(name);
+
+ return 3;
+}
+
+int ScriptInterpreter::o1_playSeries() {
+ const char *name = STRING(0);
+ int layer = INTEGER(1);
+ int flags = INTEGER(2);
+ int trigger = INTEGER(3);
+ int frameRate = INTEGER(4);
+ int loopCount = INTEGER(5);
+ int scale = INTEGER(6);
+ int x = INTEGER(7);
+ int y = INTEGER(8);
+ int firstFrame = INTEGER(9);
+ int lastFrame = INTEGER(10);
+
+ printf("name = %s; layer = %04X; flags = %08X; trigger = %d; frameRate = %d; loopCount = %d; scale = %d; x = %d; y = %d: firstFrame = %d; lastFrame = %d\n",
+ name, layer, flags, trigger, frameRate, loopCount, scale, x, y, firstFrame, lastFrame);
+ fflush(stdout);
+
+ // TODO: Return the machine to the script
+ _vm->_ws->playSeries(name, layer, flags, trigger, frameRate, loopCount, scale, x, y, firstFrame, lastFrame);
+
+ return 11;
+}
+
+int ScriptInterpreter::o1_showSeries() {
+ const char *name = STRING(0);
+ int layer = INTEGER(1);
+ int flags = INTEGER(2);
+ int trigger = INTEGER(3);
+ int duration = INTEGER(4);
+ int frameIndex = INTEGER(5);
+ int scale = INTEGER(6);
+ int x = INTEGER(7);
+ int y = INTEGER(8);
+
+ printf("name = %s; layer = %04X; flags = %08X; trigger = %d; duration = %d; frameIndex = %d; scale = %d; x = %d; y = %d\n",
+ name, layer, flags, trigger, duration, frameIndex, scale, x, y);
+ fflush(stdout);
+
+ // TODO: Return the machine to the script
+ _vm->_ws->showSeries(name, layer, flags, trigger, duration, frameIndex, scale, x, y);
+
+ return 9;
+}
+
+int ScriptInterpreter::o1_loadSeries() {
+ const char *name = STRING(0);
+ int hash = INTEGER(1);
+ // skip arg 3: palette ptr
+
+ printf("name = %s; hash = %d\n", name, hash);
+ fflush(stdout);
+
+ int result = _vm->_ws->loadSeries(name, hash, NULL);
+
+ RETURN(result);
+ return 3;
+}
+
+int ScriptInterpreter::o1_unloadSeries() {
+ return 0;
+}
+
+int ScriptInterpreter::o1_preloadBreakSeries() {
+ const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
+ return 1;
+}
+
+int ScriptInterpreter::o1_unloadBreakSeries() {
+ const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
+ return 1;
+}
+
+int ScriptInterpreter::o1_startBreakSeries() {
+ const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
+ return 1;
+}
+
+int ScriptInterpreter::o1_globalTriggerProc() {
+ int value1 = INTEGER(0);
+ int value2 = INTEGER(1);
+ int value3 = INTEGER(2);
+ printf("%d; %d; %d\n", value1, value2, value3);
+ return 3;
+}
+
+int ScriptInterpreter::o1_triggerTimerProc() {
+ int value1 = INTEGER(0);
+ int value2 = INTEGER(1);
+ int value3 = INTEGER(2);
+ printf("%d; %d; %d\n", value1, value2, value3);
+ return 3;
+}
+
+int ScriptInterpreter::o1_dispatchTrigger() {
+ int trigger = INTEGER(0);
+ printf("trigger = %d\n", trigger);
+
+ _vm->_kernel->sendTrigger(trigger);
+ //g_system->delayMillis(5000);
+
+ return 1;
+}
+
+int ScriptInterpreter::o1_getRangedRandomValue() {
+ int minValue = INTEGER(0);
+ int maxValue = INTEGER(1);
+ RETURN(_vm->imath_ranged_rand(minValue, maxValue));
+ return 2;
+}
+
+int ScriptInterpreter::o1_wilburSaid() {
+ const SaidArray& saidArray = DATA(0, SaidArray);
+
+ int result = 0;
+
+ // NOTE: The "Common::String soundName" stuff is just temporary until playVoice is fixed.
+
+ for (int i = 0; i < saidArray.size(); i++) {
+ SaidArrayItem *item = saidArray[i];
+
+ if (_vm->_player->said("LOOK AT", item->itemName) && item->digiNameLook) {
+ printf(" -> LOOK AT: '%s'\n", item->digiNameLook);
+ Common::String soundName = Common::String(item->digiNameLook) + ".raw";
+ _vm->_sound->playVoice(soundName.c_str(), 100);
+ result = 1;
+ break;
+ }
+
+ if (_vm->_player->said("TAKE", item->itemName) && item->digiNameTake) {
+ printf(" -> TAKE: '%s'\n", item->digiNameTake);
+ Common::String soundName = Common::String(item->digiNameTake) + ".raw";
+ _vm->_sound->playVoice(soundName.c_str(), 100);
+ result = 1;
+ break;
+ }
+
+ if (_vm->_player->said("GEAR", item->itemName) && item->digiNameGear) {
+ printf(" -> GEAR: '%s'\n", item->digiNameGear);
+ Common::String soundName = Common::String(item->digiNameGear) + ".raw";
+ _vm->_sound->playVoice(soundName.c_str(), 100);
+ result = 1;
+ break;
+ }
+
+ /*
+ printf("##### itemName = '%s'; digiNameLook = %s; digiNameTake = %s; digiNameGear = %s\n",
+ item->itemName, item->digiNameLook, item->digiNameTake, item->digiNameGear);
+ */
+ }
+ printf(" -> '%d'\n", result);
+ fflush(stdout);
+
+ RETURN(result);
+ return 1;
+}
+
+int ScriptInterpreter::o1_wilburParse() {
+ const ParserArray& parserArray = DATA(0, ParserArray);
+ RETURN(0);
+ return 1;
+}
+
+int ScriptInterpreter::o1_wilburSpeech() {
+ const char *name = STRING(0);
+ int trigger = INTEGER(1);
+ int room = INTEGER(2);
+ int flag = INTEGER(3);
+ int volume = INTEGER(4);
+ int slot = INTEGER(5);
+
+ printf("%s; %d; %d; %d; %d; %d\n", name, trigger, room, flag, volume, slot);
+ fflush(stdout);
+ //g_system->delayMillis(5000);
+
+ KernelTriggerType oldTriggerMode = _vm->_kernel->triggerMode;
+
+ // TODO
+ Common::String soundName = Common::String(name) + ".raw";
+ _vm->_sound->playVoice(soundName.c_str(), 100);
+
+ _vm->_kernel->triggerMode = oldTriggerMode;
+
+ return 6;
+}
+
+// Kernel vars
+
+void ScriptInterpreter::getKernelVar(int index, ScriptValue &value) {
+
+ printf("ScriptInterpreter::getKernelVar() index = %d\n", index);
+
+ if (index > _kernelVarsMax) {
+ printf("ScriptInterpreter::getKernelVar() Invalid kernel var index %d!\n", index);
+ return;
+ }
+
+ printf("ScriptInterpreter::getKernelVar() name = %s\n", _kernelVars[index].desc);
+
+ ScriptKernelVariable var = _kernelVars[index].var;
+
+ switch (var) {
+
+ case kKernelTrigger:
+ value = _vm->_kernel->trigger;
+ break;
+
+ case kKernelTriggerMode:
+ value = (int)_vm->_kernel->triggerMode;
+ break;
+
+ case kKernelContinueHandlingTrigger:
+ value = (int)_vm->_kernel->daemonTriggerAvailable;
+ break;
+
+ case kGameVersion:
+ // TODO
+ value = 0;
+ break;
+
+ case kGameLanguage:
+ // TODO
+ value = 0;
+ break;
+
+ case kGameNewRoom:
+ // TODO
+ value = 0;
+ break;
+
+ case kPlayerCommandReady:
+ value = (int)_vm->_player->commandReady;
+ break;
+
+ default:
+ printf("ScriptInterpreter::getKernelVar() Invalid kernel var %d!\n", var);
+ //g_system->delayMillis(2000);
+
+ }
+
+}
+
+void ScriptInterpreter::setKernelVar(int index, const ScriptValue &value) {
+
+ printf("ScriptInterpreter::setKernelVar() index = %d\n", index);
+
+ if (index > _kernelVarsMax) {
+ printf("ScriptInterpreter::setKernelVar() Invalid kernel var index %d!\n", index);
+ return;
+ }
+
+ printf("ScriptInterpreter::setKernelVar() name = %s\n", _kernelVars[index].desc);
+
+ ScriptKernelVariable var = _kernelVars[index].var;
+
+ switch (var) {
+
+ case kKernelTrigger:
+ _vm->_kernel->trigger = toInteger(value);
+ printf("kKernelTrigger -> %d\n", toInteger(value));
+ break;
+
+ case kKernelTriggerMode:
+ _vm->_kernel->triggerMode = (KernelTriggerType)toInteger(value);
+ printf("kKernelTrigger -> %d\n", toInteger(value));
+ break;
+
+ case kKernelContinueHandlingTrigger:
+ _vm->_kernel->daemonTriggerAvailable = (toInteger(value) != 0);
+ printf("kKernelContinueHandlingTrigger -> %d\n", toInteger(value));
+ break;
+
+ case kGameNewRoom:
+ _vm->_kernel->newRoom = toInteger(value);
+ printf("kGameNewRoom -> %d\n", toInteger(value));
+ break;
+
+ case kPlayerCommandReady:
+ // TODO
+ printf("kPlayerCommandReady -> %d\n", toInteger(value));
+ break;
+
+ default:
+ printf("ScriptInterpreter::setKernelVar() Invalid kernel var %d!\n", var);
+ //g_system->delayMillis(2000);
+
+ }
+
+}
+
+} // End of namespace M4