Пример #1
0
/**
 * Moving actor process - 1 per moving actor in current scene.
 */
void T1MoverProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	const PMOVER pActor = *(const PMOVER *)param;

	CORO_BEGIN_CODE(_ctx);

	while (1) {
		if (pActor->bSpecReel) {
			if (!pActor->bHidden)
#ifdef DEBUG
			assert(StepAnimScript(&pActor->actorAnim) != ScriptFinished); // Actor reel has finished!
#else
			StepAnimScript(&pActor->actorAnim);
#endif
		} else
			DoMoveActor(pActor);

		CORO_SLEEP(1);		// allow rescheduling

	}

	CORO_END_CODE;
}
Пример #2
0
/**
 * Decide when to scroll and scroll when decided to.
 */
void ScrollProcess(CORO_PARAM, const void *) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	// In Tinsel v2, scenes may play movies, so the background may not always
	// already be initialized like it is in v1
	while (!GetBgObject())
		CORO_SLEEP(1);

	g_ImageH = BgHeight();		// Dimensions
	g_ImageW = BgWidth();		//  of this scene.

	// Give up if there'll be no purpose in this process
	if (g_ImageW == SCREEN_WIDTH  &&  g_ImageH == SCREEN_HEIGHT)
		CORO_KILL_SELF();

	if (!TinselV2) {
		g_LeftScroll = g_DownScroll = 0;		// No iterations outstanding
		g_oldx = g_oldy = 0;
		g_scrollPixelsX = g_scrollPixelsY = SCROLLPIXELS;
	}

	if (!g_scrollActor)
		g_scrollActor = GetLeadId();

	g_pScrollMover = GetMover(g_scrollActor);

	while (1) {
		MonitorScroll();		// Set scroll requirement

		if (g_LeftScroll || g_DownScroll)	// Scroll if required
			ScrollImage();

		CORO_SLEEP(1);		// allow re-scheduling
	}

	CORO_END_CODE;
}
Пример #3
0
/**
 * WaitInterpret
 */
void WaitInterpret(CORO_PARAM, PPROCESS pWaitProc, bool *result) {
	int i;
	PPROCESS currentProcess = g_scheduler->getCurrentProcess();
	assert(currentProcess);
	assert(currentProcess != pWaitProc);
	if (result) *result = false;

	/*
	 * Calling process is the waiter, find its interpret context.
	 */

	CORO_BEGIN_CONTEXT;
		PINT_CONTEXT picWaiter, picWaitee;
	CORO_END_CONTEXT(_ctx);


	CORO_BEGIN_CODE(_ctx);

	for (i = 0, _ctx->picWaiter = icList; i < NUM_INTERPRET; i++, _ctx->picWaiter++) {
		if (_ctx->picWaiter->GSort != GS_NONE && _ctx->picWaiter->pProc == currentProcess) {
			break;
		}
	}

	/*
	 * Find the interpret context of the process we're waiting for
	 */
	for (i = 0, _ctx->picWaitee = icList; i < NUM_INTERPRET; i++, _ctx->picWaitee++) {
		if (_ctx->picWaitee->GSort != GS_NONE && _ctx->picWaitee->pProc == pWaitProc) {
			break;
		}
	}

	/*
	 * Set the first as waiting for the second
	 */
	assert(_ctx->picWaitee->waitNumber2 == 0);
	_ctx->picWaiter->waitNumber1 = _ctx->picWaitee->waitNumber2 = UniqueWaitNumber();
	_ctx->picWaiter->resumeCode = RES_WAITING;

	/*
	 * Wait for it
	 */
	CORO_GIVE_WAY;
	while (_ctx->picWaiter->resumeCode == RES_WAITING) {
		CORO_SLEEP(1);
	}

	if (result)
		*result = (_ctx->picWaiter->resumeCode == RES_FINISHED);
	CORO_END_CODE;
}
Пример #4
0
/**
 * Perform a walk directly initiated by a click.
 */
