aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/events.cpp
diff options
context:
space:
mode:
authorMax Horn2008-07-23 09:02:47 +0000
committerMax Horn2008-07-23 09:02:47 +0000
commitc441c5261ff3e6ad114c0384ef818b942655f3a6 (patch)
tree6563ef6632ec89f7db2bbb62ad42aea680b507e6 /engines/tinsel/events.cpp
parente7c1a88dd3bf024e87ef62ff0c851b6a551ae2a5 (diff)
downloadscummvm-rg350-c441c5261ff3e6ad114c0384ef818b942655f3a6.tar.gz
scummvm-rg350-c441c5261ff3e6ad114c0384ef818b942655f3a6.tar.bz2
scummvm-rg350-c441c5261ff3e6ad114c0384ef818b942655f3a6.zip
Added Tinsel engine to main repos (no news item for it ON PURPOSE)
svn-id: r33230
Diffstat (limited to 'engines/tinsel/events.cpp')
-rw-r--r--engines/tinsel/events.cpp439
1 files changed, 439 insertions, 0 deletions
diff --git a/engines/tinsel/events.cpp b/engines/tinsel/events.cpp
new file mode 100644
index 0000000000..8064bdd3f3
--- /dev/null
+++ b/engines/tinsel/events.cpp
@@ -0,0 +1,439 @@
+/* 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$
+ *
+ * Main purpose is to process user events.
+ * Also provides a couple of utility functions.
+ */
+
+#include "tinsel/actors.h"
+#include "tinsel/config.h"
+#include "tinsel/cursor.h"
+#include "tinsel/dw.h"
+#include "tinsel/events.h"
+#include "tinsel/handle.h" // For LockMem()
+#include "tinsel/inventory.h"
+#include "tinsel/move.h" // For walking lead actor
+#include "tinsel/pcode.h" // For Interpret()
+#include "tinsel/pid.h"
+#include "tinsel/polygons.h"
+#include "tinsel/rince.h" // For walking lead actor
+#include "tinsel/sched.h"
+#include "tinsel/scroll.h" // For DontScrollCursor()
+#include "tinsel/timers.h" // DwGetCurrentTime()
+#include "tinsel/tinlib.h" // For control()
+#include "tinsel/token.h"
+
+namespace Tinsel {
+
+//----------------- EXTERNAL FUNCTIONS ---------------------
+
+// in PDISPLAY.C
+extern int GetTaggedActor(void);
+extern HPOLYGON GetTaggedPoly(void);
+
+
+//----------------- EXTERNAL GLOBAL DATA ---------------------
+
+extern bool bEnableF1;
+
+
+//----------------- LOCAL GLOBAL DATA --------------------
+
+static int userEvents = 0; // Whenever a button or a key comes in
+static uint32 lastUserEvent = 0; // Time it hapenned
+static int butEvents = 0; // Single or double, left or right. Or escape key.
+static int escEvents = 0; // Escape key
+
+
+static int eCount = 0;
+
+/**
+ * Gets called before each schedule, only 1 user action per schedule
+ * is allowed.
+ */
+void ResetEcount(void) {
+ eCount = 0;
+}
+
+
+void IncUserEvents(void) {
+ userEvents++;
+ lastUserEvent = DwGetCurrentTime();
+}
+
+/**
+ * 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, BUTEVENT be) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+ if (be == BE_SLEFT) {
+ GetToken(TOKEN_LEFT_BUT);
+ CORO_SLEEP(dclickSpeed+1);
+ FreeToken(TOKEN_LEFT_BUT);
+
+ // Prevent activation of 2 events on the same tick
+ if (++eCount != 1)
+ CORO_KILL_SELF();
+
+ break;
+
+ } else if (be == BE_DLEFT) {
+ GetToken(TOKEN_LEFT_BUT);
+ FreeToken(TOKEN_LEFT_BUT);
+ }
+ CORO_END_CODE;
+}
+
+/**
+ * Take control from player, if the player has it.
+ * Return TRUE if control taken, FALSE if not.
+ */
+
+bool GetControl(int param) {
+ if (TestToken(TOKEN_CONTROL)) {
+ control(param);
+ return true;
+ } else
+ return false;
+}
+
+struct TP_INIT {
+ HPOLYGON hPoly; // Polygon
+ USER_EVENT event; // Trigerring event
+ BUTEVENT bev; // To allow for double clicks
+ bool take_control; // Set if control should be taken
+ // while code is running.
+ int actor;
+};
+
+/**
+ * Runs glitter code associated with a polygon.
+ */
+static void PolyTinselProcess(CORO_PARAM) {
+ // COROUTINE
+ CORO_BEGIN_CONTEXT;
+ PINT_CONTEXT pic;
+ bool took_control; // Set if this function takes control
+ CORO_END_CONTEXT(_ctx);
+
+ TP_INIT *to = (TP_INIT *)ProcessGetParamsSelf(); // get the stuff copied to process when it was created
+
+ CORO_BEGIN_CODE(_ctx);
+
+ CORO_INVOKE_1(AllowDclick, to->bev); // May kill us if single click
+
+ // Control may have gone off during AllowDclick()
+ if (!TestToken(TOKEN_CONTROL)
+ && (to->event == WALKTO || to->event == ACTION || to->event == LOOK))
+ CORO_KILL_SELF();
+
+ // Take control, if requested
+ if (to->take_control)
+ _ctx->took_control = GetControl(CONTROL_OFF);
+ else
+ _ctx->took_control = false;
+
+ // Hide conversation if appropriate
+ if (to->event == CONVERSE)
+ convHide(true);
+
+ // Run the code
+ _ctx->pic = InitInterpretContext(GS_POLYGON, getPolyScript(to->hPoly), to->event, to->hPoly, to->actor, NULL);
+ CORO_INVOKE_1(Interpret, _ctx->pic);
+
+ // Free control if we took it
+ if (_ctx->took_control)
+ control(CONTROL_ON);
+
+ // Restore conv window if applicable
+ if (to->event == CONVERSE)
+ convHide(false);
+
+ CORO_END_CODE;
+}
+
+/**
+ * Runs glitter code associated with a polygon.
+ */
+void RunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, BUTEVENT be, bool tc) {
+ TP_INIT to = { hPoly, event, be, tc, 0 };
+
+ CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
+}
+
+void effRunPolyTinselCode(HPOLYGON hPoly, USER_EVENT event, int actor) {
+ TP_INIT to = { hPoly, event, BE_NONE, false, actor };
+
+ CoroutineInstall(PID_TCODE, PolyTinselProcess, &to, sizeof(to));
+}
+
+//-----------------------------------------------------------------------
+
+struct WP_INIT {
+ int x; // } Where to walk to
+ int y; // }
+};
+
+/**
+ * Perform a walk directly initiated by a click.
+ */
+static void WalkProcess(CORO_PARAM) {
+ // COROUTINE
+ CORO_BEGIN_CONTEXT;
+ PMACTOR pActor;
+ CORO_END_CONTEXT(_ctx);
+
+ WP_INIT *to = (WP_INIT *)ProcessGetParamsSelf(); // get the co-ordinates - copied to process when it was created
+
+ CORO_BEGIN_CODE(_ctx);
+
+ _ctx->pActor = GetMover(LEAD_ACTOR);
+ if (_ctx->pActor->MActorState == NORM_MACTOR) {
+ assert(_ctx->pActor->hCpath != NOPOLY); // Lead actor is not in a path
+
+ GetToken(TOKEN_LEAD);
+ SetActorDest(_ctx->pActor, to->x, to->y, false, 0);
+ DontScrollCursor();
+
+ while (MAmoving(_ctx->pActor))
+ CORO_SLEEP(1);
+
+ FreeToken(TOKEN_LEAD);
+ }
+
+ CORO_END_CODE;
+}
+
+void walkto(int x, int y) {
+ WP_INIT to = { x, y };
+
+ CoroutineInstall(PID_TCODE, WalkProcess, &to, sizeof(to));
+}
+
+/**
+ * Run appropriate actor or polygon glitter code.
+ * If none, and it's a WALKTO event, do a walk.
+ */
+static void User_Event(USER_EVENT uEvent, BUTEVENT be) {
+ int actor;
+ int aniX, aniY;
+ HPOLYGON hPoly;
+
+ // Prevent activation of 2 events on the same tick
+ if (++eCount != 1)
+ return;
+
+ if ((actor = GetTaggedActor()) != 0)
+ actorEvent(actor, uEvent, be);
+ else if ((hPoly = GetTaggedPoly()) != NOPOLY)
+ RunPolyTinselCode(hPoly, uEvent, be, false);
+ else {
+ GetCursorXY(&aniX, &aniY, true);
+
+ // There could be a poly involved which has no tag.
+ if ((hPoly = InPolygon(aniX, aniY, TAG)) != NOPOLY
+ || (hPoly = InPolygon(aniX, aniY, EXIT)) != NOPOLY) {
+ RunPolyTinselCode(hPoly, uEvent, be, false);
+ } else if (uEvent == WALKTO)
+ walkto(aniX, aniY);
+ }
+}
+
+
+/**
+ * ProcessButEvent
+ */
+void ProcessButEvent(BUTEVENT be) {
+ IncUserEvents();
+
+ if (bSwapButtons) {
+ switch (be) {
+ case BE_SLEFT:
+ be = BE_SRIGHT;
+ break;
+ case BE_DLEFT:
+ be = BE_DRIGHT;
+ break;
+ case BE_SRIGHT:
+ be = BE_SLEFT;
+ break;
+ case BE_DRIGHT:
+ be = BE_DLEFT;
+ break;
+ case BE_LDSTART:
+ be = BE_RDSTART;
+ break;
+ case BE_LDEND:
+ be = BE_RDEND;
+ break;
+ case BE_RDSTART:
+ be = BE_LDSTART;
+ break;
+ case BE_RDEND:
+ be = BE_LDEND;
+ break;
+ default:
+ break;
+ }
+ }
+
+// if (be == BE_SLEFT || be == BE_DLEFT || be == BE_SRIGHT || be == BE_DRIGHT)
+ if (be == BE_SLEFT || be == BE_SRIGHT)
+ butEvents++;
+
+ if (!TestToken(TOKEN_CONTROL) && be != BE_LDEND)
+ return;
+
+ if (InventoryActive()) {
+ ButtonToInventory(be);
+ } else {
+ switch (be) {
+ case BE_SLEFT:
+ User_Event(WALKTO, BE_SLEFT);
+ break;
+
+ case BE_DLEFT:
+ User_Event(ACTION, BE_DLEFT);
+ break;
+
+ case BE_SRIGHT:
+ User_Event(LOOK, BE_SRIGHT);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * ProcessKeyEvent
+ */
+
+void ProcessKeyEvent(KEYEVENT ke) {
+ // This stuff to allow F1 key during startup.
+ if (bEnableF1 && ke == OPTION_KEY)
+ control(CONTROL_ON);
+ else
+ IncUserEvents();
+
+ if (ke == ESC_KEY) {
+ escEvents++;
+ butEvents++; // Yes, I do mean this
+ }
+
+ // FIXME: This comparison is weird - I added (BUTEVENT) cast for now to suppress warning
+ if (!TestToken(TOKEN_CONTROL) && (BUTEVENT)ke != BE_LDEND)
+ return;
+
+ switch (ke) {
+ case QUIT_KEY:
+ PopUpConf(QUIT);
+ break;
+
+ case OPTION_KEY:
+ PopUpConf(OPTION);
+ break;
+
+ case SAVE_KEY:
+ PopUpConf(SAVE);
+ break;
+
+ case LOAD_KEY:
+ PopUpConf(LOAD);
+ break;
+
+ case WALKTO_KEY:
+ if (InventoryActive())
+ ButtonToInventory(BE_SLEFT);
+ else
+ User_Event(WALKTO, BE_NONE);
+ break;
+
+ case ACTION_KEY:
+ if (InventoryActive())
+ ButtonToInventory(BE_DLEFT);
+ else
+ User_Event(ACTION, BE_NONE);
+ break;
+
+ case LOOK_KEY:
+ if (InventoryActive())
+ ButtonToInventory(BE_SRIGHT);
+ else
+ User_Event(LOOK, BE_NONE);
+ break;
+
+ case ESC_KEY:
+ case PGUP_KEY:
+ case PGDN_KEY:
+ case HOME_KEY:
+ case END_KEY:
+ if (InventoryActive())
+ KeyToInventory(ke);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * For ESCapable Glitter sequences
+ */
+
+int GetEscEvents(void) {
+ return escEvents;
+}
+
+/**
+ * For cutting short talk()s etc.
+ */
+
+int GetLeftEvents(void) {
+ return butEvents;
+}
+
+/**
+ * For waitkey() Glitter function
+ */
+
+int getUserEvents(void) {
+ return userEvents;
+}
+
+uint32 getUserEventTime(void) {
+ return DwGetCurrentTime() - lastUserEvent;
+}
+
+void resetUserEventTime(void) {
+ lastUserEvent = DwGetCurrentTime();
+}
+
+} // end of namespace Tinsel