/** * Process to fade one palette. * A pointer to a 'FADE' structure must be passed to this process when * it is created. */ static void FadeProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; COLORREF fadeRGB[MAX_COLORS]; // local copy of palette const long *pColMult; // pointer to color multiplier table PALETTE *pPalette; // pointer to palette CORO_END_CONTEXT(_ctx); // get the fade data structure - copied to process when it was created const FADE *pFade = (const FADE *)param; CORO_BEGIN_CODE(_ctx); if (TinselV2) // Note that this palette is being faded FadingPalette(pFade->pPalQ, true); // get pointer to palette - reduce pointer indirection a bit _ctx->pPalette = (PALETTE *)LockMem(FROM_32(pFade->pPalQ->hPal)); for (_ctx->pColMult = pFade->pColorMultTable; *_ctx->pColMult >= 0; _ctx->pColMult++) { // go through all multipliers in table - until a negative entry // fade palette using next multiplier if (TinselV2) FadePalette(_ctx->fadeRGB, pFade->pPalQ->palRGB, pFade->pPalQ->numColors, (uint32) *_ctx->pColMult); else FadePalette(_ctx->fadeRGB, _ctx->pPalette->palRGB, FROM_32(_ctx->pPalette->numColors), (uint32) *_ctx->pColMult); // send new palette to video DAC UpdateDACqueue(pFade->pPalQ->posInDAC, FROM_32(_ctx->pPalette->numColors), _ctx->fadeRGB); // allow time for video DAC to be updated CORO_SLEEP(1); } if (TinselV2) // Note that this palette is being faded FadingPalette(pFade->pPalQ, false); CORO_END_CODE; }
/** * Run a scene process with the given event. */ void SceneProcessEvent(CORO_PARAM, uint32 procID, TINSEL_EVENT event, bool bWait, int myEscape, bool *result) { uint32 i; // Loop counter if (result) *result = false; CORO_BEGIN_CONTEXT; PROCESS_STRUC *pStruc; PPROCESS pProc; PINT_CONTEXT pic; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); _ctx->pStruc = (PROCESS_STRUC *)LockMem(hSceneProcess); for (i = 0; i < numSceneProcess; i++) { if (FROM_LE_32(_ctx->pStruc[i].processId) == procID) { assert(_ctx->pStruc[i].hProcessCode); // Must have some code to run _ctx->pic = InitInterpretContext(GS_PROCESS, FROM_LE_32(_ctx->pStruc[i].hProcessCode), event, NOPOLY, // No polygon 0, // No actor NULL, // No object myEscape); if (_ctx->pic == NULL) return; _ctx->pProc = g_scheduler->createProcess(PID_PROCESS + i, ProcessTinselProcess, &_ctx->pic, sizeof(_ctx->pic)); AttachInterpret(_ctx->pic, _ctx->pProc); break; } } if (i == numSceneProcess) return; if (bWait) { CORO_INVOKE_2(WaitInterpret, _ctx->pProc, result); } CORO_END_CODE; }
/** * Get actor to adopt its appropriate walking reel. */ void SetMoverWalkReel(PMOVER pMover, DIRECTION reel, int scale, bool force) { SCNHANDLE whichReel; const FILM *pfilm; // Kill off any play that may be going on for this actor // and restore the real actor storeActorReel(pMover->actorID, NULL, 0, NULL, 0, 0, 0); UnHideMover(pMover); // Don't do it if using a special walk reel if (pMover->bWalkReel) return; if (force || pMover->scale != scale || pMover->direction != reel) { assert(reel >= 0 && reel <= 3 && scale > 0 && scale <= TOTAL_SCALES); // out of range scale or reel // If scale change and both are regular scales // and there's a scaling reel in the right direction if (pMover->scale != scale && scale <= NUM_MAINSCALES && pMover->scale <= NUM_MAINSCALES && (whichReel = ScalingReel(pMover->actorID, pMover->scale, scale, reel)) != 0) { // error("Cripes"); ; // Use what is now in 'whichReel' } else { whichReel = pMover->walkReels[scale-1][reel]; assert(whichReel); // no reel } pfilm = (const FILM *)LockMem(whichReel); assert(pfilm != NULL); // no film InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, FROM_32(pfilm->reels[0].script), 1); // Synchronised walking reels assert(pMover->stepCount >= 0); SkipFrames(&pMover->actorAnim, pMover->stepCount); pMover->scale = scale; pMover->direction = reel; } }
/** * Runs secondary reels for a scene background */ static void BGotherProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; OBJECT *pObj; ANIM anim; CORO_END_CONTEXT(_ctx); const FREEL *pReel = (const FREEL *)param; const MULTI_INIT *pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj)); CORO_BEGIN_CODE(_ctx); // Initialise and insert the object, and initialise its script. _ctx->pObj = MultiInitObject(pmi); MultiInsertObject(GetPlayfieldList(FIELD_WORLD), _ctx->pObj); InitStepAnimScript(&_ctx->anim, pBG[0], FROM_LE_32(pReel->script), BGspeed); while (StepAnimScript(&_ctx->anim) != ScriptFinished) CORO_SLEEP(1); CORO_END_CODE; }
/** * About to jump or end * @param pAnim Animation data structure */ bool AboutToJumpOrEnd(PANIM pAnim) { if (pAnim->aniDelta == 1) { // get a pointer to the script ANI_SCRIPT *pAni = (ANI_SCRIPT *)LockMem(pAnim->hScript); int zzz = pAnim->scriptIndex; for (;;) { // repeat until a real image switch (FROM_LE_32(pAni[zzz].op)) { case ANI_END: // end of animation script case ANI_JUMP: // do animation jump return true; case ANI_HFLIP: // flip animated object horizontally case ANI_VFLIP: // flip animated object vertically case ANI_HVFLIP: // flip animated object in both directions zzz++; break; case ANI_ADJUSTX: // adjust animated object x animation point case ANI_ADJUSTY: // adjust animated object y animation point zzz += 2; break; case ANI_ADJUSTXY: // adjust animated object x & y animation points zzz += 3; break; case ANI_HIDE: // hide animated object default: // must be an actual animation frame handle return false; } } } return false; }
/** * Run main animation that comprises the scene background. */ static void BGmainProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); const FILM *pFilm; const FREEL *pReel; const MULTI_INIT *pmi; // get the stuff copied to process when it was created if (pBG[0] == NULL) { /*** At start of scene ***/ if (!TinselV2) { pReel = (const FREEL *)param; // Get the MULTI_INIT structure pmi = (const MULTI_INIT *)LockMem(FROM_LE_32(pReel->mobj)); // Initialise and insert the object, and initialise its script. pBG[0] = MultiInitObject(pmi); MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[0]); InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed); bgReels = 1; } else { /*** At start of scene ***/ pFilm = (const FILM *)LockMem(hBackground); bgReels = FROM_LE_32(pFilm->numreels); int i; for (i = 0; i < bgReels; i++) { // Get the MULTI_INIT structure pmi = (PMULTI_INIT) LockMem(FROM_LE_32(pFilm->reels[i].mobj)); // Initialise and insert the object, and initialise its script. pBG[i] = MultiInitObject(pmi); MultiInsertObject(GetPlayfieldList(FIELD_WORLD), pBG[i]); MultiSetZPosition(pBG[i], 0); InitStepAnimScript(&thisAnim[i], pBG[i], FROM_LE_32(pFilm->reels[i].script), BGspeed); if (i > 0) pBG[i-1]->pSlave = pBG[i]; } } if (bDoFadeIn) { FadeInFast(NULL); bDoFadeIn = false; } else if (TinselV2) PokeInTagColor(); for (;;) { for (int i = 0; i < bgReels; i++) { if (StepAnimScript(&thisAnim[i]) == ScriptFinished) error("Background animation has finished"); } CORO_SLEEP(1); } } else { // New background during scene if (!TinselV2) { pReel = (const FREEL *)param; InitStepAnimScript(&thisAnim[0], pBG[0], FROM_LE_32(pReel->script), BGspeed); StepAnimScript(&thisAnim[0]); } else { pFilm = (const FILM *)LockMem(hBackground); assert(bgReels == (int32)FROM_LE_32(pFilm->numreels)); // Just re-initialise the scripts. for (int i = 0; i < bgReels; i++) { InitStepAnimScript(&thisAnim[i], pBG[i], pFilm->reels[i].script, BGspeed); StepAnimScript(&thisAnim[i]); } } } CORO_END_CODE; }
/** * Advance to next frame routine. * @param pAnim Animation data structure */ SCRIPTSTATE DoNextFrame(ANIM *pAnim) { // get a pointer to the script const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); while (1) { // repeat until a real image debugC(DEBUG_DETAILED, kTinselDebugAnimations, "DoNextFrame %ph index=%d, op=%xh", (byte *)pAnim, pAnim->scriptIndex, FROM_LE_32(pAni[pAnim->scriptIndex].op)); switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) { case ANI_END: // end of animation script // move to next opcode pAnim->scriptIndex++; // indicate script has finished return ScriptFinished; case ANI_JUMP: // do animation jump // move to jump address pAnim->scriptIndex++; // jump to new frame position pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); // go fetch a real image break; case ANI_HFLIP: // flip animated object horizontally // next opcode pAnim->scriptIndex++; MultiHorizontalFlip(pAnim->pObject); // go fetch a real image break; case ANI_VFLIP: // flip animated object vertically // next opcode pAnim->scriptIndex++; MultiVerticalFlip(pAnim->pObject); // go fetch a real image break; case ANI_HVFLIP: // flip animated object in both directions // next opcode pAnim->scriptIndex++; MultiHorizontalFlip(pAnim->pObject); MultiVerticalFlip(pAnim->pObject); // go fetch a real image break; case ANI_ADJUSTX: // adjust animated object x animation point // move to x adjustment operand pAnim->scriptIndex++; MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0); // next opcode pAnim->scriptIndex++; // go fetch a real image break; case ANI_ADJUSTY: // adjust animated object y animation point // move to y adjustment operand pAnim->scriptIndex++; MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)); // next opcode pAnim->scriptIndex++; // go fetch a real image break; case ANI_ADJUSTXY: // adjust animated object x & y animation points { int x, y; // move to x adjustment operand pAnim->scriptIndex++; x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); // move to y adjustment operand pAnim->scriptIndex++; y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); MultiAdjustXY(pAnim->pObject, x, y); // next opcode pAnim->scriptIndex++; // go fetch a real image break; } case ANI_NOSLEEP: // do not sleep for this frame // next opcode pAnim->scriptIndex++; // indicate not to sleep return ScriptNoSleep; case ANI_CALL: // call routine // move to function address pAnim->scriptIndex++; // make function call // REMOVED BUGGY CODE // pFunc is a function pointer that's part of a union and is assumed to be 32-bits. // There is no known place where a function pointer is stored inside the animation // scripts, something which wouldn't have worked anyway. Having played through the // entire game, there hasn't been any occurence of this case, so just error out here // in case we missed something (highly unlikely though) error("ANI_CALL opcode encountered! Please report this error to the ScummVM team"); //(*pAni[pAnim->scriptIndex].pFunc)(pAnim); return ScriptSleep; // for compilers that don't support NORETURN #if 0 // next opcode pAnim->scriptIndex++; // go fetch a real image break; #endif case ANI_HIDE: // hide animated object MultiHideObject(pAnim->pObject); // next opcode pAnim->scriptIndex++; // dont skip a sleep return ScriptSleep; default: // must be an actual animation frame handle // set objects new animation frame pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame); // re-shape the object MultiReshape(pAnim->pObject); // next opcode pAnim->scriptIndex++; // dont skip a sleep return ScriptSleep; } } }
/** * Skip the specified number of frames. * @param pAnim Animation data structure * @param numFrames Number of frames to skip */ void SkipFrames(ANIM *pAnim, int numFrames) { // get a pointer to the script const ANI_SCRIPT *pAni = (const ANI_SCRIPT *)LockMem(pAnim->hScript); if (!TinselV2 && (numFrames <= 0)) // do nothing return; while (1) { // repeat until a real image switch ((int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)) { case ANI_END: // end of animation script // going off the end is probably a error, but only in Tinsel 1 if (!TinselV2) error("SkipFrames(): formally 'assert(0)!'"); return; case ANI_JUMP: // do animation jump // move to jump address pAnim->scriptIndex++; // jump to new frame position pAnim->scriptIndex += (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); if (TinselV2) // Done if skip to jump return; break; case ANI_HFLIP: // flip animated object horizontally // next opcode pAnim->scriptIndex++; MultiHorizontalFlip(pAnim->pObject); break; case ANI_VFLIP: // flip animated object vertically // next opcode pAnim->scriptIndex++; MultiVerticalFlip(pAnim->pObject); break; case ANI_HVFLIP: // flip animated object in both directions // next opcode pAnim->scriptIndex++; MultiHorizontalFlip(pAnim->pObject); MultiVerticalFlip(pAnim->pObject); break; case ANI_ADJUSTX: // adjust animated object x animation point // move to x adjustment operand pAnim->scriptIndex++; MultiAdjustXY(pAnim->pObject, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op), 0); // next opcode pAnim->scriptIndex++; break; case ANI_ADJUSTY: // adjust animated object y animation point // move to y adjustment operand pAnim->scriptIndex++; MultiAdjustXY(pAnim->pObject, 0, (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op)); // next opcode pAnim->scriptIndex++; break; case ANI_ADJUSTXY: // adjust animated object x & y animation points { int x, y; // move to x adjustment operand pAnim->scriptIndex++; x = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); // move to y adjustment operand pAnim->scriptIndex++; y = (int32)FROM_LE_32(pAni[pAnim->scriptIndex].op); MultiAdjustXY(pAnim->pObject, x, y); // next opcode pAnim->scriptIndex++; break; } case ANI_NOSLEEP: // do not sleep for this frame // next opcode pAnim->scriptIndex++; break; case ANI_CALL: // call routine // skip function address pAnim->scriptIndex += 2; break; case ANI_HIDE: // hide animated object // next opcode pAnim->scriptIndex++; break; default: // must be an actual animation frame handle // one less frame if (numFrames == 0) return; if (numFrames == -1 || numFrames-- > 0) { // next opcode pAnim->scriptIndex++; } else { // set objects new animation frame pAnim->pObject->hShape = FROM_LE_32(pAni[pAnim->scriptIndex].hFrame); // re-shape the object MultiReshape(pAnim->pObject); // we have skipped to the correct place return; } break; } } }
/** * Initialise a object using a OBJ_INIT structure to supply parameters. * @param pInitTbl Pointer to object initialisation table */ OBJECT *InitObject(const OBJ_INIT *pInitTbl) { // allocate a new object OBJECT *pObj = AllocObject(); // make sure object created assert(pObj != NULL); // set objects shape pObj->hImg = pInitTbl->hObjImg; // set objects ID pObj->oid = pInitTbl->objID; // set objects flags pObj->flags = DMA_CHANGED | pInitTbl->objFlags; // set objects Z position pObj->zPos = pInitTbl->objZ; // get pointer to image if (pInitTbl->hObjImg) { int aniX, aniY; // objects animation offsets PALQ *pPalQ = NULL; // palette queue pointer const IMAGE *pImg = (const IMAGE *)LockMem(pInitTbl->hObjImg); // handle to image if (pImg->hImgPal) { // allocate a palette for this object pPalQ = AllocPalette(FROM_LE_32(pImg->hImgPal)); // make sure palette allocated assert(pPalQ != NULL); } // assign palette to object pObj->pPal = pPalQ; // set objects size pObj->width = FROM_LE_16(pImg->imgWidth); pObj->height = FROM_LE_16(pImg->imgHeight) & ~C16_FLAG_MASK; pObj->flags &= ~C16_FLAG_MASK; pObj->flags |= FROM_LE_16(pImg->imgHeight) & C16_FLAG_MASK; // set objects bitmap definition pObj->hBits = FROM_LE_32(pImg->hImgBits); // get animation offset of object GetAniOffset(pObj->hImg, pInitTbl->objFlags, &aniX, &aniY); // set objects X position - subtract ani offset pObj->xPos = intToFrac(pInitTbl->objX - aniX); // set objects Y position - subtract ani offset pObj->yPos = intToFrac(pInitTbl->objY - aniY); } else { // no image handle - null image // set objects X position pObj->xPos = intToFrac(pInitTbl->objX); // set objects Y position pObj->yPos = intToFrac(pInitTbl->objY); } // return new object return pObj; }
/** * Main text outputting routine. If a object list is specified a * multi-object is created for the whole text and a pointer to the head * of the list is returned. * @param pList Object list to add text to * @param szStr String to output * @param color Color for monochrome text * @param xPos X position of string * @param yPos Y position of string * @param hFont Which font to use * @param mode Mode flags for the string * @param sleepTime Sleep time between each character (if non-zero) */ OBJECT *ObjectTextOut(OBJECT **pList, char *szStr, int color, int xPos, int yPos, SCNHANDLE hFont, int mode, int sleepTime) { int xJustify; // x position of text after justification int yOffset; // offset to next line of text OBJECT *pFirst; // head of multi-object text list OBJECT *pChar = 0; // object ptr for the character byte c; SCNHANDLE hImg; const IMAGE *pImg; // make sure there is a linked list to add text to assert(pList); // get font pointer const FONT *pFont = (const FONT *)LockMem(hFont); // init head of text list pFirst = NULL; // get image for capital W assert(pFont->fontDef[(int)'W']); pImg = (const IMAGE *)LockMem(FROM_32(pFont->fontDef[(int)'W'])); // get height of capital W for offset to next line yOffset = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK; while (*szStr) { // x justify the text according to the mode flags xJustify = JustifyText(szStr, xPos, pFont, mode); // repeat until end of string or end of line while ((c = *szStr) != EOS_CHAR && c != LF_CHAR) { if (g_bMultiByte) { if (c & 0x80) c = ((c & ~0x80) << 8) + *++szStr; } hImg = FROM_32(pFont->fontDef[c]); if (hImg == 0) { // no image for this character // add font spacing for a space character xJustify += FROM_32(pFont->spaceSize); } else { // printable character int aniX, aniY; // char image animation offsets OBJ_INIT oi; oi.hObjImg = FROM_32(pFont->fontInit.hObjImg); oi.objFlags = FROM_32(pFont->fontInit.objFlags); oi.objID = FROM_32(pFont->fontInit.objID); oi.objX = FROM_32(pFont->fontInit.objX); oi.objY = FROM_32(pFont->fontInit.objY); oi.objZ = FROM_32(pFont->fontInit.objZ); // allocate and init a character object if (pFirst == NULL) // first time - init head of list pFirst = pChar = InitObject(&oi); // FIXME: endian issue using fontInit!!! else // chain to multi-char list pChar = pChar->pSlave = InitObject(&oi); // FIXME: endian issue using fontInit!!! // convert image handle to pointer pImg = (const IMAGE *)LockMem(hImg); // fill in character object pChar->hImg = hImg; // image def pChar->width = FROM_16(pImg->imgWidth); // width of chars bitmap pChar->height = FROM_16(pImg->imgHeight) & ~C16_FLAG_MASK; // height of chars bitmap pChar->hBits = FROM_32(pImg->hImgBits); // bitmap // check for absolute positioning if (mode & TXT_ABSOLUTE) pChar->flags |= DMA_ABS; // set characters color - only effective for mono fonts pChar->constant = color; // get Y animation offset GetAniOffset(hImg, pChar->flags, &aniX, &aniY); // set x position - ignore animation point pChar->xPos = intToFrac(xJustify); // set y position - adjust for animation point pChar->yPos = intToFrac(yPos - aniY); if (mode & TXT_SHADOW) { // we want to shadow the character OBJECT *pShad; // allocate a object for the shadow and chain to multi-char list pShad = pChar->pSlave = AllocObject(); // copy the character for a shadow CopyObject(pShad, pChar); // add shadow offsets to characters position pShad->xPos += intToFrac(FROM_32(pFont->xShadow)); pShad->yPos += intToFrac(FROM_32(pFont->yShadow)); // shadow is behind the character pShad->zPos--; // shadow is always mono pShad->flags = DMA_CNZ | DMA_CHANGED; // check for absolute positioning if (mode & TXT_ABSOLUTE) pShad->flags |= DMA_ABS; // shadow always uses first palette entry // should really alloc a palette here also ???? pShad->constant = 1; // add shadow to object list InsertObject(pList, pShad); } // add character to object list InsertObject(pList, pChar); // move to end of list if (pChar->pSlave) pChar = pChar->pSlave; // add character spacing xJustify += FROM_16(pImg->imgWidth); } // finally add the inter-character spacing xJustify += FROM_32(pFont->xSpacing); // next character in string ++szStr; } // adjust the text y position and add the inter-line spacing yPos += yOffset + FROM_32(pFont->ySpacing); // check for newline if (c == LF_CHAR) // next character in string ++szStr; } // return head of list return pFirst; }
static void LoadScene(SCNHANDLE scene, int entry) { uint i; TP_INIT init; const SCENE_STRUC *ss; const ENTRANCE_STRUC *es; // Scene handle SceneHandle = scene; // Save scene handle in case of Save_Scene() LockMem(SceneHandle); // Make sure scene is loaded LockScene(SceneHandle); // Prevent current scene from being discarded if (TinselV2) { // CdPlay() stuff byte *cptr = FindChunk(scene, CHUNK_CDPLAY_FILENUM); assert(cptr); i = READ_LE_UINT32(cptr); assert(i < 512); cptr = FindChunk(scene, CHUNK_CDPLAY_FILENAME); assert(cptr); SetCdPlaySceneDetails(i, (const char *)cptr); } // Find scene structure ss = GetSceneStruc(FindChunk(scene, CHUNK_SCENE)); assert(ss != NULL); if (TinselV2) { // Handle to scene description newestScene = FROM_LE_32(ss->hSceneDesc); // Music stuff char *cptr = (char *)FindChunk(scene, CHUNK_MUSIC_FILENAME); assert(cptr); _vm->_pcmMusic->setMusicSceneDetails(FROM_LE_32(ss->hMusicScript), FROM_LE_32(ss->hMusicSegment), cptr); } if (entry == NO_ENTRY_NUM) { // Restoring scene // Initialise all the polygons for this scene InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), true); // Initialise the actors for this scene StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), false); if (TinselV2) // Returning from cutscene SendSceneTinselProcess(RESTORE); } else { // Genuine new scene // Initialise all the polygons for this scene InitPolygons(FROM_LE_32(ss->hPoly), FROM_LE_32(ss->numPoly), false); // Initialise the actors for this scene StartTaggedActors(FROM_LE_32(ss->hTaggedActor), FROM_LE_32(ss->numTaggedActor), true); // Run the appropriate entrance code (if any) es = (const ENTRANCE_STRUC *)LockMem(FROM_LE_32(ss->hEntrance)); for (i = 0; i < FROM_LE_32(ss->numEntrance); i++) { if (FROM_LE_32(es->eNumber) == (uint)entry) { if (es->hScript) { init.event = STARTUP; init.hTinselCode = es->hScript; g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } break; } // Move to next entrance if (TinselV2) ++es; else es = (const ENTRANCE_STRUC *)((const byte *)es + 8); } if (i == FROM_LE_32(ss->numEntrance)) error("Non-existant scene entry number"); if (ss->hSceneScript) { init.event = STARTUP; init.hTinselCode = ss->hSceneScript; g_scheduler->createProcess(PID_TCODE, SceneTinselProcess, &init, sizeof(init)); } } // Default refer type SetDefaultRefer(FROM_LE_32(ss->defRefer)); // Scene's processes SceneProcesses(FROM_LE_32(ss->numProcess), FROM_LE_32(ss->hProcess)); }
/** * Tinsel 2 Moving actor process * - 1 per moving actor in current scene. */ void T2MoverProcess(CORO_PARAM, const void *param) { CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); // Get the co-ordinates - copied to process when it was created const MAINIT *rpos = (const MAINIT *)param; PMOVER pMover = rpos->pMover; int i; FILM *pFilm; PMULTI_INIT pmi; CORO_BEGIN_CODE(_ctx); for (i = 0; i < TOTAL_SCALES; i++) { if (pMover->walkReels[i][FORWARD]) break; } assert(i < TOTAL_SCALES); InitMover(pMover); InitialPathChecks(pMover, rpos->X, rpos->Y); pFilm = (FILM *)LockMem(pMover->walkReels[i][FORWARD]); // Any old reel pmi = (PMULTI_INIT)LockMem(FROM_32(pFilm->reels[0].mobj)); // Poke in the background palette PokeInPalette(pmi); pMover->actorObj = MultiInitObject(pmi); // FIXME: This is what the original did. A bug, perhaps? // pMover->actorID = pMover->actorID; pMover->bActive = true; // add it to display list MultiInsertObject( GetPlayfieldList(FIELD_WORLD), pMover->actorObj ); InitStepAnimScript(&pMover->actorAnim, pMover->actorObj, pFilm->reels[0].script, ONE_SECOND/pFilm->frate); pMover->stepCount = 0; MultiSetAniXY(pMover->actorObj, pMover->objX, pMover->objY); // If no path, just use first path in the scene if (pMover->hCpath != NOPOLY) SetMoverZ(pMover, pMover->objY, GetPolyZfactor(pMover->hCpath)); else SetMoverZ(pMover, pMover->objY, GetPolyZfactor(FirstPathPoly())); // Make him the right size SetMoverStanding(pMover); HideMover(pMover); // Allows a play to come in before this appears pMover->bHidden = false; // ...but don't stay hidden for (;;) { if (pMover->bSpecReel) { if (!pMover->bHidden) StepAnimScript(&pMover->actorAnim); } else DoMoveActor(pMover); CheckBrightness(pMover); CORO_SLEEP(1); } CORO_END_CODE; }
bool PCMMusicPlayer::getNextChunk() { MusicSegment *musicSegments; int32 *script, *scriptBuffer; int id; int snum; uint32 sampleOffset, sampleLength, sampleCLength; Common::File file; byte *buffer; Common::SeekableReadStream *sampleStream; switch (_state) { case S_NEW: case S_NEXT: _forcePlay = false; script = scriptBuffer = (int32 *)LockMem(_hScript); // Set parameters for this chunk of music id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex++]); if (snum == MUSIC_JUMP || snum == MUSIC_END) { // Let usual code sort it out! _scriptIndex--; // Undo increment _forcePlay = true; // Force a Play _state = S_END1; // 'Goto' S_END1 break; } musicSegments = (MusicSegment *) LockMem(_hSegment); assert(FROM_32(musicSegments[snum].numChannels) == 1); assert(FROM_32(musicSegments[snum].bitsPerSample) == 16); sampleOffset = FROM_32(musicSegments[snum].sampleOffset); sampleLength = FROM_32(musicSegments[snum].sampleLength); sampleCLength = (((sampleLength + 63) & ~63)*33)/64; if (!file.open(_filename)) error(CANNOT_FIND_FILE, _filename.c_str()); file.seek(sampleOffset); if (file.eos() || file.err() || (uint32)file.pos() != sampleOffset) error(FILE_IS_CORRUPT, _filename.c_str()); buffer = (byte *) malloc(sampleCLength); assert(buffer); // read all of the sample if (file.read(buffer, sampleCLength) != sampleCLength) error(FILE_IS_CORRUPT, _filename.c_str()); debugC(DEBUG_DETAILED, kTinselDebugMusic, "Creating ADPCM music chunk with size %d, " "offset %d (script %d.%d)", sampleCLength, sampleOffset, _scriptNum, _scriptIndex - 1); sampleStream = new Common::MemoryReadStream(buffer, sampleCLength, DisposeAfterUse::YES); delete _curChunk; _curChunk = new Tinsel8_ADPCMStream(sampleStream, DisposeAfterUse::YES, sampleCLength, 22050, 1, 32); _state = S_MID; return true; case S_END1: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END1 (script %d.%d)", _scriptNum, _scriptIndex); script = scriptBuffer = (int32 *) LockMem(_hScript); id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex]); if (snum == MUSIC_END) { _state = S_END2; } else { if (snum == MUSIC_JUMP) _scriptIndex = FROM_32(script[_scriptIndex+1]); _state = _forcePlay ? S_NEW : S_NEXT; _forcePlay = false; } return true; case S_END2: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END2 (script %d.%d)", _scriptNum, _scriptIndex); _silenceSamples = 11025; // Half a second of silence return true; case S_END3: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END3 (script %d.%d)", _scriptNum, _scriptIndex); stop(); _state = S_IDLE; return false; case S_IDLE: return false; default: break; } return true; }