aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/cursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tinsel/cursor.cpp')
-rw-r--r--engines/tinsel/cursor.cpp647
1 files changed, 647 insertions, 0 deletions
diff --git a/engines/tinsel/cursor.cpp b/engines/tinsel/cursor.cpp
new file mode 100644
index 0000000000..b95662cbfe
--- /dev/null
+++ b/engines/tinsel/cursor.cpp
@@ -0,0 +1,647 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ * Cursor and cursor trails.
+ */
+
+#include "tinsel/cursor.h"
+
+#include "tinsel/anim.h"
+#include "tinsel/background.h"
+#include "tinsel/cursor.h"
+#include "tinsel/dw.h"
+#include "tinsel/events.h" // For EventsManager class
+#include "tinsel/film.h"
+#include "tinsel/graphics.h"
+#include "tinsel/handle.h"
+#include "tinsel/inventory.h"
+#include "tinsel/multiobj.h" // multi-part object defintions etc.
+#include "tinsel/object.h"
+#include "tinsel/pid.h"
+#include "tinsel/sched.h"
+#include "tinsel/timers.h" // For ONE_SECOND constant
+#include "tinsel/tinlib.h" // resetidletime()
+#include "tinsel/tinsel.h" // For engine access
+
+
+namespace Tinsel {
+
+//----------------- LOCAL DEFINES --------------------
+
+#define ITERATION_BASE FRAC_ONE
+#define ITER_ACCELLERATION (10L << (FRAC_BITS - 4))
+
+
+//----------------- LOCAL GLOBAL DATA --------------------
+
+static OBJECT *McurObj = 0; // Main cursor object
+static OBJECT *AcurObj = 0; // Auxiliary cursor object
+
+static ANIM McurAnim = {0,0,0,0,0}; // Main cursor animation structure
+static ANIM AcurAnim = {0,0,0,0,0}; // Auxiliary cursor animation structure
+
+static bool bHiddenCursor = false; // Set when cursor is hidden
+static bool bTempNoTrailers = false; // Set when cursor trails are hidden
+
+static bool bFrozenCursor = false; // Set when cursor position is frozen
+
+static frac_t IterationSize = 0;
+
+static SCNHANDLE CursorHandle = 0; // Handle to cursor reel data
+
+static int numTrails = 0;
+static int nextTrail = 0;
+
+static bool bWhoa = false; // Set by DropCursor() at the end of a scene
+ // - causes cursor processes to do nothing
+ // Reset when main cursor has re-initialised
+
+static bool restart = false; // When main cursor has been bWhoa-ed, it waits
+ // for this to be set to true.
+
+static short ACoX = 0, ACoY = 0; // Auxillary cursor image's animation offsets
+
+
+
+#define MAX_TRAILERS 10
+
+static struct {
+
+ ANIM trailAnim; // Animation structure
+ OBJECT *trailObj; // This trailer's object
+
+} ntrailData [MAX_TRAILERS];
+
+static int lastCursorX = 0, lastCursorY = 0;
+
+
+//----------------- FORWARD REFERENCES --------------------
+
+static void MoveCursor(void);
+
+/**
+ * Initialise and insert a cursor trail object, set its Z-pos, and hide
+ * it. Also initialise its animation script.
+ */
+static void InitCurTrailObj(int i, int x, int y) {
+ const FREEL *pfr; // pointer to reel
+ IMAGE *pim; // pointer to image
+ const MULTI_INIT *pmi; // MULTI_INIT structure
+
+ const FILM *pfilm;
+
+ if (!numTrails)
+ return;
+
+ // Get rid of old object
+ if (ntrailData[i].trailObj != NULL)
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+
+ pim = GetImageFromFilm(CursorHandle, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
+ assert(BackPal()); // No background palette
+ pim->hImgPal = TO_LE_32(BackPal());
+
+ // Initialise and insert the object, set its Z-pos, and hide it
+ ntrailData[i].trailObj = MultiInitObject(pmi);
+ MultiInsertObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+ MultiSetZPosition(ntrailData[i].trailObj, Z_CURSORTRAIL);
+ MultiSetAniXY(ntrailData[i].trailObj, x, y);
+
+ // Initialise the animation script
+ InitStepAnimScript(&ntrailData[i].trailAnim, ntrailData[i].trailObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
+ StepAnimScript(&ntrailData[i].trailAnim);
+}
+
+/**
+ * Get the cursor position from the mouse driver.
+ */
+static bool GetDriverPosition(int *x, int *y) {
+ Common::Point ptMouse = _vm->getMousePosition();
+ *x = ptMouse.x;
+ *y = ptMouse.y;
+
+ return(*x >= 0 && *x <= SCREEN_WIDTH-1 &&
+ *y >= 0 && *y <= SCREEN_HEIGHT-1);
+}
+
+/**
+ * Move the cursor relative to current position.
+ */
+void AdjustCursorXY(int deltaX, int deltaY) {
+ int x, y;
+
+ if (deltaX || deltaY) {
+ if (GetDriverPosition(&x, &y))
+ _vm->setMousePosition(Common::Point(x + deltaX, y + deltaY));
+ }
+ MoveCursor();
+}
+
+/**
+ * Move the cursor to an absolute position.
+ */
+void SetCursorXY(int newx, int newy) {
+ int x, y;
+ int Loffset, Toffset; // Screen offset
+
+ PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
+ newx -= Loffset;
+ newy -= Toffset;
+
+ if (GetDriverPosition(&x, &y))
+ _vm->setMousePosition(Common::Point(newx, newy));
+ MoveCursor();
+}
+
+/**
+ * Move the cursor to a screen position.
+ */
+void SetCursorScreenXY(int newx, int newy) {
+ int x, y;
+
+ if (GetDriverPosition(&x, &y))
+ _vm->setMousePosition(Common::Point(newx, newy));
+ MoveCursor();
+}
+
+/**
+ * Called by the world and his brother.
+ * Returns the cursor's animation position in (x,y).
+ * Returns false if there is no cursor object.
+ */
+bool GetCursorXYNoWait(int *x, int *y, bool absolute) {
+ if (McurObj == NULL) {
+ *x = *y = 0;
+ return false;
+ }
+
+ GetAniPosition(McurObj, x, y);
+
+ if (absolute) {
+ int Loffset, Toffset; // Screen offset
+ PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
+ *x += Loffset;
+ *y += Toffset;
+ }
+
+ return true;
+}
+
+/**
+ * Called by the world and his brother.
+ * Returns the cursor's animation position.
+ * If called while there is no cursor object, the calling process ends
+ * up waiting until there is.
+ */
+void GetCursorXY(int *x, int *y, bool absolute) {
+ //while (McurObj == NULL)
+ // ProcessSleepSelf();
+ assert(McurObj);
+ GetCursorXYNoWait(x, y, absolute);
+}
+
+/**
+ * Re-initialise the main cursor to use the main cursor reel.
+ * Called from TINLIB.C to restore cursor after hiding it.
+ * Called from INVENTRY.C to restore cursor after customising it.
+ */
+void RestoreMainCursor(void) {
+ const FILM *pfilm;
+
+ if (McurObj != NULL) {
+ pfilm = (const FILM *)LockMem(CursorHandle);
+
+ InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfilm->reels->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
+ StepAnimScript(&McurAnim);
+ }
+ bHiddenCursor = false;
+ bFrozenCursor = false;
+}
+
+/**
+ * Called from INVENTRY.C to customise the main cursor.
+ */
+void SetTempCursor(SCNHANDLE pScript) {
+ if (McurObj != NULL)
+ InitStepAnimScript(&McurAnim, McurObj, pScript, 2);
+}
+
+/**
+ * Hide the cursor.
+ */
+void DwHideCursor(void) {
+ int i;
+
+ bHiddenCursor = true;
+
+ if (McurObj)
+ MultiHideObject(McurObj);
+ if (AcurObj)
+ MultiHideObject(AcurObj);
+
+ for (i = 0; i < numTrails; i++) {
+ if (ntrailData[i].trailObj != NULL) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+ ntrailData[i].trailObj = NULL;
+ }
+ }
+}
+
+/**
+ * Unhide the cursor.
+ */
+void UnHideCursor(void) {
+ bHiddenCursor = false;
+}
+
+/**
+ * Freeze the cursor.
+ */
+void FreezeCursor(void) {
+ bFrozenCursor = true;
+}
+
+/**
+ * HideCursorTrails
+ */
+void HideCursorTrails(void) {
+ int i;
+
+ bTempNoTrailers = true;
+
+ for (i = 0; i < numTrails; i++) {
+ if (ntrailData[i].trailObj != NULL) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+ ntrailData[i].trailObj = NULL;
+ }
+ }
+}
+
+/**
+ * UnHideCursorTrails
+ */
+void UnHideCursorTrails(void) {
+ bTempNoTrailers = false;
+}
+
+/**
+ * Get pointer to image from a film reel. And the rest.
+ */
+IMAGE *GetImageFromReel(const FREEL *pfr, const MULTI_INIT **ppmi) {
+ const MULTI_INIT *pmi;
+ const FRAME *pFrame;
+
+ pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfr->mobj));
+ if (ppmi)
+ *ppmi = pmi;
+
+ pFrame = (const FRAME *)LockMem(FROM_LE_32(pmi->hMulFrame));
+
+ // get pointer to image
+ return (IMAGE *)LockMem(READ_LE_UINT32(pFrame));
+}
+
+/**
+ * Get pointer to image from a film. And the rest.
+ */
+IMAGE *GetImageFromFilm(SCNHANDLE hFilm, int reel, const FREEL **ppfr, const MULTI_INIT **ppmi, const FILM **ppfilm) {
+ const FILM *pfilm;
+ const FREEL *pfr;
+
+ pfilm = (const FILM *)LockMem(hFilm);
+ if (ppfilm)
+ *ppfilm = pfilm;
+
+ pfr = &pfilm->reels[reel];
+ if (ppfr)
+ *ppfr = pfr;
+
+ return GetImageFromReel(pfr, ppmi);
+}
+
+/**
+ * Delete auxillary cursor. Restore animation offsets in the image.
+ */
+void DelAuxCursor(void) {
+ if (AcurObj != NULL) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), AcurObj);
+ AcurObj = NULL;
+ }
+}
+
+/**
+ * Set auxillary cursor.
+ * Save animation offsets from the image if required.
+ */
+void SetAuxCursor(SCNHANDLE hFilm) {
+ IMAGE *pim; // Pointer to auxillary cursor's image
+ const FREEL *pfr;
+ const MULTI_INIT *pmi;
+ const FILM *pfilm;
+ int x, y; // Cursor position
+
+ DelAuxCursor(); // Get rid of previous
+
+ GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
+
+ pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
+ assert(BackPal()); // no background palette
+ pim->hImgPal = TO_LE_32(BackPal()); // Poke in the background palette
+
+ ACoX = (short)(FROM_LE_16(pim->imgWidth)/2 - ((int16) FROM_LE_16(pim->anioffX)));
+ ACoY = (short)(FROM_LE_16(pim->imgHeight)/2 - ((int16) FROM_LE_16(pim->anioffY)));
+
+ // Initialise and insert the auxillary cursor object
+ AcurObj = MultiInitObject(pmi);
+ MultiInsertObject(GetPlayfieldList(FIELD_STATUS), AcurObj);
+
+ // Initialise the animation and set its position
+ InitStepAnimScript(&AcurAnim, AcurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
+ MultiSetAniXY(AcurObj, x - ACoX, y - ACoY);
+ MultiSetZPosition(AcurObj, Z_ACURSOR);
+
+ if (bHiddenCursor)
+ MultiHideObject(AcurObj);
+}
+
+/**
+ * MoveCursor
+ */
+static void MoveCursor(void) {
+ int startX, startY;
+ Common::Point ptMouse;
+ frac_t newX, newY;
+ unsigned dir;
+
+ // get cursors start animation position
+ GetCursorXYNoWait(&startX, &startY, false);
+
+ // get mouse drivers current position
+ ptMouse = _vm->getMousePosition();
+
+ // convert to fixed point
+ newX = intToFrac(ptMouse.x);
+ newY = intToFrac(ptMouse.y);
+
+ // modify mouse driver position depending on cursor keys
+ if ((dir = _vm->getKeyDirection()) != 0) {
+ if (dir & MSK_LEFT)
+ newX -= IterationSize;
+
+ if (dir & MSK_RIGHT)
+ newX += IterationSize;
+
+ if (dir & MSK_UP)
+ newY -= IterationSize;
+
+ if (dir & MSK_DOWN)
+ newY += IterationSize;
+
+ IterationSize += ITER_ACCELLERATION;
+
+ // set new mouse driver position
+ _vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY)));
+ } else
+
+ IterationSize = ITERATION_BASE;
+
+ // get new mouse driver position - could have been modified
+ ptMouse = _vm->getMousePosition();
+
+ if (lastCursorX != ptMouse.x || lastCursorY != ptMouse.y) {
+ resetUserEventTime();
+
+ if (!bTempNoTrailers && !bHiddenCursor) {
+ InitCurTrailObj(nextTrail++, lastCursorX, lastCursorY);
+ if (nextTrail == numTrails)
+ nextTrail = 0;
+ }
+ }
+
+ // adjust cursor to new mouse position
+ if (McurObj)
+ MultiSetAniXY(McurObj, ptMouse.x, ptMouse.y);
+ if (AcurObj != NULL)
+ MultiSetAniXY(AcurObj, ptMouse.x - ACoX, ptMouse.y - ACoY);
+
+ if (InventoryActive() && McurObj) {
+ // Notify the inventory
+ Xmovement(ptMouse.x - startX);
+ Ymovement(ptMouse.y - startY);
+ }
+
+ lastCursorX = ptMouse.x;
+ lastCursorY = ptMouse.y;
+}
+
+/**
+ * Initialise cursor object.
+ */
+static void InitCurObj(void) {
+ const FILM *pfilm;
+ const FREEL *pfr;
+ const MULTI_INIT *pmi;
+ IMAGE *pim;
+
+ pim = GetImageFromFilm(CursorHandle, 0, &pfr, &pmi, &pfilm);// Get pointer to image
+ assert(BackPal()); // no background palette
+ pim->hImgPal = TO_LE_32(BackPal());
+//---
+
+ AcurObj = NULL; // No auxillary cursor
+
+ McurObj = MultiInitObject(pmi);
+ MultiInsertObject(GetPlayfieldList(FIELD_STATUS), McurObj);
+
+ InitStepAnimScript(&McurAnim, McurObj, FROM_LE_32(pfr->script), ONE_SECOND / FROM_LE_32(pfilm->frate));
+}
+
+/**
+ * Initialise the cursor position.
+ */
+static void InitCurPos(void) {
+ Common::Point ptMouse = _vm->getMousePosition();
+ lastCursorX = ptMouse.x;
+ lastCursorY = ptMouse.y;
+
+ MultiSetZPosition(McurObj, Z_CURSOR);
+ MoveCursor();
+ MultiHideObject(McurObj);
+
+ IterationSize = ITERATION_BASE;
+}
+
+/**
+ * CursorStoppedCheck
+ */
+static void CursorStoppedCheck(CORO_PARAM) {
+ // COROUTINE
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // If scene is closing down
+ if (bWhoa) {
+ // ...wait for next scene start-up
+ while (!restart)
+ CORO_SLEEP(1);
+
+ // Re-initialise
+ InitCurObj();
+ InitCurPos();
+ InventoryIconCursor(); // May be holding something
+
+ // Re-start the cursor trails
+ restart = false; // set all bits
+ bWhoa = false;
+ }
+ CORO_END_CODE;
+}
+
+/**
+ * The main cursor process.
+ */
+void CursorProcess(CORO_PARAM, const void *) {
+ // COROUTINE
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ while (!CursorHandle || !BackPal())
+ CORO_SLEEP(1);
+
+ InitCurObj();
+ InitCurPos();
+ InventoryIconCursor(); // May be holding something
+
+ bWhoa = false;
+ restart = false;
+
+ while (1) {
+ // allow rescheduling
+ CORO_SLEEP(1);
+
+ // Stop/start between scenes
+ CORO_INVOKE_0(CursorStoppedCheck);
+
+ // Step the animation script(s)
+ StepAnimScript(&McurAnim);
+ if (AcurObj != NULL)
+ StepAnimScript(&AcurAnim);
+ for (int i = 0; i < numTrails; i++) {
+ if (ntrailData[i].trailObj != NULL) {
+ if (StepAnimScript(&ntrailData[i].trailAnim) == ScriptFinished) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+ ntrailData[i].trailObj = NULL;
+ }
+ }
+ }
+
+ // Move the cursor as appropriate
+ if (!bFrozenCursor)
+ MoveCursor();
+
+ // If the cursor should be hidden...
+ if (bHiddenCursor) {
+ // ...hide the cursor object(s)
+ MultiHideObject(McurObj);
+ if (AcurObj)
+ MultiHideObject(AcurObj);
+
+ for (int i = 0; i < numTrails; i++) {
+ if (ntrailData[i].trailObj != NULL)
+ MultiHideObject(ntrailData[i].trailObj);
+ }
+
+ // Wait 'til cursor is again required.
+ while (bHiddenCursor) {
+ CORO_SLEEP(1);
+
+ // Stop/start between scenes
+ CORO_INVOKE_0(CursorStoppedCheck);
+ }
+ }
+ }
+ CORO_END_CODE;
+}
+
+/**
+ * Called from dec_cursor() Glitter function.
+ * Register the handle to cursor reel data.
+ */
+void DwInitCursor(SCNHANDLE bfilm) {
+ const FILM *pfilm;
+
+ CursorHandle = bfilm;
+
+ pfilm = (const FILM *)LockMem(CursorHandle);
+ numTrails = FROM_LE_32(pfilm->numreels) - 1;
+
+ assert(numTrails <= MAX_TRAILERS);
+}
+
+/**
+ * DropCursor is called when a scene is closing down.
+ */
+void DropCursor(void) {
+ AcurObj = NULL; // No auxillary cursor
+ McurObj = NULL; // No cursor object (imminently deleted elsewhere)
+ bHiddenCursor = false; // Not hidden in next scene
+ bTempNoTrailers = false; // Trailers not hidden in next scene
+ bWhoa = true; // Suspend cursor processes
+
+ for (int i = 0; i < numTrails; i++) {
+ if (ntrailData[i].trailObj != NULL) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), ntrailData[i].trailObj);
+ ntrailData[i].trailObj = NULL;
+ }
+ }
+}
+
+/**
+ * RestartCursor is called when a new scene is starting up.
+ */
+void RestartCursor(void) {
+ restart = true; // Get the main cursor to re-initialise
+}
+
+/**
+ * Called when restarting the game, ensures correct re-start with NULL
+ * pointers etc.
+ */
+void RebootCursor(void) {
+ McurObj = AcurObj = NULL;
+ for (int i = 0; i < MAX_TRAILERS; i++)
+ ntrailData[i].trailObj = NULL;
+
+ bHiddenCursor = bTempNoTrailers = bFrozenCursor = false;
+
+ CursorHandle = 0;
+
+ bWhoa = false;
+ restart = false;
+}
+
+} // end of namespace Tinsel