Exemple #1
0
/**
 * Started up for scene script and entrance script.
 */
static void SceneTinselProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		INT_CONTEXT *pic;
		const TP_INIT *pInit;
		int myEscape;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	// The following myEscape value setting is used for enabling title screen skipping in DW1
	if (TinselV1 && (sceneCtr == 1)) initialMyEscape = GetEscEvents();
	_ctx->myEscape = (TinselV1 && (sceneCtr < 4)) ? initialMyEscape : 0;

	// get the stuff copied to process when it was created
	_ctx->pInit = (const TP_INIT *)param;
	assert(_ctx->pInit);
	assert(_ctx->pInit->hTinselCode);		// Must have some code to run

	_ctx->pic = InitInterpretContext(GS_SCENE,
		READ_LE_UINT32(&_ctx->pInit->hTinselCode),
		TinselV2 ? _ctx->pInit->event : NOEVENT,
		NOPOLY,			// No polygon
		0,				// No actor
		NULL,			// No object
		_ctx->myEscape);
	CORO_INVOKE_1(Interpret, _ctx->pic);

	if (_ctx->pInit->event == CLOSEDOWN || _ctx->pInit->event == LEAVE_T2)
		bWatchingOut = false;

	CORO_END_CODE;
}
Exemple #2
0
void UpdateActorEsc(int ano, int escEvent) {
	RANGE_CHECK(ano);

	if (escEvent) {
		actorInfo[ano - 1].bEscOn = true;
		actorInfo[ano - 1].escEvent = escEvent;
	} else {
		actorInfo[ano - 1].bEscOn = false;
		actorInfo[ano - 1].escEvent = GetEscEvents();
	}

}
Exemple #3
0
/**
 * Interprets the PCODE instructions in the code array.
 */
