[Scummvm-cvs-logs] SF.net SVN: scummvm:[35670] scummvm/trunk/engines/saga

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Fri Jan 2 14:59:34 CET 2009


Revision: 35670
          http://scummvm.svn.sourceforge.net/scummvm/?rev=35670&view=rev
Author:   thebluegr
Date:     2009-01-02 13:59:34 +0000 (Fri, 02 Jan 2009)

Log Message:
-----------
Rewrote the SAGA script system to use an opcode table, like in other engines

Modified Paths:
--------------
    scummvm/trunk/engines/saga/script.cpp
    scummvm/trunk/engines/saga/script.h
    scummvm/trunk/engines/saga/sfuncs.cpp
    scummvm/trunk/engines/saga/sthread.cpp

Modified: scummvm/trunk/engines/saga/script.cpp
===================================================================
--- scummvm/trunk/engines/saga/script.cpp	2009-01-02 09:53:11 UTC (rev 35669)
+++ scummvm/trunk/engines/saga/script.cpp	2009-01-02 13:59:34 UTC (rev 35670)
@@ -41,8 +41,9 @@
 
 namespace Saga {
 
+#define RID_SCENE1_VOICE_START 57
+#define RID_SCENE1_VOICE_END 186
 
-
 // Initializes the scripting module.
 // Loads script resource look-up table, initializes script data system
 Script::Script(SagaEngine *vm) : _vm(vm) {
@@ -161,6 +162,7 @@
 	_vm->loadStrings(_mainStrings, stringsPointer, stringsLength);
 	free(stringsPointer);
 
+	setupScriptOpcodeList();
 	setupScriptFuncList();
 }
 
@@ -179,6 +181,823 @@
 	free(_commonBuffer);
 }
 
