diff options
Diffstat (limited to 'engines/wintermute/Base/scriptables/ScScript.cpp')
-rw-r--r-- | engines/wintermute/Base/scriptables/ScScript.cpp | 1600 |
1 files changed, 1600 insertions, 0 deletions
diff --git a/engines/wintermute/Base/scriptables/ScScript.cpp b/engines/wintermute/Base/scriptables/ScScript.cpp new file mode 100644 index 0000000000..7a2f0db62a --- /dev/null +++ b/engines/wintermute/Base/scriptables/ScScript.cpp @@ -0,0 +1,1600 @@ +/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/Base/scriptables/ScValue.h"
+#include "engines/wintermute/Base/scriptables/ScScript.h"
+#include "engines/wintermute/Base/BGame.h"
+#include "engines/wintermute/Base/scriptables/ScEngine.h"
+#include "engines/wintermute/Base/scriptables/ScStack.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CScScript, false)
+
+//////////////////////////////////////////////////////////////////////////
+CScScript::CScScript(CBGame *inGame, CScEngine *Engine): CBBase(inGame) {
+ _buffer = NULL;
+ _bufferSize = _iP = 0;
+ _filename = NULL;
+ _currentLine = 0;
+
+ _symbols = NULL;
+ _numSymbols = 0;
+
+ _engine = Engine;
+
+ _globals = NULL;
+
+ _scopeStack = NULL;
+ _callStack = NULL;
+ _thisStack = NULL;
+ _stack = NULL;
+
+ _operand = NULL;
+ _reg1 = NULL;
+
+ _functions = NULL;
+ _numFunctions = 0;
+
+ _methods = NULL;
+ _numMethods = 0;
+
+ _events = NULL;
+ _numEvents = 0;
+
+ _externals = NULL;
+ _numExternals = 0;
+
+ _state = SCRIPT_FINISHED;
+ _origState = SCRIPT_FINISHED;
+
+ _waitObject = NULL;
+ _waitTime = 0;
+ _waitFrozen = false;
+ _waitScript = NULL;
+
+ _timeSlice = 0;
+
+ _thread = false;
+ _methodThread = false;
+ _threadEvent = NULL;
+
+ _freezable = true;
+ _owner = NULL;
+
+ _unbreakable = false;
+ _parentScript = NULL;
+
+ _tracingMode = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScScript::~CScScript() {
+ Cleanup();
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::InitScript() {
+ TScriptHeader *Header = (TScriptHeader *)_buffer;
+ if (Header->magic != SCRIPT_MAGIC) {
+ Game->LOG(0, "File '%s' is not a valid compiled script", _filename);
+ Cleanup();
+ return E_FAIL;
+ }
+
+ if (Header->version > SCRIPT_VERSION) {
+ Game->LOG(0, "Script '%s' has a wrong version %d.%d (expected %d.%d)", _filename, Header->version / 256, Header->version % 256, SCRIPT_VERSION / 256, SCRIPT_VERSION % 256);
+ Cleanup();
+ return E_FAIL;
+ }
+
+ InitTables();
+
+ // init stacks
+ _scopeStack = new CScStack(Game);
+ _callStack = new CScStack(Game);
+ _thisStack = new CScStack(Game);
+ _stack = new CScStack(Game);
+
+ _operand = new CScValue(Game);
+ _reg1 = new CScValue(Game);
+
+
+ // skip to the beginning
+ _iP = Header->code_start;
+ _currentLine = 0;
+
+ // init breakpoints
+ _engine->RefreshScriptBreakpoints(this);
+
+
+ // ready to rumble...
+ _state = SCRIPT_RUNNING;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::InitTables() {
+ uint32 OrigIP = _iP;
+
+ TScriptHeader *Header = (TScriptHeader *)_buffer;
+
+ int32 i;
+
+ // load symbol table
+ _iP = Header->symbol_table;
+
+ _numSymbols = GetDWORD();
+ _symbols = new char*[_numSymbols];
+ for (i = 0; i < _numSymbols; i++) {
+ uint32 index = GetDWORD();
+ _symbols[index] = GetString();
+ }
+
+ // load functions table
+ _iP = Header->func_table;
+
+ _numFunctions = GetDWORD();
+ _functions = new TFunctionPos[_numFunctions];
+ for (i = 0; i < _numFunctions; i++) {
+ _functions[i].pos = GetDWORD();
+ _functions[i].name = GetString();
+ }
+
+
+ // load events table
+ _iP = Header->event_table;
+
+ _numEvents = GetDWORD();
+ _events = new TEventPos[_numEvents];
+ for (i = 0; i < _numEvents; i++) {
+ _events[i].pos = GetDWORD();
+ _events[i].name = GetString();
+ }
+
+
+ // load externals
+ if (Header->version >= 0x0101) {
+ _iP = Header->externals_table;
+
+ _numExternals = GetDWORD();
+ _externals = new TExternalFunction[_numExternals];
+ for (i = 0; i < _numExternals; i++) {
+ _externals[i].dll_name = GetString();
+ _externals[i].name = GetString();
+ _externals[i].call_type = (TCallType)GetDWORD();
+ _externals[i].returns = (TExternalType)GetDWORD();
+ _externals[i].nu_params = GetDWORD();
+ if (_externals[i].nu_params > 0) {
+ _externals[i].params = new TExternalType[_externals[i].nu_params];
+ for (int j = 0; j < _externals[i].nu_params; j++) {
+ _externals[i].params[j] = (TExternalType)GetDWORD();
+ }
+ }
+ }
+ }
+
+ // load method table
+ _iP = Header->method_table;
+
+ _numMethods = GetDWORD();
+ _methods = new TMethodPos[_numMethods];
+ for (i = 0; i < _numMethods; i++) {
+ _methods[i].pos = GetDWORD();
+ _methods[i].name = GetString();
+ }
+
+
+ _iP = OrigIP;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Create(const char *Filename, byte *Buffer, uint32 Size, CBScriptHolder *Owner) {
+ Cleanup();
+
+ _thread = false;
+ _methodThread = false;
+
+ delete[] _threadEvent;
+ _threadEvent = NULL;
+
+ _filename = new char[strlen(Filename) + 1];
+ if (_filename) strcpy(_filename, Filename);
+
+ _buffer = new byte [Size];
+ if (!_buffer) return E_FAIL;
+
+ memcpy(_buffer, Buffer, Size);
+
+ _bufferSize = Size;
+
+ HRESULT res = InitScript();
+ if (FAILED(res)) return res;
+
+ // establish global variables table
+ _globals = new CScValue(Game);
+
+ _owner = Owner;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::CreateThread(CScScript *Original, uint32 InitIP, const char *EventName) {
+ Cleanup();
+
+ _thread = true;
+ _methodThread = false;
+ _threadEvent = new char[strlen(EventName) + 1];
+ if (_threadEvent) strcpy(_threadEvent, EventName);
+
+ // copy filename
+ _filename = new char[strlen(Original->_filename) + 1];
+ if (_filename) strcpy(_filename, Original->_filename);
+
+ // copy buffer
+ _buffer = new byte [Original->_bufferSize];
+ if (!_buffer) return E_FAIL;
+
+ memcpy(_buffer, Original->_buffer, Original->_bufferSize);
+ _bufferSize = Original->_bufferSize;
+
+ // initialize
+ HRESULT res = InitScript();
+ if (FAILED(res)) return res;
+
+ // copy globals
+ _globals = Original->_globals;
+
+ // skip to the beginning of the event
+ _iP = InitIP;
+
+ _timeSlice = Original->_timeSlice;
+ _freezable = Original->_freezable;
+ _owner = Original->_owner;
+
+ _engine = Original->_engine;
+ _parentScript = Original;
+
+ return S_OK;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::CreateMethodThread(CScScript *Original, const char *MethodName) {
+ uint32 IP = Original->GetMethodPos(MethodName);
+ if (IP == 0) return E_FAIL;
+
+ Cleanup();
+
+ _thread = true;
+ _methodThread = true;
+ _threadEvent = new char[strlen(MethodName) + 1];
+ if (_threadEvent) strcpy(_threadEvent, MethodName);
+
+ // copy filename
+ _filename = new char[strlen(Original->_filename) + 1];
+ if (_filename) strcpy(_filename, Original->_filename);
+
+ // copy buffer
+ _buffer = new byte [Original->_bufferSize];
+ if (!_buffer) return E_FAIL;
+
+ memcpy(_buffer, Original->_buffer, Original->_bufferSize);
+ _bufferSize = Original->_bufferSize;
+
+ // initialize
+ HRESULT res = InitScript();
+ if (FAILED(res)) return res;
+
+ // copy globals
+ _globals = Original->_globals;
+
+ // skip to the beginning of the event
+ _iP = IP;
+
+ _timeSlice = Original->_timeSlice;
+ _freezable = Original->_freezable;
+ _owner = Original->_owner;
+
+ _engine = Original->_engine;
+ _parentScript = Original;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CScScript::Cleanup() {
+ if (_buffer) delete [] _buffer;
+ _buffer = NULL;
+
+ if (_filename) delete [] _filename;
+ _filename = NULL;
+
+ if (_symbols) delete [] _symbols;
+ _symbols = NULL;
+ _numSymbols = 0;
+
+ if (_globals && !_thread) delete _globals;
+ _globals = NULL;
+
+ if (_scopeStack) delete _scopeStack;
+ _scopeStack = NULL;
+
+ if (_callStack) delete _callStack;
+ _callStack = NULL;
+
+ if (_thisStack) delete _thisStack;
+ _thisStack = NULL;
+
+ if (_stack) delete _stack;
+ _stack = NULL;
+
+ if (_functions) delete [] _functions;
+ _functions = NULL;
+ _numFunctions = 0;
+
+ if (_methods) delete [] _methods;
+ _methods = NULL;
+ _numMethods = 0;
+
+ if (_events) delete [] _events;
+ _events = NULL;
+ _numEvents = 0;
+
+
+ if (_externals) {
+ for (int i = 0; i < _numExternals; i++) {
+ if (_externals[i].nu_params > 0) delete [] _externals[i].params;
+ }
+ delete [] _externals;
+ }
+ _externals = NULL;
+ _numExternals = 0;
+
+ delete _operand;
+ delete _reg1;
+ _operand = NULL;
+ _reg1 = NULL;
+
+ delete[] _threadEvent;
+ _threadEvent = NULL;
+
+ _state = SCRIPT_FINISHED;
+
+ _waitObject = NULL;
+ _waitTime = 0;
+ _waitFrozen = false;
+ _waitScript = NULL;
+
+ _parentScript = NULL; // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::GetDWORD() {
+ uint32 ret = *(uint32 *)(_buffer + _iP);
+ _iP += sizeof(uint32);
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+double CScScript::GetFloat() {
+ double ret = *(double *)(_buffer + _iP);
+ _iP += sizeof(double);
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+char *CScScript::GetString() {
+ char *ret = (char *)(_buffer + _iP);
+ while (*(char *)(_buffer + _iP) != '\0') _iP++;
+ _iP++; // string terminator
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::ExecuteInstruction() {
+ HRESULT ret = S_OK;
+
+ uint32 dw;
+ const char *str = NULL;
+
+ //CScValue* op = new CScValue(Game);
+ _operand->Cleanup();
+
+ CScValue *op1;
+ CScValue *op2;
+
+ uint32 inst = GetDWORD();
+ switch (inst) {
+
+ case II_DEF_VAR:
+ _operand->SetNULL();
+ dw = GetDWORD();
+ if (_scopeStack->_sP < 0) {
+ _globals->SetProp(_symbols[dw], _operand);
+ if (Game->GetDebugMgr()->_enabled)
+ Game->GetDebugMgr()->OnVariableInit(WME_DBGVAR_SCRIPT, this, NULL, _globals->GetProp(_symbols[dw]), _symbols[dw]);
+ } else {
+ _scopeStack->GetTop()->SetProp(_symbols[dw], _operand);
+ if (Game->GetDebugMgr()->_enabled)
+ Game->GetDebugMgr()->OnVariableInit(WME_DBGVAR_SCOPE, this, _scopeStack->GetTop(), _scopeStack->GetTop()->GetProp(_symbols[dw]), _symbols[dw]);
+ }
+
+ break;
+
+ case II_DEF_GLOB_VAR:
+ case II_DEF_CONST_VAR: {
+ dw = GetDWORD();
+/* char *Temp = _symbols[dw]; // TODO delete */
+ // only create global var if it doesn't exist
+ if (!_engine->_globals->PropExists(_symbols[dw])) {
+ _operand->SetNULL();
+ _engine->_globals->SetProp(_symbols[dw], _operand, false, inst == II_DEF_CONST_VAR);
+
+ if (Game->GetDebugMgr()->_enabled)
+ Game->GetDebugMgr()->OnVariableInit(WME_DBGVAR_GLOBAL, this, NULL, _engine->_globals->GetProp(_symbols[dw]), _symbols[dw]);
+ }
+ break;
+ }
+
+ case II_RET:
+ if (_scopeStack->_sP >= 0 && _callStack->_sP >= 0) {
+ Game->GetDebugMgr()->OnScriptShutdownScope(this, _scopeStack->GetTop());
+
+ _scopeStack->Pop();
+ _iP = (uint32)_callStack->Pop()->GetInt();
+
+ if (_scopeStack->_sP < 0) Game->GetDebugMgr()->OnScriptChangeScope(this, NULL);
+ else Game->GetDebugMgr()->OnScriptChangeScope(this, _scopeStack->GetTop());
+ } else {
+ if (_thread) {
+ _state = SCRIPT_THREAD_FINISHED;
+ } else {
+ if (_numEvents == 0 && _numMethods == 0) _state = SCRIPT_FINISHED;
+ else _state = SCRIPT_PERSISTENT;
+ }
+ }
+
+ break;
+
+ case II_RET_EVENT:
+ _state = SCRIPT_FINISHED;
+ break;
+
+
+ case II_CALL:
+ dw = GetDWORD();
+
+ _operand->SetInt(_iP);
+ _callStack->Push(_operand);
+
+ _iP = dw;
+
+ break;
+
+ case II_CALL_BY_EXP: {
+ // push var
+ // push string
+ str = _stack->Pop()->GetString();
+ char *MethodName = new char[strlen(str) + 1];
+ strcpy(MethodName, str);
+
+ CScValue *var = _stack->Pop();
+ if (var->_type == VAL_VARIABLE_REF) var = var->_valRef;
+
+ HRESULT res = E_FAIL;
+ bool TriedNative = false;
+
+ // we are already calling this method, try native
+ if (_thread && _methodThread && strcmp(MethodName, _threadEvent) == 0 && var->_type == VAL_NATIVE && _owner == var->GetNative()) {
+ TriedNative = true;
+ res = var->_valNative->ScCallMethod(this, _stack, _thisStack, MethodName);
+ }
+
+ if (FAILED(res)) {
+ if (var->IsNative() && var->GetNative()->CanHandleMethod(MethodName)) {
+ if (!_unbreakable) {
+ _waitScript = var->GetNative()->InvokeMethodThread(MethodName);
+ if (!_waitScript) {
+ _stack->CorrectParams(0);
+ RuntimeError("Error invoking method '%s'.", MethodName);
+ _stack->PushNULL();
+ } else {
+ _state = SCRIPT_WAITING_SCRIPT;
+ _waitScript->CopyParameters(_stack);
+ }
+ } else {
+ // can call methods in unbreakable mode
+ _stack->CorrectParams(0);
+ RuntimeError("Cannot call method '%s'. Ignored.", MethodName);
+ _stack->PushNULL();
+ }
+ delete [] MethodName;
+ break;
+ }
+ /*
+ CScValue* val = var->GetProp(MethodName);
+ if(val){
+ dw = GetFuncPos(val->GetString());
+ if(dw==0){
+ TExternalFunction* f = GetExternal(val->GetString());
+ if(f){
+ ExternalCall(_stack, _thisStack, f);
+ }
+ else{
+ // not an internal nor external, try for native function
+ Game->ExternalCall(this, _stack, _thisStack, val->GetString());
+ }
+ }
+ else{
+ _operand->SetInt(_iP);
+ _callStack->Push(_operand);
+ _iP = dw;
+ }
+ }
+ */
+ else {
+ res = E_FAIL;
+ if (var->_type == VAL_NATIVE && !TriedNative) res = var->_valNative->ScCallMethod(this, _stack, _thisStack, MethodName);
+
+ if (FAILED(res)) {
+ _stack->CorrectParams(0);
+ RuntimeError("Call to undefined method '%s'. Ignored.", MethodName);
+ _stack->PushNULL();
+ }
+ }
+ }
+ delete [] MethodName;
+ }
+ break;
+
+ case II_EXTERNAL_CALL: {
+ uint32 SymbolIndex = GetDWORD();
+
+ TExternalFunction *f = GetExternal(_symbols[SymbolIndex]);
+ if (f) {
+ ExternalCall(_stack, _thisStack, f);
+ } else Game->ExternalCall(this, _stack, _thisStack, _symbols[SymbolIndex]);
+
+ break;
+ }
+ case II_SCOPE:
+ _operand->SetNULL();
+ _scopeStack->Push(_operand);
+
+ if (_scopeStack->_sP < 0) Game->GetDebugMgr()->OnScriptChangeScope(this, NULL);
+ else Game->GetDebugMgr()->OnScriptChangeScope(this, _scopeStack->GetTop());
+
+ break;
+
+ case II_CORRECT_STACK:
+ dw = GetDWORD(); // params expected
+ _stack->CorrectParams(dw);
+ break;
+
+ case II_CREATE_OBJECT:
+ _operand->SetObject();
+ _stack->Push(_operand);
+ break;
+
+ case II_POP_EMPTY:
+ _stack->Pop();
+ break;
+
+ case II_PUSH_VAR: {
+ CScValue *var = GetVar(_symbols[GetDWORD()]);
+ if (false && /*var->_type==VAL_OBJECT ||*/ var->_type == VAL_NATIVE) {
+ _operand->SetReference(var);
+ _stack->Push(_operand);
+ } else _stack->Push(var);
+ break;
+ }
+
+ case II_PUSH_VAR_REF: {
+ CScValue *var = GetVar(_symbols[GetDWORD()]);
+ _operand->SetReference(var);
+ _stack->Push(_operand);
+ break;
+ }
+
+ case II_POP_VAR: {
+ char *VarName = _symbols[GetDWORD()];
+ CScValue *var = GetVar(VarName);
+ if (var) {
+ CScValue *val = _stack->Pop();
+ if (!val) {
+ RuntimeError("Script stack corruption detected. Please report this script at WME bug reports forum.");
+ var->SetNULL();
+ } else {
+ if (val->GetType() == VAL_VARIABLE_REF) val = val->_valRef;
+ if (val->_type == VAL_NATIVE) var->SetValue(val);
+ else {
+ var->Copy(val);
+ }
+ }
+
+ if (Game->GetDebugMgr()->_enabled)
+ Game->GetDebugMgr()->OnVariableChangeValue(var, val);
+ }
+
+ break;
+ }
+
+ case II_PUSH_VAR_THIS:
+ _stack->Push(_thisStack->GetTop());
+ break;
+
+ case II_PUSH_INT:
+ _stack->PushInt((int)GetDWORD());
+ break;
+
+ case II_PUSH_FLOAT:
+ _stack->PushFloat(GetFloat());
+ break;
+
+
+ case II_PUSH_BOOL:
+ _stack->PushBool(GetDWORD() != 0);
+
+ break;
+
+ case II_PUSH_STRING:
+ _stack->PushString(GetString());
+ break;
+
+ case II_PUSH_NULL:
+ _stack->PushNULL();
+ break;
+
+ case II_PUSH_THIS_FROM_STACK:
+ _operand->SetReference(_stack->GetTop());
+ _thisStack->Push(_operand);
+ break;
+
+ case II_PUSH_THIS:
+ _operand->SetReference(GetVar(_symbols[GetDWORD()]));
+ _thisStack->Push(_operand);
+ break;
+
+ case II_POP_THIS:
+ _thisStack->Pop();
+ break;
+
+ case II_PUSH_BY_EXP: {
+ str = _stack->Pop()->GetString();
+ CScValue *val = _stack->Pop()->GetProp(str);
+ if (val) _stack->Push(val);
+ else _stack->PushNULL();
+
+ break;
+ }
+
+ case II_POP_BY_EXP: {
+ str = _stack->Pop()->GetString();
+ CScValue *var = _stack->Pop();
+ CScValue *val = _stack->Pop();
+
+ if (val == NULL) {
+ RuntimeError("Script stack corruption detected. Please report this script at WME bug reports forum.");
+ var->SetNULL();
+ } else var->SetProp(str, val);
+
+ if (Game->GetDebugMgr()->_enabled)
+ Game->GetDebugMgr()->OnVariableChangeValue(var, NULL);
+
+ break;
+ }
+
+ case II_PUSH_REG1:
+ _stack->Push(_reg1);
+ break;
+
+ case II_POP_REG1:
+ _reg1->Copy(_stack->Pop());
+ break;
+
+ case II_JMP:
+ _iP = GetDWORD();
+ break;
+
+ case II_JMP_FALSE: {
+ dw = GetDWORD();
+ //if(!_stack->Pop()->GetBool()) _iP = dw;
+ CScValue *Val = _stack->Pop();
+ if (!Val) {
+ RuntimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?");
+ } else {
+ if (!Val->GetBool()) _iP = dw;
+ }
+ break;
+ }
+
+ case II_ADD:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ if (op1->IsNULL() || op2->IsNULL()) _operand->SetNULL();
+ else if (op1->GetType() == VAL_STRING || op2->GetType() == VAL_STRING) {
+ char *tempStr = new char [strlen(op1->GetString()) + strlen(op2->GetString()) + 1];
+ strcpy(tempStr, op1->GetString());
+ strcat(tempStr, op2->GetString());
+ _operand->SetString(str);
+ delete [] tempStr;
+ } else if (op1->GetType() == VAL_INT && op2->GetType() == VAL_INT)
+ _operand->SetInt(op1->GetInt() + op2->GetInt());
+ else _operand->SetFloat(op1->GetFloat() + op2->GetFloat());
+
+ _stack->Push(_operand);
+
+ break;
+
+ case II_SUB:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ if (op1->IsNULL() || op2->IsNULL()) _operand->SetNULL();
+ else if (op1->GetType() == VAL_INT && op2->GetType() == VAL_INT)
+ _operand->SetInt(op1->GetInt() - op2->GetInt());
+ else _operand->SetFloat(op1->GetFloat() - op2->GetFloat());
+
+ _stack->Push(_operand);
+
+ break;
+
+ case II_MUL:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ if (op1->IsNULL() || op2->IsNULL()) _operand->SetNULL();
+ else if (op1->GetType() == VAL_INT && op2->GetType() == VAL_INT)
+ _operand->SetInt(op1->GetInt() * op2->GetInt());
+ else _operand->SetFloat(op1->GetFloat() * op2->GetFloat());
+
+ _stack->Push(_operand);
+
+ break;
+
+ case II_DIV:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ if (op2->GetFloat() == 0.0f) RuntimeError("Division by zero.");
+
+ if (op1->IsNULL() || op2->IsNULL() || op2->GetFloat() == 0.0f) _operand->SetNULL();
+ else _operand->SetFloat(op1->GetFloat() / op2->GetFloat());
+
+ _stack->Push(_operand);
+
+ break;
+
+ case II_MODULO:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ if (op2->GetInt() == 0) RuntimeError("Division by zero.");
+
+ if (op1->IsNULL() || op2->IsNULL() || op2->GetInt() == 0) _operand->SetNULL();
+ else _operand->SetInt(op1->GetInt() % op2->GetInt());
+
+ _stack->Push(_operand);
+
+ break;
+
+ case II_NOT:
+ op1 = _stack->Pop();
+ //if(op1->IsNULL()) _operand->SetNULL();
+ if (op1->IsNULL()) _operand->SetBool(true);
+ else _operand->SetBool(!op1->GetBool());
+ _stack->Push(_operand);
+
+ break;
+
+ case II_AND:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+ if (op1 == NULL || op2 == NULL) {
+ RuntimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?");
+ _operand->SetBool(false);
+ } else {
+ _operand->SetBool(op1->GetBool() && op2->GetBool());
+ }
+ _stack->Push(_operand);
+ break;
+
+ case II_OR:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+ if (op1 == NULL || op2 == NULL) {
+ RuntimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?");
+ _operand->SetBool(false);
+ } else {
+ _operand->SetBool(op1->GetBool() || op2->GetBool());
+ }
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_EQ:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if((op1->IsNULL() && !op2->IsNULL()) || (!op1->IsNULL() && op2->IsNULL())) _operand->SetBool(false);
+ else if(op1->IsNative() && op2->IsNative()){
+ _operand->SetBool(op1->GetNative() == op2->GetNative());
+ }
+ else if(op1->GetType()==VAL_STRING || op2->GetType()==VAL_STRING){
+ _operand->SetBool(scumm_stricmp(op1->GetString(), op2->GetString())==0);
+ }
+ else if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() == op2->GetFloat());
+ }
+ else{
+ _operand->SetBool(op1->GetInt() == op2->GetInt());
+ }
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) == 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_NE:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if((op1->IsNULL() && !op2->IsNULL()) || (!op1->IsNULL() && op2->IsNULL())) _operand->SetBool(true);
+ else if(op1->IsNative() && op2->IsNative()){
+ _operand->SetBool(op1->GetNative() != op2->GetNative());
+ }
+ else if(op1->GetType()==VAL_STRING || op2->GetType()==VAL_STRING){
+ _operand->SetBool(scumm_stricmp(op1->GetString(), op2->GetString())!=0);
+ }
+ else if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() != op2->GetFloat());
+ }
+ else{
+ _operand->SetBool(op1->GetInt() != op2->GetInt());
+ }
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) != 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_L:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() < op2->GetFloat());
+ }
+ else _operand->SetBool(op1->GetInt() < op2->GetInt());
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) < 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_G:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() > op2->GetFloat());
+ }
+ else _operand->SetBool(op1->GetInt() > op2->GetInt());
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) > 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_LE:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() <= op2->GetFloat());
+ }
+ else _operand->SetBool(op1->GetInt() <= op2->GetInt());
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) <= 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_GE:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ /*
+ if(op1->GetType()==VAL_FLOAT && op2->GetType()==VAL_FLOAT){
+ _operand->SetBool(op1->GetFloat() >= op2->GetFloat());
+ }
+ else _operand->SetBool(op1->GetInt() >= op2->GetInt());
+ */
+
+ _operand->SetBool(CScValue::Compare(op1, op2) >= 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_CMP_STRICT_EQ:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ //_operand->SetBool(op1->GetType()==op2->GetType() && op1->GetFloat()==op2->GetFloat());
+ _operand->SetBool(CScValue::CompareStrict(op1, op2) == 0);
+ _stack->Push(_operand);
+
+ break;
+
+ case II_CMP_STRICT_NE:
+ op2 = _stack->Pop();
+ op1 = _stack->Pop();
+
+ //_operand->SetBool(op1->GetType()!=op2->GetType() || op1->GetFloat()!=op2->GetFloat());
+ _operand->SetBool(CScValue::CompareStrict(op1, op2) != 0);
+ _stack->Push(_operand);
+ break;
+
+ case II_DBG_LINE: {
+ int NewLine = GetDWORD();
+ if (NewLine != _currentLine) {
+ _currentLine = NewLine;
+ if (Game->GetDebugMgr()->_enabled) {
+ Game->GetDebugMgr()->OnScriptChangeLine(this, _currentLine);
+ for (int i = 0; i < _breakpoints.GetSize(); i++) {
+ if (_breakpoints[i] == _currentLine) {
+ Game->GetDebugMgr()->OnScriptHitBreakpoint(this);
+ Sleep(0);
+ break;
+ }
+ }
+ if (_tracingMode) {
+ Game->GetDebugMgr()->OnScriptHitBreakpoint(this);
+ Sleep(0);
+ break;
+ }
+ }
+ }
+ break;
+
+ }
+ default:
+ Game->LOG(0, "Fatal: Invalid instruction %d ('%s', line %d, IP:0x%x)\n", inst, _filename, _currentLine, _iP - sizeof(uint32));
+ _state = SCRIPT_FINISHED;
+ ret = E_FAIL;
+ } // switch(instruction)
+
+ //delete op;
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::GetFuncPos(const char *Name) {
+ for (int i = 0; i < _numFunctions; i++) {
+ if (strcmp(Name, _functions[i].name) == 0) return _functions[i].pos;
+ }
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::GetMethodPos(const char *Name) {
+ for (int i = 0; i < _numMethods; i++) {
+ if (strcmp(Name, _methods[i].name) == 0) return _methods[i].pos;
+ }
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CScScript::GetVar(char *Name) {
+ CScValue *ret = NULL;
+
+ // scope locals
+ if (_scopeStack->_sP >= 0) {
+ if (_scopeStack->GetTop()->PropExists(Name)) ret = _scopeStack->GetTop()->GetProp(Name);
+ }
+
+ // script globals
+ if (ret == NULL) {
+ if (_globals->PropExists(Name)) ret = _globals->GetProp(Name);
+ }
+
+ // engine globals
+ if (ret == NULL) {
+ if (_engine->_globals->PropExists(Name)) ret = _engine->_globals->GetProp(Name);
+ }
+
+ if (ret == NULL) {
+ //RuntimeError("Variable '%s' is inaccessible in the current block. Consider changing the script.", Name);
+ Game->LOG(0, "Warning: variable '%s' is inaccessible in the current block. Consider changing the script (script:%s, line:%d)", Name, _filename, _currentLine);
+ CScValue *Val = new CScValue(Game);
+ CScValue *Scope = _scopeStack->GetTop();
+ if (Scope) {
+ Scope->SetProp(Name, Val);
+ ret = _scopeStack->GetTop()->GetProp(Name);
+ } else {
+ _globals->SetProp(Name, Val);
+ ret = _globals->GetProp(Name);
+ }
+ delete Val;
+ }
+
+ return ret;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::WaitFor(CBObject *Object) {
+ if (_unbreakable) {
+ RuntimeError("Script cannot be interrupted.");
+ return S_OK;
+ }
+
+ _state = SCRIPT_WAITING;
+ _waitObject = Object;
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::WaitForExclusive(CBObject *Object) {
+ _engine->ResetObject(Object);
+ return WaitFor(Object);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Sleep(uint32 Duration) {
+ if (_unbreakable) {
+ RuntimeError("Script cannot be interrupted.");
+ return S_OK;
+ }
+
+ _state = SCRIPT_SLEEPING;
+ if (Game->_state == GAME_FROZEN) {
+ _waitTime = CBPlatform::GetTime() + Duration;
+ _waitFrozen = true;
+ } else {
+ _waitTime = Game->_timer + Duration;
+ _waitFrozen = false;
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Finish(bool IncludingThreads) {
+ if (_state != SCRIPT_FINISHED && IncludingThreads) {
+ _state = SCRIPT_FINISHED;
+ FinishThreads();
+ } else _state = SCRIPT_FINISHED;
+
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Run() {
+ _state = SCRIPT_RUNNING;
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+void CScScript::RuntimeError(LPCSTR fmt, ...) {
+ char buff[256];
+ va_list va;
+
+ va_start(va, fmt);
+ vsprintf(buff, fmt, va);
+ va_end(va);
+
+ Game->LOG(0, "Runtime error. Script '%s', line %d", _filename, _currentLine);
+ Game->LOG(0, " %s", buff);
+
+ if (!Game->_suppressScriptErrors)
+ Game->QuickMessage("Script runtime error. View log for details.");
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Persist(CBPersistMgr *PersistMgr) {
+
+ PersistMgr->Transfer(TMEMBER(Game));
+
+ // buffer
+ if (PersistMgr->_saving) {
+ if (_state != SCRIPT_PERSISTENT && _state != SCRIPT_FINISHED && _state != SCRIPT_THREAD_FINISHED) {
+ PersistMgr->Transfer(TMEMBER(_bufferSize));
+ PersistMgr->PutBytes(_buffer, _bufferSize);
+ } else {
+ // don't save idle/finished scripts
+ int bufferSize = 0;
+ PersistMgr->Transfer(TMEMBER(bufferSize));
+ }
+ } else {
+ PersistMgr->Transfer(TMEMBER(_bufferSize));
+ if (_bufferSize > 0) {
+ _buffer = new byte[_bufferSize];
+ PersistMgr->GetBytes(_buffer, _bufferSize);
+ InitTables();
+ } else _buffer = NULL;
+ }
+
+ PersistMgr->Transfer(TMEMBER(_callStack));
+ PersistMgr->Transfer(TMEMBER(_currentLine));
+ PersistMgr->Transfer(TMEMBER(_engine));
+ PersistMgr->Transfer(TMEMBER(_filename));
+ PersistMgr->Transfer(TMEMBER(_freezable));
+ PersistMgr->Transfer(TMEMBER(_globals));
+ PersistMgr->Transfer(TMEMBER(_iP));
+ PersistMgr->Transfer(TMEMBER(_scopeStack));
+ PersistMgr->Transfer(TMEMBER(_stack));
+ PersistMgr->Transfer(TMEMBER_INT(_state));
+ PersistMgr->Transfer(TMEMBER(_operand));
+ PersistMgr->Transfer(TMEMBER_INT(_origState));
+ PersistMgr->Transfer(TMEMBER(_owner));
+ PersistMgr->Transfer(TMEMBER(_reg1));
+ PersistMgr->Transfer(TMEMBER(_thread));
+ PersistMgr->Transfer(TMEMBER(_threadEvent));
+ PersistMgr->Transfer(TMEMBER(_thisStack));
+ PersistMgr->Transfer(TMEMBER(_timeSlice));
+ PersistMgr->Transfer(TMEMBER(_waitObject));
+ PersistMgr->Transfer(TMEMBER(_waitScript));
+ PersistMgr->Transfer(TMEMBER(_waitTime));
+ PersistMgr->Transfer(TMEMBER(_waitFrozen));
+
+ PersistMgr->Transfer(TMEMBER(_methodThread));
+ PersistMgr->Transfer(TMEMBER(_methodThread));
+ PersistMgr->Transfer(TMEMBER(_unbreakable));
+ PersistMgr->Transfer(TMEMBER(_parentScript));
+
+ if (!PersistMgr->_saving) _tracingMode = false;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScScript *CScScript::InvokeEventHandler(const char *EventName, bool Unbreakable) {
+ //if(_state!=SCRIPT_PERSISTENT) return NULL;
+
+ uint32 pos = GetEventPos(EventName);
+ if (!pos) return NULL;
+
+ CScScript *thread = new CScScript(Game, _engine);
+ if (thread) {
+ HRESULT ret = thread->CreateThread(this, pos, EventName);
+ if (SUCCEEDED(ret)) {
+ thread->_unbreakable = Unbreakable;
+ _engine->_scripts.Add(thread);
+ Game->GetDebugMgr()->OnScriptEventThreadInit(thread, this, EventName);
+ return thread;
+ } else {
+ delete thread;
+ return NULL;
+ }
+ } else return NULL;
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::GetEventPos(const char *Name) {
+ for (int i = _numEvents - 1; i >= 0; i--) {
+ if (scumm_stricmp(Name, _events[i].name) == 0) return _events[i].pos;
+ }
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CScScript::CanHandleEvent(const char *EventName) {
+ return GetEventPos(EventName) != 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CScScript::CanHandleMethod(const char *MethodName) {
+ return GetMethodPos(MethodName) != 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Pause() {
+ if (_state == SCRIPT_PAUSED) {
+ Game->LOG(0, "Attempting to pause a paused script ('%s', line %d)", _filename, _currentLine);
+ return E_FAIL;
+ }
+
+ if (!_freezable || _state == SCRIPT_PERSISTENT) return S_OK;
+
+ _origState = _state;
+ _state = SCRIPT_PAUSED;
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::Resume() {
+ if (_state != SCRIPT_PAUSED) return S_OK;
+
+ _state = _origState;
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScScript::TExternalFunction *CScScript::GetExternal(char *Name) {
+ for (int i = 0; i < _numExternals; i++) {
+ if (strcmp(Name, _externals[i].name) == 0) return &_externals[i];
+ }
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::ExternalCall(CScStack *Stack, CScStack *ThisStack, CScScript::TExternalFunction *Function) {
+
+#ifndef __WIN32__
+
+ Game->LOG(0, "External functions are not supported on this platform.");
+ Stack->CorrectParams(0);
+ Stack->PushNULL();
+ return E_FAIL;
+
+#else
+
+ bool Success = false;
+ HMODULE hDll = LoadLibrary(Function->dll_name);
+
+ if (hDll) {
+ FARPROC pFunc = GetProcAddress(hDll, Function->name);
+ if (pFunc) {
+ int i;
+ Success = true;
+ Stack->CorrectParams(Function->nu_params);
+ CBDynBuffer *Buffer = new CBDynBuffer(Game, 20 * sizeof(uint32));
+
+ for (i = 0; i < Function->nu_params; i++) {
+ CScValue *Val = Stack->Pop();
+ switch (Function->params[i]) {
+ case TYPE_BOOL:
+ Buffer->PutDWORD((uint32)Val->GetBool());
+ break;
+ case TYPE_LONG:
+ Buffer->PutDWORD(Val->GetInt());
+ break;
+ case TYPE_BYTE:
+ Buffer->PutDWORD((byte)Val->GetInt());
+ break;
+ case TYPE_STRING:
+ if (Val->IsNULL()) Buffer->PutDWORD(0);
+ else Buffer->PutDWORD((uint32)Val->GetString());
+ break;
+ case TYPE_MEMBUFFER:
+ if (Val->IsNULL()) Buffer->PutDWORD(0);
+ else Buffer->PutDWORD((uint32)Val->GetMemBuffer());
+ break;
+ case TYPE_FLOAT: {
+ float f = Val->GetFloat();
+ Buffer->PutDWORD(*((uint32 *)&f));
+ break;
+ }
+ case TYPE_DOUBLE: {
+ double d = Val->GetFloat();
+ uint32 *pd = (uint32 *)&d;
+
+ Buffer->PutDWORD(pd[0]);
+ Buffer->PutDWORD(pd[1]);
+ break;
+ }
+ }
+ }
+
+ // call
+ uint32 ret;
+ bool StackCorrupted = false;
+ switch (Function->call_type) {
+ case CALL_CDECL:
+ ret = Call_cdecl(Buffer->_buffer, Buffer->GetSize(), (uint32)pFunc, &StackCorrupted);
+ break;
+ default:
+ ret = Call_stdcall(Buffer->_buffer, Buffer->GetSize(), (uint32)pFunc, &StackCorrupted);
+ }
+ delete Buffer;
+
+ // return
+ switch (Function->returns) {
+ case TYPE_BOOL:
+ Stack->PushBool((byte)ret != 0);
+ break;
+ case TYPE_LONG:
+ Stack->PushInt(ret);
+ break;
+ case TYPE_BYTE:
+ Stack->PushInt((byte)ret);
+ break;
+ break;
+ case TYPE_STRING:
+ Stack->PushString((char *)ret);
+ break;
+ case TYPE_MEMBUFFER: {
+ CSXMemBuffer *Buf = new CSXMemBuffer(Game, (void *)ret);
+ Stack->PushNative(Buf, false);
+ }
+ break;
+ case TYPE_FLOAT: {
+ uint32 dw = GetST0();
+ Stack->PushFloat(*((float *)&dw));
+ break;
+ }
+ case TYPE_DOUBLE:
+ Stack->PushFloat(GetST0Double());
+ break;
+
+ default:
+ Stack->PushNULL();
+ }
+
+ if (StackCorrupted) RuntimeError("Warning: Stack corrupted after calling '%s' in '%s'\n Check parameters and/or calling convention.", Function->name, Function->dll_name);
+ } else RuntimeError("Exported function '%s' not found in '%s'", Function->name, Function->dll_name);
+ } else RuntimeError("Error loading DLL '%s'", Function->dll_name);
+
+ if (!Success) {
+ Stack->CorrectParams(0);
+ Stack->PushNULL();
+ }
+
+ if (hDll) FreeLibrary(hDll);
+
+ return Success ? S_OK : E_FAIL;
+#endif
+}
+
+#ifdef __WIN32__
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::Call_cdecl(const void *args, size_t sz, uint32 func, bool *StackCorrupt) {
+ uint32 rc; // here's our return value...
+ uint32 OrigESP;
+ bool StkCorrupt = false;
+ __asm {
+ mov OrigESP, esp
+ mov ecx, sz // get size of buffer
+ mov esi, args // get buffer
+ sub esp, ecx // allocate stack space
+ mov edi, esp // start of destination stack frame
+ shr ecx, 2 // make it dwords
+ rep movsd // copy params to real stack
+ call [func] // call the function
+ mov rc, eax // save the return value
+ add esp, sz // restore the stack pointer
+ cmp esp, OrigESP
+ jz finish
+ mov esp, OrigESP
+ mov StkCorrupt, 1
+ finish:
+ }
+
+ if (StackCorrupt) *StackCorrupt = StkCorrupt;
+ return rc;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+uint32 CScScript::Call_stdcall(const void *args, size_t sz, uint32 func, bool *StackCorrupt) {
+ uint32 rc; // here's our return value...
+ uint32 OrigESP;
+ bool StkCorrupt = false;
+
+ __asm {
+ mov OrigESP, esp
+ mov ecx, sz // get size of buffer
+ mov esi, args // get buffer
+ sub esp, ecx // allocate stack space
+ mov edi, esp // start of destination stack frame
+ shr ecx, 2 // make it dwords
+ rep movsd // copy it
+ call [func] // call the function
+ mov rc, eax // save the return value
+ cmp esp, OrigESP
+ jz finish
+ mov esp, OrigESP
+ mov StkCorrupt, 1
+ finish:
+ }
+
+ if (StackCorrupt) *StackCorrupt = StkCorrupt;
+ return rc;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+__declspec(naked) uint32 CScScript::GetST0(void) {
+ uint32 f; // temp var
+ __asm {
+ fstp uint32 ptr [f] // pop ST0 into f
+ mov eax, uint32 ptr [f] // copy into eax
+ ret // done
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+double CScScript::GetST0Double(void) {
+ double d; // temp var
+ __asm {
+ fstp qword ptr [d] // get ST0 into d
+ }
+ return d;
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::CopyParameters(CScStack *Stack) {
+ int i;
+ int NumParams = Stack->Pop()->GetInt();
+ for (i = NumParams - 1; i >= 0; i--) {
+ _stack->Push(Stack->GetAt(i));
+ }
+ _stack->PushInt(NumParams);
+
+ for (i = 0; i < NumParams; i++) Stack->Pop();
+
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::FinishThreads() {
+ for (int i = 0; i < _engine->_scripts.GetSize(); i++) {
+ CScScript *Scr = _engine->_scripts[i];
+ if (Scr->_thread && Scr->_state != SCRIPT_FINISHED && Scr->_owner == _owner && scumm_stricmp(Scr->_filename, _filename) == 0)
+ Scr->Finish(true);
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// IWmeDebugScript interface implementation
+int CScScript::DbgGetLine() {
+ return _currentLine;
+}
+
+//////////////////////////////////////////////////////////////////////////
+const char *CScScript::DbgGetFilename() {
+ return _filename;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::DbgSendScript(IWmeDebugClient *Client) {
+ if (_methodThread) Client->OnScriptMethodThreadInit(this, _parentScript, _threadEvent);
+ else if (_thread) Client->OnScriptEventThreadInit(this, _parentScript, _threadEvent);
+ else Client->OnScriptInit(this);
+
+ return DbgSendVariables(Client);
+ return S_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+HRESULT CScScript::DbgSendVariables(IWmeDebugClient *Client) {
+ // send script globals
+ _globals->DbgSendVariables(Client, WME_DBGVAR_SCRIPT, this, 0);
+
+ // send scope variables
+ if (_scopeStack->_sP >= 0) {
+ for (int i = 0; i <= _scopeStack->_sP; i++) {
+ // CScValue *Scope = _scopeStack->GetAt(i);
+ //Scope->DbgSendVariables(Client, WME_DBGVAR_SCOPE, this, (unsigned int)Scope);
+ }
+ }
+ return S_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+TScriptState CScScript::DbgGetState() {
+ return _state;
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CScScript::DbgGetNumBreakpoints() {
+ return _breakpoints.GetSize();
+}
+
+//////////////////////////////////////////////////////////////////////////
+int CScScript::DbgGetBreakpoint(int Index) {
+ if (Index >= 0 && Index < _breakpoints.GetSize()) return _breakpoints[Index];
+ else return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CScScript::DbgSetTracingMode(bool IsTracing) {
+ _tracingMode = IsTracing;
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CScScript::DbgGetTracingMode() {
+ return _tracingMode;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CScScript::AfterLoad() {
+ if (_buffer == NULL) {
+ byte *buffer = _engine->GetCompiledScript(_filename, &_bufferSize);
+ if (!buffer) {
+ Game->LOG(0, "Error reinitializing script '%s' after load. Script will be terminated.", _filename);
+ _state = SCRIPT_ERROR;
+ return;
+ }
+
+ _buffer = new byte [_bufferSize];
+ memcpy(_buffer, buffer, _bufferSize);
+
+ InitTables();
+ }
+}
+
+} // end of namespace WinterMute
|