Comm animation processing rewrite; cleaner and meaner; a bunch of bugs fixed, and some probably added ;)
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3305 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
Changes towards version 0.7:
|
||||
- Comm animation processing rewrite, bugs fixed - Alex
|
||||
- Added graphics context debugging function - SvdB
|
||||
- Thread down-throttling and game sleep when inactive (currently disabled),
|
||||
(bug #1070), from Flandry
|
||||
|
||||
+50
-109
@@ -53,6 +53,8 @@ LOCDATA CommData;
|
||||
int cur_comm;
|
||||
UNICODE shared_phrase_buf[2048];
|
||||
|
||||
static BOOLEAN TalkingFinished;
|
||||
|
||||
typedef struct response_entry
|
||||
{
|
||||
RESPONSE_REF response_ref;
|
||||
@@ -87,7 +89,6 @@ static const UNICODE * volatile last_subtitle;
|
||||
static CONTEXT TextCacheContext;
|
||||
static FRAME TextCacheFrame;
|
||||
|
||||
volatile BOOLEAN ClearSummary;
|
||||
|
||||
RECT CommWndRect = {
|
||||
// default values; actually inited by HailAlien()
|
||||
@@ -382,51 +383,6 @@ DrawSISComWindow (void)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DrawAlienFrame (FRAME aframe, SEQUENCE *pSeq)
|
||||
{
|
||||
COUNT i;
|
||||
STAMP s;
|
||||
ANIMATION_DESC *ADPtr;
|
||||
|
||||
s.origin.x = -SAFE_X;
|
||||
s.origin.y = 0;
|
||||
s.frame = CommData.AlienFrame;
|
||||
if (s.frame == 0)
|
||||
s.frame = aframe;
|
||||
|
||||
BatchGraphics ();
|
||||
DrawStamp (&s);
|
||||
i = CommData.NumAnimations;
|
||||
ADPtr = &CommData.AlienAmbientArray[i];
|
||||
while (i--)
|
||||
{
|
||||
--ADPtr;
|
||||
|
||||
if (!(ADPtr->AnimFlags & ANIM_MASK))
|
||||
{
|
||||
s.frame = SetAbsFrameIndex (s.frame, ADPtr->StartIndex);
|
||||
DrawStamp (&s);
|
||||
ADPtr->AnimFlags |= ANIM_DISABLED;
|
||||
}
|
||||
else if (pSeq)
|
||||
{
|
||||
if (pSeq->AnimType == PICTURE_ANIM)
|
||||
{
|
||||
s.frame = pSeq->AnimObj.CurFrame;
|
||||
DrawStamp (&s);
|
||||
}
|
||||
--pSeq;
|
||||
}
|
||||
}
|
||||
if (aframe && CommData.AlienFrame && aframe != CommData.AlienFrame)
|
||||
{
|
||||
s.frame = aframe;
|
||||
DrawStamp (&s);
|
||||
}
|
||||
UnbatchGraphics ();
|
||||
}
|
||||
|
||||
void
|
||||
init_communication (void)
|
||||
{
|
||||
@@ -553,13 +509,11 @@ SpewPhrases (COUNT wait_track)
|
||||
BOOLEAN ContinuityBreak;
|
||||
DWORD TimeIn;
|
||||
COUNT which_track;
|
||||
FRAME F;
|
||||
BOOLEAN rewind = FALSE;
|
||||
|
||||
TimeIn = GetTimeCounter ();
|
||||
|
||||
ContinuityBreak = FALSE;
|
||||
F = CommData.AlienFrame;
|
||||
if (wait_track == 0)
|
||||
{ // Restarting with a rewind
|
||||
wait_track = (COUNT)~0;
|
||||
@@ -636,12 +590,10 @@ SpewPhrases (COUNT wait_track)
|
||||
else if (optSmoothScroll == OPT_3DO)
|
||||
FastForward_Smooth ();
|
||||
ContinuityBreak = TRUE;
|
||||
// XXX: Ugly hack: This causes all animations (talking and ambient)
|
||||
// XXX: This causes all animations (talking and ambient)
|
||||
// in ambient_anim_task to stop progressing. I see no reason why
|
||||
// the animations cannot continue while seeking. This hack has
|
||||
// spawned a multitude of workarounds in the comm code, and IMHO
|
||||
// should be removed.
|
||||
CommData.AlienFrame = 0;
|
||||
// the animations cannot continue while seeking.
|
||||
PauseAnimTask = TRUE;
|
||||
}
|
||||
else if (left || rewind)
|
||||
{
|
||||
@@ -652,8 +604,8 @@ SpewPhrases (COUNT wait_track)
|
||||
else if (optSmoothScroll == OPT_3DO)
|
||||
FastReverse_Smooth ();
|
||||
ContinuityBreak = TRUE;
|
||||
// XXX: See ugly hack discussion above
|
||||
CommData.AlienFrame = 0;
|
||||
// XXX: See pause discussion above
|
||||
PauseAnimTask = TRUE;
|
||||
}
|
||||
else if (ContinuityBreak)
|
||||
{
|
||||
@@ -663,20 +615,20 @@ SpewPhrases (COUNT wait_track)
|
||||
SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2));
|
||||
}
|
||||
else
|
||||
{ // XXX: See ugly hack discussion above
|
||||
{ // XXX: See pause discussion above
|
||||
// Additionally, this used to have a buggy guard condition, which
|
||||
// would cause the animations to remain paused in a couple cases
|
||||
// after seeking back to the beginning.
|
||||
// Broken cases were: Syreen "several hours later" and Starbase
|
||||
// VUX Beast analysis by the scientist.
|
||||
CommData.AlienFrame = F;
|
||||
PauseAnimTask = FALSE;
|
||||
}
|
||||
|
||||
which_track = PlayingTrack ();
|
||||
|
||||
} while (ContinuityBreak || (which_track && which_track <= wait_track));
|
||||
|
||||
CommData.AlienFrame = F;
|
||||
PauseAnimTask = FALSE;
|
||||
ClearSubtitles ();
|
||||
|
||||
if (!which_track || wait_track == (COUNT)~0)
|
||||
@@ -696,22 +648,17 @@ DoTalkSegue (COUNT wait_track)
|
||||
BOOLEAN done;
|
||||
|
||||
// Transition animation to talking state, if necessary
|
||||
if (CommData.AlienTalkDesc.NumFrames)
|
||||
if (wantTalkingAnim () && haveTalkingAnim ())
|
||||
{
|
||||
if (!(CommData.AlienTransitionDesc.AnimFlags & TALK_INTRO))
|
||||
{
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_INTRO;
|
||||
if (CommData.AlienTransitionDesc.NumFrames)
|
||||
CommData.AlienTalkDesc.AnimFlags |= TALK_INTRO;
|
||||
}
|
||||
if (haveTransitionAnim ())
|
||||
setRunIntroAnim ();
|
||||
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~PAUSE_TALKING;
|
||||
if (CommData.AlienTalkDesc.NumFrames)
|
||||
CommData.AlienTalkDesc.AnimFlags |= WAIT_TALKING;
|
||||
while (CommData.AlienTalkDesc.AnimFlags & TALK_INTRO)
|
||||
setRunTalkingAnim ();
|
||||
|
||||
while (runningIntroAnim ())
|
||||
{ // wait until the transition finishes
|
||||
UnlockMutex (GraphicsLock);
|
||||
TaskSwitch ();
|
||||
SleepThread (ONE_SECOND / 30);
|
||||
LockMutex (GraphicsLock);
|
||||
}
|
||||
}
|
||||
@@ -719,14 +666,8 @@ DoTalkSegue (COUNT wait_track)
|
||||
done = !SpewPhrases (wait_track);
|
||||
|
||||
// transition back to silent, if necessary
|
||||
if (CommData.AlienTalkDesc.NumFrames)
|
||||
{
|
||||
// must set the TALK_DONE flag so that the animation task
|
||||
// releases WAIT_TALKING from AlienTalkDesc
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
if ((CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING))
|
||||
CommData.AlienTalkDesc.AnimFlags |= PAUSE_TALKING;
|
||||
}
|
||||
if (runningTalkingAnim ())
|
||||
setStopTalkingAnim ();
|
||||
|
||||
return done;
|
||||
}
|
||||
@@ -734,13 +675,15 @@ DoTalkSegue (COUNT wait_track)
|
||||
static void
|
||||
FlushTalkSegue (void)
|
||||
{
|
||||
WaitForNoInput (ONE_SECOND / 2);
|
||||
FlushInput ();
|
||||
while (AnyButtonPress (TRUE))
|
||||
TaskSwitch ();
|
||||
|
||||
// Wait until the animation task stops "talking"
|
||||
do
|
||||
TaskSwitch ();
|
||||
while (CommData.AlienTalkDesc.AnimFlags & PAUSE_TALKING);
|
||||
SleepThread (ONE_SECOND / 30);
|
||||
while (runningTalkingAnim ());
|
||||
|
||||
TalkingFinished = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -749,8 +692,7 @@ AlienTalkSegue (COUNT wait_track)
|
||||
BOOLEAN done;
|
||||
|
||||
// this skips any talk segues that follow an aborted one
|
||||
if ((GLOBAL (CurrentActivity) & CHECK_ABORT)
|
||||
|| (CommData.AlienTransitionDesc.AnimFlags & TALK_DONE))
|
||||
if ((GLOBAL (CurrentActivity) & CHECK_ABORT) || TalkingFinished)
|
||||
return;
|
||||
|
||||
LockMutex (GraphicsLock);
|
||||
@@ -758,7 +700,7 @@ AlienTalkSegue (COUNT wait_track)
|
||||
if (!pCurInputState->Initialized)
|
||||
{
|
||||
SetColorMap (GetColorMapAddress (CommData.AlienColorMap));
|
||||
DrawAlienFrame (CommData.AlienFrame, NULL);
|
||||
DrawAlienFrame (NULL, 0, TRUE);
|
||||
UpdateSpeechGraphics (TRUE);
|
||||
|
||||
if (LOBYTE (GLOBAL (CurrentActivity)) == WON_LAST_BATTLE
|
||||
@@ -807,7 +749,8 @@ AlienTalkSegue (COUNT wait_track)
|
||||
DWORD TimeOut;
|
||||
|
||||
TimeOut = GetTimeCounter () + (ONE_SECOND >> 1);
|
||||
/* if (CommData.NumAnimations) */
|
||||
// Anim task processes not only ambient animations, but also
|
||||
// talking animations and subtitles
|
||||
pCurInputState->AnimTask = StartCommAnimTask ();
|
||||
|
||||
UnlockMutex (GraphicsLock);
|
||||
@@ -825,15 +768,9 @@ AlienTalkSegue (COUNT wait_track)
|
||||
UnlockMutex (GraphicsLock);
|
||||
FlushTalkSegue ();
|
||||
|
||||
if (done || wait_track == (COUNT)~0)
|
||||
{ // all done talking here
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
}
|
||||
else
|
||||
if (!done && wait_track != (COUNT)~0)
|
||||
{ // there is more to come
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~TALK_DONE;
|
||||
// allow a transition to talking state again later
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~TALK_INTRO;
|
||||
TalkingFinished = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1000,7 +937,7 @@ SelectResponse (ENCOUNTER_STATE *pES)
|
||||
|
||||
FadeMusic (BACKGROUND_VOL, ONE_SECOND);
|
||||
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~(TALK_INTRO | TALK_DONE);
|
||||
TalkingFinished = FALSE;
|
||||
pES->num_responses = 0;
|
||||
(*pES->response_list[pES->cur_response].response_func)
|
||||
(pES->response_list[pES->cur_response].response_ref);
|
||||
@@ -1024,7 +961,7 @@ SelectConversationSummary (ENCOUNTER_STATE *pES)
|
||||
|
||||
LockMutex (GraphicsLock);
|
||||
RefreshResponses (pES);
|
||||
ClearSummary = TRUE;
|
||||
clear_subtitles = TRUE;
|
||||
PauseAnimTask = FALSE;
|
||||
UnlockMutex (GraphicsLock);
|
||||
}
|
||||
@@ -1060,9 +997,7 @@ PlayerResponseInput (ENCOUNTER_STATE *pES)
|
||||
FadeMusic (BACKGROUND_VOL, ONE_SECOND);
|
||||
LockMutex (GraphicsLock);
|
||||
FeedbackPlayerPhrase (pES->phrase_buf);
|
||||
// reset transition state
|
||||
CommData.AlienTransitionDesc.AnimFlags &=
|
||||
~(TALK_INTRO | TALK_DONE);
|
||||
TalkingFinished = FALSE;
|
||||
DoTalkSegue (0);
|
||||
|
||||
if (!(GLOBAL (CurrentActivity) & CHECK_ABORT))
|
||||
@@ -1073,9 +1008,6 @@ PlayerResponseInput (ENCOUNTER_STATE *pES)
|
||||
|
||||
UnlockMutex (GraphicsLock);
|
||||
FlushTalkSegue ();
|
||||
// done one way or the other
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_UP])
|
||||
response = (BYTE)((response + (BYTE)(pES->num_responses - 1))
|
||||
@@ -1119,7 +1051,8 @@ DoCommunication (ENCOUNTER_STATE *pES)
|
||||
{
|
||||
SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT);
|
||||
|
||||
if (!(CommData.AlienTransitionDesc.AnimFlags & TALK_DONE))
|
||||
// First, finish playing all queued tracks if not done yet
|
||||
if (!TalkingFinished)
|
||||
AlienTalkSegue ((COUNT)~0);
|
||||
|
||||
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
|
||||
@@ -1141,14 +1074,10 @@ DoCommunication (ENCOUNTER_STATE *pES)
|
||||
{
|
||||
FadeMusic (BACKGROUND_VOL, ONE_SECOND);
|
||||
LockMutex (GraphicsLock);
|
||||
// reset transition state
|
||||
CommData.AlienTransitionDesc.AnimFlags &=
|
||||
~(TALK_INTRO | TALK_DONE);
|
||||
TalkingFinished = FALSE;
|
||||
DoTalkSegue (0);
|
||||
UnlockMutex (GraphicsLock);
|
||||
FlushTalkSegue ();
|
||||
// done one way or the other
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
|
||||
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
|
||||
break;
|
||||
@@ -1172,7 +1101,6 @@ DoCommunication (ENCOUNTER_STATE *pES)
|
||||
LockMutex (GraphicsLock);
|
||||
pES->AnimTask = 0;
|
||||
}
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~(TALK_INTRO | TALK_DONE);
|
||||
|
||||
SetContext (SpaceContext);
|
||||
DestroyContext (TaskContext);
|
||||
@@ -1243,6 +1171,8 @@ HailAlien (void)
|
||||
pCurInputState = &ES;
|
||||
memset (pCurInputState, 0, sizeof (*pCurInputState));
|
||||
|
||||
TalkingFinished = FALSE;
|
||||
|
||||
ES.InputFunc = DoCommunication;
|
||||
PlayerFont = LoadFont (PLAYER_FONT);
|
||||
|
||||
@@ -1443,7 +1373,9 @@ InitCommunication (CONVERSATION which_comm)
|
||||
status != YEHAT_REBEL_SHIP ? which_comm :
|
||||
YEHAT_REBEL_CONVERSATION);
|
||||
if (LocDataPtr)
|
||||
{ // We make a copy here
|
||||
CommData = *LocDataPtr;
|
||||
}
|
||||
|
||||
UnlockMutex (GraphicsLock);
|
||||
|
||||
@@ -1717,3 +1649,12 @@ CheckSubtitles (void)
|
||||
}
|
||||
UnlockMutex (subtitle_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
EnableTalkingAnim (BOOLEAN enable)
|
||||
{
|
||||
if (enable)
|
||||
CommData.AlienTalkDesc.AnimFlags &= ~PAUSE_TALKING;
|
||||
else
|
||||
CommData.AlienTalkDesc.AnimFlags |= PAUSE_TALKING;
|
||||
}
|
||||
|
||||
+68
-3
@@ -28,10 +28,73 @@
|
||||
|
||||
#include "commanim.h"
|
||||
|
||||
extern void DrawAlienFrame (FRAME aframe, SEQUENCE *pSeq);
|
||||
|
||||
extern LOCDATA CommData;
|
||||
extern volatile BOOLEAN ClearSummary;
|
||||
|
||||
static inline BOOLEAN
|
||||
haveTalkingAnim (void)
|
||||
{
|
||||
return CommData.AlienTalkDesc.NumFrames > 0;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
haveTransitionAnim (void)
|
||||
{
|
||||
return CommData.AlienTransitionDesc.NumFrames > 0;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
wantTalkingAnim (void)
|
||||
{
|
||||
return !(CommData.AlienTalkDesc.AnimFlags & PAUSE_TALKING);
|
||||
}
|
||||
|
||||
static inline void
|
||||
setRunTalkingAnim (void)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags |= WAIT_TALKING;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clearRunTalkingAnim (void)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags &= ~WAIT_TALKING;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
runningTalkingAnim (void)
|
||||
{
|
||||
return (CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING);
|
||||
}
|
||||
|
||||
static inline void
|
||||
setRunIntroAnim (void)
|
||||
{
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_INTRO;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
runningIntroAnim (void)
|
||||
{
|
||||
return (CommData.AlienTransitionDesc.AnimFlags & TALK_INTRO);
|
||||
}
|
||||
|
||||
static inline void
|
||||
setStopTalkingAnim (void)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags |= TALK_DONE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clearStopTalkingAnim (void)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags &= ~TALK_DONE;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
signaledStopTalkingAnim (void)
|
||||
{
|
||||
return CommData.AlienTalkDesc.AnimFlags & TALK_DONE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +108,8 @@ extern BOOLEAN HaveSubtitlesChanged (void);
|
||||
|
||||
extern RECT CommWndRect; /* comm window rect */
|
||||
|
||||
extern void EnableTalkingAnim (BOOLEAN enable);
|
||||
|
||||
#endif /* _COMM_H */
|
||||
|
||||
|
||||
|
||||
@@ -838,14 +838,13 @@ Intro (void)
|
||||
|
||||
if (!GET_GAME_STATE (MET_ORZ_BEFORE))
|
||||
{
|
||||
BYTE N;
|
||||
|
||||
SET_GAME_STATE (MET_ORZ_BEFORE, 1);
|
||||
|
||||
N = CommData.AlienTalkDesc.NumFrames;
|
||||
CommData.AlienTalkDesc.NumFrames = 0;
|
||||
// Disable talking anim and run the computer report
|
||||
EnableTalkingAnim (FALSE);
|
||||
AlienTalkSegue (1);
|
||||
CommData.AlienTalkDesc.NumFrames = N;
|
||||
// Run whatever is left with talking anim
|
||||
EnableTalkingAnim (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1291,11 +1291,10 @@ DiscussDevices (BOOLEAN TalkAbout)
|
||||
// Run all tracks upto the Vux Beast scientist's report
|
||||
AlienTalkSegue (VuxBeastIndex - 1);
|
||||
// Disable Commander's speech animation and run the report
|
||||
i = CommData.AlienTalkDesc.NumFrames;
|
||||
CommData.AlienTalkDesc.NumFrames = 0;
|
||||
EnableTalkingAnim (FALSE);
|
||||
AlienTalkSegue (VuxBeastIndex);
|
||||
// Enable Commander's speech animation and run the rest
|
||||
CommData.AlienTalkDesc.NumFrames = i;
|
||||
EnableTalkingAnim (TRUE);
|
||||
AlienTalkSegue ((COUNT)~0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +123,12 @@ SelectAlienZOQ (void)
|
||||
{
|
||||
if (LastAlien != ZOQ_ALIEN)
|
||||
{
|
||||
// Transition to neutral state first if Pik was talking
|
||||
if (LastAlien != FOT_ALIEN)
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
LastAlien = ZOQ_ALIEN;
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_INTRO;
|
||||
CommData.AlienTransitionDesc.StartIndex = FOT_TO_ZOQ;
|
||||
CommData.AlienTalkDesc.AnimFlags |= TALK_INTRO;
|
||||
CommData.AlienTalkDesc.StartIndex = ZOQ_TALK_INDEX;
|
||||
CommData.AlienTalkDesc.NumFrames = ZOQ_TALK_FRAMES;
|
||||
CommData.AlienAmbientArray[1].AnimFlags &= ~WAIT_TALKING;
|
||||
@@ -142,9 +145,12 @@ SelectAlienPIK (void)
|
||||
{
|
||||
if (LastAlien != PIK_ALIEN)
|
||||
{
|
||||
// Transition to neutral state first if Zoq was talking
|
||||
if (LastAlien != FOT_ALIEN)
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_DONE;
|
||||
LastAlien = PIK_ALIEN;
|
||||
CommData.AlienTransitionDesc.AnimFlags |= TALK_INTRO;
|
||||
CommData.AlienTransitionDesc.StartIndex = FOT_TO_PIK;
|
||||
CommData.AlienTalkDesc.AnimFlags |= TALK_INTRO;
|
||||
CommData.AlienTalkDesc.StartIndex = PIK_TALK_INDEX;
|
||||
CommData.AlienTalkDesc.NumFrames = PIK_TALK_FRAMES;
|
||||
CommData.AlienAmbientArray[1].AnimFlags |= WAIT_TALKING;
|
||||
|
||||
+474
-372
@@ -44,118 +44,371 @@ static int ambient_anim_task (void *data);
|
||||
|
||||
volatile BOOLEAN PauseAnimTask = FALSE;
|
||||
|
||||
static inline DWORD
|
||||
randomFrameRate (SEQUENCE *pSeq)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
return ADPtr->BaseFrameRate +
|
||||
TFB_Random () % (ADPtr->RandomFrameRate + 1);
|
||||
}
|
||||
|
||||
static inline DWORD
|
||||
randomRestartRate (SEQUENCE *pSeq)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
return ADPtr->BaseRestartRate +
|
||||
TFB_Random () % (ADPtr->RandomRestartRate + 1);
|
||||
}
|
||||
|
||||
static inline COUNT
|
||||
randomFrameIndex (SEQUENCE *pSeq, COUNT from)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
return from + TFB_Random () % (ADPtr->NumFrames - from);
|
||||
}
|
||||
|
||||
static void
|
||||
SetUpSequence (SEQUENCE *pSeq)
|
||||
SetupAmbientSequences (SEQUENCE *pSeq, COUNT Num)
|
||||
{
|
||||
COUNT i;
|
||||
ANIMATION_DESC *ADPtr;
|
||||
|
||||
i = CommData.NumAnimations;
|
||||
pSeq = &pSeq[i];
|
||||
ADPtr = &CommData.AlienAmbientArray[i];
|
||||
while (i--)
|
||||
for (i = 0; i < Num; ++i, ++pSeq)
|
||||
{
|
||||
--ADPtr;
|
||||
--pSeq;
|
||||
ANIMATION_DESC *ADPtr = &CommData.AlienAmbientArray[i];
|
||||
|
||||
memset (pSeq, 0, sizeof (*pSeq));
|
||||
|
||||
pSeq->ADPtr = ADPtr;
|
||||
if (ADPtr->AnimFlags & COLORXFORM_ANIM)
|
||||
pSeq->AnimType = COLOR_ANIM;
|
||||
else
|
||||
pSeq->AnimType = PICTURE_ANIM;
|
||||
pSeq->Direction = UP_DIR;
|
||||
pSeq->FramesLeft = ADPtr->NumFrames;
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
pSeq->AnimObj.CurCMap = SetAbsColorMapIndex (
|
||||
CommData.AlienColorMap, ADPtr->StartIndex);
|
||||
else
|
||||
pSeq->AnimObj.CurFrame = SetAbsFrameIndex (
|
||||
CommData.AlienFrame, ADPtr->StartIndex);
|
||||
|
||||
// Default: first frame is neutral
|
||||
if (ADPtr->AnimFlags & RANDOM_ANIM)
|
||||
{
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
pSeq->AnimObj.CurCMap =
|
||||
SetRelColorMapIndex (pSeq->AnimObj.CurCMap,
|
||||
(COUNT)((COUNT)TFB_Random () % pSeq->FramesLeft));
|
||||
else
|
||||
pSeq->AnimObj.CurFrame =
|
||||
SetRelFrameIndex (pSeq->AnimObj.CurFrame,
|
||||
(COUNT)((COUNT)TFB_Random () % pSeq->FramesLeft));
|
||||
{ // Set a random frame/colormap
|
||||
pSeq->NextIndex = TFB_Random () % ADPtr->NumFrames;
|
||||
}
|
||||
else if (ADPtr->AnimFlags & YOYO_ANIM)
|
||||
{
|
||||
{ // Skip the first frame/colormap (it's neutral)
|
||||
pSeq->NextIndex = 1;
|
||||
--pSeq->FramesLeft;
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
pSeq->AnimObj.CurCMap =
|
||||
SetRelColorMapIndex (pSeq->AnimObj.CurCMap, 1);
|
||||
else
|
||||
pSeq->AnimObj.CurFrame =
|
||||
IncFrameIndex (pSeq->AnimObj.CurFrame);
|
||||
}
|
||||
else if (ADPtr->AnimFlags & CIRCULAR_ANIM)
|
||||
{ // Exception that makes everything more painful:
|
||||
// *Last* frame is neutral
|
||||
pSeq->CurIndex = ADPtr->NumFrames - 1;
|
||||
pSeq->NextIndex = 0;
|
||||
}
|
||||
|
||||
pSeq->Alarm = ADPtr->BaseRestartRate
|
||||
+ ((COUNT)TFB_Random () % (ADPtr->RandomRestartRate + 1)) + 1;
|
||||
pSeq->Alarm = randomRestartRate (pSeq) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SetupTalkSequence (SEQUENCE *pSeq, ANIMATION_DESC *ADPtr)
|
||||
{
|
||||
memset (pSeq, 0, sizeof (*pSeq));
|
||||
// Initially disabled, and until needed
|
||||
ADPtr->AnimFlags |= ANIM_DISABLED;
|
||||
pSeq->ADPtr = ADPtr;
|
||||
pSeq->AnimType = PICTURE_ANIM;
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
animAtNeutralIndex (SEQUENCE *pSeq)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
if (ADPtr->AnimFlags & CIRCULAR_ANIM)
|
||||
{ // CIRCULAR_ANIM's neutral frame is the last
|
||||
return pSeq->NextIndex == 0;
|
||||
}
|
||||
else
|
||||
{ // All others, neutral frame is the first
|
||||
return pSeq->CurIndex == 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline BOOLEAN
|
||||
conflictsWithTalkingAnim (SEQUENCE *pSeq)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
return ADPtr->AnimFlags & CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING;
|
||||
}
|
||||
|
||||
static void
|
||||
ProcessColormapAnims (SEQUENCE *pSeq, COUNT Num)
|
||||
{
|
||||
COUNT i;
|
||||
|
||||
for (i = 0; i < Num; ++i, ++pSeq)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
if ((ADPtr->AnimFlags & ANIM_DISABLED)
|
||||
|| pSeq->AnimType != COLOR_ANIM
|
||||
|| !pSeq->Change)
|
||||
continue;
|
||||
|
||||
XFormColorMap (GetColorMapAddress (
|
||||
SetAbsColorMapIndex (CommData.AlienColorMap,
|
||||
ADPtr->StartIndex + pSeq->CurIndex)),
|
||||
pSeq->Alarm - 1);
|
||||
pSeq->Change = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
AdvanceAmbientSequence (SEQUENCE *pSeq)
|
||||
{
|
||||
BOOLEAN active;
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
--pSeq->FramesLeft;
|
||||
// YOYO_ANIM does not actually end until it comes back
|
||||
// in reverse direction, even if FramesLeft gets to 0 here
|
||||
if (pSeq->FramesLeft
|
||||
|| ((ADPtr->AnimFlags & YOYO_ANIM) && pSeq->NextIndex != 0))
|
||||
{
|
||||
active = TRUE;
|
||||
pSeq->Alarm = randomFrameRate (pSeq) + 1;
|
||||
}
|
||||
else
|
||||
{ // animation ended
|
||||
active = FALSE;
|
||||
pSeq->Alarm = randomRestartRate (pSeq) + 1;
|
||||
}
|
||||
|
||||
// Will draw the next frame or change to next colormap
|
||||
pSeq->CurIndex = pSeq->NextIndex;
|
||||
pSeq->Change = TRUE;
|
||||
|
||||
if (pSeq->FramesLeft == 0)
|
||||
{ // Animation ended
|
||||
// Set it up for the next round
|
||||
pSeq->FramesLeft = ADPtr->NumFrames;
|
||||
|
||||
if (ADPtr->AnimFlags & YOYO_ANIM)
|
||||
{ // YOYO_ANIM never draws the first frame
|
||||
// ("first" depends on direction)
|
||||
--pSeq->FramesLeft;
|
||||
pSeq->Direction = -pSeq->Direction;
|
||||
}
|
||||
else if (ADPtr->AnimFlags & CIRCULAR_ANIM)
|
||||
{ // Rewind the CIRCULAR_ANIM
|
||||
// NextIndex will be brought to 0 just below
|
||||
pSeq->NextIndex = -1;
|
||||
}
|
||||
// RANDOM_ANIM is setup just below
|
||||
}
|
||||
|
||||
if (ADPtr->AnimFlags & RANDOM_ANIM)
|
||||
pSeq->NextIndex = randomFrameIndex (pSeq, 0);
|
||||
else
|
||||
pSeq->NextIndex += pSeq->Direction;
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
static void
|
||||
ResetSequence (SEQUENCE *pSeq)
|
||||
{
|
||||
// Reset the animation and cause a redraw of the neutral frame,
|
||||
// assuming it is not ANIM_DISABLED
|
||||
// NOTE: This does not handle CIRCULAR_ANIM properly
|
||||
pSeq->Direction = NO_DIR;
|
||||
pSeq->CurIndex = 0;
|
||||
pSeq->Change = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
AdvanceTalkingSequence (SEQUENCE *pSeq, DWORD ElapsedTicks)
|
||||
{
|
||||
// We use the actual descriptor for flags processing and
|
||||
// a copied one for drawing. A copied one is updated only
|
||||
// when it is safe to do so.
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
if (pSeq->Direction == NO_DIR)
|
||||
{ // just starting now
|
||||
pSeq->Direction = UP_DIR;
|
||||
// It's now safe to pick up new Talk descriptor if changed
|
||||
// (e.g. Zoq and Pik taking turns to talk)
|
||||
if (CommData.AlienTalkDesc.StartIndex != ADPtr->StartIndex)
|
||||
{ // copy the new one
|
||||
*ADPtr = CommData.AlienTalkDesc;
|
||||
}
|
||||
|
||||
assert (pSeq->CurIndex == 0);
|
||||
pSeq->Alarm = 0; // now!
|
||||
ADPtr->AnimFlags &= ~ANIM_DISABLED;
|
||||
}
|
||||
|
||||
if (pSeq->Alarm > ElapsedTicks)
|
||||
{ // Not time yet
|
||||
pSeq->Alarm -= ElapsedTicks;
|
||||
return;
|
||||
}
|
||||
|
||||
// Time to start or advance the animation
|
||||
pSeq->Alarm = randomFrameRate (pSeq);
|
||||
pSeq->Change = TRUE;
|
||||
// Talking animation is like RANDOM_ANIM, except that
|
||||
// random frames always alternate with the neutral one
|
||||
// The animation does not stop until we reset it
|
||||
if (pSeq->CurIndex == 0)
|
||||
{ // random frame next
|
||||
pSeq->CurIndex = randomFrameIndex (pSeq, 1);
|
||||
pSeq->Alarm += randomRestartRate (pSeq);
|
||||
}
|
||||
else
|
||||
{ // neutral frame next
|
||||
pSeq->CurIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
AdvanceTransitSequence (SEQUENCE *pSeq, DWORD ElapsedTicks)
|
||||
{
|
||||
BOOLEAN done = FALSE;
|
||||
// We use the actual descriptor for flags processing and
|
||||
// a copied one for drawing. A copied one is updated only
|
||||
// when it is safe to do so.
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
if (pSeq->Direction == NO_DIR)
|
||||
{ // just starting now
|
||||
pSeq->Alarm = 0; // now!
|
||||
ADPtr->AnimFlags &= ~ANIM_DISABLED;
|
||||
}
|
||||
|
||||
if (pSeq->Alarm > ElapsedTicks)
|
||||
{ // Not time yet
|
||||
pSeq->Alarm -= ElapsedTicks;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Time to start or advance the animation
|
||||
pSeq->Change = TRUE;
|
||||
|
||||
if (pSeq->Direction == NO_DIR)
|
||||
{ // just starting now
|
||||
pSeq->FramesLeft = ADPtr->NumFrames;
|
||||
// Both INTRO and DONE may be set at the same time,
|
||||
// when e.g. Zoq and Pik are taking turns to talk
|
||||
// Process the DONE transition first to go into
|
||||
// a neutral state before switching over.
|
||||
if (CommData.AlienTransitionDesc.AnimFlags & TALK_DONE)
|
||||
{
|
||||
pSeq->Direction = DOWN_DIR;
|
||||
pSeq->CurIndex = ADPtr->NumFrames - 1;
|
||||
}
|
||||
else if (CommData.AlienTransitionDesc.AnimFlags & TALK_INTRO)
|
||||
{
|
||||
pSeq->Direction = UP_DIR;
|
||||
// It's now safe to pick up new Transition descriptor if changed
|
||||
// (e.g. Zoq and Pik taking turns to talk)
|
||||
if (CommData.AlienTransitionDesc.StartIndex
|
||||
!= ADPtr->StartIndex)
|
||||
{ // copy the new one
|
||||
*ADPtr = CommData.AlienTransitionDesc;
|
||||
}
|
||||
|
||||
pSeq->CurIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
--pSeq->FramesLeft;
|
||||
if (pSeq->FramesLeft == 0)
|
||||
{ // animation is done
|
||||
if (pSeq->Direction == UP_DIR)
|
||||
{ // done with TALK_INTRO transition
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~TALK_INTRO;
|
||||
}
|
||||
else if (pSeq->Direction == DOWN_DIR)
|
||||
{ // done with TALK_DONE transition
|
||||
CommData.AlienTransitionDesc.AnimFlags &= ~TALK_DONE;
|
||||
|
||||
// Done with all transition frames
|
||||
ADPtr->AnimFlags |= ANIM_DISABLED;
|
||||
done = TRUE;
|
||||
}
|
||||
pSeq->Direction = NO_DIR;
|
||||
}
|
||||
else
|
||||
{ // next frame
|
||||
pSeq->Alarm = randomFrameRate (pSeq);
|
||||
pSeq->CurIndex += pSeq->Direction;
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
static int
|
||||
ambient_anim_task (void *data)
|
||||
{
|
||||
SIZE TalkAlarm;
|
||||
FRAME TalkFrame;
|
||||
FRAME ResetTalkFrame = NULL;
|
||||
FRAME TransitionFrame = NULL;
|
||||
FRAME AnimFrame[MAX_ANIMATIONS];
|
||||
COUNT i;
|
||||
DWORD LastTime;
|
||||
FRAME CommFrame;
|
||||
SEQUENCE Sequencer[MAX_ANIMATIONS];
|
||||
ANIMATION_DESC TalkBuffer = CommData.AlienTalkDesc;
|
||||
TimeCount LastTime;
|
||||
SEQUENCE Sequences[MAX_ANIMATIONS + 2];
|
||||
// 2 extra for Talk and Transition animations
|
||||
SEQUENCE *pSeq;
|
||||
ANIMATION_DESC *ADPtr;
|
||||
DWORD ActiveMask;
|
||||
// Bit mask of all animations that are currently active.
|
||||
// Bit 'i' is set if the animation with index 'i' is active.
|
||||
DWORD LastOscillTime;
|
||||
Task task = (Task) data;
|
||||
BOOLEAN TransitionDone = FALSE;
|
||||
BOOLEAN TalkFrameChanged = FALSE;
|
||||
BOOLEAN FrameChanged[MAX_ANIMATIONS];
|
||||
BOOLEAN ColorChange = FALSE;
|
||||
|
||||
while ((CommFrame = CommData.AlienFrame) == 0
|
||||
&& !Task_ReadState (task, TASK_EXIT))
|
||||
ANIMATION_DESC TalkDesc;
|
||||
ANIMATION_DESC TransitDesc;
|
||||
SEQUENCE* Talk;
|
||||
SEQUENCE* Transit;
|
||||
COUNT FirstAmbient;
|
||||
COUNT TotalSequences;
|
||||
|
||||
while (!CommData.AlienFrame && !Task_ReadState (task, TASK_EXIT))
|
||||
TaskSwitch ();
|
||||
|
||||
ActiveMask = 0;
|
||||
|
||||
// Certain data must be accessed under GraphicsLock
|
||||
LockMutex (GraphicsLock);
|
||||
|
||||
memset (&DisplayArray[0], 0, sizeof (DisplayArray));
|
||||
SetUpSequence (Sequencer);
|
||||
TalkDesc = CommData.AlienTalkDesc;
|
||||
TransitDesc = CommData.AlienTransitionDesc;
|
||||
|
||||
// Animation sequences have to be drawn in reverse, and
|
||||
// talk animations have to be drawn last (so we add them first)
|
||||
TotalSequences = 0;
|
||||
// Transition animation last
|
||||
Transit = Sequences + TotalSequences;
|
||||
SetupTalkSequence (Transit, &TransitDesc);
|
||||
++TotalSequences;
|
||||
// Talk animation second last
|
||||
Talk = Sequences + TotalSequences;
|
||||
SetupTalkSequence (Talk, &TalkDesc);
|
||||
++TotalSequences;
|
||||
FirstAmbient = TotalSequences;
|
||||
SetupAmbientSequences (Sequences + FirstAmbient, CommData.NumAnimations);
|
||||
TotalSequences += CommData.NumAnimations;
|
||||
|
||||
UnlockMutex (GraphicsLock);
|
||||
|
||||
ActiveMask = 0;
|
||||
TalkAlarm = 0;
|
||||
TalkFrame = 0;
|
||||
LastTime = GetTimeCounter ();
|
||||
LastOscillTime = LastTime;
|
||||
memset (FrameChanged, 0, sizeof (FrameChanged));
|
||||
memset (AnimFrame, 0, sizeof (AnimFrame));
|
||||
for (i = 0; i < CommData.NumAnimations; i++)
|
||||
{
|
||||
COUNT nextIndex;
|
||||
|
||||
if (CommData.AlienAmbientArray[i].AnimFlags & YOYO_ANIM)
|
||||
nextIndex = CommData.AlienAmbientArray[i].StartIndex;
|
||||
else
|
||||
nextIndex = (CommData.AlienAmbientArray[i].StartIndex
|
||||
+ CommData.AlienAmbientArray[i].NumFrames - 1);
|
||||
AnimFrame[i] = SetAbsFrameIndex (CommFrame, nextIndex);
|
||||
}
|
||||
|
||||
while (!Task_ReadState (task, TASK_EXIT))
|
||||
{
|
||||
BOOLEAN Change, CanTalk;
|
||||
DWORD CurTime, ElapsedTicks;
|
||||
BOOLEAN CanTalk;
|
||||
TimeCount CurTime;
|
||||
DWORD ElapsedTicks;
|
||||
|
||||
SleepThreadUntil (LastTime + ONE_SECOND / AMBIENT_ANIM_RATE);
|
||||
|
||||
@@ -165,368 +418,153 @@ ambient_anim_task (void *data)
|
||||
ElapsedTicks = CurTime - LastTime;
|
||||
LastTime = CurTime;
|
||||
|
||||
Change = FALSE;
|
||||
if (PauseAnimTask)
|
||||
{ // anims not processed
|
||||
i = CommData.NumAnimations;
|
||||
if (CommData.AlienFrame)
|
||||
CanTalk = TRUE;
|
||||
CanTalk = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
CanTalk = FALSE;
|
||||
CanTalk = TRUE;
|
||||
}
|
||||
|
||||
pSeq = &Sequencer[i];
|
||||
ADPtr = &CommData.AlienAmbientArray[i];
|
||||
while (i-- && !Task_ReadState (task, TASK_EXIT))
|
||||
// Process ambient animations
|
||||
pSeq = Sequences + FirstAmbient;
|
||||
for ( ; i < CommData.NumAnimations; ++i, ++pSeq)
|
||||
{
|
||||
--ADPtr;
|
||||
--pSeq;
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
DWORD ActiveBit = 1L << i;
|
||||
|
||||
if (ADPtr->AnimFlags & ANIM_DISABLED)
|
||||
continue;
|
||||
|
||||
if (pSeq->Direction == NO_DIR)
|
||||
{
|
||||
if (!(ADPtr->AnimFlags
|
||||
& CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING))
|
||||
{
|
||||
// This animation does not conflict with the talking
|
||||
// animation right now.
|
||||
{ // animation is paused
|
||||
if (!conflictsWithTalkingAnim (pSeq))
|
||||
{ // start it up
|
||||
pSeq->Direction = UP_DIR;
|
||||
}
|
||||
}
|
||||
else if ((DWORD)pSeq->Alarm > ElapsedTicks)
|
||||
pSeq->Alarm -= (COUNT)ElapsedTicks;
|
||||
else
|
||||
{
|
||||
if (!(ActiveMask & ADPtr->BlockMask)
|
||||
&& (--pSeq->FramesLeft
|
||||
|| ((ADPtr->AnimFlags & YOYO_ANIM)
|
||||
&& pSeq->Direction == UP_DIR)))
|
||||
{
|
||||
ActiveMask |= 1L << i;
|
||||
pSeq->Alarm = ADPtr->BaseFrameRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomFrameRate + 1)) + 1;
|
||||
else if (pSeq->Alarm > ElapsedTicks)
|
||||
{ // not time yet
|
||||
pSeq->Alarm -= ElapsedTicks;
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveMask &= ~(1L << i);
|
||||
pSeq->Alarm = ADPtr->BaseRestartRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomRestartRate + 1)) + 1;
|
||||
if (ActiveMask & ADPtr->BlockMask)
|
||||
else if (ActiveMask & ADPtr->BlockMask)
|
||||
{ // animation is blocked
|
||||
assert (!(ActiveMask & ActiveBit));
|
||||
assert (animAtNeutralIndex (pSeq));
|
||||
// reschedule
|
||||
pSeq->Alarm = randomRestartRate (pSeq) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
{
|
||||
XFormColorMap (GetColorMapAddress (pSeq->AnimObj.CurCMap),
|
||||
(COUNT) (pSeq->Alarm - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
Change = TRUE;
|
||||
AnimFrame[i] = pSeq->AnimObj.CurFrame;
|
||||
FrameChanged[i] = 1;
|
||||
{ // Time to start or advance the animation
|
||||
if (AdvanceAmbientSequence (pSeq))
|
||||
ActiveMask |= ActiveBit;
|
||||
else
|
||||
ActiveMask &= ~ActiveBit;
|
||||
}
|
||||
|
||||
if (pSeq->FramesLeft == 0)
|
||||
if (pSeq->AnimType == PICTURE_ANIM && pSeq->Direction != NO_DIR
|
||||
&& conflictsWithTalkingAnim (pSeq))
|
||||
{
|
||||
pSeq->FramesLeft = (BYTE)(ADPtr->NumFrames - 1);
|
||||
|
||||
if (pSeq->Direction == DOWN_DIR)
|
||||
pSeq->Direction = UP_DIR;
|
||||
else if (ADPtr->AnimFlags & YOYO_ANIM)
|
||||
pSeq->Direction = DOWN_DIR;
|
||||
else
|
||||
{
|
||||
++pSeq->FramesLeft;
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
pSeq->AnimObj.CurCMap = SetRelColorMapIndex (
|
||||
pSeq->AnimObj.CurCMap,
|
||||
(SWORD) (-pSeq->FramesLeft));
|
||||
else
|
||||
{
|
||||
pSeq->AnimObj.CurFrame = SetRelFrameIndex (
|
||||
pSeq->AnimObj.CurFrame,
|
||||
(SWORD) (-pSeq->FramesLeft));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ADPtr->AnimFlags & RANDOM_ANIM)
|
||||
{
|
||||
COUNT nextIndex = ADPtr->StartIndex +
|
||||
(TFB_Random () % ADPtr->NumFrames);
|
||||
|
||||
if (pSeq->AnimType == COLOR_ANIM)
|
||||
pSeq->AnimObj.CurCMap = SetAbsColorMapIndex (
|
||||
pSeq->AnimObj.CurCMap, nextIndex);
|
||||
else
|
||||
pSeq->AnimObj.CurFrame = SetAbsFrameIndex (
|
||||
pSeq->AnimObj.CurFrame, nextIndex);
|
||||
}
|
||||
else if (pSeq->AnimType == COLOR_ANIM)
|
||||
{
|
||||
if (pSeq->Direction == UP_DIR)
|
||||
pSeq->AnimObj.CurCMap = SetRelColorMapIndex (
|
||||
pSeq->AnimObj.CurCMap, 1);
|
||||
else
|
||||
pSeq->AnimObj.CurCMap = SetRelColorMapIndex (
|
||||
pSeq->AnimObj.CurCMap, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pSeq->Direction == UP_DIR)
|
||||
pSeq->AnimObj.CurFrame =
|
||||
IncFrameIndex (pSeq->AnimObj.CurFrame);
|
||||
else
|
||||
pSeq->AnimObj.CurFrame =
|
||||
DecFrameIndex (pSeq->AnimObj.CurFrame);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSeq->AnimType == PICTURE_ANIM
|
||||
&& (ADPtr->AnimFlags
|
||||
& CommData.AlienTalkDesc.AnimFlags & WAIT_TALKING)
|
||||
&& pSeq->Direction != NO_DIR)
|
||||
{
|
||||
// This is a picture animation which would conflict with
|
||||
// the talking animation, and it is not stopped yet.
|
||||
COUNT index;
|
||||
|
||||
CanTalk = FALSE;
|
||||
if (!(pSeq->Direction != UP_DIR
|
||||
|| (index = GetFrameIndex (pSeq->AnimObj.CurFrame)) >
|
||||
ADPtr->StartIndex + 1
|
||||
|| (index == ADPtr->StartIndex + 1
|
||||
&& (ADPtr->AnimFlags & CIRCULAR_ANIM))))
|
||||
// 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;
|
||||
ActiveMask &= ~ActiveBit;
|
||||
}
|
||||
else
|
||||
{ // Otherwise, let the animation run until it's safe
|
||||
CanTalk = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ADPtr = &CommData.AlienTalkDesc;
|
||||
if (CanTalk
|
||||
&& ADPtr->NumFrames
|
||||
&& (ADPtr->AnimFlags & WAIT_TALKING)
|
||||
&& !(CommData.AlienTransitionDesc.AnimFlags & PAUSE_TALKING))
|
||||
// Process the talking and transition animations
|
||||
if (CanTalk && haveTalkingAnim () && runningTalkingAnim ())
|
||||
{
|
||||
BOOLEAN done = FALSE;
|
||||
for (i = 0; i < CommData.NumAnimations; i++)
|
||||
if (ActiveMask & (1L << i)
|
||||
&& CommData.AlienAmbientArray[i].AnimFlags & WAIT_TALKING)
|
||||
|
||||
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 (!done)
|
||||
{
|
||||
|
||||
if (ADPtr->StartIndex != TalkBuffer.StartIndex)
|
||||
{
|
||||
Change = TRUE;
|
||||
ResetTalkFrame = SetAbsFrameIndex (CommFrame,
|
||||
TalkBuffer.StartIndex);
|
||||
TalkBuffer = CommData.AlienTalkDesc;
|
||||
}
|
||||
|
||||
if ((long)TalkAlarm > (long)ElapsedTicks)
|
||||
TalkAlarm -= (SIZE)ElapsedTicks;
|
||||
else
|
||||
if (signaledStopTalkingAnim () && done)
|
||||
{
|
||||
BYTE AFlags;
|
||||
SIZE FrameRate;
|
||||
|
||||
if (TalkAlarm > 0)
|
||||
TalkAlarm = 0;
|
||||
else
|
||||
TalkAlarm = -1;
|
||||
|
||||
AFlags = ADPtr->AnimFlags;
|
||||
if (!(AFlags & (TALK_INTRO | TALK_DONE)))
|
||||
{
|
||||
FrameRate =
|
||||
ADPtr->BaseFrameRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomFrameRate + 1));
|
||||
if (TalkAlarm < 0
|
||||
|| GetFrameIndex (TalkFrame) ==
|
||||
ADPtr->StartIndex)
|
||||
{
|
||||
TalkFrame = SetAbsFrameIndex (CommFrame,
|
||||
(COUNT) (ADPtr->StartIndex + 1
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->NumFrames - 1))));
|
||||
FrameRate += ADPtr->BaseRestartRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomRestartRate + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
TalkFrame = SetAbsFrameIndex (CommFrame,
|
||||
ADPtr->StartIndex);
|
||||
if (ADPtr->AnimFlags & PAUSE_TALKING)
|
||||
{
|
||||
if (!(CommData.AlienTransitionDesc.AnimFlags
|
||||
& TALK_DONE))
|
||||
{
|
||||
CommData.AlienTransitionDesc.AnimFlags |=
|
||||
PAUSE_TALKING;
|
||||
ADPtr->AnimFlags &= ~PAUSE_TALKING;
|
||||
}
|
||||
else if (CommData.AlienTransitionDesc.NumFrames)
|
||||
ADPtr->AnimFlags |= TALK_DONE;
|
||||
else
|
||||
ADPtr->AnimFlags &=
|
||||
~(WAIT_TALKING | PAUSE_TALKING);
|
||||
|
||||
FrameRate = 0;
|
||||
}
|
||||
clearRunTalkingAnim ();
|
||||
clearStopTalkingAnim ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ADPtr = &CommData.AlienTransitionDesc;
|
||||
if (AFlags & TALK_INTRO)
|
||||
{
|
||||
FrameRate = ADPtr->BaseFrameRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomFrameRate + 1));
|
||||
if (TalkAlarm < 0 || TransitionDone)
|
||||
{
|
||||
TalkFrame = SetAbsFrameIndex (CommFrame,
|
||||
ADPtr->StartIndex);
|
||||
TransitionDone = FALSE;
|
||||
}
|
||||
else
|
||||
TalkFrame = IncFrameIndex (TalkFrame);
|
||||
|
||||
if ((BYTE)(GetFrameIndex (TalkFrame)
|
||||
- ADPtr->StartIndex + 1) ==
|
||||
ADPtr->NumFrames)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags &=
|
||||
~TALK_INTRO;
|
||||
TransitionDone = TRUE;
|
||||
}
|
||||
TransitionFrame = TalkFrame;
|
||||
}
|
||||
else /* if (AFlags & TALK_DONE) */
|
||||
{
|
||||
FrameRate = ADPtr->BaseFrameRate
|
||||
+ ((COUNT)TFB_Random ()
|
||||
% (ADPtr->RandomFrameRate + 1));
|
||||
if (TalkAlarm < 0)
|
||||
TalkFrame = SetAbsFrameIndex (CommFrame,
|
||||
(COUNT) (ADPtr->StartIndex
|
||||
+ ADPtr->NumFrames - 1));
|
||||
else
|
||||
TalkFrame = DecFrameIndex (TalkFrame);
|
||||
|
||||
if (GetFrameIndex (TalkFrame) ==
|
||||
ADPtr->StartIndex)
|
||||
{
|
||||
CommData.AlienTalkDesc.AnimFlags &=
|
||||
~(PAUSE_TALKING | TALK_DONE);
|
||||
if (ADPtr->AnimFlags & TALK_INTRO)
|
||||
CommData.AlienTalkDesc.AnimFlags &=
|
||||
~WAIT_TALKING;
|
||||
else
|
||||
{
|
||||
ADPtr->AnimFlags |= PAUSE_TALKING;
|
||||
ADPtr->AnimFlags &= ~TALK_DONE;
|
||||
}
|
||||
FrameRate = 0;
|
||||
}
|
||||
TransitionFrame = NULL;
|
||||
}
|
||||
}
|
||||
TalkFrameChanged = TRUE;
|
||||
|
||||
Change = TRUE;
|
||||
|
||||
TalkAlarm = FrameRate;
|
||||
}
|
||||
}
|
||||
else if (done && (ADPtr->AnimFlags & PAUSE_TALKING))
|
||||
{
|
||||
ADPtr->AnimFlags &= ~(WAIT_TALKING | PAUSE_TALKING);
|
||||
}
|
||||
{ // Not talking (task may be paused)
|
||||
// Disable talking anim if it is done
|
||||
if (Talk->Direction == NO_DIR)
|
||||
TalkDesc.AnimFlags |= ANIM_DISABLED;
|
||||
}
|
||||
|
||||
// Draw all animations
|
||||
if (!PauseAnimTask)
|
||||
{
|
||||
CONTEXT OldContext;
|
||||
BOOLEAN CheckSub = FALSE;
|
||||
BOOLEAN SubtitleChange;
|
||||
BOOLEAN FullRedraw;
|
||||
BOOLEAN Change;
|
||||
|
||||
// Clearing any active subtitles counts as 'change'
|
||||
SubtitleChange = HaveSubtitlesChanged ();
|
||||
FullRedraw = ColorChange || SubtitleChange;
|
||||
|
||||
OldContext = SetContext (TaskContext);
|
||||
|
||||
if (ColorChange || ClearSummary)
|
||||
{ // Redraw the whole comm screen
|
||||
FRAME F;
|
||||
F = CommData.AlienFrame;
|
||||
CommData.AlienFrame = CommFrame;
|
||||
DrawAlienFrame (TalkFrame,
|
||||
&Sequencer[CommData.NumAnimations - 1]);
|
||||
CommData.AlienFrame = F;
|
||||
CheckSub = TRUE;
|
||||
SubtitleChange = ClearSummary;
|
||||
ColorChange = FALSE;
|
||||
ClearSummary = FALSE;
|
||||
}
|
||||
if (Change || SubtitleChange)
|
||||
{
|
||||
STAMP s;
|
||||
s.origin.x = -SAFE_X;
|
||||
s.origin.y = 0;
|
||||
if (SubtitleChange)
|
||||
{
|
||||
s.frame = CommFrame;
|
||||
DrawStamp (&s);
|
||||
}
|
||||
i = CommData.NumAnimations;
|
||||
while (i--)
|
||||
{
|
||||
if (SubtitleChange || FrameChanged[i])
|
||||
{
|
||||
s.frame = AnimFrame[i];
|
||||
DrawStamp (&s);
|
||||
FrameChanged[i] = 0;
|
||||
}
|
||||
}
|
||||
if (SubtitleChange && TransitionFrame)
|
||||
{
|
||||
s.frame = TransitionFrame;
|
||||
DrawStamp (&s);
|
||||
}
|
||||
if (ResetTalkFrame)
|
||||
{
|
||||
s.frame = ResetTalkFrame;
|
||||
DrawStamp (&s);
|
||||
ResetTalkFrame = NULL;
|
||||
}
|
||||
if (TalkFrame && TalkFrameChanged)
|
||||
{
|
||||
s.frame = TalkFrame;
|
||||
DrawStamp (&s);
|
||||
TalkFrameChanged = FALSE;
|
||||
}
|
||||
Change = FALSE;
|
||||
CheckSub = TRUE;
|
||||
}
|
||||
// Colormap animations are processed separately
|
||||
// from picture anims (see XFormColorMap_step)
|
||||
ProcessColormapAnims (Sequences + FirstAmbient,
|
||||
CommData.NumAnimations);
|
||||
|
||||
if (CheckSub)
|
||||
Change = DrawAlienFrame (Sequences, TotalSequences, FullRedraw);
|
||||
if (FullRedraw || Change)
|
||||
RedrawSubtitles ();
|
||||
|
||||
SetContext (OldContext);
|
||||
|
||||
ColorChange = FALSE;
|
||||
}
|
||||
|
||||
if (LastOscillTime + (ONE_SECOND / OSCILLOSCOPE_RATE) < CurTime)
|
||||
{
|
||||
LastOscillTime = CurTime;
|
||||
UpdateSpeechGraphics (FALSE);
|
||||
}
|
||||
|
||||
UnbatchGraphics ();
|
||||
UnlockMutex (GraphicsLock);
|
||||
|
||||
ColorChange = XFormColorMap_step ();
|
||||
}
|
||||
FinishTask (task);
|
||||
@@ -539,4 +577,68 @@ StartCommAnimTask (void)
|
||||
return AssignTask (ambient_anim_task, 3072, "ambient animations");
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
DrawAlienFrame (SEQUENCE *Sequences, COUNT Num, BOOLEAN fullRedraw)
|
||||
{
|
||||
int i;
|
||||
STAMP s;
|
||||
BOOLEAN Change = FALSE;
|
||||
|
||||
BatchGraphics ();
|
||||
|
||||
s.origin.x = -SAFE_X;
|
||||
s.origin.y = 0;
|
||||
|
||||
if (fullRedraw)
|
||||
{
|
||||
// Draw the main frame
|
||||
s.frame = CommData.AlienFrame;
|
||||
DrawStamp (&s);
|
||||
|
||||
// Draw any static frames (has to be in reverse)
|
||||
for (i = CommData.NumAnimations - 1; i >= 0; --i)
|
||||
{
|
||||
ANIMATION_DESC *ADPtr = &CommData.AlienAmbientArray[i];
|
||||
|
||||
if (ADPtr->AnimFlags & ANIM_MASK)
|
||||
continue;
|
||||
|
||||
ADPtr->AnimFlags |= ANIM_DISABLED;
|
||||
|
||||
if (!(ADPtr->AnimFlags & COLORXFORM_ANIM))
|
||||
{ // It's a static frame (e.g. Flagship picture at Starbase)
|
||||
s.frame = SetAbsFrameIndex (CommData.AlienFrame,
|
||||
ADPtr->StartIndex);
|
||||
DrawStamp (&s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Sequences)
|
||||
{ // Draw the animation sequences (has to be in reverse)
|
||||
for (i = Num - 1; i >= 0; --i)
|
||||
{
|
||||
SEQUENCE *pSeq = &Sequences[i];
|
||||
ANIMATION_DESC *ADPtr = pSeq->ADPtr;
|
||||
|
||||
if ((ADPtr->AnimFlags & ANIM_DISABLED)
|
||||
|| pSeq->AnimType != PICTURE_ANIM)
|
||||
continue;
|
||||
|
||||
// Draw current animation frame only if changed
|
||||
if (!fullRedraw && !pSeq->Change)
|
||||
continue;
|
||||
|
||||
s.frame = SetAbsFrameIndex (CommData.AlienFrame,
|
||||
ADPtr->StartIndex + pSeq->CurIndex);
|
||||
DrawStamp (&s);
|
||||
pSeq->Change = FALSE;
|
||||
|
||||
Change = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
UnbatchGraphics ();
|
||||
|
||||
return Change;
|
||||
}
|
||||
|
||||
+81
-12
@@ -21,14 +21,81 @@
|
||||
#include "libs/gfxlib.h"
|
||||
#include "libs/tasklib.h"
|
||||
|
||||
// Some background: every animation has a neutral frame which returns
|
||||
// the image to the state it was in before the animation began. Which
|
||||
// frame is neutral depends on the animation type.
|
||||
// Animation types:
|
||||
#define RANDOM_ANIM (1 << 0)
|
||||
// The next index is randomly chosen.
|
||||
// The first frame is neutral
|
||||
#define CIRCULAR_ANIM (1 << 1)
|
||||
// After the last index has been reached, the animation starts over.
|
||||
// The last frame is neutral. This complicates the animation task.
|
||||
#define YOYO_ANIM (1 << 2)
|
||||
// After the last index has been reached, the order that the
|
||||
// animation frames are used is reversed.
|
||||
// The first frame is neutral
|
||||
#define ANIM_MASK (RANDOM_ANIM | CIRCULAR_ANIM | YOYO_ANIM)
|
||||
// Mask of all animation types.
|
||||
// Static frames do not have any of these flags set.
|
||||
|
||||
#define WAIT_TALKING (1 << 3)
|
||||
// This is set in AlienTalkDesc when the talking animation is active
|
||||
// or should be active.
|
||||
// In AlienAmbientArray, this is set for those ambient animations
|
||||
// which can not be active while the talking animation is active.
|
||||
// Such animations stop at the end of the current animation cycle
|
||||
// when the talking animation activates.
|
||||
#define PAUSE_TALKING (1 << 4)
|
||||
// Set in AlienTalkDesc when we do not want the talking animation
|
||||
#define TALK_INTRO (1 << 5)
|
||||
// In AlienTransitionDesc: indicates a transition to talking state
|
||||
#define TALK_DONE (1 << 6)
|
||||
// In AlienTransitionDesc: indicates a transition to silent state
|
||||
// In AlienTalkDesc: signals the end of talking animation
|
||||
#define ANIM_DISABLED (1 << 7)
|
||||
|
||||
#define COLORXFORM_ANIM PAUSE_TALKING
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COUNT StartIndex;
|
||||
// Index of the first image (for image animation) or
|
||||
// index of the first color map (for palette animation)
|
||||
BYTE NumFrames;
|
||||
// Number of frames in the animation.
|
||||
|
||||
BYTE AnimFlags;
|
||||
// One of RANDOM_ANIM, CIRCULAR_ANIM, or YOYO_ANIM
|
||||
// plus flags (WAIT_TALKING, ANIM_DISABLED)
|
||||
|
||||
COUNT BaseFrameRate;
|
||||
// Minimum interframe delay
|
||||
COUNT RandomFrameRate;
|
||||
// Maximum additional interframe delay
|
||||
// Actual delay: BaseFrameRate + Random(0..RandomFrameRate)
|
||||
COUNT BaseRestartRate;
|
||||
// Minimum delay before restarting animation
|
||||
COUNT RandomRestartRate;
|
||||
// Maximum additional delay before restarting animation
|
||||
// Actual delay: BaseRestartRate + Random(0..RandomRestartRate)
|
||||
|
||||
DWORD BlockMask;
|
||||
// Bit mask of the indices of all animations that can not
|
||||
// be active at the same time as this animation, usually,
|
||||
// due to the image overlap conflicts.
|
||||
} ANIMATION_DESC;
|
||||
|
||||
#define MAX_ANIMATIONS 20
|
||||
|
||||
|
||||
#ifdef COMM_INTERNAL
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UP_DIR,
|
||||
// Animation indices are increasing
|
||||
DOWN_DIR,
|
||||
// Animation indices are decreasing
|
||||
NO_DIR
|
||||
DOWN_DIR = -1, // Animation indices are decreasing
|
||||
NO_DIR = 0,
|
||||
UP_DIR = 1, // Animation indices are increasing
|
||||
} ANIM_DIR;
|
||||
|
||||
typedef enum
|
||||
@@ -42,20 +109,22 @@ typedef enum
|
||||
// Describes an active animation.
|
||||
struct SEQUENCE
|
||||
{
|
||||
COUNT Alarm;
|
||||
ANIMATION_DESC *ADPtr;
|
||||
DWORD Alarm;
|
||||
ANIM_DIR Direction;
|
||||
BYTE FramesLeft;
|
||||
COUNT CurIndex;
|
||||
COUNT NextIndex;
|
||||
COUNT FramesLeft;
|
||||
ANIM_TYPE AnimType;
|
||||
union
|
||||
{
|
||||
FRAME CurFrame;
|
||||
COLORMAP CurCMap;
|
||||
} AnimObj;
|
||||
BOOLEAN Change;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct SEQUENCE SEQUENCE;
|
||||
|
||||
// Returns TRUE if there was an animation change
|
||||
extern BOOLEAN DrawAlienFrame (SEQUENCE *pSeq, COUNT Num, BOOLEAN fullRedraw);
|
||||
|
||||
void UpdateSpeechGraphics (BOOLEAN Initialize);
|
||||
Task StartCommAnimTask(void);
|
||||
|
||||
|
||||
+6
-48
@@ -24,56 +24,9 @@
|
||||
#include "libs/reslib.h"
|
||||
#include "sis.h"
|
||||
#include "velocity.h"
|
||||
#include "commanim.h"
|
||||
|
||||
|
||||
// XXX: the following should be moved to commanim.h
|
||||
// Animation types:
|
||||
#define RANDOM_ANIM (1 << 0)
|
||||
// The next index is randomly chosen.
|
||||
#define CIRCULAR_ANIM (1 << 1)
|
||||
// After the last index has been reached, the animation starts over.
|
||||
#define YOYO_ANIM (1 << 2)
|
||||
// After the last index has been reached, the order that the
|
||||
// animation frames are used is reversed.
|
||||
#define ANIM_MASK (RANDOM_ANIM | CIRCULAR_ANIM | YOYO_ANIM)
|
||||
// Mask of all animation types.
|
||||
|
||||
#define WAIT_TALKING (1 << 3)
|
||||
// This is set in AlienTalkDesc when the ambient animations should
|
||||
// stop at the end of the current animation cycle.
|
||||
// In AlienAmbientArray, this is set for those ambient animations
|
||||
// which can not be active while the talking animation is active.
|
||||
#define PAUSE_TALKING (1 << 4)
|
||||
#define TALK_INTRO (1 << 5)
|
||||
#define TALK_DONE (1 << 6)
|
||||
|
||||
#define ANIM_DISABLED (1 << 7)
|
||||
|
||||
#define COLORXFORM_ANIM PAUSE_TALKING
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COUNT StartIndex;
|
||||
// Index of the first image (for image animation) or
|
||||
// index of the first color map (for palette animation)
|
||||
BYTE NumFrames;
|
||||
// Number of frames in the animation.
|
||||
|
||||
BYTE AnimFlags;
|
||||
// One of RANDOM_ANIM, CIRCULAR_ANIM, or YOYO_ANIM
|
||||
|
||||
COUNT BaseFrameRate;
|
||||
COUNT RandomFrameRate;
|
||||
COUNT BaseRestartRate;
|
||||
COUNT RandomRestartRate;
|
||||
|
||||
DWORD BlockMask;
|
||||
// Bit mask of the indices of all animations that can not
|
||||
// be active at the same time as this animation.
|
||||
} ANIMATION_DESC;
|
||||
|
||||
#define MAX_ANIMATIONS 20
|
||||
|
||||
// general numbers-speech generator info
|
||||
// should accomodate most common base-10 languages
|
||||
// many languages require various plural forms
|
||||
@@ -160,7 +113,12 @@ typedef struct
|
||||
COUNT NumAnimations;
|
||||
ANIMATION_DESC AlienAmbientArray[MAX_ANIMATIONS];
|
||||
|
||||
// Transition animation to/from talking state;
|
||||
// the first frame is neutral (sort of like YOYO_ANIM)
|
||||
ANIMATION_DESC AlienTransitionDesc;
|
||||
// Talking animation, like RANDOM_ANIM, except random frames
|
||||
// always alternate with a neutral frame;
|
||||
// the first frame is neutral
|
||||
ANIMATION_DESC AlienTalkDesc;
|
||||
|
||||
NUMBER_SPEECH AlienNumberSpeech;
|
||||
|
||||
Reference in New Issue
Block a user