+// Script opcodes
+#define OPCODE(x) {&Script::x, #x}
+
+void Script::setupScriptOpcodeList() {
+	static const ScriptOpDescription SAGA1ScriptOpcodes[] = {
+		OPCODE(opDummy),		// 00: Undefined
+		// Internal operations
+		OPCODE(opNextBlock),	// 01: Continue execution at next block
+		OPCODE(opDup),			// 02: Duplicate 16-bit value on stack
+		OPCODE(opDrop),			// 03: Drop 16-bit value on stack
+		// Primary values
+		OPCODE(opZero),			// 04: Push a zero on the stack
+		OPCODE(opOne),			// 05: Push a one on the stack
+		OPCODE(opConstInt),		// 06: Constant integer
+		OPCODE(opDummy),		// 07: Constant ID reference (unused)
+		OPCODE(opStrLit),		// 08: String literal
+		OPCODE(opDummy),		// 09: Symbol address (unused)
+		OPCODE(opDummy),		// 10: Symbol contents (unused)
+		// References within this module
+		OPCODE(opGetFlag),		// 11: Read flag bit
+		OPCODE(opGetInt),		// 12: Read integer
+		OPCODE(opDummy),		// 13: Read string (unused)
+		OPCODE(opDummy),		// 14: Read id (unused)
+		OPCODE(opPutFlag),		// 15: Write flag bit
+		OPCODE(opPutInt),		// 16: Write integer
+		OPCODE(opDummy),		// 17: Write string (unused)
+		OPCODE(opDummy),		// 18: Write id (unused)
+		// Void versions, which consume their arguments
+		OPCODE(opPutFlagV),		// 19: Write flag bit
+		OPCODE(opPutIntV),		// 20: Write integer
+		OPCODE(opDummy),		// 21: Write string (unused)
+		OPCODE(opDummy),		// 22: Write id (unused)
+		// Function calling
+		OPCODE(opCall),			// 23: Call function
+		OPCODE(opCcall),		// 24: Call C function
+		OPCODE(opCcallV),		// 25: Call C function (void)
+		OPCODE(opEnter),		// 26: Enter a function
+		OPCODE(opReturn),		// 27: Return from a function
+		OPCODE(opReturnV),		// 28: Return from a function (void)
+		// Branching
+		OPCODE(opJmp),			// 29
+		OPCODE(opJmpTrueV),		// 30: Test argument and consume it
+		OPCODE(opJmpFalseV),	// 31: Test argument and consume it
+		OPCODE(opJmpTrue),		// 32: Test argument but don't consume it
+		OPCODE(opJmpFalse),		// 33: Test argument but don't consume it
+		OPCODE(opJmpSwitch),	// 34: Switch (integer)
+		OPCODE(opDummy),		// 35: Switch (string) (unused)
+		OPCODE(opJmpRandom),	// 36: Random jump
+		// Unary operators
+		OPCODE(opNegate),		// 37
+		OPCODE(opNot),			// 38
+		OPCODE(opCompl),		// 39
+		OPCODE(opIncV),			// 40: Increment, don't push
+		OPCODE(opDecV),			// 41: Increment, don't push
+		OPCODE(opPostInc),		// 42
+		OPCODE(opPostDec),		// 43
+		// Arithmetic
+		OPCODE(opAdd),			// 44
+		OPCODE(opSub),			// 45
+		OPCODE(opMul),			// 46
+		OPCODE(opDiv),			// 47
+		OPCODE(opMod),			// 48
+		// Conditional
+		OPCODE(opDummy),		// 49: opConditional (unused)
+		OPCODE(opDummy),		// 50: opComma (unused)
+		// Comparison
+		OPCODE(opEq),			// 51
+		OPCODE(opNe),			// 52
+		OPCODE(opGt),			// 53
+		OPCODE(opLt),			// 54
+		OPCODE(opGe),			// 55
+		OPCODE(opLe),			// 56
+		// String comparison
+		OPCODE(opDummy),		// 57: opStrEq (unused)
+		OPCODE(opDummy),		// 58: opStrNe (unused)
+		OPCODE(opDummy),		// 59: opStrGt (unused)
+		OPCODE(opDummy),		// 60: opStrLt (unused)
+		OPCODE(opDummy),		// 61: opStrGe (unused)
+		OPCODE(opDummy),		// 62: opStrLe (unused)
+		// Shift
+		OPCODE(opRsh),			// 63
+		OPCODE(opLsh),			// 64
+		// Bitwise
+		OPCODE(opAnd),			// 65
+		OPCODE(opOr),			// 66
+		OPCODE(opXor),			// 67
+		// Logical
+		OPCODE(opLAnd),			// 68
+		OPCODE(opLOr),			// 69
+		OPCODE(opLXor),			// 70
+		// String manipulation
+		OPCODE(opDummy),		// 71: opStrCat, string concatenation (unused)
+		OPCODE(opDummy),		// 72: opStrFormat, string formatting (unused)
+		// Assignment 
+		OPCODE(opDummy),		// 73: assign (unused)
+		OPCODE(opDummy),		// 74: += (unused)
+		OPCODE(opDummy),		// 75: -= (unused)
+		OPCODE(opDummy),		// 76: *= (unused)
+		OPCODE(opDummy),		// 77: /= (unused)
+		OPCODE(opDummy),		// 78: %= (unused)
+		OPCODE(opDummy),		// 79: <<= (unused)
+		OPCODE(opDummy),		// 80: >>= (unused)
+		OPCODE(opDummy),		// 81: and (unused)
+		OPCODE(opDummy),		// 82: or (unused)
+		// Special
+		OPCODE(opSpeak),		// 83
+		OPCODE(opDialogBegin),	// 84
+		OPCODE(opDialogEnd),	// 85
+		OPCODE(opReply),		// 86
+		OPCODE(opAnimate)		// 87
+	};
+
+	static const ScriptOpDescription SAGA2ScriptOpcodes[] = {
+		OPCODE(opDummy),		// 00: Undefined
+		// Internal operations
+		OPCODE(opNextBlock),	// 01: Continue execution at next block
+		OPCODE(opDup),			// 02: Duplicate 16-bit value on stack
+		OPCODE(opDrop),			// 03: Drop 16-bit value on stack
+		// Primary values
+		OPCODE(opZero),			// 04: Push a zero on the stack
+		OPCODE(opOne),			// 05: Push a one on the stack
+		OPCODE(opConstInt),		// 06: Constant integer
+		OPCODE(opDummy),		// 07: Constant ID reference (unused)
+		OPCODE(opStrLit),		// 08: String literal
+		OPCODE(opDummy),		// 09: Symbol address (unused)
+		OPCODE(opDummy),		// 10: Symbol contents (unused)
+		OPCODE(opDummy),		// 11: Reference to "this" (unused)
+		OPCODE(opDummy),		// 12: Dereference of an ID (unused)
+		// References within this module
+		OPCODE(opGetFlag),		// 13: Read flag bit
+		OPCODE(opGetByte),		// 14: Read byte
+		OPCODE(opGetInt),		// 15: Read integer
+		OPCODE(opDummy),		// 16: Read string (unused)
+		OPCODE(opDummy),		// 17: Read id (unused)
+		OPCODE(opPutFlag),		// 18: Write flag bit
+		OPCODE(opPutByte),		// 19: Write byte
+		OPCODE(opPutInt),		// 20: Write integer
+		OPCODE(opDummy),		// 21: Write string (unused)
+		OPCODE(opDummy),		// 22: Write id (unused)
+		OPCODE(opDummy),		// 23: Push effective address (unused)
+		// Void versions, which consume their arguments
+		OPCODE(opPutFlagV),		// 24: Write flag bit
+		OPCODE(opPutByteV),		// 25: Write byte
+		OPCODE(opPutIntV),		// 26: Write integer
+		OPCODE(opDummy),		// 27: Write string (unused)
+		OPCODE(opDummy),		// 28: Write id (unused)
+		// Function calling
+		OPCODE(opCallNear),		// 29: Call function in the same segment
+		OPCODE(opCallFar),		// 30: Call function in other segment
+		OPCODE(opCcall),		// 31: Call C function
+		OPCODE(opCcallV),		// 32: Call C function (void)
+		OPCODE(opCallMember),	// 33: Call member function
+		OPCODE(opCallMemberV),	// 34: Call member function (void)
+		OPCODE(opEnter),		// 35: Enter a function
+		OPCODE(opReturn),		// 36: Return from a function
+		OPCODE(opReturnV),		// 37: Return from a function (void)
+		// Branching
+		OPCODE(opJmp),			// 38
+		OPCODE(opJmpTrueV),		// 39: Test argument and consume it
+		OPCODE(opJmpFalseV),	// 40: Test argument and consume it
+		OPCODE(opJmpTrue),		// 41: Test argument but don't consume it
+		OPCODE(opJmpFalse),		// 42: Test argument but don't consume it
+		OPCODE(opJmpSwitch),	// 43: Switch (integer)
+		OPCODE(opDummy),		// 44: Switch (string) (unused)
+		OPCODE(opJmpRandom),	// 45: Random jump
+		// Unary operators
+		OPCODE(opNegate),		// 46
+		OPCODE(opNot),			// 47
+		OPCODE(opCompl),		// 48
+		OPCODE(opIncV),			// 49: Increment, don't push
+		OPCODE(opDecV),			// 50: Increment, don't push
+		OPCODE(opPostInc),		// 51
+		OPCODE(opPostDec),		// 52
+		// Arithmetic
+		OPCODE(opAdd),			// 53
+		OPCODE(opSub),			// 54
+		OPCODE(opMul),			// 55
+		OPCODE(opDiv),			// 56
+		OPCODE(opMod),			// 57
+		// Conditional
+		OPCODE(opDummy),		// 58: opConditional (unused)
+		OPCODE(opDummy),		// 59: opComma (unused)
+		// Comparison
+		OPCODE(opEq),			// 60
+		OPCODE(opNe),			// 61
+		OPCODE(opGt),			// 62
+		OPCODE(opLt),			// 63
+		OPCODE(opGe),			// 64
+		OPCODE(opLe),			// 65
+		// String comparison
+		OPCODE(opDummy),		// 66: opStrEq (unused)
+		OPCODE(opDummy),		// 67: opStrNe (unused)
+		OPCODE(opDummy),		// 68: opStrGt (unused)
+		OPCODE(opDummy),		// 69: opStrLt (unused)
+		OPCODE(opDummy),		// 70: opStrGe (unused)
+		OPCODE(opDummy),		// 71: opStrLe (unused)
+		// Shift
+		OPCODE(opRsh),			// 72
+		OPCODE(opLsh),			// 73
+		// Bitwise
+		OPCODE(opAnd),			// 74
+		OPCODE(opOr),			// 75
+		OPCODE(opXor),			// 76
+		// Logical
+		OPCODE(opLAnd),			// 77
+		OPCODE(opLOr),			// 78
+		OPCODE(opLXor),			// 79
+		// String manipulation
+		OPCODE(opDummy),		// 80: opStrCat, string concatenation (unused)
+		OPCODE(opDummy),		// 81: opStrFormat, string formatting (unused)
+		// Assignment 
+		OPCODE(opDummy),		// 82: assign (unused)
+		OPCODE(opDummy),		// 83: += (unused)
+		OPCODE(opDummy),		// 84: -= (unused)
+		OPCODE(opDummy),		// 85: *= (unused)
+		OPCODE(opDummy),		// 86: /= (unused)
+		OPCODE(opDummy),		// 87: %= (unused)
+		OPCODE(opDummy),		// 88: <<= (unused)
+		OPCODE(opDummy),		// 89: >>= (unused)
+		OPCODE(opDummy),		// 90: and (unused)
+		OPCODE(opDummy),		// 91: or (unused)
+		// Special
+		OPCODE(opSpeak),		// 92
+		OPCODE(opDialogBegin),	// 93
+		OPCODE(opDialogEnd),	// 94
+		OPCODE(opReply),		// 95
+		OPCODE(opAnimate),		// 96
+		OPCODE(opJmpSeedRandom),// 97: Seeded random jump
+		OPCODE(opDummy)			// 98: Get seeded export number (unused)
+	};
+
+	if (!_vm->isSaga2()) {
+		_scriptOpsList = SAGA1ScriptOpcodes;
+	} else {
+		_scriptOpsList = SAGA2ScriptOpcodes;		
+	}
+}
+
+
+void Script::opDup(SCRIPTOP_PARAMS) {
+	thread->push(thread->stackTop());
+}
+
+void Script::opDrop(SCRIPTOP_PARAMS) {
+	thread->pop();
+}
+
+void Script::opZero(SCRIPTOP_PARAMS) {
+	thread->push(0);
+}
+
+void Script::opOne(SCRIPTOP_PARAMS) {
+	thread->push(1);
+}
+
+void Script::opConstInt(SCRIPTOP_PARAMS) {
+	thread->push(scriptS->readSint16LE());
+}
+
+void Script::opStrLit(SCRIPTOP_PARAMS) {
+	thread->push(scriptS->readSint16LE());
+}
+
+void Script::opGetFlag(SCRIPTOP_PARAMS) {
+	byte *addr = thread->baseAddress(scriptS->readByte());
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += (iparam1 >> 3);
+	iparam1 = (1 << (iparam1 & 7));
+	thread->push((*addr) & iparam1 ? 1 : 0);
+}
+
+void Script::opGetByte(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opGetByte");
+}
+
+void Script::opGetInt(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	thread->push(readUint16(addr, mode));
+	debug(8, "0x%X", readUint16(addr, mode));
+}
+
+void Script::opPutFlag(SCRIPTOP_PARAMS) {
+	byte *addr = thread->baseAddress(scriptS->readByte());
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += (iparam1 >> 3);
+	iparam1 = (1 << (iparam1 & 7));
+	if (thread->stackTop()) {
+		*addr |= iparam1;
+	} else {
+		*addr &= ~iparam1;
+	}
+}
+
+void Script::opPutByte(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opPutByte");
+}
+
+void Script::opPutInt(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	writeUint16(addr, thread->stackTop(), mode);
+}
+
+void Script::opPutFlagV(SCRIPTOP_PARAMS) {
+	byte *addr = thread->baseAddress(scriptS->readByte());
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += (iparam1 >> 3);
+	iparam1 = (1 << (iparam1 & 7));
+	if (thread->pop()) {
+		*addr |= iparam1;
+	} else {
+		*addr &= ~iparam1;
+	}
+}
+
+void Script::opPutByteV(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opPutByteV");
+}
+
+void Script::opPutIntV(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	writeUint16(addr, thread->pop(), mode);
+}
+
+void Script::opCall(SCRIPTOP_PARAMS) {
+	byte argumentsCount = scriptS->readByte();
+	int16 iparam1 = scriptS->readByte();
+	if (iparam1 != kAddressModule) {
+		error("Script::runThread iparam1 != kAddressModule");
+	}
+	byte *addr = thread->baseAddress(iparam1);
+	iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	thread->push(argumentsCount);
+
+	// NOTE: The original pushes the program
+	// counter as a pointer here. But I don't think
+	// we will have to do that.
+	thread->push(scriptS->pos());
+	// NOTE2: program counter is 32bit - so we should "emulate" it size - because kAddressStack relies on it
+	thread->push(0);
+	thread->_instructionOffset = iparam1;
+}
+
+void Script::opCallNear(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opCallNear");
+}
+
+void Script::opCallFar(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opCallFar");
+}
+
+void Script::opCcall(SCRIPTOP_PARAMS) {
+	byte argumentsCount = scriptS->readByte();
+	uint16 functionNumber = scriptS->readUint16LE();
+	if (functionNumber >= ((_vm->getGameId() == GID_IHNM) ?
+						   IHNM_SCRIPT_FUNCTION_MAX : ITE_SCRIPT_FUNCTION_MAX)) {
+		error("Script::opCcall() Invalid script function number (%d)", functionNumber);
+	}
+
+	debug(2, "Calling #%d %s argCount=%i", functionNumber, _scriptFunctionsList[functionNumber].scriptFunctionName, argumentsCount);
+	ScriptFunctionType scriptFunction = _scriptFunctionsList[functionNumber].scriptFunction;
+	uint16 checkStackTopIndex = thread->_stackTopIndex + argumentsCount;
+	(this->*scriptFunction)(thread, argumentsCount, stopParsing);
+	if (stopParsing)
+		return;
+
+	if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
+		scriptFunction == &Saga::Script::sfVsetTrack) {
+		stopParsing = true; // cause abortAllThreads called and _this_ thread destroyed
+		return;
+	}
+
+	thread->_stackTopIndex = checkStackTopIndex;
+
+	thread->push(thread->_returnValue);		// return value
+
+	if (thread->_flags & kTFlagAsleep)
+		breakOut = true;	// break out of loop!
+}
+
+void Script::opCallMember(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opCallMember");
+}
+
+void Script::opCallMemberV(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opCallMemberV");
+}
+
+void Script::opCcallV(SCRIPTOP_PARAMS) {
+	byte argumentsCount = scriptS->readByte();
+	uint16 functionNumber = scriptS->readUint16LE();
+	if (functionNumber >= ((_vm->getGameId() == GID_IHNM) ?
+						   IHNM_SCRIPT_FUNCTION_MAX : ITE_SCRIPT_FUNCTION_MAX)) {
+		error("Script::opCcallV() Invalid script function number (%d)", functionNumber);
+	}
+
+	debug(2, "Calling #%d %s argCount=%i", functionNumber, _scriptFunctionsList[functionNumber].scriptFunctionName, argumentsCount);
+	ScriptFunctionType scriptFunction = _scriptFunctionsList[functionNumber].scriptFunction;
+	uint16 checkStackTopIndex = thread->_stackTopIndex + argumentsCount;
+	(this->*scriptFunction)(thread, argumentsCount, stopParsing);
+	if (stopParsing)
+		return;
+	
+	if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
+		scriptFunction == &Saga::Script::sfVsetTrack) {
+		stopParsing = true;
+		return;		// cause abortAllThreads called and _this_ thread destroyed
+	}
+
+	thread->_stackTopIndex = checkStackTopIndex;
+
+	if (thread->_flags & kTFlagAsleep)
+		breakOut = true;	// break out of loop!
+}
+
+void Script::opEnter(SCRIPTOP_PARAMS) {
+	thread->push(thread->_frameIndex);
+	thread->_frameIndex = thread->_stackTopIndex;
+	thread->_stackTopIndex -= (scriptS->readSint16LE() / 2);
+}
+
+void Script::opReturn(SCRIPTOP_PARAMS) {
+	thread->_returnValue = thread->pop();		// return value
+
+	thread->_stackTopIndex = thread->_frameIndex;
+	thread->_frameIndex = thread->pop();
+	if (thread->pushedSize() == 0) {
+		thread->_flags |= kTFlagFinished;
+		stopParsing = true;
+		return;
+	} else {
+		thread->pop(); //cause it 0
+		thread->_instructionOffset = thread->pop();
+
+		// Pop all the call parameters off the stack
+		int16 iparam1 = thread->pop();
+		while (iparam1--) {
+			thread->pop();
+		}
+
+		thread->push(thread->_returnValue);
+	}
+}
+
+void Script::opReturnV(SCRIPTOP_PARAMS) {
+	thread->_stackTopIndex = thread->_frameIndex;
+	thread->_frameIndex = thread->pop();
+	if (thread->pushedSize() == 0) {
+		thread->_flags |= kTFlagFinished;
+		stopParsing = true;
+		return;
+	} else {
+		thread->pop(); //cause it 0
+		thread->_instructionOffset = thread->pop();
+
+		// Pop all the call parameters off the stack
+		int16 iparam1 = thread->pop();
+		while (iparam1--) {
+			thread->pop();
+		}
+	}
+}
+
+void Script::opJmp(SCRIPTOP_PARAMS) {
+	thread->_instructionOffset = scriptS->readUint16LE();
+}
+
+void Script::opJmpTrueV(SCRIPTOP_PARAMS) {
+	uint16 jmpOffset1 = scriptS->readUint16LE();
+	if (thread->pop())
+		thread->_instructionOffset = jmpOffset1;
+}
+
+void Script::opJmpFalseV(SCRIPTOP_PARAMS) {
+	uint16 jmpOffset1 = scriptS->readUint16LE();
+	if (!thread->pop())
+		thread->_instructionOffset = jmpOffset1;
+}
+
+void Script::opJmpTrue(SCRIPTOP_PARAMS) {
+	uint16 jmpOffset1 = scriptS->readUint16LE();
+	if (thread->stackTop())
+		thread->_instructionOffset = jmpOffset1;
+}
+
+void Script::opJmpFalse(SCRIPTOP_PARAMS) {
+	uint16 jmpOffset1 = scriptS->readUint16LE();
+	if (!thread->stackTop())
+		thread->_instructionOffset = jmpOffset1;
+}
+
+void Script::opJmpSwitch(SCRIPTOP_PARAMS) {
+	int16 iparam1 = scriptS->readSint16LE();
+	int16 iparam2 = thread->pop();
+	int16 iparam3;
+
+	while (iparam1--) {
+		iparam3 = scriptS->readUint16LE();
+		thread->_instructionOffset = scriptS->readUint16LE();
+		if (iparam3 == iparam2)
+			break;
+	}
+
+	if (iparam1 < 0)
+		thread->_instructionOffset = scriptS->readUint16LE();
+}
+
+void Script::opJmpRandom(SCRIPTOP_PARAMS) {
+	// Supposedly the number of possible branches.
+	// The original interpreter ignores it.
+	scriptS->readUint16LE();
+	int16 iparam1 = scriptS->readSint16LE();
+	iparam1 = _vm->_rnd.getRandomNumber(iparam1 - 1);
+	int16 iparam2;
+
+	while (1) {
+		iparam2 = scriptS->readSint16LE();
+		thread->_instructionOffset = scriptS->readUint16LE();
+
+		iparam1 -= iparam2;
+		if (iparam1 < 0)
+			break;
+	}
+}
+
+void Script::opNegate(SCRIPTOP_PARAMS) {
+	thread->push(-thread->pop());
+}
+
+void Script::opNot(SCRIPTOP_PARAMS) {
+	thread->push(!thread->pop());
+}
+
+void Script::opCompl(SCRIPTOP_PARAMS) {
+	thread->push(~thread->pop());
+}
+
+void Script::opIncV(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	iparam1 = readUint16(addr, mode);
+	writeUint16(addr, iparam1 + 1, mode);
+}
+
+void Script::opDecV(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	iparam1 = readUint16(addr, mode);
+	writeUint16(addr, iparam1 - 1, mode);
+}
+
+void Script::opPostInc(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	iparam1 = readUint16(addr, mode);
+	thread->push(iparam1);
+	writeUint16(addr, iparam1 + 1, mode);
+}
+
+void Script::opPostDec(SCRIPTOP_PARAMS) {
+	byte mode = scriptS->readByte();
+	byte *addr = thread->baseAddress(mode);
+	int16 iparam1 = scriptS->readSint16LE();
+	addr += iparam1;
+	iparam1 = readUint16(addr, mode);
+	thread->push(iparam1);
+	writeUint16(addr, iparam1 - 1, mode);
+}
+
+void Script::opAdd(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 + iparam2);
+}
+
+void Script::opSub(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 - iparam2);
+}
+
+void Script::opMul(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 * iparam2);
+}
+
+void Script::opDiv(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 / iparam2);
+}
+
+void Script::opMod(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 % iparam2);
+}
+
+void Script::opEq(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 == iparam2) ? 1 : 0);
+}
+
+void Script::opNe(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 != iparam2) ? 1 : 0);
+}
+
+void Script::opGt(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 > iparam2) ? 1 : 0);
+}
+
+void Script::opLt(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 < iparam2) ? 1 : 0);
+}
+
+void Script::opGe(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 >= iparam2) ? 1 : 0);
+}
+
+void Script::opLe(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 <= iparam2) ? 1 : 0);
+}
+
+void Script::opRsh(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 >> iparam2);
+}
+
+void Script::opLsh(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 << iparam2);
+}
+
+void Script::opAnd(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 & iparam2);
+}
+
+void Script::opOr(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 | iparam2);
+}
+
+void Script::opXor(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(iparam1 ^ iparam2);
+}
+
+void Script::opLAnd(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 && iparam2) ? 1 : 0);
+}
+
+void Script::opLOr(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push((iparam1 || iparam2) ? 1 : 0);
+}
+
+void Script::opLXor(SCRIPTOP_PARAMS) {
+	int16 iparam2 = thread->pop();
+	int16 iparam1 = thread->pop();
+	thread->push(((iparam1 && !iparam2) || (!iparam1 && iparam2)) ? 1 : 0);
+}
+
+void Script::opSpeak(SCRIPTOP_PARAMS) {
+	if (_vm->_actor->isSpeaking()) {
+		thread->wait(kWaitTypeSpeech);
+		stopParsing = false;
+		return;
+	}
+
+	int stringsCount = scriptS->readByte();
+	uint16 actorId = scriptS->readUint16LE();
+	uint16 speechFlags = scriptS->readByte();
+	int sampleResourceId = -1;
+	int16 first;
+	const char *strings[ACTOR_SPEECH_STRING_MAX];
+
+	scriptS->readUint16LE(); // x,y skip
+
+	if (stringsCount == 0)
+		error("opSpeak stringsCount == 0");
+
+	if (stringsCount > ACTOR_SPEECH_STRING_MAX)
+		error("opSpeak stringsCount=0x%X exceed ACTOR_SPEECH_STRING_MAX", stringsCount);
+
+	int16 iparam1 = first = thread->stackTop();
+	for (int i = 0; i < stringsCount; i++) {
+		iparam1 = thread->pop();
+		strings[i] = thread->_strings->getString(iparam1);
+	}
+
+	// now data contains last string index
+
+	if (_vm->getFeatures() & GF_OLD_ITE_DOS) { // special ITE dos
+		if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) &&
+			(iparam1 >= 288) && (iparam1 <= (RID_SCENE1_VOICE_END - RID_SCENE1_VOICE_START + 288))) {
+			sampleResourceId = RID_SCENE1_VOICE_START + iparam1 - 288;
+		}
+	} else {
+		if (thread->_voiceLUT->voicesCount > first)
+			sampleResourceId = thread->_voiceLUT->voices[first];
+	}
+
+	if (sampleResourceId < 0 || sampleResourceId > 4000)
+		sampleResourceId = -1;
+
+	if (_vm->getGameId() == GID_ITE && !sampleResourceId)
+		sampleResourceId = -1;
+
+	_vm->_actor->actorSpeech(actorId, strings, stringsCount, sampleResourceId, speechFlags);
+
+	if (!(speechFlags & kSpeakAsync)) {
+		thread->wait(kWaitTypeSpeech);
+	}
+}
+
+void Script::opDialogBegin(SCRIPTOP_PARAMS) {
+	if (_conversingThread) {
+		thread->wait(kWaitTypeDialogBegin);
+		stopParsing = false;
+		return;
+	}
+	_conversingThread = thread;
+	_vm->_interface->converseClear();
+}
+
+void Script::opDialogEnd(SCRIPTOP_PARAMS) {
+	if (thread == _conversingThread) {
+		_vm->_interface->activate();
+		_vm->_interface->setMode(kPanelConverse);
+		thread->wait(kWaitTypeDialogEnd);
+		stopParsing = false;
+		return;
+	}
+}
+
+void Script::opReply(SCRIPTOP_PARAMS) {
+	const char *str;
+	byte replyNum = scriptS->readByte();
+	byte flags = scriptS->readByte();
+	int16 iparam1 = 0;
+	int strID = thread->pop();
+
+	if (flags & kReplyOnce) {
+		iparam1 = scriptS->readSint16LE();
+		byte *addr = thread->_staticBase + (iparam1 >> 3);
+		if (*addr & (1 << (iparam1 & 7))) {
+			return;
+		}
+	}
+
+	str = thread->_strings->getString(strID);
+	if (_vm->_interface->converseAddText(str, strID, replyNum, flags, iparam1))
+		warning("Error adding ConverseText (%s, %d, %d, %d)", str, replyNum, flags, iparam1);
+}
+
+void Script::opAnimate(SCRIPTOP_PARAMS) {
+	scriptS->readUint16LE();
+	scriptS->readUint16LE();
+	thread->_instructionOffset += scriptS->readByte();
+}
+
+void Script::opJmpSeedRandom(SCRIPTOP_PARAMS) {
+	// SAGA 2 opcode
+	// TODO
+	warning("opJmpSeedRandom");
+}
+
 void Script::loadModule(int scriptModuleNumber) {
 	byte *resourcePointer;
 	size_t resourceLength;

Modified: scummvm/trunk/engines/saga/script.h
===================================================================
--- scummvm/trunk/engines/saga/script.h	2009-01-02 09:53:11 UTC (rev 35669)
+++ scummvm/trunk/engines/saga/script.h	2009-01-02 13:59:34 UTC (rev 35670)
@@ -109,75 +109,6 @@
 	kWaitTypeWakeUp = 11		// IHNM. wait until get waken up
 };
 
