aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/actors.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tinsel/actors.cpp')
-rw-r--r--engines/tinsel/actors.cpp1135
1 files changed, 978 insertions, 157 deletions
diff --git a/engines/tinsel/actors.cpp b/engines/tinsel/actors.cpp
index c2f01added..c151bdac9b 100644
--- a/engines/tinsel/actors.cpp
+++ b/engines/tinsel/actors.cpp
@@ -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 @@ namespace Tinsel {
#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,27 +97,46 @@ struct ACTORINFO {
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;
+};
+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 = 0;
+static ACTORINFO *actorInfo = NULL;
static COLORREF defaultColour = 0; // Text colour
@@ -109,6 +144,18 @@ 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 @@ void RegisterActors(int num) {
// 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 @@ void RegisterActors(int num) {
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 @@ void FreeActors() {
* 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,40 +214,83 @@ void setleadid(int leadID) {
/**
* 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 @@ static void ActorRestoredProcess(CORO_PARAM, const void *param) {
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 @@ void RestoreActorProcess(int id, INT_CONTEXT *pic) {
* @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 @@ void actorEvent(int ano, USER_EVENT event, BUTEVENT be) {
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 @@ void StartActor(const ACTOR_STRUC *as, bool bRunScript) {
// 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 @@ void StartActor(const ACTOR_STRUC *as, bool bRunScript) {
* @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 @@ void StartActors(SCNHANDLE ah, int numActors, bool bRunScript) {
* 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
- actorInfo[i].talkFilm = 0;
- actorInfo[i].latestFilm = 0;
- actorInfo[i].playFilm = 0;
- actorInfo[i].talking = false;
+ for (int i = 0; i < NumActors; i++) {
+ if (TinselV2) {
+ // Save text colour
+ COLORREF tColour = actorInfo[i].textColour;
+
+ 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 @@ void DropActors(void) {
* @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 @@ void EnableActor(int ano) {
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 @@ void EnableActor(int ano) {
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 @@ void FirstTaggedActor(void) {
* 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 @@ int NextTaggedActor(void) {
}
/**
+ * 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 @@ int32 actorMaskType(int ano) {
* @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 GetActorPos(int ano, int *x, int *y) {
*/
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 @@ void GetActorMidTop(int ano, int *x, int *y) {
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 GetActorLeft(int ano) {
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);
+ }
+
+ // Tinsel 2 version
+ PMOVER pMover = GetMover(ano);
+ int i;
+ bool bIsObj;
+ int right = 0;
- return MultiRightmost(actorInfo[ano - 1].presObj);
+ 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 GetActorRight(int ano) {
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,10 +942,65 @@ int GetActorTop(int ano) {
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);
+ }
+
+ // 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);
- return MultiLowest(actorInfo[ano - 1].presObj);
+ 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;
}
/**
@@ -603,18 +1008,47 @@ int GetActorBottom(int ano) {
* 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;
}
/**
@@ -623,7 +1057,7 @@ void HideActor(int ano) {
* @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 @@ bool HideMovingActor(int ano, int sf) {
pActor = GetMover(ano);
if (pActor) {
- hideMActor(pActor, sf);
+ HideMover(pActor, sf);
return true;
} else {
if (actorInfo[ano - 1].presObj != NULL)
@@ -645,7 +1079,7 @@ bool HideMovingActor(int ano, int sf) {
* @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 @@ void unHideMovingActor(int ano) {
assert(pActor); // not a moving actor
- unhideMActor(pActor);
+ UnHideMover(pActor);
}
/**
@@ -663,7 +1097,7 @@ void unHideMovingActor(int ano) {
* 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 @@ void restoreMovement(int ano) {
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 @@ void restoreMovement(int ano) {
* 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 @@ const FREEL *actorReel(int ano) {
/***************************************************************************/
-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 @@ SCNHANDLE getActorLatestFilm(int ano) {
/***************************************************************************/
-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 @@ int AsetZPos(OBJECT *pObj, int y, int32 z) {
z += z ? -1 : 0;
- zPos = y + (z << 10);
+ zPos = y + (z << ZSHIFT);
MultiSetZPosition(pObj, zPos);
return zPos;
}
@@ -809,9 +1256,18 @@ int AsetZPos(OBJECT *pObj, int y, int32 z) {
/**
* 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 @@ void storeActorAttr(int ano, int r1, int g1, int b1) {
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;
- else
+ if ((ano == -1) || !actorInfo[ano - 1].textColour)
return defaultColour;
+ else
+ 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
-
-// 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++;
+ 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) {
+
+ 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 setactorson(void) {
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