static void WalkProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		PMOVER pMover;
		int thisWalk;
	CORO_END_CONTEXT(_ctx);

	const WP_INIT *to = (const WP_INIT *)param;	// get the co-ordinates - copied to process when it was created

	CORO_BEGIN_CODE(_ctx);

	_ctx->pMover = GetMover(LEAD_ACTOR);

	if (TinselV2 && MoverIs(_ctx->pMover) && !MoverIsSWalking(_ctx->pMover)) {
		assert(_ctx->pMover->hCpath != NOPOLY); // Lead actor is not in a path

		_ctx->thisWalk = SetActorDest(_ctx->pMover, to->x, to->y, false, 0);
		DontScrollCursor();

		while (MoverMoving(_ctx->pMover) && (_ctx->thisWalk == GetWalkNumber(_ctx->pMover)))
			CORO_SLEEP(1);

	} else if (!TinselV2 && _ctx->pMover->bActive) {
		assert(_ctx->pMover->hCpath != NOPOLY); // Lead actor is not in a path

		GetToken(TOKEN_LEAD);
		SetActorDest(_ctx->pMover, to->x, to->y, false, 0);
		DontScrollCursor();

		while (MoverMoving(_ctx->pMover))
			CORO_SLEEP(1);

		FreeToken(TOKEN_LEAD);
	}

	CORO_END_CODE;
}
Пример #5
0
/**
 * Process to fade one palette.
 * A pointer to a 'FADE' structure must be passed to this process when
 * it is created.
 */
static void FadeProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		COLORREF fadeRGB[MAX_COLORS];	// local copy of palette
		const long *pColMult;			// pointer to color multiplier table
		PALETTE *pPalette;		// pointer to palette
	CORO_END_CONTEXT(_ctx);

	// get the fade data structure - copied to process when it was created
	const FADE *pFade = (const FADE *)param;

	CORO_BEGIN_CODE(_ctx);

	if (TinselV2)
		// Note that this palette is being faded
		FadingPalette(pFade->pPalQ, true);

	// get pointer to palette - reduce pointer indirection a bit
	_ctx->pPalette = (PALETTE *)LockMem(FROM_32(pFade->pPalQ->hPal));

	for (_ctx->pColMult = pFade->pColorMultTable; *_ctx->pColMult >= 0; _ctx->pColMult++) {
		// go through all multipliers in table - until a negative entry

		// fade palette using next multiplier
		if (TinselV2)
			FadePalette(_ctx->fadeRGB, pFade->pPalQ->palRGB,
				pFade->pPalQ->numColors, (uint32) *_ctx->pColMult);
		else
			FadePalette(_ctx->fadeRGB, _ctx->pPalette->palRGB,
				FROM_32(_ctx->pPalette->numColors), (uint32) *_ctx->pColMult);

		// send new palette to video DAC
		UpdateDACqueue(pFade->pPalQ->posInDAC, FROM_32(_ctx->pPalette->numColors), _ctx->fadeRGB);

		// allow time for video DAC to be updated
		CORO_SLEEP(1);
	}

	if (TinselV2)
		// Note that this palette is being faded
		FadingPalette(pFade->pPalQ, false);

	CORO_END_CODE;
}
Пример #6
0
/**
 * Handles launching a single click action result if the timeout for a double-click
 * expires
 */
static void SingleLeftProcess(CORO_PARAM, const void *) {
	CORO_BEGIN_CONTEXT;
		uint32 endTicks;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	// Work out when to wait until
	_ctx->endTicks = DwGetCurrentTime() + (uint32)dclickSpeed;

	// Timeout a double click (may not work once every 49 days!)
	do {
		CORO_SLEEP(1);
	} while (DwGetCurrentTime() < _ctx->endTicks);

	if (GetProvNotProcessed())
		PlayerEvent(PLR_WALKTO, clickPos);

	CORO_KILL_SELF();
	CORO_END_CODE;
}
Пример #7
0
void CdCD(CORO_PARAM) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	while (g_bChangingCD) {
		if (g_scheduler->getCurrentProcess()) {
			// FIXME: CdCD gets passed a nullContext in RegisterGlobals() and
			//        PrimeSceneHopper(), because I didn't know how to get a proper
			//        context without converting the whole calling stack to CORO'd
			//        functions. If these functions really get called while a CD
			//        change is requested, this needs to be resolved.
			if (coroParam == nullContext)
				error("CdCD needs context");
			CORO_SLEEP(1);
		} else
			error("No current process in CdCD()");
	}

	CORO_END_CODE;
}
Пример #8
0
/**
 * If this is a single click, wait to check it's not the first half of a
 * double click.
 * If this is a double click, the process from the waiting single click
 * gets killed.
 */
void AllowDclick(CORO_PARAM, PLR_EVENT be) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);
	if (be == PLR_SLEFT) {
		GetToken(TOKEN_LEFT_BUT);
		CORO_SLEEP(_vm->_config->_dclickSpeed+1);
		FreeToken(TOKEN_LEFT_BUT);

		// Prevent activation of 2 events on the same tick
		if (++g_eCount != 1)
			CORO_KILL_SELF();

		break;

	} else if (be == PLR_DLEFT) {
		GetToken(TOKEN_LEFT_BUT);
		FreeToken(TOKEN_LEFT_BUT);
	}
	CORO_END_CODE;
}
Пример #9
0
/**
 * Runs secondary reels for a scene background
 */