-enum OpCodes {
-	opNextBlock = 0x01,
-	opDup = 0x02,
-	opDrop = 0x03,
-	opZero = 0x04,
-	opOne = 0x05,
-	opConstint = 0x06,
-//...
-	opStrlit = 0x08,
-//...
-	opGetFlag = 0x0B,
-	opGetInt = 0x0C,
-//...
-	opPutFlag = 0x0F,
-	opPutInt = 0x10,
-	//...
-	opPutFlagV = 0x13,
-	opPutIntV = 0x14,
-//...
-	opCall = 0x17,
-	opCcall = 0x18,
-	opCcallV = 0x19,
-	opEnter = 0x1A,
-	opReturn = 0x1B,
-	opReturnV = 0x1C,
-	opJmp = 0x1D,
-	opJmpTrueV = 0x1E,
-	opJmpFalseV = 0x1F,
-	opJmpTrue = 0x20,
-	opJmpFalse = 0x21,
-	opJmpSwitch = 0x22,
-//...
-	opJmpRandom = 0x24,
-	opNegate = 0x25,
-	opNot = 0x26,
-	opCompl = 0x27,
-	opIncV = 0x28,
-	opDecV = 0x29,
-	opPostInc = 0x2A,
-	opPostDec = 0x2B,
-	opAdd = 0x2C,
-	opSub = 0x2D,
-	opMul = 0x2E,
-	opDiv = 0x2F,
-	opMod = 0x30,
-//...
-	opEq = 0x33,
-	opNe = 0x34,
-	opGt = 0x35,
-	opLt = 0x36,
-	opGe = 0x37,
-	opLe = 0x38,
-//...
-	opRsh = 0x3F,
-	opLsh = 0x40,
-	opAnd = 0x41,
-	opOr = 0x42,
-	opXor = 0x43,
-	opLAnd = 0x44,
-	opLOr = 0x45,
-	opLXor = 0x46,
-//...
-	opSpeak = 0x53,
-	opDialogBegin = 0x54,
-	opDialogEnd = 0x55,
-	opReply = 0x56,
-	opAnimate = 0x57
-};
-
 enum CycleFlags {
 	kCyclePong    = 1 << 0,
 	kCycleOnce    = 1 << 1,
@@ -342,7 +273,7 @@
 
 typedef SortedList<ScriptThread> ScriptThreadList;
 
-
+#define SCRIPTOP_PARAMS ScriptThread *thread, MemoryReadStream *scriptS, bool &stopParsing, bool &breakOut
 #define SCRIPTFUNC_PARAMS ScriptThread *thread, int nArgs, bool &disContinue
 
 class Script {
@@ -472,7 +403,7 @@
 	void loadModuleBase(ModuleData &module, const byte *resourcePointer, size_t resourceLength);
 
 	// runThread returns true if we should break running of other threads
-	bool runThread(ScriptThread *thread, uint instructionLimit);
+	bool runThread(ScriptThread *thread);
 	void setThreadEntrypoint(ScriptThread *thread, int entrypointNumber);
 
 public:
@@ -480,6 +411,85 @@
 
 private:
 
+	// Script opcodes ------------------------------------------------------------
+	typedef void (Script::*ScriptOpType)(SCRIPTOP_PARAMS);
+	struct ScriptOpDescription {
+		ScriptOpType scriptOp;
+		const char *scriptOpName;
+	};
+	const ScriptOpDescription *_scriptOpsList;
+
+	void setupScriptOpcodeList();
+	void opDummy(SCRIPTOP_PARAMS) { warning("Dummy opcode called"); }
+	void opNextBlock(SCRIPTOP_PARAMS) { 
+		thread->_instructionOffset = (((thread->_instructionOffset) >> 10) + 1) << 10;
+	}
+	void opDup(SCRIPTOP_PARAMS);
+	void opDrop(SCRIPTOP_PARAMS);
+	void opZero(SCRIPTOP_PARAMS);
+	void opOne(SCRIPTOP_PARAMS);
+	void opConstInt(SCRIPTOP_PARAMS);
+	void opStrLit(SCRIPTOP_PARAMS);
+	void opGetFlag(SCRIPTOP_PARAMS);
+	void opGetByte(SCRIPTOP_PARAMS);		// SAGA 2
+	void opGetInt(SCRIPTOP_PARAMS);
+	void opPutFlag(SCRIPTOP_PARAMS);
+	void opPutByte(SCRIPTOP_PARAMS);		// SAGA 2
+	void opPutInt(SCRIPTOP_PARAMS);
+	void opPutFlagV(SCRIPTOP_PARAMS);
+	void opPutByteV(SCRIPTOP_PARAMS);
+	void opPutIntV(SCRIPTOP_PARAMS);
+	void opCall(SCRIPTOP_PARAMS);			// SAGA 1
+	void opCallNear(SCRIPTOP_PARAMS);		// SAGA 2
+	void opCallFar(SCRIPTOP_PARAMS);		// SAGA 2
+	void opCcall(SCRIPTOP_PARAMS);
+	void opCcallV(SCRIPTOP_PARAMS);
+	void opCallMember(SCRIPTOP_PARAMS);		// SAGA 2
+	void opCallMemberV(SCRIPTOP_PARAMS);	// SAGA 2
+	void opEnter(SCRIPTOP_PARAMS);
+	void opReturn(SCRIPTOP_PARAMS);
+	void opReturnV(SCRIPTOP_PARAMS);
+	void opJmp(SCRIPTOP_PARAMS);
+	void opJmpTrueV(SCRIPTOP_PARAMS);
+	void opJmpFalseV(SCRIPTOP_PARAMS);
+	void opJmpTrue(SCRIPTOP_PARAMS);
+	void opJmpFalse(SCRIPTOP_PARAMS);
+	void opJmpSwitch(SCRIPTOP_PARAMS);
+	void opJmpRandom(SCRIPTOP_PARAMS);
+	void opNegate(SCRIPTOP_PARAMS);
+	void opNot(SCRIPTOP_PARAMS);
+	void opCompl(SCRIPTOP_PARAMS);
+	void opIncV(SCRIPTOP_PARAMS);
+	void opDecV(SCRIPTOP_PARAMS);
+	void opPostInc(SCRIPTOP_PARAMS);
+	void opPostDec(SCRIPTOP_PARAMS);
+	void opAdd(SCRIPTOP_PARAMS);
+	void opSub(SCRIPTOP_PARAMS);
+	void opMul(SCRIPTOP_PARAMS);
+	void opDiv(SCRIPTOP_PARAMS);
+	void opMod(SCRIPTOP_PARAMS);
+	void opEq(SCRIPTOP_PARAMS);
+	void opNe(SCRIPTOP_PARAMS);
+	void opGt(SCRIPTOP_PARAMS);
+	void opLt(SCRIPTOP_PARAMS);
+	void opGe(SCRIPTOP_PARAMS);
+	void opLe(SCRIPTOP_PARAMS);
+	void opRsh(SCRIPTOP_PARAMS);
+	void opLsh(SCRIPTOP_PARAMS);
+	void opAnd(SCRIPTOP_PARAMS);
+	void opOr(SCRIPTOP_PARAMS);
+	void opXor(SCRIPTOP_PARAMS);
+	void opLAnd(SCRIPTOP_PARAMS);
+	void opLOr(SCRIPTOP_PARAMS);
+	void opLXor(SCRIPTOP_PARAMS);
+	void opSpeak(SCRIPTOP_PARAMS);
+	void opDialogBegin(SCRIPTOP_PARAMS);
+	void opDialogEnd(SCRIPTOP_PARAMS);
+	void opReply(SCRIPTOP_PARAMS);
+	void opAnimate(SCRIPTOP_PARAMS);
+	void opJmpSeedRandom(SCRIPTOP_PARAMS);
+
+	// Script functions ----------------------------------------------------------
 	typedef void (Script::*ScriptFunctionType)(SCRIPTFUNC_PARAMS);
 
 	struct ScriptFunctionDescription {
@@ -488,7 +498,7 @@
 	};
 	const ScriptFunctionDescription *_scriptFunctionsList;
 
-	void setupScriptFuncList(void);
+	void setupScriptFuncList();
 
 	void sfPutString(SCRIPTFUNC_PARAMS);
 	void sfWait(SCRIPTFUNC_PARAMS);
@@ -515,7 +525,7 @@
 	void sfScriptOpenDoor(SCRIPTFUNC_PARAMS);
 	void sfScriptCloseDoor(SCRIPTFUNC_PARAMS);
 	void sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS);
-	void SF_cycleColors(SCRIPTFUNC_PARAMS);
+	void sfCycleColors(SCRIPTFUNC_PARAMS);
 	void sfDoCenterActor(SCRIPTFUNC_PARAMS);
 	void sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS);
 	void sfScriptWalkToAsync(SCRIPTFUNC_PARAMS);

