static int flash_ship_task (void *data) { DWORD TimeIn; COLOR c; Task task = (Task) data; c = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x00, 0x00), 0x24); TimeIn = GetTimeCounter (); while (!Task_ReadState (task, TASK_EXIT)) { STAMP s; SHIP_FRAGMENTPTR StarShipPtr; COLOR OldColor; CONTEXT OldContext; LockMutex (GraphicsLock); s.origin = pMenuState->first_item; StarShipPtr = (SHIP_FRAGMENTPTR)LockStarShip ( &GLOBAL (built_ship_q), (HSTARSHIP)pMenuState->CurFrame); s.frame = StarShipPtr->ShipInfo.icons; UnlockStarShip (&GLOBAL (built_ship_q), (HSTARSHIP)pMenuState->CurFrame); OldContext = SetContext (StatusContext); if (c >= BUILD_COLOR (MAKE_RGB15 (0x1F, 0x19, 0x19), 0x24)) c = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x00, 0x00), 0x24); else c += BUILD_COLOR (MAKE_RGB15 (0x00, 0x02, 0x02), 0x00); OldColor = SetContextForeGroundColor (c); DrawFilledStamp (&s); SetContextForeGroundColor (OldColor); SetContext (OldContext); UnlockMutex (GraphicsLock); SleepThreadUntil (TimeIn + ONE_SECOND / 15); TimeIn = GetTimeCounter (); } FinishTask (task); return 0; }
// Pre: caller holds the graphics lock. void MeleeGameOver (void) { COUNT playerI; DWORD TimeOut; BOOLEAN PressState, ButtonState; // Show the battle result. for (playerI = 0; playerI < NUM_PLAYERS; playerI++) DrawPickMeleeFrame (playerI); #ifdef NETPLAY negotiateReadyConnections(true, NetState_inSetup); #endif TimeOut = GetTimeCounter () + (ONE_SECOND * 4); PressState = PulsedInputState.menu[KEY_MENU_SELECT] || PulsedInputState.menu[KEY_MENU_CANCEL]; do { UpdateInputState (); ButtonState = PulsedInputState.menu[KEY_MENU_SELECT] || PulsedInputState.menu[KEY_MENU_CANCEL]; if (PressState) { PressState = ButtonState; ButtonState = FALSE; } Async_process (); TaskSwitch (); } while (!(GLOBAL (CurrentActivity) & CHECK_ABORT) && (!ButtonState && (!(PlayerControl[0] & PlayerControl[1] & PSYTRON_CONTROL) || GetTimeCounter () < TimeOut))); }
static void BackgroundInitKernel (DWORD TimeOut) { LoadMasterShipList (TaskSwitch); TaskSwitch (); InitGameKernel (); while ((GetTimeCounter () <= TimeOut) && !(GLOBAL (CurrentActivity) & CHECK_ABORT)) { UpdateInputState (); TaskSwitch (); } }
// This function figures out the chunk that should be playing based on // 'offset' into the total playing time of all tracks. It then sets // the speech source's sample to the necessary decoder and seeks the // decoder to the proper point. // XXX: This means that whatever speech has already been queued on the // source will continue playing, so we may need some small timing // adjustments. It may be simpler to just call PlayStream(). static void seek_track (sint32 offset) { TFB_SoundChunk *cur; TFB_SoundChunk *last_tag = NULL; if (!sound_sample) return; // nothing to recompute if (offset < 0) offset = 0; else if ((uint32)offset > tracks_length) offset = tracks_length + 1; // Adjusting the stream start time is the only way we can arbitrarily // seek the stream right now soundSource[SPEECH_SOURCE].start_time = GetTimeCounter () - offset; // Find the chunk that should be playing at this time offset for (cur = chunks_head; cur && offset >= chunk_end_time (cur); cur = cur->next) { // .. looking for the last callback as we go along // XXX: this effectively set the last point where Fot is looking at. // TODO: this should be somehow changed if we implement more // callbacks, like Melnorme trading, offloading at Starbase, etc. if (cur->tag_me) last_tag = cur; } if (cur) { cur_chunk = cur; SoundDecoder_Seek (cur->decoder, (uint32) (((float)offset / ONE_SECOND - cur->start_time) * 1000)); sound_sample->decoder = cur->decoder; if (cur->tag_me) last_tag = cur; if (last_tag) DoTrackTag (last_tag); } else { // The offset is beyond the length of all tracks StopStream (SPEECH_SOURCE); cur_chunk = NULL; cur_sub_chunk = NULL; } }
void InitCommAnimations (void) { COUNT i; ActiveMask = 0; TalkDesc = CommData.AlienTalkDesc; TransitDesc = CommData.AlienTransitionDesc; // JMS: Shofixti Colony comm screen is blacked out upon the first encounter. if (CommData.AlienConv == SHOFIXTICOLONY_CONVERSATION) { if (GET_GAME_STATE (SHOFIXTI_COLONY_MET) < 2) TalkDesc.AnimFlags |= ANIM_DISABLED; for (i = 0; i < CommData.NumAnimations; ++i) { ANIMATION_DESC *ADPtr = &CommData.AlienAmbientArray[i]; // JMS: Turn on the anims & disable black screen when the time is right. if ((GET_GAME_STATE (SHOFIXTI_COLONY_MET) == 0 && i < CommData.NumAnimations - 1) || (GET_GAME_STATE (SHOFIXTI_COLONY_MET) >= 1 && i == CommData.NumAnimations - 1) ) ADPtr->AnimFlags |= ANIM_DISABLED; } } // 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; LastTime = GetTimeCounter (); }
static void flashSelectedTeam (MELEE_STATE *pMS) { #define FLASH_RATE (ONE_SECOND / 9) static TimeCount NextTime = 0; static int hilite = 0; TimeCount Now = GetTimeCounter (); if (Now >= NextTime) { CONTEXT OldContext; NextTime = Now + FLASH_RATE; hilite ^= 1; OldContext = SetContext (SpaceContext); SelectFileString (pMS, hilite); SetContext (OldContext); } }
void ResetKeyRepeat (void) { DWORD initTime = GetTimeCounter (); int i, j; for (i = 0; i < NUM_TEMPLATES; i++) { for (j = 0; j < NUM_KEYS; j++) { RepeatDelays.key[i][j] = _max_accel; Times.key[i][j] = initTime; } } for (i = 0; i < NUM_MENU_KEYS; i++) { RepeatDelays.menu[i] = _max_accel; Times.menu[i] = initTime; } GestaltRepeatDelay = _max_accel; GestaltTime = initTime; }
void PrintThreadsStats_SDL (void) { TrueThread ptr; int now; now = GetTimeCounter (); SDL_mutexP (threadQueueMutex); fprintf(stderr, "--- Active threads ---\n"); for (ptr = threadQueue; ptr != NULL; ptr = ptr->next) { fprintf (stderr, "Thread named '%s'.\n", ptr->name); fprintf (stderr, "Started %d.%d minutes ago.\n", (now - ptr->startTime) / 60000, ((now - ptr->startTime) / 1000) % 60); LocalStats (ptr->native); if (ptr->next != NULL) fprintf(stderr, "\n"); } SDL_mutexV (threadQueueMutex); fprintf(stderr, "----------------------\n"); fflush (stderr); }
static void computeFPS (void) { static TimeCount last_time; static TimePeriod fps_counter; TimeCount current_time; TimePeriod delta_time; current_time = GetTimeCounter (); delta_time = current_time - last_time; last_time = current_time; fps_counter += delta_time; if (fps_counter > FPS_PERIOD) { log_add (log_User, "fps %.2f, effective %.2f", (float)ONE_SECOND / delta_time, (float)ONE_SECOND * RenderedFrames / fps_counter); fps_counter = 0; RenderedFrames = 0; } }
static BOOLEAN DoRestart (MENU_STATE *pMS) { static TimeCount LastInputTime; static TimeCount InactTimeOut; TimeCount TimeIn = GetTimeCounter (); /* Cancel any presses of the Pause key. */ GamePaused = FALSE; if(optSuperMelee && !optLoadGame && PacksInstalled()){ pMS->CurState = PLAY_SUPER_MELEE; PulsedInputState.menu[KEY_MENU_SELECT] = 65535; } if(optLoadGame && !optSuperMelee && PacksInstalled()){ pMS->CurState = LOAD_SAVED_GAME; PulsedInputState.menu[KEY_MENU_SELECT] = 65535; } if (pMS->Initialized) Flash_process(pMS->flashContext); if (!pMS->Initialized) { if (pMS->hMusic && !comingFromInit) { StopMusic (); DestroyMusic (pMS->hMusic); pMS->hMusic = 0; } pMS->hMusic = loadMainMenuMusic (Rando); InactTimeOut = (optMainMenuMusic ? 60 : 20) * ONE_SECOND; pMS->flashContext = Flash_createOverlay (ScreenContext, NULL, NULL); Flash_setMergeFactors (pMS->flashContext, -3, 3, 16); Flash_setSpeed (pMS->flashContext, (6 * ONE_SECOND) / 14, 0, (6 * ONE_SECOND) / 14, 0); Flash_setFrameTime (pMS->flashContext, ONE_SECOND / 16); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); Flash_start (pMS->flashContext); LastInputTime = GetTimeCounter (); pMS->Initialized = TRUE; SleepThreadUntil (FadeScreen (FadeAllToColor, ONE_SECOND / 2)); if (!comingFromInit){ FadeMusic(0,0); PlayMusic (pMS->hMusic, TRUE, 1); if (optMainMenuMusic) FadeMusic (NORMAL_VOLUME+70, ONE_SECOND * 3); } } else if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return FALSE; } else if (PulsedInputState.menu[KEY_MENU_SELECT]) { //BYTE fade_buf[1]; COUNT oldresfactor; switch (pMS->CurState) { case LOAD_SAVED_GAME: if (!RestartMessage(pMS, TimeIn)) { LastActivity = CHECK_LOAD; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; optLoadGame = FALSE; } else return TRUE; break; case START_NEW_GAME: if (!RestartMessage(pMS, TimeIn)) { LastActivity = CHECK_LOAD | CHECK_RESTART; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; } else return TRUE; break; case PLAY_SUPER_MELEE: if (!RestartMessage(pMS, TimeIn)) { GLOBAL (CurrentActivity) = SUPER_MELEE; optSuperMelee = FALSE; } else return TRUE; break; case SETUP_GAME: oldresfactor = resolutionFactor; Flash_pause(pMS->flashContext); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); SetupMenu (); SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); InactTimeOut = (optMainMenuMusic ? 60 : 20) * ONE_SECOND; LastInputTime = GetTimeCounter (); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); ScreenTransition (3, NULL); // JMS_GFX: This prevents drawing an annoying wrong-sized "Setup" frame when changing resolution. if (oldresfactor < resolutionFactor) DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, TRUE); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); Flash_continue(pMS->flashContext); UnbatchGraphics (); return TRUE; case QUIT_GAME: SleepThreadUntil (FadeScreen (FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; break; } Flash_pause(pMS->flashContext); return FALSE; } else if (PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_DOWN]) { BYTE NewState; NewState = pMS->CurState; if (PulsedInputState.menu[KEY_MENU_UP]) { if (NewState == START_NEW_GAME) NewState = QUIT_GAME; else --NewState; } else if (PulsedInputState.menu[KEY_MENU_DOWN]) { if (NewState == QUIT_GAME) NewState = START_NEW_GAME; else ++NewState; } if (NewState != pMS->CurState) { BatchGraphics (); DrawRestartMenu (pMS, NewState, pMS->CurFrame, FALSE); UnbatchGraphics (); pMS->CurState = NewState; } LastInputTime = GetTimeCounter (); } else if (PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT]) { // Does nothing, but counts as input for timeout purposes LastInputTime = GetTimeCounter (); } else if (MouseButtonDown) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 54)); // Mouse not supported message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); LastInputTime = GetTimeCounter (); } else { // No input received, check if timed out // JMS: After changing resolution mode, prevent displaying credits // (until the next time the game is restarted). This is to prevent // showing the credits with the wrong resolution mode's font&background. if (GetTimeCounter () - LastInputTime > InactTimeOut && !optRequiresRestart && PacksInstalled()) { SleepThreadUntil (FadeMusic (0, ONE_SECOND/2)); StopMusic (); FadeMusic (NORMAL_VOLUME, 0); GLOBAL (CurrentActivity) = (ACTIVITY)~0; return FALSE; } } comingFromInit = FALSE; SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; }
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; } }
static DWORD XFormPLUT (COLORMAPPTR ColorMapPtr, SIZE TimeInterval) { TFB_ColorMap *map; XFORM_CONTROL *control; int index; int x; int first_avail = -1; DWORD EndTime; DWORD Now; Now = GetTimeCounter (); index = *(UBYTE*)ColorMapPtr; LockMutex (XFormControl.Lock); // Find an available slot, or reuse if required for (x = 0; x <= XFormControl.Highest && index != XFormControl.TaskControl[x].CMapIndex; ++x) { if (first_avail == -1 && XFormControl.TaskControl[x].CMapIndex == -1) first_avail = x; } if (index == XFormControl.TaskControl[x].CMapIndex) { // already xforming this colormap -- cancel and reuse slot finish_colormap_xform (x); } else if (first_avail >= 0) { // picked up a slot along the way x = first_avail; } else if (x >= MAX_XFORMS) { // flush some xforms if the queue is full log_add (log_Debug, "WARNING: XFormPLUT(): no slots available"); x = XFormControl.Highest; finish_colormap_xform (x); } // take next unused one control = &XFormControl.TaskControl[x]; if (x > XFormControl.Highest) XFormControl.Highest = x; // make a copy of the current map LockMutex (maplock); map = colormaps[index]; if (!map) { UnlockMutex (maplock); UnlockMutex (XFormControl.Lock); log_add (log_Warning, "BUG: XFormPLUT(): no current map"); return (0); } GetColorMapColors (control->OldCMap, map); UnlockMutex (maplock); control->CMapIndex = index; control->CMapPtr = ColorMapPtr; control->Ticks = TimeInterval; if (control->Ticks < 0) control->Ticks = 0; /* prevent negative fade */ control->StartTime = Now; control->EndTime = EndTime = Now + control->Ticks; UnlockMutex (XFormControl.Lock); return (EndTime); }
/* This gives the XFormColorMap task a timeslice to do its thing * Only one thread should ever be allowed to be calling this at any time */ BOOLEAN XFormColorMap_step (void) { BOOLEAN Changed = FALSE; int x; DWORD Now = GetTimeCounter (); LockMutex (XFormControl.Lock); for (x = 0; x <= XFormControl.Highest; ++x) { XFORM_CONTROL *control = &XFormControl.TaskControl[x]; int index = control->CMapIndex; int TicksLeft = control->EndTime - Now; TFB_ColorMap *curmap; if (index < 0) continue; // unused slot LockMutex (maplock); curmap = colormaps[index]; if (!curmap) { UnlockMutex (maplock); log_add (log_Error, "BUG: XFormColorMap_step(): no current map"); finish_colormap_xform (x); continue; } if (TicksLeft > 0) { #define XFORM_SCALE 0x10000 TFB_ColorMap *newmap = NULL; UBYTE *newClr; Color *oldClr; int frac; int i; newmap = clone_colormap (curmap, index); oldClr = control->OldCMap; newClr = (UBYTE*)control->CMapPtr + 2; frac = (int)(control->Ticks - TicksLeft) * XFORM_SCALE / control->Ticks; for (i = 0; i < NUMBER_OF_PLUTVALS; ++i, ++oldClr, newClr += PLUTVAL_BYTE_SIZE) { Color color; color.a = 0xff; color.r = blendChan (oldClr->r, newClr[PLUTVAL_RED], frac, XFORM_SCALE); color.g = blendChan (oldClr->g, newClr[PLUTVAL_GREEN], frac, XFORM_SCALE); color.b = blendChan (oldClr->b, newClr[PLUTVAL_BLUE], frac, XFORM_SCALE); SetNativePaletteColor (newmap->palette, i, color); } colormaps[index] = newmap; release_colormap (curmap); } UnlockMutex (maplock); if (TicksLeft <= 0) { // asked for immediate xform or already done finish_colormap_xform (x); } Changed = TRUE; } UnlockMutex (XFormControl.Lock); return Changed; }
static BOOLEAN DoRestart (MENU_STATE *pMS) { static TimeCount LastInputTime; static TimeCount InactTimeOut; TimeCount TimeIn = GetTimeCounter (); /* Cancel any presses of the Pause key. */ GamePaused = FALSE; if (pMS->Initialized) Flash_process(pMS->flashContext); if (!pMS->Initialized) { if (pMS->hMusic) { StopMusic (); DestroyMusic (pMS->hMusic); pMS->hMusic = 0; } pMS->hMusic = LoadMusic (MAINMENU_MUSIC); InactTimeOut = (pMS->hMusic ? 120 : 20) * ONE_SECOND; pMS->flashContext = Flash_createOverlay (ScreenContext, NULL, NULL); Flash_setMergeFactors (pMS->flashContext, -3, 3, 16); Flash_setSpeed (pMS->flashContext, (6 * ONE_SECOND) / 16, 0, (6 * ONE_SECOND) / 16, 0); Flash_setFrameTime (pMS->flashContext, ONE_SECOND / 16); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); Flash_start (pMS->flashContext); PlayMusic (pMS->hMusic, TRUE, 1); LastInputTime = GetTimeCounter (); pMS->Initialized = TRUE; SleepThreadUntil (FadeScreen (FadeAllToColor, ONE_SECOND / 2)); } else if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return FALSE; } else if (PulsedInputState.menu[KEY_MENU_SELECT]) { //BYTE fade_buf[1]; COUNT oldresfactor; BOOLEAN packsInstalled; if (resolutionFactor == 0) packsInstalled = TRUE; else if (resolutionFactor == 1 && hires2xPackPresent) packsInstalled = TRUE; else if (resolutionFactor == 2 && hires4xPackPresent) packsInstalled = TRUE; else packsInstalled = FALSE; switch (pMS->CurState) { case LOAD_SAVED_GAME: if (resFactorWasChanged) { LockMutex (GraphicsLock); SetFlashRect (NULL); UnlockMutex (GraphicsLock); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35)); // Got to restart -message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); //fade_buf[0] = FadeAllToBlack; //SleepThreadUntil (XFormColorMap ((COLORMAPPTR)fade_buf, ONE_SECOND / 2)); SleepThreadUntil (FadeScreen(FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; } else if (!packsInstalled) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35 + resolutionFactor)); // Could not find graphics pack - message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; } else { LastActivity = CHECK_LOAD; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; } break; case START_NEW_GAME: if (resFactorWasChanged) { LockMutex (GraphicsLock); SetFlashRect (NULL); UnlockMutex (GraphicsLock); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35)); // Got to restart -message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); //fade_buf[0] = FadeAllToBlack; //SleepThreadUntil (XFormColorMap ((COLORMAPPTR)fade_buf, ONE_SECOND / 2)); SleepThreadUntil (FadeScreen(FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; } else if (!packsInstalled) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35 + resolutionFactor)); // Could not find graphics pack - message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; } else { LastActivity = CHECK_LOAD | CHECK_RESTART; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; } break; case PLAY_SUPER_MELEE: if (resFactorWasChanged) { LockMutex (GraphicsLock); SetFlashRect (NULL); UnlockMutex (GraphicsLock); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35)); // Got to restart -message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); //fade_buf[0] = FadeAllToBlack; //SleepThreadUntil (XFormColorMap ((COLORMAPPTR)fade_buf, ONE_SECOND / 2)); SleepThreadUntil (FadeScreen(FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; } else if (!packsInstalled) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 35 + resolutionFactor)); // Could not find graphics pack - message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; } else { GLOBAL (CurrentActivity) = SUPER_MELEE; } break; case SETUP_GAME: oldresfactor = resolutionFactor; Flash_pause(pMS->flashContext); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); SetupMenu (); SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); LastInputTime = GetTimeCounter (); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); ScreenTransition (3, NULL); // JMS_GFX: This prevents drawing an annoying wrong-sized "Setup" frame when changing resolution. if (oldresfactor < resolutionFactor) DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, TRUE); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); Flash_continue(pMS->flashContext); UnbatchGraphics (); return TRUE; case QUIT_GAME: SleepThreadUntil (FadeScreen (FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; break; } Flash_pause(pMS->flashContext); return FALSE; } else if (PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_DOWN]) { BYTE NewState; NewState = pMS->CurState; if (PulsedInputState.menu[KEY_MENU_UP]) { if (NewState == START_NEW_GAME) NewState = QUIT_GAME; else --NewState; } else if (PulsedInputState.menu[KEY_MENU_DOWN]) { if (NewState == QUIT_GAME) NewState = START_NEW_GAME; else ++NewState; } if (NewState != pMS->CurState) { BatchGraphics (); DrawRestartMenu (pMS, NewState, pMS->CurFrame, FALSE); UnbatchGraphics (); pMS->CurState = NewState; } LastInputTime = GetTimeCounter (); } else if (PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT]) { // Does nothing, but counts as input for timeout purposes LastInputTime = GetTimeCounter (); } else if (MouseButtonDown) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 54)); // Mouse not supported message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame, FALSE); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); LastInputTime = GetTimeCounter (); } else { // No input received, check if timed out if (GetTimeCounter () - LastInputTime > InactTimeOut) { SleepThreadUntil (FadeMusic (0, ONE_SECOND)); StopMusic (); FadeMusic (NORMAL_VOLUME, 0); GLOBAL (CurrentActivity) = (ACTIVITY)~0; return FALSE; } } SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; }
static BOOLEAN DoRestart (PMENU_STATE pMS) { static DWORD InTime; static DWORD InactTimeOut; /* Cancel any presses of the Pause key. */ GamePaused = FALSE; if (!pMS->Initialized) { if (pMS->hMusic) { StopMusic (); DestroyMusic (pMS->hMusic); pMS->hMusic = 0; } pMS->hMusic = LoadMusic (MAINMENU_MUSIC); InactTimeOut = (pMS->hMusic ? 120 : 20) * ONE_SECOND; PlayMusic (pMS->hMusic, TRUE, 1); DrawRestartMenu ((BYTE)~0, pMS->CurState, pMS->CurFrame); pMS->Initialized = TRUE; { BYTE clut_buf[] = {FadeAllToColor}; DWORD TimeOut = XFormColorMap ((COLORMAPPTR)clut_buf, ONE_SECOND / 2); while ((GetTimeCounter () <= TimeOut) && !(GLOBAL (CurrentActivity) & CHECK_ABORT)) { UpdateInputState (); TaskSwitch (); } } } #ifdef TESTING else if (InputState & DEVICE_EXIT) return (FALSE); #endif /* TESTING */ else if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return (FALSE); } else if (!(PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_DOWN] || PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT] || PulsedInputState.menu[KEY_MENU_SELECT] || MouseButtonDown)) { if (GetTimeCounter () - InTime < InactTimeOut) return (TRUE); SleepThreadUntil (FadeMusic (0, ONE_SECOND)); StopMusic (); FadeMusic (NORMAL_VOLUME, 0); GLOBAL (CurrentActivity) = (ACTIVITY)~0; return (FALSE); } else if (PulsedInputState.menu[KEY_MENU_SELECT]) { BYTE fade_buf[1]; switch (pMS->CurState) { case LOAD_SAVED_GAME: LastActivity = CHECK_LOAD; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; break; case START_NEW_GAME: LastActivity = CHECK_LOAD | CHECK_RESTART; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; break; case PLAY_SUPER_MELEE: GLOBAL (CurrentActivity) = SUPER_MELEE; break; case SETUP_GAME: LockMutex (GraphicsLock); SetFlashRect (NULL_PTR, (FRAME)0); UnlockMutex (GraphicsLock); SetupMenu (); SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); InTime = GetTimeCounter (); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu ((BYTE)~0, pMS->CurState, pMS->CurFrame); ScreenTransition (3, NULL); UnbatchGraphics (); return TRUE; case QUIT_GAME: fade_buf[0] = FadeAllToBlack; SleepThreadUntil (XFormColorMap ((COLORMAPPTR)fade_buf, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; break; } LockMutex (GraphicsLock); SetFlashRect (NULL_PTR, (FRAME)0); UnlockMutex (GraphicsLock); return (FALSE); } else { BYTE NewState; NewState = pMS->CurState; if (PulsedInputState.menu[KEY_MENU_UP]) { if (NewState-- == START_NEW_GAME) NewState = QUIT_GAME; } else if (PulsedInputState.menu[KEY_MENU_DOWN]) { if (NewState++ == QUIT_GAME) NewState = START_NEW_GAME; } if (NewState != pMS->CurState) { BatchGraphics (); DrawRestartMenu (pMS->CurState, NewState, pMS->CurFrame); UnbatchGraphics (); pMS->CurState = NewState; } } // if (MouseButtonDown) // { // LockMutex (GraphicsLock); // SetFlashRect (NULL_PTR, (FRAME)0); // UnlockMutex (GraphicsLock); // MouseError (); // SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); // SetTransitionSource (NULL); // BatchGraphics (); // DrawRestartMenuGraphic (pMS); // DrawRestartMenu ((BYTE)~0, pMS->CurState, pMS->CurFrame); // ScreenTransition (3, NULL); // UnbatchGraphics (); // } if (MouseButtonDown) { // TODO WTF FIX GAME CONTROLS } InTime = GetTimeCounter (); return (TRUE); }
BOOLEAN Battle (BattleFrameCallback *callback) { SIZE num_ships; LockMutex (GraphicsLock); #if !(DEMO_MODE || CREATE_JOURNAL) if (LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE) { // In Supermelee, the RNG is already initialised. TFB_SeedRandom (GetTimeCounter ()); } #else /* DEMO_MODE */ if (BattleSeed == 0) BattleSeed = TFB_Random (); TFB_SeedRandom (BattleSeed); BattleSeed = TFB_Random (); /* get next battle seed */ #endif /* DEMO_MODE */ BattleSong (FALSE); num_ships = InitShips (); if (instantVictory) { num_ships = 0; battle_counter[0] = 1; battle_counter[1] = 0; instantVictory = FALSE; } if (num_ships) { BATTLE_STATE bs; GLOBAL (CurrentActivity) |= IN_BATTLE; battle_counter[0] = CountLinks (&race_q[0]); battle_counter[1] = CountLinks (&race_q[1]); if (optMeleeScale != TFB_SCALE_STEP) SetGraphicScaleMode (optMeleeScale); setupBattleInputOrder (); #ifdef NETPLAY initBattleInputBuffers (); #ifdef NETPLAY_CHECKSUM initChecksumBuffers (); #endif /* NETPLAY_CHECKSUM */ battleFrameCount = 0; ResetWinnerStarShip (); setBattleStateConnections (&bs); #endif /* NETPLAY */ if (!selectAllShips (num_ships)) { GLOBAL (CurrentActivity) |= CHECK_ABORT; goto AbortBattle; } BattleSong (TRUE); bs.NextTime = 0; #ifdef NETPLAY initBattleStateDataConnections (); { bool allOk = negotiateReadyConnections (true, NetState_inBattle); if (!allOk) { GLOBAL (CurrentActivity) |= CHECK_ABORT; goto AbortBattle; } } #endif /* NETPLAY */ bs.InputFunc = DoBattle; bs.frame_cb = callback; bs.first_time = (BOOLEAN)(LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE); UnlockMutex (GraphicsLock); DoInput (&bs, FALSE); LockMutex (GraphicsLock); AbortBattle: if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE) { if (GLOBAL (CurrentActivity) & CHECK_ABORT) { // Do not return to the main menu when a game is aborted, // (just to the supermelee menu). #ifdef NETPLAY UnlockMutex (GraphicsLock); waitResetConnections(NetState_inSetup); // A connection may already be in inSetup (set from // GetMeleeStarship). This is not a problem, although // it will generate a warning in debug mode. LockMutex (GraphicsLock); #endif GLOBAL (CurrentActivity) &= ~CHECK_ABORT; } else { // Show the result of the battle. MeleeGameOver (); } } #ifdef NETPLAY uninitBattleInputBuffers(); #ifdef NETPLAY_CHECKSUM uninitChecksumBuffers (); #endif /* NETPLAY_CHECKSUM */ setBattleStateConnections (NULL); #endif /* NETPLAY */ StopDitty (); StopMusic (); StopSound (); } UninitShips (); FreeBattleSong (); UnlockMutex (GraphicsLock); return (BOOLEAN) (num_ships < 0); }
// Post: the NetState for all players is NetState_interBattle static BOOLEAN GetMeleeStarShips (COUNT playerMask, HSTARSHIP *ships) { COUNT playerI; BOOLEAN ok; GETMELEE_STATE gmstate; TimeCount now; COUNT i; #ifdef NETPLAY for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { NetConnection *conn; if ((playerMask & (1 << playerI)) == 0) continue; // XXX: This does not have to be done per connection. conn = netConnections[playerI]; if (conn != NULL) { BattleStateData *battleStateData; battleStateData = (BattleStateData *) NetConnection_getStateData (conn); battleStateData->getMeleeState = &gmstate; } } #endif ok = true; now = GetTimeCounter (); gmstate.InputFunc = DoGetMelee; gmstate.Initialized = FALSE; for (i = 0; i < NUM_PLAYERS; ++i) { // We have to use TFB_Random() results in specific order playerI = GetPlayerOrder (i); gmstate.player[playerI].selecting = (playerMask & (1 << playerI)) != 0; gmstate.player[playerI].ships_left = battle_counter[playerI]; // We determine in advance which ship would be chosen if the player // wants a random ship, to keep it simple to keep network parties // synchronised. gmstate.player[playerI].randomIndex = (COUNT)TFB_Random () % gmstate.player[playerI].ships_left; gmstate.player[playerI].done = FALSE; if (!gmstate.player[playerI].selecting) continue; gmstate.player[playerI].timeIn = now; gmstate.player[playerI].row = 0; gmstate.player[playerI].col = NUM_PICKMELEE_COLUMNS; #ifdef NETPLAY gmstate.player[playerI].remoteSelected = FALSE; #endif gmstate.player[playerI].flashContext = Flash_createHighlight (ScreenContext, NULL); Flash_setMergeFactors (gmstate.player[playerI].flashContext, 2, 3, 2); Flash_setFrameTime (gmstate.player[playerI].flashContext, ONE_SECOND / 16); #ifdef NETPLAY if (PlayerControl[playerI] & NETWORK_CONTROL) Flash_setSpeed (gmstate.player[playerI].flashContext, ONE_SECOND / 2, 0, ONE_SECOND / 2, 0); else #endif { Flash_setSpeed (gmstate.player[playerI].flashContext, 0, ONE_SECOND / 16, 0, ONE_SECOND / 16); } PickMelee_ChangedSelection (&gmstate, playerI); Flash_start (gmstate.player[playerI].flashContext); } #ifdef NETPLAY { // NB. gmstate.player[].randomIndex and gmstate.player[].done must // be initialised before negotiateReadyConnections is completed, to // ensure that they are initialised when the SelectShip packet // arrives. bool allOk = negotiateReadyConnections (true, NetState_selectShip); if (!allOk) { // Some network connection has been reset. ok = false; } } #endif SetDefaultMenuRepeatDelay (); SetContext (OffScreenContext); DoInput (&gmstate, FALSE); WaitForSoundEnd (0); for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { if (!gmstate.player[playerI].selecting) continue; if (gmstate.player[playerI].done) { // Flash rectangle is already terminated. ships[playerI] = gmstate.player[playerI].hBattleShip; } else { Flash_terminate (gmstate.player[playerI].flashContext); gmstate.player[playerI].flashContext = NULL; ok = false; } } #ifdef NETPLAY if (ok) { if (!negotiateReadyConnections (true, NetState_interBattle)) ok = false; } else setStateConnections (NetState_interBattle); #endif if (!ok) { // Aborting. GLOBAL (CurrentActivity) &= ~IN_BATTLE; } #ifdef NETPLAY for (playerI = 0; playerI < NUM_PLAYERS; playerI++) { NetConnection *conn; if ((playerMask & (1 << playerI)) == 0) continue; // XXX: This does not have to be done per connection. conn = netConnections[playerI]; if (conn != NULL && NetConnection_isConnected (conn)) { BattleStateData *battleStateData; battleStateData = (BattleStateData *) NetConnection_getStateData (conn); battleStateData->getMeleeState = NULL; } } #endif return ok; }
static BOOLEAN DoTalkSegue (TALKING_STATE *pTS) { bool left = false; bool right = false; COUNT curTrack; if (GLOBAL (CurrentActivity) & CHECK_ABORT) { pTS->ended = true; return FALSE; } if (PulsedInputState.menu[KEY_MENU_CANCEL]) { JumpTrack (); pTS->ended = true; return FALSE; } if (optSmoothScroll == OPT_PC) { left = PulsedInputState.menu[KEY_MENU_LEFT] != 0; right = PulsedInputState.menu[KEY_MENU_RIGHT] != 0; } else if (optSmoothScroll == OPT_3DO) { left = CurrentInputState.menu[KEY_MENU_LEFT] != 0; right = CurrentInputState.menu[KEY_MENU_RIGHT] != 0; } #if DEMO_MODE || CREATE_JOURNAL left = false; right = false; #endif if (right) { SetSliderImage (SetAbsFrameIndex (ActivityFrame, 3)); if (optSmoothScroll == OPT_PC) FastForward_Page (); else if (optSmoothScroll == OPT_3DO) FastForward_Smooth (); pTS->seeking = true; } else if (left || pTS->rewind) { pTS->rewind = false; SetSliderImage (SetAbsFrameIndex (ActivityFrame, 4)); if (optSmoothScroll == OPT_PC) FastReverse_Page (); else if (optSmoothScroll == OPT_3DO) FastReverse_Smooth (); pTS->seeking = true; } else if (pTS->seeking) { // This is only done once the seeking is over (in the smooth // scroll case, once the user releases the seek button) pTS->seeking = false; SetSliderImage (SetAbsFrameIndex (ActivityFrame, 2)); } else { // 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. CheckSubtitles (); } // XXX: When seeking, all animations (talking and ambient) stop // progressing. This is an original 3DO behavior, and I see no // reason why the animations cannot continue while seeking. UpdateAnimations (pTS->seeking); UpdateSpeechGraphics (); curTrack = PlayingTrack (); pTS->ended = !pTS->seeking && !curTrack; SleepThreadUntil (pTS->NextTime); // Need a high enough framerate for 3DO smooth seeking pTS->NextTime = GetTimeCounter () + ONE_SECOND / 60; return pTS->seeking || (curTrack && curTrack <= pTS->waitTrack); }
BOOLEAN DoLoadTeam (MELEE_STATE *pMS) { DWORD TimeIn = GetTimeCounter (); /* Cancel any presses of the Pause key. */ GamePaused = FALSE; if (GLOBAL (CurrentActivity) & CHECK_ABORT) return FALSE; SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN | MENU_SOUND_PAGEUP | MENU_SOUND_PAGEDOWN, MENU_SOUND_SELECT); if (!pMS->Initialized) { LockMutex (GraphicsLock); DrawFileStrings (pMS); SelectFileString (pMS, true); pMS->Initialized = TRUE; pMS->InputFunc = DoLoadTeam; UnlockMutex (GraphicsLock); return TRUE; } if (PulsedInputState.menu[KEY_MENU_SELECT] || PulsedInputState.menu[KEY_MENU_CANCEL]) { if (PulsedInputState.menu[KEY_MENU_SELECT]) { // Copy the selected fleet to the player. Melee_LocalChange_team (pMS, pMS->side, pMS->load.view[pMS->load.cur - pMS->load.top]); } pMS->InputFunc = DoMelee; pMS->LastInputTime = GetTimeCounter (); { RECT r; GetFrameRect (SetAbsFrameIndex (MeleeFrame, 28), &r); LockMutex (GraphicsLock); RepairMeleeFrame (&r); UnlockMutex (GraphicsLock); } return TRUE; } { COUNT newTop = pMS->load.top; COUNT newIndex = pMS->load.cur; if (PulsedInputState.menu[KEY_MENU_UP]) { if (newIndex > 0) { newIndex--; if (newIndex < newTop) newTop = (newTop < LOAD_TEAM_VIEW_SIZE) ? 0 : newTop - LOAD_TEAM_VIEW_SIZE; } } else if (PulsedInputState.menu[KEY_MENU_DOWN]) { COUNT numEntries = pMS->load.numIndices + pMS->load.preBuiltCount; if (newIndex + 1 < numEntries) { newIndex++; if (newIndex >= pMS->load.bot) newTop = pMS->load.bot; } } else if (PulsedInputState.menu[KEY_MENU_PAGE_UP]) { newIndex = (newIndex < LOAD_TEAM_VIEW_SIZE) ? 0 : newIndex - LOAD_TEAM_VIEW_SIZE; newTop = (newTop < LOAD_TEAM_VIEW_SIZE) ? 0 : newTop - LOAD_TEAM_VIEW_SIZE; } else if (PulsedInputState.menu[KEY_MENU_PAGE_DOWN]) { COUNT numEntries = pMS->load.numIndices + pMS->load.preBuiltCount; if (newIndex + LOAD_TEAM_VIEW_SIZE < numEntries) { newIndex += LOAD_TEAM_VIEW_SIZE; newTop += LOAD_TEAM_VIEW_SIZE; } else { newIndex = numEntries - 1; if (newTop + LOAD_TEAM_VIEW_SIZE < numEntries && numEntries > LOAD_TEAM_VIEW_SIZE) newTop = numEntries - LOAD_TEAM_VIEW_SIZE; } } if (newIndex != pMS->load.cur) { // The cursor has been moved. LockMutex (GraphicsLock); if (newTop == pMS->load.top) { // The view itself hasn't changed. SelectFileString (pMS, false); } else { // The view is changed. pMS->load.top = newTop; DrawFileStrings (pMS); } pMS->load.cur = newIndex; UnlockMutex (GraphicsLock); } } flashSelectedTeam (pMS); SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; }
//============================================================================= // 更新処理 //============================================================================= void UpdateGameManager(void) { #ifdef _DEBUG if(GetKeyboardTrigger(DIK_F1)) { g_nGameMode = SELECTMODE_PLAY; } if(GetKeyboardTrigger(DIK_F2)) { g_nGameMode = SELECTMODE_WALLEDIT; } if(GetKeyboardTrigger(DIK_F3)) { g_nGameMode = SELECTMODE_GIMMICKEDIT; } if(GetKeyboardTrigger(DIK_F4)) { g_nGameMode = SELECTMODE_PLAYEREDIT; } if(GetKeyboardTrigger(DIK_F5)) { g_nGameMode = SELECTMODE_DELETE; } if(GetKeyboardTrigger(DIK_F6)) { g_nGameMode = SELECTMODE_SCENECHANGE; } if(GetKeyboardTrigger(DIK_F7)) { g_nGameMode = SELECTMODE_PLAYERBAR_NUM; } if(GetKeyboardTrigger(DIK_F8)) { g_nGameMode = SELECTMODE_ITEMNUMEDIT; } if(g_nGameMode != SELECTMODE_PLAY) GetBackG()[BACKGROUND_EDIT_NET].bUse = true; else GetBackG()[BACKGROUND_EDIT_NET].bUse = false; #endif switch (g_nGameMode) { case SELECTMODE_PLAY: { PrintDebugProc("【ゲームモード】\n"); if(GetTimeCounter()->fCurrentTime > TIME_15) g_bIsPlay = false; if(!g_bIsPlay) { if(IsMouseRightTriggered()) { int nGimNum = -1; int nItemNum = GetItemNum()->nItemLockTime; bool bIsLock = false; if(IsGimmickLock(&nGimNum, &bIsLock, &nItemNum) == true) { if(bIsLock == true) { SetItem(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), ITEM_TYPE_01, nGimNum); UpdataItemNum(-1); } else { DeleteItem(nGimNum); UpdataItemNum(1); } } } } break; } case SELECTMODE_WALLEDIT: { PrintDebugProc("【壁を編集するモード】\n"); WallCreateMode(); break; } case SELECTMODE_GIMMICKEDIT: { PrintDebugProc("【ギミック編集モード】\n"); GimmickCreateMode(); break; } case SELECTMODE_PLAYEREDIT: { PrintDebugProc("【プレイヤー編集モード】\n"); if(IsMouseLeftPressed()) IsMouseHitPlayer(); PlayerEdit(); break; } case SELECTMODE_DELETE: { PrintDebugProc("【削除モード】\n"); DeleteGimmick(); DeleteWall(); break; } case SELECTMODE_SCENECHANGE: { PrintDebugProc("【ステージ切り替えるモード】\n"); if(IsMouseRightTriggered()) { if(*GetSceneNum() < SCENE_TYPE_MAX) (*GetSceneNum())++; if(*GetSceneNum() == SCENE_TYPE_MAX) *GetSceneNum() = 0; g_bIsSceneInit = true; } if(g_bIsSceneInit == true) { g_bIsSceneInit = false; switch (*GetSceneNum()) { case SCENE_01: // 从文件中读取 LoadData(SCENE_01); break; case SCENE_02: // 从文件中读取 LoadData(SCENE_02); break; case SCENE_03: // 从文件中读取 LoadData(SCENE_03); break; case SCENE_04: // 从文件中读取 LoadData(SCENE_04); break; case SCENE_05: // 从文件中读取 LoadData(SCENE_05); break; default: break; } // 読み込むデータを初期化 InitDataPlayer(); InitDataWall(); InitDataGimmick(); InitDataPlayerbar(); for(int nCntGim = 0; nCntGim < MAX_GIMMICK; nCntGim++) { // 根据补完的数据对机关场景进行位置和运动预处理 SetupGimmickTrack(nCntGim); *GetCleanupSwitch() = false; } } break; } case SELECTMODE_PLAYERBAR_NUM: { PrintDebugProc("【時間軸編集モード】\n"); PrintDebugProc("数字キー「1」 時間軸数:1\n"); PrintDebugProc("数字キー「2」 時間軸数:2\n"); PrintDebugProc("数字キー「3」 時間軸数:3\n"); if(GetKeyboardTrigger(DIK_1)) { for(int nCntPlayBar = 0; nCntPlayBar < MAX_PLAYBAR; nCntPlayBar++) { //if(g_pPlaybar_GM[nCntPlayBar].bUse == true) g_pPlaybar_GM[nCntPlayBar].bUse = false; } for(int nCntGim = 0; nCntGim < MAX_GIMMICK; nCntGim++) { if(g_pGimmick_GM[nCntGim].bUse) { g_pGimmick_GM[nCntGim].nPriorityNum01 = -1; g_pGimmick_GM[nCntGim].nPriorityNum02 = -1; g_pGimmick_GM[nCntGim].nPriorityNum03 = -1; } } SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_1); PlaybarNumCount(); } if(GetKeyboardTrigger(DIK_2)) { for(int nCntPlayBar = 0; nCntPlayBar < MAX_PLAYBAR; nCntPlayBar++) { //if(g_pPlaybar_GM[nCntPlayBar].bUse == true) g_pPlaybar_GM[nCntPlayBar].bUse = false; } for(int nCntGim = 0; nCntGim < MAX_GIMMICK; nCntGim++) { if(g_pGimmick_GM[nCntGim].bUse) { g_pGimmick_GM[nCntGim].nPriorityNum01 = -1; g_pGimmick_GM[nCntGim].nPriorityNum02 = -1; g_pGimmick_GM[nCntGim].nPriorityNum03 = -1; } } SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_1); SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_2); PlaybarNumCount(); } if(GetKeyboardTrigger(DIK_3)) { for(int nCntPlayBar = 0; nCntPlayBar < MAX_PLAYBAR; nCntPlayBar++) { //if(g_pPlaybar_GM[nCntPlayBar].bUse == true) g_pPlaybar_GM[nCntPlayBar].bUse = false; } for(int nCntGim = 0; nCntGim < MAX_GIMMICK; nCntGim++) { if(g_pGimmick_GM[nCntGim].bUse) { g_pGimmick_GM[nCntGim].nPriorityNum01 = -1; g_pGimmick_GM[nCntGim].nPriorityNum02 = -1; g_pGimmick_GM[nCntGim].nPriorityNum03 = -1; } } SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_1); SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_2); SetPlaybar(D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f), PLAYBAR_3_3); PlaybarNumCount(); } break; } case SELECTMODE_ITEMNUMEDIT: { PrintDebugProc("【アイテム個数編集モード】\n"); PrintDebugProc("【メニュー】 【アイテム】 【個数】\n"); PrintDebugProc("数字キー「1」 時間固定アイテム:%d\n\n", g_pItemNum_GM->nItemLockTime); if(GetKeyboardTrigger(DIK_1)) { g_nMenuSelect_GM = 1; } switch (g_nMenuSelect_GM) { case 1: PrintDebugProc("矢印キー【左】、【右】 【プラス/マイナス 1】\n"); PrintDebugProc("矢印キー【上】、【下】 【プラス/マイナス 5】\n"); if(GetKeyboardRepeat(DIK_LEFT)) { g_pItemNum_GM->nItemLockTime -= 1; if(g_pItemNum_GM->nItemLockTime < 0) g_pItemNum_GM->nItemLockTime = 0; } if(GetKeyboardRepeat(DIK_RIGHT)) { g_pItemNum_GM->nItemLockTime += 1; if(g_pItemNum_GM->nItemLockTime > 9) g_pItemNum_GM->nItemLockTime = 9; } if(GetKeyboardRepeat(DIK_DOWN)) { g_pItemNum_GM->nItemLockTime -= 5; if(g_pItemNum_GM->nItemLockTime < 0) g_pItemNum_GM->nItemLockTime = 0; } if(GetKeyboardRepeat(DIK_UP)) { g_pItemNum_GM->nItemLockTime += 5; if(g_pItemNum_GM->nItemLockTime > 9) g_pItemNum_GM->nItemLockTime = 9; } break; default: break; } } default: break; } if(!g_bIsPlay) { switch (*GetSceneNum()) { case SCENE_01: PrintDebugProc("【SCENE_01】\n"); // 今のシーンをセーフする if(IsMouseCenterTriggered()) SaveData(SCENE_01); break; case SCENE_02: PrintDebugProc("【SCENE_02】\n"); if(IsMouseCenterTriggered()) SaveData(SCENE_02); break; case SCENE_03: PrintDebugProc("【SCENE_03】\n"); if(IsMouseCenterTriggered()) SaveData(SCENE_03); break; case SCENE_04: PrintDebugProc("【SCENE_04】\n"); if(IsMouseCenterTriggered()) SaveData(SCENE_04); break; case SCENE_05: PrintDebugProc("【SCENE_05】\n"); if(IsMouseCenterTriggered()) SaveData(SCENE_05); break; default: break; } } switch(*GetMode()) { case GAMEMODE_LOGO: break; case GAMEMODE_TITLE: { if(GetKeyboardTrigger(DIK_RETURN) || IsMouseLeftTriggered()) SetFade(FADE_OUT, FADE_IN, GAMEMODE_STAGE_SELECT); break; } case GAMEMODE_STAGE_SELECT: { g_bIsStop = true; g_bIsPlay = false; if(GetKeyboardTrigger(DIK_RETURN)) SetFade(FADE_OUT, FADE_IN, GAMEMODE_GAME); if(IsMouseLeftTriggered()) { int pIconNum = 0; if(IsMouseHitIcon(&pIconNum) == true) { *GetSceneNum() = GetGameElement()[pIconNum].nType; g_bIsSceneInit = true; } } if(g_bIsSceneInit == true) { g_bIsSceneInit = false; switch (*GetSceneNum()) { case SCENE_01: // 从文件中读取 LoadData(SCENE_01); break; case SCENE_02: // 从文件中读取 LoadData(SCENE_02); break; case SCENE_03: // 从文件中读取 LoadData(SCENE_03); break; case SCENE_04: // 从文件中读取 LoadData(SCENE_04); break; case SCENE_05: // 从文件中读取 LoadData(SCENE_05); break; default: break; } // 読み込むデータを初期化 InitDataPlayer(); InitDataWall(); InitDataGimmick(); InitDataPlayerbar(); for(int nCntGim = 0; nCntGim < MAX_GIMMICK; nCntGim++) { // 根据补完的数据对机关场景进行位置和运动预处理 SetupGimmickTrack(nCntGim); *GetCleanupSwitch() = false; } //*GetMode() = GAMEMODE_GAME; SetFade(FADE_OUT, FADE_IN, GAMEMODE_GAME); } break; } case GAMEMODE_GAME: break; case GAMEMODE_END: break; default: break; } }
static void DoSell (RESPONSE_REF R) { BYTE num_new_rainbows; UWORD rainbow_mask; SIZE added_credit; int what_to_sell_queued = 0; rainbow_mask = MAKE_WORD ( GET_GAME_STATE (RAINBOW_WORLD0), GET_GAME_STATE (RAINBOW_WORLD1) ); num_new_rainbows = (BYTE)(-GET_GAME_STATE (MELNORME_RAINBOW_COUNT)); while (rainbow_mask) { if (rainbow_mask & 1) ++num_new_rainbows; rainbow_mask >>= 1; } if (!PLAYER_SAID (R, sell)) { if (PLAYER_SAID (R, sell_life_data)) { DWORD TimeIn; added_credit = GLOBAL_SIS (TotalBioMass) * BIO_CREDIT_VALUE; NPCPhrase (SOLD_LIFE_DATA1); NPCPhrase (-(int)GLOBAL_SIS (TotalBioMass)); NPCPhrase (SOLD_LIFE_DATA2); NPCPhrase (-(int)added_credit); NPCPhrase (SOLD_LIFE_DATA3); // queue WHAT_TO_SELL before talk-segue if (num_new_rainbows) { NPCPhrase (WHAT_TO_SELL); what_to_sell_queued = 1; } AlienTalkSegue (1); DrawCargoStrings ((BYTE)~0, (BYTE)~0); SleepThread (ONE_SECOND / 2); TimeIn = GetTimeCounter (); DrawCargoStrings ( (BYTE)NUM_ELEMENT_CATEGORIES, (BYTE)NUM_ELEMENT_CATEGORIES ); do { TimeIn = GetTimeCounter (); if (AnyButtonPress (TRUE)) { DeltaCredit (GLOBAL_SIS (TotalBioMass) * BIO_CREDIT_VALUE); GLOBAL_SIS (TotalBioMass) = 0; } else { --GLOBAL_SIS (TotalBioMass); DeltaCredit (BIO_CREDIT_VALUE); } DrawCargoStrings ( (BYTE)NUM_ELEMENT_CATEGORIES, (BYTE)NUM_ELEMENT_CATEGORIES ); } while (GLOBAL_SIS (TotalBioMass)); SleepThread (ONE_SECOND / 2); LockMutex (GraphicsLock); ClearSISRect (DRAW_SIS_DISPLAY); UnlockMutex (GraphicsLock); } else /* if (R == sell_rainbow_locations) */ { added_credit = num_new_rainbows * (250 * BIO_CREDIT_VALUE); NPCPhrase (SOLD_RAINBOW_LOCATIONS1); NPCPhrase (-(int)num_new_rainbows); NPCPhrase (SOLD_RAINBOW_LOCATIONS2); NPCPhrase (-(int)added_credit); NPCPhrase (SOLD_RAINBOW_LOCATIONS3); num_new_rainbows += GET_GAME_STATE (MELNORME_RAINBOW_COUNT); SET_GAME_STATE (MELNORME_RAINBOW_COUNT, num_new_rainbows); num_new_rainbows = 0; DeltaCredit (added_credit); } AskedToBuy = FALSE; } if (GLOBAL_SIS (TotalBioMass) || num_new_rainbows) { if (!what_to_sell_queued) NPCPhrase (WHAT_TO_SELL); if (GLOBAL_SIS (TotalBioMass)) Response (sell_life_data, DoSell); if (num_new_rainbows) Response (sell_rainbow_locations, DoSell); Response (done_selling, NatureOfConversation); } else { if (PLAYER_SAID (R, sell)) NPCPhrase (NOTHING_TO_SELL); DISABLE_PHRASE (sell); NatureOfConversation (R); } }
static BOOLEAN DoRestart (MENU_STATE *pMS) { static TimeCount LastInputTime; static TimeCount InactTimeOut; TimeCount TimeIn = GetTimeCounter (); /* Cancel any presses of the Pause key. */ GamePaused = FALSE; if (pMS->Initialized) Flash_process(pMS->flashContext); if (!pMS->Initialized) { if (pMS->hMusic) { StopMusic (); DestroyMusic (pMS->hMusic); pMS->hMusic = 0; } pMS->hMusic = LoadMusic (MAINMENU_MUSIC); InactTimeOut = (pMS->hMusic ? 120 : 20) * ONE_SECOND; pMS->flashContext = Flash_createOverlay (ScreenContext, NULL, NULL); Flash_setMergeFactors (pMS->flashContext, -3, 3, 16); Flash_setSpeed (pMS->flashContext, (6 * ONE_SECOND) / 16, 0, (6 * ONE_SECOND) / 16, 0); Flash_setFrameTime (pMS->flashContext, ONE_SECOND / 16); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame); Flash_start (pMS->flashContext); PlayMusic (pMS->hMusic, TRUE, 1); LastInputTime = GetTimeCounter (); pMS->Initialized = TRUE; SleepThreadUntil (FadeScreen (FadeAllToColor, ONE_SECOND / 2)); } else if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return FALSE; } else if (PulsedInputState.menu[KEY_MENU_SELECT]) { switch (pMS->CurState) { case LOAD_SAVED_GAME: LastActivity = CHECK_LOAD; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; break; case START_NEW_GAME: LastActivity = CHECK_LOAD | CHECK_RESTART; GLOBAL (CurrentActivity) = IN_INTERPLANETARY; break; case PLAY_SUPER_MELEE: GLOBAL (CurrentActivity) = SUPER_MELEE; break; case SETUP_GAME: Flash_pause(pMS->flashContext); Flash_setState(pMS->flashContext, FlashState_fadeIn, (3 * ONE_SECOND) / 16); SetupMenu (); SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); LastInputTime = GetTimeCounter (); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); ScreenTransition (3, NULL); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame); Flash_continue(pMS->flashContext); UnbatchGraphics (); return TRUE; case QUIT_GAME: SleepThreadUntil (FadeScreen (FadeAllToBlack, ONE_SECOND / 2)); GLOBAL (CurrentActivity) = CHECK_ABORT; break; } Flash_pause(pMS->flashContext); return FALSE; } else if (PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_DOWN]) { BYTE NewState; NewState = pMS->CurState; if (PulsedInputState.menu[KEY_MENU_UP]) { if (NewState == START_NEW_GAME) NewState = QUIT_GAME; else --NewState; } else if (PulsedInputState.menu[KEY_MENU_DOWN]) { if (NewState == QUIT_GAME) NewState = START_NEW_GAME; else ++NewState; } if (NewState != pMS->CurState) { BatchGraphics (); DrawRestartMenu (pMS, NewState, pMS->CurFrame); UnbatchGraphics (); pMS->CurState = NewState; } LastInputTime = GetTimeCounter (); } else if (PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT]) { // Does nothing, but counts as input for timeout purposes LastInputTime = GetTimeCounter (); } else if (MouseButtonDown) { Flash_pause(pMS->flashContext); DoPopupWindow (GAME_STRING (MAINMENU_STRING_BASE + 54)); // Mouse not supported message SetMenuSounds (MENU_SOUND_UP | MENU_SOUND_DOWN, MENU_SOUND_SELECT); SetTransitionSource (NULL); BatchGraphics (); DrawRestartMenuGraphic (pMS); DrawRestartMenu (pMS, pMS->CurState, pMS->CurFrame); ScreenTransition (3, NULL); UnbatchGraphics (); Flash_continue(pMS->flashContext); LastInputTime = GetTimeCounter (); } else { // No input received, check if timed out if (GetTimeCounter () - LastInputTime > InactTimeOut) { SleepThreadUntil (FadeMusic (0, ONE_SECOND)); StopMusic (); FadeMusic (NORMAL_VOLUME, 0); GLOBAL (CurrentActivity) = (ACTIVITY)~0; return FALSE; } } SleepThreadUntil (TimeIn + ONE_SECOND / 30); return TRUE; }
static BOOLEAN DoBattle (BATTLE_STATE *bs) { extern UWORD nth_frame; RECT r; BYTE battle_speed; SetMenuSounds (MENU_SOUND_NONE, MENU_SOUND_NONE); #if defined (NETPLAY) && defined (NETPLAY_CHECKSUM) if (getNumNetConnections() > 0 && battleFrameCount % NETPLAY_CHECKSUM_INTERVAL == 0) { crc_State state; Checksum checksum; crc_init(&state); crc_processState (&state); checksum = (Checksum) crc_finish (&state); Netplay_NotifyAll_checksum ((uint32) battleFrameCount, (uint32) checksum); flushPacketQueues (); addLocalChecksum (battleFrameCount, checksum); } #endif ProcessInput (); // Also calls NetInput() #if defined (NETPLAY) && defined (NETPLAY_CHECKSUM) if (getNumNetConnections() > 0) { size_t delay = getBattleInputDelay(); if (battleFrameCount >= delay && (battleFrameCount - delay) % NETPLAY_CHECKSUM_INTERVAL == 0) { if (!(GLOBAL (CurrentActivity) & CHECK_ABORT)) { if (!verifyChecksums (battleFrameCount - delay)) { GLOBAL(CurrentActivity) |= CHECK_ABORT; resetConnections (ResetReason_syncLoss); } } } } #endif LockMutex (GraphicsLock); if (bs->first_time) { r.corner.x = SIS_ORG_X; r.corner.y = SIS_ORG_Y; r.extent.width = SIS_SCREEN_WIDTH; r.extent.height = SIS_SCREEN_HEIGHT; SetTransitionSource (&r); } BatchGraphics (); // Call the callback function, if set if (bs->frame_cb) bs->frame_cb (); RedrawQueue (TRUE); if (bs->first_time) { bs->first_time = FALSE; ScreenTransition (3, &r); } UnbatchGraphics (); UnlockMutex (GraphicsLock); if ((!(GLOBAL (CurrentActivity) & IN_BATTLE)) || (GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))) { return FALSE; } battle_speed = HIBYTE (nth_frame); if (battle_speed == (BYTE)~0) { // maximum speed, nothing rendered at all TaskSwitch (); } else { SleepThreadUntil (bs->NextTime + BATTLE_FRAME_RATE / (battle_speed + 1)); bs->NextTime = GetTimeCounter (); } if ((GLOBAL (CurrentActivity) & IN_BATTLE) == 0) return FALSE; #ifdef NETPLAY battleFrameCount++; #endif return TRUE; }