diff options
| author | Torbjörn Andersson | 2003-12-14 16:33:27 +0000 | 
|---|---|---|
| committer | Torbjörn Andersson | 2003-12-14 16:33:27 +0000 | 
| commit | 4420b15d9f59227cc57bb60d5b38c73639437a62 (patch) | |
| tree | 0516b8935d48adc82ea6d758e154af1b75fcbc44 /sword2/interpreter.cpp | |
| parent | ce04dd9f7e77fe1c31eb14aebde2f69c16d33684 (diff) | |
| download | scummvm-rg350-4420b15d9f59227cc57bb60d5b38c73639437a62.tar.gz scummvm-rg350-4420b15d9f59227cc57bb60d5b38c73639437a62.tar.bz2 scummvm-rg350-4420b15d9f59227cc57bb60d5b38c73639437a62.zip | |
Mostly cleanups, but I believe this also fixes an endian problem in the
"restart script" opcode. To actually verify this, though, I'd need to find
a case where any other script than script 0 at offset 0 is restarted...
svn-id: r11638
Diffstat (limited to 'sword2/interpreter.cpp')
| -rw-r--r-- | sword2/interpreter.cpp | 891 | 
1 files changed, 429 insertions, 462 deletions
| diff --git a/sword2/interpreter.cpp b/sword2/interpreter.cpp index d30ecee760..15a990e054 100644 --- a/sword2/interpreter.cpp +++ b/sword2/interpreter.cpp @@ -24,197 +24,188 @@  namespace Sword2 { -// This file serves two purposes. It is compiled as part of the test functions -// of Linc, and also as part of the game - -// I assume Linc was the name of some sort of development tool. Anyway, I've -// removed the pieces of code that were labelled as INSIDE_LINC, because we -// don't have it, and probably wouldn't have much use for it if we did. -  // The machine code table -#define MAX_FN_NUMBER	117 -  #define OPCODE(x)	{ &Logic::x, #x } -void Logic::setupOpcodes(void) { -	static const OpcodeEntry opcodes[MAX_FN_NUMBER + 1] = { -		/* 00 */ -		OPCODE(fnTestFunction), -		OPCODE(fnTestFlags), -		OPCODE(fnRegisterStartPoint), -		OPCODE(fnInitBackground), -		/* 04 */ -		OPCODE(fnSetSession), -		OPCODE(fnBackSprite), -		OPCODE(fnSortSprite), -		OPCODE(fnForeSprite), -		/* 08 */ -		OPCODE(fnRegisterMouse), -		OPCODE(fnAnim), -		OPCODE(fnRandom), -		OPCODE(fnPreLoad), -		/* 0C */ -		OPCODE(fnAddSubject), -		OPCODE(fnInteract), -		OPCODE(fnChoose), -		OPCODE(fnWalk), -		/* 10 */ -		OPCODE(fnWalkToAnim), -		OPCODE(fnTurn), -		OPCODE(fnStandAt), -		OPCODE(fnStand), -		/* 14 */ -		OPCODE(fnStandAfterAnim), -		OPCODE(fnPause), -		OPCODE(fnMegaTableAnim), -		OPCODE(fnAddMenuObject), -		/* 18 */ -		OPCODE(fnStartConversation), -		OPCODE(fnEndConversation), -		OPCODE(fnSetFrame), -		OPCODE(fnRandomPause), -		/* 1C */ -		OPCODE(fnRegisterFrame), -		OPCODE(fnNoSprite), -		OPCODE(fnSendSync), -		OPCODE(fnUpdatePlayerStats), -		/* 20 */ -		OPCODE(fnPassGraph), -		OPCODE(fnInitFloorMouse), -		OPCODE(fnPassMega), -		OPCODE(fnFaceXY), -		/* 24 */ -		OPCODE(fnEndSession), -		OPCODE(fnNoHuman), -		OPCODE(fnAddHuman), -		OPCODE(fnWeWait), -		/* 28 */ -		OPCODE(fnTheyDoWeWait), -		OPCODE(fnTheyDo), -		OPCODE(fnWalkToTalkToMega), -		OPCODE(fnFadeDown), -		/* 2C */ -		OPCODE(fnISpeak), -		OPCODE(fnTotalRestart), -		OPCODE(fnSetWalkGrid), -		OPCODE(fnSpeechProcess), -		/* 30 */ -		OPCODE(fnSetScaling), -		OPCODE(fnStartEvent), -		OPCODE(fnCheckEventWaiting), -		OPCODE(fnRequestSpeech), -		/* 34 */ -		OPCODE(fnGosub), -		OPCODE(fnTimedWait), -		OPCODE(fnPlayFx), -		OPCODE(fnStopFx), -		/* 38 */ -		OPCODE(fnPlayMusic), -		OPCODE(fnStopMusic), -		OPCODE(fnSetValue), -		OPCODE(fnNewScript), -		/* 3C */ -		OPCODE(fnGetSync), -		OPCODE(fnWaitSync), -		OPCODE(fnRegisterWalkGrid), -		OPCODE(fnReverseMegaTableAnim), -		/* 40 */ -		OPCODE(fnReverseAnim), -		OPCODE(fnAddToKillList), -		OPCODE(fnSetStandbyCoords), -		OPCODE(fnBackPar0Sprite), -		/* 44 */ -		OPCODE(fnBackPar1Sprite), -		OPCODE(fnForePar0Sprite), -		OPCODE(fnForePar1Sprite), -		OPCODE(fnSetPlayerActionEvent), -		/* 48 */ -		OPCODE(fnSetScrollCoordinate), -		OPCODE(fnStandAtAnim), -		OPCODE(fnSetScrollLeftMouse), -		OPCODE(fnSetScrollRightMouse), -		/* 4C */ -		OPCODE(fnColour), -		OPCODE(fnFlash), -		OPCODE(fnPreFetch), -		OPCODE(fnGetPlayerSaveData), -		/* 50 */ -		OPCODE(fnPassPlayerSaveData), -		OPCODE(fnSendEvent), -		OPCODE(fnAddWalkGrid), -		OPCODE(fnRemoveWalkGrid), -		/* 54 */ -		OPCODE(fnCheckForEvent), -		OPCODE(fnPauseForEvent), -		OPCODE(fnClearEvent), -		OPCODE(fnFaceMega), -		/* 58 */ -		OPCODE(fnPlaySequence), -		OPCODE(fnShadedSprite), -		OPCODE(fnUnshadedSprite), -		OPCODE(fnFadeUp), -		/* 60 */ -		OPCODE(fnDisplayMsg), -		OPCODE(fnSetObjectHeld), -		OPCODE(fnAddSequenceText), -		OPCODE(fnResetGlobals), -		/* 64 */ -		OPCODE(fnSetPalette), -		OPCODE(fnRegisterPointerText), -		OPCODE(fnFetchWait), -		OPCODE(fnRelease), -		/* 68 */ -		OPCODE(fnPrepareMusic), -		OPCODE(fnSoundFetch), -		OPCODE(fnPrepareMusic),	// Again, apparently -		OPCODE(fnSmackerLeadIn), -		/* 6C */ -		OPCODE(fnSmackerLeadOut), -		OPCODE(fnStopAllFx), -		OPCODE(fnCheckPlayerActivity), -		OPCODE(fnResetPlayerActivityDelay), -		/* 70 */ -		OPCODE(fnCheckMusicPlaying), -		OPCODE(fnPlayCredits), -		OPCODE(fnSetScrollSpeedNormal), -		OPCODE(fnSetScrollSpeedSlow), -		/* 74 */ -		OPCODE(fnRemoveChooser), -		OPCODE(fnSetFxVolAndPan), -		OPCODE(fnSetFxVol), -		OPCODE(fnRestoreGame), -		/* 78 */ -		OPCODE(fnRefreshInventory), -		OPCODE(fnChangeShadows) -	}; - -	_opcodes = opcodes; -} - -int32 Logic::executeOpcode(int i, int32 *params) { -	OpcodeProc op = _opcodes[i].proc; - -	debug(5, "%s", _opcodes[i].desc); - -	return (this->*op) (params); -} - -// FIXME: Is the handling of script local variables really alignment-safe? - -#define CHECKSTACKPOINTER2 assert(stackPointer2 >= 0 && stackPointer2 < STACK_SIZE); -#define	PUSHONSTACK(x) { stack2[stackPointer2] = (x); stackPointer2++; CHECKSTACKPOINTER2 } -#define POPOFFSTACK(x) { x = stack2[stackPointer2 - 1]; stackPointer2--; CHECKSTACKPOINTER2 } -#define DOOPERATION(x) { stack2[stackPointer2 - 2] = (x); stackPointer2--; CHECKSTACKPOINTER2 } +typedef int32 (Logic::*OpcodeProc)(int32 *); +struct OpcodeEntry { +	OpcodeProc proc; +	const char *desc; +}; + +static const OpcodeEntry opcodes[] = { +	/* 00 */ +	OPCODE(fnTestFunction), +	OPCODE(fnTestFlags), +	OPCODE(fnRegisterStartPoint), +	OPCODE(fnInitBackground), +	/* 04 */ +	OPCODE(fnSetSession), +	OPCODE(fnBackSprite), +	OPCODE(fnSortSprite), +	OPCODE(fnForeSprite), +	/* 08 */ +	OPCODE(fnRegisterMouse), +	OPCODE(fnAnim), +	OPCODE(fnRandom), +	OPCODE(fnPreLoad), +	/* 0C */ +	OPCODE(fnAddSubject), +	OPCODE(fnInteract), +	OPCODE(fnChoose), +	OPCODE(fnWalk), +	/* 10 */ +	OPCODE(fnWalkToAnim), +	OPCODE(fnTurn), +	OPCODE(fnStandAt), +	OPCODE(fnStand), +	/* 14 */ +	OPCODE(fnStandAfterAnim), +	OPCODE(fnPause), +	OPCODE(fnMegaTableAnim), +	OPCODE(fnAddMenuObject), +	/* 18 */ +	OPCODE(fnStartConversation), +	OPCODE(fnEndConversation), +	OPCODE(fnSetFrame), +	OPCODE(fnRandomPause), +	/* 1C */ +	OPCODE(fnRegisterFrame), +	OPCODE(fnNoSprite), +	OPCODE(fnSendSync), +	OPCODE(fnUpdatePlayerStats), +	/* 20 */ +	OPCODE(fnPassGraph), +	OPCODE(fnInitFloorMouse), +	OPCODE(fnPassMega), +	OPCODE(fnFaceXY), +	/* 24 */ +	OPCODE(fnEndSession), +	OPCODE(fnNoHuman), +	OPCODE(fnAddHuman), +	OPCODE(fnWeWait), +	/* 28 */ +	OPCODE(fnTheyDoWeWait), +	OPCODE(fnTheyDo), +	OPCODE(fnWalkToTalkToMega), +	OPCODE(fnFadeDown), +	/* 2C */ +	OPCODE(fnISpeak), +	OPCODE(fnTotalRestart), +	OPCODE(fnSetWalkGrid), +	OPCODE(fnSpeechProcess), +	/* 30 */ +	OPCODE(fnSetScaling), +	OPCODE(fnStartEvent), +	OPCODE(fnCheckEventWaiting), +	OPCODE(fnRequestSpeech), +	/* 34 */ +	OPCODE(fnGosub), +	OPCODE(fnTimedWait), +	OPCODE(fnPlayFx), +	OPCODE(fnStopFx), +	/* 38 */ +	OPCODE(fnPlayMusic), +	OPCODE(fnStopMusic), +	OPCODE(fnSetValue), +	OPCODE(fnNewScript), +	/* 3C */ +	OPCODE(fnGetSync), +	OPCODE(fnWaitSync), +	OPCODE(fnRegisterWalkGrid), +	OPCODE(fnReverseMegaTableAnim), +	/* 40 */ +	OPCODE(fnReverseAnim), +	OPCODE(fnAddToKillList), +	OPCODE(fnSetStandbyCoords), +	OPCODE(fnBackPar0Sprite), +	/* 44 */ +	OPCODE(fnBackPar1Sprite), +	OPCODE(fnForePar0Sprite), +	OPCODE(fnForePar1Sprite), +	OPCODE(fnSetPlayerActionEvent), +	/* 48 */ +	OPCODE(fnSetScrollCoordinate), +	OPCODE(fnStandAtAnim), +	OPCODE(fnSetScrollLeftMouse), +	OPCODE(fnSetScrollRightMouse), +	/* 4C */ +	OPCODE(fnColour), +	OPCODE(fnFlash), +	OPCODE(fnPreFetch), +	OPCODE(fnGetPlayerSaveData), +	/* 50 */ +	OPCODE(fnPassPlayerSaveData), +	OPCODE(fnSendEvent), +	OPCODE(fnAddWalkGrid), +	OPCODE(fnRemoveWalkGrid), +	/* 54 */ +	OPCODE(fnCheckForEvent), +	OPCODE(fnPauseForEvent), +	OPCODE(fnClearEvent), +	OPCODE(fnFaceMega), +	/* 58 */ +	OPCODE(fnPlaySequence), +	OPCODE(fnShadedSprite), +	OPCODE(fnUnshadedSprite), +	OPCODE(fnFadeUp), +	/* 5C */ +	OPCODE(fnDisplayMsg), +	OPCODE(fnSetObjectHeld), +	OPCODE(fnAddSequenceText), +	OPCODE(fnResetGlobals), +	/* 60 */ +	OPCODE(fnSetPalette), +	OPCODE(fnRegisterPointerText), +	OPCODE(fnFetchWait), +	OPCODE(fnRelease), +	/* 64 */ +	OPCODE(fnPrepareMusic), +	OPCODE(fnSoundFetch), +	OPCODE(fnPrepareMusic),	// Again, apparently +	OPCODE(fnSmackerLeadIn), +	/* 68 */ +	OPCODE(fnSmackerLeadOut), +	OPCODE(fnStopAllFx), +	OPCODE(fnCheckPlayerActivity), +	OPCODE(fnResetPlayerActivityDelay), +	/* 6C */ +	OPCODE(fnCheckMusicPlaying), +	OPCODE(fnPlayCredits), +	OPCODE(fnSetScrollSpeedNormal), +	OPCODE(fnSetScrollSpeedSlow), +	/* 70 */ +	OPCODE(fnRemoveChooser), +	OPCODE(fnSetFxVolAndPan), +	OPCODE(fnSetFxVol), +	OPCODE(fnRestoreGame), +	/* 74 */ +	OPCODE(fnRefreshInventory), +	OPCODE(fnChangeShadows) +}; + +#define push(value) \ +do { \ +	assert(stackPtr < ARRAYSIZE(stack)); \ +	stack[stackPtr++] = (value); \ +} while (false); + +#define pop() (assert(stackPtr < ARRAYSIZE(stack)), stack[--stackPtr])  void Logic::setGlobalInterpreterVariables(int32 *vars) {  	_globals = vars;  }  int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) { -	bool checkPyramidBug = false; +	// Interestingly, unlike our BASS engine the stack is a local variable. +	// This has some interesting implications which may or may not be +	// necessary to the BS2 engine. -	#define STACK_SIZE		10 +	int32 stack[STACK_SIZE]; +	int32 stackPtr = 0; + +	bool checkPyramidBug = false;  	_standardHeader *header = (_standardHeader *) scriptData;  	scriptData += sizeof(_standardHeader) + sizeof(_object_hub); @@ -227,35 +218,35 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) {  	// Initialise some stuff -	int ip = 0;			 // Code pointer -	int curCommand,parameter, value; // Command and parameter variables -	int32 stack2[STACK_SIZE];	 // The current stack -	int32 stackPointer2 = 0;	// Position within stack -	int parameterReturnedFromMcodeFunction = 0;	// Allow scripts to return things -	int savedStartOfMcode = 0;	// For saving start of mcode commands - -	int count; -	int retVal; -	int caseCount, foundCase; -	int scriptNumber, foundScript; -	const char *tempScrPtr; +	uint32 ip = 0;			 // Code pointer +	int scriptNumber;  	// Get the start of variables and start of code -	debug(5, "Enter interpreter data %x, object %x, offset %d", scriptData, objectData, *offset); - -	// FIXME: 'scriptData' and 'variables' used to be const. However, -	// this code writes into 'variables' so it can not be const. -	char *variables = scriptData + sizeof(int32); +	uint32 *variables = (uint32 *) (scriptData + sizeof(int32));  	const char *code = scriptData + (int32) READ_LE_UINT32(scriptData) + sizeof(int32);  	uint32 noScripts = (int32) READ_LE_UINT32(code); +	code += sizeof(int32); + +	const uint32 *offsetTable = (const uint32 *) code; +  	if (*offset < noScripts) { -		ip = READ_LE_UINT32((const int *) code + *offset + 1); -		debug(5, "Start script %d with offset %d", *offset, ip); +		ip = READ_LE_UINT32(&offsetTable[*offset]); +		scriptNumber = *offset; +		debug(4, "Start script %d with offset %d", *offset, ip);  	} else { +		uint i; +  		ip = *offset; -		debug(5, "Start script with offset %d", ip); + +		for (i = 1; i < noScripts; i++) { +			if (ip < READ_LE_UINT32(code + 4 * i)) +				break; +		} + +		scriptNumber = i - 1; +		debug(4, "Resume script %d with offset %d", scriptNumber, ip);  	}  	// WORKAROUND: The dreaded pyramid makes the torch untakeable when you @@ -273,19 +264,13 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) {  	// So if his click hander (action script number 2) finishes, and  	// variable 913 is 1, we set it back to 0 manually. -	if (strcmp((char *) header->name, "titipoco_81") == 0 && -	    ip >= (int32) READ_LE_UINT32((const int *) code + 3) && -	    ip < (int32) READ_LE_UINT32((const int *) code + 4)) { -		checkPyramidBug = true; -	} +	checkPyramidBug = strcmp((char *) header->name, "titipoco_81") == 0 && scriptNumber == 2; -	code += noScripts * sizeof(int32) + sizeof(int32); +	code += noScripts * sizeof(int32); -#ifdef DONTPROCESSSCRIPTCHECKSUM -	code += sizeof(int32) * 3; -#else  	// Code should nop be pointing at an identifier and a checksum  	const int *checksumBlock = (const int *) code; +  	code += sizeof(int32) * 3;  	if (READ_LE_UINT32(checksumBlock) != 12345678) { @@ -296,25 +281,37 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) {  	int codeLen = READ_LE_UINT32(checksumBlock + 1);  	int checksum = 0; -	for (count = 0; count < codeLen; count++) -		checksum += (unsigned char) code[count]; +	for (int i = 0; i < codeLen; i++) +		checksum += (unsigned char) code[i];  	if (checksum != (int32) READ_LE_UINT32(checksumBlock + 2)) {  		error("Checksum error in object %s", header->name);  		return 0;  	} -#endif -	int runningScript = 1; +	bool runningScript = true; + +	int parameterReturnedFromMcodeFunction = 0;	// Allow scripts to return things +	int savedStartOfMcode = 0;	// For saving start of mcode commands  	while (runningScript) { +		int32 a, b; +		int curCommand, parameter, value; // Command and parameter variables +		int retVal; +		int caseCount; +		bool foundCase; +		int32 ptrval; +  		curCommand = code[ip++];  		switch (curCommand) { + +		// Script-related opcodes +  		case CP_END_SCRIPT:  			// End the script  			debug(5, "End script"); -			runningScript = 0; +			runningScript = false;  			// WORKAROUND: Pyramid Bug. See explanation above. @@ -324,79 +321,130 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) {  			}  			break; +		case CP_QUIT: +			// Quit out for a cycle +			debug(5, "Quit script for a cycle"); +			*offset = ip; +			return 0; +		case CP_TERMINATE: +			// Quit out immediately without affecting the offset +			// pointer +			debug(5, "Terminate script"); +			return 3; +		case CP_RESTART_SCRIPT: +			// Start the script again +			debug(5, "Restart script"); +			ip = READ_LE_UINT32(&offsetTable[scriptNumber]); +			break; + +		// Stack-related opcodes + +		case CP_PUSH_INT32: +			// Push a long word value on to the stack +			Read32ip(parameter); +			debug(5, "Push int32 %d", parameter); +			push(parameter); +			break;  		case CP_PUSH_LOCAL_VAR32:  			// Push the contents of a local variable  			Read16ip(parameter); -			debug(5, "Push local var %d (%d)", parameter, *(int32 *) (variables + parameter)); -			PUSHONSTACK(*(int32 *) (variables + parameter)); +			parameter /= 4; +			debug(5, "Push local var %d (%d)", parameter, variables[parameter]); +			push(variables[parameter]);  			break;  		case CP_PUSH_GLOBAL_VAR32:  			// Push a global variable  			Read16ip(parameter);  			assert(_globals);  			debug(5, "Push global var %d (%d)", parameter, _globals[parameter]); -			PUSHONSTACK(_globals[parameter]); +			push(_globals[parameter]); +			break; +		case CP_PUSH_LOCAL_ADDR: +			// push the address of a local variable +			Read16ip(parameter); +			parameter /= 4; +			ptrval = _vm->_memory->ptrToInt((const uint8 *) &variables[parameter]); +			debug(5, "Push address of local variable %d (%x)", parameter, ptrval); +			push(ptrval); +			break; +		case CP_PUSH_STRING: +			// Push the address of a string on to the stack +			// Get the string size +			Read8ip(parameter); + +			// ip points to the string +			ptrval = _vm->_memory->ptrToInt((const uint8 *) (code + ip)); +			debug(5, "Push address of string (%x)\n", ptrval); +			push(ptrval); +			ip += (parameter + 1); +			break; +		case CP_PUSH_DEREFERENCED_STRUCTURE: +			// Push the address of a dereferenced structure +			Read32ip(parameter); +			ptrval = _vm->_memory->ptrToInt((const uint8 *) (objectData + sizeof(int32) + sizeof(_standardHeader) + sizeof(_object_hub) + parameter)); +			debug(5, "Push address of far variable (%x)", ptrval); +			push(ptrval);  			break;  		case CP_POP_LOCAL_VAR32:  			// Pop a value into a local word variable  			Read16ip(parameter); -			POPOFFSTACK(value); +			parameter /= 4; +			value = pop();  			debug(5, "Pop %d into local var %d", value, parameter); -			*((int32 *) (variables + parameter)) = value; +			variables[parameter] = value;  			break; -		case CP_CALL_MCODE: -			// Call an mcode routine +		case CP_POP_GLOBAL_VAR32: +			// Pop a global variable  			Read16ip(parameter); -			assert(parameter <= MAX_FN_NUMBER); -			// amount to adjust stack by (no of parameters) -			Read8ip(value); -			retVal = executeOpcode(parameter, stack2 + stackPointer2 - value); - -			stackPointer2 -= value; -			CHECKSTACKPOINTER2 - -			switch (retVal & 7) { -			case IR_STOP: -				// Quit out for a cycle -				*offset = ip; -				return 0; -			case IR_CONT: -				// Continue as normal -				break; -			case IR_TERMINATE: -				// Return without updating the -				// offset -				return 2; -			case IR_REPEAT: -				// Return setting offset to -				// start of this function call -				*offset = savedStartOfMcode; -				return 0; -			case IR_GOSUB: -				// that's really neat -				*offset = ip; -				return 2; -			default: -				assert(false); -			} -			parameterReturnedFromMcodeFunction = retVal >> 3; +			value = pop(); +			debug(5, "Pop %d into global var %d", value, parameter); +			_globals[parameter] = value;  			break; -		case CP_PUSH_LOCAL_ADDR: -			// push the address of a local variable +		case CP_ADDNPOP_LOCAL_VAR32:  			Read16ip(parameter); -			debug(5, "Push address of local variable %d (%x)", parameter, _vm->_memory->ptrToInt((const uint8 *) (variables + parameter))); -			PUSHONSTACK(_vm->_memory->ptrToInt((uint8 *) (variables + parameter))); +			parameter /= 4; +			value = pop(); +			variables[parameter] += value; +			debug(5, "+= %d into local var %d -> %d", value, parameter, variables[parameter]);  			break; -		case CP_PUSH_INT32: -			// Push a long word value on to the stack -			Read32ip(parameter); -			debug(5, "Push int32 %d (%x)", parameter, parameter); -			PUSHONSTACK(parameter); +		case CP_SUBNPOP_LOCAL_VAR32: +			Read16ip(parameter); +			parameter /= 4; +			value = pop(); +			variables[parameter] -= value; +			debug(5, "-= %d into local var %d -> %d", value, parameter, variables[parameter]); +			break; +		case CP_ADDNPOP_GLOBAL_VAR32: +			// Add and pop a global variable +			Read16ip(parameter); +			value = pop(); +			_globals[parameter] += value; +			debug(5, "+= %d into global var %d -> %d", value, parameter, _globals[parameter]); +			break; +		case CP_SUBNPOP_GLOBAL_VAR32: +			// Sub and pop a global variable +			Read16ip(parameter); +			value = pop(); +			_globals[parameter] -= value; +			debug(5, "-= %d into global var %d -> %d", value, parameter, _globals[parameter]); +			break; + +		// Jump opcodes + +		case CP_SKIPONTRUE: +			// Skip if the value on the stack is true +			Read32ipLeaveip(parameter); +			value = pop(); +			debug(5, "Skip %d if %d is false", parameter, value); +			if (!value) +				ip += sizeof(int32); +			else +				ip += parameter;  			break;  		case CP_SKIPONFALSE:  			// Skip if the value on the stack is false  			Read32ipLeaveip(parameter); -			POPOFFSTACK(value); +			value = pop();  			debug(5, "Skip %d if %d is false", parameter, value);  			if (value)  				ip += sizeof(int32); @@ -410,251 +458,170 @@ int Logic::runScript(char *scriptData, char *objectData, uint32 *offset) {  			ip += parameter;  			break;  		case CP_SWITCH: -			// 9 switch -			POPOFFSTACK(value); +			// switch +			value = pop();  			Read32ip(caseCount);  			// Search the cases -			foundCase = 0; -			for (count = 0; count < caseCount && !foundCase; count++) { +			foundCase = false; +			for (int i = 0; i < caseCount && !foundCase; i++) {  				if (value == (int32) READ_LE_UINT32(code + ip)) {  					// We have found the case, so lets  					// jump to it -					foundCase = 1; +					foundCase = true;  					ip += READ_LE_UINT32(code + ip + sizeof(int32));  				} else  					ip += sizeof(int32) * 2;  			} -			// If we found no matching case then use the -			// default +			// If we found no matching case then use the default  			if (!foundCase)  				ip += READ_LE_UINT32(code + ip);  			break; -		case CP_ADDNPOP_LOCAL_VAR32: -			Read16ip(parameter); -			POPOFFSTACK(value); -			*((int32 *) (variables + parameter)) += value; -			debug(5, "+= %d into local var %d->%d", value, parameter, *(int32 *) (variables + parameter)); +		case CP_SAVE_MCODE_START: +			// Save the start position on an mcode instruction in +			// case we need to restart it again +			savedStartOfMcode = ip - 1;  			break; -		case CP_SUBNPOP_LOCAL_VAR32: +		case CP_CALL_MCODE: +			// Call an mcode routine  			Read16ip(parameter); -			POPOFFSTACK(value); -			*((int32 *) (variables + parameter)) -= value; -			debug(5, "-= %d into local var %d->%d", value, parameter, *(int32 *) (variables + parameter)); +			assert(parameter < ARRAYSIZE(opcodes)); +			// amount to adjust stack by (no of parameters) +			Read8ip(value); +			debug(5, "Calling '%s' with %d parameters", opcodes[parameter].desc, value); +			stackPtr -= value; +			assert(stackPtr >= 0); +			retVal = (this->*opcodes[parameter].proc)(&stack[stackPtr]); + +			switch (retVal & 7) { +			case IR_STOP: +				// Quit out for a cycle +				*offset = ip; +				return 0; +			case IR_CONT: +				// Continue as normal +				break; +			case IR_TERMINATE: +				// Return without updating the offset +				return 2; +			case IR_REPEAT: +				// Return setting offset to start of this +				// function call +				*offset = savedStartOfMcode; +				return 0; +			case IR_GOSUB: +				// that's really neat +				*offset = ip; +				return 2; +			default: +				error("Bad return code (%d) from '%s'", opcodes[parameter].desc, retVal & 7); +			} +			parameterReturnedFromMcodeFunction = retVal >> 3;  			break; -		case CP_SKIPONTRUE: -			// Skip if the value on the stack is TRUE -			Read32ipLeaveip(parameter); -			POPOFFSTACK(value); -			debug(5, "Skip %d if %d is false", parameter, value); -			if (!value) -				ip += sizeof(int32); -			else -				ip += parameter; +		case CP_JUMP_ON_RETURNED: +			// Jump to a part of the script depending on +			// the return value from an mcode routine + +			// Get the maximum value +			Read8ip(parameter); +			ip += READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4);  			break; -		case CP_POP_GLOBAL_VAR32: -			// Pop a global variable -			Read16ip(parameter); -			POPOFFSTACK(value); -			debug(5, "Pop %d into global var %d", value, parameter); -#ifdef TRACEGLOBALVARIABLESET -			TRACEGLOBALVARIABLESET(parameter, value); -#endif +		// Operators -			_globals[parameter] = value; +		case OP_ISEQUAL: +			b = pop(); +			a = pop(); +			push(a == b); +			debug(5, "operation %d == %d", a, b);  			break; -		case CP_ADDNPOP_GLOBAL_VAR32: -			// Add and pop a global variable -			Read16ip(parameter); -			POPOFFSTACK(value); -			_globals[parameter] += value; -			debug(5, "+= %d into global var %d->%d", value, parameter, _globals[parameter]); +		case OP_NOTEQUAL: +			b = pop(); +			a = pop(); +			push(a != b); +			debug(5, "operation %d != %d", a, b);  			break; -		case CP_SUBNPOP_GLOBAL_VAR32: -			// Sub and pop a global variable -			Read16ip(parameter); -			POPOFFSTACK(value); -			_globals[parameter] -= value; -			debug(5, "-= %d into global var %d->%d", value, parameter, _globals[parameter]); +		case OP_GTTHAN: +			b = pop(); +			a = pop(); +			push(a > b); +			debug(5, "operation %d > %d", a, b);  			break; -		case CP_DEBUGON: -			// Turn debugging on -			_debugFlag = true; +		case OP_LSTHAN: +			b = pop(); +			a = pop(); +			push(a < b); +			debug(5, "operation %d < %d", a, b);  			break; -		case CP_DEBUGOFF: -			// Turn debugging on -			_debugFlag = false; +		case OP_GTTHANE: +			b = pop(); +			a = pop(); +			push(a >= b); +			debug(5, "operation %d >= %d", a, b);  			break; -		case CP_QUIT: -			// Quit out for a cycle -			*offset = ip; -			return 0; -		case CP_TERMINATE: -			// Quit out immediately without affecting the offset -			// pointer -			return 3; - -		// Operators - -		case OP_ISEQUAL: -			// '==' -			debug(5, "%d == %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] == stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] == stack2[stackPointer2 - 1]); +		case OP_LSTHANE: +			b = pop(); +			a = pop(); +			push(a <= b); +			debug(5, "operation %d <= %d", a, b);  			break;  		case OP_PLUS: -			// '+' -			debug(5, "%d + %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] + stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] + stack2[stackPointer2 - 1]); +			b = pop(); +			a = pop(); +			push(a + b); +			debug(5, "operation %d + %d", a, b);  			break;  		case OP_MINUS: -			// '-' -			debug(5, "%d - %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] - stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] - stack2[stackPointer2 - 1]); +			b = pop(); +			a = pop(); +			push(a - b); +			debug(5, "operation %d - %d", a, b);  			break;  		case OP_TIMES: -			// '*' -			debug(5, "%d * %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] * stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] * stack2[stackPointer2 - 1]); +			b = pop(); +			a = pop(); +			push(a * b); +			debug(5, "operation %d * %d", a, b);  			break;  		case OP_DIVIDE: -			// '/' -			debug(5, "%d / %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] / stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] / stack2[stackPointer2 - 1]); -			break; -		case OP_NOTEQUAL: -			// '!=' -			debug(5, "%d != %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] != stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] != stack2[stackPointer2 - 1]); +			b = pop(); +			a = pop(); +			push(a / b); +			debug(5, "operation %d / %d", a, b);  			break;  		case OP_ANDAND: -			// '&&' -			debug(5, "%d && %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] && stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] && stack2[stackPointer2 - 1]); -			break; -		case OP_GTTHAN: -			// '>' -			debug(5, "%d > %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] > stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] > stack2[stackPointer2 - 1]); +			b = pop(); +			a = pop(); +			push(a && b); +			debug(5, "operation %d && %d", a, b);  			break; -		case OP_LSTHAN: -			// '<' -			debug(5, "%d < %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] < stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] < stack2[stackPointer2 - 1]); +		case OP_OROR: +			b = pop(); +			a = pop(); +			push(a || b); +			debug(5, "operation %d || %d", a, b);  			break; -		case CP_JUMP_ON_RETURNED: -			// Jump to a part of the script depending on -			// the return value from an mcode routine -			// Get the maximum value -			Read8ip(parameter); -			ip += READ_LE_UINT32(code + ip + parameterReturnedFromMcodeFunction * 4); +		// Debugging opcodes, I think + +		case CP_DEBUGON: +			// Turn debugging on +			_debugFlag = true; +			break; +		case CP_DEBUGOFF: +			// Turn debugging on +			_debugFlag = false;  			break;  		case CP_TEMP_TEXT_PROCESS:  			// Process a text line -			// This was apparently used in Linc  			Read32ip(parameter);  			debug(5, "Process text id %d", parameter);  			break; -		case CP_SAVE_MCODE_START: -			// Save the start position on an mcode instruction in -			// case we need to restart it again -			savedStartOfMcode = ip - 1; -			break; -		case CP_RESTART_SCRIPT: -			// Start the script again -			// Do a ip search to find the script we are running - -			tempScrPtr = scriptData + READ_LE_UINT32(scriptData) + sizeof(int32); -			scriptNumber = 0; -			foundScript = 0; - -			for (count = 1; count < (int) noScripts && !foundScript; count++) { -				if (ip < ((const int *) tempScrPtr)[count + 1]) { -					scriptNumber = count - 1; -					foundScript = 1; -				} -			} - -			if (!foundScript) -				scriptNumber = count - 1; - -			// So we know what script we are running, lets restart -			// it - -			ip = ((const int *) tempScrPtr)[scriptNumber + 1]; -			break; -		case CP_PUSH_STRING: -			// Push the address of a string on to the stack -			// Get the string size -			Read8ip(parameter); - -			// ip points to the string -			PUSHONSTACK(_vm->_memory->ptrToInt((const uint8 *) (code + ip))); -			ip += (parameter + 1); -			break; -		case CP_PUSH_DEREFERENCED_STRUCTURE: -			// Push the address of a dereferenced structure -			Read32ip(parameter); -			debug(5, "Push address of far variable (%x)", _vm->_memory->ptrToInt((const uint8 *) (objectData + sizeof(int32) + sizeof(_standardHeader) + sizeof(_object_hub) + parameter))); -			PUSHONSTACK(_vm->_memory->ptrToInt((const uint8 *) (objectData + sizeof(int32) + sizeof(_standardHeader) + sizeof(_object_hub) + parameter))); -			break; -		case OP_GTTHANE: -			// '>=' -			debug(5, "%d >= %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] >= stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] >= stack2[stackPointer2 - 1]); -			break; -		case OP_LSTHANE: -			// '<=' -			debug(5, "%d <= %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] <= stack2[stackPointer2 - 1]); -			DOOPERATION(stack2[stackPointer2 - 2] <= stack2[stackPointer2 - 1]); -			break; -		case OP_OROR: -			// '||' -			debug(5, "%d || %d -> %d", -				stack2[stackPointer2 - 2], -				stack2[stackPointer2 - 1], -				stack2[stackPointer2 - 2] || stack2[stackPointer2 - 1]); -			DOOPERATION (stack2[stackPointer2 - 2] || stack2[stackPointer2 - 1]); -			break;  		default: -			error("Interpreter error: Invalid token %d", curCommand); +			error("Invalid script command %d", curCommand);  			return 3;  		}  	} | 
