diff options
author | Filippos Karapetis | 2008-12-01 20:35:36 +0000 |
---|---|---|
committer | Filippos Karapetis | 2008-12-01 20:35:36 +0000 |
commit | af945ac7881ae7e414f004bd0e99e8c3b5d76be9 (patch) | |
tree | 72e9c6fd43406e2021973b4f163ab4faa10143fb /engines/tinsel/play.cpp | |
parent | f10f151ff742801e12534bb052bd89419bf906cb (diff) | |
download | scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.gz scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.bz2 scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.zip |
Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable
svn-id: r35196
Diffstat (limited to 'engines/tinsel/play.cpp')
-rw-r--r-- | engines/tinsel/play.cpp | 853 |
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 |