[Scummvm-cvs-logs] SF.net SVN: scummvm:[35196] scummvm/trunk/engines/tinsel
thebluegr at users.sourceforge.net
thebluegr at users.sourceforge.net
Mon Dec 1 21:35:37 CET 2008
Revision: 35196
http://scummvm.svn.sourceforge.net/scummvm/?rev=35196&view=rev
Author: thebluegr
Date: 2008-12-01 20:35:36 +0000 (Mon, 01 Dec 2008)
Log Message:
-----------
Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable
Modified Paths:
--------------
scummvm/trunk/engines/tinsel/actors.cpp
scummvm/trunk/engines/tinsel/actors.h
scummvm/trunk/engines/tinsel/anim.cpp
scummvm/trunk/engines/tinsel/anim.h
scummvm/trunk/engines/tinsel/background.cpp
scummvm/trunk/engines/tinsel/background.h
scummvm/trunk/engines/tinsel/bg.cpp
scummvm/trunk/engines/tinsel/config.cpp
scummvm/trunk/engines/tinsel/config.h
scummvm/trunk/engines/tinsel/coroutine.h
scummvm/trunk/engines/tinsel/cursor.cpp
scummvm/trunk/engines/tinsel/cursor.h
scummvm/trunk/engines/tinsel/debugger.cpp
scummvm/trunk/engines/tinsel/detection.cpp
scummvm/trunk/engines/tinsel/dw.h
scummvm/trunk/engines/tinsel/effect.cpp
scummvm/trunk/engines/tinsel/events.cpp
scummvm/trunk/engines/tinsel/events.h
scummvm/trunk/engines/tinsel/faders.cpp
scummvm/trunk/engines/tinsel/faders.h
scummvm/trunk/engines/tinsel/font.cpp
scummvm/trunk/engines/tinsel/font.h
scummvm/trunk/engines/tinsel/graphics.cpp
scummvm/trunk/engines/tinsel/graphics.h
scummvm/trunk/engines/tinsel/handle.cpp
scummvm/trunk/engines/tinsel/handle.h
scummvm/trunk/engines/tinsel/heapmem.cpp
scummvm/trunk/engines/tinsel/mareels.cpp
scummvm/trunk/engines/tinsel/module.mk
scummvm/trunk/engines/tinsel/move.cpp
scummvm/trunk/engines/tinsel/move.h
scummvm/trunk/engines/tinsel/multiobj.cpp
scummvm/trunk/engines/tinsel/multiobj.h
scummvm/trunk/engines/tinsel/music.cpp
scummvm/trunk/engines/tinsel/music.h
scummvm/trunk/engines/tinsel/object.cpp
scummvm/trunk/engines/tinsel/object.h
scummvm/trunk/engines/tinsel/palette.cpp
scummvm/trunk/engines/tinsel/palette.h
scummvm/trunk/engines/tinsel/pcode.cpp
scummvm/trunk/engines/tinsel/pcode.h
scummvm/trunk/engines/tinsel/pdisplay.cpp
scummvm/trunk/engines/tinsel/pid.h
scummvm/trunk/engines/tinsel/play.cpp
scummvm/trunk/engines/tinsel/polygons.cpp
scummvm/trunk/engines/tinsel/polygons.h
scummvm/trunk/engines/tinsel/rince.cpp
scummvm/trunk/engines/tinsel/rince.h
scummvm/trunk/engines/tinsel/saveload.cpp
scummvm/trunk/engines/tinsel/savescn.cpp
scummvm/trunk/engines/tinsel/savescn.h
scummvm/trunk/engines/tinsel/scene.cpp
scummvm/trunk/engines/tinsel/scene.h
scummvm/trunk/engines/tinsel/sched.cpp
scummvm/trunk/engines/tinsel/sched.h
scummvm/trunk/engines/tinsel/scn.cpp
scummvm/trunk/engines/tinsel/scn.h
scummvm/trunk/engines/tinsel/scroll.cpp
scummvm/trunk/engines/tinsel/scroll.h
scummvm/trunk/engines/tinsel/sound.cpp
scummvm/trunk/engines/tinsel/sound.h
scummvm/trunk/engines/tinsel/strres.cpp
scummvm/trunk/engines/tinsel/strres.h
scummvm/trunk/engines/tinsel/text.cpp
scummvm/trunk/engines/tinsel/text.h
scummvm/trunk/engines/tinsel/timers.cpp
scummvm/trunk/engines/tinsel/timers.h
scummvm/trunk/engines/tinsel/tinlib.cpp
scummvm/trunk/engines/tinsel/tinlib.h
scummvm/trunk/engines/tinsel/tinsel.cpp
scummvm/trunk/engines/tinsel/tinsel.h
Added Paths:
-----------
scummvm/trunk/engines/tinsel/bmv.cpp
scummvm/trunk/engines/tinsel/dialogs.cpp
scummvm/trunk/engines/tinsel/dialogs.h
scummvm/trunk/engines/tinsel/drives.cpp
scummvm/trunk/engines/tinsel/drives.h
scummvm/trunk/engines/tinsel/mareels.h
scummvm/trunk/engines/tinsel/pdisplay.h
scummvm/trunk/engines/tinsel/play.h
scummvm/trunk/engines/tinsel/sysvar.cpp
scummvm/trunk/engines/tinsel/sysvar.h
Removed Paths:
-------------
scummvm/trunk/engines/tinsel/inventory.cpp
scummvm/trunk/engines/tinsel/inventory.h
Modified: scummvm/trunk/engines/tinsel/actors.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/actors.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/actors.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -25,19 +25,23 @@
*/
#include "tinsel/actors.h"
+#include "tinsel/background.h"
#include "tinsel/events.h"
#include "tinsel/film.h" // for FREEL
#include "tinsel/handle.h"
-#include "tinsel/inventory.h" // INV_NOICON
+#include "tinsel/dialogs.h" // INV_NOICON
#include "tinsel/move.h"
#include "tinsel/multiobj.h"
#include "tinsel/object.h" // for POBJECT
#include "tinsel/pcode.h"
#include "tinsel/pid.h"
+#include "tinsel/play.h"
#include "tinsel/polygons.h"
#include "tinsel/rince.h"
#include "tinsel/sched.h"
#include "tinsel/serializer.h"
+#include "tinsel/sysvar.h"
+#include "tinsel/tinsel.h"
#include "tinsel/token.h"
#include "common/util.h"
@@ -51,25 +55,37 @@
#include "common/pack-start.h" // START STRUCT PACKING
/** actor struct - one per actor */
-struct ACTOR_STRUC {
+struct T1_ACTOR_STRUC {
int32 masking; //!< type of actor masking
SCNHANDLE hActorId; //!< handle actor ID string index
SCNHANDLE hActorCode; //!< handle to actor script
} PACKED_STRUCT;
+struct T2_ACTOR_STRUC {
+ SCNHANDLE hActorId; // handle actor ID string index
+ SCNHANDLE hTagText; // tag
+ int32 tagPortionV; // defines tag area
+ int32 tagPortionH; // defines tag area
+ SCNHANDLE hActorCode; // handle to actor script
+} PACKED_STRUCT;
+
#include "common/pack-end.h" // END STRUCT PACKING
+//----------------- LOCAL MACROS ----------------------------
+#define RANGE_CHECK(num) assert(num > 0 && num <= NumActors);
//----------------- LOCAL GLOBAL DATA --------------------
+#define MAX_REELS 6
+
static int LeadActorId = 0; // The lead actor
static int NumActors = 0; // The total number of actors in the game
struct ACTORINFO {
- bool alive; // TRUE == alive
- bool hidden; // TRUE == hidden
+ bool bAlive; // TRUE == alive
+ bool bHidden; // TRUE == hidden
bool completed; // TRUE == script played out
int x, y, z;
@@ -81,34 +97,65 @@
int presRnum; // the present reel number
SCNHANDLE presFilm; // the film that reel belongs to
OBJECT *presObj; // reference for position information
- int presX, presY;
+ int presPlayX, presPlayY;
bool tagged; // actor tagged?
SCNHANDLE hTag; // handle to tag text
int tType; // e.g. TAG_Q1TO3
- bool escOn;
- int escEv;
+ bool bEscOn;
+ int escEvent;
- COLORREF tColour; // Text colour
+ COLORREF textColour; // Text colour
SCNHANDLE playFilm; // revert to this after talks
SCNHANDLE talkFilm; // this be deleted in the future!
SCNHANDLE latestFilm; // the last film ordered
- bool talking;
+ bool bTalking;
int steps;
+ int loopCount;
+ // DW2 new fields and alternates
+ int presColumns[MAX_REELS]; // the present columns
+ OBJECT *presObjs[MAX_REELS]; // reference for position information
+ int filmNum;
};
-static ACTORINFO *actorInfo = 0;
+struct TAGACTOR {
+ // Copies of compiled data
+ int id;
+ SCNHANDLE hTagText; // handle to tag text
+ int32 tagPortionV; // which portion is active
+ int32 tagPortionH; // which portion is active
+ SCNHANDLE hActorCode; // The actor's script
+ int tagFlags;
+ SCNHANDLE hOverrideTag; // Override tag.
+};
+typedef TAGACTOR *PTAGACTOR;
+
+
+static ACTORINFO *actorInfo = NULL;
+
static COLORREF defaultColour = 0; // Text colour
static bool bActorsOn = false;
static int ti = 0;
+#define MAX_TAGACTORS 10
+
+static TAGACTOR taggedActors[MAX_TAGACTORS];
+
+static int numTaggedActors = 0;
+
+static uint8 *zFactors = NULL;
+
+static Z_POSITIONS zPositions[NUM_ZPOSITIONS];
+
+//-------------------- METHOD LIST -----------------------
+
/**
* Called once at start-up time, and again at restart time.
* Registers the total number of actors in the game.
@@ -122,10 +169,13 @@
// Check we can save so many
assert(NumActors <= MAX_SAVED_ALIVES);
- // Allocate RAM for actorInfo
+ // Allocate RAM for actor structures
+
// FIXME: For now, we always allocate MAX_SAVED_ALIVES blocks,
// as this makes the save/load code simpler
actorInfo = (ACTORINFO *)calloc(MAX_SAVED_ALIVES, sizeof(ACTORINFO));
+ if (TinselV2)
+ zFactors = (uint8 *)malloc(MAX_SAVED_ALIVES);
// make sure memory allocated
if (actorInfo == NULL) {
@@ -136,11 +186,13 @@
assert(num == NumActors);
memset(actorInfo, 0, MAX_SAVED_ALIVES * sizeof(ACTORINFO));
+ if (TinselV2)
+ memset(zFactors, 0, MAX_SAVED_ALIVES);
}
// All actors start off alive.
while (num--)
- actorInfo[num].alive = true;
+ actorInfo[num].bAlive = true;
}
void FreeActors() {
@@ -154,7 +206,7 @@
* Called from dec_lead(), i.e. normally once at start of master script.
* @param leadID Lead Id
*/
-void setleadid(int leadID) {
+void SetLeadId(int leadID) {
LeadActorId = leadID;
actorInfo[leadID-1].mtype = ACT_MASK;
}
@@ -162,41 +214,84 @@
/**
* No comment.
*/
-int LeadId(void) {
+int GetLeadId(void) {
return LeadActorId;
}
+bool ActorIsGhost(int actor) {
+ return actor == SysVar(ISV_GHOST_ACTOR);
+}
+
struct ATP_INIT {
int id; // Actor number
- USER_EVENT event; // Event
- BUTEVENT bev; // Causal mouse event
+ TINSEL_EVENT event; // Event
+ PLR_EVENT bev; // Causal mouse event
+
+ PINT_CONTEXT pic;
};
/**
+ * Convert actor id to index into TaggedActors[]
+ */
+static int TaggedActorIndex(int actor) {
+ int i;
+
+ for (i = 0; i < numTaggedActors; i++) {
+ if (taggedActors[i].id == actor)
+ return i;
+ }
+
+ error("You may say to yourself \"this is not my tagged actor\"");
+}
+
+/**
* Runs actor's glitter code.
*/
static void ActorTinselProcess(CORO_PARAM, const void *param) {
// COROUTINE
CORO_BEGIN_CONTEXT;
INT_CONTEXT *pic;
+ bool bTookControl;
CORO_END_CONTEXT(_ctx);
// get the stuff copied to process when it was created
- ATP_INIT *atp = (ATP_INIT *)param;
+ const ATP_INIT *atp = (const ATP_INIT *)param;
CORO_BEGIN_CODE(_ctx);
- CORO_INVOKE_1(AllowDclick, atp->bev); // May kill us if single click
+ if (TinselV2) {
+ // Take control for CONVERSE events
+ if (atp->event == CONVERSE) {
+ _ctx->bTookControl = GetControl();
+ HideConversation(true);
+ } else
+ _ctx->bTookControl = false;
- // Run the Glitter code
- assert(actorInfo[atp->id - 1].actorCode); // no code to run
+ // Run the Glitter code
+ CORO_INVOKE_1(Interpret, atp->pic);
- _ctx->pic = InitInterpretContext(GS_ACTOR, actorInfo[atp->id - 1].actorCode, atp->event, NOPOLY, atp->id, NULL);
- CORO_INVOKE_1(Interpret, _ctx->pic);
+ // Restore conv window if applicable
+ if (atp->event == CONVERSE) {
+ // Free control if we took it
+ if (_ctx->bTookControl)
+ ControlOn();
- // If it gets here, actor's code has run to completion
- actorInfo[atp->id - 1].completed = true;
+ HideConversation(false);
+ }
+ } else {
+ CORO_INVOKE_1(AllowDclick, atp->bev); // May kill us if single click
+ // Run the Glitter code
+ assert(actorInfo[atp->id - 1].actorCode); // no code to run
+
+ _ctx->pic = InitInterpretContext(GS_ACTOR, actorInfo[atp->id - 1].actorCode,
+ atp->event, NOPOLY, atp->id, NULL);
+ CORO_INVOKE_1(Interpret, _ctx->pic);
+
+ // If it gets here, actor's code has run to completion
+ actorInfo[atp->id - 1].completed = true;
+ }
+
CORO_END_CODE;
}
@@ -215,7 +310,7 @@
CORO_END_CONTEXT(_ctx);
// get the stuff copied to process when it was created
- RATP_INIT *r = (RATP_INIT *)param;
+ const RATP_INIT *r = (const RATP_INIT *)param;
CORO_BEGIN_CODE(_ctx);
@@ -240,7 +335,7 @@
* @param event Event structure
* @param be ButEvent
*/
-void actorEvent(int ano, USER_EVENT event, BUTEVENT be) {
+void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be) {
ATP_INIT atp;
// Only if there is Glitter code associated with this actor.
@@ -248,20 +343,59 @@
atp.id = ano;
atp.event = event;
atp.bev = be;
+ atp.pic = NULL;
g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
}
}
/**
+ * Starts up process to run actor's glitter code.
+ */
+void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEscape, bool *result) {
+ ATP_INIT atp;
+ int index;
+ CORO_BEGIN_CONTEXT;
+ PPROCESS pProc;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ index = TaggedActorIndex(ano);
+ assert(taggedActors[index].hActorCode);
+ if (result) *result = false;
+
+ atp.id = 0;
+ atp.event = tEvent;
+ atp.pic = InitInterpretContext(GS_ACTOR,
+ taggedActors[index].hActorCode,
+ tEvent,
+ NOPOLY, // No polygon
+ ano, // Actor
+ NULL, // No object
+ myEscape);
+
+ if (atp.pic != NULL) {
+ _ctx->pProc = g_scheduler->createProcess(PID_TCODE, ActorTinselProcess, &atp, sizeof(atp));
+ AttachInterpret(atp.pic, _ctx->pProc);
+
+ if (bWait)
+ CORO_INVOKE_2(WaitInterpret,_ctx->pProc, result);
+ }
+
+ CORO_END_CODE;
+}
+
+
+/**
* Called at the start of each scene for each actor with a code block.
* @param as Actor structure
* @param bRunScript Flag for whether to run actor's script for the scene
*/
-void StartActor(const ACTOR_STRUC *as, bool bRunScript) {
+void StartActor(const T1_ACTOR_STRUC *as, bool bRunScript) {
SCNHANDLE hActorId = FROM_LE_32(as->hActorId);
// Zero-out many things
- actorInfo[hActorId - 1].hidden = false;
+ actorInfo[hActorId - 1].bHidden = false;
actorInfo[hActorId - 1].completed = false;
actorInfo[hActorId - 1].x = 0;
actorInfo[hActorId - 1].y = 0;
@@ -276,10 +410,10 @@
// Run actor's script for this scene
if (bRunScript) {
if (bActorsOn)
- actorInfo[hActorId - 1].alive = true;
+ actorInfo[hActorId - 1].bAlive = true;
- if (actorInfo[hActorId - 1].alive && FROM_LE_32(as->hActorCode))
- actorEvent(hActorId, STARTUP, BE_NONE);
+ if (actorInfo[hActorId - 1].bAlive && FROM_LE_32(as->hActorCode))
+ ActorEvent(hActorId, STARTUP, PLR_NOEVENT);
}
}
@@ -289,18 +423,47 @@
* @param numActors Number of actors
* @param bRunScript Flag for whether to run actor scene scripts
*/
-void StartActors(SCNHANDLE ah, int numActors, bool bRunScript) {
+void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript) {
int i;
- // Only actors with code blocks got (x, y) re-initialised, so...
- for (i = 0; i < NumActors; i++) {
- actorInfo[i].x = actorInfo[i].y = 0;
- actorInfo[i].mtype = 0;
+ if (TinselV2) {
+ // Clear it all out for a fresh start
+ memset(taggedActors, 0, sizeof(taggedActors));
+ numTaggedActors = numActors;
+ } else {
+ // Only actors with code blocks got (x, y) re-initialised, so...
+ for (i = 0; i < NumActors; i++) {
+ actorInfo[i].x = actorInfo[i].y = 0;
+ actorInfo[i].mtype = 0;
+ }
}
- const ACTOR_STRUC *as = (const ACTOR_STRUC *)LockMem(ah);
- for (i = 0; i < numActors; i++, as++) {
- StartActor(as, bRunScript);
+ if (!TinselV2) {
+ // Tinsel 1 load variation
+ const T1_ACTOR_STRUC *as = (const T1_ACTOR_STRUC *)LockMem(ah);
+ for (i = 0; i < numActors; i++, as++) {
+ StartActor(as, bRunScript);
+ }
+ } else if (numActors > 0) {
+ // Tinsel 2 load variation
+ const T2_ACTOR_STRUC *as = (T2_ACTOR_STRUC *)LockMem(ah);
+ for (i = 0; i < numActors; i++, as++) {
+ assert(as->hActorCode);
+
+ // Store current scene's parameters for this tagged actor
+ taggedActors[i].id = FROM_LE_32(as->hActorId);
+ taggedActors[i].hTagText = FROM_LE_32(as->hTagText);
+ taggedActors[i].tagPortionV = FROM_LE_32(as->tagPortionV);
+ taggedActors[i].tagPortionH = FROM_LE_32(as->tagPortionH);
+ taggedActors[i].hActorCode = FROM_LE_32(as->hActorCode);
+
+ // Run actor's script for this scene
+ if (bRunScript) {
+ // Send in reverse order - they get swapped round in the scheduler
+ ActorEvent(nullContext, taggedActors[i].id, SHOWEVENT, false, 0);
+ ActorEvent(nullContext, taggedActors[i].id, STARTUP, false, 0);
+ }
+ }
}
}
@@ -308,18 +471,34 @@
* Called between scenes, zeroises all actors.
*/
void DropActors(void) {
+
for (int i = 0; i < NumActors; i++) {
- actorInfo[i].actorCode = 0; // No script
- actorInfo[i].presReel = NULL; // No reel running
- actorInfo[i].presFilm = 0; // ditto
- actorInfo[i].presObj = NULL; // No object
- actorInfo[i].x = 0; // No position
- actorInfo[i].y = 0; // ditto
+ if (TinselV2) {
+ // Save text colour
+ COLORREF tColour = actorInfo[i].textColour;
- actorInfo[i].talkFilm = 0;
- actorInfo[i].latestFilm = 0;
- actorInfo[i].playFilm = 0;
- actorInfo[i].talking = false;
+ memset(&actorInfo[i], 0, sizeof(ACTORINFO));
+
+ // Restor text colour
+ actorInfo[i].textColour = tColour;
+
+ // Clear extra arrays
+ memset(zFactors, 0, NumActors);
+ memset(zPositions, 0, sizeof(zPositions));
+ } else {
+ // In Tinsel v1, only certain fields get reset
+ actorInfo[i].actorCode = 0; // No script
+ actorInfo[i].presReel = NULL; // No reel running
+ actorInfo[i].presFilm = 0; // ditto
+ actorInfo[i].presObj = NULL; // No object
+ actorInfo[i].x = 0; // No position
+ actorInfo[i].y = 0; // ditto
+
+ actorInfo[i].talkFilm = 0;
+ actorInfo[i].latestFilm = 0;
+ actorInfo[i].playFilm = 0;
+ actorInfo[i].bTalking = false;
+ }
}
}
@@ -328,17 +507,17 @@
* @param ano Actor Id
*/
void DisableActor(int ano) {
- PMACTOR pActor;
+ PMOVER pActor;
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].alive = false; // Record as dead
+ actorInfo[ano - 1].bAlive = false; // Record as dead
actorInfo[ano - 1].x = actorInfo[ano - 1].y = 0;
// Kill off moving actor properly
pActor = GetMover(ano);
if (pActor)
- KillMActor(pActor);
+ KillMover(pActor);
}
/**
@@ -349,14 +528,14 @@
assert(ano > 0 && ano <= NumActors); // illegal actor number
// Re-incarnate only if it's dead, or it's script ran to completion
- if (!actorInfo[ano - 1].alive || actorInfo[ano - 1].completed) {
- actorInfo[ano - 1].alive = true;
- actorInfo[ano - 1].hidden = false;
+ if (!actorInfo[ano - 1].bAlive || actorInfo[ano - 1].completed) {
+ actorInfo[ano - 1].bAlive = true;
+ actorInfo[ano - 1].bHidden = false;
actorInfo[ano - 1].completed = false;
// Re-run actor's script for this scene
if (actorInfo[ano-1].actorCode)
- actorEvent(ano, STARTUP, BE_NONE);
+ ActorEvent(ano, STARTUP, PLR_NOEVENT);
}
}
@@ -367,7 +546,7 @@
bool actorAlive(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- return actorInfo[ano - 1].alive;
+ return actorInfo[ano - 1].bAlive;
}
/**
@@ -444,16 +623,16 @@
* or there are no more tagged actors to look at.
*/
int NextTaggedActor(void) {
- PMACTOR pActor;
+ PMOVER pActor;
bool hid;
do {
if (actorInfo[ti].tagged) {
pActor = GetMover(ti+1);
if (pActor)
- hid = getMActorHideState(pActor);
+ hid = MoverHidden(pActor);
else
- hid = actorInfo[ti].hidden;
+ hid = actorInfo[ti].bHidden;
if (!hid) {
return ++ti;
@@ -465,6 +644,41 @@
}
/**
+ * Called from TagProcess, NextTaggedActor() is
+ * called repeatedly until the caller gets fed up or
+ * there are no more tagged actors to look at.
+ */
+int NextTaggedActor(int previous) {
+ PMOVER pMover;
+
+ // Convert actor number to index
+ if (!previous)
+ previous = -1;
+ else
+ previous = TaggedActorIndex(previous);
+
+ while (++previous < numTaggedActors) {
+ pMover = GetMover(taggedActors[previous].id);
+
+ // No tag on lead actor while he's moving
+ if ((taggedActors[previous].id) == GetLeadId() && MoverMoving(pMover)) {
+ taggedActors[previous].tagFlags &= ~(POINTING | TAGWANTED);
+ continue;
+ }
+
+ // Not if the actor doesn't exist at the moment
+ if (pMover && !MoverIs(pMover))
+ continue;
+
+ if (!(pMover ? MoverHidden(pMover) : ActorHidden(taggedActors[previous].id))) {
+ return taggedActors[previous].id;
+ }
+ }
+
+ return 0;
+}
+
+/**
* Returns the masking type of the actor.
* @param ano Actor Id
*/
@@ -481,41 +695,88 @@
* @param x X position
* @param y Y position
*/
-void storeActorPos(int ano, int x, int y) {
+void StoreActorPos(int ano, int x, int y) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
actorInfo[ano - 1].x = x;
actorInfo[ano - 1].y = y;
}
-void storeActorSteps(int ano, int steps) {
+void StoreActorSteps(int ano, int steps) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
actorInfo[ano - 1].steps = steps;
}
-int getActorSteps(int ano) {
+int GetActorSteps(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
return actorInfo[ano - 1].steps;
}
-void storeActorZpos(int ano, int z) {
+void StoreActorZpos(int ano, int z, int column) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].z = z;
+ if (!TinselV2) {
+ // Prior to Tinsel 2, only a single z value was stored
+ actorInfo[ano - 1].z = z;
+ } else {
+ // Alter existing entry, if there is one
+ for (int i = 0; i < NUM_ZPOSITIONS; i++) {
+ if (zPositions[i].actor == ano && zPositions[i].column == column) {
+ zPositions[i].z = z;
+ return;
+ }
+ }
+
+ // No existing entry found, so find an empty slot
+ for (int i = 0; i < NUM_ZPOSITIONS; i++) {
+ if (zPositions[i].actor == 0) {
+ zPositions[i].actor = (short)ano;
+ zPositions[i].column = (short)column;
+ zPositions[i].z = z;
+ return;
+ }
+ }
+
+ error("NUM_ZPOSITIONS exceeded");
+ }
}
+int GetActorZpos(int ano, int column) {
+ RANGE_CHECK(ano);
+ // Find entry, there should be one
+ for (int i = 0; i < NUM_ZPOSITIONS; i++) {
+ if (zPositions[i].actor == ano && zPositions[i].column == column) {
+ return zPositions[i].z;
+ }
+ }
+
+ return 1000; // Nominal value
+}
+
+void IncLoopCount(int ano) {
+ RANGE_CHECK(ano);
+
+ actorInfo[ano - 1].loopCount++;
+}
+
+int GetLoopCount(int ano) {
+ RANGE_CHECK(ano);
+
+ return actorInfo[ano - 1].loopCount;
+}
+
void GetActorPos(int ano, int *x, int *y) {
- PMACTOR pActor;
+ PMOVER pActor;
assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // unknown actor
pActor = GetMover(ano);
if (pActor)
- GetMActorPosition(pActor, x, y);
+ GetMoverPosition(pActor, x, y);
else {
*x = actorInfo[ano - 1].x;
*y = actorInfo[ano - 1].y;
@@ -531,15 +792,18 @@
*/
void GetActorMidTop(int ano, int *x, int *y) {
// Not used in JAPAN version
- PMACTOR pActor;
+ PMOVER pActor;
assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // unknown actor
pActor = GetMover(ano);
if (pActor)
- GetMActorMidTopPosition(pActor, x, y);
- else if (actorInfo[ano - 1].presObj) {
+ GetMoverMidTop(pActor, x, y);
+ else if (TinselV2) {
+ *x = (GetActorLeft(ano) + GetActorRight(ano)) / 2;
+ *y = GetActorTop(ano);
+ } else if (actorInfo[ano - 1].presObj) {
*x = (MultiLeftmost(actorInfo[ano - 1].presObj)
+ MultiRightmost(actorInfo[ano - 1].presObj)) / 2;
*y = MultiHighest(actorInfo[ano - 1].presObj);
@@ -554,10 +818,39 @@
int GetActorLeft(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- if (!actorInfo[ano - 1].presObj)
- return 0;
+ if (!TinselV2) {
+ // Tinsel 1 version
+ if (!actorInfo[ano - 1].presObj)
+ return 0;
- return MultiLeftmost(actorInfo[ano - 1].presObj);
+ return MultiLeftmost(actorInfo[ano - 1].presObj);
+ }
+
+ // Tinsel 2 version
+ PMOVER pMover = GetMover(ano);
+ int i;
+ bool bIsObj;
+ int left = 0;
+
+ if (pMover != NULL) {
+ return GetMoverLeft(pMover);
+ } else {
+ for (i = 0, bIsObj = false; i < MAX_REELS; i++) {
+ // If there's an object
+ // and it is not a blank frame for it...
+ if (actorInfo[ano-1].presObjs[i] && MultiHasShape(actorInfo[ano - 1].presObjs[i])) {
+ if (!bIsObj) {
+ bIsObj = true;
+ left = MultiLeftmost(actorInfo[ano - 1].presObjs[i]);
+ } else {
+ if (MultiLeftmost(actorInfo[ano - 1].presObjs[i]) < left)
+ left = MultiLeftmost(actorInfo[ano - 1].presObjs[i]);
+ }
+ }
+ }
+
+ return bIsObj ? left : 0;
+ }
}
/**
@@ -567,10 +860,38 @@
int GetActorRight(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- if (!actorInfo[ano - 1].presObj)
- return 0;
+ if (!TinselV2) {
+ // Tinsel 1 version
+ if (!actorInfo[ano - 1].presObj)
+ return 0;
- return MultiRightmost(actorInfo[ano - 1].presObj);
+ return MultiRightmost(actorInfo[ano - 1].presObj);
+ }
+
+ // Tinsel 2 version
+ PMOVER pMover = GetMover(ano);
+ int i;
+ bool bIsObj;
+ int right = 0;
+
+ if (pMover != NULL) {
+ return GetMoverRight(pMover);
+ } else {
+ for (i = 0, bIsObj = false; i < MAX_REELS; i++) {
+ // If there's an object
+ // and it is not a blank frame for it...
+ if (actorInfo[ano-1].presObjs[i] && MultiHasShape(actorInfo[ano-1].presObjs[i])) {
+ if (!bIsObj) {
+ bIsObj = true;
+ right = MultiRightmost(actorInfo[ano-1].presObjs[i]);
+ } else {
+ if (MultiRightmost(actorInfo[ano-1].presObjs[i]) > right)
+ right = MultiRightmost(actorInfo[ano-1].presObjs[i]);
+ }
+ }
+ }
+ return bIsObj ? right : 0;
+ }
}
/**
@@ -580,10 +901,39 @@
int GetActorTop(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- if (!actorInfo[ano - 1].presObj)
- return 0;
+ if (!TinselV2) {
+ // Tinsel 1 version
+ if (!actorInfo[ano - 1].presObj)
+ return 0;
- return MultiHighest(actorInfo[ano - 1].presObj);
+ return MultiHighest(actorInfo[ano - 1].presObj);
+ }
+
+ // Tinsel 2 version
+ PMOVER pMover = GetMover(ano);
+ int i;
+ bool bIsObj;
+ int top = 0;
+
+ if (pMover != NULL) {
+ return GetMoverTop(pMover);
+ } else {
+ for (i = 0, bIsObj = false; i < MAX_REELS; i++) {
+ // If there's an object
+ // and it is not a blank frame for it...
+ if (actorInfo[ano-1].presObjs[i] && MultiHasShape(actorInfo[ano-1].presObjs[i])) {
+ if (!bIsObj) {
+ bIsObj = true;
+ top = MultiHighest(actorInfo[ano-1].presObjs[i]);
+ } else {
+ if (MultiHighest(actorInfo[ano-1].presObjs[i]) < top)
+ top = MultiHighest(actorInfo[ano-1].presObjs[i]);
+ }
+ }
+ }
+
+ return bIsObj ? top : 0;
+ }
}
/**
@@ -592,38 +942,122 @@
int GetActorBottom(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- if (!actorInfo[ano - 1].presObj)
- return 0;
+ if (!TinselV2) {
+ // Tinsel 1 version
+ if (!actorInfo[ano - 1].presObj)
+ return 0;
- return MultiLowest(actorInfo[ano - 1].presObj);
+ return MultiLowest(actorInfo[ano - 1].presObj);
+ }
+
+ // Tinsel 2 version
+ PMOVER pMover = GetMover(ano);
+ int i;
+ bool bIsObj;
+ int bottom = 0;
+
+ if (pMover != NULL) {
+ return GetMoverBottom(pMover);
+ } else {
+ for (i = 0, bIsObj = false; i < MAX_REELS; i++) {
+ // If there's an object
+ // and it is not a blank frame for it...
+ if (actorInfo[ano-1].presObjs[i] && MultiHasShape(actorInfo[ano-1].presObjs[i])) {
+ if (!bIsObj) {
+ bIsObj = true;
+ bottom = MultiLowest(actorInfo[ano-1].presObjs[i]);
+ } else {
+ if (MultiLowest(actorInfo[ano-1].presObjs[i]) > bottom)
+ bottom = MultiLowest(actorInfo[ano-1].presObjs[i]);
+ }
+ }
+ }
+ return bIsObj ? bottom : 0;
+ }
}
/**
+ * Shows the given actor
+ */
+void ShowActor(CORO_PARAM, int ano) {
+ PMOVER pMover;
+ RANGE_CHECK(ano);
+
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ // reset hidden flag
+ actorInfo[ano - 1].bHidden = false;
+
+ // Send event to tagged actors
+ if (IsTaggedActor(ano))
+ CORO_INVOKE_ARGS(ActorEvent, (CORO_SUBCTX, ano, SHOWEVENT, true, 0));
+
+ // If moving actor involved, un-hide it
+ pMover = GetMover(ano);
+ if (pMover)
+ UnHideMover(pMover);
+
+ CORO_END_CODE;
+}
+
+/**
* Set actor hidden status to true.
* For a moving actor, actually hide it.
* @param ano Actor Id
*/
-void HideActor(int ano) {
- PMACTOR pActor;
-
+void HideActor(CORO_PARAM, int ano) {
+ PMOVER pMover;
assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ if (TinselV2) {
+ actorInfo[ano - 1].bHidden = true;
+
+ // Send event to tagged actors
+ // (this is duplicated in HideMover())
+ if (IsTaggedActor(ano)) {
+ CORO_INVOKE_ARGS(ActorEvent, (CORO_SUBCTX, ano, HIDEEVENT, true, 0));
+
+ // It may be pointed to
+ SetActorPointedTo(ano, false);
+ SetActorTagWanted(ano, false, false, 0);
+ }
+ }
+
// Get moving actor involved
- pActor = GetMover(ano);
+ pMover = GetMover(ano);
- if (pActor)
- hideMActor(pActor, 0);
- else
- actorInfo[ano - 1].hidden = true;
+ if (pMover)
+ HideMover(pMover, 0);
+ else if (!TinselV2)
+ actorInfo[ano - 1].bHidden = true;
+
+ CORO_END_CODE;
}
/**
+ * Return actor hidden status.
+ */
+bool ActorHidden(int ano) {
+ RANGE_CHECK(ano);
+
+ return actorInfo[ano - 1].bHidden;
+}
+
+/**
* Hide an actor if it's a moving actor.
* @param ano Actor Id
* @param sf sf
*/
bool HideMovingActor(int ano, int sf) {
- PMACTOR pActor;
+ PMOVER pActor;
assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor
@@ -631,7 +1065,7 @@
pActor = GetMover(ano);
if (pActor) {
- hideMActor(pActor, sf);
+ HideMover(pActor, sf);
return true;
} else {
if (actorInfo[ano - 1].presObj != NULL)
@@ -645,7 +1079,7 @@
* @param ano Actor Id
*/
void unHideMovingActor(int ano) {
- PMACTOR pActor;
+ PMOVER pActor;
assert((ano > 0 && ano <= NumActors) || ano == LEAD_ACTOR); // illegal actor
@@ -654,7 +1088,7 @@
assert(pActor); // not a moving actor
- unhideMActor(pActor);
+ UnHideMover(pActor);
}
/**
@@ -663,7 +1097,7 @@
* actor's walk (if any) from the new co-ordinates.
*/
void restoreMovement(int ano) {
- PMACTOR pActor;
+ PMOVER pActor;
assert(ano > 0 && ano <= NumActors); // illegal actor number
@@ -672,11 +1106,11 @@
assert(pActor); // not a moving actor
- if (pActor->objx == actorInfo[ano - 1].x && pActor->objy == actorInfo[ano - 1].y)
+ if (pActor->objX == actorInfo[ano - 1].x && pActor->objY == actorInfo[ano - 1].y)
return;
- pActor->objx = actorInfo[ano - 1].x;
- pActor->objy = actorInfo[ano - 1].y;
+ pActor->objX = actorInfo[ano - 1].x;
+ pActor->objY = actorInfo[ano - 1].y;
if (pActor->actorObj)
SSetActorDest(pActor);
@@ -686,28 +1120,28 @@
* More properly should be called:
* 'store_actor_reel_and/or_film_and/or_object()'
*/
-void storeActorReel(int ano, const FREEL *reel, SCNHANDLE film, OBJECT *pobj, int reelnum, int x, int y) {
- PMACTOR pActor;
+void storeActorReel(int ano, const FREEL *reel, SCNHANDLE hFilm, OBJECT *pobj, int reelnum, int x, int y) {
+ PMOVER pActor;
assert(ano > 0 && ano <= NumActors); // illegal actor number
pActor = GetMover(ano);
- // Only store the reel and film for a moving actor if NOT called from MActorProcess()
- // (MActorProcess() calls with reel=film=NULL, pobj not NULL)
+ // Only store the reel and film for a moving actor if NOT called from MoverProcess()
+ // (MoverProcess() calls with reel=film=NULL, pobj not NULL)
if (!pActor
- || !(reel == NULL && film == 0 && pobj != NULL)) {
+ || !(reel == NULL && hFilm == 0 && pobj != NULL)) {
actorInfo[ano - 1].presReel = reel; // Store reel
actorInfo[ano - 1].presRnum = reelnum; // Store reel number
- actorInfo[ano - 1].presFilm = film; // Store film
- actorInfo[ano - 1].presX = x;
- actorInfo[ano - 1].presY = y;
+ actorInfo[ano - 1].presFilm = hFilm; // Store film
+ actorInfo[ano - 1].presPlayX = x;
+ actorInfo[ano - 1].presPlayY = y;
}
- // Only store the object for a moving actor if called from MActorProcess()
+ // Only store the object for a moving actor if called from MoverProcess()
if (!pActor) {
actorInfo[ano - 1].presObj = pobj; // Store object
- } else if (reel == NULL && film == 0 && pobj != NULL) {
+ } else if (reel == NULL && hFilm == 0 && pobj != NULL) {
actorInfo[ano - 1].presObj = pobj; // Store object
}
}
@@ -723,50 +1157,50 @@
/***************************************************************************/
-void setActorPlayFilm(int ano, SCNHANDLE film) {
+void SetActorPlayFilm(int ano, SCNHANDLE hFilm) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].playFilm = film;
+ actorInfo[ano - 1].playFilm = hFilm;
}
-SCNHANDLE getActorPlayFilm(int ano) {
+SCNHANDLE GetActorPlayFilm(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
return actorInfo[ano - 1].playFilm;
}
-void setActorTalkFilm(int ano, SCNHANDLE film) {
+void SetActorTalkFilm(int ano, SCNHANDLE hFilm) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].talkFilm = film;
+ actorInfo[ano - 1].talkFilm = hFilm;
}
-SCNHANDLE getActorTalkFilm(int ano) {
+SCNHANDLE GetActorTalkFilm(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
return actorInfo[ano - 1].talkFilm;
}
-void setActorTalking(int ano, bool tf) {
+void SetActorTalking(int ano, bool tf) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].talking = tf;;
+ actorInfo[ano - 1].bTalking = tf;;
}
-bool isActorTalking(int ano) {
+bool ActorIsTalking(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- return actorInfo[ano - 1].talking;
+ return actorInfo[ano - 1].bTalking;
}
-void setActorLatestFilm(int ano, SCNHANDLE film) {
+void SetActorLatestFilm(int ano, SCNHANDLE hFilm) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].latestFilm = film;
+ actorInfo[ano - 1].latestFilm = hFilm;
actorInfo[ano - 1].steps = 0;
}
-SCNHANDLE getActorLatestFilm(int ano) {
+SCNHANDLE GetActorLatestFilm(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
return actorInfo[ano - 1].latestFilm;
@@ -774,23 +1208,36 @@
/***************************************************************************/
-void updateActorEsc(int ano, bool escOn, int escEvent) {
+void UpdateActorEsc(int ano, bool escOn, int escEvent) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- actorInfo[ano - 1].escOn = escOn;
- actorInfo[ano - 1].escEv = escEvent;
+ actorInfo[ano - 1].bEscOn = escOn;
+ actorInfo[ano - 1].escEvent = escEvent;
}
-bool actorEsc(int ano) {
+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();
+ }
+
+}
+
+bool ActorEsc(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- return actorInfo[ano - 1].escOn;
+ return actorInfo[ano - 1].bEscOn;
}
-int actorEev(int ano) {
+int ActorEev(int ano) {
assert(ano > 0 && ano <= NumActors); // illegal actor number
- return actorInfo[ano - 1].escEv;
+ return actorInfo[ano - 1].escEvent;
}
/**
@@ -801,7 +1248,7 @@
z += z ? -1 : 0;
- zPos = y + (z << 10);
+ zPos = y + (z << ZSHIFT);
MultiSetZPosition(pObj, zPos);
return zPos;
}
@@ -809,9 +1256,18 @@
/**
* Guess what these do.
*/
-void MAsetZPos(PMACTOR pActor, int y, int32 zFactor) {
- if (!pActor->aHidden)
- AsetZPos(pActor->actorObj, y, zFactor);
+void SetMoverZ(PMOVER pMover, int y, int32 zFactor) {
+ if (!pMover->bHidden) {
+ if (!TinselV2)
+ AsetZPos(pMover->actorObj, y, zFactor);
+ else if (MoverIsSWalking(pMover) && pMover->zOverride != -1) {
+ // Special for SWalk()
+ MultiSetZPosition(pMover->actorObj, (pMover->zOverride << ZSHIFT) + y);
+ } else {
+ // Normal case
+ MultiSetZPosition(pMover->actorObj, (zFactor << ZSHIFT) + y);
+ }
+ }
}
/**
@@ -828,51 +1284,127 @@
if (ano == -1)
defaultColour = RGB(r1, g1, b1);
else
- actorInfo[ano - 1].tColour = RGB(r1, g1, b1);
+ actorInfo[ano - 1].textColour = RGB(r1, g1, b1);
}
/**
+ * Called from ActorRGB() - Stores actor's speech colour.
+ */
+
+void SetActorRGB(int ano, COLORREF colour) {
+ assert(ano >= 0 && ano <= NumActors);
+
+ if (ano)
+ actorInfo[ano - 1].textColour = colour;
+ else
+ defaultColour = colour;
+}
+
+/**
* Get the actor's stored speech colour.
* @param ano Actor Id
*/
-COLORREF getActorTcol(int ano) {
+COLORREF GetActorRGB(int ano) {
// Not used in JAPAN version
- assert(ano > 0 && ano <= NumActors); // illegal actor number
+ assert((ano >= -1) && (ano <= NumActors)); // illegal actor number
- if (actorInfo[ano - 1].tColour)
- return actorInfo[ano - 1].tColour;
+ if ((ano == -1) || !actorInfo[ano - 1].textColour)
+ return defaultColour;
else
- return defaultColour;
+ return actorInfo[ano - 1].textColour;
}
/**
+ * Set the actor's Z-factor
+ */
+void SetActorZfactor(int ano, uint32 zFactor) {
+ RANGE_CHECK(ano);
+
+ zFactors[ano - 1] = (uint8)zFactor;
+}
+
+uint32 GetActorZfactor(int ano) {
+ RANGE_CHECK(ano);
+
+ return zFactors[ano - 1];
+}
+
+/**
* Store relevant information pertaining to currently existing actors.
*/
int SaveActors(SAVED_ACTOR *sActorInfo) {
- int i, j;
+ int i, j, k;
for (i = 0, j = 0; i < NumActors; i++) {
- if (actorInfo[i].presObj != NULL) {
- assert(j < MAX_SAVED_ACTORS); // Saving too many actors
+ for (k = 0; k < (TinselV2 ? MAX_REELS : 1); ++k) {
+ bool presFlag = !TinselV2 ? actorInfo[i].presObj != NULL :
+ (actorInfo[i].presObjs[k] != NULL) && !IsCdPlayHandle(actorInfo[i].presFilm);
+ if (presFlag) {
-// sActorInfo[j].hidden = actorInfo[i].hidden;
- sActorInfo[j].bAlive = actorInfo[i].alive;
-// sActorInfo[j].x = (short)actorInfo[i].x;
-// sActorInfo[j].y = (short)actorInfo[i].y;
- sActorInfo[j].z = (short)actorInfo[i].z;
-// sActorInfo[j].presReel = actorInfo[i].presReel;
- sActorInfo[j].presRnum = (short)actorInfo[i].presRnum;
- sActorInfo[j].presFilm = actorInfo[i].presFilm;
- sActorInfo[j].presX = (short)actorInfo[i].presX;
- sActorInfo[j].presY = (short)actorInfo[i].presY;
- sActorInfo[j].actorID = (short)(i+1);
- j++;
+ assert(j < MAX_SAVED_ACTORS); // Saving too many actors
+
+ if (!TinselV2) {
+ sActorInfo[j].bAlive = actorInfo[i].bAlive;
+ sActorInfo[j].zFactor = (short)actorInfo[i].z;
+ sActorInfo[j].presRnum = (short)actorInfo[i].presRnum;
+ }
+
+ sActorInfo[j].actorID = (short)(i+1);
+ if (TinselV2)
+ sActorInfo[j].bHidden = actorInfo[i].bHidden;
+ // sActorInfo[j].x = (short)actorInfo[i].x;
+ // sActorInfo[j].y = (short)actorInfo[i].y;
+ // sActorInfo[j].presReel = actorInfo[i].presReel;
+ sActorInfo[j].presFilm = actorInfo[i].presFilm;
+ sActorInfo[j].presPlayX = (short)actorInfo[i].presPlayX;
+ sActorInfo[j].presPlayY = (short)actorInfo[i].presPlayY;
+ j++;
+
+ break;
+ }
}
}
return j;
}
+/**
+ * Restore actor data
+ */
+void RestoreActors(int numActors, PSAVED_ACTOR sActorInfo) {
+ int i, aIndex;
+
+ for (i = 0; i < numActors; i++) {
+ aIndex = sActorInfo[i].actorID - 1;
+
+ actorInfo[aIndex].bHidden = sActorInfo[i].bHidden;
+
+ // Play the same reel.
+ if (sActorInfo[i].presFilm != 0) {
+ RestoreActorReels(sActorInfo[i].presFilm, sActorInfo[i].actorID,
+ sActorInfo[i].presPlayX, sActorInfo[i].presPlayY);
+ }
+ }
+}
+
+void SaveZpositions(void *zpp) {
+ memcpy(zpp, zPositions, sizeof(zPositions));
+}
+
+void RestoreZpositions(void *zpp) {
+ memcpy(zPositions, zpp, sizeof(zPositions));
+}
+
+void SaveActorZ(byte *saveActorZ) {
+ assert(NumActors <= MAX_SAVED_ACTOR_Z);
+
+ memcpy(saveActorZ, zFactors, NumActors);
+}
+
+void RestoreActorZ(byte *saveActorZ) {
+ memcpy(zFactors, saveActorZ, NumActors);
+}
+
void setactorson(void) {
bActorsOn = true;
}
@@ -880,18 +1412,307 @@
void ActorsLife(int ano, bool bAlive) {
assert((ano > 0 && ano <= NumActors) || ano == -1); // illegal actor number
- actorInfo[ano-1].alive = bAlive;
+ actorInfo[ano-1].bAlive = bAlive;
}
void syncAllActorsAlive(Serializer &s) {
for (int i = 0; i < MAX_SAVED_ALIVES; i++) {
- s.syncAsByte(actorInfo[i].alive);
+ s.syncAsByte(actorInfo[i].bAlive);
s.syncAsByte(actorInfo[i].tagged);
s.syncAsByte(actorInfo[i].tType);
s.syncAsUint32LE(actorInfo[i].hTag);
}
}
+/**
+ * Called from EndActor()
+ */
+void dwEndActor(int ano) {
+ int i;
+ RANGE_CHECK(ano);
+
+ // Make play.c think it's been replaced
+// The following line may have been indirectly making text go away!
+// actorInfo[ano - 1].presFilm = NULL;
+// but things were returning after a cut scene.
+// so re-instate it and de-register the object
+ actorInfo[ano - 1].presFilm = 0;
+ actorInfo[ano-1].filmNum++;
+
+ for (i = 0; i < MAX_REELS; i++) {
+ // It may take a frame to remove this, so make it invisible
+ if (actorInfo[ano-1].presObjs[i] != NULL) {
+ MultiHideObject(actorInfo[ano-1].presObjs[i]);
+ actorInfo[ano-1].presObjs[i] = NULL;
+ }
+ }
+}
+
+
+/**
+ * Returns a tagged actor's tag portion.
+ */
+void GetActorTagPortion(int ano, unsigned *top, unsigned *bottom, unsigned *left, unsigned *right) {
+ // Convert actor number to index
+ ano = TaggedActorIndex(ano);
+
+ *top = taggedActors[ano].tagPortionV >> 16;
+ *bottom = taggedActors[ano].tagPortionV & 0xffff;
+ *left = taggedActors[ano].tagPortionH >> 16;
+ *right = taggedActors[ano].tagPortionH & 0xffff;
+
+ // ensure validity
+ assert(*top >= 1 && *top <= 8);
+ assert(*bottom >= *top && *bottom <= 8);
+ assert(*left >= 1 && *left <= 8);
+ assert(*right >= *left && *right <= 8);
+}
+
+/**
+ * Returns handle to tagged actor's tag text.
+ */
+SCNHANDLE GetActorTagHandle(int ano) {
+ // Convert actor number to index
+ ano = TaggedActorIndex(ano);
+
+ return taggedActors[ano].hOverrideTag ?
+ taggedActors[ano].hOverrideTag : taggedActors[ano].hTagText;
+}
+
+void SetActorPointedTo(int actor, bool bPointedTo) {
+ // Convert actor number to index
+ actor = TaggedActorIndex(actor);
+
+ if (bPointedTo)
+ taggedActors[actor].tagFlags |= POINTING;
+ else
+ taggedActors[actor].tagFlags &= ~POINTING;
+}
+
+bool ActorIsPointedTo(int actor) {
+ // Convert actor number to index
+ actor = TaggedActorIndex(actor);
+
+ return (taggedActors[actor].tagFlags & POINTING);
+}
+
+void SetActorTagWanted(int actor, bool bTagWanted, bool bCursor, SCNHANDLE hOverrideTag) {
+ // Convert actor number to index
+ actor = TaggedActorIndex(actor);
+
+ if (bTagWanted) {
+ taggedActors[actor].tagFlags |= TAGWANTED;
+ taggedActors[actor].hOverrideTag = hOverrideTag;
+ } else {
+ taggedActors[actor].tagFlags &= ~TAGWANTED;
+ taggedActors[actor].hOverrideTag = 0;
+ }
+
+ if (bCursor)
+ taggedActors[actor].tagFlags |= FOLLOWCURSOR;
+ else
+ taggedActors[actor].tagFlags &= ~FOLLOWCURSOR;
+}
+
+bool ActorTagIsWanted(int actor) {
+ // Convert actor number to index
+ actor = TaggedActorIndex(actor);
+
+ return (taggedActors[actor].tagFlags & TAGWANTED);
+}
+
+/**
+ * Given cursor position and an actor number, ascertains
+ * whether the cursor is within the actor's tag area.
+ * Returns True for a positive result, False for negative.
+ */
+bool InHotSpot(int ano, int curX, int curY) {
+ int aTop, aBot; // Top and bottom limits }
+ int aHeight; // Height } of active area
+ int aLeft, aRight; // Left and right }
+ int aWidth; // Width }
+ unsigned topEighth, botEighth, leftEighth, rightEighth;
+
+ // First check if within broad range
+ if (curX < (aLeft = GetActorLeft(ano)) // too far left
+ || curX > (aRight = GetActorRight(ano)) // too far right
+ || curY < (aTop = GetActorTop(ano)) // too high
+ || curY > (aBot = GetActorBottom(ano)) ) // too low
+ return false;
+
+ GetActorTagPortion(ano, &topEighth, &botEighth, &leftEighth, &rightEighth);
+
+ aWidth = aRight - aLeft;
+ aLeft += ((leftEighth - 1)*aWidth)/8;
+ aRight -= ((8 - rightEighth)*aWidth)/8;
+
+ // check if within x-range
+ if (curX < aLeft || curX > aRight)
+ return false;
+
+ aHeight = aBot - aTop;
+ aTop += ((topEighth - 1)*aHeight)/8;
+ aBot -= ((8 - botEighth)*aHeight)/8;
+
+ // check if within y-range
+ if (curY < aTop || curY > aBot)
+ return false;
+
+ return true;
+}
+
+/**
+ * Front Tagged Actor
+ */
+int FrontTaggedActor(void) {
+ int i;
+
+ for (i = 0; i < numTaggedActors; i++) {
+ if (taggedActors[i].tagFlags & POINTING)
+ return taggedActors[i].id;
+ }
+ return 0;
+}
+
+/**
+ * GetActorTagPos
+ */
+void GetActorTagPos(int actor, int *pTagX, int *pTagY, bool bAbsolute) {
+ unsigned topEighth, botEighth;
+ int aTop; // Top and bottom limits }
+ int aHeight; // Height } of active area
+ int Loffset, Toffset;
+
+ GetActorTagPortion(actor, &topEighth, &botEighth, (unsigned *)&Loffset, (unsigned *)&Toffset);
+
+ aTop = GetActorTop(actor);
+ aHeight = GetActorBottom(actor) - aTop;
+ aTop += ((topEighth - 1) * aHeight) / 8;
+
+ *pTagX = ((GetActorLeft(actor) + GetActorRight(actor)) / 2);
+ *pTagY = aTop;
+
+ if (!bAbsolute) {
+ PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
+ *pTagX -= Loffset;
+ *pTagY -= Toffset;
+ }
+}
+
+/**
+ * Is Tagged Actor
+ */
+bool IsTaggedActor(int actor) {
+ int i;
+
+ for (i = 0; i < numTaggedActors; i++) {
+ if (taggedActors[i].id == actor)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * StoreActorPresFilm
+ */
+void StoreActorPresFilm(int ano, SCNHANDLE hFilm, int x, int y) {
+ int i;
+
+ RANGE_CHECK(ano);
+
+ actorInfo[ano-1].presFilm = hFilm;
+ actorInfo[ano-1].presPlayX = x;
+ actorInfo[ano-1].presPlayY = y;
+ actorInfo[ano-1].filmNum++;
+
+ for (i = 0; i < MAX_REELS; i++) {
+ // It may take a frame to remove this, so make it invisible
+ if (actorInfo[ano - 1].presObjs[i] != NULL)
+ MultiHideObject(actorInfo[ano - 1].presObjs[i]);
+
+ actorInfo[ano - 1].presColumns[i] = -1;
+ actorInfo[ano - 1].presObjs[i] = NULL;
+ }
+}
+
+/**
+ * GetActorPresFilm
+ */
+SCNHANDLE GetActorPresFilm(int ano) {
+ RANGE_CHECK(ano);
+
+ return actorInfo[ano - 1].presFilm;
+}
+
+
+/**
+ * GetActorFilmNumber
+ */
+int GetActorFilmNumber(int ano) {
+ RANGE_CHECK(ano);
+
+ return actorInfo[ano - 1].filmNum;
+}
+
+/**
+ * More properly should be called:
+ * 'StoreActorReelAndObject()'
+ */
+void StoreActorReel(int actor, int column, OBJECT *pObj) {
+ RANGE_CHECK(actor);
+ int i;
+
+ for (i = 0; i < MAX_REELS; i++) {
+ if (actorInfo[actor-1].presColumns[i] == -1) {
+ // Store reel and object
+ actorInfo[actor - 1].presColumns[i] = column;
+ actorInfo[actor - 1].presObjs[i] = pObj;
+ break;
+ }
+ }
+
+ assert(i < MAX_REELS);
+}
+
+/**
+ * NotPlayingReel
+ */
+void NotPlayingReel(int actor, int filmNumber, int column) {
+ int i;
+
+ RANGE_CHECK(actor);
+
+ if (actorInfo[actor-1].filmNum != filmNumber)
+ return;
+
+ // De-register this reel
+ for (i = 0; i < MAX_REELS; i++) {
+ if (actorInfo[actor-1].presColumns[i] == column) {
+ actorInfo[actor-1].presObjs[i] = NULL;
+ actorInfo[actor-1].presColumns[i] = -1;
+ break;
+ }
+ }
+
+ // De-register the film if this was the last reel
+ for (i = 0; i < MAX_REELS; i++) {
+ if (actorInfo[actor-1].presColumns[i] != -1)
+ break;
+ }
+ if (i == MAX_REELS)
+ actorInfo[actor-1].presFilm = 0;
+}
+
+bool ActorReelPlaying(int actor, int column) {
+ RANGE_CHECK(actor);
+
+ for (int i = 0; i < MAX_REELS; i++) {
+ if (actorInfo[actor - 1].presColumns[i] == column)
+ return true;
+ }
+ return false;
+}
+
} // end of namespace Tinsel
Modified: scummvm/trunk/engines/tinsel/actors.h
===================================================================
--- scummvm/trunk/engines/tinsel/actors.h 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/actors.h 2008-12-01 20:35:36 UTC (rev 35196)
@@ -29,24 +29,30 @@
#include "tinsel/dw.h" // for SCNHANDLE
-#include "tinsel/events.h" // for USER_EVENT
+#include "tinsel/events.h" // for TINSEL_EVENT
#include "tinsel/palette.h" // for COLORREF
namespace Tinsel {
struct FREEL;
struct INT_CONTEXT;
-struct MACTOR;
+struct MOVER;
struct OBJECT;
+#define ACTORTAG_KEY 0x1000000
+#define OTH_RELATEDACTOR 0x00000fff
+#define OTH_RELATIVE 0x00001000
+#define OTH_ABSOLUTE 0x00002000
+
/*----------------------------------------------------------------------*/
void RegisterActors(int num);
void FreeActors(void);
-void setleadid(int rid);
-int LeadId(void);
-void StartActors(SCNHANDLE ah, int numActors, bool bRunScript);
+void SetLeadId(int rid);
+int GetLeadId(void);
+bool ActorIsGhost(int actor);
+void StartTaggedActors(SCNHANDLE ah, int numActors, bool bRunScript);
void DropActors(void); // No actor reels running
void DisableActor(int actor);
void EnableActor(int actor);
@@ -63,61 +69,111 @@
int GetActorRight(int ano);
int GetActorTop(int ano);
int GetActorBottom(int ano);
-void HideActor(int ano);
+void ShowActor(CORO_PARAM, int ano);
+void HideActor(CORO_PARAM, int ano);
+bool ActorHidden(int ano);
bool HideMovingActor(int id, int sf);
void unHideMovingActor(int id);
void restoreMovement(int id);
-void storeActorReel(int ano, const FREEL *reel, SCNHANDLE film, OBJECT *pobj, int reelnum, int x, int y);
+void storeActorReel(int ano, const FREEL *reel, SCNHANDLE hFilm, OBJECT *pobj, int reelnum, int x, int y);
const FREEL *actorReel(int ano);
SCNHANDLE actorFilm(int ano);
-void setActorPlayFilm(int ano, SCNHANDLE film);
-SCNHANDLE getActorPlayFilm(int ano);
-void setActorTalkFilm(int ano, SCNHANDLE film);
-SCNHANDLE getActorTalkFilm(int ano);
-void setActorTalking(int ano, bool tf);
-bool isActorTalking(int ano);
-void setActorLatestFilm(int ano, SCNHANDLE film);
-SCNHANDLE getActorLatestFilm(int ano);
+void SetActorPlayFilm(int ano, SCNHANDLE hFilm);
+SCNHANDLE GetActorPlayFilm(int ano);
+void SetActorTalkFilm(int ano, SCNHANDLE hFilm);
+SCNHANDLE GetActorTalkFilm(int ano);
+void SetActorTalking(int ano, bool tf);
+bool ActorIsTalking(int ano);
+void SetActorLatestFilm(int ano, SCNHANDLE hFilm);
+SCNHANDLE GetActorLatestFilm(int ano);
-void updateActorEsc(int ano, bool escOn, int escEv);
-bool actorEsc(int ano);
-int actorEev(int ano);
-void storeActorPos(int ano, int x, int y);
-void storeActorSteps(int ano, int steps);
-int getActorSteps(int ano);
-void storeActorZpos(int ano, int z);
+void UpdateActorEsc(int ano, bool escOn, int escEvent);
+void UpdateActorEsc(int ano, int escEvent);
+bool ActorEsc(int ano);
+int ActorEev(int ano);
+void StoreActorPos(int ano, int x, int y);
+void StoreActorSteps(int ano, int steps);
+int GetActorSteps(int ano);
+void StoreActorZpos(int ano, int z, int column = -1);
+int GetActorZpos(int ano, int column);
+void IncLoopCount(int ano);
+int GetLoopCount(int ano);
SCNHANDLE GetActorTag(int ano);
void FirstTaggedActor(void);
int NextTaggedActor(void);
+int NextTaggedActor(int previous);
int AsetZPos(OBJECT *pObj, int y, int32 zFactor);
-void MAsetZPos(MACTOR *pActor, int y, int32 zFactor);
-void actorEvent(int ano, USER_EVENT event, BUTEVENT be);
+void SetMoverZ(MOVER *pMover, int y, int32 zFactor);
+void ActorEvent(int ano, TINSEL_EVENT event, PLR_EVENT be);
void storeActorAttr(int ano, int r1, int g1, int b1);
-COLORREF getActorTcol(int ano);
+COLORREF GetActorRGB(int ano);
+void SetActorRGB(int ano, COLORREF colour);
+void SetActorZfactor(int ano, uint32 zFactor);
+uint32 GetActorZfactor(int ano);
void setactorson(void);
void ActorsLife(int id, bool bAlive);
+void dwEndActor(int ano);
+
+void ActorEvent(CORO_PARAM, int ano, TINSEL_EVENT tEvent, bool bWait, int myEscape, bool *result = NULL);
+
+void GetActorTagPortion(int ano, unsigned *top, unsigned *bottom, unsigned *left, unsigned *right);
+SCNHANDLE GetActorTagHandle(int ano);
+void SetActorPointedTo(int actor, bool bPointedTo);
+bool ActorIsPointedTo(int actor);
+void SetActorTagWanted(int actor, bool bTagWanted, bool bCursor, SCNHANDLE hOverrideTag);
+bool ActorTagIsWanted(int actor);
+bool InHotSpot(int ano, int curX, int curY);
+int FrontTaggedActor(void);
+void GetActorTagPos(int actor, int *pTagX, int *pTagY, bool bAbsolute);
+bool IsTaggedActor(int actor);
+void StoreActorPresFilm(int ano, SCNHANDLE hFilm, int x, int y);
+SCNHANDLE GetActorPresFilm(int ano);
+int GetActorFilmNumber(int ano);
+void StoreActorReel(int actor, int column, OBJECT *pObj);
+void NotPlayingReel(int actor, int filmNumber, int column);
+bool ActorReelPlaying(int actor, int column);
+void SetActorPlayFilm(int ano, SCNHANDLE hFilm);
+SCNHANDLE GetActorPlayFilm(int ano);
+
/*----------------------------------------------------------------------*/
struct SAVED_ACTOR {
short actorID;
- short z;
+ short zFactor;
bool bAlive;
+ bool bHidden;
SCNHANDLE presFilm; //!< the film that reel belongs to
short presRnum; //!< the present reel number
- short presX, presY;
+ short presPlayX, presPlayY;
};
+typedef SAVED_ACTOR *PSAVED_ACTOR;
+#define NUM_ZPOSITIONS 200 // Reasonable-sounding number
+
+struct Z_POSITIONS {
+ short actor;
+ short column;
+ int z;
+};
+
int SaveActors(SAVED_ACTOR *sActorInfo);
-
void RestoreActorProcess(int id, INT_CONTEXT *pic);
+int SaveActors(PSAVED_ACTOR sActorInfo);
+void RestoreActors(int numActors, PSAVED_ACTOR sActorInfo);
+void SaveZpositions(void *zpp);
+void RestoreZpositions(void *zpp);
+
+void SaveActorZ(byte *saveActorZ);
+void RestoreActorZ(byte *saveActorZ);
+
/*----------------------------------------------------------------------*/
} // end of namespace Tinsel
Modified: scummvm/trunk/engines/tinsel/anim.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/anim.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/anim.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -29,32 +29,12 @@
#include "tinsel/multiobj.h" // multi-part object defintions etc.
#include "tinsel/object.h"
#include "tinsel/sched.h"
+#include "tinsel/tinsel.h"
#include "common/util.h"
namespace Tinsel {
-/** Animation script commands */
-enum {
- ANI_END = 0, //!< end of animation script
- ANI_JUMP = 1, //!< animation script jump
- ANI_HFLIP = 2, //!< flip animated object horizontally
- ANI_VFLIP = 3, //!< flip animated object vertically
- ANI_HVFLIP = 4, //!< flip animated object in both directions
- ANI_ADJUSTX = 5, //!< adjust animated object x animation point
- ANI_ADJUSTY = 6, //!< adjust animated object y animation point
- ANI_ADJUSTXY = 7, //!< adjust animated object x & y animation points
- ANI_NOSLEEP = 8, //!< do not sleep for this frame
- ANI_CALL = 9, //!< call routine
- ANI_HIDE = 10 //!< hide animated object
-};
-
-/** animation script command possibilities */
-union ANI_SCRIPT {
- int32 op; //!< treat as an opcode or operand
- uint32 hFrame; //!< treat as a animation frame handle
-};
-
/**
* Advance to next frame routine.
* @param pAnim Animation data structure
@@ -64,6 +44,9 @@
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
while (1) { // repeat until a real image
+ debugC(DEBUG_DETAILED, kTinselDebugAnimations,
+ "DoNextFrame %ph index=%d, op=%xh", (byte *)pAnim, pAnim->scriptIndex,
+ FROM_LE_32(pAni[pAnim->scriptIndex].op));
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
case ANI_END: // end of animation script
@@ -104,7 +87,6 @@
// go fetch a real image
break;
-
case ANI_HVFLIP: // flip animated object in both directions
// next opcode
@@ -230,6 +212,12 @@
void InitStepAnimScript(ANIM *pAnim, OBJECT *pAniObj, SCNHANDLE hNewScript, int aniSpeed) {
OBJECT *pObj; // multi-object list iterator
+ debugC(DEBUG_DETAILED, kTinselDebugAnimations,
+ "InitStepAnimScript Object=(%d,%d,%xh) script=%xh aniSpeed=%d rec=%ph",
+ !pAniObj ? 0 : fracToInt(pAniObj->xPos),
+ !pAniObj ? 0 : fracToInt(pAniObj->yPos),
+ !pAniObj ? 0 : pAniObj->hImg, hNewScript, aniSpeed, (byte *)pAnim);
+
pAnim->aniDelta = 1; // will animate on next call to NextAnimRate
pAnim->pObject = pAniObj; // set object to animate
pAnim->hScript = hNewScript; // set animation script
@@ -254,9 +242,13 @@
// re-init animation delta counter
pAnim->aniDelta = pAnim->aniRate;
- // move to next frame
- while ((state = DoNextFrame(pAnim)) == ScriptNoSleep)
- ;
+ if (TinselV2)
+ state = DoNextFrame(pAnim);
+ else {
+ // move to next frame
+ while ((state = DoNextFrame(pAnim)) == ScriptNoSleep)
+ ;
+ }
return state;
}
@@ -274,7 +266,7 @@
// get a pointer to the script
const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript);
- if (numFrames <= 0)
+ if (!TinselV2 && (numFrames <= 0))
// do nothing
return;
@@ -282,9 +274,10 @@
switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) {
case ANI_END: // end of animation script
- // going off the end is probably a error
- error("SkipFrames(): formally 'assert(0)!'");
- break;
+ // going off the end is probably a error, but only in Tinsel 1
+ if (!TinselV2)
+ error("SkipFrames(): formally 'assert(0)!'");
+ return;
case ANI_JUMP: // do animation jump
@@ -293,6 +286,10 @@
// jump to new frame position
pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op);
+
+ if (TinselV2)
+ // Done if skip to jump
+ return;
break;
case ANI_HFLIP: // flip animated object horizontally
@@ -383,7 +380,10 @@
default: // must be an actual animation frame handle
// one less frame
- if (numFrames-- > 0) {
+ if (numFrames == 0)
+ return;
+
+ if (numFrames == -1 || numFrames-- > 0) {
// next opcode
pAnim->scriptIndex++;
} else {
@@ -401,4 +401,48 @@
}
}
+/**
+ * About to jump or end
+ * @param pAnim Animation data structure
+ */
+bool AboutToJumpOrEnd(PANIM pAnim) {
+ if (pAnim->aniDelta == 1) {
+ // get a pointer to the script
+ ANI_SCRIPT *pAni = (ANI_SCRIPT *)LockMem(pAnim->hScript);
+ int zzz = pAnim->scriptIndex;
+
+ for (;;) {
+ // repeat until a real image
+ switch (FROM_LE_32(pAni[zzz].op)) {
+ case ANI_END: // end of animation script
+ case ANI_JUMP: // do animation jump
+ return true;
+
+ case ANI_HFLIP: // flip animated object horizontally
+ case ANI_VFLIP: // flip animated object vertically
+ case ANI_HVFLIP: // flip animated object in both directions
+ zzz++;
+ break;
+
+ case ANI_ADJUSTX: // adjust animated object x animation point
+ case ANI_ADJUSTY: // adjust animated object y animation point
+ zzz += 2;
+ break;
+
+ case ANI_ADJUSTXY: // adjust animated object x & y animation points
+ zzz += 3;
+ break;
+
+ case ANI_HIDE: // hide animated object
+ default: // must be an actual animation frame handle
+ return false;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
} // end of namespace Tinsel
Modified: scummvm/trunk/engines/tinsel/anim.h
===================================================================
--- scummvm/trunk/engines/tinsel/anim.h 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/anim.h 2008-12-01 20:35:36 UTC (rev 35196)
@@ -41,8 +41,34 @@
uint32 hScript; //!< animation script handle
int scriptIndex; //!< current position in animation script
};
+typedef ANIM *PANIM;
+typedef void (*PANI_ADDR)(struct ANIM *);
+/** Animation script commands */
+enum {
+ ANI_END = 0, //!< end of animation script
+ ANI_JUMP = 1, //!< animation script jump
+ ANI_HFLIP = 2, //!< flip animated object horizontally
+ ANI_VFLIP = 3, //!< flip animated object vertically
+ ANI_HVFLIP = 4, //!< flip animated object in both directions
+ ANI_ADJUSTX = 5, //!< adjust animated object x animation point
+ ANI_ADJUSTY = 6, //!< adjust animated object y animation point
+ ANI_ADJUSTXY = 7, //!< adjust animated object x & y animation points
+ ANI_NOSLEEP = 8, //!< do not sleep for this frame
+ ANI_CALL = 9, //!< call routine
+ ANI_HIDE = 10, //!< hide animated object
+ ANI_STOP = 11 //!< stop sound
+};
+
+/** animation script command possibilities */
+union ANI_SCRIPT {
+ int32 op; //!< treat as an opcode or operand
+ uint32 hFrame; //!< treat as a animation frame handle
+// PANI_ADDR pFunc; //!< treat as a animation function call
+};
+
+
/*----------------------------------------------------------------------*\
|* Anim Function Prototypes *|
\*----------------------------------------------------------------------*/
@@ -66,6 +92,8 @@
ANIM *pAnim, // animation data structure
int numFrames); // number of frames to skip
+bool AboutToJumpOrEnd(PANIM pAnim);
+
} // end of namespace Tinsel
#endif // TINSEL_ANIM_H
Modified: scummvm/trunk/engines/tinsel/background.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/background.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/background.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -37,6 +37,9 @@
// current background
BACKGND *pCurBgnd = NULL;
+// FIXME: Not yet used
+static bool bEntireRedraw;
+
/**
* Called to initialise a background.
* @param pBgnd Pointer to data struct for current background
@@ -125,6 +128,27 @@
}
/**
+ * Returns the x position of the centre of the specified playfield
+ * @param which Which playfield
+ */
+
+int PlayfieldGetCentreX(int which) {
+ PLAYFIELD *pPlayfield; // pointer to relavent playfield
+
+ // make sure there is a background
+ assert(pCurBgnd != NULL);
+
+ // make sure the playfield number is in range
+ assert(which >= 0 && which < pCurBgnd->numPlayfields);
+
+ // get playfield pointer
+ pPlayfield = pCurBgnd->fieldArray + which;
+
+ // get current integer position
+ return fracToInt(pPlayfield->fieldX) + SCREEN_WIDTH/2;
+}
+
+/**
* Returns the display list for the specified playfield.
* @param which Which playfield
*/
@@ -229,4 +253,9 @@
ResetClipRect();
}
+void ForceEntireRedraw(void) {
+ bEntireRedraw = true;
+}
+
+
} // end of namespace Tinsel
Modified: scummvm/trunk/engines/tinsel/background.h
===================================================================
--- scummvm/trunk/engines/tinsel/background.h 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/background.h 2008-12-01 20:35:36 UTC (rev 35196)
@@ -27,10 +27,11 @@
#ifndef TINSEL_BACKGND_H // prevent multiple includes
#define TINSEL_BACKGND_H
+#include "common/frac.h"
+#include "common/rect.h"
+#include "tinsel/coroutine.h"
#include "tinsel/dw.h" // for SCNHANDLE
#include "tinsel/palette.h" // palette definitions
-#include "common/frac.h"
-#include "common/rect.h"
namespace Tinsel {
@@ -78,6 +79,8 @@
void InitBackground( // called to initialise a background
BACKGND *pBgnd); // pointer to data struct for current background
+void StartupBackground(CORO_PARAM, SCNHANDLE hFilm);
+
void StopBgndScrolling(void); // Stops all background playfields from scrolling
void PlayfieldSetPos( // Sets the xy position of the specified playfield in the current background
@@ -90,6 +93,9 @@
int *pXpos, // returns current x position
int *pYpos); // returns current y position
+int PlayfieldGetCentreX( // Returns the xy position of the specified playfield in the current background
+ int which); // which playfield
+
OBJECT *GetPlayfieldList( // Returns the display list for the specified playfield
int which); // which playfield
@@ -100,8 +106,16 @@
void RedrawBackgnd(void); // Completely redraws all the playfield object lists for the current background
-SCNHANDLE BackPal(void);
+OBJECT *GetBgObject();
+SCNHANDLE BgPal(void);
+
+void ForceEntireRedraw(void);
+
+int BgWidth(void);
+
+int BgHeight(void);
+
} // end of namespace Tinsel
#endif // TINSEL_BACKGND_H
Modified: scummvm/trunk/engines/tinsel/bg.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/bg.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/bg.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -37,7 +37,8 @@
#include "tinsel/pid.h"
#include "tinsel/sched.h"
#include "tinsel/timers.h" // For ONE_SECOND constant
-#include "tinsel/tinlib.h" // For control()
+#include "tinsel/tinlib.h" // For Control()
+#include "tinsel/tinsel.h"
#include "common/util.h"
@@ -45,49 +46,61 @@
//----------------- LOCAL GLOBAL DATA --------------------
-static SCNHANDLE BackPalette = 0; // Background's palette
-static OBJECT *pBG = 0; // The main picture's object.
+#define MAX_BG 10
+
+static SCNHANDLE hBgPal = 0; // Background's palette
+static POBJECT pBG[MAX_BG];
+static ANIM thisAnim[MAX_BG]; // used by BGmainProcess()
static int BGspeed = 0;
-static SCNHANDLE BgroundHandle = 0; // Current scene handle - stored in case of Save_Scene()
-static bool DoFadeIn = false;
-static ANIM thisAnim; // used by BGmainProcess()
+static SCNHANDLE hBackground = 0; // Current scene handle - stored in case of Save_Scene()
+static bool bDoFadeIn = false;
+static int bgReels;
/**
+ * GetBgObject
+ */
+OBJECT *GetBgObject() {
+ return pBG[0];
+}
+
+/**
* BackPal
*/
-SCNHANDLE BackPal(void) {
- return BackPalette;
+SCNHANDLE BgPal(void) {
+ return hBgPal;
}
/**
* SetDoFadeIn
*/
void SetDoFadeIn(bool tf) {
- DoFadeIn = tf;
+ bDoFadeIn = tf;
}
/**
* Called before scene change.
*/
void DropBackground(void) {
- pBG = NULL; // No background
- BackPalette = 0; // No background palette
+ pBG[0] = NULL; // No background
+
+ if (!TinselV2)
+ hBgPal = 0; // No background palette
}
/**
* Return the width of the current background.
*/
-int BackgroundWidth(void) {
- assert(pBG);
- return MultiRightmost(pBG) + 1;
+int BgWidth(void) {
+ assert(pBG[0]);
+ return MultiRightmost(pBG[0]) + 1;
}
/**
* Return the height of the current background.
*/
-int BackgroundHeight(void) {
- assert(pBG);
- return MultiLowest(pBG) + 1;
+int BgHeight(void) {
+ assert(pBG[0]);
+ return MultiLowest(pBG[0]) + 1;
}
/**
@@ -100,90 +113,137 @@
CORO_BEGIN_CODE(_ctx);
- const FREEL *pfr;
+ const FILM *pFilm;
+ const FREEL *pReel;
const MULTI_INIT *pmi;
// get the stuff copied to process when it was created
- pfr = (const FREEL *)param;
-
- if (pBG == NULL) {
+ if (pBG[0] == NULL) {
/*** At start of scene ***/
- // Get the MULTI_INIT structure
- pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pfr->mobj));
+ if (!TinselV2) {
+ pReel = (const FREEL *)param;
- // Initialise and insert the object, and initialise its script.
- pBG = MultiInitObject(pmi);
- MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG);
- InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
+ // Get the MULTI_INIT structure
+ pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj));
- if (DoFadeIn) {
- FadeInFast(NULL);
- DoFadeIn = false;
+ // 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 = pFilm->numreels;
+
+ int i;
+ for (i = 0; i < bgReels; i++) {
+ // Get the MULTI_INIT structure
+ pmi = (PMULTI_INIT) LockMem(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], pFilm->reels[i].script, BGspeed);
+
+ if (i > 0)
+ pBG[i-1]->pSlave = pBG[i];
+ }
}
- while (StepAnimScript(&thisAnim) != ScriptFinished)
+ if (bDoFadeIn) {
+ FadeInFast(NULL);
+ bDoFadeIn = false;
+ } else if (TinselV2)
+ PokeInTagColour();
+
+ for (;;) {
+ for (int i = 0; i < bgReels; i++) {
+ if (StepAnimScript(&thisAnim[i]) == ScriptFinished)
+ error("Background animation has finished!");
+ }
+
CORO_SLEEP(1);
-
- error("Background animation has finished!");
+ }
} 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 == pFilm->numreels);
- // Just re-initialise the script.
- InitStepAnimScript(&thisAnim, pBG, FROM_LE_32(pfr->script), BGspeed);
- StepAnimScript(&thisAnim);
+ // 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;
}
/**
- * setBackPal()
+ * AetBgPal()
*/
-void setBackPal(SCNHANDLE hPal) {
- BackPalette = hPal;
+void SetBackPal(SCNHANDLE hPal) {
+ hBgPal = hPal;
- fettleFontPal(BackPalette);
- CreateTranslucentPalette(BackPalette);
+ FettleFontPal(hBgPal);
+ CreateTranslucentPalette(hBgPal);
}
void ChangePalette(SCNHANDLE hPal) {
- SwapPalette(FindPalette(BackPalette), hPal);
+ SwapPalette(FindPalette(hBgPal), hPal);
- setBackPal(hPal);
+ SetBackPal(hPal);
}
/**
* Given the scene background film, extracts the palette handle for
* everything else's use, then starts a display process for each reel
* in the film.
- * @param bfilm Scene background film
+ * @param hFilm Scene background film
*/
-void startupBackground(SCNHANDLE bfilm) {
+void StartupBackground(CORO_PARAM, SCNHANDLE hFilm) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
const FILM *pfilm;
IMAGE *pim;
- BgroundHandle = bfilm; // Save handle in case of Save_Scene()
+ hBackground = hFilm; // Save handle in case of Save_Scene()
- pim = GetImageFromFilm(bfilm, 0, NULL, NULL, &pfilm);
- setBackPal(FROM_LE_32(pim->hImgPal));
+ pim = GetImageFromFilm(hFilm, 0, NULL, NULL, &pfilm);
+ SetBackPal(FROM_LE_32(pim->hImgPal));
// Extract the film speed
BGspeed = ONE_SECOND / FROM_LE_32(pfilm->frate);
- if (pBG == NULL)
- control(CONTROL_STARTOFF); // New feature - start scene with control off
-
// Start display process for each reel in the film
- assert(FROM_LE_32(pfilm->numreels) == 1); // Multi-reeled backgrounds withdrawn
g_scheduler->createProcess(PID_REEL, BGmainProcess, &pfilm->reels[0], sizeof(FREEL));
+
+ if (pBG[0] == NULL)
+ ControlStartOff();
+
+ if (TinselV2 && (coroParam != nullContext))
+ CORO_GIVE_WAY;
+
+ CORO_END_CODE;
}
/**
* Return the current scene handle.
*/
SCNHANDLE GetBgroundHandle(void) {
- return BgroundHandle;
+ return hBackground;
}
} // end of namespace Tinsel
Added: scummvm/trunk/engines/tinsel/bmv.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/bmv.cpp (rev 0)
+++ scummvm/trunk/engines/tinsel/bmv.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -0,0 +1,1272 @@
+/* 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$
+ *
+ * The movie player.
+ */
+
+#include "common/file.h"
+#include "sound/mixer.h"
+#include "sound/audiostream.h"
+#include "tinsel/tinsel.h"
+#include "tinsel/background.h"
+#include "tinsel/cliprect.h"
+#include "tinsel/coroutine.h"
+#include "tinsel/config.h"
+#include "tinsel/dw.h"
+#include "tinsel/events.h"
+#include "tinsel/font.h"
+#include "tinsel/graphics.h"
+#include "tinsel/handle.h"
+#include "tinsel/heapmem.h"
+#include "tinsel/multiobj.h"
+#include "tinsel/object.h"
+#include "tinsel/palette.h"
+#include "tinsel/sched.h"
+#include "tinsel/strres.h"
+#include "tinsel/text.h"
+#include "tinsel/timers.h"
+#include "tinsel/tinlib.h"
+#include "tinsel/tinsel.h"
+
+namespace Tinsel {
+
+//----------------- GLOBAL GLOBAL DATA ------------------------
+
+bool bOldAudio;
+
+//----------------- LOCAL GLOBAL DATA ------------------------
+
+//static READREQ rr;
+
+//----------------- LOCAL DEFINES ----------------------------
+
+#define SZ_C_BLOB 65
+#define SZ_U_BLOB 128
+
+#define BLANK_SOUND 0x0 // for 16 bit silence
+
+#define PT_A 20 // Number of times PT_B may be reached
+#define PT_B 6
+
+
+#define SLOT_SIZE (25*1024)
+//#define NUM_SLOTS 168
+#define NUM_SLOTS 122 // -> ~ 3MB
+
+
+#define PREFETCH (NUM_SLOTS/2) // For initial test
+
+#ifndef _Windows
+//#define ADVANCE_SOUND 12 // 1 second
+#define ADVANCE_SOUND 18 // 1 1/2 second
+//#define MAX_ADVANCE_SOUND 36 // 3 seconds
+#else
+#define ADVANCE_SOUND 18 // 1 1/2 seconds
+#endif
+#define SUBSEQUENT_SOUND 6 // 1/2 second
+
+
+
+// PACKET TYPE IDs & FLAGS
+
+#define CD_SLOT_NOP 0x00 // Skip to next slot
+#define CD_LE_FIN 0x01 // End of movie
+#define CD_PDELTA 0x02 // Image compressed to previous one
+#define CD_SDELTA 0x03 // Image self-compressed
+
+#define BIT0 0x01
+
+#define CD_XSCR 0x04 // Screen has a scroll offset
+#define CD_CMAP 0x08 // Colour map is included
+#define CD_CMND 0x10 // Command is included
+#define CD_AUDIO 0x20 // Audio data is included
+#define CD_EXTEND 0x40 // Extended modes "A"-"z"
+#define CD_PRINT 0x80 // goes in conjunction with CD_CMD
+
+// Data field sizes
+#define sz_XSCR_pkt 2
+#define sz_CMAP_pkt 0x300
+#define sz_CMD_TALK_pkt 10
+#define sz_CMD_PRINT_pkt 8
+#define sz_AUDIO_pkt 3675
+
+
+typedef struct {
+
+ short x;
+ short y;
+ short stringId;
+ unsigned char duration;
+ char r; // may be b!
+ char g;
+ char b; // may be r!
+
+} TALK_CMD, *PTALK_CMD;
+
+typedef struct {
+
+ short x;
+ short y;
+ short stringId;
+ unsigned char duration;
+ unsigned char fontId;
+
+} PRINT_CMD, *PPRINT_CMD;
+
+
+//----------------- LOCAL GLOBAL DATA ------------------------
+
+// Set when a movie is on
+static bool bMovieOn;
+
+// Set to kill one off
+static bool bAbort;
+
+// For escaping out of movies
+static int bmvEscape;
+
+// Movie file pointer
+static Common::File stream;
+
+// Movie file name
+static char szMovieFile[14];
+
+// Pointers to buffers
+static byte *bigBuffer; //, *screenBuffer;
+
+// Next data to use to extract a frame
+static int nextUseOffset;
+
+// Next data to use to extract sound data
+static int nextSoundOffset;
+
+// When above offset gets to what this is set at, rewind
+static int wrapUseOffset;
+
+// The offset of the most future packet
+static int mostFutureOffset;
+
+// The current frame
+static int currentFrame;
+static int currentSoundFrame;
+
+// Number of packets currently in RAM
+static int numAdvancePackets;
+
+// Next slot that will be read from disc
+static int nextReadSlot;
+
+// Set when the whole file has been read
+static bool bFileEnd;
+
+// Palette
+static COLORREF moviePal[256];
+
+static int blobsInBuffer;
+
+static struct {
+
+ POBJECT pText;
+ int dieFrame;
+
+} texts[2];
+
+static COLORREF talkColour;
+
+static int bigProblemCount;
+
+static bool bIsText;
+
+static int movieTick;
+static int startTick;
+static uint32 nextMovieTime = 0;
+
+static int nowTick;
+
+static uint16 Au_Prev1 = 0;
+static uint16 Au_Prev2 = 0;
+static byte *ScreenBeg;
+static byte *screenBuffer;
+
+static bool audioStarted;
+
+static Audio::AppendableAudioStream *audioStream = 0;
+static Audio::SoundHandle audioHandle;
+
+const uint16 Au_DecTable[16] = {16512, 8256, 4128, 2064, 1032, 516, 258, 192,
+ 129, 88, 64, 56, 48, 40, 36, 32};
+
+//---------------- DECOMPRESSOR FUNCTIONS --------------------
+
+#define SCREEN_WIDE 640
+#define SCREEN_HIGH 429
+#define SAM_P_BLOB (32 * 2)
+
+#define ROR(x,v) x = ((x >> (v%32)) | (x << (32 - (v%32))));
+#define ROL(x,v) x = ((x << (v%32)) | (x >> (32 - (v%32))));
+#define NEXT_BYTE(v) v = forwardDirection ? v + 1 : v - 1;
+
+static void PrepBMV(const byte *sourceData, int length, short deltaFetchDisp) {
+ uint8 NibbleHi = 0;
+ const byte *saved_esi;
+ uint32 eax = 0;
+ uint32 edx = length;
+ int32 ebx = deltaFetchDisp;
+ uint32 ecx = 0;
+ const byte *esi;
+ byte *edi, *ebp;
+
+ bool forwardDirection = (deltaFetchDisp <= -SCREEN_WIDE) || (deltaFetchDisp >= 0);
+ if (forwardDirection) {
+ // Forward decompression
+ esi = sourceData;
+ edi = ScreenBeg;
+ ebp = ScreenBeg + SCREEN_WIDE * SCREEN_HIGH;
+ } else {
+ esi = sourceData + length - 1;
+ edi = ScreenBeg + SCREEN_WIDE * SCREEN_HIGH - 1;
+ ebp = ScreenBeg - 1;
+ }
+
+ bool firstLoop, flag;
+
+ int loopCtr = 0;
+ for (;;) {
+ flag = false;
+
+ if ((loopCtr == 0) || (edx == 4)) {
+ // Get the next hi,lo nibble
+ eax = (eax & 0xffffff00) | *esi;
+ firstLoop = true;
+ } else {
+ // Get the high nibble
+ eax = eax & 0xffffff00 | (NibbleHi >> 4);
+ firstLoop = false;
+ }
+
+ // Is lo nibble '00xx'?
+ if ((eax & 0xC) == 0) {
+ for (;;) {
+//@_rDN_Lp_1:
+ // Only execute this bit first the first time into the loop
+ if (!firstLoop) {
+ ROR(eax, 2);
+ ecx += 2;
+ eax = (eax & 0xffffff00) | *esi;
+
+ if ((eax & 0xC) != 0)
+ break;
+ }
+ firstLoop = false;
+
+//@_rD2nd_1:
+ ROR(eax, 2); // Save bi-bit into hi 2 bits
+ ecx += 2; // and increase bit-shifter
+ // Shift another 2 bits to get hi nibble
+ eax = (eax & 0xffffff00) | ((eax & 0xff) >> 2);
+ NEXT_BYTE(esi);
+
+ if ((eax & 0xC) != 0) {
+ flag = true;
+ ROL(eax, ecx);
+ break;
+ }
+ }
+ } else if (loopCtr != 0) {
+ flag = edx != 4;
+ }
+
+ if (flag) {
+//@_rdNum__1:
+ edx = 4; // offset rDNum_Lo ; Next nibble is a 'lo'
+ } else {
+// @_rDNum_1
+ NibbleHi = (uint8)eax;
+ edx = 0; // offset rDNum_Hi ; Next nibble is a 'hi' (reserved)
+ eax &= 0xffffff0f;
+ NEXT_BYTE(esi);
+ ROL(eax, ecx);
+ }
+//rDN_1:
+//@_rD_or_R:
+ bool actionFlag = (eax & 1) != 0;
+ eax >>= 1;
+ ecx = eax - 1;
+
+ // Move to next loop index
+ if (++loopCtr == 4) loopCtr = 1;
+
+ if (actionFlag) {
+ // Adjust loopCtr to fall into the correct processing case
+ loopCtr = loopCtr % 3 + 1;
+ }
+
+ switch (loopCtr) {
+ case 1:
+ // @_rDelta:
+ saved_esi = esi; // Save the source pointer
+ esi = edi + ebx; // Point it to existing data
+
+ while (ecx > 0) {
+ *edi = *esi;
+ NEXT_BYTE(esi);
+ NEXT_BYTE(edi);
+ --ecx;
+ }
+
+ esi = saved_esi;
+ break;
+
+ case 2:
+ // @_rRaw
+ // Copy data from source to dest
+ while (ecx > 0) {
+ *edi = *esi;
+ NEXT_BYTE(esi);
+ NEXT_BYTE(edi);
+ --ecx;
+ }
+ break;
+
+ case 3:
+ // @_rRun
+ // Repeating run of data
+ eax = forwardDirection ? *(edi - 1) : *(edi + 1);
+
+ while (ecx > 0) {
+ *edi = (uint8)eax;
+ NEXT_BYTE(edi);
+ --ecx;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (edi == ebp)
+ break; // Exit if complete
+
+ eax = 0;
+ }
+}
+
+static void InitBMV(byte *memoryBuffer) {
+ // Clear the two extra 'off-screen' rows
+ memset(memoryBuffer, 0, SCREEN_WIDE);
+ memset(memoryBuffer + SCREEN_WIDE * (SCREEN_HIGH + 1), 0, SCREEN_WIDE);
+
+ if (audioStream) {
+ _vm->_mixer->stopHandle(audioHandle);
+
+ delete audioStream;
+ audioStream = 0;
+ }
+
+ // Set the screen beginning to the second line (ie. past the off-screen line)
+ ScreenBeg = memoryBuffer + SCREEN_WIDTH;
+ Au_Prev1 = Au_Prev2 = 0;
+}
+
+void PrepAudio(const byte *sourceData, int blobCount, byte *destPtr) {
+ uint16 dx1 = Au_Prev1;
+ uint16 dx2 = Au_Prev2;
+
+ uint16 *destP = (uint16 *) destPtr;
+ int8 *srcP = (int8 *) sourceData;
+
+ // Blob Loop
+ while (blobCount-- > 0) {
+ uint32 ebx = (uint8) *srcP++;
+ uint32 ebp = ebx & 0x1E;
+
+ int blobSize = SAM_P_BLOB / 2;
+
+ ebx = (((ebx & 0x0F) << 4) | ((ebx & 0xF0) >> 4)) & 0x1E;
+
+ ebp = Au_DecTable[ebp >> 1];
+ ebx = Au_DecTable[ebx >> 1];
+
+ // Inner loop
+ while (blobSize-- > 0) {
+ uint32 s1 = (((int32) *srcP++) * ((int32) ebp)) >> 5;
+ uint32 s2 = (((int32) *srcP++) * ((int32) ebx)) >> 5;
+
+ dx1 += s1 & 0xFFFF;
+ dx2 += s2 & 0xFFFF;
+
+ *destP++ = TO_BE_16(dx1);
+ *destP++ = TO_BE_16(dx2);
+ }
+ }
+
+ Au_Prev1 = dx1;
+ Au_Prev2 = dx2;
+}
+
+//----------------- BMV FUNCTIONS ----------------------------
+
+static bool MaintainBuffer(void);
+
+
+/**
+ * Called when a packet contains a palette field.
+ * Build a COLORREF array and queue it to the DAC.
+ */
+static void MoviePalette(int paletteOffset) {
+ int i;
+ byte *r;
+
+ r = bigBuffer + paletteOffset;
+
+ for (i = 0; i < 256; i++, r += 3) {
+ moviePal[i] = RGB(*r, *(r + 1), *(r + 2));
+ }
+
+ UpdateDACqueue(1, 255, &moviePal[1]);
+
+ // Don't clobber talk
+ if (talkColour != 0)
+ SetTextPal(talkColour);
+}
+
+static void InitialiseMovieSound() {
+ audioStream =
+ Audio::makeAppendableAudioStream(22050,
+ Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_STEREO);
+ audioStarted = false;
+}
+
+static void StartMovieSound() {
+}
+
+static void FinishMovieSound() {
+ if (audioStream) {
+ _vm->_mixer->stopHandle(audioHandle);
+
+ delete audioStream;
+ audioStream = 0;
+ }
+}
+
+/**
+ * Called when a packet contains an audio field.
+ */
+static void MovieAudio(int audioOffset, int blobs) {
+ if (audioOffset == 0 && blobs == 0)
+ blobs = 57;
+
+ byte *data = new byte[blobs * 128];
+
+ if (audioOffset != 0)
+ PrepAudio(bigBuffer+audioOffset, blobs, data);
+ else
+ memset(data, 0, blobs * 128);
+
+ audioStream->queueBuffer(data, blobs * 128);
+
+ if (currentSoundFrame == ADVANCE_SOUND) {
+ if (!audioStarted) {
+ _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType,
+ &audioHandle, audioStream, -1, Audio::Mixer::kMaxChannelVolume, 0, false);
+ audioStarted = true;
+ }
+ }
+}
+
+/*-----------------------------------------------------*\
+|-------------------------------------------------------|
+\*-----------------------------------------------------*/
+
+void FettleMovieText(void) {
+ int i;
+
+ bIsText = false;
+
+ for (i = 0; i < 2; i++) {
+ if (texts[i].pText) {
+ if (currentFrame > texts[i].dieFrame) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), texts[i].pText);
+ texts[i].pText = NULL;
+ } else {
+ MultiForceRedraw(texts[i].pText);
+ bIsText = true;
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------*\
+|-------------------------------------------------------|
+\*-----------------------------------------------------*/
+
+void BmvDrawText(bool bDraw) {
+ int w, h, x, y;
+
+ for (int i = 0; i < 2; i++) {
+ if (texts[i].pText) {
+ x = MultiLeftmost(texts[i].pText);
+ y = MultiHighest(texts[i].pText);
+ w = MIN(MultiRightmost(texts[i].pText) + 1, (int)SCREEN_WIDTH) - x;
+ h = MIN(MultiLowest(texts[i].pText) + 1, SCREEN_HIGH) - y;
+
+ const byte *src = ScreenBeg + (y * SCREEN_WIDTH) + x;
+ byte *dest = (byte *)_vm->screen().getBasePtr(x, y);
+
+ for (int j = 0; j < h; j++, dest += SCREEN_WIDTH, src += SCREEN_WIDTH) {
+ memcpy(dest, src, w);
+ }
+
+ if (bDraw) {
+ Common::Point ptWin;
+ Common::Rect rcPlayClip;
+
+ ptWin.x = ptWin.y = 0;
+ rcPlayClip.left = x;
+ rcPlayClip.top = y;
+ rcPlayClip.right = x+w;
+ rcPlayClip.bottom = y+h;
+ UpdateClipRect(GetPlayfieldList(FIELD_STATUS), &ptWin, &rcPlayClip);
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------*\
+|-------------------------------------------------------|
+\*-----------------------------------------------------*/
+
+void MovieText(CORO_PARAM, int stringId, int x, int y, int fontId, COLORREF *pTalkColour, int duration) {
+ SCNHANDLE hFont;
+ int index;
+
+ if (fontId == 1) {
+ // It's a 'print'
+
+ hFont = GetTagFontHandle();
+ index = 0;
+ } else {
+ // It's a 'talk'
+
+ if (pTalkColour != NULL)
+ SetTextPal(*pTalkColour);
+ hFont = GetTalkFontHandle();
+ index = 1;
+ }
+
+ if (texts[index].pText)
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), texts[index].pText);
+
+ LoadSubString(stringId, 0, TextBufferAddr(), TBUFSZ);
+
+ texts[index].dieFrame = currentFrame + duration;
+ texts[index].pText = ObjectTextOut(coroParam, GetPlayfieldList(FIELD_STATUS),
+ TextBufferAddr(),
+ 0,
+ x, y,
+ hFont,
+ TXT_CENTRE, 0);
+ KeepOnScreen(texts[index].pText, &x, &y);
+}
+
+/**
+ * Called when a packet contains a command field.
+ */
+static int MovieCommand(char cmd, int commandOffset) {
+ if (cmd & CD_PRINT) {
+ PPRINT_CMD pCmd;
+
+ pCmd = (PPRINT_CMD)(bigBuffer + commandOffset);
+
+ MovieText(nullContext, pCmd->stringId,
+ pCmd->x,
+ pCmd->y,
+ pCmd->fontId,
+ NULL,
+ pCmd->duration);
+
+ return sz_CMD_PRINT_pkt;
+ } else {
+ if (bSubtitles) {
+ PTALK_CMD pCmd;
+
+ pCmd = (PTALK_CMD)(bigBuffer + commandOffset);
+ talkColour = RGB(pCmd->r, pCmd->g, pCmd->b);
+
+ MovieText(nullContext, pCmd->stringId,
+ pCmd->x,
+ pCmd->y,
+ 0,
+ &talkColour,
+ pCmd->duration);
+ }
+ return sz_CMD_TALK_pkt;
+ }
+}
+
+/**
+ * Called from PlayMovie() in tinlib.cpp
+ * Kicks off the playback of a movie, and waits around
+ * until it's finished.
+ */
+void PlayBMV(CORO_PARAM, SCNHANDLE hFileStem, int myEscape) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ assert(!bMovieOn);
+
+ strcpy(szMovieFile, (char *)LockMem(hFileStem));
+ strcat(szMovieFile, BMOVIE_EXTENSION);
+
+ assert(strlen(szMovieFile) <= 12);
+
+ bMovieOn = true;
+ bAbort = false;
+ bmvEscape = myEscape;
+
+ do {
+ CORO_SLEEP(1);
+ } while (bMovieOn);
+
+ CORO_END_CODE;
+}
+
+/**
+ * Given a packet offset, calculates the offset of the
+ * next packet. The packet may not yet exist, and the
+ *return value may be off the end of bigBuffer.
+ */
+static int FollowingPacket(int thisPacket, bool bReallyImportant) {
+ unsigned char *data;
+ int nextSlot, length;
+
+ // Set pointer to thisPacket's data
+ data = bigBuffer + thisPacket;
+
+ switch (*data) {
+ case CD_SLOT_NOP:
+ nextSlot = thisPacket/SLOT_SIZE;
+ if (thisPacket%SLOT_SIZE)
+ nextSlot++;
+
+ return nextSlot * SLOT_SIZE;
+
+ case CD_LE_FIN:
+ return -1;
+
+ default:
+ // Following 3 bytes are the length
+ if (bReallyImportant) {
+ // wrapped round or at least 3 bytes
+ assert(((nextReadSlot * SLOT_SIZE) < thisPacket) ||
+ ((thisPacket + 3) < (nextReadSlot * SLOT_SIZE)));
+
+ if ((nextReadSlot * SLOT_SIZE >= thisPacket) &&
+ ((thisPacket + 3) >= nextReadSlot*SLOT_SIZE)) {
+ // MaintainBuffer calls this back, but with false
+ MaintainBuffer();
+ }
+ } else {
+ // not wrapped and not 3 bytes
+ if (nextReadSlot*SLOT_SIZE >= thisPacket && thisPacket+3 >= nextReadSlot*SLOT_SIZE)
+ return thisPacket + 3;
+ }
+ length = *(int32 *)(bigBuffer + thisPacket + 1);
+ length &= 0x00ffffff;
+ return thisPacket + length + 4;
+ }
+}
+
+/**
+ * Called from the foreground when starting playback of a movie.
+ */
+static void LoadSlots(int number) {
+ int nextOffset;
+
+ assert(number + nextReadSlot < NUM_SLOTS);
+
+ if (stream.read(bigBuffer + nextReadSlot*SLOT_SIZE, number * SLOT_SIZE) !=
+ (uint32)(number * SLOT_SIZE)) {
+ int possibleSlots;
+
+ // May be a short file
+ possibleSlots = stream.size() / SLOT_SIZE;
+ if ((number + nextReadSlot) > possibleSlots) {
+ bFileEnd = true;
+ nextReadSlot = possibleSlots;
+ } else
+ error(FILE_IS_CORRUPT, szMovieFile);
+ }
+
+ nextReadSlot += number;
+
+ nextOffset = FollowingPacket(nextUseOffset, true);
+ while (nextOffset < nextReadSlot*SLOT_SIZE
+ && nextOffset != -1) {
+ numAdvancePackets++;
+ mostFutureOffset = nextOffset;
+ nextOffset = FollowingPacket(mostFutureOffset, false);
+ }
+}
+
+/**
+ * Called from the foreground when starting playback of a movie.
+ */
+static void InitialiseBMV(void) {
+ if (!stream.open(szMovieFile))
+ error(CANNOT_FIND_FILE, szMovieFile);
+
+ // Grab the data buffer
+ bigBuffer = (byte *)malloc(NUM_SLOTS * SLOT_SIZE);
+ if (bigBuffer == NULL)
+ error(NO_MEM, "FMV data buffer\n");
+
+ // Screen buffer (2 lines more than screen
+ screenBuffer = (byte *)malloc(SCREEN_WIDTH * (SCREEN_HIGH + 2));
+ if (screenBuffer == NULL)
+ error(NO_MEM, "FMV screen buffer\n");
+
+ // Pass the sceen buffer to the decompresser
+ InitBMV(screenBuffer);
+
+ // Initialise some stuff
+ nextUseOffset = 0;
+ nextSoundOffset = 0;
+ wrapUseOffset = -1;
+ mostFutureOffset = 0;
+ currentFrame = 0;
+ currentSoundFrame = 0;
+ numAdvancePackets = 0;
+ nextReadSlot = 0;
+ bFileEnd = false;
+ blobsInBuffer = 0;
+ memset(texts, 0, sizeof(texts));
+ talkColour = 0;
+ bigProblemCount = 0;
+
+ movieTick = 0;
+
+ bIsText = false;
+
+// memset(&rr, 0, sizeof(rr));
+
+ // Prefetch data
+ LoadSlots(PREFETCH);
+
+ while (numAdvancePackets < ADVANCE_SOUND)
+ LoadSlots(1);
+
+ // Initialise the sound channel
+ InitialiseMovieSound();
+}
+
+/**
+ * Called from the foreground when ending playback of a movie.
+ */
+void FinishBMV(void) {
+ int i;
+
+ // Notify the sound channel
+ FinishMovieSound();
+
+ // Close the file stream
+ if (stream.isOpen())
+ stream.close();
+
+ // Release the data buffer
+ if (bigBuffer != NULL) {
+ free(bigBuffer);
+ bigBuffer = NULL;
+ }
+
+ // Release the screen buffer
+ if (screenBuffer != NULL) {
+ free(screenBuffer);
+ screenBuffer = NULL;
+ }
+
+ // Ditch any text objects
+ for (i = 0; i < 2; i++) {
+ if (texts[i].pText) {
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), texts[i].pText);
+ texts[i].pText = NULL;
+ }
+ }
+ bMovieOn = false;
+
+ nextMovieTime = 0;
+
+ // Test for 'twixt-movie glitch
+ ClearScreen();
+}
+
+/**
+ * MaintainBuffer()
+ */
+static bool MaintainBuffer(void) {
+ int nextOffset;
+
+ // No action if the file is all read
+ if (bFileEnd == true)
+ return false;
+
+ // See if next complete packet exists
+ // and if so, if it will fit in the top of the buffer
+ nextOffset = FollowingPacket(mostFutureOffset, false);
+ if (nextOffset == -1) {
+ // No following packets
+ return false;
+ } else if (nextOffset > NUM_SLOTS * SLOT_SIZE) {
+ // The current unfinished packet will not fit
+ // Copy this slot to slot 0
+
+ // Not if we're still using it!!!
+ // Or, indeed, if the player is still lagging
+ if (nextUseOffset < SLOT_SIZE || nextUseOffset > mostFutureOffset) {
+ // Slot 0 is still in use, buffer is full!
+ return false;
+ }
+
+ // Tell data player where to make the jump
+ wrapUseOffset = mostFutureOffset;
+
+ // mostFuture Offset is now in slot 0
+ mostFutureOffset %= SLOT_SIZE;
+
+ // Copy the data we already have for unfinished packet
+ memcpy(bigBuffer + mostFutureOffset,
+ bigBuffer + wrapUseOffset,
+ SLOT_SIZE - mostFutureOffset);
+
+ // Next read is into slot 1
+ nextReadSlot = 1;
+ }
+
+ if (nextReadSlot == NUM_SLOTS) {
+ // Want to go to slot zero, wait if still in use
+ if (nextUseOffset < SLOT_SIZE) {
+ // Slot 0 is still in use, buffer is full!
+ return false;
+ }
+
+ // nextOffset must be the buffer size
+ assert(nextOffset == NUM_SLOTS*SLOT_SIZE);
+
+ // wrapUseOffset must not be set
+ assert(wrapUseOffset == -1);
+ wrapUseOffset = nextOffset;
+
+ nextReadSlot = 0;
+ mostFutureOffset = 0;
+ }
+
+ // Don't overwrite unused data
+ if (nextUseOffset / SLOT_SIZE == nextReadSlot) {
+ // Buffer is full!
+ return false;
+ }
+
+ if (stream.read(bigBuffer + nextReadSlot * SLOT_SIZE, SLOT_SIZE) != SLOT_SIZE) {
+ bFileEnd = true;
+ }
+
+ // Read next slot next time
+ nextReadSlot++;
+
+ // Find new mostFutureOffset
+ nextOffset = FollowingPacket(mostFutureOffset, false);
+ while (nextOffset < nextReadSlot*SLOT_SIZE
+ && nextOffset != -1) {
+ numAdvancePackets++;
+ mostFutureOffset = nextOffset;
+ nextOffset = FollowingPacket(mostFutureOffset, false);
+ }
+
+ // New test feature for e.g. short files
+ if (bFileEnd && *(bigBuffer+mostFutureOffset) != CD_LE_FIN)
+ bAbort = true;
+
+ return true;
+}
+
+/**
+ * DoBMVFrame
+ */
+static bool DoBMVFrame(void) {
+ unsigned char *data;
+ int graphOffset, length;
+ signed short xscr;
+
+ if (nextUseOffset == wrapUseOffset) {
+ nextUseOffset %= SLOT_SIZE;
+ }
+
+ while (nextUseOffset == mostFutureOffset) {
+ data = bigBuffer + nextUseOffset;
+ if (*data != CD_LE_FIN) {
+ // Don't get stuck in an infinite loop
+ if (!MaintainBuffer()) {
+ FinishBMV();
+ return false;
+ }
+
+ if (nextUseOffset == wrapUseOffset) {
+ nextUseOffset %= SLOT_SIZE;
+ }
+ } else
+ break;
+ }
+
+ // Set pointer to data
+ data = bigBuffer + nextUseOffset;
+
+ // If still at most Future, it must be last
+ if (nextUseOffset == mostFutureOffset) {
+ assert(*data == CD_LE_FIN);
+ }
+
+ switch (*data) {
+ case CD_SLOT_NOP:
+ nextUseOffset = FollowingPacket(nextUseOffset, true);
+ if (nextUseOffset == wrapUseOffset) {
+ nextUseOffset %= SLOT_SIZE;
+ wrapUseOffset = -1;
+ }
+ numAdvancePackets--;
+ return false;
+
+ case CD_LE_FIN:
+ FinishBMV();
+ numAdvancePackets--;
+ return true;
+
+ default:
+ length = *(int *)(data + 1);
+ length &= 0x00ffffff;
+
+ graphOffset = nextUseOffset + 4; // Skip command byte and length
+
+ if (*data & CD_AUDIO) {
+ if (bOldAudio) {
+ graphOffset += sz_AUDIO_pkt; // Skip audio data
+ length -= sz_AUDIO_pkt;
+ } else {
+ int blobs;
+
+ blobs = *(bigBuffer + graphOffset);
+ blobs *= SZ_C_BLOB;
+ graphOffset += (blobs + 1);
+ length -= (blobs + 1);
+ }
+ }
+
+ if (*data & CD_CMND) {
+ int cmdLen;
+
+ // Process command and skip data
+ cmdLen = MovieCommand(*data, graphOffset);
+
+ graphOffset += cmdLen;
+ length -= cmdLen;
+ }
+
+ if (*data & CD_CMAP) {
+ MoviePalette(graphOffset);
+ graphOffset += sz_CMAP_pkt; // Skip palette data
+ length -= sz_CMAP_pkt;
+ }
+
+ if (*data & CD_XSCR) {
+ xscr = *(signed short *)(bigBuffer + graphOffset);
+ graphOffset += sz_XSCR_pkt; // Skip scroll offset
+ length -= sz_XSCR_pkt;
+ } else if (*data & BIT0)
+ xscr = -640;
+ else
+ xscr = 0;
+
+ PrepBMV(bigBuffer + graphOffset, length, xscr);
+
+ currentFrame++;
+ numAdvancePackets--;
+
+ nextUseOffset = FollowingPacket(nextUseOffset, true);
+ if (nextUseOffset == wrapUseOffset) {
+ nextUseOffset %= SLOT_SIZE;
+ wrapUseOffset = -1;
+ }
+ return true;
+ }
+}
+
+/**
+ * DoSoundFrame
+ */
+static bool DoSoundFrame(void) {
+ unsigned char *data;
+ int graphOffset;
+
+ if (nextSoundOffset == wrapUseOffset) {
+ nextSoundOffset %= SLOT_SIZE;
+ }
+
+ // Make sure the full slot is here
+ while (nextSoundOffset == mostFutureOffset) {
+ data = bigBuffer + nextSoundOffset;
+ if (*data != CD_LE_FIN) {
+ // Don't get stuck in an infinite loop
+ if (!MaintainBuffer()) {
+ if (!bOldAudio)
+ MovieAudio(0, 0);
+ currentSoundFrame++;
+ return false;
+ }
+
+ if (nextSoundOffset == wrapUseOffset) {
+ nextSoundOffset %= SLOT_SIZE;
+ }
+ } else
+ break;
+ }
+
+ // Set pointer to data
+ data = bigBuffer + nextSoundOffset;
+
+ // If still at most Future, it must be last
+ if (nextSoundOffset == mostFutureOffset) {
+ assert(*data == CD_LE_FIN);
+ }
+
+ switch (*data) {
+ case CD_SLOT_NOP:
+ nextSoundOffset = FollowingPacket(nextSoundOffset, true);
+ if (nextSoundOffset == wrapUseOffset) {
+ nextSoundOffset %= SLOT_SIZE;
+ }
+ return false;
+
+ case CD_LE_FIN:
+ if (!bOldAudio)
+ MovieAudio(0, 0);
+ currentSoundFrame++;
+ return true;
+
+ default:
+ if (*data & CD_AUDIO) {
+ graphOffset = nextSoundOffset + 4; // Skip command byte and length
+
+ if (!bOldAudio) {
+ int blobs = *(bigBuffer + graphOffset);
+ MovieAudio(graphOffset+1, blobs);
+ }
+ } else {
+ if (!bOldAudio)
+ MovieAudio(0, 0);
+ }
+
+ nextSoundOffset = FollowingPacket(nextSoundOffset, false);
+ if (nextSoundOffset == wrapUseOffset) {
+ nextSoundOffset %= SLOT_SIZE;
+ }
+ currentSoundFrame++;
+ return true;
+ }
+
+ return true;
+}
+
+/**
+ * CopyMovieToScreen
+ */
+void CopyMovieToScreen(void) {
+ // Not if not up and running yet!
+ if (!screenBuffer || (currentFrame == 0)) {
+ ForceEntireRedraw();
+ DrawBackgnd();
+ return;
+ }
+
+ // The movie surface is slightly less high than the output screen (429 rows versus 432).
+ // Because of this, there's some extra line clearing above and below the displayed area
+ int yStart = (SCREEN_HEIGHT - SCREEN_HIGH) / 2;
+ memset(_vm->screen().getBasePtr(0, 0), 0, yStart * SCREEN_WIDTH);
+ memcpy(_vm->screen().getBasePtr(0, yStart), ScreenBeg, SCREEN_WIDTH * SCREEN_HIGH);
+ memset(_vm->screen().getBasePtr(0, yStart + SCREEN_HIGH), 0,
+ (SCREEN_HEIGHT - SCREEN_HIGH - yStart) * SCREEN_WIDTH);
+
+ BmvDrawText(true);
+ PalettesToVideoDAC(); // Keep palette up-to-date
+ UpdateScreenRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+ BmvDrawText(false);
+}
+
+/**
+ * LookAtBuffers
+ */
+static void LookAtBuffers(void) {
+ static int junk;
+ int i;
+
+ if (bigBuffer) {
+ for (i = 0; i < NUM_SLOTS; i++)
+ junk += bigBuffer[i*SLOT_SIZE];
+ }
+}
+
+/**
+ * Handles playback of any active movie. Called from the foreground 24 times a second.
+ */
+void FettleBMV(void) {
+ static int nextMaintain = 0;
+
+ int refFrame;
+ // Tick counter needs to be incrementing at a 24Hz rate
+ int tick = movieTick++;
+
+ if (!bMovieOn)
+ return;
+
+ // Escape the rest if appropriate
+ if (bAbort || (bmvEscape && bmvEscape != GetEscEvents())) {
+ FinishBMV();
+ return;
+ }
+
+ LookAtBuffers();
+
+ if (!stream.isOpen()) {
+ int i;
+
+ // First time in with this movie
+
+ InitialiseBMV();
+
+ for (i = 0; i < ADVANCE_SOUND;) {
+ if (DoSoundFrame())
+ i++;
+ }
+ startTick = -ONE_SECOND / 4; // 1/4 second
+ return;
+ }
+
+ if (startTick < 0) {
+ startTick++;
+ return;
+ }
+ if (startTick == 0) {
+ startTick = tick;
+ nextMaintain = startTick + 1;
+ StartMovieSound();
+ }
+
+ nextMovieTime = g_system->getMillis() + 41;
+
+ FettleMovieText();
+
+ if (bigProblemCount < PT_A) {
+ refFrame = currentSoundFrame;
+
+ while (currentSoundFrame < ((tick+1-startTick)/2 + ADVANCE_SOUND) && bMovieOn) {
+ if (currentSoundFrame == refFrame+PT_B)
+ break;
+
+ DoSoundFrame();
+ }
+ }
+
+ // Time to process a frame (or maybe more)
+ if (bigProblemCount < PT_A) {
+ refFrame = currentFrame;
+
+ while ((currentFrame < (tick-startTick)/2) && bMovieOn) {
+ DoBMVFrame();
+
+ if (currentFrame == refFrame+PT_B) {
+ bigProblemCount++;
+
+ if (bigProblemCount == PT_A) {
+ startTick = tick-(2*currentFrame);
+ bigProblemCount = 0;
+ }
+ break;
+ }
+ }
+ if (currentFrame == refFrame || currentFrame <= refFrame+3) {
+ bigProblemCount = 0;
+ }
+ } else {
+ while (currentFrame < (tick-startTick)/2 && bMovieOn) {
+ DoBMVFrame();
+ }
+ }
+
+ if (tick >= nextMaintain || numAdvancePackets < SUBSEQUENT_SOUND) {
+ MaintainBuffer();
+ nextMaintain = tick + 2;
+ }
+}
+
+/**
+ * Returns true if a movie is playing.
+ */
+bool MoviePlaying(void) {
+ return bMovieOn;
+}
+
+/**
+ * Returns the audio lag in ms
+ */
+int32 MovieAudioLag(void) {
+ if (!bMovieOn || !audioStream)
+ return 0;
+
+ // Calculate lag
+ int32 playLength = (movieTick - startTick - 1) * ((((uint32) 1000) << 10) / 24);
+ return (playLength - (audioStream->getTotalPlayTime() << 10)) >> 10;
+}
+
+uint32 NextMovieTime(void) {
+ return nextMovieTime;
+}
+
+void AbortMovie(void) {
+ bAbort = true;
+}
+
+void SlowMovieDown(void) {
+ bigProblemCount = 0;
+
+ if (currentFrame < (nowTick-startTick)/2 && bMovieOn) {
+ startTick = nowTick - 2*currentFrame;
+ } else
+ startTick += 2;
+}
+
+void SpeedMovieUp(void) {
+ if (!bigProblemCount) {
+ startTick -= 2;
+ }
+}
+
+} // end of namespace Tinsel
Property changes on: scummvm/trunk/engines/tinsel/bmv.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Modified: scummvm/trunk/engines/tinsel/config.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/config.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/config.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -24,6 +24,8 @@
* This file contains configuration functionality
*/
+//#define USE_3FLAGS 1
+
#include "tinsel/config.h"
#include "tinsel/dw.h"
#include "tinsel/sound.h"
@@ -39,7 +41,7 @@
//----------------- GLOBAL GLOBAL DATA --------------------
int dclickSpeed = DOUBLE_CLICK_TIME;
-int volMidi = Audio::Mixer::kMaxChannelVolume;
+int volMusic = Audio::Mixer::kMaxChannelVolume;
int volSound = Audio::Mixer::kMaxChannelVolume;
int volVoice = Audio::Mixer::kMaxChannelVolume;
int speedText = DEFTEXTSPEED;
@@ -49,21 +51,18 @@
int bAmerica = 0;
-// Shouldn't really be here, but time is short...
-bool bNoBlocking;
/**
* Write settings to config manager and flush the config file to disk.
*/
void WriteConfig(void) {
ConfMan.setInt("dclick_speed", dclickSpeed);
- ConfMan.setInt("music_volume", volMidi);
+ ConfMan.setInt("music_volume", volMusic);
ConfMan.setInt("sfx_volume", volSound);
ConfMan.setInt("speech_volume", volVoice);
ConfMan.setInt("talkspeed", (speedText * 255) / 100);
ConfMan.setBool("subtitles", bSubtitles);
//ConfMan.setBool("swap_buttons", bSwapButtons ? 1 : 0);
- //ConfigData.bAmerica = bAmerica; // EN_USA / EN_GRB
// Store language for multilingual versions
if ((_vm->getFeatures() & GF_USE_3FLAGS) || (_vm->getFeatures() & GF_USE_4FLAGS) || (_vm->getFeatures() & GF_USE_5FLAGS)) {
@@ -92,16 +91,14 @@
ConfMan.flushToDisk();
}
-/*---------------------------------------------------------------------*\
-| ReadConfig() |
-|-----------------------------------------------------------------------|
-|
-\*---------------------------------------------------------------------*/
+/**
+ * Read configuration settings from the config file into memory
+ */
void ReadConfig(void) {
if (ConfMan.hasKey("dclick_speed"))
dclickSpeed = ConfMan.getInt("dclick_speed");
- volMidi = ConfMan.getInt("music_volume");
+ volMusic = ConfMan.getInt("music_volume");
volSound = ConfMan.getInt("sfx_volume");
volVoice = ConfMan.getInt("speech_volume");
Modified: scummvm/trunk/engines/tinsel/config.h
===================================================================
--- scummvm/trunk/engines/tinsel/config.h 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/config.h 2008-12-01 20:35:36 UTC (rev 35196)
@@ -37,7 +37,7 @@
};
extern int dclickSpeed;
-extern int volMidi;
+extern int volMusic;
extern int volSound;
extern int volVoice;
extern int speedText;
@@ -51,10 +51,6 @@
extern bool isJapanMode();
-
-// Shouldn't really be here, but time is short...
-extern bool bNoBlocking;
-
} // end of namespace Tinsel
#endif
Modified: scummvm/trunk/engines/tinsel/coroutine.h
===================================================================
--- scummvm/trunk/engines/tinsel/coroutine.h 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/coroutine.h 2008-12-01 20:35:36 UTC (rev 35196)
@@ -70,6 +70,7 @@
typedef CoroBaseContext *CoroContext;
+extern CoroContext nullContext;
/**
* Wrapper class which holds a pointer to a pointer to a CoroBaseContext.
@@ -101,6 +102,7 @@
#define CORO_END_CONTEXT(x) } *x = (CoroContextTag *)coroParam
#define CORO_BEGIN_CODE(x) \
+ if (&coroParam == &nullContext) assert(!nullContext);\
if (!x) {coroParam = x = new CoroContextTag();}\
assert(coroParam);\
assert(coroParam->_sleep >= 0);\
@@ -109,17 +111,22 @@
switch(coroParam->_line) { case 0:;
#define CORO_END_CODE \
+ if (&coroParam == &nullContext) nullContext = NULL; \
}
-#define CORO_SLEEP(delay) \
- do {\
+#define CORO_SLEEP(delay) do {\
coroParam->_line = __LINE__;\
coroParam->_sleep = delay;\
+ assert(&coroParam != &nullContext);\
return; case __LINE__:;\
} while (0)
+#define CORO_GIVE_WAY do { g_scheduler->giveWay(); CORO_SLEEP(1); } while (0)
+#define CORO_RESCHEDULE do { g_scheduler->reschedule(); CORO_SLEEP(1); } while (0)
+
/** Stop the currently running coroutine */
-#define CORO_KILL_SELF() do { coroParam->_sleep = -1; return; } while(0)
+#define CORO_KILL_SELF() \
+ do { if (&coroParam != &nullContext) { coroParam->_sleep = -1; } return; } while(0)
/** Invoke another coroutine */
#define CORO_INVOKE_ARGS(subCoro, ARGS) \
@@ -130,9 +137,22 @@
subCoro ARGS;\
if (!coroParam->_subctx) break;\
coroParam->_sleep = coroParam->_subctx->_sleep;\
+ assert(&coroParam != &nullContext);\
return; case __LINE__:;\
} while(1);\
} while (0)
+#define CORO_INVOKE_ARGS_V(subCoro, RESULT, ARGS) \
+ do {\
+ coroParam->_line = __LINE__;\
+ coroParam->_subctx = 0;\
+ do {\
+ subCoro ARGS;\
+ if (!coroParam->_subctx) break;\
+ coroParam->_sleep = coroParam->_subctx->_sleep;\
+ assert(&coroParam != &nullContext);\
+ return RESULT; case __LINE__:;\
+ } while(1);\
+ } while (0)
#define CORO_INVOKE_0(subCoroutine) \
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX))
@@ -140,6 +160,8 @@
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0))
#define CORO_INVOKE_2(subCoroutine, a0,a1) \
CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1))
+#define CORO_INVOKE_3(subCoroutine, a0,a1,a2) \
+ CORO_INVOKE_ARGS(subCoroutine,(CORO_SUBCTX,a0,a1,a2))
} // end of namespace Tinsel
Modified: scummvm/trunk/engines/tinsel/cursor.cpp
===================================================================
--- scummvm/trunk/engines/tinsel/cursor.cpp 2008-11-30 21:17:58 UTC (rev 35195)
+++ scummvm/trunk/engines/tinsel/cursor.cpp 2008-12-01 20:35:36 UTC (rev 35196)
@@ -34,11 +34,14 @@
#include "tinsel/film.h"
#include "tinsel/graphics.h"
#include "tinsel/handle.h"
-#include "tinsel/inventory.h"
+#include "tinsel/dialogs.h"
#include "tinsel/multiobj.h" // multi-part object defintions etc.
#include "tinsel/object.h"
#include "tinsel/pid.h"
+#include "tinsel/play.h"
#include "tinsel/sched.h"
+#include "tinsel/sysvar.h"
+#include "tinsel/text.h"
#include "tinsel/timers.h" // For ONE_SECOND constant
#include "tinsel/tinlib.h" // resetidletime()
#include "tinsel/tinsel.h" // For engine access
@@ -54,20 +57,21 @@
//----------------- LOCAL GLOBAL DATA --------------------
-static OBJECT *McurObj = 0; // Main cursor object
-static OBJECT *AcurObj = 0; // Auxiliary cursor object
+static OBJECT *McurObj = NULL; // Main cursor object
+static OBJECT *AcurObj = NULL; // 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 bHiddenCursor = false; // Set when cursor is hidden
static bool bTempNoTrailers = false; // Set when cursor trails are hidden
+static bool bTempHide = false; // Set when cursor is 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 SCNHANDLE hCursorFilm = 0; // Handle to cursor reel data
static int numTrails = 0;
static int nextTrail = 0;
@@ -76,8 +80,11 @@
// - 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 uint16 restart = 0; // When main cursor has been bWhoa-ed, it waits
+ // for this to be set to 0x8000.
+ // Main cursor sets all the bits after a re-start
+ // - each cursor trail examines it's own bit
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list