aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2005-10-13 18:05:04 +0000
committerJohannes Schickel2005-10-13 18:05:04 +0000
commitce2e9ab9d8a814f2356371b941ddb7e83d387427 (patch)
tree16516e73d26edb16fde1ce44384829b74f3fd4ff
parente9b7a88e77de0043aa1eacf1e80b90d9d257c5c9 (diff)
downloadscummvm-rg350-ce2e9ab9d8a814f2356371b941ddb7e83d387427.tar.gz
scummvm-rg350-ce2e9ab9d8a814f2356371b941ddb7e83d387427.tar.bz2
scummvm-rg350-ce2e9ab9d8a814f2356371b941ddb7e83d387427.zip
Rewrite of the script interpretation class:
- Now only one instance is needed for many scripts - Fixed a few command procs, but lacks opcode caller implementation svn-id: r19064
-rw-r--r--kyra/resource.cpp6
-rw-r--r--kyra/resource.h2
-rw-r--r--kyra/script.cpp706
-rw-r--r--kyra/script.h183
-rw-r--r--kyra/script_v1.cpp354
5 files changed, 487 insertions, 764 deletions
diff --git a/kyra/resource.cpp b/kyra/resource.cpp
index 5debefa8b9..ce066dd842 100644
--- a/kyra/resource.cpp
+++ b/kyra/resource.cpp
@@ -179,12 +179,6 @@ uint8* Resource::fileData(const char* file, uint32* size) {
return buffer;
}
-VMContext* Resource::loadScript(const char* file) {
- VMContext* context = new VMContext(_engine);
- context->loadScript(file);
- return context;
-}
-
///////////////////////////////////////////
// Pak file manager
#define PAKFile_Iterate Common::List<PakChunk*>::iterator start=_files.begin();start != _files.end(); ++start
diff --git a/kyra/resource.h b/kyra/resource.h
index 3cd2473463..f028628b0c 100644
--- a/kyra/resource.h
+++ b/kyra/resource.h
@@ -74,8 +74,6 @@ public:
uint8* fileData(const char* file, uint32* size);
- VMContext* loadScript(const char* file);
-
protected:
struct PakFileEntry {
PAKFile *_file;
diff --git a/kyra/script.cpp b/kyra/script.cpp
index 358d65b1bb..4f941241e5 100644
--- a/kyra/script.cpp
+++ b/kyra/script.cpp
@@ -22,538 +22,274 @@
#include "common/stdafx.h"
#include "common/stream.h"
#include "common/util.h"
+#include "common/system.h"
#include "kyra/kyra.h"
-#include "kyra/script.h"
#include "kyra/resource.h"
+#include "kyra/script.h"
-#define COMMAND(x) { &VMContext::x, #x }
-#define OPCODE(x) { &VMContext::x, #x }
+#define FORM_CHUNK 0x4D524F46
+#define TEXT_CHUNK 0x54584554
+#define DATA_CHUNK 0x41544144
+#define ORDR_CHUNK 0x5244524F
namespace Kyra {
-VMContext::VMContext(KyraEngine* engine) {
- _engine = engine;
- _error = false;
-
+ScriptHelper::ScriptHelper(KyraEngine *vm) : _vm(vm) {
+#define COMMAND(x) { &ScriptHelper::x, #x }
// now we create a list of all Command/Opcode procs and so
static CommandEntry commandProcs[] = {
// 0x00
- COMMAND(c1_goToLine),
- COMMAND(c1_setReturn),
- COMMAND(c1_pushRetRec),
+ COMMAND(c1_jmpTo),
+ COMMAND(c1_setRetValue),
+ COMMAND(c1_pushRetOrPos),
COMMAND(c1_push),
// 0x04
COMMAND(c1_push),
COMMAND(c1_pushVar),
- COMMAND(c1_pushFrameNeg),
- COMMAND(c1_pushFramePos),
+ COMMAND(c1_pushBPNeg),
+ COMMAND(c1_pushBPAdd),
// 0x08
- COMMAND(c1_popRetRec),
+ COMMAND(c1_popRetOrPos),
COMMAND(c1_popVar),
- COMMAND(c1_popFrameNeg),
- COMMAND(c1_popFramePos),
+ COMMAND(c1_popBPNeg),
+ COMMAND(c1_popBPAdd),
// 0x0C
- COMMAND(c1_addToSP),
- COMMAND(c1_subFromSP),
+ COMMAND(c1_addSP),
+ COMMAND(c1_subSP),
COMMAND(c1_execOpcode),
- COMMAND(c1_ifNotGoTo),
+ COMMAND(c1_ifNotJmp),
// 0x10
COMMAND(c1_negate),
- COMMAND(c1_evaluate)
+ COMMAND(c1_eval),
+ COMMAND(c1_setRetAndJmp)
};
- _numCommands = ARRAYSIZE(commandProcs);
_commands = commandProcs;
-
- static OpcodeEntry opcodeProcs[] = {
- // 0x00
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x04
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x08
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x0C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x10
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x14
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x18
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x1C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x20
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x24
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x28
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x2C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x30
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x34
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x38
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x3C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x40
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x44
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x48
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x4C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x50
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x54
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x58
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x5C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x60
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x64
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x68
- OPCODE(o1_0x68),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x6C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x70
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x74
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x78
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x7C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x80
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x84
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x88
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x8C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x90
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x94
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x98
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0x9C
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xA0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xA4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xA8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xAC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xB0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xB4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xB8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xBC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xC0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xC4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xC8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xCC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xD0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xD4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xD8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xDC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xE0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xE4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xE8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xEC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xF0
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xF4
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xF8
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- // 0xFC
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode),
- OPCODE(o1_unknownOpcode)
- };
- _numOpcodes = ARRAYSIZE(opcodeProcs);
- _opcodes = opcodeProcs;
-
- _scriptFile = NULL;
- _scriptFileSize = 0;
+#undef COMMAND
}
-void VMContext::loadScript(const char* file) {
- if (_scriptFile) {
- delete [] _scriptFile;
- _scriptFileSize = 0;
- }
-
- memset(_stack, 0, sizeof(int32) * ARRAYSIZE(_stack));
-
- // loads the new file
- _scriptFile = _engine->resource()->fileData(file, &_scriptFileSize);
+ScriptHelper::~ScriptHelper() {
+}
- if (!_scriptFileSize || !_scriptFile) {
- error("couldn't load script file '%s'", file);
+bool ScriptHelper::loadScript(const char *filename, ScriptData *scriptData, byte *specialPtr) {
+ uint32 size = 0;
+ uint8 *data = _vm->resource()->fileData(filename, &size);
+ byte *curData = data;
+
+ uint32 formBlockSize = getFORMBlockSize(curData);
+ if (formBlockSize == (uint32)-1) {
+ delete [] data;
+ error("No FORM chunk found in file: '%s'", filename);
+ return false;
}
-
- Common::MemoryReadStream script(_scriptFile, _scriptFileSize);
- memset(_chunks, 0, sizeof(ScriptChunk) * kCountChunkTypes);
- uint8 chunkName[sizeof("EMC2ORDR") + 1];
-
- // so lets look for our chunks :)
- while (!script.eos()) {
- // lets read only the first 4 chars
- script.read(chunkName, sizeof(uint8) * 4);
- chunkName[4] = '\0';
-
- // check name of chunk
- if (!scumm_stricmp((const char *)chunkName, "FORM")) {
- // FreeKyra swaps the size I only read it in BigEndian :)
- _chunks[kForm]._size = script.readUint32BE();
- } else if (!scumm_stricmp((const char *)chunkName, "TEXT")) {
- uint32 text_size = script.readUint32BE();
- text_size += text_size % 2 != 0 ? 1 : 0;
-
- _chunks[kText]._data = _scriptFile + script.pos();
- _chunks[kText]._size = READ_BE_UINT16(_chunks[kText]._data) >> 1;
- _chunks[kText]._additional = _chunks[kText]._data + (_chunks[kText]._size << 1);
- script.seek(script.pos() + text_size);
- } else if (!scumm_stricmp((const char *)chunkName, "DATA")) {
- _chunks[kData]._size = script.readUint32BE();
- _chunks[kData]._data = _scriptFile + script.pos();
- // mostly it will be the end of the file because all files should end with a 'DATA' chunk
- script.seek(script.pos() + _chunks[kData]._size);
+
+ uint32 chunkSize = getIFFBlockSize(data, curData, size, TEXT_CHUNK);
+ if (chunkSize != (uint32)-1) {
+ if (specialPtr) {
+ scriptData->mustBeFreed = 0;
+ scriptData->text = specialPtr;
+ specialPtr += chunkSize;
} else {
- // read next 4 chars
- script.read(&chunkName[4], sizeof(uint8) * 4);
- chunkName[8] = '\0';
-
- if (!scumm_stricmp((const char *)chunkName, "EMC2ORDR")) {
- _chunks[kEmc2Ordr]._size = script.readUint32BE() >> 1;
- _chunks[kEmc2Ordr]._data = _scriptFile + script.pos();
- script.seek(script.pos() + _chunks[kEmc2Ordr]._size * 2);
- } else {
- // any unkown chunk or problems with seeking through the file
- error("unknown chunk(%s)", chunkName);
- }
+ scriptData->mustBeFreed = 1;
+ scriptData->text = new byte[chunkSize];
+ }
+ if (!loadIFFBlock(data, curData, size, TEXT_CHUNK, scriptData->text, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load TEXT chunk from file: '%s'", filename);
+ return false;
}
}
+
+ chunkSize = getIFFBlockSize(data, curData, size, ORDR_CHUNK);
+ if (chunkSize == (uint32)-1) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("No ORDR chunk found in file: '%s'", filename);
+ return false;
+ }
+ if (specialPtr) {
+ scriptData->mustBeFreed = 0;
+ scriptData->ordr = specialPtr;
+ specialPtr += chunkSize;
+ } else {
+ scriptData->mustBeFreed = 1;
+ scriptData->ordr = new byte[chunkSize];
+ }
+ if (!loadIFFBlock(data, curData, size, ORDR_CHUNK, scriptData->ordr, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load ORDR chunk from file: '%s'", filename);
+ return false;
+ }
+ chunkSize = chunkSize / 2;
+ while (chunkSize--) {
+ ((uint16*)scriptData->ordr)[chunkSize] = READ_BE_UINT16(&((uint16*)scriptData->ordr)[chunkSize]);
+ }
+
+ chunkSize = getIFFBlockSize(data, curData, size, DATA_CHUNK);
+ if (chunkSize == (uint32)-1) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("No DATA chunk found in file: '%s'", filename);
+ return false;
+ }
+ if (specialPtr) {
+ scriptData->mustBeFreed = 0;
+ scriptData->data = specialPtr;
+ specialPtr += chunkSize;
+ } else {
+ scriptData->mustBeFreed = 1;
+ scriptData->data = new byte[chunkSize];
+ }
+ if (!loadIFFBlock(data, curData, size, DATA_CHUNK, scriptData->data, chunkSize)) {
+ delete [] data;
+ unloadScript(scriptData);
+ error("Couldn't load DATA chunk from file: '%s'", filename);
+ return false;
+ }
+ scriptData->dataSize = chunkSize / 2;
+
+ delete [] data;
+ return true;
}
-int32 VMContext::param(int32 index) {
- if (_stackPos - index - 1 >= ARRAYSIZE(_stack) || _stackPos - index - 1 < 0)
- return -0xFFFF;
- return _stack[_stackPos - index - 1];
+void ScriptHelper::unloadScript(ScriptData *data) {
+ if (data->mustBeFreed) {
+ delete [] data->text;
+ delete [] data->ordr;
+ delete [] data->data;
+ }
+
+ data->mustBeFreed = 0;
+ data->text = data->ordr = data->data = 0;
}
-const char* VMContext::stringAtIndex(int32 index) {
- if (index < 0 || (uint32)index >= _chunks[kText]._size)
- return 0;
-
- return (const char *)(_chunks[kText]._additional + _chunks[kText]._data[index]);
+void ScriptHelper::initScript(ScriptState *scriptStat, ScriptData *data) {
+ scriptStat->dataPtr = data;
+ scriptStat->ip = 0;
+ scriptStat->stack[60] = 0;
+ scriptStat->bp = 62;
+ scriptStat->sp = 60;
}
-bool VMContext::startScript(int32 func) {
- if ((uint32)func >= _chunks[kEmc2Ordr]._size || func < 0) {
- debug("script doesn't support function %d", func);
+bool ScriptHelper::startScript(ScriptState *script, int function) {
+ if (!script->dataPtr) {
return false;
}
-
- _instructionPos = READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[func]) << 1;
- _stackPos = 0;
- _tempPos = 0;
- _delay = 0;
- _error = false;
- _scriptState = kScriptRunning;
-
- uint32 pos = 0xFFFFFFFE;
-
- // get start of next script
- for (uint32 tmp = 0; tmp < _chunks[kEmc2Ordr]._size; ++tmp) {
- if ((uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) > (uint32)_instructionPos &&
- (uint32)((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1)) < pos) {
- pos = ((READ_BE_UINT16(&_chunks[kEmc2Ordr]._data[tmp]) << 1));
- }
- }
-
- if (pos > _scriptFileSize) {
- pos = _scriptFileSize;
+ uint16 functionOffset = ((uint16*)script->dataPtr->ordr)[function];
+ if (functionOffset == (uint16)-1) {
+ return false;
}
-
- _nextScriptPos = pos;
-
+ script->ip = &script->dataPtr->data[functionOffset*2+2];
return true;
}
-uint32 VMContext::contScript(void) {
- uint8* script_start = _chunks[kData]._data;
- assert(script_start);
-
- uint32 scriptStateAtStart = _scriptState;
-
- // runs the script
- while (true) {
- if ((uint32)_instructionPos > _chunks[kData]._size) {
- debug("_instructionPos( = %d) > _chunks[kData]._size( = %d)", _instructionPos, _chunks[kData]._size);
- _error = true;
- break;
- } else if (_instructionPos >= _nextScriptPos) {
- _scriptState = kScriptStopped;
- break;
- }
-
- _currentCommand = *(script_start + _instructionPos++);
-
- // gets out
- if (_currentCommand & 0x80) {
- _argument = ((_currentCommand & 0x0F) << 8) | *(script_start + _instructionPos++);
- _currentCommand &= 0xF0;
- } else if (_currentCommand & 0x40) {
- _argument = *(script_start + _instructionPos++);
- } else if (_currentCommand & 0x20) {
- _instructionPos++;
-
- uint16 tmp = *(uint16*)(script_start + _instructionPos);
- tmp &= 0xFF7F;
+bool ScriptHelper::validScript(ScriptState *script) {
+ if (!script->ip || !script->dataPtr)
+ return false;
+ return true;
+}
- _argument = READ_BE_UINT16(&tmp);
- _instructionPos += 2;
- } else {
- debug("unknown way of getting the command (0x%X)", _currentCommand);
- // next thing
- continue;
- }
+bool ScriptHelper::runScript(ScriptState *script) {
+ _curScript = script;
+ _parameter = 0;
+ _continue = true;
+
+ if (!_curScript->ip) {
+ return false;
+ }
+
+ int16 code = READ_BE_UINT16(_curScript->ip); _curScript->ip += 2;
+ int16 opcode = (code >> 8) & 0x1F;
+
+ if (code & 0x8000) {
+ opcode = 0;
+ _parameter = code & 0x7FFF;
+ } else if (code & 0x4000) {
+ _parameter = code & 0xFF;
+ } else if (code & 0x2000) {
+ _parameter = READ_BE_UINT16(_curScript->ip); _curScript->ip += 2;
+ } else {
+ _parameter = 0;
+ }
+
+ if (opcode > 18) {
+ error("Script unknown command: %d", opcode);
+ } else {
+ debug(5, "%s(%d)", _commands[opcode].desc, _parameter);
+ (this->*(_commands[opcode].proc))();
+ }
+
+ _curScript = 0;
+ return _continue;
+}
- _currentCommand &= 0x1f;
+uint32 ScriptHelper::getFORMBlockSize(byte *&data) const {
+ static const uint32 chunkName = FORM_CHUNK;
+ if (READ_LE_UINT32(data) != chunkName) {
+ return (uint32)-1;
+ }
+ data += 4;
+ uint32 retValue = READ_BE_UINT32(data); data += 4;
+ return retValue;
+}
- if (_currentCommand < _numCommands) {
- CommandProc currentProc = _commands[_currentCommand].proc;
- (this->*currentProc)();
+uint32 ScriptHelper::getIFFBlockSize(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName) const {
+ uint32 size = (uint32)-1;
+ bool special = false;
+
+ if (data == (start + maxSize)) {
+ data = start + 0x0C;
+ }
+ while (data < (start + maxSize)) {
+ uint32 chunk = READ_LE_UINT32(data); data += 4;
+ uint32 size_temp = READ_BE_UINT32(data); data += 4;
+ if (chunk != chunkName) {
+ if (special) {
+ data += (size_temp + 1) & 0xFFFFFFFE;
+ } else {
+ data = start + 0x0C;
+ special = true;
+ }
} else {
- c1_unknownCommand();
- }
-
- if (_error) {
- _scriptState = kScriptError;
+ // kill our data
+ data = start;
+ size = size_temp;
break;
}
+ }
+ return size;
+}
- if (scriptStateAtStart != _scriptState) {
- break;
+bool ScriptHelper::loadIFFBlock(byte *start, byte *&data, uint32 maxSize, const uint32 chunkName, byte *loadTo, uint32 ptrSize) const {
+ bool special = false;
+
+ if (data == (start + maxSize)) {
+ data = start + 0x0C;
+ }
+ while (data < (start + maxSize)) {
+ uint32 chunk = READ_LE_UINT32(data); data += 4;
+ uint32 chunkSize = READ_BE_UINT32(data); data += 4;
+ if (chunk != chunkName) {
+ if (special) {
+ data += (chunkSize + 1) & 0xFFFFFFFE;
+ } else {
+ data = start + 0x0C;
+ special = true;
+ }
+ } else {
+ uint32 loadSize = 0;
+ if (chunkSize < ptrSize)
+ loadSize = chunkSize;
+ else
+ loadSize = ptrSize;
+ memcpy(loadTo, data, loadSize);
+ chunkSize = (chunkSize + 1) & 0xFFFFFFFE;
+ if (chunkSize > loadSize) {
+ data += (chunkSize - loadSize);
+ }
+ return true;
}
}
-
- return _scriptState;
+ return false;
}
} // end of namespace Kyra
diff --git a/kyra/script.h b/kyra/script.h
index 3acaf6bb9c..b9cc31d562 100644
--- a/kyra/script.h
+++ b/kyra/script.h
@@ -22,136 +22,83 @@
#ifndef KYRASCRIPT_H
#define KYRASCRIPT_H
+#include "kyra/kyra.h"
+
namespace Kyra {
-// TODO:
-// find out more script functions
-enum ScriptFunc {
- kSetupScene = 0,
- kClickEvent = 1, // _registers[1] and _registers[2] are mouse x, y _registers[4] is action
- kActorEvent = 2,
- kEnterEvent = 4,
- kExitEvent = 5,
- kLoadResources = 7
+struct ScriptData {
+ byte *text;
+ byte *data;
+ byte *ordr;
+ uint16 dataSize;
+ /*command table ptr (uint32)*/
+ uint16 mustBeFreed;
};
-enum ScriptState {
- kScriptStopped = 0,
- kScriptRunning = 1,
- kScriptWaiting = 2,
- kScriptError = 3
+struct ScriptState {
+ byte *ip;
+ ScriptData *dataPtr;
+ int16 retValue;
+ uint16 bp;
+ uint16 sp;
+ int16 variables[30];
+ int16 stack[61];
};
+enum {
+ SCRIPT_INIT = 0
+};
-class VMContext {
-
+class ScriptHelper {
public:
-
- VMContext(KyraEngine* engine);
- ~VMContext() { delete [] _scriptFile; }
-
- void loadScript(const char* file);
-
- const char* stringAtIndex(int32 index);
-
- // TODO: check for 'over'flow
- void pushStack(int32 value) { _stack[_stackPos++] = value; }
- void registerValue(int32 reg, int32 value) { _registers[reg] = value; }
- int32 checkReg(int32 reg) { return _registers[reg]; }
-
- uint32 state(void) { return _scriptState; }
-
- bool startScript(int32 func);
- uint32 contScript(void);
-
+ ScriptHelper(KyraEngine *vm);
+ virtual ~ScriptHelper();
+
+ bool loadScript(const char *filename, ScriptData *data, byte *specialPtr = 0);
+ void unloadScript(ScriptData *data);
+
+ void initScript(ScriptState *scriptStat, ScriptData *data);
+ bool startScript(ScriptState *script, int function);
+
+ bool validScript(ScriptState *script);
+
+ bool runScript(ScriptState *script);
protected:
- KyraEngine* _engine;
- uint8* _scriptFile;
- uint32 _scriptFileSize;
-
- uint32 _scriptState;
- uint32 _delay;
-
- int32 _registers[32]; // registers of the interpreter
- int32 _stack[64]; // our stack
-
- // TODO: check for 'under'flow
- int32 popStack(void) { return _stack[--_stackPos]; }
- int32& topStack(void) { return _stack[_stackPos]; }
-
- uint32 _returnValue;
-
- int32 _nextScriptPos;
- int32 _instructionPos;
- int32 _stackPos;
- int32 _tempPos;
-
- // used by command & opcode procs
- uint16 _argument;
- uint8 _currentCommand;
- uint32 _currentOpcode;
-
- int32 param(int32 index);
- const char* paramString(int32 index) { return stringAtIndex(param(index)); }
-
- bool _error; // used by all command- and opcodefuncs
-
- enum ScriptChunkTypes {
- kForm = 0,
- kEmc2Ordr = 1,
- kText = 2,
- kData = 3,
- kCountChunkTypes
- };
-
- struct ScriptChunk {
- uint32 _size;
- uint8* _data; // by TEXT used for count of texts, by EMC2ODRD it is used for a count of somewhat
- uint8* _additional; // currently only used for TEXT
- };
-
- ScriptChunk _chunks[kCountChunkTypes];
-
- typedef void (VMContext::*CommandProc)();
+ uint32 getFORMBlockSize(byte *&data) const;
+ uint32 getIFFBlockSize(byte *start, byte *&data, uint32 maxSize, const uint32 chunk) const;
+ bool loadIFFBlock(byte *start, byte *&data, uint32 maxSize, const uint32 chunk, byte *loadTo, uint32 ptrSize) const;
+
+ KyraEngine *_vm;
+ ScriptState *_curScript;
+ uint32 _parameter;
+ bool _continue;
+
+ typedef void (ScriptHelper::*CommandProc)();
struct CommandEntry {
CommandProc proc;
const char* desc;
};
-
- typedef void (VMContext::*OpcodeProc)();
- struct OpcodeEntry {
- OpcodeProc proc;
- const char* desc;
- };
-
- uint16 _numCommands;
- const CommandEntry* _commands;
- uint16 _numOpcodes;
- const OpcodeEntry* _opcodes;
-
-protected:
- // the command procs
- void c1_goToLine(void); // 0x00
- void c1_setReturn(void); // 0x01
- void c1_pushRetRec(void); // 0x02
- void c1_push(void); // 0x03 & 0x04
- void c1_pushVar(void); // 0x05
- void c1_pushFrameNeg(void); // 0x06
- void c1_pushFramePos(void); // 0x07
- void c1_popRetRec(void); // 0x08
- void c1_popVar(void); // 0x09
- void c1_popFrameNeg(void); // 0x0A
- void c1_popFramePos(void); // 0x0B
- void c1_addToSP(void); // 0x0C
- void c1_subFromSP(void); // 0x0D
- void c1_execOpcode(void); // 0x0E
- void c1_ifNotGoTo(void); // 0x0F
- void c1_negate(void); // 0x10
- void c1_evaluate(void); // 0x11
- void c1_unknownCommand(void);
-
- // the opcode procs
- void o1_0x68(void); // 0x68
- void o1_unknownOpcode(void);
+
+ const CommandEntry *_commands;
+private:
+ void c1_jmpTo();
+ void c1_setRetValue();
+ void c1_pushRetOrPos();
+ void c1_push();
+ //void c1_push(); same as 03
+ void c1_pushVar();
+ void c1_pushBPNeg();
+ void c1_pushBPAdd();
+ void c1_popRetOrPos();
+ void c1_popVar();
+ void c1_popBPNeg();
+ void c1_popBPAdd();
+ void c1_addSP();
+ void c1_subSP();
+ void c1_execOpcode();
+ void c1_ifNotJmp();
+ void c1_negate();
+ void c1_eval();
+ void c1_setRetAndJmp();
};
} // end of namespace Kyra
diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp
index 7ae03be931..2f8252ea1a 100644
--- a/kyra/script_v1.cpp
+++ b/kyra/script_v1.cpp
@@ -24,219 +24,267 @@
#include "kyra/script.h"
namespace Kyra {
-// Command procs
-void VMContext::c1_unknownCommand(void) {
- debug("unknown command '0x%x'.", _currentCommand);
- debug("\targument: '0x%x'", _argument);
-
- _error = true;
-}
-
-void VMContext::c1_goToLine(void) {
- _instructionPos = _argument << 1;
+void ScriptHelper::c1_jmpTo() {
+ _curScript->ip = _curScript->dataPtr->data + (_parameter << 1);
}
-void VMContext::c1_setReturn(void) {
- _returnValue = _argument;
+void ScriptHelper::c1_setRetValue() {
+ _curScript->retValue = _parameter;
}
-void VMContext::c1_pushRetRec(void) {
- if (!_argument) {
- pushStack(_returnValue);
- } else {
- int32 rec = ((int16)_tempPos << 16) | ((_instructionPos >> 1) + 1);
- pushStack(rec);
- _tempPos = _instructionPos;
+void ScriptHelper::c1_pushRetOrPos() {
+ switch (_parameter) {
+ case 0:
+ _curScript->stack[--_curScript->sp] = _curScript->retValue;
+ break;
+
+ case 1:
+ _curScript->stack[--_curScript->sp] = (_curScript->ip - _curScript->dataPtr->data) / 2 + 1;
+ _curScript->stack[--_curScript->sp] = _curScript->bp;
+ _curScript->bp = _curScript->sp + 2;
+ break;
+
+ default:
+ _continue = false;
+ _curScript->ip = 0;
+ break;
}
}
-void VMContext::c1_push(void) {
- pushStack(_argument);
+void ScriptHelper::c1_push() {
+ _curScript->stack[--_curScript->sp] = _parameter;
}
-void VMContext::c1_pushVar(void) {
- pushStack(_registers[_argument]);
+void ScriptHelper::c1_pushVar() {
+ _curScript->stack[--_curScript->sp] = _curScript->variables[_parameter];
}
-void VMContext::c1_pushFrameNeg(void) {
- pushStack(_stack[_tempPos + _argument]);
+void ScriptHelper::c1_pushBPNeg() {
+ _curScript->stack[--_curScript->sp] = _curScript->stack[(-(_parameter + 2)) + _curScript->bp];
}
-void VMContext::c1_pushFramePos(void) {
- pushStack(_stack[_tempPos - _argument]);
+void ScriptHelper::c1_pushBPAdd() {
+ _curScript->stack[--_curScript->sp] = _curScript->stack[(_parameter - 1) + _curScript->bp];
}
-void VMContext::c1_popRetRec(void) {
- if (!_argument) {
- _returnValue = popStack();
- } else {
- if (_stackPos <= 0) {
- _scriptState = kScriptStopped;
- }
- int32 rec = popStack();
-
- _tempPos = (int16)((rec & 0xFFFF0000) >> 16);
- _instructionPos = (rec & 0x0000FFFF) * 2;
+void ScriptHelper::c1_popRetOrPos() {
+ switch (_parameter) {
+ case 0:
+ _curScript->retValue = _curScript->stack[++_curScript->sp-1];
+ break;
+
+ case 1:
+ if (_curScript->sp >= 60) {
+ _continue = false;
+ _curScript->ip = 0;
+ } else {
+ _curScript->bp = _curScript->stack[++_curScript->sp-1];
+ _curScript->ip = _curScript->dataPtr->data + (_curScript->stack[++_curScript->sp-1] << 1);
+ }
+ break;
+
+ default:
+ _continue = false;
+ _curScript->ip = 0;
+ break;
}
}
-void VMContext::c1_popVar(void) {
- _registers[_argument] = popStack();
+void ScriptHelper::c1_popVar() {
+ _curScript->variables[_parameter] = _curScript->stack[++_curScript->sp-1];
}
-void VMContext::c1_popFrameNeg(void) {
- _stack[_tempPos + _argument] = popStack();
+void ScriptHelper::c1_popBPNeg() {
+ _curScript->stack[(-(_parameter + 2)) + _curScript->bp] = _curScript->stack[++_curScript->sp-1];
}
-void VMContext::c1_popFramePos(void) {
- _stack[_tempPos - _argument] = popStack();
+void ScriptHelper::c1_popBPAdd() {
+ _curScript->stack[(_parameter - 1) + _curScript->bp] = _curScript->stack[++_curScript->sp-1];
}
-void VMContext::c1_addToSP(void) {
- _stackPos -= _argument;
+void ScriptHelper::c1_addSP() {
+ _curScript->sp += _parameter;
}
-void VMContext::c1_subFromSP(void) {
- _stackPos += _argument;
+void ScriptHelper::c1_subSP() {
+ _curScript->sp -= _parameter;
}
-void VMContext::c1_execOpcode(void) {
- if (_argument < _numOpcodes) {
- OpcodeProc proc = _opcodes[_argument].proc;
- (this->*proc)();
- } else {
- error("Invalid opcode 0x%X", _argument);
- }
+void ScriptHelper::c1_execOpcode() {
+ warning("c1_execOpcode STUB");
+ // return 0 zero for now
+ _curScript->retValue = 0;
}
-void VMContext::c1_ifNotGoTo(void) {
- if (!popStack()) {
- _instructionPos = _argument << 1;
+void ScriptHelper::c1_ifNotJmp() {
+ if (_curScript->stack[++_curScript->sp-1] != 0) {
+ _parameter &= 0x7FFF;
+ _curScript->ip = _curScript->dataPtr->data + (_parameter << 1);
}
}
-void VMContext::c1_negate(void) {
- switch(_argument) {
- case 0:
- topStack() = !topStack();
+void ScriptHelper::c1_negate() {
+ int16 value = _curScript->stack[_curScript->sp];
+ switch (_parameter) {
+ case 0:
+ if (!value) {
+ _curScript->stack[_curScript->sp] = 0;
+ } else {
+ _curScript->stack[_curScript->sp] = 1;
+ }
break;
-
- case 1:
- topStack() = -topStack();
+
+ case 1:
+ _curScript->stack[_curScript->sp] = -value;
break;
-
- case 2:
- topStack() = ~topStack();
+
+ case 2:
+ _curScript->stack[_curScript->sp] = ~value;
break;
-
- default:
- debug("unkown negate instruction %d", _argument);
- _error = true;
+
+ default:
+ _continue = false;
break;
- };
+ }
}
-void VMContext::c1_evaluate(void) {
- int32 x, y;
- int32 res = false;
-
- x = popStack();
- y = popStack();
-
- switch(_argument) {
- case 0:
- res = x && y;
+void ScriptHelper::c1_eval() {
+ int16 ret = 0;
+ bool error = false;
+
+ int16 val1 = _curScript->stack[++_curScript->sp-1];
+ int16 val2 = _curScript->stack[++_curScript->sp-1];
+
+ switch (_parameter) {
+ case 0:
+ if (!val2 || !val1) {
+ ret = 0;
+ } else {
+ ret = 1;
+ }
break;
-
- case 1:
- res = x || y;
+
+ case 1:
+ if (val2 || val1) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 3:
- res = x != y;
+
+ case 2:
+ if (val1 == val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 4:
- res = x < y;
+
+ case 3:
+ if (val1 != val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 5:
- res = x <= y;
+
+ case 4:
+ if (val1 > val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 6:
- res = x > y;
+
+ case 5:
+ if (val1 >= val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 7:
- res = x >= y;
+
+ case 6:
+ if (val1 < val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 8:
- res = x + y;
+
+ case 7:
+ if (val1 <= val2) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
break;
-
- case 9:
- res = x - y;
+
+ case 8:
+ ret = val1 + val2;
break;
-
- case 10:
- res = x * y;
+
+ case 9:
+ ret = val2 - val1;
break;
-
- case 11:
- res = x / y;
+
+ case 10:
+ ret = val1 * val2;
break;
-
- case 12:
- res = x >> y;
+
+ case 11:
+ ret = val2 / val1;
break;
-
- case 13:
- res = x << y;
+
+ case 12:
+ ret = val2 >> val1;
break;
-
- case 14:
- res = x & y;
+
+ case 13:
+ ret = val2 << val1;
break;
-
- case 15:
- res = x | y;
+
+ case 14:
+ ret = val1 & val2;
break;
-
- case 16:
- res = x % y;
+
+ case 15:
+ ret = val1 | val2;
break;
-
- case 17:
- res = x ^ y;
+
+ case 16:
+ ret = val2 % val1;
break;
-
- default:
- debug("unknown evaluate command");
+
+ case 17:
+ ret = val1 ^ val2;
break;
- };
-
- pushStack(res);
+
+ default:
+ warning("Unknown evaluate func: %d", _parameter);
+ error = true;
+ break;
+ }
+
+ if (error) {
+ _curScript->ip = 0;
+ _continue = false;
+ } else {
+ _curScript->stack[--_curScript->sp] = ret;
+ }
}
-// opcode procs
-void VMContext::o1_unknownOpcode(void) {
- _error = true;
-
- debug("unknown opcode '0x%x'.", _argument);
- debug("parameters:\n"
- "Param0: %d\nParam1: %d\nParam2: %d\nParam3: %d\nParam4: %d\nParam5: %d\n"
- "Param0 as a string: %s\nParam1 as a string: %s\nParam2 as a string: %s\n"
- "Param3 as a string: %s\nParam4 as a string: %s\nParam5 as a string: %s\n",
- param(0), param(1), param(2), param(3), param(5), param(5),
- paramString(0), paramString(1), paramString(2), paramString(3),
- paramString(4), paramString(5));
+void ScriptHelper::c1_setRetAndJmp() {
+ if (_curScript->sp >= 60) {
+ _continue = false;
+ _curScript->ip = 0;
+ } else {
+ _curScript->retValue = _curScript->stack[++_curScript->sp-1];
+ uint16 temp = _curScript->stack[++_curScript->sp-1];
+ _curScript->stack[60] = 0;
+ _curScript->ip = &_curScript->dataPtr->data[temp*2];
+ }
}
-void VMContext::o1_0x68(void) {
- debug("o1_0x68 was called with param0: '0x%x'", param(0));
- _error = true;
-}
} // end of namespace Kyra