void Interpret(CORO_PARAM, INT_CONTEXT *ic) {
	do {
		int tmp, tmp2;
		int ip = ic->ip;
		const WorkaroundEntry *wkEntry = ic->fragmentPtr;

		if (wkEntry == NULL) {
			// Check to see if a workaround fragment needs to be executed
			for (wkEntry = workaroundList; wkEntry->script != NULL; ++wkEntry) {
				if ((wkEntry->version == TinselVersion) &&
					(wkEntry->hCode == ic->hCode) &&
					(wkEntry->ip == ip) &&
					(!TinselV1 || (wkEntry->scnFlag == ((_vm->getFeatures() & GF_SCNFILES) != 0)))) {
					// Point to start of workaround fragment
					ip = 0;
					break;
				}
			}
			if (wkEntry->script == NULL)
				wkEntry = NULL;
		}

		byte opcode = (byte)GetBytes(ic->code, wkEntry, ip, 0);
		if (TinselV0 && ((opcode & OPMASK) > OP_IMM))
			opcode += 3;

		debug(7, "ip=%d  Opcode %d (-> %d)", ic->ip, opcode, opcode & OPMASK);
		switch (opcode & OPMASK) {
		case OP_HALT:			// end of program

			ic->bHalt = true;
			break;

		case OP_IMM:			// loads immediate data onto stack
		case OP_STR:			// loads string handle onto stack
		case OP_FILM:			// loads film handle onto stack
		case OP_CDFILM:			// loads film handle onto stack
		case OP_FONT:			// loads font handle onto stack
		case OP_PAL:			// loads palette handle onto stack

			ic->stack[++ic->sp] = Fetch(opcode, ic->code, wkEntry, ip);
			break;

		case OP_ZERO:			// loads zero onto stack
			ic->stack[++ic->sp] = 0;
			break;

		case OP_ONE:			// loads one onto stack
			ic->stack[++ic->sp] = 1;
			break;

		case OP_MINUSONE:		// loads minus one onto stack
			ic->stack[++ic->sp] = -1;
			break;

		case OP_LOAD:			// loads local variable onto stack

			ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)];
			break;

		case OP_GLOAD:				// loads global variable onto stack

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			assert(0 <= tmp && tmp < numGlobals);
			ic->stack[++ic->sp] = pGlobals[tmp];
			break;

		case OP_STORE:				// pops stack and stores in local variable

			ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)] = ic->stack[ic->sp--];
			break;

		case OP_GSTORE:				// pops stack and stores in global variable

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			assert(0 <= tmp && tmp < numGlobals);
			pGlobals[tmp] = ic->stack[ic->sp--];
			break;

		case OP_CALL:				// procedure call

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			//assert(0 <= tmp && tmp < codeSize);	// TODO: Verify jumps are not out of bounds
			ic->stack[ic->sp + 1] = 0;	// static link
			ic->stack[ic->sp + 2] = ic->bp;	// dynamic link
			ic->stack[ic->sp + 3] = ip;	// return address
			ic->bp = ic->sp + 1;		// set new base pointer
			ip = tmp;	// set ip to procedure address
			break;

		case OP_LIBCALL:		// library procedure or function call

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			// NOTE: Interpret() itself is not using the coroutine facilities,
			// but still accepts a CORO_PARAM, so from the outside it looks
			// like a coroutine. In fact it may still acts as a kind of "proxy"
			// for some underlying coroutine. To enable this, we just pass on
			// 'coroParam' to CallLibraryRoutine(). If we then detect that
			// coroParam was set to a non-zero value, this means that some
			// coroutine code did run at some point, and we are now supposed
			// to sleep or die -- hence, we 'return' if coroParam != 0.
			//
			// This works because Interpret() is fully re-entrant: If we return
			// now and are later called again, then we will end up in the very
			// same spot (i.e. here).
			//
			// The reasons we do it this way, instead of turning Interpret into
			// a 'proper' coroutine are (1) we avoid implementation problems
			// (CORO_INVOKE involves adding 'case' statements, but Interpret
			// already has a huge switch/case, so that would not work out of the
			// box), (2) we incurr less overhead, (3) it's easier to debug,
			// (4) it's simply cool ;).
			tmp2 = CallLibraryRoutine(coroParam, tmp, &ic->stack[ic->sp], ic, &ic->resumeState);
			if (coroParam)
				return;
			if (!TinselV0)
				ic->sp += tmp2;
			LockCode(ic);
			if (TinselV2 && (ic->resumeState == RES_1))
				ic->resumeState = RES_NOT;
			break;

		case OP_RET:			// procedure return

			ic->sp = ic->bp - 1;		// restore stack
			ip = ic->stack[ic->sp + 3];	// return address
			ic->bp = ic->stack[ic->sp + 2];	// restore previous base pointer
			break;

		case OP_ALLOC:			// allocate storage on stack

			ic->sp += (int32)Fetch(opcode, ic->code, wkEntry, ip);
			break;

		case OP_JUMP:	// unconditional jump

			ip = Fetch(opcode, ic->code, wkEntry, ip);
			wkEntry = NULL;					// In case a jump occurs from a workaround
			break;

		case OP_JMPFALSE:	// conditional jump

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			if (ic->stack[ic->sp--] == 0) {
				// condition satisfied - do the jump
				ip = tmp;
				wkEntry = NULL;					// In case a jump occurs from a workaround
			}
			break;

		case OP_JMPTRUE:	// conditional jump

			tmp = Fetch(opcode, ic->code, wkEntry, ip);
			if (ic->stack[ic->sp--] != 0) {
				// condition satisfied - do the jump
				ip = tmp;
				wkEntry = NULL;					// In case a jump occurs from a workaround
			}
			break;

		case OP_EQUAL:			// tests top two items on stack for equality
		case OP_LESS:			// tests top two items on stack
		case OP_LEQUAL:			// tests top two items on stack
		case OP_NEQUAL:			// tests top two items on stack
		case OP_GEQUAL:			// tests top two items on stack
		case OP_GREAT:			// tests top two items on stack
		case OP_LOR:			// logical or of top two items on stack and replaces with result
		case OP_LAND:			// logical ands top two items on stack and replaces with result

			// pop one operand
			ic->sp--;
			assert(ic->sp >= 0);
			tmp = ic->stack[ic->sp];
			tmp2 = ic->stack[ic->sp + 1];

			// replace other operand with result of operation
			switch (opcode) {
			case OP_EQUAL:  tmp = (tmp == tmp2); break;
			case OP_LESS:   tmp = (tmp <  tmp2); break;
			case OP_LEQUAL: tmp = (tmp <= tmp2); break;
			case OP_NEQUAL: tmp = (tmp != tmp2); break;
			case OP_GEQUAL: tmp = (tmp >= tmp2); break;
			case OP_GREAT:  tmp = (tmp >  tmp2); break;

			case OP_LOR:    tmp = (tmp || tmp2); break;
			case OP_LAND:   tmp = (tmp && tmp2); break;
			}

			ic->stack[ic->sp] = tmp;
			break;

		case OP_PLUS:			// adds top two items on stack and replaces with result
		case OP_MINUS:			// subs top two items on stack and replaces with result
		case OP_MULT:			// multiplies top two items on stack and replaces with result
		case OP_DIV:			// divides top two items on stack and replaces with result
		case OP_MOD:			// divides top two items on stack and replaces with modulus
		case OP_AND:			// bitwise ands top two items on stack and replaces with result
		case OP_OR:				// bitwise ors top two items on stack and replaces with result
		case OP_EOR:			// bitwise exclusive ors top two items on stack and replaces with result

			// pop one operand
			ic->sp--;
			assert(ic->sp >= 0);
			tmp = ic->stack[ic->sp];
			tmp2 = ic->stack[ic->sp + 1];

			// replace other operand with result of operation
			switch (opcode) {
			case OP_PLUS:   tmp += tmp2; break;
			case OP_MINUS:  tmp -= tmp2; break;
			case OP_MULT:   tmp *= tmp2; break;
			case OP_DIV:    tmp /= tmp2; break;
			case OP_MOD:    tmp %= tmp2; break;
			case OP_AND:    tmp &= tmp2; break;
			case OP_OR:     tmp |= tmp2; break;
			case OP_EOR:    tmp ^= tmp2; break;
			}
			ic->stack[ic->sp] = tmp;
			break;

		case OP_NOT:			// logical nots top item on stack

			ic->stack[ic->sp] = !ic->stack[ic->sp];
			break;

		case OP_COMP:			// complements top item on stack
			ic->stack[ic->sp] = ~ic->stack[ic->sp];
			break;

		case OP_NEG:			// negates top item on stack
			ic->stack[ic->sp] = -ic->stack[ic->sp];
			break;

		case OP_DUP:			// duplicates top item on stack
			ic->stack[ic->sp + 1] = ic->stack[ic->sp];
			ic->sp++;
			break;

		case OP_ESCON:
			bNoPause = true;
			ic->escOn = true;
			ic->myEscape = GetEscEvents();
			break;

		case OP_ESCOFF:
			ic->escOn = false;
			ic->myEscape = 0;
			break;

		default:
			error("Interpret() - Unknown opcode");
		}

		// check for stack under-overflow
		assert(ic->sp >= 0 && ic->sp < PCODE_STACK_SIZE);
		ic->ip = ip;
		ic->fragmentPtr = wkEntry;
	} while (!ic->bHalt);

	// make sure stack is unwound
	assert(ic->sp == 0);

	FreeInterpretContextPi(ic);
}