static BOOLEAN TalkSegue (COUNT wait_track) { TALKING_STATE talkingState; // Transition animation to talking state, if necessary if (wantTalkingAnim () && haveTalkingAnim ()) { if (haveTransitionAnim ()) setRunIntroAnim (); setRunTalkingAnim (); // wait until the transition finishes while (runningIntroAnim ()) runCommAnimFrame (); } memset (&talkingState, 0, sizeof talkingState); if (wait_track == 0) { // Restarting with a rewind wait_track = WAIT_TRACK_ALL; talkingState.rewind = true; } else if (!PlayingTrack ()) { // initial start of player PlayTrack (); assert (PlayingTrack ()); } // Run the talking controls SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); talkingState.InputFunc = DoTalkSegue; talkingState.waitTrack = wait_track; DoInput (&talkingState, FALSE); ClearSubtitles (); if (talkingState.ended) { // reached the end; set STOP icon SetSliderImage (SetAbsFrameIndex (ActivityFrame, 8)); } // transition back to silent, if necessary if (runningTalkingAnim ()) setStopTalkingAnim (); // Wait until the animation task stops "talking" while (runningTalkingAnim ()) runCommAnimFrame (); return talkingState.ended; }
BOOLEAN ProcessCommAnimations (BOOLEAN FullRedraw, BOOLEAN paused) { if (paused) { // Drive colormap xforms and nothing else XFormColorMap_step (); return FALSE; } else { COUNT i; SEQUENCE *pSeq; BOOLEAN Change; BOOLEAN CanTalk = TRUE; TimeCount CurTime; DWORD ElapsedTicks; DWORD NextActiveMask; CurTime = GetTimeCounter (); ElapsedTicks = CurTime - LastTime; LastTime = CurTime; // Process ambient animations NextActiveMask = ActiveMask; pSeq = Sequences + FirstAmbient; for (i = 0; i < CommData.NumAnimations; ++i, ++pSeq) { ANIMATION_DESC *ADPtr = pSeq->ADPtr; DWORD ActiveBit = 1L << i; if (ADPtr->AnimFlags & ANIM_DISABLED) continue; if (pSeq->Direction == NO_DIR) { // animation is paused if (!conflictsWithTalkingAnim (pSeq)) { // start it up pSeq->Direction = UP_DIR; } } else if (pSeq->Alarm > ElapsedTicks) { // not time yet pSeq->Alarm -= ElapsedTicks; } else if (ActiveMask & ADPtr->BlockMask) { // animation is blocked assert (!(ActiveMask & ActiveBit) && "Check animations' mutual blocking masks"); assert (animAtNeutralIndex (pSeq)); // reschedule pSeq->Alarm = randomRestartRate (pSeq) + 1; continue; } else { // Time to start or advance the animation if (AdvanceAmbientSequence (pSeq)) { // Animation is active this frame and the next ActiveMask |= ActiveBit; NextActiveMask |= ActiveBit; } else { // Animation remains active this frame but not the next // This keeps any conflicting animations (BlockMask) // from activating in the same frame and scribbling over // our last image. NextActiveMask &= ~ActiveBit; } } if (pSeq->AnimType == PICTURE_ANIM && pSeq->Direction != NO_DIR && conflictsWithTalkingAnim (pSeq)) { // We want to talk, but this is a running picture animation // which conflicts with the talking animation // See if it is safe to stop it now. if (animAtNeutralIndex (pSeq)) { // pause the animation pSeq->Direction = NO_DIR; NextActiveMask &= ~ActiveBit; // Talk animation is drawn last, so it's not a conflict // for this frame. The talk animation will be drawn // over the neutral frame. } else { // Otherwise, let the animation run until it's safe CanTalk = FALSE; } } // BW: to be checked. I've tried to remove what's supposed to be removed while keeping the Syreen zoom-in feature. // It may have to be re-programmed in the new commanim style. if (pSeq->AnimType == PICTURE_ANIM && (ADPtr->AnimFlags & CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING) && pSeq->Direction != NO_DIR) { // JMS: Cut marked animations short when starting talk. // The animations are marked with FAST_STOP_AT_TALK_START in the races' comm source codes. if (ADPtr->AnimFlags & FAST_STOP_AT_TALK_START) { CanTalk = TRUE; //pSeq->AnimObj.CurFrame = SetAbsFrameIndex(pSeq->AnimObj.CurFrame, ADPtr->StartIndex); pSeq->Direction = NO_DIR; } } // JMS: This handles ambient animations which should occur only during talk // A lot of conditions are necessary to eliminate unwanted animations // from the duration of talk transition! if (pSeq->AnimType == PICTURE_ANIM && ADPtr->AnimFlags & WHEN_TALKING && (!(CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING) || (CommData.AlienTalkDesc.AnimFlags & TALK_INTRO) || (CommData.AlienTalkDesc.AnimFlags & TALK_DONE)) && !(CommData.AlienTransitionDesc.AnimFlags & PAUSE_TALKING) && pSeq->Direction != NO_DIR) { // Stop the anim if not talking pSeq->Direction = NO_DIR; } } // All ambient animations have been processed. Advance the mask. ActiveMask = NextActiveMask; // Process the talking and transition animations if (CanTalk && haveTalkingAnim () && runningTalkingAnim ()) { BOOLEAN done = FALSE; if (signaledStopTalkingAnim () && haveTransitionAnim ()) { // Run the transition. We will clear everything // when it is done CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE; } if (CommData.AlienTransitionDesc.AnimFlags & (TALK_INTRO | TALK_DONE)) { // Transitioning in or out of talking if ((CommData.AlienTransitionDesc.AnimFlags & TALK_DONE) && Transit->Direction == NO_DIR) { // This is needed when switching talking anims ResetSequence (Talk); } done = AdvanceTransitSequence (Transit, ElapsedTicks); } else if (!signaledStopTalkingAnim ()) { // Talking, transition is done AdvanceTalkingSequence (Talk, ElapsedTicks); } else { // Not talking ResetSequence (Talk); done = TRUE; } if (signaledStopTalkingAnim () && done) { clearRunTalkingAnim (); clearStopTalkingAnim (); } } else { // Not talking -- disable talking anim if it is done if (Talk->Direction == NO_DIR) TalkDesc.AnimFlags |= ANIM_DISABLED; } BatchGraphics (); // Draw all animations { BOOLEAN ColorChange = XFormColorMap_step (); if (ColorChange) FullRedraw = TRUE; // Colormap animations are processed separately // from picture anims (see XFormColorMap_step) ProcessColormapAnims (Sequences + FirstAmbient, CommData.NumAnimations); Change = DrawAlienFrame (Sequences, TotalSequences, FullRedraw); if (FullRedraw) Change = TRUE; } UnbatchGraphics (); // Post-process ambient animations pSeq = Sequences + FirstAmbient; for (i = 0; i < CommData.NumAnimations; ++i, ++pSeq) { ANIMATION_DESC *ADPtr = pSeq->ADPtr; DWORD ActiveBit = 1L << i; if (ADPtr->AnimFlags & ANIM_DISABLED) continue; // We can only disable a one-shot anim here, otherwise the // last frame will not be drawn if ((ADPtr->AnimFlags & ONE_SHOT_ANIM) && !(NextActiveMask & ActiveBit)) { // One-shot animation, inactive next frame ADPtr->AnimFlags |= ANIM_DISABLED; } } return Change; } }