static void BGotherProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		OBJECT *pObj;
		ANIM anim;
	CORO_END_CONTEXT(_ctx);

	const FREEL *pReel = (const FREEL *)param;
	const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));

	CORO_BEGIN_CODE(_ctx);

	// Initialise and insert the object, and initialise its script.
	_ctx->pObj = MultiInitObject(pmi);
	MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pObj);

	InitStepAnimScript(&_ctx->anim, pBG[0], FROM_LE_32(pReel->script), BGspeed);

	while (StepAnimScript(&_ctx->anim) != ScriptFinished)
		CORO_SLEEP(1);

	CORO_END_CODE;
}
Пример #10
0
/**
 * Run main animation that comprises the scene background.
 */
static void BGmainProcess(CORO_PARAM, const void *param) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	const FILM *pFilm;
	const FREEL *pReel;
	const MULTI_INIT *pmi;

	// get the stuff copied to process when it was created
	if (pBG[0] == NULL) {
		/*** At start of scene ***/

		if (!TinselV2) {
			pReel = (const FREEL *)param;

			// Get the MULTI_INIT structure
			pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));

			// Initialise and insert the object, and initialise its script.
			pBG[0] = MultiInitObject(pmi);
			MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[0]);
			InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
			bgReels = 1;
		} else {
			/*** At start of scene ***/
			pFilm = (const FILM *)LockMem(hBackground);
			bgReels = FROM_LE_32(pFilm->numreels);

			int i;
			for (i = 0; i < bgReels; i++) {
				// Get the MULTI_INIT structure
				pmi = (PMULTI_INIT) LockMem(FROM_LE_32(pFilm->reels[i].mobj));

				// Initialise and insert the object, and initialise its script.
				pBG[i] = MultiInitObject(pmi);
				MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[i]);
				MultiSetZPosition(pBG[i], 0);
				InitStepAnimScript(&thisAnim[i], pBG[i], FROM_LE_32(pFilm->reels[i].script), BGspeed);

				if (i > 0)
					pBG[i-1]->pSlave = pBG[i];
			}
		}

		if (bDoFadeIn) {
			FadeInFast(NULL);
			bDoFadeIn = false;
		} else if (TinselV2)
			PokeInTagColor();

		for (;;) {
			for (int i = 0; i < bgReels; i++) {
				if (StepAnimScript(&thisAnim[i]) == ScriptFinished)
					error("Background animation has finished");
			}

			CORO_SLEEP(1);
		}
	} else {
		// New background during scene
		if (!TinselV2) {
			pReel = (const FREEL *)param;
			InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed);
			StepAnimScript(&thisAnim[0]);
		} else {
			pFilm = (const FILM *)LockMem(hBackground);
			assert(bgReels == (int32)FROM_LE_32(pFilm->numreels));

			// Just re-initialise the scripts.
			for (int i = 0; i < bgReels; i++) {
				InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed);
				StepAnimScript(&thisAnim[i]);
			}
		}
	}

	CORO_END_CODE;
}
Пример #11
0
/**
 * Process to handle changes in the mouse buttons.
 */
