diff options
| -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 | 