Modified: scummvm/trunk/engines/saga/sfuncs.cpp
===================================================================
--- scummvm/trunk/engines/saga/sfuncs.cpp	2009-01-02 09:53:11 UTC (rev 35669)
+++ scummvm/trunk/engines/saga/sfuncs.cpp	2009-01-02 13:59:34 UTC (rev 35670)
@@ -54,8 +54,8 @@
 
 #define OPCODE(x) {&Script::x, #x}
 
-void Script::setupScriptFuncList(void) {
-	static const ScriptFunctionDescription ITEscriptFunctionsList[ITE_SCRIPT_FUNCTION_MAX] = {
+void Script::setupScriptFuncList() {
+	static const ScriptFunctionDescription ITEScriptFunctionsList[ITE_SCRIPT_FUNCTION_MAX] = {
 		OPCODE(sfPutString),
 		OPCODE(sfWait),
 		OPCODE(sfTakeObject),
@@ -80,7 +80,7 @@
 		OPCODE(sfScriptOpenDoor),
 		OPCODE(sfScriptCloseDoor),
 		OPCODE(sfSetBgdAnimSpeed),
-		OPCODE(SF_cycleColors),
+		OPCODE(sfCycleColors),
 		OPCODE(sfDoCenterActor),
 		OPCODE(sfStartBgdAnimSpeed),
 		OPCODE(sfScriptWalkToAsync),
@@ -136,7 +136,7 @@
 		OPCODE(sfPlayVoice)
 	};
 
-static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCTION_MAX] = {
+static const ScriptFunctionDescription IHNMScriptFunctionsList[IHNM_SCRIPT_FUNCTION_MAX] = {
 		OPCODE(sfNull),
 		OPCODE(sfWait),
 		OPCODE(sfTakeObject),
@@ -161,7 +161,7 @@
 		OPCODE(sfScriptOpenDoor),
 		OPCODE(sfScriptCloseDoor),
 		OPCODE(sfSetBgdAnimSpeed),
-		OPCODE(SF_cycleColors),
+		OPCODE(sfCycleColors),
 		OPCODE(sfDoCenterActor),
 		OPCODE(sfStartBgdAnimSpeed),
 		OPCODE(sfScriptWalkToAsync),
@@ -244,9 +244,9 @@
 		OPCODE(sfDisableAbortSpeeches)
 	};
 	if (_vm->getGameId() == GID_IHNM)
-		_scriptFunctionsList = IHNMscriptFunctionsList;
+		_scriptFunctionsList = IHNMScriptFunctionsList;
 	else
-		_scriptFunctionsList = ITEscriptFunctionsList;
+		_scriptFunctionsList = ITEScriptFunctionsList;
 }
 
 // Script function #0 (0x00)
@@ -688,8 +688,8 @@
 }
 
 // Script function #24 (0x18)
-void Script::SF_cycleColors(SCRIPTFUNC_PARAMS) {
-	SF_stub("SF_cycleColors", thread, nArgs);
+void Script::sfCycleColors(SCRIPTFUNC_PARAMS) {
+	SF_stub("sfCycleColors", thread, nArgs);
 
 	error("Please, report this to sev");
 }

Modified: scummvm/trunk/engines/saga/sthread.cpp
===================================================================
--- scummvm/trunk/engines/saga/sthread.cpp	2009-01-02 09:53:11 UTC (rev 35669)
+++ scummvm/trunk/engines/saga/sthread.cpp	2009-01-02 13:59:34 UTC (rev 35670)
@@ -37,9 +37,6 @@
 
 namespace Saga {
 
-#define RID_SCENE1_VOICE_START 57
-#define RID_SCENE1_VOICE_END 186
-
 ScriptThread *Script::createThread(uint16 scriptModuleNumber, uint16 scriptEntryPointNumber) {
 	ScriptThread *newThread;
 
@@ -165,7 +162,7 @@
 		}
 
 		if (!(thread->_flags & kTFlagWaiting)) {
-			if (runThread(thread, STHREAD_TIMESLICE)) {
+			if (runThread(thread)) {
 				break;
 			}
 		}
@@ -196,536 +193,31 @@
 		executeThreads(0);
 }
 
-bool Script::runThread(ScriptThread *thread, uint instructionLimit) {
-	const char*operandName;
-	uint instructionCount;
+bool Script::runThread(ScriptThread *thread) {
 	uint16 savedInstructionOffset;
-
-	byte *addr;
-	byte mode;
-	uint16 jmpOffset1;
-	int16 iparam1;
-	int16 iparam2;
-	int16 iparam3;
-
-	bool disContinue;
-	byte argumentsCount;
-	uint16 functionNumber;
-	uint16 checkStackTopIndex;
-	ScriptFunctionType scriptFunction;
-
+	bool stopParsing = false;
+	bool breakOut = false;
 	int operandChar;
-	int i;
 
 	MemoryReadStream scriptS(thread->_moduleBase, thread->_moduleBaseSize);
 
 	scriptS.seek(thread->_instructionOffset);
 
-	for (instructionCount = 0; instructionCount < instructionLimit; instructionCount++) {
+	for (uint instructionCount = 0; instructionCount < STHREAD_TIMESLICE; instructionCount++) {
 		if (thread->_flags & (kTFlagAsleep))
 			break;
 
 		savedInstructionOffset = thread->_instructionOffset;
 		operandChar = scriptS.readByte();
 
-
-#define CASEOP(opName)	case opName:												\
-							if (operandChar == opName) {							\
-								operandName = #opName;								\
-								debug(2, "%s", operandName);						\
-							}
-
 		debug(8, "Executing thread offset: %u (%x) stack: %d", thread->_instructionOffset, operandChar, thread->pushedSize());
-		operandName="";
-		switch (operandChar) {
-		CASEOP(opNextBlock)
-			// Some sort of "jump to the start of the next memory
-			// page" instruction, I think.
-			thread->_instructionOffset = (((thread->_instructionOffset) >> 10) + 1) << 10;
-			break;
 
-// STACK INSTRUCTIONS
-		CASEOP(opDup)
-			thread->push(thread->stackTop());
-			break;
-		CASEOP(opDrop)
-			thread->pop();
-			break;
-		CASEOP(opZero)
-			thread->push(0);
-			break;
-		CASEOP(opOne)
-			thread->push(1);
-			break;
-		CASEOP(opConstint)
-		CASEOP(opStrlit)
-			iparam1 = scriptS.readSint16LE();
-			thread->push(iparam1);
-			debug(8, "0x%X", iparam1);
-			break;
+		stopParsing = false;
+		(this->*_scriptOpsList[operandChar].scriptOp)(thread, &scriptS, stopParsing, breakOut);
+		debug(4, "Calling op %s", this->_scriptOpsList[operandChar].scriptOpName);
+		if (stopParsing)
+			return true;
 
-// DATA INSTRUCTIONS
-		CASEOP(opGetFlag)
-			addr = thread->baseAddress(scriptS.readByte());
-			iparam1 = scriptS.readSint16LE();
-			addr += (iparam1 >> 3);
-			iparam1 = (1 << (iparam1 & 7));
-			thread->push((*addr) & iparam1 ? 1 : 0);
-			break;
-		CASEOP(opGetInt)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			thread->push(readUint16(addr, mode));
-			debug(8, "0x%X", readUint16(addr, mode));
-			break;
-		CASEOP(opPutFlag)
-			addr = thread->baseAddress(scriptS.readByte());
-			iparam1 = scriptS.readSint16LE();
-			addr += (iparam1 >> 3);
-			iparam1 = (1 << (iparam1 & 7));
-			if (thread->stackTop()) {
-				*addr |= iparam1;
-			} else {
-				*addr &= ~iparam1;
-			}
-			break;
-		CASEOP(opPutInt)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			writeUint16(addr, thread->stackTop(), mode);
-			break;
-		CASEOP(opPutFlagV)
-			addr = thread->baseAddress(scriptS.readByte());
-			iparam1 = scriptS.readSint16LE();
-			addr += (iparam1 >> 3);
-			iparam1 = (1 << (iparam1 & 7));
-			if (thread->pop()) {
-				*addr |= iparam1;
-			} else {
-				*addr &= ~iparam1;
-			}
-			break;
-		CASEOP(opPutIntV)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			writeUint16(addr, thread->pop(), mode);
-			break;
-
-// FUNCTION CALL INSTRUCTIONS
-		CASEOP(opCall)
-			argumentsCount = scriptS.readByte();
-			iparam1 = scriptS.readByte();
-			if (iparam1 != kAddressModule) {
-				error("Script::runThread iparam1 != kAddressModule");
-			}
-			addr = thread->baseAddress(iparam1);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			thread->push(argumentsCount);
-
-			jmpOffset1 = scriptS.pos();
-			// NOTE: The original pushes the program
-			// counter as a pointer here. But I don't think
-			// we will have to do that.
-			thread->push(jmpOffset1);
-			// NOTE2: program counter is 32bit - so we should "emulate" it size - because kAddressStack relies on it
-			thread->push(0);
-			thread->_instructionOffset = iparam1;
-
-			break;
-		CASEOP(opCcall)
-		CASEOP(opCcallV)
-			argumentsCount = scriptS.readByte();
-			functionNumber = scriptS.readUint16LE();
-			if (functionNumber >= ((_vm->getGameId() == GID_IHNM) ?
-								   IHNM_SCRIPT_FUNCTION_MAX : ITE_SCRIPT_FUNCTION_MAX)) {
-				error("Script::runThread() Invalid script function number (%d)", functionNumber);
-			}
-
-			debug(2, "Calling #%d %s argCount=%i", functionNumber, _scriptFunctionsList[functionNumber].scriptFunctionName, argumentsCount);
-			scriptFunction = _scriptFunctionsList[functionNumber].scriptFunction;
-			checkStackTopIndex = thread->_stackTopIndex + argumentsCount;
-			disContinue = false;
-			(this->*scriptFunction)(thread, argumentsCount, disContinue);
-			if (disContinue) {
-				return true;
-			}
-			if (scriptFunction == &Saga::Script::sfScriptGotoScene ||
-				scriptFunction == &Saga::Script::sfVsetTrack) {
-				return true; // cause abortAllThreads called and _this_ thread destroyed
-			}
-
-			thread->_stackTopIndex = checkStackTopIndex;
-
-			if (operandChar == opCcall) {// CALL function
-				thread->push(thread->_returnValue);
-			}
-
-			if (thread->_flags & kTFlagAsleep)
-				instructionCount = instructionLimit;	// break out of loop!
-			break;
-		CASEOP(opEnter)
-			thread->push(thread->_frameIndex);
-			thread->_frameIndex = thread->_stackTopIndex;
-			thread->_stackTopIndex -= (scriptS.readSint16LE() / 2);
-			break;
-		CASEOP(opReturn)
-			thread->_returnValue = thread->pop();
-		CASEOP(opReturnV)
-			thread->_stackTopIndex = thread->_frameIndex;
-			thread->_frameIndex = thread->pop();
-			if (thread->pushedSize() == 0) {
-				thread->_flags |= kTFlagFinished;
-				return true;
-			} else {
-				thread->pop(); //cause it 0
-				thread->_instructionOffset = thread->pop();
-
-				// Pop all the call parameters off the stack
-				iparam1 = thread->pop();
-				while (iparam1--) {
-					thread->pop();
-				}
-
-				if (operandChar == opReturn) {
-					thread->push(thread->_returnValue);
-				}
-			}
-			break;
-
-// BRANCH INSTRUCTIONS
-		CASEOP(opJmp)
-			jmpOffset1 = scriptS.readUint16LE();
-			thread->_instructionOffset = jmpOffset1;
-			break;
-		CASEOP(opJmpTrueV)
-			jmpOffset1 = scriptS.readUint16LE();
-			if (thread->pop()) {
-				thread->_instructionOffset = jmpOffset1;
-			}
-			break;
-		CASEOP(opJmpFalseV)
-			jmpOffset1 = scriptS.readUint16LE();
-			if (!thread->pop()) {
-				thread->_instructionOffset = jmpOffset1;
-			}
-			break;
-		CASEOP(opJmpTrue)
-			jmpOffset1 = scriptS.readUint16LE();
-			if (thread->stackTop()) {
-				thread->_instructionOffset = jmpOffset1;
-			}
-			break;
-		CASEOP(opJmpFalse)
-			jmpOffset1 = scriptS.readUint16LE();
-			if (!thread->stackTop()) {
-				thread->_instructionOffset = jmpOffset1;
-			}
-			break;
-		CASEOP(opJmpSwitch)
-			iparam1 = scriptS.readSint16LE();
-			iparam2 = thread->pop();
-			while (iparam1--) {
-				iparam3 = scriptS.readUint16LE();
-				thread->_instructionOffset = scriptS.readUint16LE();
-				if (iparam3 == iparam2) {
-					break;
-				}
-			}
-			if (iparam1 < 0) {
-				thread->_instructionOffset = scriptS.readUint16LE();
-			}
-			break;
-		CASEOP(opJmpRandom)
-			// Supposedly the number of possible branches.
-			// The original interpreter ignores it.
-			scriptS.readUint16LE();
-			iparam1 = scriptS.readSint16LE();
-			iparam1 = _vm->_rnd.getRandomNumber(iparam1 - 1);
-			while (1) {
-				iparam2 = scriptS.readSint16LE();
-				thread->_instructionOffset = scriptS.readUint16LE();
-
-				iparam1 -= iparam2;
-				if (iparam1 < 0) {
-					break;
-				}
-			}
-			break;
-
-// UNARY INSTRUCTIONS
-		CASEOP(opNegate)
-			thread->push(-thread->pop());
-			break;
-		CASEOP(opNot)
-			thread->push(!thread->pop());
-			break;
-		CASEOP(opCompl)
-			thread->push(~thread->pop());
-			break;
-
-		CASEOP(opIncV)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			iparam1 = readUint16(addr, mode);
-			writeUint16(addr, iparam1 + 1, mode);
-			break;
-		CASEOP(opDecV)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			iparam1 = readUint16(addr, mode);
-			writeUint16(addr, iparam1 - 1, mode);
-			break;
-		CASEOP(opPostInc)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			iparam1 = readUint16(addr, mode);
-			thread->push(iparam1);
-			writeUint16(addr, iparam1 + 1, mode);
-			break;
-		CASEOP(opPostDec)
-			mode = scriptS.readByte();
-			addr = thread->baseAddress(mode);
-			iparam1 = scriptS.readSint16LE();
-			addr += iparam1;
-			iparam1 = readUint16(addr, mode);
-			thread->push(iparam1);
-			writeUint16(addr, iparam1 - 1, mode);
-			break;
-
-// ARITHMETIC INSTRUCTIONS
-		CASEOP(opAdd)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 += iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opSub)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 -= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opMul)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 *= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opDiv)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 /= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opMod)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 %= iparam2;
-			thread->push(iparam1);
-			break;
-
-// COMPARISION INSTRUCTIONS
-		CASEOP(opEq)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 == iparam2) ? 1 : 0);
-			debug(8, "0x%X 0x%X", iparam1, iparam2);
-			break;
-		CASEOP(opNe)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 != iparam2) ? 1 : 0);
-			break;
-		CASEOP(opGt)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 > iparam2) ? 1 : 0);
-			break;
-		CASEOP(opLt)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 < iparam2) ? 1 : 0);
-			break;
-		CASEOP(opGe)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 >= iparam2) ? 1 : 0);
-			break;
-		CASEOP(opLe)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 <= iparam2) ? 1 : 0);
-			break;
-
-// SHIFT INSTRUCTIONS
-		CASEOP(opRsh)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 >>= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opLsh)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 <<= iparam2;
-			thread->push(iparam1);
-			break;
-
-// BITWISE INSTRUCTIONS
-		CASEOP(opAnd)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 &= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opOr)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 |= iparam2;
-			thread->push(iparam1);
-			break;
-		CASEOP(opXor)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			iparam1 ^= iparam2;
-			thread->push(iparam1);
-			break;
-
-// LOGICAL INSTRUCTIONS
-		CASEOP(opLAnd)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 && iparam2) ? 1 : 0);
-			break;
-		CASEOP(opLOr)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push((iparam1 || iparam2) ? 1 : 0);
-			break;
-		CASEOP(opLXor)
-			iparam2 = thread->pop();
-			iparam1 = thread->pop();
-			thread->push(((iparam1 && !iparam2) || (!iparam1 && iparam2)) ? 1 : 0);
-			break;
-
-// GAME INSTRUCTIONS
-		CASEOP(opSpeak) {
-				int stringsCount;
-				uint16 actorId;
-				uint16 speechFlags;
-				int sampleResourceId = -1;
-				int16 first;
-				const char *strings[ACTOR_SPEECH_STRING_MAX];
-
-				if (_vm->_actor->isSpeaking()) {
-					thread->wait(kWaitTypeSpeech);
-					return false;
-				}
-
-				stringsCount = scriptS.readByte();
-				actorId = scriptS.readUint16LE();
-				speechFlags = scriptS.readByte();
-				scriptS.readUint16LE(); // x,y skip
-
-				if (stringsCount == 0)
-					error("opSpeak stringsCount == 0");
-
-				if (stringsCount > ACTOR_SPEECH_STRING_MAX)
-					error("opSpeak stringsCount=0x%X exceed ACTOR_SPEECH_STRING_MAX", stringsCount);
-
-				iparam1 = first = thread->stackTop();
-				for (i = 0; i < stringsCount; i++) {
-					 iparam1 = thread->pop();
-					 strings[i] = thread->_strings->getString(iparam1);
-				}
-				// now data contains last string index
-
-				if (_vm->getFeatures() & GF_OLD_ITE_DOS) { // special ITE dos
-					if ((_vm->_scene->currentSceneNumber() == ITE_DEFAULT_SCENE) &&
-						(iparam1 >= 288) && (iparam1 <= (RID_SCENE1_VOICE_END - RID_SCENE1_VOICE_START + 288))) {
-						sampleResourceId = RID_SCENE1_VOICE_START + iparam1 - 288;
-					}
-				} else {
-					if (thread->_voiceLUT->voicesCount > first) {
-						sampleResourceId = thread->_voiceLUT->voices[first];
-					}
-				}
-
-				if (sampleResourceId < 0 || sampleResourceId > 4000)
-					sampleResourceId = -1;
-
-				if (_vm->getGameId() == GID_ITE && !sampleResourceId)
-					sampleResourceId = -1;
-
-				_vm->_actor->actorSpeech(actorId, strings, stringsCount, sampleResourceId, speechFlags);
-
-				if (!(speechFlags & kSpeakAsync)) {
-					thread->wait(kWaitTypeSpeech);
-				}
-			}
-			break;
-		CASEOP(opDialogBegin)
-			if (_conversingThread) {
-				thread->wait(kWaitTypeDialogBegin);
-				return false;
-			}
-			_conversingThread = thread;
-			_vm->_interface->converseClear();
-			break;
-		CASEOP(opDialogEnd)
-			if (thread == _conversingThread) {
-				_vm->_interface->activate();
-				_vm->_interface->setMode(kPanelConverse);
-				thread->wait(kWaitTypeDialogEnd);
-				return false;
-			}
-			break;
-		CASEOP(opReply) {
-				const char *str;
-				byte replyNum;
-				byte flags;
-				replyNum = scriptS.readByte();
-				flags = scriptS.readByte();
-				iparam1 = 0;
-				int strID = thread->pop();
-
-				if (flags & kReplyOnce) {
-					iparam1 = scriptS.readSint16LE();
-					addr = thread->_staticBase + (iparam1 >> 3);
-					if (*addr & (1 << (iparam1 & 7))) {
-						break;
-					}
-				}
-
-				str = thread->_strings->getString(strID);
-				if (_vm->_interface->converseAddText(str, strID, replyNum, flags, iparam1))
-					warning("Error adding ConverseText (%s, %d, %d, %d)", str, replyNum, flags, iparam1);
-			}
-			break;
-		CASEOP(opAnimate)
-			scriptS.readUint16LE();
-			scriptS.readUint16LE();
-			jmpOffset1 = scriptS.readByte();
-			thread->_instructionOffset += jmpOffset1;
-			break;
-
-		default:
-			error("Script::runThread() Invalid opcode encountered 0x%X", operandChar);
-		}
-
 		if (thread->_flags & (kTFlagFinished | kTFlagAborted)) {
 			error("Wrong flags %d in thread", thread->_flags);
 		}
@@ -740,6 +232,9 @@
 
 			scriptS.seek(thread->_instructionOffset);
 		}
+
+		if (breakOut)
+			break;
 	}
 	return false;
 }


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list