static void BackgroundInitKernel (DWORD TimeOut) { LoadMasterShipList (TaskSwitch); TaskSwitch (); InitGameKernel (); while ((GetTimeCounter () <= TimeOut) && !(GLOBAL (CurrentActivity) & CHECK_ABORT)) { UpdateInputState (); TaskSwitch (); } }
void RebindInputState (int templat, int control, int index) { VCONTROL_GESTURE g; char keybuf[40], valbuf[40]; keybuf[39] = valbuf[39] = '\0'; if (templat >= num_templ || control >= num_flight || index >= MAX_FLIGHT_ALTERNATES) { log_add (log_Warning, "RebindInputState(): invalid control index"); return; } /* Remove the old binding on this spot */ RemoveInputState (templat, control, index); /* Wait for the next interesting bit of user input */ VControl_ClearGesture (); while (!VControl_GetLastGesture (&g)) { TaskSwitch (); } /* And now, add the new binding. */ VControl_AddGestureBinding (&g, (int *)(flight_vec + templat * num_flight + control)); *CONTROL_PTR(templat, control, index) = g; snprintf (keybuf, 39, "keys.%d.%s.%d", templat+1, flight_res_names[control], index+1); VControl_DumpGesture (valbuf, 39, &g); res_PutString (keybuf, valbuf); }
/* Insert the contents of the selection buffer into the queue of the tty associated with the current console. Invoked by ioctl(). */ int paste_selection(struct tty_struct *tty) { DECLARE_WAITQUEUE(wait, current); char *bp = sel_buffer; int c = sel_buffer_lth; int l; struct vt_struct *vt = (struct vt_struct *) tty->driver_data; if (!bp || !c) return 0; do_unblank_screen(); current->state = TASK_INTERRUPTIBLE; add_wait_queue(&vt->paste_wait, &wait); while (c) { if (test_bit(TTY_THROTTLED, &tty->flags)) { TaskSwitch(); continue; } l = MIN(c, tty->ldisc.receive_room(tty)); tty->ldisc.receive_buf(tty, bp, 0, l); c -= l; bp += l; } current->state = TASK_RUNNING; return 0; }
void WaitForNoInput (SIZE Duration) { INPUT_STATE PressState; PressState = AnyButtonPress (FALSE); if (Duration < 0) { if (PressState) return; Duration = -Duration; } else if (!PressState) return; { DWORD TimeOut; INPUT_STATE ButtonState; TimeOut = GetTimeCounter () + Duration; do { ButtonState = AnyButtonPress (FALSE); if (PressState) { PressState = ButtonState; ButtonState = 0; } } while (!ButtonState && (TaskSwitch (), GetTimeCounter ()) <= TimeOut); } }
void SignalStopMainThread (void) { GamePaused = FALSE; GLOBAL (CurrentActivity) |= CHECK_ABORT; TaskSwitch (); }
void SplashScreen (void (* DoProcessing)(DWORD TimeOut)) { BYTE xform_buf[1]; STAMP s; DWORD TimeOut; BOOLEAN InputState; xform_buf[0] = FadeAllToBlack; SleepThreadUntil (XFormColorMap ( (COLORMAPPTR) xform_buf, ONE_SECOND / 120)); LockMutex (GraphicsLock); SetContext (ScreenContext); s.origin.x = s.origin.y = 0; s.frame = CaptureDrawable (LoadGraphic (TITLE_ANIM)); DrawStamp (&s); DestroyDrawable (ReleaseDrawable (s.frame)); UnlockMutex (GraphicsLock); xform_buf[0] = FadeAllToColor; TimeOut = XFormColorMap ((COLORMAPPTR)xform_buf, ONE_SECOND / 2); if (DoProcessing) DoProcessing (TimeOut); if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return; } /* There was a forcible setting of CHECK_ABORT here. I cannot * find any purpose for this that DoRestart doesn't handle * better (forcing all other threads but this one to quit out, * I believe), and have thus removed it. It was interfering * with the proper operation of the quit operation. * --Michael */ TimeOut += ONE_SECOND * 3; while (!(InputState = AnyButtonPress (FALSE)) && (GetTimeCounter () <= TimeOut) && !(GLOBAL (CurrentActivity) & CHECK_ABORT)) { TaskSwitch (); } if (GLOBAL (CurrentActivity) & CHECK_ABORT) { return; } GLOBAL (CurrentActivity) &= ~CHECK_ABORT; /* You can't try to quit during a fade to black, because if * you try, the confirmation window will fade to black too. * Fixing this will require a rewrite of our whole rendering * engine. -- Michael */ xform_buf[0] = FadeAllToBlack; SleepThreadUntil (XFormColorMap ((COLORMAPPTR)xform_buf, ONE_SECOND / 2)); }
/* This could probably be done better with a condition variable of some kind. */ void ConcludeTask (Task task) { Thread old = task->thread; // log_add (log_Debug, "Awaiting conclusion of %s", task->name); if (old) { Task_SetState (task, TASK_EXIT); while (task->thread == old) { TaskSwitch (); } } }
void DoInput (void *pInputState, BOOLEAN resetInput) { if (resetInput) FlushInput (); do { MENU_SOUND_FLAGS soundFlags; Async_process (); TaskSwitch (); UpdateInputState (); #if DEMO_MODE || CREATE_JOURNAL if (ArrowInput != DemoInput) #endif { #if CREATE_JOURNAL JournalInput (InputState); #endif /* CREATE_JOURNAL */ } soundFlags = MenuKeysToSoundFlags (&PulsedInputState); if (MenuSounds && (soundFlags & (sound_0 | sound_1))) { SOUND S; S = MenuSounds; if (soundFlags & sound_1) S = SetAbsSoundIndex (S, MENU_SOUND_SUCCESS); PlaySoundEffect (S, 0, NotPositional (), NULL, 0); } if (inputCallback) inputCallback (); } while (((INPUT_STATE_DESC*)pInputState)->InputFunc (pInputState)); if (resetInput) FlushInput (); }
// 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))); }
void CScheduler::Yield (void) { while ((m_nCurrent = GetNextTask ()) == MAX_TASKS) // no task is ready { assert (m_nTasks > 0); } assert (m_nCurrent < MAX_TASKS); CTask *pNext = m_pTask[m_nCurrent]; assert (pNext != 0); if (m_pCurrent == pNext) { return; } TTaskRegisters *pOldRegs = m_pCurrent->GetRegs (); m_pCurrent = pNext; TTaskRegisters *pNewRegs = m_pCurrent->GetRegs (); assert (pOldRegs != 0); assert (pNewRegs != 0); TaskSwitch (pOldRegs, pNewRegs); }
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); }
// Only call from main() thread!! void TFB_FlushGraphics (void) { int commands_handled; BOOLEAN livelock_deterrence; // This is technically a locking violation on DrawCommandQueue.Size, // but it is likely to not be very destructive. if (DrawCommandQueue.Size == 0) { static int last_fade = 255; static int last_transition = 255; int current_fade = GetFadeAmount (); int current_transition = TransitionAmount; if ((current_fade != 255 && current_fade != last_fade) || (current_transition != 255 && current_transition != last_transition) || (current_fade == 255 && last_fade != 255) || (current_transition == 255 && last_transition != 255)) { TFB_SwapBuffers (TFB_REDRAW_FADING); // if fading, redraw every frame } else { TaskSwitch (); } last_fade = current_fade; last_transition = current_transition; BroadcastCondVar (RenderingCond); return; } if (GfxFlags & TFB_GFXFLAGS_SHOWFPS) computeFPS (); commands_handled = 0; livelock_deterrence = FALSE; if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE) { TFB_BatchReset (); } if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE) { Lock_DCQ (-1); livelock_deterrence = TRUE; } TFB_BBox_Reset (); for (;;) { TFB_DrawCommand DC; if (!TFB_DrawCommandQueue_Pop (&DC)) { // the Queue is now empty. break; } ++commands_handled; if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size > DCQ_LIVELOCK_MAX) { // log_add (log_Debug, "Initiating livelock deterrence!"); livelock_deterrence = TRUE; Lock_DCQ (-1); } switch (DC.Type) { case TFB_DRAWCOMMANDTYPE_SETMIPMAP: { TFB_DrawCommand_SetMipmap *cmd = &DC.data.setmipmap; TFB_DrawImage_SetMipmap (cmd->image, cmd->mipmap, cmd->hotx, cmd->hoty); break; } case TFB_DRAWCOMMANDTYPE_IMAGE: { TFB_DrawCommand_Image *cmd = &DC.data.image; TFB_Image *DC_image = cmd->image; const int x = cmd->x; const int y = cmd->y; TFB_DrawCanvas_Image (DC_image, x, y, cmd->scale, cmd->scaleMode, cmd->colormap, cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer)); if (cmd->destBuffer == TFB_SCREEN_MAIN) { LockMutex (DC_image->mutex); if (cmd->scale) TFB_BBox_RegisterCanvas (DC_image->ScaledImg, x - DC_image->last_scale_hs.x, y - DC_image->last_scale_hs.y); else TFB_BBox_RegisterCanvas (DC_image->NormalImg, x - DC_image->NormalHs.x, y - DC_image->NormalHs.y); UnlockMutex (DC_image->mutex); } break; } case TFB_DRAWCOMMANDTYPE_FILLEDIMAGE: { TFB_DrawCommand_FilledImage *cmd = &DC.data.filledimage; TFB_Image *DC_image = cmd->image; const int x = cmd->x; const int y = cmd->y; TFB_DrawCanvas_FilledImage (DC_image, x, y, cmd->scale, cmd->scaleMode, cmd->color, cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer)); if (cmd->destBuffer == TFB_SCREEN_MAIN) { LockMutex (DC_image->mutex); if (cmd->scale) TFB_BBox_RegisterCanvas (DC_image->ScaledImg, x - DC_image->last_scale_hs.x, y - DC_image->last_scale_hs.y); else TFB_BBox_RegisterCanvas (DC_image->NormalImg, x - DC_image->NormalHs.x, y - DC_image->NormalHs.y); UnlockMutex (DC_image->mutex); } break; } case TFB_DRAWCOMMANDTYPE_FONTCHAR: { TFB_DrawCommand_FontChar *cmd = &DC.data.fontchar; TFB_Char *DC_char = cmd->fontchar; const int x = cmd->x; const int y = cmd->y; TFB_DrawCanvas_FontChar (DC_char, cmd->backing, x, y, cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer)); if (cmd->destBuffer == TFB_SCREEN_MAIN) { RECT r; r.corner.x = x - DC_char->HotSpot.x; r.corner.y = y - DC_char->HotSpot.y; r.extent.width = DC_char->extent.width; r.extent.height = DC_char->extent.height; TFB_BBox_RegisterRect (&r); } break; } case TFB_DRAWCOMMANDTYPE_LINE: { TFB_DrawCommand_Line *cmd = &DC.data.line; if (cmd->destBuffer == TFB_SCREEN_MAIN) { TFB_BBox_RegisterPoint (cmd->x1, cmd->y1); TFB_BBox_RegisterPoint (cmd->x2, cmd->y2); } TFB_DrawCanvas_Line (cmd->x1, cmd->y1, cmd->x2, cmd->y2, cmd->color, cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer)); break; } case TFB_DRAWCOMMANDTYPE_RECTANGLE: { TFB_DrawCommand_Rect *cmd = &DC.data.rect; if (cmd->destBuffer == TFB_SCREEN_MAIN) TFB_BBox_RegisterRect (&cmd->rect); TFB_DrawCanvas_Rect (&cmd->rect, cmd->color, cmd->drawMode, TFB_GetScreenCanvas (cmd->destBuffer)); break; } case TFB_DRAWCOMMANDTYPE_SCISSORENABLE: { TFB_DrawCommand_Scissor *cmd = &DC.data.scissor; TFB_DrawCanvas_SetClipRect ( TFB_GetScreenCanvas (TFB_SCREEN_MAIN), &cmd->rect); TFB_BBox_SetClipRect (&DC.data.scissor.rect); break; } case TFB_DRAWCOMMANDTYPE_SCISSORDISABLE: TFB_DrawCanvas_SetClipRect ( TFB_GetScreenCanvas (TFB_SCREEN_MAIN), NULL); TFB_BBox_SetClipRect (NULL); break; case TFB_DRAWCOMMANDTYPE_COPYTOIMAGE: { TFB_DrawCommand_CopyToImage *cmd = &DC.data.copytoimage; TFB_Image *DC_image = cmd->image; const POINT dstPt = {0, 0}; if (DC_image == 0) { log_add (log_Debug, "DCQ ERROR: COPYTOIMAGE passed null " "image ptr"); break; } LockMutex (DC_image->mutex); TFB_DrawCanvas_CopyRect ( TFB_GetScreenCanvas (cmd->srcBuffer), &cmd->rect, DC_image->NormalImg, dstPt); UnlockMutex (DC_image->mutex); break; } case TFB_DRAWCOMMANDTYPE_COPY: { TFB_DrawCommand_Copy *cmd = &DC.data.copy; const RECT r = cmd->rect; if (cmd->destBuffer == TFB_SCREEN_MAIN) TFB_BBox_RegisterRect (&cmd->rect); TFB_DrawCanvas_CopyRect ( TFB_GetScreenCanvas (cmd->srcBuffer), &r, TFB_GetScreenCanvas (cmd->destBuffer), r.corner); break; } case TFB_DRAWCOMMANDTYPE_DELETEIMAGE: { TFB_Image *DC_image = DC.data.deleteimage.image; TFB_DrawImage_Delete (DC_image); break; } case TFB_DRAWCOMMANDTYPE_DELETEDATA: { void *data = DC.data.deletedata.data; HFree (data); break; } case TFB_DRAWCOMMANDTYPE_SENDSIGNAL: ClearSemaphore (DC.data.sendsignal.sem); break; case TFB_DRAWCOMMANDTYPE_REINITVIDEO: { TFB_DrawCommand_ReinitVideo *cmd = &DC.data.reinitvideo; int oldDriver = GraphicsDriver; int oldFlags = GfxFlags; int oldWidth = ScreenWidthActual; int oldHeight = ScreenHeightActual; // JMS_GFX: Added resolutionFactor if (TFB_ReInitGraphics (cmd->driver, cmd->flags, cmd->width, cmd->height, resolutionFactor)) { log_add (log_Error, "Could not provide requested mode: " "reverting to last known driver."); // We don't know what exactly failed, so roll it all back if (TFB_ReInitGraphics (oldDriver, oldFlags, oldWidth, oldHeight, resolutionFactor)) { log_add (log_Fatal, "Couldn't reinit at that point either. " "Your video has been somehow tied in knots."); exit (EXIT_FAILURE); } } TFB_SwapBuffers (TFB_REDRAW_YES); break; } case TFB_DRAWCOMMANDTYPE_CALLBACK: { DC.data.callback.callback (DC.data.callback.arg); break; } } } if (livelock_deterrence) Unlock_DCQ (); TFB_SwapBuffers (TFB_REDRAW_NO); RenderedFrames++; BroadcastCondVar (RenderingCond); }
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; }
/* This code assumes that you aren't in Character Mode. This is * currently safe because VControl doesn't see keystrokes when you * are, and thus cannot conclude that an exit is necessary. */ BOOLEAN DoConfirmExit (void) { BOOLEAN result; static BOOLEAN in_confirm = FALSE; if (LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE && LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE && !(LastActivity & CHECK_RESTART)) SuspendGameClock (); if (CommData.ConversationPhrases && PlayingTrack ()) PauseTrack (); LockMutex (GraphicsLock); if (in_confirm) { result = FALSE; ExitRequested = FALSE; } else { RECT r; STAMP s; FRAME F; CONTEXT oldContext; RECT oldRect; BOOLEAN response = FALSE, done; in_confirm = TRUE; oldContext = SetContext (ScreenContext); GetContextClipRect (&oldRect); SetContextClipRect (NULL_PTR); r.extent.width = CONFIRM_WIN_WIDTH + 4; r.extent.height = CONFIRM_WIN_HEIGHT + 4; r.corner.x = (SCREEN_WIDTH - r.extent.width) >> 1; r.corner.y = (SCREEN_HEIGHT - r.extent.height) >> 1; s.origin = r.corner; F = CaptureDrawable (LoadDisplayPixmap (&r, (FRAME)0)); SetSystemRect (&r); DrawConfirmationWindow (response); // Releasing the lock lets the rotate_planet_task // draw a frame. PauseRotate can still allow one more frame // to be drawn, so it is safer to just not release the lock //UnlockMutex (GraphicsLock); FlushGraphics (); //LockMutex (GraphicsLock); GLOBAL (CurrentActivity) |= CHECK_ABORT; FlushInput (); done = FALSE; do { // Forbid recursive calls or pausing here! ExitRequested = FALSE; GamePaused = FALSE; UpdateInputState (); if (PulsedInputState.menu[KEY_MENU_SELECT]) { done = TRUE; PlayMenuSound (MENU_SOUND_SUCCESS); } else if (PulsedInputState.menu[KEY_MENU_CANCEL]) { done = TRUE; response = FALSE; } else if (PulsedInputState.menu[KEY_MENU_LEFT] || PulsedInputState.menu[KEY_MENU_RIGHT]) { response = !response; DrawConfirmationWindow (response); PlayMenuSound (MENU_SOUND_MOVE); } TaskSwitch (); } while (!done); s.frame = F; DrawStamp (&s); DestroyDrawable (ReleaseDrawable (s.frame)); ClearSystemRect (); if (response) { result = TRUE; } else { result = FALSE; GLOBAL (CurrentActivity) &= ~CHECK_ABORT; } ExitRequested = FALSE; GamePaused = FALSE; FlushInput (); SetContextClipRect (&oldRect); SetContext (oldContext); } UnlockMutex (GraphicsLock); if (LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE && LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE && !(LastActivity & CHECK_RESTART)) ResumeGameClock (); if (CommData.ConversationPhrases && PlayingTrack ()) { ResumeTrack (); if (CommData.AlienTransitionDesc.AnimFlags & TALK_DONE) do_subtitles ((void *)~0); } in_confirm = FALSE; return (result); }
BOOLEAN PauseGame (void) { RECT r; STAMP s; BOOLEAN ClockActive; CONTEXT OldContext; FRAME F; HOT_SPOT OldHot; if (ActivityFrame == 0 || (GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_PAUSE)) || (LastActivity & (CHECK_LOAD | CHECK_RESTART))) return (FALSE); GLOBAL (CurrentActivity) |= CHECK_PAUSE; ClockActive = (BOOLEAN)( LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE && GameClockRunning () ); if (ClockActive) SuspendGameClock (); else if (CommData.ConversationPhrases && PlayingTrack ()) PauseTrack (); SetSemaphore (GraphicsSem); OldContext = SetContext (ScreenContext); OldHot = SetFrameHot (Screen, MAKE_HOT_SPOT (0, 0)); GetFrameRect (ActivityFrame, &r); r.corner.x = (SCREEN_WIDTH - r.extent.width) >> 1; r.corner.y = (SCREEN_HEIGHT - r.extent.height) >> 1; s.origin = r.corner; s.frame = ActivityFrame; F = CaptureDrawable (LoadDisplayPixmap (&r, (FRAME)0)); DrawStamp (&s); FlushGraphics (); { BYTE scan; scan = KBDToUNICODE (SK_F1); while (KeyDown (scan)) TaskSwitch (); } FlushInput (); while (KeyHit () != SK_F1) TaskSwitch (); s.frame = F; DrawStamp (&s); DestroyDrawable (ReleaseDrawable (s.frame)); SetFrameHot (Screen, OldHot); SetContext (OldContext); WaitForNoInput (ONE_SECOND / 4); FlushInput (); ClearSemaphore (GraphicsSem); if (ClockActive) ResumeGameClock (); else if (CommData.ConversationPhrases && PlayingTrack ()) ResumeTrack (); TaskSwitch (); GLOBAL (CurrentActivity) &= ~CHECK_PAUSE; return (TRUE); }