static void MouseProcess(CORO_PARAM, const void *) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
		bool lastLWasDouble;
		bool lastRWasDouble;
		uint32 lastLeftClick, lastRightClick;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);

	_ctx->lastLWasDouble = false;
	_ctx->lastRWasDouble = false;
	_ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime();

	while (true) {

		if (mouseButtons.empty()) {
			// allow scheduling
			CORO_SLEEP(1);
			continue;
		}

		// get next mouse button event
		Common::EventType type = *mouseButtons.begin();
		mouseButtons.erase(mouseButtons.begin());

		int xp, yp;
		GetCursorXYNoWait(&xp, &yp, true);
		const Common::Point mousePos(xp, yp);

		switch (type) {
		case Common::EVENT_LBUTTONDOWN:
			// left button press
			if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) {
				// Left button double-click

				if (TinselV2) {
					// Kill off the button process and fire off the action command
					g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1);
					PlayerEvent(PLR_ACTION, clickPos);
				} else {
					// signal left drag start
					ProcessButEvent(PLR_DRAG1_START);

					// signal left double click event
					ProcessButEvent(PLR_DLEFT);
				}

				_ctx->lastLWasDouble = true;
			} else {
				// Initial mouse down - either for a single click, or potentially
				// the start of a double-click action

				if (TinselV2) {
					PlayerEvent(PLR_DRAG1_START, mousePos);

					ProvNotProcessed();
					PlayerEvent(PLR_PROV_WALKTO, mousePos);

				} else {
					// signal left drag start
					ProcessButEvent(PLR_DRAG1_START);

					// signal left single click event
					ProcessButEvent(PLR_SLEFT);
				}

				_ctx->lastLWasDouble = false;
			}
			break;

		case Common::EVENT_LBUTTONUP:
			// left button release

			// update click timer
			if (_ctx->lastLWasDouble == false) {
				_ctx->lastLeftClick = DwGetCurrentTime();

				// If player control is enabled, start a process which, if it times out,
				// will activate a single button click
				if (TinselV2 && ControlIsOn()) {
					clickPos = mousePos;
					g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, NULL, 0);
				}
			} else
				_ctx->lastLeftClick -= dclickSpeed;

			if (TinselV2)
				// Signal left drag end
				PlayerEvent(PLR_DRAG1_END, mousePos);
			else
				// signal left drag end
				ProcessButEvent(PLR_DRAG1_END);
			break;

		case Common::EVENT_RBUTTONDOWN:
			// right button press

			if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) {
				// Right button double-click
				if (TinselV2) {
					PlayerEvent(PLR_NOEVENT, clickPos);
				} else {
					// signal right drag start
					ProcessButEvent(PLR_DRAG2_START);

					// signal right double click event
					ProcessButEvent(PLR_DRIGHT);
				}

				_ctx->lastRWasDouble = true;
			} else {
				if (TinselV2) {
					PlayerEvent(PLR_DRAG2_START, mousePos);
					PlayerEvent(PLR_LOOK, mousePos);
				} else {
					// signal right drag start
					ProcessButEvent(PLR_DRAG2_START);

					// signal right single click event
					ProcessButEvent(PLR_SRIGHT);
				}

				_ctx->lastRWasDouble = false;
			}
			break;

		case Common::EVENT_RBUTTONUP:
			// right button release

			// update click timer
			if (_ctx->lastRWasDouble == false)
				_ctx->lastRightClick = DwGetCurrentTime();
			else
				_ctx->lastRightClick -= dclickSpeed;

			if (TinselV2)
				// Signal left drag end
				PlayerEvent(PLR_DRAG2_END, mousePos);
			else
				// signal right drag end
				ProcessButEvent(PLR_DRAG2_END);
			break;

		default:
			break;
		}
	}
	CORO_END_CODE;
}
Пример #12
0
/**
 * Process to handle keypresses
 */
