diff --git a/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp b/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp index 1a45016368d..b0a5b065429 100644 --- a/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp +++ b/Core/GameEngine/Source/GameClient/GUI/LoadScreen.cpp @@ -60,6 +60,7 @@ #include "Common/GameEngine.h" #include "Common/GameLOD.h" #include "Common/GameState.h" +#include "Common/MessageStream.h" #include "Common/MultiplayerSettings.h" #include "Common/Player.h" #include "Common/PlayerList.h" @@ -68,6 +69,7 @@ #include "GameClient/Display.h" #include "GameClient/GadgetProgressBar.h" #include "GameClient/GadgetStaticText.h" +#include "GameClient/GameClient.h" #include "GameClient/GameText.h" #include "GameClient/GameWindowManager.h" #include "GameClient/GameWindowTransitions.h" @@ -157,7 +159,8 @@ LoadScreen::~LoadScreen() void LoadScreen::update( Int percent ) { TheGameEngine->serviceWindowsOS(); - if (TheGameEngine->getQuitting()) + TheMessageStream->propagateMessages(); + if (TheGameEngine->getQuitting() || (TheGameLogic && TheGameLogic->m_quitToDesktopAfterMatch)) return; //don't bother with any of this if the player is exiting game. TheWindowManager->update(); @@ -539,20 +542,11 @@ void SinglePlayerLoadScreen::init( GameInfo *game ) Int shiftedPercent = -FRAME_FUDGE_ADD + 1; while (m_videoStream->frameIndex() < m_videoStream->frameCount() - 1 ) { - // TheSuperHackers @feature User can now skip video by pressing ESC - if (TheKeyboard) + if (GameClient::isMovieAbortRequested()) { - TheKeyboard->UPDATE(); - KeyboardIO *io = TheKeyboard->findKey(KEY_ESC, KeyboardIO::STATUS_UNUSED); - if (io && BitIsSet(io->state, KEY_STATE_DOWN)) - { - io->setUsed(); - break; - } + break; } - TheGameEngine->serviceWindowsOS(); - if(!m_videoStream->isFrameReady()) { Sleep(1); @@ -634,6 +628,11 @@ void SinglePlayerLoadScreen::init( GameInfo *game ) fudgeFactor = 30 * ((currTime - begin)/ INT_TO_REAL(delay )); GadgetProgressBarSetProgress(m_progressBar, fudgeFactor); + if (GameClient::isMovieAbortRequested()) + { + break; + } + TheWindowManager->update(); TheDisplay->draw(); Sleep(100); @@ -1054,20 +1053,11 @@ void ChallengeLoadScreen::init( GameInfo *game ) Int shiftedPercent = -FRAME_FUDGE_ADD + 1; while (m_videoStream->frameIndex() < m_videoStream->frameCount() - 1 ) { - // TheSuperHackers @feature User can now skip video by pressing ESC - if (TheKeyboard) + if (GameClient::isMovieAbortRequested()) { - TheKeyboard->UPDATE(); - KeyboardIO *io = TheKeyboard->findKey(KEY_ESC, KeyboardIO::STATUS_UNUSED); - if (io && BitIsSet(io->state, KEY_STATE_DOWN)) - { - io->setUsed(); - break; - } + break; } - TheGameEngine->serviceWindowsOS(); - if(!m_videoStream->isFrameReady()) { Sleep(1); @@ -1109,7 +1099,13 @@ void ChallengeLoadScreen::init( GameInfo *game ) // if we're min speced m_videoStream->frameGoto(m_videoStream->frameCount()); // zero based while(!m_videoStream->isFrameReady()) + { + if (GameClient::isMovieAbortRequested()) + { + break; + } Sleep(1); + } m_videoStream->frameDecompress(); m_videoStream->frameRender(m_videoBuffer); if(m_videoBuffer) @@ -1126,6 +1122,11 @@ void ChallengeLoadScreen::init( GameInfo *game ) fudgeFactor = 30 * ((currTime - begin)/ INT_TO_REAL(delay )); GadgetProgressBarSetProgress(m_progressBar, fudgeFactor); + if (GameClient::isMovieAbortRequested()) + { + break; + } + TheWindowManager->update(); TheDisplay->draw(); Sleep(100); diff --git a/Generals/Code/GameEngine/Include/Common/MessageStream.h b/Generals/Code/GameEngine/Include/Common/MessageStream.h index a8b937ef538..8336ce45342 100644 --- a/Generals/Code/GameEngine/Include/Common/MessageStream.h +++ b/Generals/Code/GameEngine/Include/Common/MessageStream.h @@ -277,6 +277,7 @@ class GameMessage : public MemoryPoolObject MSG_META_TOGGLE_PAUSE_ALT, ///< TheSuperHackers @feature Toggle game pause (alternative mapping) MSG_META_STEP_FRAME, ///< TheSuperHackers @feature Step one frame MSG_META_STEP_FRAME_ALT, ///< TheSuperHackers @feature Step one frame (alternative mapping) + MSG_META_DEMO_INSTANT_QUIT, ///< bail out of game immediately // META items that are really for debug/demo/development use only... @@ -289,7 +290,6 @@ class GameMessage : public MemoryPoolObject MSG_META_DEMO_LOD_INCREASE, ///< increase LOD by 1 MSG_META_DEMO_TOGGLE_ZOOM_LOCK, ///< Toggle the camera zoom lock on/off MSG_META_DEMO_PLAY_CAMEO_MOVIE, ///< Play a movie in the cameo spot - MSG_META_DEMO_INSTANT_QUIT, ///< bail out of game immediately MSG_META_DEMO_TOGGLE_SPECIAL_POWER_DELAYS, ///< Toggle special power delays on/off MSG_META_DEMO_BATTLE_CRY, ///< battle cry MSG_META_DEMO_SWITCH_TEAMS, ///< switch local control to another team diff --git a/Generals/Code/GameEngine/Include/GameClient/GameClient.h b/Generals/Code/GameEngine/Include/GameClient/GameClient.h index dd9bb98ce1a..2bd00f36d00 100644 --- a/Generals/Code/GameEngine/Include/GameClient/GameClient.h +++ b/Generals/Code/GameEngine/Include/GameClient/GameClient.h @@ -150,6 +150,8 @@ class GameClient : public SubsystemInterface, UnsignedInt getRenderedObjectCount() const { return m_renderedObjectCount; } void incrementRenderedObjectCount() { m_renderedObjectCount++; } + static Bool isMovieAbortRequested(); + protected: // snapshot methods diff --git a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h index a5b91bb8f6f..7d27118e0ae 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -153,6 +153,7 @@ class GameLogic : public SubsystemInterface, public Snapshot // super hack void startNewGame( Bool saveGame ); + void tryStartNewGame( Bool saveGame ); void loadMapINI( AsciiString mapName ); void updateLoadProgress( Int progress ); @@ -196,6 +197,7 @@ class GameLogic : public SubsystemInterface, public Snapshot UnsignedInt getFrameObjectsChangedTriggerAreas() {return m_frameObjectsChangedTriggerAreas;} void exitGame(); + void quit(Bool toDesktop); void clearGameData(Bool showScoreScreen = TRUE); ///< Clear the game data void closeWindows(); @@ -243,6 +245,8 @@ class GameLogic : public SubsystemInterface, public Snapshot // this should be called only by UpdateModule, thanks. void friend_awakenUpdateModule(Object* obj, UpdateModulePtr update, UnsignedInt whenToWakeUp); + Bool m_quitToDesktopAfterMatch; + protected: // snapshot methods diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp index bd5803484bb..2bf1e959f41 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp @@ -137,23 +137,9 @@ void destroyQuitMenu() */ static void exitQuitMenu() { + TheGameLogic->quit(FALSE); // destroy the quit menu destroyQuitMenu(); - - // clear out all the game data - if ( TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInSkirmishGame() && !TheGameInfo->isSandbox() ) - { - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT); - msg->appendBooleanArgument(TRUE); - } - TheGameLogic->exitGame(); - // TheGameLogic->clearGameData(); - // display the menu on top of the shell stack - // TheShell->showShell(); - - // this will trigger an exit - // TheGameEngine->setQuitting( TRUE ); - TheInGameUI->setClientQuiet( TRUE ); } static void noExitQuitMenu() { @@ -162,20 +148,9 @@ static void noExitQuitMenu() static void quitToDesktopQuitMenu() { + TheGameLogic->quit(TRUE); // destroy the quit menu destroyQuitMenu(); - - if (TheGameLogic->isInGame()) - { - if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD) - { - TheRecorder->stopRecording(); - } - TheGameLogic->clearGameData(); - } - TheGameEngine->setQuitting(TRUE); - TheInGameUI->setClientQuiet( TRUE ); - } static void surrenderQuitMenu() diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 8f89f92955d..8fb8fcde69a 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -535,6 +535,11 @@ void GameClient::update() Int beginTime = timeGetTime(); while(beginTime + 4000 > timeGetTime() ) { + if (GameClient::isMovieAbortRequested()) + { + break; + } + TheWindowManager->update(); // redraw all views, update the GUI TheDisplay->draw(); @@ -755,6 +760,32 @@ void GameClient::updateHeadless() TheParticleSystemManager->reset(); } +Bool GameClient::isMovieAbortRequested() +{ + // TheSuperHackers @feature User can skip video by pressing ESC + if (TheKeyboard) + { + TheKeyboard->UPDATE(); + KeyboardIO *io = TheKeyboard->findKey(KEY_ESC, KeyboardIO::STATUS_UNUSED); + if (io && BitIsSet(io->state, KEY_STATE_DOWN)) + { + io->setUsed(); + return TRUE; + } + } + + // TheSuperHackers @feature Service OS for Window Close / Alt-F4 events + TheGameEngine->serviceWindowsOS(); + TheMessageStream->propagateMessages(); + + if (TheGameEngine->getQuitting() || (TheGameLogic && TheGameLogic->m_quitToDesktopAfterMatch)) + { + return TRUE; + } + + return FALSE; +} + /** ----------------------------------------------------------------------------------------------- * Call the given callback function for each object contained within the given region. */ diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index 13103412d04..32486bf77ae 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -3697,27 +3697,15 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage break; } - - -#if defined(RTS_DEBUG) - //------------------------------------------------------------------------- BEGIN DEMO MESSAGES - //------------------------------------------------------------------------- BEGIN DEMO MESSAGES - //------------------------------------------------------------------------- BEGIN DEMO MESSAGES - //------------------------------------------------------------------------------- DEMO MESSAGES - //----------------------------------------------------------------------------------------- + case GameMessage::MSG_META_DEMO_INSTANT_QUIT: - if (TheGameLogic->isInGame()) - { - if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD) - { - TheRecorder->stopRecording(); - } - TheGameLogic->clearGameData(); - } - TheGameEngine->setQuitting(TRUE); + { + TheGameLogic->quit(TRUE); disp = DESTROY_MESSAGE; break; + } +#if defined(RTS_DEBUG) //------------------------------------------------------------------------------- DEMO MESSAGES //----------------------------------------------------------------------------------------- case GameMessage::MSG_META_DEMO_SWITCH_TEAMS: @@ -5053,6 +5041,7 @@ static Bool isSystemMessage( const GameMessage *msg ) case GameMessage::MSG_LOGIC_CRC: case GameMessage::MSG_SET_REPLAY_CAMERA: case GameMessage::MSG_FRAME_TICK: + case GameMessage::MSG_META_DEMO_INSTANT_QUIT: return TRUE; } return FALSE; diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 25a0bdf0175..75790105739 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -244,6 +244,7 @@ GameLogic::GameLogic() m_logicTimeScaleEnabledMemory = FALSE; m_loadScreen = nullptr; m_forceGameStartByTimeOut = FALSE; + m_quitToDesktopAfterMatch = FALSE; #ifdef DUMP_PERF_STATS m_overallFailedPathfinds = 0; #endif @@ -911,6 +912,8 @@ static void populateRandomStartPosition( GameInfo *game ) } } +struct QuitGameException {}; + // ------------------------------------------------------------------------------------------------ /** Update the load screen progress */ // ------------------------------------------------------------------------------------------------ @@ -920,6 +923,10 @@ void GameLogic::updateLoadProgress( Int progress ) if( m_loadScreen ) m_loadScreen->update( progress ); + if (TheGameEngine->getQuitting() || m_quitToDesktopAfterMatch) + { + throw QuitGameException(); + } } // ------------------------------------------------------------------------------------------------ @@ -966,7 +973,18 @@ void GameLogic::setGameMode( GameMode mode ) // ------------------------------------------------------------------------------------------------ void GameLogic::startNewGame( Bool saveGame ) { + try + { + tryStartNewGame(saveGame); + } + catch (QuitGameException&) + { + // TheSuperHackers @info The application is cleanly aborting the loading process + } +} +void GameLogic::tryStartNewGame( Bool saveGame ) +{ #ifdef DUMP_PERF_STATS __int64 startTime64; __int64 endTime64,freq64; @@ -2066,8 +2084,6 @@ void GameLogic::startNewGame( Bool saveGame ) { TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE( "GUI:FastForwardInstructions", L"Press F to toggle Fast Forward" ) ); } - - } //----------------------------------------------------------------------------------------- @@ -3619,6 +3635,71 @@ void GameLogic::exitGame() TheMessageStream->appendMessage(GameMessage::MSG_CLEAR_GAME_DATA); } +// ------------------------------------------------------------------------------------------------ +void GameLogic::quit(Bool toDesktop) +{ + if (isInGame()) + { + if (isInInteractiveGame()) + { + if (!TheInGameUI->isQuitMenuVisible()) + { + ToggleQuitMenu(); + return; + } + + if (isInMultiplayerGame() && TheGameInfo && !TheGameInfo->isSandbox()) + { + GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT); + msg->appendBooleanArgument(TRUE); + } + } + + if (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_RECORD) + { + TheRecorder->stopRecording(); + } + + setGamePaused(FALSE); + + if (TheScriptEngine) + { + TheScriptEngine->forceUnfreezeTime(); + TheScriptEngine->doUnfreezeTime(); + } + + if (toDesktop) + { + if (isInMultiplayerGame()) + { + m_quitToDesktopAfterMatch = TRUE; + exitGame(); + } + else + { + clearGameData(); + } + } + else + { + exitGame(); + } + } + + if (toDesktop) + { + if (!isInMultiplayerGame()) + { + TheGameEngine->setQuitting(TRUE); + } + } + + if (TheInGameUI) + { + TheInGameUI->setClientQuiet(TRUE); + } +} + // ------------------------------------------------------------------------------------------------ /** A new GameLogic object has been constructed, therefore create * a corresponding drawable and bind them together. */ diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index 14e3a2dffc1..447748f4b5c 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -275,9 +275,10 @@ void GameLogic::clearGameData( Bool showScoreScreen ) // if(shellGame) - if (TheGlobalData->m_initialFile.isEmpty() == FALSE) + if (TheGlobalData->m_initialFile.isEmpty() == FALSE || m_quitToDesktopAfterMatch) { TheGameEngine->setQuitting(TRUE); + m_quitToDesktopAfterMatch = FALSE; } HideControlBar(); diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h index 7959a404cd7..e143fbd2b05 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h @@ -155,6 +155,7 @@ class GameClient : public SubsystemInterface, void incrementRenderedObjectCount() { m_renderedObjectCount++; } virtual void notifyTerrainObjectMoved(Object *obj) = 0; + static Bool isMovieAbortRequested(); protected: diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 160d1dbd4cf..2bd30a053dd 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -158,6 +158,7 @@ class GameLogic : public SubsystemInterface, public Snapshot // super hack void startNewGame( Bool loadSaveGame ); + void tryStartNewGame( Bool loadSaveGame ); void loadMapINI( AsciiString mapName ); void updateLoadProgress( Int progress ); @@ -211,6 +212,7 @@ class GameLogic : public SubsystemInterface, public Snapshot UnsignedInt getFrameObjectsChangedTriggerAreas() {return m_frameObjectsChangedTriggerAreas;} void exitGame(); + void quit(Bool toDesktop); void clearGameData(Bool showScoreScreen = TRUE); ///< Clear the game data void closeWindows(); @@ -261,6 +263,8 @@ class GameLogic : public SubsystemInterface, public Snapshot // this should be called only by UpdateModule, thanks. void friend_awakenUpdateModule(Object* obj, UpdateModulePtr update, UnsignedInt whenToWakeUp); + Bool m_quitToDesktopAfterMatch; + protected: // snapshot methods diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp index 5273e4e6387..e35afd50b21 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/QuitMenu.cpp @@ -137,23 +137,9 @@ void destroyQuitMenu() */ static void exitQuitMenu() { + TheGameLogic->quit(FALSE); // destroy the quit menu destroyQuitMenu(); - - // clear out all the game data - if ( TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInSkirmishGame() && !TheGameInfo->isSandbox() ) - { - GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT); - msg->appendBooleanArgument(TRUE); - } - TheGameLogic->exitGame(); - // TheGameLogic->clearGameData(); - // display the menu on top of the shell stack - // TheShell->showShell(); - - // this will trigger an exit - // TheGameEngine->setQuitting( TRUE ); - TheInGameUI->setClientQuiet( TRUE ); } static void noExitQuitMenu() { @@ -162,20 +148,9 @@ static void noExitQuitMenu() static void quitToDesktopQuitMenu() { + TheGameLogic->quit(TRUE); // destroy the quit menu destroyQuitMenu(); - - if (TheGameLogic->isInGame()) - { - if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD) - { - TheRecorder->stopRecording(); - } - TheGameLogic->clearGameData(); - } - TheGameEngine->setQuitting(TRUE); - TheInGameUI->setClientQuiet( TRUE ); - } static void surrenderQuitMenu() diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 87c1b27090f..238cf5b0051 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -556,6 +556,11 @@ void GameClient::update() Int beginTime = timeGetTime(); while(beginTime + 4000 > timeGetTime() ) { + if (GameClient::isMovieAbortRequested()) + { + break; + } + TheWindowManager->update(); // redraw all views, update the GUI TheDisplay->draw(); @@ -793,6 +798,32 @@ void GameClient::updateHeadless() TheParticleSystemManager->reset(); } +Bool GameClient::isMovieAbortRequested() +{ + // TheSuperHackers @feature User can skip video by pressing ESC + if (TheKeyboard) + { + TheKeyboard->UPDATE(); + KeyboardIO *io = TheKeyboard->findKey(KEY_ESC, KeyboardIO::STATUS_UNUSED); + if (io && BitIsSet(io->state, KEY_STATE_DOWN)) + { + io->setUsed(); + return TRUE; + } + } + + // TheSuperHackers @feature Service OS for Window Close / Alt-F4 events + TheGameEngine->serviceWindowsOS(); + TheMessageStream->propagateMessages(); + + if (TheGameEngine->getQuitting() || (TheGameLogic && TheGameLogic->m_quitToDesktopAfterMatch)) + { + return TRUE; + } + + return FALSE; +} + /** ----------------------------------------------------------------------------------------------- * Call the given callback function for each object contained within the given region. */ diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp index bf06bd0a858..aa07e502c7f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/CommandXlat.cpp @@ -91,10 +91,6 @@ #include "ww3d.h" - -#define dont_ALLOW_ALT_F4 - - #if defined(RTS_DEBUG) /*non-static*/ Real TheSkateDistOverride = 0.0f; @@ -4076,26 +4072,12 @@ GameMessageDisposition CommandTranslator::translateGameMessage(const GameMessage } - - -#ifdef ALLOW_ALT_F4 case GameMessage::MSG_META_DEMO_INSTANT_QUIT: { - if (TheGameLogic->isInGame()) - { - if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD) - { - TheRecorder->stopRecording(); - } - TheGameLogic->clearGameData(); - } - TheGameEngine->setQuitting(TRUE); + TheGameLogic->quit(TRUE); disp = DESTROY_MESSAGE; break; } -#endif - - //------------------------------------------------------------------------------- DEMO MESSAGES @@ -5586,6 +5568,7 @@ static Bool isSystemMessage( const GameMessage *msg ) case GameMessage::MSG_LOGIC_CRC: case GameMessage::MSG_SET_REPLAY_CAMERA: case GameMessage::MSG_FRAME_TICK: + case GameMessage::MSG_META_DEMO_INSTANT_QUIT: return TRUE; } return FALSE; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 4d0bb085dc4..a77b33a0d4c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -262,6 +262,7 @@ GameLogic::GameLogic() m_loadingMap = FALSE; m_loadingSave = FALSE; m_clearingGameData = FALSE; + m_quitToDesktopAfterMatch = FALSE; } //------------------------------------------------------------------------------------------------- @@ -1052,6 +1053,8 @@ static void populateRandomStartPosition( GameInfo *game ) } } +struct QuitGameException {}; + // ------------------------------------------------------------------------------------------------ /** Update the load screen progress */ // ------------------------------------------------------------------------------------------------ @@ -1061,6 +1064,10 @@ void GameLogic::updateLoadProgress( Int progress ) if( m_loadScreen ) m_loadScreen->update( progress ); + if (TheGameEngine->getQuitting() || m_quitToDesktopAfterMatch) + { + throw QuitGameException(); + } } // ------------------------------------------------------------------------------------------------ @@ -1101,6 +1108,18 @@ void GameLogic::setGameMode( GameMode mode ) * point and ready to load up with all the data */ // ------------------------------------------------------------------------------------------------ void GameLogic::startNewGame( Bool loadingSaveGame ) +{ + try + { + tryStartNewGame(loadingSaveGame); + } + catch (QuitGameException&) + { + // TheSuperHackers @info The application is cleanly aborting the loading process + } +} + +void GameLogic::tryStartNewGame( Bool loadingSaveGame ) { #ifdef DUMP_PERF_STATS @@ -2368,8 +2387,6 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) { TheInGameUI->messageNoFormat( TheGameText->FETCH_OR_SUBSTITUTE( "GUI:FastForwardInstructions", L"Press F to toggle Fast Forward" ) ); } - - } //----------------------------------------------------------------------------------------- @@ -4170,6 +4187,71 @@ void GameLogic::exitGame() TheMessageStream->appendMessage(GameMessage::MSG_CLEAR_GAME_DATA); } +// ------------------------------------------------------------------------------------------------ +void GameLogic::quit(Bool toDesktop) +{ + if (isInGame()) + { + if (isInInteractiveGame()) + { + if (!TheInGameUI->isQuitMenuVisible()) + { + ToggleQuitMenu(); + return; + } + + if (isInMultiplayerGame() && TheGameInfo && !TheGameInfo->isSandbox()) + { + GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT); + msg->appendBooleanArgument(TRUE); + } + } + + if (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_RECORD) + { + TheRecorder->stopRecording(); + } + + setGamePaused(FALSE); + + if (TheScriptEngine) + { + TheScriptEngine->forceUnfreezeTime(); + TheScriptEngine->doUnfreezeTime(); + } + + if (toDesktop) + { + if (isInMultiplayerGame()) + { + m_quitToDesktopAfterMatch = TRUE; + exitGame(); + } + else + { + clearGameData(); + } + } + else + { + exitGame(); + } + } + + if (toDesktop) + { + if (!isInMultiplayerGame()) + { + TheGameEngine->setQuitting(TRUE); + } + } + + if (TheInGameUI) + { + TheInGameUI->setClientQuiet(TRUE); + } +} + // ------------------------------------------------------------------------------------------------ /** A new GameLogic object has been constructed, therefore create * a corresponding drawable and bind them together. */ diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index 291d269f276..33b712d37c3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -280,9 +280,10 @@ void GameLogic::clearGameData( Bool showScoreScreen ) // if(shellGame) - if (TheGlobalData->m_initialFile.isEmpty() == FALSE) + if (TheGlobalData->m_initialFile.isEmpty() == FALSE || m_quitToDesktopAfterMatch) { TheGameEngine->setQuitting(TRUE); + m_quitToDesktopAfterMatch = FALSE; } HideControlBar();