diff options
author | Johannes Schickel | 2005-10-13 18:05:04 +0000 |
---|---|---|
committer | Johannes Schickel | 2005-10-13 18:05:04 +0000 |
commit | ce2e9ab9d8a814f2356371b941ddb7e83d387427 (patch) | |
tree | 16516e73d26edb16fde1ce44384829b74f3fd4ff | |
parent | e9b7a88e77de0043aa1eacf1e80b90d9d257c5c9 (diff) | |
download | scummvm-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.cpp | 6 | ||||
-rw-r--r-- | kyra/resource.h | 2 | ||||
-rw-r--r-- | kyra/script.cpp | 706 | ||||
-rw-r--r-- | kyra/script.h | 183 | ||||
-rw-r--r-- | kyra/script_v1.cpp | 354 |
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 |