aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/play.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tinsel/play.cpp')
-rw-r--r--engines/tinsel/play.cpp853
1 files changed, 759 insertions, 94 deletions
diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp
index e32fc88d3d..27b2ea1bf5 100644
--- a/engines/tinsel/play.cpp
+++ b/engines/tinsel/play.cpp
@@ -26,20 +26,50 @@
#include "tinsel/actors.h"
#include "tinsel/background.h"
+#include "tinsel/coroutine.h"
#include "tinsel/dw.h"
#include "tinsel/film.h"
#include "tinsel/handle.h"
#include "tinsel/multiobj.h"
#include "tinsel/object.h"
#include "tinsel/pid.h"
+#include "tinsel/play.h"
#include "tinsel/polygons.h"
#include "tinsel/rince.h"
#include "tinsel/sched.h"
+#include "tinsel/scn.h"
+#include "tinsel/sound.h"
#include "tinsel/timers.h"
-#include "tinsel/tinlib.h" // stand()
+#include "tinsel/tinlib.h" // Stand()
namespace Tinsel {
+struct PPINIT {
+ SCNHANDLE hFilm; // The 'film'
+ int16 x; // } Co-ordinates from the play()
+ int16 y; // } - set to (-1, -1) if none.
+ int16 z; // normally 0, set if from restore
+ int16 speed; // Film speed
+ int16 actorid; // Set if called from an actor code block
+ bool splay; // Set if called from splay()
+ bool bTop; // Set if called from topplay()
+ bool bRestore;
+ int16 sf; // SlowFactor - only used for moving actors
+ int16 column; // Column number, first column = 0
+
+ uint8 escOn;
+ int32 myescEvent;
+};
+
+//----------------- LOCAL GLOBAL DATA --------------------
+
+static SOUNDREELS soundReels[MAX_SOUNDREELS];
+static int soundReelNumbers[MAX_SOUNDREELS];
+
+static int soundReelWait;
+
+//-------------------- METHODS ----------------------
+
/**
* Poke the background palette into an image.
*/
@@ -54,13 +84,30 @@ static void PokeInPalette(SCNHANDLE hMulFrame) {
// get pointer to image
pim = (IMAGE *)LockMem(READ_LE_UINT32(pFrame)); // handle to image
- pim->hImgPal = TO_LE_32(BackPal());
+ pim->hImgPal = TO_LE_32(BgPal());
}
}
+/**
+ * Poke the background palette into an image.
+ */
+void PokeInPalette(const MULTI_INIT *pmi) {
+ FRAME *pFrame; // Pointer to frame
+ IMAGE *pim; // Pointer to image
+
+ // Could be an empty column
+ if (pmi->hMulFrame) {
+ pFrame = (FRAME *)LockMem(pmi->hMulFrame);
+
+ // get pointer to image
+ pim = (IMAGE *)LockMem(*pFrame); // handle to image
+
+ pim->hImgPal = BgPal();
+ }
+}
int32 NoNameFunc(int actorID, bool bNewMover) {
- PMACTOR pActor;
+ PMOVER pActor;
int32 retval;
pActor = GetMover(actorID);
@@ -68,9 +115,9 @@ int32 NoNameFunc(int actorID, bool bNewMover) {
if (pActor != NULL && !bNewMover) {
// If no path, just use first path in the scene
if (pActor->hCpath == NOPOLY)
- retval = getPolyZfactor(FirstPathPoly());
+ retval = GetPolyZfactor(FirstPathPoly());
else
- retval = getPolyZfactor(pActor->hCpath);
+ retval = GetPolyZfactor(pActor->hCpath);
} else {
switch (actorMaskType(actorID)) {
case ACT_DEFAULT:
@@ -91,22 +138,272 @@ int32 NoNameFunc(int actorID, bool bNewMover) {
return retval;
}
-struct PPINIT {
- SCNHANDLE hFilm; // The 'film'
- int16 x; // } Co-ordinates from the play()
- int16 y; // } - set to (-1, -1) if none.
- int16 z; // normally 0, set if from restore
- int16 speed; // Film speed
- int16 actorid; // Set if called from an actor code block
- uint8 splay; // Set if called from splay()
- uint8 bTop; // Set if called from topplay()
- int16 sf; // SlowFactor - only used for moving actors
- int16 column; // Column number, first column = 0
+static FREEL *GetReel(SCNHANDLE hFilm, int column) {
+ FILM *pFilm = (FILM *)LockMem(hFilm);
- uint8 escOn;
- int32 myescEvent;
-};
+ return &pFilm->reels[column];
+}
+
+static int RegisterSoundReel(SCNHANDLE hFilm, int column, int actorCol) {
+ int i;
+
+ for (i = 0; i < MAX_SOUNDREELS; i++) {
+ // Should assert this doesn't happen, but let's be tolerant
+ if (soundReels[i].hFilm == hFilm && soundReels[i].column == column)
+ break;
+ if (!soundReels[i].hFilm)
+ {
+ soundReels[i].hFilm = hFilm;
+ soundReels[i].column = column;
+ soundReels[i].actorCol = actorCol;
+ break;
+ }
+ }
+
+ soundReelNumbers[i]++;
+ return i;
+}
+
+void NoSoundReels(void) {
+ memset(soundReels, 0, sizeof(soundReels));
+ soundReelWait = 0;
+}
+
+static void DeRegisterSoundReel(SCNHANDLE hFilm, int column) {
+ for (int i = 0; i < MAX_SOUNDREELS; i++) {
+ // Should assert this doesn't happen, but let's be tolerant
+ if (soundReels[i].hFilm == hFilm && soundReels[i].column == column) {
+ soundReels[i].hFilm = 0;
+ break;
+ }
+ }
+}
+
+void SaveSoundReels(PSOUNDREELS psr) {
+ for (int i = 0; i < MAX_SOUNDREELS; i++)
+ {
+ if (IsCdPlayHandle(soundReels[i].hFilm))
+ soundReels[i].hFilm = 0;
+ }
+
+ memcpy(psr, soundReels, sizeof(soundReels));
+}
+
+void RestoreSoundReels(PSOUNDREELS psr) {
+ memcpy(soundReels, psr, sizeof(soundReels));
+}
+
+static uint32 GetZfactor(int actorID, PMOVER pMover, bool bNewMover) {
+ if (pMover != NULL && bNewMover == false) {
+ // If no path, just use first path in the scene
+ if (pMover->hCpath == NOPOLY)
+ return GetPolyZfactor(FirstPathPoly());
+ else
+ return GetPolyZfactor(pMover->hCpath);
+ } else {
+ return GetActorZfactor(actorID);
+ }
+}
+
+/**
+ * Handles reels with sound id.
+ * @param hFilm The 'film'
+ * @param column Column number, first column = 0
+ * @param speed Film speed
+ */
+static void SoundReel(CORO_PARAM, SCNHANDLE hFilm, int column, int speed,
+ int myescEvent, int actorCol) {
+ FILM *pFilm;
+ FREEL *pReel;
+ ANI_SCRIPT *pAni;
+
+ short x, y;
+
+ CORO_BEGIN_CONTEXT;
+ int myId;
+ int myNum;
+ int frameNumber;
+ int speed;
+ int sampleNumber;
+ bool bFinished;
+ bool bLooped;
+ int reelActor;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ if (actorCol) {
+ PMULTI_INIT pmi; // MULTI_INIT structure
+
+ pReel = GetReel(hFilm, actorCol - 1);
+ pmi = (PMULTI_INIT) LockMem(pReel->mobj);
+ _ctx->reelActor = pmi->mulID;
+ } else
+ _ctx->reelActor = 0;
+
+ _ctx->frameNumber = 0;
+ _ctx->speed = speed;
+ _ctx->sampleNumber = 0;
+ _ctx->bFinished = false;
+ _ctx->bLooped = false;
+ _ctx->myId = RegisterSoundReel(hFilm, column, actorCol);
+ _ctx->myNum = soundReelNumbers[_ctx->myId];
+
+ do {
+ pFilm = (FILM *)LockMem(hFilm);
+ pReel = &pFilm->reels[column];
+
+ pAni = (ANI_SCRIPT *)LockMem(pReel->script);
+
+ if (_ctx->speed == -1) {
+ _ctx->speed = (ONE_SECOND/pFilm->frate);
+
+ // Restored reel
+ for (;;) {
+ if (pAni[_ctx->frameNumber].op == ANI_END)
+ break;
+ else if (pAni[_ctx->frameNumber].op == ANI_JUMP) {
+ _ctx->frameNumber++;
+ _ctx->frameNumber += pAni[_ctx->frameNumber].op;
+ break;
+ }
+ // Could check for the other stuff here
+ // but they really dont happen
+ // OH YES THEY DO
+ else if (pAni[_ctx->frameNumber].op == ANI_ADJUSTX
+ || pAni[_ctx->frameNumber].op == ANI_ADJUSTY) {
+ _ctx->frameNumber += 2;
+ } else if (pAni[_ctx->frameNumber].op == ANI_ADJUSTXY) {
+ _ctx->frameNumber += 3;
+ } else {
+ // ANI_STOP, ANI_HIDE, ANI_HFLIP,
+ // ANI_VFLIP, ANI_HVFLIP, default
+ _ctx->frameNumber++;
+ }
+ }
+ }
+
+ switch (pAni[_ctx->frameNumber].op) {
+ case ANI_END:
+ // Stop this sample if repeating
+ if (_ctx->sampleNumber && _ctx->bLooped)
+ _vm->_sound->stopSpecSample(_ctx->sampleNumber, 0);
+ _ctx->bFinished = true;
+ break;
+
+ case ANI_JUMP:
+ _ctx->frameNumber++;
+
+ assert(pAni[_ctx->frameNumber].op < 0);
+
+ _ctx->frameNumber += pAni[_ctx->frameNumber].op;
+
+ assert(_ctx->frameNumber >= 0);
+ continue;
+
+ case ANI_STOP:
+ // Stop this sample
+ if (_ctx->sampleNumber)
+ _vm->_sound->stopSpecSample(_ctx->sampleNumber, 0);
+ break;
+
+ case ANI_HIDE:
+ // No op
+ break;
+
+ case ANI_HFLIP:
+ case ANI_VFLIP:
+ case ANI_HVFLIP:
+ _ctx->frameNumber++;
+ continue;
+
+ case ANI_ADJUSTX:
+ case ANI_ADJUSTY:
+ _ctx->frameNumber += 2;
+ continue;
+
+ case ANI_ADJUSTXY:
+ _ctx->frameNumber += 3;
+ continue;
+
+ default:
+ // Stop this sample
+ if (_ctx->sampleNumber)
+ _vm->_sound->stopSpecSample(_ctx->sampleNumber, 0);
+
+ _ctx->sampleNumber = pAni[_ctx->frameNumber++].op;
+ if (_ctx->sampleNumber > 0)
+ _ctx->bLooped = false;
+ else {
+ _ctx->sampleNumber = ~_ctx->sampleNumber;
+ _ctx->bLooped = true;
+ }
+ x = (short)(pAni[_ctx->frameNumber].op >> 16);
+ y = (short)(pAni[_ctx->frameNumber].op & 0xffff);
+
+ if (x == 0)
+ x = -1;
+
+ _vm->_sound->playSample(_ctx->sampleNumber, 0, _ctx->bLooped, x, y, PRIORITY_SCRIPT,
+ Audio::Mixer::kSFXSoundType);
+
+ break;
+ }
+
+ CORO_SLEEP(_ctx->speed);
+ _ctx->frameNumber++;
+
+ if (_ctx->reelActor && GetActorPresFilm(_ctx->reelActor) != hFilm) {
+ // Stop this sample if repeating
+ if (_ctx->sampleNumber && _ctx->bLooped)
+ _vm->_sound->stopSpecSample(_ctx->sampleNumber, 0);
+
+ _ctx->bFinished = true;
+ }
+
+ if (myescEvent && myescEvent != GetEscEvents()) {
+ // Stop this sample
+ if (_ctx->sampleNumber)
+ _vm->_sound->stopSpecSample(_ctx->sampleNumber, 0);
+
+ _ctx->bFinished = true;
+ }
+ } while (!_ctx->bFinished && _ctx->myNum == soundReelNumbers[_ctx->myId]);
+
+ // De-register - if not been replaced
+ if (_ctx->myNum == soundReelNumbers[_ctx->myId])
+ DeRegisterSoundReel(hFilm, column);
+
+ CORO_END_CODE;
+}
+
+static void ResSoundReel(CORO_PARAM, const void *) {
+ // get the stuff copied to process when it was created
+ PPROCESS pProc = g_scheduler->getCurrentProcess();
+ int i = *(int *)pProc->param;
+
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ CORO_INVOKE_ARGS(SoundReel, (CORO_SUBCTX, soundReels[i].hFilm, soundReels[i].column,
+ -1, 0, soundReels[i].actorCol));
+
+ CORO_KILL_SELF();
+ CORO_END_CODE;
+}
+
+static void SoundReelWaitCheck(void) {
+ if (--soundReelWait == 0) {
+ for (int i = 0; i < MAX_SOUNDREELS; i++) {
+ if (soundReels[i].hFilm) {
+ g_scheduler->createProcess(PID_REEL, ResSoundReel, &i, sizeof(i));
+ }
+ }
+ }
+}
/**
* - Don't bother if this reel is already playing for this actor.
@@ -121,7 +418,7 @@ struct PPINIT {
* - If called from an splay(), moving actor's co-ordinates are updated
* after the play, any walk still in progress will go on from there.
*/
-void PlayReel(CORO_PARAM, const PPINIT *ppi) {
+static void t1PlayReel(CORO_PARAM, const PPINIT *ppi) {
CORO_BEGIN_CONTEXT;
OBJECT *pPlayObj; // Object
ANIM thisAnim; // Animation structure
@@ -134,6 +431,8 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
int stepCount;
int frameCount;
int reelActor;
+ PMOVER pActor;
+ int tmpX, tmpY;
CORO_END_CONTEXT(_ctx);
static int firstColZ = 0; // Z-position of column zero
@@ -142,14 +441,13 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
CORO_BEGIN_CODE(_ctx);
const MULTI_INIT *pmi; // MULTI_INIT structure
- PMACTOR pActor;
bool bNewMover; // Gets set if a moving actor that isn't in scene yet
const FILM *pfilm;
_ctx->lifeNoMatter = false;
_ctx->replaced = false;
- pActor = NULL;
+ _ctx->pActor = NULL;
bNewMover = false;
pfilm = (const FILM *)LockMem(ppi->hFilm);
@@ -166,26 +464,26 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
return;
/**** Delete a bit down there if this stays ****/
- updateActorEsc(_ctx->reelActor, ppi->escOn, ppi->myescEvent);
+ UpdateActorEsc(_ctx->reelActor, ppi->escOn, ppi->myescEvent);
// To handle the play()-talk(), talk()-play(), talk()-talk() and play()-play() scenarios
- if (ppi->hFilm != getActorLatestFilm(_ctx->reelActor)) {
+ if (ppi->hFilm != GetActorLatestFilm(_ctx->reelActor)) {
// This in not the last film scheduled for this actor
// It may be the last non-talk film though
- if (isActorTalking(_ctx->reelActor))
- setActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk
+ if (ActorIsTalking(_ctx->reelActor))
+ SetActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk
return;
}
- if (isActorTalking(_ctx->reelActor)) {
+ if (ActorIsTalking(_ctx->reelActor)) {
// Note: will delete this and there'll be no need to store the talk film!
- if (ppi->hFilm != getActorTalkFilm(_ctx->reelActor)) {
- setActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk
+ if (ppi->hFilm != GetActorTalkFilm(_ctx->reelActor)) {
+ SetActorPlayFilm(_ctx->reelActor, ppi->hFilm); // Revert to this film after talk
return;
}
} else {
- setActorPlayFilm(_ctx->reelActor, ppi->hFilm);
+ SetActorPlayFilm(_ctx->reelActor, ppi->hFilm);
}
// If this reel is already playing for this actor, just forget it.
@@ -206,34 +504,33 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
// Otherwise, use actor's position if there are not embedded co-ords.
// Add this first test for nth columns with offsets
// in plays with (x,y)
- int tmpX, tmpY;
- tmpX = ppi->x;
- tmpY = ppi->y;
+ _ctx->tmpX = ppi->x;
+ _ctx->tmpY = ppi->y;
if (ppi->column != 0 && (pmi->mulX || pmi->mulY)) {
- } else if (tmpX != -1 || tmpY != -1) {
- MultiSetAniXY(_ctx->pPlayObj, tmpX, tmpY);
+ } else if (_ctx->tmpX != -1 || _ctx->tmpY != -1) {
+ MultiSetAniXY(_ctx->pPlayObj, _ctx->tmpX, _ctx->tmpY);
} else if (!pmi->mulX && !pmi->mulY) {
- GetActorPos(_ctx->reelActor, &tmpX, &tmpY);
- MultiSetAniXY(_ctx->pPlayObj, tmpX, tmpY);
+ GetActorPos(_ctx->reelActor, &_ctx->tmpX, &_ctx->tmpY);
+ MultiSetAniXY(_ctx->pPlayObj, _ctx->tmpX, _ctx->tmpY);
}
// If it's a moving actor, this hides the moving actor
// used to do this only if (actorid == 0) - I don't know why
_ctx->mActor = HideMovingActor(_ctx->reelActor, ppi->sf);
- // If it's a moving actor, get its MACTOR structure.
+ // If it's a moving actor, get its MOVER structure.
// If it isn't in the scene yet, get its task running - using
- // stand() - to prevent a glitch at the end of the play.
+ // Stand() - to prevent a glitch at the end of the play.
if (_ctx->mActor) {
- pActor = GetMover(_ctx->reelActor);
- if (getMActorState(pActor) == NO_MACTOR) {
- stand(_ctx->reelActor, MAGICX, MAGICY, 0);
+ _ctx->pActor = GetMover(_ctx->reelActor);
+ if (!getMActorState(_ctx->pActor)) {
+ CORO_INVOKE_ARGS(Stand, (CORO_SUBCTX, _ctx->reelActor, MAGICX, MAGICY, 0));
bNewMover = true;
}
}
// Register the fact that we're playing this for this actor
- storeActorReel(_ctx->reelActor, _ctx->pfreel, ppi->hFilm, _ctx->pPlayObj, ppi->column, tmpX, tmpY);
+ storeActorReel(_ctx->reelActor, _ctx->pfreel, ppi->hFilm, _ctx->pPlayObj, ppi->column, _ctx->tmpX, _ctx->tmpY);
/**** Will get rid of this if the above is kept ****/
// We may be temporarily resuscitating a dead actor
@@ -247,23 +544,23 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
// N.B. It HAS been ensured that the first column gets here first
if (ppi->z != 0) {
MultiSetZPosition(_ctx->pPlayObj, ppi->z);
- storeActorZpos(_ctx->reelActor, ppi->z);
+ StoreActorZpos(_ctx->reelActor, ppi->z);
} else if (ppi->bTop) {
if (ppi->column == 0) {
firstColZ = Z_TOPPLAY + actorMaskType(_ctx->reelActor);
MultiSetZPosition(_ctx->pPlayObj, firstColZ);
- storeActorZpos(_ctx->reelActor, firstColZ);
+ StoreActorZpos(_ctx->reelActor, firstColZ);
} else {
MultiSetZPosition(_ctx->pPlayObj, firstColZ + ppi->column);
- storeActorZpos(_ctx->reelActor, firstColZ + ppi->column);
+ StoreActorZpos(_ctx->reelActor, firstColZ + ppi->column);
}
} else if (ppi->column == 0) {
if (_ctx->mActor && !bNewMover) {
// If no path, just use first path in the scene
- if (pActor->hCpath == NOPOLY)
- fColZfactor = getPolyZfactor(FirstPathPoly());
+ if (_ctx->pActor->hCpath == NOPOLY)
+ fColZfactor = GetPolyZfactor(FirstPathPoly());
else
- fColZfactor = getPolyZfactor(pActor->hCpath);
+ fColZfactor = GetPolyZfactor(_ctx->pActor->hCpath);
firstColZ = AsetZPos(_ctx->pPlayObj, MultiLowest(_ctx->pPlayObj), fColZfactor);
} else {
switch (actorMaskType(_ctx->reelActor)) {
@@ -293,14 +590,14 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
break;
}
}
- storeActorZpos(_ctx->reelActor, firstColZ);
+ StoreActorZpos(_ctx->reelActor, firstColZ);
} else {
if (NoNameFunc(_ctx->reelActor, bNewMover) > fColZfactor) {
fColZfactor = NoNameFunc(_ctx->reelActor, bNewMover);
firstColZ = fColZfactor << 10;
}
MultiSetZPosition(_ctx->pPlayObj, firstColZ + ppi->column);
- storeActorZpos(_ctx->reelActor, firstColZ + ppi->column);
+ StoreActorZpos(_ctx->reelActor, firstColZ + ppi->column);
}
/*
@@ -313,7 +610,7 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
do {
if (_ctx->stepCount++ == 0) {
_ctx->frameCount++;
- storeActorSteps(_ctx->reelActor, _ctx->frameCount);
+ StoreActorSteps(_ctx->reelActor, _ctx->frameCount);
}
if (_ctx->stepCount == ppi->speed)
_ctx->stepCount = 0;
@@ -323,7 +620,7 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
int x, y;
GetAniPosition(_ctx->pPlayObj, &x, &y);
- storeActorPos(_ctx->reelActor, x, y);
+ StoreActorPos(_ctx->reelActor, x, y);
CORO_SLEEP(1);
@@ -332,7 +629,7 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
break;
}
- if (actorEsc(_ctx->reelActor) && actorEev(_ctx->reelActor) != GetEscEvents())
+ if (ActorEsc(_ctx->reelActor) && ActorEev(_ctx->reelActor) != GetEscEvents())
break;
} while (_ctx->lifeNoMatter || actorAlive(_ctx->reelActor));
@@ -359,26 +656,308 @@ void PlayReel(CORO_PARAM, const PPINIT *ppi) {
}
/**
+ * - Don't bother if this reel is already playing for this actor.
+ * - If explicit co-ordinates, use these, If embedded co-ordinates,
+ * leave alone, otherwise use actor's current position.
+ * - Moving actors get hidden during this play, other actors get
+ * replaced by this play.
+ * - Column 0 of a film gets its appropriate Z-position, slave columns
+ * get slightly bigger Z-positions, in column order.
+ * - Play proceeds until the script finishes, another reel starts up for
+ * this actor, or the actor gets killed.
+ * - If called from an splay(), moving actor's co-ordinates are updated
+ * after the play, any walk still in progress will go on from there.
+ * @param x Co-ordinates from the play(), set to (-1, -1) if none
+ * @param y Co-ordinates from the play(), set to (-1, -1) if none
+ * @param bRestore Normally False, set if from restore
+ * @param speed Film speed
+ * @param hFilm The 'film'
+ * @param column Column number, first column = 0
+ */
+static void t2PlayReel(CORO_PARAM, int x, int y, bool bRestore, int speed, SCNHANDLE hFilm,
+ int column, int myescEvent, bool bTop) {
+ CORO_BEGIN_CONTEXT;
+ bool bReplaced;
+ bool bGotHidden;
+ int stepCount;
+ int frameCount;
+ bool bEscapedAlready;
+ bool bPrinciple; // true if this is the first column in a film for one actor
+ bool bRelative; // true if relative specified in script
+
+ FREEL *pFreel;
+ MULTI_INIT *pmi; // MULTI_INIT structure
+ POBJECT pPlayObj; // Object
+ ANIM thisAnim; // Animation structure
+
+ int reelActor; // Which actor this reel belongs to
+ PMOVER pMover; // set if it's a moving actor
+ bool bNewMover; // Gets set if a moving actor that isn't in scene yet
+
+ int filmNumber;
+ int myZ; // Remember for hide/unhide
+ CORO_END_CONTEXT(_ctx);
+
+ CORO_BEGIN_CODE(_ctx);
+
+ _ctx->bReplaced = false;
+ _ctx->bGotHidden = false;
+ _ctx->stepCount = 0;
+ _ctx->frameCount = 0;
+
+ _ctx->bEscapedAlready = false;
+
+ // Get the reel and MULTI_INIT structure
+ _ctx->pFreel = GetReel(hFilm, column);
+ _ctx->pmi = (MULTI_INIT *)LockMem(_ctx->pFreel->mobj);
+
+ if (_ctx->pmi->mulID == -2) {
+ CORO_INVOKE_ARGS(SoundReel, (CORO_SUBCTX, hFilm, column, speed, myescEvent,
+ _ctx->pmi->otherFlags & OTH_RELATEDACTOR));
+ return;
+ }
+
+ // Save actor's ID
+ _ctx->reelActor = _ctx->pmi->mulID;
+
+ UpdateActorEsc(_ctx->reelActor, myescEvent);
+
+ // To handle the play()-talk(), talk()-play(), talk()-talk() and play()-play() scenarios
+ if (hFilm != GetActorLatestFilm(_ctx->reelActor)) {
+ // This in not the last film scheduled for this actor
+
+ // It may be the last non-talk film though
+ if (ActorIsTalking(_ctx->reelActor))
+ SetActorPlayFilm(_ctx->reelActor, hFilm); // Revert to this film after talk
+
+ return;
+ }
+ if (ActorIsTalking(_ctx->reelActor)) {
+ // Note: will delete this and there'll be no need to store the talk film!
+ if (hFilm != GetActorTalkFilm(_ctx->reelActor)) {
+ SetActorPlayFilm(_ctx->reelActor, hFilm); // Revert to this film after talk
+ return;
+ }
+ } else {
+ SetActorPlayFilm(_ctx->reelActor, hFilm);
+ }
+
+ // Register the film for this actor
+ if (hFilm != GetActorPresFilm(_ctx->reelActor)) {
+ _ctx->bPrinciple = true;
+ StoreActorPresFilm(_ctx->reelActor, hFilm, x, y);
+ } else {
+ _ctx->bPrinciple = false;
+
+ // If this reel is already playing for this actor, just forget it.
+ if (ActorReelPlaying(_ctx->reelActor, column))
+ return;
+ }
+
+ /*
+ * Insert the object
+ */
+ // Poke in the background palette
+ PokeInPalette(_ctx->pmi);
+
+ // Set ghost bit if wanted
+ if (ActorIsGhost(_ctx->reelActor)) {
+ assert(_ctx->pmi->mulFlags == DMA_WNZ || _ctx->pmi->mulFlags == (DMA_WNZ | DMA_GHOST));
+ _ctx->pmi->mulFlags |= DMA_GHOST;
+ }
+
+ // Set up and insert the multi-object
+ _ctx->pPlayObj = MultiInitObject(_ctx->pmi);
+ if (!bTop)
+ MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
+ else
+ MultiInsertObject(GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
+
+ /*
+ * More action for moving actors
+ */
+ _ctx->pMover = GetMover(_ctx->reelActor);
+ if (_ctx->pMover != NULL) {
+ HideMover(_ctx->pMover);
+
+ if (!MoverIs(_ctx->pMover)) {
+ // Used to do a Stand here to prevent glitches
+
+ _ctx->bNewMover = true;
+ } else
+ _ctx->bNewMover = false;
+ }
+
+ // Register the reel for this actor
+ StoreActorReel(_ctx->reelActor, column, _ctx->pPlayObj);
+
+ _ctx->filmNumber = GetActorFilmNumber(_ctx->reelActor);
+
+ /*
+ * Sort out x and y
+ */
+ assert( ((_ctx->pmi->otherFlags & OTH_RELATIVE) && !(_ctx->pmi->otherFlags & OTH_ABSOLUTE))
+ || ((_ctx->pmi->otherFlags & OTH_ABSOLUTE) && !(_ctx->pmi->otherFlags & OTH_RELATIVE)) );
+
+ _ctx->bRelative = _ctx->pmi->otherFlags & OTH_RELATIVE;
+
+ if (_ctx->bRelative) {
+ // Use actor's position. If (x, y) specified, move the actor.
+ if (x == -1 && y == -1)
+ GetActorPos(_ctx->reelActor, &x, &y);
+ else
+ StoreActorPos(_ctx->reelActor, x, y);
+ } else if (x == -1 && y == -1)
+ x = y = 0; // Use (0,0) if no specified
+
+ // Add embedded co-ords
+ MultiSetAniXY(_ctx->pPlayObj, x + _ctx->pmi->mulX, y + _ctx->pmi->mulY);
+
+ /*
+ * Sort out z
+ */
+ if (bRestore) {
+ _ctx->myZ = GetActorZpos(_ctx->reelActor, column);
+
+ SoundReelWaitCheck();
+ } else {
+ static int baseZposn; // Z-position of column zero
+ static uint32 baseZfact; // Z-factor of column zero's actor
+
+ // N.B. It HAS been ensured that the first column gets here first
+
+ if (_ctx->pmi->mulZ != -1) {
+ // Z override in script
+
+ baseZfact = _ctx->pmi->mulZ;
+ baseZposn = (baseZfact << ZSHIFT) + MultiLowest(_ctx->pPlayObj);
+ if (bTop)
+ baseZposn += Z_TOPPLAY;
+ } else if (column == 0
+ || GetZfactor(_ctx->reelActor, _ctx->pMover, _ctx->bNewMover) > baseZfact) {
+ // Subsequent columns are based on this one
+
+ baseZfact = GetZfactor(_ctx->reelActor, _ctx->pMover, _ctx->bNewMover);
+ baseZposn = (baseZfact << ZSHIFT) + MultiLowest(_ctx->pPlayObj);
+ if (bTop)
+ baseZposn += Z_TOPPLAY;
+ }
+ _ctx->myZ = baseZposn + column;
+ }
+ MultiSetZPosition(_ctx->pPlayObj, _ctx->myZ);
+ StoreActorZpos(_ctx->reelActor, _ctx->myZ, column);
+
+ /*
+ * Play until the script finishes,
+ * another reel starts up for this actor,
+ * or the actor gets killed.
+ */
+ InitStepAnimScript(&_ctx->thisAnim, _ctx->pPlayObj, _ctx->pFreel->script, speed);
+
+ if (bRestore || (ActorEsc(_ctx->reelActor) == true &&
+ ActorEev(_ctx->reelActor) != GetEscEvents())) {
+ // From restore, step to jump or end
+ SkipFrames(&_ctx->thisAnim, -1);
+ }
+
+ for (;;) {
+ if (_ctx->stepCount++ == 0) {
+ _ctx->frameCount++;
+ StoreActorSteps(_ctx->reelActor, _ctx->frameCount);
+ }
+ if (_ctx->stepCount == speed)
+ _ctx->stepCount = 0;
+
+ if (_ctx->bPrinciple && AboutToJumpOrEnd(&_ctx->thisAnim))
+ IncLoopCount(_ctx->reelActor);
+
+ if (StepAnimScript(&_ctx->thisAnim) == ScriptFinished)
+ break;
+
+ if (_ctx->bRelative) {
+ GetAniPosition(_ctx->pPlayObj, &x, &y);
+ StoreActorPos(_ctx->reelActor, x, y);
+ }
+
+ if (_ctx->bGotHidden) {
+ if (!ActorHidden(_ctx->reelActor)) {
+ MultiSetZPosition(_ctx->pPlayObj, _ctx->myZ);
+ _ctx->bGotHidden = false;
+ }
+ } else {
+ if (ActorHidden(_ctx->reelActor)) {
+ MultiSetZPosition(_ctx->pPlayObj, -1);
+ _ctx->bGotHidden = true;
+ }
+ }
+
+ CORO_SLEEP(1);
+
+ if (GetActorFilmNumber(_ctx->reelActor) != _ctx->filmNumber) {
+ _ctx->bReplaced = true;
+ break;
+ }
+
+ if (ActorEsc(_ctx->reelActor) == true && ActorEev(_ctx->reelActor) != GetEscEvents()) {
+ if (!_ctx->bEscapedAlready) {
+ SkipFrames(&_ctx->thisAnim, -1);
+ _ctx->bEscapedAlready = true;
+ }
+
+//WHY??? UpdateActorEsc(reelActor, GetEscEvents());
+// The above line of code, not commented out would fix the coffee pot flash
+// but why was it commented out?
+// The extra boolean is used instead, 'cos it's release week and I want to play it safe!
+ }
+ }
+
+ // Register the fact that we're NOT playing this for this actor
+ NotPlayingReel(_ctx->reelActor, _ctx->filmNumber, column);
+
+ // Ditch the object
+ if (!bTop)
+ MultiDeleteObject(GetPlayfieldList(FIELD_WORLD), _ctx->pPlayObj);
+ else
+ MultiDeleteObject(GetPlayfieldList(FIELD_STATUS), _ctx->pPlayObj);
+
+ // Restore moving actor is nessesary
+ if (_ctx->pMover != NULL && _ctx->bPrinciple && !_ctx->bReplaced)
+ UnHideMover(_ctx->pMover);
+
+ CORO_END_CODE;
+}
+
+/**
* Run all animations that comprise the play film.
*/
-static void playProcess(CORO_PARAM, const void *param) {
- // get the stuff copied to process when it was created
- PPINIT *ppi = (PPINIT *)param;
+static void PlayProcess(CORO_PARAM, const void *param) {
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
- PlayReel(coroParam, ppi);
+ const PPINIT *ppi = (const PPINIT *)param;
+ CORO_BEGIN_CODE(_ctx);
+
+ if (TinselV2)
+ CORO_INVOKE_ARGS(t2PlayReel, (CORO_SUBCTX, ppi->x, ppi->y, ppi->bRestore, ppi->speed,
+ ppi->hFilm, ppi->column, ppi->myescEvent, ppi->bTop));
+ else
+ CORO_INVOKE_1(t1PlayReel, ppi);
+
+ CORO_END_CODE;
}
// *******************************************************
// To handle the play()-talk(), talk()-play(), talk()-talk() and play()-play() scenarios
-void newestFilm(SCNHANDLE film, const FREEL *reel) {
+void NewestFilm(SCNHANDLE film, const FREEL *reel) {
const MULTI_INIT *pmi; // MULTI_INIT structure
// Get the MULTI_INIT structure
pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(reel->mobj));
- setActorLatestFilm((int32)FROM_LE_32(pmi->mulID), film);
+ if (!TinselV2 || ((int32)FROM_LE_32(pmi->mulID) != -2))
+ SetActorLatestFilm((int32)FROM_LE_32(pmi->mulID), film);
}
// *******************************************************
@@ -389,64 +968,90 @@ void newestFilm(SCNHANDLE film, const FREEL *reel) {
* NOTE: The processes are started in reverse order so that the first
* column's process kicks in first.
*/
-void playFilm(SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact, bool escOn,
+void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact, bool escOn,
int myescEvent, bool bTop) {
- const FILM *pfilm = (const FILM *)LockMem(film);
- PPINIT ppi;
+ assert(hFilm != 0); // Trying to play NULL film
+ const FILM *pFilm;
+
+ CORO_BEGIN_CONTEXT;
+ CORO_END_CONTEXT(_ctx);
- assert(film != 0); // Trying to play NULL film
+ CORO_BEGIN_CODE(_ctx);
+
+ pFilm = (const FILM *)LockMem(hFilm);
+ PPINIT ppi;
// Now allowed empty films!
- if (pfilm->numreels == 0)
+ if (pFilm->numreels == 0)
return; // Nothing to do!
- ppi.hFilm = film;
+ ppi.hFilm = hFilm;
ppi.x = x;
ppi.y = y;
ppi.z = 0;
- ppi.speed = (ONE_SECOND / FROM_LE_32(pfilm->frate));
+ ppi.bRestore = false;
+ ppi.speed = (ONE_SECOND / FROM_LE_32(pFilm->frate));
ppi.actorid = actorid;
ppi.splay = splay;
ppi.bTop = bTop;
ppi.sf = sfact;
ppi.escOn = escOn;
- ppi.myescEvent = myescEvent;
+ ppi.myescEvent = myescEvent;
// Start display process for each reel in the film
- for (int i = FROM_LE_32(pfilm->numreels) - 1; i >= 0; i--) {
- newestFilm(film, &pfilm->reels[i]);
+ for (int i = FROM_LE_32(pFilm->numreels) - 1; i >= 0; i--) {
+ NewestFilm(hFilm, &pFilm->reels[i]);
ppi.column = i;
- g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(PPINIT));
+ g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(PPINIT));
}
+
+ if (TinselV2) {
+ // Let it all kick in and position this process
+ // down the process list from the playing process(es)
+ // This ensures something
+ CORO_GIVE_WAY;
+
+ if (myescEvent && myescEvent != GetEscEvents())
+ g_scheduler->rescheduleAll();
+ }
+
+ CORO_END_CODE;
+}
+
+void PlayFilm(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int myescEvent, bool bTop) {
+ PlayFilm(coroParam, hFilm, x, y, 0, false, false, false, myescEvent, bTop);
}
/**
* Start up a play process for each slave column in a film.
* Play the first column directly from the parent process.
*/
-void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay, int sfact,
+void PlayFilmc(CORO_PARAM, SCNHANDLE hFilm, int x, int y, int actorid, bool splay, bool sfact,
bool escOn, int myescEvent, bool bTop) {
CORO_BEGIN_CONTEXT;
PPINIT ppi;
+ int i;
+ int loopCount;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
- assert(film != 0); // Trying to play NULL film
- const FILM *pfilm;
+ assert(hFilm != 0); // Trying to play NULL film
+ const FILM *pFilm;
- pfilm = (const FILM *)LockMem(film);
+ pFilm = (const FILM *)LockMem(hFilm);
// Now allowed empty films!
- if (pfilm->numreels == 0)
+ if (pFilm->numreels == 0)
return; // Already played to completion!
- _ctx->ppi.hFilm = film;
+ _ctx->ppi.hFilm = hFilm;
_ctx->ppi.x = x;
_ctx->ppi.y = y;
_ctx->ppi.z = 0;
- _ctx->ppi.speed = (ONE_SECOND / FROM_LE_32(pfilm->frate));
+ _ctx->ppi.bRestore = false;
+ _ctx->ppi.speed = (ONE_SECOND / FROM_LE_32(pFilm->frate));
_ctx->ppi.actorid = actorid;
_ctx->ppi.splay = splay;
_ctx->ppi.bTop = bTop;
@@ -454,18 +1059,40 @@ void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay
_ctx->ppi.escOn = escOn;
_ctx->ppi.myescEvent = myescEvent;
- // Start display process for each secondary reel in the film
- for (int i = FROM_LE_32(pfilm->numreels) - 1; i > 0; i--) {
- newestFilm(film, &pfilm->reels[i]);
+ // Start display process for each secondary reel in the film in Tinsel 1,
+ // or all of them in Tinsel 2
+ for (int i = FROM_LE_32(pFilm->numreels) - 1; i >= (TinselV2 ? 0 : 1); i--) {
+ NewestFilm(hFilm, &pFilm->reels[i]);
_ctx->ppi.column = i;
- g_scheduler->createProcess(PID_REEL, playProcess, &_ctx->ppi, sizeof(PPINIT));
+ g_scheduler->createProcess(PID_REEL, PlayProcess, &_ctx->ppi, sizeof(PPINIT));
}
- newestFilm(film, &pfilm->reels[0]);
+ if (TinselV2) {
+ // Let it all kick in and position this 'waiting' process
+ // down the process list from the playing process(es)
+ // This ensures immediate return when the reel finishes
+ CORO_GIVE_WAY;
- _ctx->ppi.column = 0;
- CORO_INVOKE_1(PlayReel, &_ctx->ppi);
+ _ctx->i = ExtractActor(hFilm);
+ _ctx->loopCount = GetLoopCount(_ctx->i);
+
+ // Wait until film changes or loop count increases
+ while (GetActorPresFilm(_ctx->i) == hFilm && GetLoopCount(_ctx->i) == _ctx->loopCount) {
+ if (myescEvent && myescEvent != GetEscEvents()) {
+ g_scheduler->rescheduleAll();
+ break;
+ }
+
+ CORO_SLEEP(1);
+ }
+ } else {
+ // For Tinsel 1, launch the primary reel
+ NewestFilm(hFilm, &pFilm->reels[0]);
+
+ _ctx->ppi.column = 0;
+ CORO_INVOKE_1(t1PlayReel, &_ctx->ppi);
+ }
CORO_END_CODE;
}
@@ -473,13 +1100,14 @@ void playFilmc(CORO_PARAM, SCNHANDLE film, int x, int y, int actorid, bool splay
/**
* Start up a play process for a particular column in a film.
*
- * NOTE: This is specifically for actors during a restore scene.
+ * NOTE: This is specifically for actors during a Tinsel 1 restore scene.
*/
-void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y) {
- const FILM *pfilm = (const FILM *)LockMem(film);
+void RestoreActorReels(SCNHANDLE hFilm, short reelnum, short z, int x, int y) {
+ assert(!TinselV2);
+ const FILM *pfilm = (const FILM *)LockMem(hFilm);
PPINIT ppi;
- ppi.hFilm = film;
+ ppi.hFilm = hFilm;
ppi.x = x;
ppi.y = y;
ppi.z = z;
@@ -487,21 +1115,58 @@ void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y) {
ppi.actorid = 0;
ppi.splay = false;
ppi.bTop = false;
+ ppi.bRestore = true;
ppi.sf = 0;
ppi.column = reelnum;
+ ppi.myescEvent = 0;
- // FIXME: The PlayReel play loop was previously breaking out, and then deleting objects, when
- // returning to a scene because escOn and myescEvent were undefined. Need to make sure whether
- // restored objects should have any particular combination of these two values
ppi.escOn = false;
ppi.myescEvent = GetEscEvents();
assert(pfilm->numreels);
- newestFilm(film, &pfilm->reels[reelnum]);
+ NewestFilm(hFilm, &pfilm->reels[reelnum]);
// Start display process for the reel
- g_scheduler->createProcess(PID_REEL, playProcess, &ppi, sizeof(ppi));
+ g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
+}
+
+/**
+ * Start up a play process for a particular column in a film.
+ *
+ * NOTE: This is specifically for actors during a Tinsel 2 restore scene.
+ */
+void RestoreActorReels(SCNHANDLE hFilm, int actor, int x, int y) {
+ assert(TinselV2);
+ FILM *pFilm = (FILM *)LockMem(hFilm);
+ PPINIT ppi;
+
+ int i;
+ FREEL *pFreel;
+ PMULTI_INIT pmi; // MULTI_INIT structure
+
+ ppi.hFilm = hFilm;
+ ppi.x = (short)x;
+ ppi.y = (short)y;
+ ppi.bRestore = true;
+ ppi.speed = (short)(ONE_SECOND/pFilm->frate);
+ ppi.bTop = false;
+ ppi.myescEvent = 0;
+
+ // Search backwards for now as later column will be the one
+ for (i = pFilm->numreels - 1; i >= 0; i--) {
+ pFreel = &pFilm->reels[i];
+ pmi = (PMULTI_INIT) LockMem(pFreel->mobj);
+ if (pmi->mulID == actor) {
+ ppi.column = (short)i;
+ NewestFilm(hFilm, &pFilm->reels[i]);
+
+ // Start display process for the reel
+ g_scheduler->createProcess(PID_REEL, PlayProcess, &ppi, sizeof(ppi));
+
+ soundReelWait++;
+ }
+ }
}
} // end of namespace Tinsel