void KeyboardProcess(CORO_PARAM, const void *) {
	// COROUTINE
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	CORO_BEGIN_CODE(_ctx);
	while (true) {
		if (keypresses.empty()) {
			// allow scheduling
			CORO_SLEEP(1);
			continue;
		}

		// Get the next keyboard event off the stack
		Common::Event evt = *keypresses.begin();
		keypresses.erase(keypresses.begin());
		const Common::Point mousePos = _vm->getMousePosition();

		// Switch for special keys
		switch (evt.kbd.keycode) {
		// Drag action
		case Common::KEYCODE_LALT:
		case Common::KEYCODE_RALT:
			if (evt.type == Common::EVENT_KEYDOWN) {
				if (!bSwapButtons)
					ProcessButEvent(PLR_DRAG2_START);
				else
					ProcessButEvent(PLR_DRAG1_START);
			} else {
				if (!bSwapButtons)
					ProcessButEvent(PLR_DRAG1_END);
				else
					ProcessButEvent(PLR_DRAG2_END);
			}
			continue;

		case Common::KEYCODE_LCTRL:
		case Common::KEYCODE_RCTRL:
			if (evt.type == Common::EVENT_KEYDOWN) {
				ProcessKeyEvent(PLR_LOOK);
			} else {
				// Control key release
			}
			continue;

		default:
			break;
		}

		// At this point only key down events need processing
		if (evt.type == Common::EVENT_KEYUP)
			continue;

		if (_vm->_keyHandler != NULL)
			// Keyboard is hooked, so pass it on to that handler first
			if (!_vm->_keyHandler(evt.kbd))
				continue;

		switch (evt.kbd.keycode) {
		/*** SPACE = WALKTO ***/
		case Common::KEYCODE_SPACE:
			ProcessKeyEvent(PLR_WALKTO);
			continue;

		/*** RETURN = ACTION ***/
		case Common::KEYCODE_RETURN:
		case Common::KEYCODE_KP_ENTER:
			ProcessKeyEvent(PLR_ACTION);
			continue;

		/*** l = LOOK ***/
		case Common::KEYCODE_l:		// LOOK
			ProcessKeyEvent(PLR_LOOK);
			continue;

		case Common::KEYCODE_ESCAPE:
			ProcessKeyEvent(PLR_ESCAPE);
			continue;

#ifdef SLOW_RINCE_DOWN
		case '>':
			AddInterlude(1);
			continue;
		case '<':
			AddInterlude(-1);
			continue;
#endif

		case Common::KEYCODE_F1:
			// Options dialog
			ProcessKeyEvent(PLR_MENU);
			continue;
		case Common::KEYCODE_F5:
			// Save game
			ProcessKeyEvent(PLR_SAVE);
			continue;
		case Common::KEYCODE_F7:
			// Load game
			ProcessKeyEvent(PLR_LOAD);
			continue;
		case Common::KEYCODE_m:
			// Debug facility - scene hopper
			if (TinselV2 && (evt.kbd.flags == Common::KBD_ALT))
				ProcessKeyEvent(PLR_JUMP);
			break;
		case Common::KEYCODE_q:
			if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT))
				ProcessKeyEvent(PLR_QUIT);
			continue;
		case Common::KEYCODE_PAGEUP:
		case Common::KEYCODE_KP9:
			ProcessKeyEvent(PLR_PGUP);
			continue;
		case Common::KEYCODE_PAGEDOWN:
		case Common::KEYCODE_KP3:
			ProcessKeyEvent(PLR_PGDN);
			continue;
		case Common::KEYCODE_HOME:
		case Common::KEYCODE_KP7:
			ProcessKeyEvent(PLR_HOME);
			continue;
		case Common::KEYCODE_END:
		case Common::KEYCODE_KP1:
			ProcessKeyEvent(PLR_END);
			continue;
		default:
			ProcessKeyEvent(PLR_NOEVENT);
			break;
		}
	}
	CORO_END_CODE;
}
Пример #13
0
/**
 * Tinsel 2 Moving actor process
 * - 1 per moving actor in current scene.
 */
void T2MoverProcess(CORO_PARAM, const void *param) {
	CORO_BEGIN_CONTEXT;
	CORO_END_CONTEXT(_ctx);

	// Get the co-ordinates - copied to process when it was created
	const MAINIT *rpos = (const MAINIT *)param;
	PMOVER pMover = rpos->pMover;
	int i;
	FILM *pFilm;
	PMULTI_INIT pmi;

	CORO_BEGIN_CODE(_ctx);

	for (i = 0; i < TOTAL_SCALES; i++) {
		if (pMover->walkReels[i][FORWARD])
			break;
	}
	assert(i < TOTAL_SCALES);

	InitMover(pMover);
	InitialPathChecks(pMover, rpos->X, rpos->Y);

	pFilm = (FILM *)LockMem(pMover->walkReels[i][FORWARD]);	// Any old reel
	pmi = (PMULTI_INIT)LockMem(FROM_32(pFilm->reels[0].mobj));

	// Poke in the background palette
	PokeInPalette(pmi);

	pMover->actorObj = MultiInitObject(pmi);
	// FIXME: This is what the original did. A bug, perhaps?
	// pMover->actorID = pMover->actorID;
	pMover->bActive = true;

	// add it to display list
	MultiInsertObject( GetPlayfieldList(FIELD_WORLD), pMover->actorObj );

	InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, pFilm->reels[0].script, ONE_SECOND/pFilm->frate);
	pMover->stepCount = 0;

	MultiSetAniXY(pMover->actorObj, pMover->objX, pMover->objY);

	// If no path, just use first path in the scene
	if (pMover->hCpath != NOPOLY)
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(pMover->hCpath));
	else
		SetMoverZ(pMover, pMover->objY, GetPolyZfactor(FirstPathPoly()));

	// Make him the right size
	SetMoverStanding(pMover);

	HideMover(pMover);		// Allows a play to come in before this appears
	pMover->bHidden = false;	// ...but don't stay hidden

	for (;;) {
		if (pMover->bSpecReel) {
			if (!pMover->bHidden)
				StepAnimScript(&pMover->actorAnim);
		} else
			DoMoveActor(pMover);

		CheckBrightness(pMover);

		CORO_SLEEP(1);
	}

	CORO_END_CODE;
}