diff options
| -rw-r--r-- | engines/saga/script.cpp | 821 | ||||
| -rw-r--r-- | engines/saga/script.h | 156 | ||||
| -rw-r--r-- | engines/saga/sfuncs.cpp | 18 | ||||
| -rw-r--r-- | engines/saga/sthread.cpp | 531 | 
4 files changed, 925 insertions, 601 deletions
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp index 1384f1bf47..62c7c3e368 100644 --- a/engines/saga/script.cpp +++ b/engines/saga/script.cpp @@ -41,7 +41,8 @@  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 @@ -161,6 +162,7 @@ Script::Script(SagaEngine *vm) : _vm(vm) {  	_vm->loadStrings(_mainStrings, stringsPointer, stringsLength);  	free(stringsPointer); +	setupScriptOpcodeList();  	setupScriptFuncList();  } @@ -179,6 +181,823 @@ Script::~Script() {  	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; diff --git a/engines/saga/script.h b/engines/saga/script.h index 8d9e17af20..9785ef9a77 100644 --- a/engines/saga/script.h +++ b/engines/saga/script.h @@ -109,75 +109,6 @@ enum ThreadWaitTypes {  	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 @@ public:  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 @@ private:  	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 @@ public:  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 @@ private:  	};  	const ScriptFunctionDescription *_scriptFunctionsList; -	void setupScriptFuncList(void); +	void setupScriptFuncList();  	void sfPutString(SCRIPTFUNC_PARAMS);  	void sfWait(SCRIPTFUNC_PARAMS); @@ -515,7 +525,7 @@ private:  	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); diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index 26933a36ea..9c93687a48 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -54,8 +54,8 @@ namespace Saga {  #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 @@ void Script::setupScriptFuncList(void) {  		OPCODE(sfScriptOpenDoor),  		OPCODE(sfScriptCloseDoor),  		OPCODE(sfSetBgdAnimSpeed), -		OPCODE(SF_cycleColors), +		OPCODE(sfCycleColors),  		OPCODE(sfDoCenterActor),  		OPCODE(sfStartBgdAnimSpeed),  		OPCODE(sfScriptWalkToAsync), @@ -136,7 +136,7 @@ void Script::setupScriptFuncList(void) {  		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 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT  		OPCODE(sfScriptOpenDoor),  		OPCODE(sfScriptCloseDoor),  		OPCODE(sfSetBgdAnimSpeed), -		OPCODE(SF_cycleColors), +		OPCODE(sfCycleColors),  		OPCODE(sfDoCenterActor),  		OPCODE(sfStartBgdAnimSpeed),  		OPCODE(sfScriptWalkToAsync), @@ -244,9 +244,9 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT  		OPCODE(sfDisableAbortSpeeches)  	};  	if (_vm->getGameId() == GID_IHNM) -		_scriptFunctionsList = IHNMscriptFunctionsList; +		_scriptFunctionsList = IHNMScriptFunctionsList;  	else -		_scriptFunctionsList = ITEscriptFunctionsList; +		_scriptFunctionsList = ITEScriptFunctionsList;  }  // Script function #0 (0x00) @@ -688,8 +688,8 @@ void Script::sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS) {  }  // 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");  } diff --git a/engines/saga/sthread.cpp b/engines/saga/sthread.cpp index ab1c771cbc..9e015179d9 100644 --- a/engines/saga/sthread.cpp +++ b/engines/saga/sthread.cpp @@ -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 @@ void Script::executeThreads(uint msec) {  		}  		if (!(thread->_flags & kTFlagWaiting)) { -			if (runThread(thread, STHREAD_TIMESLICE)) { +			if (runThread(thread)) {  				break;  			}  		} @@ -196,535 +193,30 @@ void Script::completeThread(void) {  		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; - -// 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); -		} +		stopParsing = false; +		(this->*_scriptOpsList[operandChar].scriptOp)(thread, &scriptS, stopParsing, breakOut); +		debug(4, "Calling op %s", this->_scriptOpsList[operandChar].scriptOpName); +		if (stopParsing) +			return true;  		if (thread->_flags & (kTFlagFinished | kTFlagAborted)) {  			error("Wrong flags %d in thread", thread->_flags); @@ -740,6 +232,9 @@ bool Script::runThread(ScriptThread *thread, uint instructionLimit) {  			scriptS.seek(thread->_instructionOffset);  		} + +		if (breakOut) +			break;  	}  	return false;  }  | 
