diff options
Diffstat (limited to 'engines/tinsel/actors.cpp')
-rw-r--r-- | engines/tinsel/actors.cpp | 1135 |
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 |