2008-04-20 14:47:37 +00:00
|
|
|
/* 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,
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
opDebug,
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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())
|
2009-05-31 10:02:16 +00:00
|
|
|
error("ScriptInterpreter::open() Error opening %s", filename);
|
2008-04-20 14:47:37 +00:00
|
|
|
|
|
|
|
_scriptFile->readUint32LE(); // skip magic for now
|
|
|
|
uint32 version = _scriptFile->readUint32LE();
|
|
|
|
if (version != kScriptFileVersion) {
|
2009-05-31 10:02:16 +00:00
|
|
|
error("ScriptInterpreter::open() DAT file version mismatch; requested %li, got %i", kScriptFileVersion, version);
|
2008-04-20 14:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
_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);
|
|
|
|
}
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
_localStackPtr = oldLocalStackPtr;
|
|
|
|
_runningFunction = oldRunningFunction;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptInterpreter::push(const ScriptValue &value) {
|
|
|
|
if (_stackPtr == ARRAYSIZE(_stack))
|
2009-05-31 10:02:16 +00:00
|
|
|
error("ScriptInterpreter::push() Stack overflow");
|
2008-04-20 14:47:37 +00:00
|
|
|
_stack[_stackPtr++] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptInterpreter::pop(ScriptValue &value) {
|
|
|
|
if (_stackPtr == 0)
|
2009-05-31 10:02:16 +00:00
|
|
|
error("ScriptInterpreter::pop() Stack underflow");
|
2008-04-20 14:47:37 +00:00
|
|
|
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];
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
default:
|
|
|
|
printf("ScriptInterpreter::toString() Invalid type %d!\n", value.type);
|
|
|
|
return NULL;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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
|
2009-03-07 19:24:31 +00:00
|
|
|
if (args > 4)
|
2008-04-20 14:47:37 +00:00
|
|
|
_stackPtr -= args - 4;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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)
|
2009-05-31 10:02:16 +00:00
|
|
|
warning("ScriptInterpreter::execOpcode() Trying to compare non-integer values (%d, %d, line %d)", value1.type, value2.type, _lineNum);
|
2008-04-20 14:47:37 +00:00
|
|
|
_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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
Common::String soundName = Common::String(name) + ".raw";
|
|
|
|
_vm->_sound->playVoice(soundName.c_str(), 100);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
// HACK until fixed
|
|
|
|
_vm->_kernel->sendTrigger(trigger);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
// HACK until palette fading is implemented
|
|
|
|
_vm->_kernel->sendTrigger(trigger);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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]);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
int result = _vm->_player->said(words[0], words[1], words[2]);
|
|
|
|
|
|
|
|
printf(" -> '%d'\n", result);
|
|
|
|
fflush(stdout);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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]);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
_vm->_scene->getSceneResources().hotspots->setActive(name, (value != 0));
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_loadConversation() {
|
|
|
|
const char *name = STRING(0);
|
2008-04-20 17:26:48 +00:00
|
|
|
//int trigger = INTEGER(1);
|
|
|
|
//int flag = INTEGER(2);
|
2008-04-20 14:47:37 +00:00
|
|
|
|
|
|
|
// TODO; just to show something
|
|
|
|
_vm->_converse->startConversation(name);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
int result = _vm->_ws->loadSeries(name, hash, NULL);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
RETURN(result);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_unloadSeries() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_preloadBreakSeries() {
|
2008-04-20 17:26:48 +00:00
|
|
|
//const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
|
2008-04-20 14:47:37 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_unloadBreakSeries() {
|
2008-04-20 17:26:48 +00:00
|
|
|
//const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
|
2008-04-20 14:47:37 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_startBreakSeries() {
|
2008-04-20 17:26:48 +00:00
|
|
|
//const SeriesStreamBreakList& seriesStreamBreakList = DATA(0, SeriesStreamBreakList);
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
_vm->_kernel->sendTrigger(trigger);
|
|
|
|
//g_system->delayMillis(5000);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
// NOTE: The "Common::String soundName" stuff is just temporary until playVoice is fixed.
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
RETURN(result);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ScriptInterpreter::o1_wilburParse() {
|
2008-04-20 17:26:48 +00:00
|
|
|
//const ParserArray& parserArray = DATA(0, ParserArray);
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
KernelTriggerType oldTriggerMode = _vm->_kernel->triggerMode;
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
Common::String soundName = Common::String(name) + ".raw";
|
|
|
|
_vm->_sound->playVoice(soundName.c_str(), 100);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
_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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
if (index > _kernelVarsMax) {
|
|
|
|
printf("ScriptInterpreter::setKernelVar() Invalid kernel var index %d!\n", index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("ScriptInterpreter::setKernelVar() name = %s\n", _kernelVars[index].desc);
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
ScriptKernelVariable var = _kernelVars[index].var;
|
|
|
|
|
|
|
|
switch (var) {
|
|
|
|
|
|
|
|
case kKernelTrigger:
|
|
|
|
_vm->_kernel->trigger = toInteger(value);
|
|
|
|
printf("kKernelTrigger -> %d\n", toInteger(value));
|
|
|
|
break;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2008-04-20 14:47:37 +00:00
|
|
|
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
|