/* =========================================================================== Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 BFG Edition Source Code. If not, see . In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "Common_dialog.h" idCVar popupDialog_debug( "popupDialog_debug", "0", CVAR_BOOL | CVAR_ARCHIVE, "display debug spam" ); extern idCVar g_demoMode; static const char* dialogStateToString[ GDM_MAX + 1 ] = { ASSERT_ENUM_STRING( GDM_INVALID, 0 ), ASSERT_ENUM_STRING( GDM_SWAP_DISKS_TO1, 1 ), ASSERT_ENUM_STRING( GDM_SWAP_DISKS_TO2, 2 ), ASSERT_ENUM_STRING( GDM_SWAP_DISKS_TO3, 3 ), ASSERT_ENUM_STRING( GDM_NO_GAMER_PROFILE, 4 ), ASSERT_ENUM_STRING( GDM_PLAY_ONLINE_NO_PROFILE, 5 ), ASSERT_ENUM_STRING( GDM_LEADERBOARD_ONLINE_NO_PROFILE, 6 ), ASSERT_ENUM_STRING( GDM_NO_STORAGE_SELECTED, 7 ), ASSERT_ENUM_STRING( GDM_ONLINE_INCORRECT_PERMISSIONS, 8 ), ASSERT_ENUM_STRING( GDM_SP_QUIT_SAVE, 9 ), ASSERT_ENUM_STRING( GDM_SP_RESTART_SAVE, 10 ), ASSERT_ENUM_STRING( GDM_SP_SIGNIN_CHANGE, 11 ), ASSERT_ENUM_STRING( GDM_SERVER_NOT_AVAILABLE, 12 ), ASSERT_ENUM_STRING( GDM_CONNECTION_LOST_HOST, 13 ), ASSERT_ENUM_STRING( GDM_CONNECTION_LOST, 14 ), ASSERT_ENUM_STRING( GDM_OPPONENT_CONNECTION_LOST, 15 ), ASSERT_ENUM_STRING( GDM_HOST_CONNECTION_LOST, 16 ), ASSERT_ENUM_STRING( GDM_HOST_CONNECTION_LOST_STATS, 17 ), ASSERT_ENUM_STRING( GDM_FAILED_TO_LOAD_RANKINGS, 18 ), ASSERT_ENUM_STRING( GDM_HOST_QUIT, 19 ), ASSERT_ENUM_STRING( GDM_BECAME_HOST_PARTY, 20 ), ASSERT_ENUM_STRING( GDM_NEW_HOST_PARTY, 21 ), ASSERT_ENUM_STRING( GDM_LOBBY_BECAME_HOST_GAME, 22 ), ASSERT_ENUM_STRING( GDM_LOBBY_NEW_HOST_GAME, 23 ), ASSERT_ENUM_STRING( GDM_NEW_HOST_GAME, 24 ), ASSERT_ENUM_STRING( GDM_NEW_HOST_GAME_STATS_DROPPED, 25 ), ASSERT_ENUM_STRING( GDM_BECAME_HOST_GAME, 26 ), ASSERT_ENUM_STRING( GDM_BECAME_HOST_GAME_STATS_DROPPED, 27 ), ASSERT_ENUM_STRING( GDM_LOBBY_DISBANDED, 28 ), ASSERT_ENUM_STRING( GDM_LEAVE_WITH_PARTY, 29 ), ASSERT_ENUM_STRING( GDM_LEAVE_LOBBY_RET_MAIN, 30 ), ASSERT_ENUM_STRING( GDM_LEAVE_LOBBY_RET_NEW_PARTY, 31 ), ASSERT_ENUM_STRING( GDM_MIGRATING, 32 ), ASSERT_ENUM_STRING( GDM_OPPONENT_LEFT, 33 ), ASSERT_ENUM_STRING( GDM_NO_MATCHES_FOUND, 34 ), ASSERT_ENUM_STRING( GDM_INVALID_INVITE, 35 ), ASSERT_ENUM_STRING( GDM_KICKED, 36 ), ASSERT_ENUM_STRING( GDM_BANNED, 37 ), ASSERT_ENUM_STRING( GDM_SAVING, 38 ), ASSERT_ENUM_STRING( GDM_OVERWRITE_SAVE, 39 ), ASSERT_ENUM_STRING( GDM_LOAD_REQUEST, 40 ), ASSERT_ENUM_STRING( GDM_AUTOSAVE_DISABLED_STORAGE_REMOVED, 41 ), ASSERT_ENUM_STRING( GDM_STORAGE_INVALID, 42 ), ASSERT_ENUM_STRING( GDM_STORAGE_REMOVED, 43 ), ASSERT_ENUM_STRING( GDM_CONNECTING, 44 ), ASSERT_ENUM_STRING( GDM_REFRESHING, 45 ), ASSERT_ENUM_STRING( GDM_DELETE_SAVE, 46 ), ASSERT_ENUM_STRING( GDM_DELETING, 47 ), ASSERT_ENUM_STRING( GDM_BINDING_ALREDY_SET, 48 ), ASSERT_ENUM_STRING( GDM_CANNOT_BIND, 49 ), ASSERT_ENUM_STRING( GDM_OVERLAY_DISABLED, 50 ), ASSERT_ENUM_STRING( GDM_DIRECT_MAP_CHANGE, 51 ), ASSERT_ENUM_STRING( GDM_DELETE_AUTOSAVE, 52 ), ASSERT_ENUM_STRING( GDM_QUICK_SAVE, 53 ), ASSERT_ENUM_STRING( GDM_MULTI_RETRY, 54 ), ASSERT_ENUM_STRING( GDM_MULTI_SELF_DESTRUCT, 55 ), ASSERT_ENUM_STRING( GDM_MULTI_VDM_QUIT, 56 ), ASSERT_ENUM_STRING( GDM_MULTI_COOP_QUIT, 57 ), ASSERT_ENUM_STRING( GDM_LOADING_PROFILE, 58 ), ASSERT_ENUM_STRING( GDM_STORAGE_REQUIRED, 59 ), ASSERT_ENUM_STRING( GDM_INSUFFICENT_STORAGE_SPACE, 60 ), ASSERT_ENUM_STRING( GDM_PARTNER_LEFT, 61 ), ASSERT_ENUM_STRING( GDM_RESTORE_CORRUPT_SAVEGAME, 62 ), ASSERT_ENUM_STRING( GDM_UNRECOVERABLE_SAVEGAME, 63 ), ASSERT_ENUM_STRING( GDM_PROFILE_SAVE_ERROR, 64 ), ASSERT_ENUM_STRING( GDM_LOBBY_FULL, 65 ), ASSERT_ENUM_STRING( GDM_QUIT_GAME, 66 ), ASSERT_ENUM_STRING( GDM_CONNECTION_PROBLEMS, 67 ), ASSERT_ENUM_STRING( GDM_VOICE_RESTRICTED, 68 ), ASSERT_ENUM_STRING( GDM_LOAD_DAMAGED_FILE, 69 ), ASSERT_ENUM_STRING( GDM_MUST_SIGNIN, 70 ), ASSERT_ENUM_STRING( GDM_CONNECTION_LOST_NO_LEADERBOARD, 71 ), ASSERT_ENUM_STRING( GDM_SP_SIGNIN_CHANGE_POST, 72 ), ASSERT_ENUM_STRING( GDM_MIGRATING_WAITING, 73 ), ASSERT_ENUM_STRING( GDM_MIGRATING_RELAUNCHING, 74 ), ASSERT_ENUM_STRING( GDM_MIGRATING_FAILED_CONNECTION, 75 ), ASSERT_ENUM_STRING( GDM_MIGRATING_FAILED_CONNECTION_STATS, 76 ), ASSERT_ENUM_STRING( GDM_MIGRATING_FAILED_DISBANDED, 77 ), ASSERT_ENUM_STRING( GDM_MIGRATING_FAILED_DISBANDED_STATS, 78 ), ASSERT_ENUM_STRING( GDM_MIGRATING_FAILED_PARTNER_LEFT, 79 ), ASSERT_ENUM_STRING( GDM_HOST_RETURNED_TO_LOBBY, 80 ), ASSERT_ENUM_STRING( GDM_HOST_RETURNED_TO_LOBBY_STATS_DROPPED, 81 ), ASSERT_ENUM_STRING( GDM_FAILED_JOIN_LOCAL_SESSION, 82 ), ASSERT_ENUM_STRING( GDM_DELETE_CORRUPT_SAVEGAME, 83 ), ASSERT_ENUM_STRING( GDM_LEAVE_INCOMPLETE_INSTANCE, 84 ), ASSERT_ENUM_STRING( GDM_UNBIND_CONFIRM, 85 ), ASSERT_ENUM_STRING( GDM_BINDINGS_RESTORE, 86 ), ASSERT_ENUM_STRING( GDM_NEW_HOST, 87 ), ASSERT_ENUM_STRING( GDM_CONFIRM_VIDEO_CHANGES, 88 ), ASSERT_ENUM_STRING( GDM_UNABLE_TO_USE_SELECTED_STORAGE_DEVICE, 89 ), ASSERT_ENUM_STRING( GDM_ERROR_LOADING_SAVEGAME, 90 ), ASSERT_ENUM_STRING( GDM_ERROR_SAVING_SAVEGAME, 91 ), ASSERT_ENUM_STRING( GDM_DISCARD_CHANGES, 92 ), ASSERT_ENUM_STRING( GDM_LEAVE_LOBBY, 93 ), ASSERT_ENUM_STRING( GDM_LEAVE_LOBBY_AND_TEAM, 94 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_0, 95 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_1, 96 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_2, 97 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_3, 98 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_4, 99 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_5, 100 ), ASSERT_ENUM_STRING( GDM_CONTROLLER_DISCONNECTED_6, 101 ), ASSERT_ENUM_STRING( GDM_DLC_ERROR_REMOVED, 102 ), ASSERT_ENUM_STRING( GDM_DLC_ERROR_CORRUPT, 103 ), ASSERT_ENUM_STRING( GDM_DLC_ERROR_MISSING, 104 ), ASSERT_ENUM_STRING( GDM_DLC_ERROR_MISSING_GENERIC, 105 ), ASSERT_ENUM_STRING( GDM_DISC_SWAP, 106 ), ASSERT_ENUM_STRING( GDM_NEEDS_INSTALL, 107 ), ASSERT_ENUM_STRING( GDM_NO_SAVEGAMES_AVAILABLE, 108 ), ASSERT_ENUM_STRING( GDM_ERROR_JOIN_TWO_PROFILES_ONE_BOX, 109 ), ASSERT_ENUM_STRING( GDM_WARNING_PLAYING_COOP_SOLO, 110 ), ASSERT_ENUM_STRING( GDM_MULTI_COOP_QUIT_LOSE_LEADERBOARDS, 111 ), ASSERT_ENUM_STRING( GDM_CORRUPT_CONTINUE, 112 ), ASSERT_ENUM_STRING( GDM_MULTI_VDM_QUIT_LOSE_LEADERBOARDS, 113 ), ASSERT_ENUM_STRING( GDM_WARNING_PLAYING_VDM_SOLO, 114 ), ASSERT_ENUM_STRING( GDM_NO_GUEST_SUPPORT, 115 ), ASSERT_ENUM_STRING( GDM_DISC_SWAP_CONFIRMATION, 116 ), ASSERT_ENUM_STRING( GDM_ERROR_LOADING_PROFILE, 117 ), ASSERT_ENUM_STRING( GDM_CANNOT_INVITE_LOBBY_FULL, 118 ), ASSERT_ENUM_STRING( GDM_WARNING_FOR_NEW_DEVICE_ABOUT_TO_LOSE_PROGRESS, 119 ), ASSERT_ENUM_STRING( GDM_DISCONNECTED, 120 ), ASSERT_ENUM_STRING( GDM_INCOMPATIBLE_NEWER_SAVE, 121 ), ASSERT_ENUM_STRING( GDM_ACHIEVEMENTS_DISABLED_DUE_TO_CHEATING, 122 ), ASSERT_ENUM_STRING( GDM_INCOMPATIBLE_POINTER_SIZE, 123 ), ASSERT_ENUM_STRING( GDM_TEXTUREDETAIL_RESTARTREQUIRED, 124 ), ASSERT_ENUM_STRING( GDM_TEXTUREDETAIL_INSUFFICIENT_CPU, 125 ), ASSERT_ENUM_STRING( GDM_CHECKPOINT_SAVE, 126 ), ASSERT_ENUM_STRING( GDM_CALCULATING_BENCHMARK, 127 ), ASSERT_ENUM_STRING( GDM_DISPLAY_BENCHMARK, 128 ), ASSERT_ENUM_STRING( GDM_DISPLAY_CHANGE_FAILED, 129 ), ASSERT_ENUM_STRING( GDM_GPU_TRANSCODE_FAILED, 130 ), ASSERT_ENUM_STRING( GDM_OUT_OF_MEMORY, 131 ), ASSERT_ENUM_STRING( GDM_CORRUPT_PROFILE, 132 ), ASSERT_ENUM_STRING( GDM_PROFILE_TOO_OUT_OF_DATE_DEVELOPMENT_ONLY, 133 ), ASSERT_ENUM_STRING( GDM_SP_LOAD_SAVE, 134 ), ASSERT_ENUM_STRING( GDM_INSTALLING_TROPHIES, 135 ), ASSERT_ENUM_STRING( GDM_XBOX_DEPLOYMENT_TYPE_FAIL, 136 ), ASSERT_ENUM_STRING( GDM_SAVEGAME_WRONG_LANGUAGE, 137 ), ASSERT_ENUM_STRING( GDM_GAME_RESTART_REQUIRED, 138 ), ASSERT_ENUM_STRING( GDM_MAX, 139 ) }; idCVar dialog_saveClearLevel( "dialog_saveClearLevel", "1000", CVAR_INTEGER, "Time required to show long message" ); /* ======================== bool DialogMsgShouldWait There are a few dialog types that should pause so the user has the ability to read what's going on ======================== */ bool DialogMsgShouldWait( gameDialogMessages_t msg ) { switch( msg ) { case GDM_SAVING: case GDM_QUICK_SAVE: case GDM_LOADING_PROFILE: case GDM_INSTALLING_TROPHIES: case GDM_REFRESHING: return true; default: return false; } } /* ================================================ idCommonDialog::ClearDialogs ================================================ */ void idCommonDialog::ClearDialogs( bool forceClear ) { bool topMessageCleared = false; for( int index = 0; index < messageList.Num(); ++index ) { if( !messageList[index].leaveOnClear || forceClear ) { ReleaseCallBacks( index ); messageList.RemoveIndex( index ); if( index == 0 ) { topMessageCleared = true; } index--; } } if( topMessageCleared ) { ActivateDialog( false ); } } /* ================================================ idCommonDialog::AddDialogIntVal ================================================ */ void idCommonDialog::AddDialogIntVal( const char* name, int val ) { if( dialog != NULL ) { dialog->SetGlobal( name, val ); } } /* ================================================ idCommonDialog::AddDialog ================================================ */ void idCommonDialog::AddDialog( gameDialogMessages_t msg, dialogType_t type, idSWFScriptFunction* acceptCallback, idSWFScriptFunction* cancelCallback, bool pause, const char* location, int lineNumber, bool leaveOnMapHeapReset, bool waitOnAtlas, bool renderDuringLoad ) { idKeyInput::ClearStates(); // TODO_D3_PORT: //sys->ClearEvents(); idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s] msg: %s, pause: %d from: %s:%d\n", __FUNCTION__, dialogStateToString[msg], pause, location == NULL ? "NULL" : location, lineNumber ); if( dialog == NULL ) { return; } idDialogInfo info; info.msg = msg; info.type = type; info.acceptCB = acceptCallback; info.cancelCB = cancelCallback; info.clear = false; info.pause = pause; info.startTime = Sys_Milliseconds(); info.killTime = 0; info.leaveOnClear = leaveOnMapHeapReset; info.renderDuringLoad = renderDuringLoad; AddDialogInternal( info ); } /* ======================== idCommonDialog::AddDynamicDialog ======================== */ void idCommonDialog::AddDynamicDialog( gameDialogMessages_t msg, const idStaticList< idSWFScriptFunction*, 4 >& callbacks, const idStaticList< idStrId, 4 >& optionText, bool pause, idStrStatic< 256 > overrideMsg, bool leaveOnMapHeapReset, bool waitOnAtlas, bool renderDuringLoad ) { if( dialog == NULL ) { return; } idDialogInfo info; info.msg = msg; info.overrideMsg = overrideMsg; info.type = DIALOG_DYNAMIC; info.pause = pause; info.leaveOnClear = leaveOnMapHeapReset; info.acceptCB = 0 < callbacks.Num() ? callbacks[0] : NULL; info.cancelCB = 1 < callbacks.Num() ? callbacks[1] : NULL; info.altCBOne = 2 < callbacks.Num() ? callbacks[2] : NULL; info.altCBTwo = 3 < callbacks.Num() ? callbacks[3] : NULL; info.txt1 = 0 < optionText.Num() ? optionText[0] : idStrId(); info.txt2 = 1 < optionText.Num() ? optionText[1] : idStrId(); info.txt3 = 2 < optionText.Num() ? optionText[2] : idStrId(); info.txt4 = 3 < optionText.Num() ? optionText[3] : idStrId(); info.renderDuringLoad = renderDuringLoad; info.clear = false; info.startTime = Sys_Milliseconds(); info.killTime = 0; AddDialogInternal( info ); } /* ======================== idCommonDialog::AddDialogInternal ======================== */ void idCommonDialog::AddDialogInternal( idDialogInfo& info ) { // don't add the dialog if it's already in the list, we never want to show a duplicate dialog if( HasDialogMsg( info.msg, NULL ) ) { return; } // Remove the delete confirmation if we remove the device and ask for a storage confirmation if( info.msg == GDM_STORAGE_REQUIRED ) { if( HasDialogMsg( GDM_DELETE_SAVE, NULL ) ) { ClearDialog( GDM_DELETE_SAVE, NULL, 0 ); } if( HasDialogMsg( GDM_DELETE_AUTOSAVE, NULL ) ) { ClearDialog( GDM_DELETE_AUTOSAVE, NULL, 0 ); } if( HasDialogMsg( GDM_LOAD_DAMAGED_FILE, NULL ) ) { ClearDialog( GDM_LOAD_DAMAGED_FILE, NULL, 0 ); } } if( info.acceptCB != NULL ) { info.acceptCB->AddRef(); } if( info.cancelCB != NULL ) { info.cancelCB->AddRef(); } if( info.altCBOne != NULL ) { info.altCBOne->AddRef(); } if( info.altCBTwo != NULL ) { info.altCBTwo->AddRef(); } if( messageList.Num() == 0 ) { messageList.Append( info ); } else { // attempting to add another one beyond our set max. take off the oldest // one from the list in order to not crash, but this really isn't a good // thing to be happening... if( !verify( messageList.Num() < MAX_DIALOGS ) ) { messageList.RemoveIndex( MAX_DIALOGS - 1 ); } if( messageList.Num() > 0 ) { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s] msg: %s new dialog added over old\n", __FUNCTION__, dialogStateToString[info.msg] ); dialog->Activate( false ); messageList.Insert( info, 0 ); } } if( info.type == DIALOG_QUICK_SAVE || info.type == DIALOG_CRAWL_SAVE || messageList[0].msg == GDM_CALCULATING_BENCHMARK ) { ShowNextDialog(); } } /* ======================== idCommonDialog::ActivateDialog ======================== */ void idCommonDialog::ActivateDialog( bool activate ) { dialogInUse = activate; if( dialog != NULL ) { dialog->Activate( activate ); } } /* ================================================ idCommonDialog::ShowDialog ================================================ */ void idCommonDialog::ShowDialog( const idDialogInfo& info ) { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s] msg: %s, m.clear = %d, m.waitClear = %d, m.killTime = %d\n", __FUNCTION__, dialogStateToString[info.msg], info.clear, info.waitClear, info.killTime ); // here instead of add dialog to make sure we meet the TCR, otherwise it has a chance to be visible for less than 1 second if( DialogMsgShouldWait( info.msg ) && !dialogInUse ) { startSaveTime = Sys_Milliseconds(); stopSaveTime = 0; } if( IsDialogActive() ) { dialog->Activate( false ); } idStr message, title; GetDialogMsg( info.msg, message, title ); dialog->SetGlobal( "titleVal", title ); if( info.overrideMsg.IsEmpty() ) { dialog->SetGlobal( "messageInfo", message ); } else { dialog->SetGlobal( "messageInfo", info.overrideMsg ); } dialog->SetGlobal( "Infotype", info.type ); if( info.acceptCB == NULL && ( info.type != DIALOG_WAIT && info.type != DIALOG_WAIT_BLACKOUT ) ) { class idSWFScriptFunction_Accept : public idSWFScriptFunction_RefCounted { public: idSWFScriptFunction_Accept( gameDialogMessages_t _msg ) { msg = _msg; } idSWFScriptVar Call( idSWFScriptObject* thisObject, const idSWFParmList& parms ) { common->Dialog().ClearDialog( msg ); return idSWFScriptVar(); } private: gameDialogMessages_t msg; }; dialog->SetGlobal( "acceptCallBack", new( TAG_SWF ) idSWFScriptFunction_Accept( info.msg ) ); } else { dialog->SetGlobal( "acceptCallBack", info.acceptCB ); } dialog->SetGlobal( "cancelCallBack", info.cancelCB ); dialog->SetGlobal( "altCBOne", info.altCBOne ); dialog->SetGlobal( "altCBTwo", info.altCBTwo ); dialog->SetGlobal( "opt1Txt", info.txt1.GetLocalizedString() ); dialog->SetGlobal( "opt2Txt", info.txt2.GetLocalizedString() ); dialog->SetGlobal( "opt3Txt", info.txt3.GetLocalizedString() ); dialog->SetGlobal( "opt4Txt", info.txt4.GetLocalizedString() ); ActivateDialog( true ); } /* ================================================ idCommonDialog::ShowNextDialog ================================================ */ void idCommonDialog::ShowNextDialog() { for( int index = 0; index < messageList.Num(); ++index ) { if( !messageList[index].clear ) { idDialogInfo info = messageList[index]; ShowDialog( info ); break; } } } /* ================================================ idCommonDialog::ShowSaveIndicator ================================================ */ void idCommonDialog::ShowSaveIndicator( bool show ) { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s]\n", __FUNCTION__ ); if( show ) { idStr msg = idStrId( "#str_dlg_pc_saving" ).GetLocalizedString(); common->Dialog().AddDialog( GDM_SAVING, DIALOG_WAIT, NULL, NULL, true, "", 0, false, true, true ); } else { common->Dialog().ClearDialog( GDM_SAVING ); } } /* ======================== idCommonDialog::RemoveSaveDialog From TCR# 047 Games must display a message during storage writes for the following conditions and the respective amount of time: - Writes longer than one second require the standard message be displayed for three seconds. - Writes longer than three seconds require the standard message be displayed for the length of the write. - Writes that last one second or less require the shorter message be displayed for one second or the standard message for three seconds. ======================== */ void idCommonDialog::RemoveWaitDialogs() { bool topMessageCleared = false; for( int index = 0; index < messageList.Num(); ++index ) { if( DialogMsgShouldWait( messageList[index].msg ) ) { if( Sys_Milliseconds() >= messageList[index].killTime && messageList[index].waitClear ) { messageList[index].clear = true; messageList[index].waitClear = false; if( index == 0 ) { topMessageCleared = true; } } } } if( topMessageCleared && messageList.Num() > 0 ) { ActivateDialog( false ); } } /* ================================================ idCommonDialog::ClearAllDialogHack ================================================ */ void idCommonDialog::ClearAllDialogHack() { for( int index = 0; index < messageList.Num(); ++index ) { messageList[index].clear = true; messageList[index].waitClear = false; } } /* ================================================ idCommonDialog::HasDialogMsg ================================================ */ bool idCommonDialog::HasDialogMsg( gameDialogMessages_t msg, bool* isNowActive ) { for( int index = 0; index < messageList.Num(); ++index ) { idDialogInfo& info = messageList[index]; if( info.msg == msg && !info.clear ) { if( isNowActive != NULL ) { *isNowActive = ( index == 0 ); } return true; } } if( isNowActive != NULL ) { *isNowActive = false; } return false; } /* ================================================ idCommonDialog::ClearDialog ================================================ */ void idCommonDialog::ClearDialog( gameDialogMessages_t msg, const char* location, int lineNumber ) { bool topMessageCleared = false; for( int index = 0; index < messageList.Num(); ++index ) { idDialogInfo& info = messageList[index]; if( info.msg == msg && !info.clear ) { if( DialogMsgShouldWait( info.msg ) ) { // you can have 2 saving dialogs simultaneously, if you clear back-to-back, we need to let the 2nd dialog // get the clear message if( messageList[index].waitClear ) { continue; } int timeShown = Sys_Milliseconds() - messageList[index].startTime; // for the time being always use the long saves if( timeShown < dialog_saveClearLevel.GetInteger() ) { messageList[index].killTime = Sys_Milliseconds() + ( dialog_saveClearLevel.GetInteger() - timeShown ); messageList[index].waitClear = true; } else { messageList[index].clear = true; if( index == 0 ) { topMessageCleared = true; } } } else { messageList[index].clear = true; if( index == 0 ) { topMessageCleared = true; } } assert( info.msg >= GDM_INVALID && info.msg < GDM_MAX ); // not sure why /analyze complains about this idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s] msg: %s, from: %s:%d, topMessageCleared = %d, m.clear = %d, m.waitClear = %d, m.killTime = %d\n", __FUNCTION__, dialogStateToString[info.msg], location == NULL ? "NULL" : location, lineNumber, topMessageCleared, messageList[index].clear, messageList[index].waitClear, messageList[index].killTime ); break; } } if( topMessageCleared && messageList.Num() > 0 ) { ActivateDialog( false ); } } /* ================================================ idCommonDialog::ReleaseCallBacks ================================================ */ void idCommonDialog::ReleaseCallBacks( int index ) { if( index < messageList.Num() ) { if( messageList[index].acceptCB != NULL ) { messageList[index].acceptCB->Release(); messageList[index].acceptCB = NULL; } if( messageList[index].cancelCB != NULL ) { messageList[index].cancelCB->Release(); messageList[index].cancelCB = NULL; } if( messageList[index].altCBOne != NULL ) { messageList[index].altCBOne->Release(); messageList[index].altCBOne = NULL; } if( messageList[index].altCBTwo != NULL ) { messageList[index].altCBTwo->Release(); messageList[index].altCBTwo = NULL; } } } /* ================================================ idCommonDialog::Render ================================================ */ void idCommonDialog::Render( bool loading ) { dialogPause = false; if( dialog == NULL ) { return; } RemoveWaitDialogs(); bool pauseCheck = false; for( int index = 0; index < messageList.Num(); ++index ) { if( messageList[index].clear ) { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s] removing %s\n", __FUNCTION__, dialogStateToString[messageList[index].msg] ); ReleaseCallBacks( index ); messageList.RemoveIndex( index ); index--; } else { if( messageList[index].pause && !pauseCheck ) { pauseCheck = true; } } } dialogPause = pauseCheck; if( messageList.Num() > 0 && !dialog->IsActive() ) { ShowNextDialog(); } if( messageList.Num() == 0 && dialog->IsActive() ) { dialog->Activate( false ); } // Decrement the time remaining on the save indicator or turn it off if( !dialogShowingSaveIndicatorRequested && saveIndicator->IsActive() ) { ShowSaveIndicator( false ); } if( messageList.Num() > 0 && messageList[0].type == DIALOG_TIMER_ACCEPT_REVERT ) { int startTime = messageList[0].startTime; int endTime = startTime + PC_KEYBOARD_WAIT; int timeRemaining = ( endTime - Sys_Milliseconds() ) / 1000; if( timeRemaining <= 0 ) { if( messageList[0].cancelCB != NULL ) { idSWFParmList parms; messageList[0].cancelCB->Call( NULL, parms ); } messageList[0].clear = true; } else { idStrId txtTime = idStrId( "#str_time_remaining" ); dialog->SetGlobal( "countdownInfo", va( txtTime.GetLocalizedString(), timeRemaining ) ); } } if( messageList.Num() > 0 && loading && ( messageList[0].renderDuringLoad == false ) ) { return; } if( dialog->IsActive() ) { dialog->Render( renderSystem, Sys_Microseconds() ); } if( saveIndicator != NULL && saveIndicator->IsActive() ) { saveIndicator->Render( renderSystem, Sys_Microseconds() ); } } /* ================================================ idCommonDialog::Init ================================================ */ void idCommonDialog::Init() { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s]\n", __FUNCTION__ ); Shutdown(); dialog = new( TAG_SWF ) idSWF( "dialog" ); saveIndicator = new( TAG_SWF ) idSWF( "save_indicator" ); #define BIND_DIALOG_CONSTANT( x ) dialog->SetGlobal( #x, x ) if( dialog != NULL ) { BIND_DIALOG_CONSTANT( DIALOG_ACCEPT ); BIND_DIALOG_CONSTANT( DIALOG_CONTINUE ); BIND_DIALOG_CONSTANT( DIALOG_ACCEPT_CANCEL ); BIND_DIALOG_CONSTANT( DIALOG_YES_NO ); BIND_DIALOG_CONSTANT( DIALOG_CANCEL ); BIND_DIALOG_CONSTANT( DIALOG_WAIT ); BIND_DIALOG_CONSTANT( DIALOG_WAIT_BLACKOUT ); BIND_DIALOG_CONSTANT( DIALOG_WAIT_CANCEL ); BIND_DIALOG_CONSTANT( DIALOG_DYNAMIC ); BIND_DIALOG_CONSTANT( DIALOG_QUICK_SAVE ); BIND_DIALOG_CONSTANT( DIALOG_TIMER_ACCEPT_REVERT ); BIND_DIALOG_CONSTANT( DIALOG_CRAWL_SAVE ); BIND_DIALOG_CONSTANT( DIALOG_CONTINUE_LARGE ); BIND_DIALOG_CONSTANT( DIALOG_BENCHMARK ); } } /* ================================================ idCommonDialog::Shutdown ================================================ */ void idCommonDialog::Shutdown() { idLib::PrintfIf( popupDialog_debug.GetBool(), "[%s]\n", __FUNCTION__ ); ClearDialogs(); delete dialog; dialog = NULL; delete saveIndicator; saveIndicator = NULL; } /* ======================== idCommonDialog::Restart ======================== */ void idCommonDialog::Restart() { Shutdown(); Init(); } /* ================================================ idCommonDialog::GetDialogMsg ================================================ */ idStr idCommonDialog::GetDialogMsg( gameDialogMessages_t msg, idStr& message, idStr& title ) { message = "#str_dlg_pc_"; switch( msg ) { case GDM_SWAP_DISKS_TO1: { message.Append( "switch_disc_to_1" ); break; } case GDM_SWAP_DISKS_TO2: { message.Append( "switch_disc_to_2" ); break; } case GDM_SWAP_DISKS_TO3: { message.Append( "switch_disc_to_3" ); break; } case GDM_NO_GAMER_PROFILE: { message.Append( "signin_request" ); break; } case GDM_PLAY_ONLINE_NO_PROFILE: { message.Append( "online_signin_request" ); break; } case GDM_LEADERBOARD_ONLINE_NO_PROFILE: { message.Append( "online_signing_request_leaderboards" ); break; } case GDM_NO_STORAGE_SELECTED: { message.Append( "storage_device_selection_request" ); break; } case GDM_ONLINE_INCORRECT_PERMISSIONS: { message.Append( "incorrect_online_permissions" ); break; } case GDM_SP_QUIT_SAVE: { title = idLocalization::GetString( "#str_04215" ); title.ToUpper(); if( g_demoMode.GetBool() ) { message = "#str_04145"; } else { message = "#str_dlg_quit_progress_lost"; } break; } case GDM_SP_LOAD_SAVE: { title = idLocalization::GetString( "#str_02187" ); title.ToUpper(); message = "#str_dlg_360_load_request"; break; } case GDM_SP_RESTART_SAVE: { title = idLocalization::GetString( "#str_04271" ); title.ToUpper(); message = "#str_dlg_restart_progress_lost"; break; } case GDM_SP_SIGNIN_CHANGE: { message = "#str_dlg_signin_changed"; break; } case GDM_SERVER_NOT_AVAILABLE: { message.Append( "game_server_unavailable" ); break; } case GDM_CONNECTION_LOST_HOST: { message = "#str_dlg_opponent_connection_lost_ranking_not_counted"; break; } case GDM_CONNECTION_LOST: { message.Append( "online_connection_lost_main_menu_return" ); break; } case GDM_OPPONENT_CONNECTION_LOST: { message = "#str_dlg_opponent_connection_lost"; break; } case GDM_HOST_CONNECTION_LOST: { message = "#str_dlg_host_connection_lost"; break; } case GDM_HOST_CONNECTION_LOST_STATS: { message = "#str_dlg_host_connection_lost_ranking_not_counted"; break; } case GDM_FAILED_TO_LOAD_RANKINGS: { message = "#str_dlg_ranking_load_failed"; break; } case GDM_HOST_QUIT: { message = "#str_dlg_host_quit"; break; } case GDM_OPPONENT_LEFT: { message = "#str_dlg_opponent_left"; break; } case GDM_PARTNER_LEFT: { message = "#str_dlg_partner_left"; break; } case GDM_NO_MATCHES_FOUND: { message = "#str_dlg_matches_not_found"; break; } case GDM_INVALID_INVITE: { message = "#str_dlg_invalid_game"; break; } case GDM_KICKED: { message = "#str_dlg_kicked"; break; } case GDM_BANNED: { message = "#str_dlg_banned"; break; } case GDM_SAVING: { title = "#str_save_dialog_heading"; message.Append( "saving" ); break; } case GDM_QUICK_SAVE: { title = "#str_save_dialog_heading"; message.Append( "saving" ); //message = "#STR_SWF_SAVING"; break; } case GDM_OVERWRITE_SAVE: { title = "#str_02306"; message = "#str_dlg_overwrite_save"; break; } case GDM_LOAD_REQUEST: { message.Append( "load_request" ); break; } case GDM_AUTOSAVE_DISABLED_STORAGE_REMOVED: { message.Append( "storage_removed_autosave_disabled" ); break; } case GDM_STORAGE_INVALID: { message.Append( "storage_not_available" ); break; } case GDM_CONNECTING: { message = "#str_dlg_connecting"; break; } case GDM_REFRESHING: { title = "#str_01694"; message = "#str_dlg_refreshing"; break; } case GDM_DELETE_SAVE: { title = "#str_02313"; message.Append( "delete_save" ); break; } case GDM_DELETING: { message.Append( "deleting" ); break; } case GDM_BINDING_ALREDY_SET: { message.Append( "bind_exists" ); break; } case GDM_CANNOT_BIND: { message.Append( "cannont_bind" ); break; } case GDM_OVERLAY_DISABLED: { message.Append( "overlay_disabled" ); break; } case GDM_BECAME_HOST_PARTY: { message = "#str_dlg_became_host_party"; break; } case GDM_NEW_HOST_PARTY: { message = "#str_dlg_new_host_party"; break; } case GDM_LOBBY_BECAME_HOST_GAME: { message = "#str_dlg_lobby_became_host_game"; break; } case GDM_LOBBY_NEW_HOST_GAME: { message.Append( "lobby_new_host_game" ); break; } case GDM_NEW_HOST_GAME: { message = "#str_dlg_new_host_game"; break; } case GDM_NEW_HOST_GAME_STATS_DROPPED: { message = "#str_dlg_new_host_game_stats_dropped"; break; } case GDM_BECAME_HOST_GAME: { message.Append( "became_host_game" ); break; } case GDM_BECAME_HOST_GAME_STATS_DROPPED: { message = "#str_dlg_became_host_game_stats_dropped"; break; } case GDM_LOBBY_DISBANDED: { message.Append( "lobby_disbanded" ); break; } case GDM_LEAVE_WITH_PARTY: { message = "#str_dlg_leave_with_party"; break; } case GDM_LEAVE_LOBBY_RET_MAIN: { message.Append( "leave_lobby_ret_main" ); break; } case GDM_LEAVE_LOBBY_RET_NEW_PARTY: { message.Append( "leave_lobby_ret_new_party" ); break; } case GDM_MIGRATING: { message = "#str_online_host_migration"; break; } case GDM_MIGRATING_WAITING: { message = "#str_online_host_migration_waiting"; break; } case GDM_MIGRATING_RELAUNCHING: { message = "#str_online_host_migration_relaunching"; break; } case GDM_DIRECT_MAP_CHANGE: { message = "#str_dlg_direct_map_change"; break; } case GDM_DELETE_AUTOSAVE: { message.Append( "delete_autosave" ); break; } case GDM_MULTI_RETRY: { message = "#str_online_confirm_retry"; break; } case GDM_MULTI_SELF_DESTRUCT: { message = "#str_online_confirm_suicide"; break; } case GDM_MULTI_VDM_QUIT: { message = "#str_online_confirm_quit_generic"; break; } case GDM_MULTI_COOP_QUIT: { message = "#str_online_confirm_coop_quit_game_generic"; break; } case GDM_LOADING_PROFILE: { message = "#str_dlg_loading_profile"; title = "#str_dlg_updating_profile"; break; } case GDM_STORAGE_REQUIRED: { message.Append( "storage_required" ); break; } case GDM_INSUFFICENT_STORAGE_SPACE: { message = "#str_dlg_insufficient_space"; break; } case GDM_RESTORE_CORRUPT_SAVEGAME: { message = "#str_dlg_restore_corrupt_savegame"; break; } case GDM_UNRECOVERABLE_SAVEGAME: { message = "#str_dlg_unrecoverable_savegame"; break; } case GDM_PROFILE_SAVE_ERROR: { message.Append( "profile_save_error" ); break; } case GDM_LOBBY_FULL: { message.Append( "lobby_full" ); break; } case GDM_QUIT_GAME: { title = "#str_01975"; // EXIT GAME message = "#str_dlg_confirm_quit"; break; } case GDM_CONNECTION_PROBLEMS: { message = "#str_online_connection_problems"; break; } case GDM_VOICE_RESTRICTED: { message.Append( "voice_restricted" ); break; } case GDM_MUST_SIGNIN: { message.Append( "must_signin" ); break; } case GDM_LOAD_DAMAGED_FILE: { message = "#str_dlg_corrupt_save_file"; break; } case GDM_DLC_ERROR_REMOVED: { message.Append( "dlc_error_content_removed" ); break; } case GDM_DLC_ERROR_CORRUPT: { message.Append( "dlc_error_content_corrupt" ); break; } case GDM_DLC_ERROR_MISSING: { message.Append( "dlc_error_content_missing" ); break; } case GDM_DLC_ERROR_MISSING_GENERIC: { message.Append( "dlc_error_content_missing_generic" ); break; } case GDM_CONNECTION_LOST_NO_LEADERBOARD: { message.Append( "online_connection_lost_no_leaderboard" ); break; } case GDM_SP_SIGNIN_CHANGE_POST: { message.Append( "signin_changed_post" ); break; } case GDM_MIGRATING_FAILED_CONNECTION: { message = "#str_online_host_migration_failed"; break; } case GDM_MIGRATING_FAILED_CONNECTION_STATS: { message = "#str_online_host_migration_failed_stats"; break; } case GDM_MIGRATING_FAILED_DISBANDED: { message = "#str_online_host_migration_failed_disbanded"; break; } case GDM_MIGRATING_FAILED_DISBANDED_STATS: { message = "#str_online_host_migration_failed_disbanded_stats"; break; } case GDM_MIGRATING_FAILED_PARTNER_LEFT: { message = "#str_online_host_migration_failed_partner_left"; break; } case GDM_FAILED_JOIN_LOCAL_SESSION: { message = "#str_dlg_failed_join_local_session"; break; } case GDM_DELETE_CORRUPT_SAVEGAME: message = "#str_dlg_delete_corrupt_savegame"; break; case GDM_LEAVE_INCOMPLETE_INSTANCE: message = "#str_dlg_leave_incomplete_instance"; break; case GDM_UNBIND_CONFIRM: message = "#str_dlg_bind_unbind"; break; case GDM_BINDINGS_RESTORE: message = "#str_dlg_bind_restore"; break; case GDM_HOST_RETURNED_TO_LOBBY: { message.Append( "host_quit_to_lobby" ); break; } case GDM_HOST_RETURNED_TO_LOBBY_STATS_DROPPED: { message.Append( "host_quit_to_lobby_stats_dropped" ); break; } case GDM_NEW_HOST: { message.Append( "new_host" ); break; } case GDM_DISC_SWAP: { message = "#str_dlg_disc_swap"; break; } case GDM_NO_SAVEGAMES_AVAILABLE: { message = "#str_dlg_no_savegames_available"; break; } case GDM_CONFIRM_VIDEO_CHANGES: { message = "#str_dlg_confirm_display_changes"; break; } case GDM_UNABLE_TO_USE_SELECTED_STORAGE_DEVICE: { message.Append( "unable_to_use_selected_storage_device" ); break; } case GDM_ERROR_LOADING_SAVEGAME: { message = "#str_dlg_error_loading_savegame"; break; } case GDM_ERROR_SAVING_SAVEGAME: { message = "#str_dlg_error_saving_savegame"; break; } case GDM_DISCARD_CHANGES: { message = "#str_dlg_confirm_discard"; break; } case GDM_LEAVE_LOBBY: { message = "#str_online_leave_game_lobby_alt_02"; break; } case GDM_LEAVE_LOBBY_AND_TEAM: { message = "#str_online_party_leave_game"; break; } case GDM_CONTROLLER_DISCONNECTED_0: case GDM_CONTROLLER_DISCONNECTED_1: case GDM_CONTROLLER_DISCONNECTED_2: case GDM_CONTROLLER_DISCONNECTED_3: case GDM_CONTROLLER_DISCONNECTED_4: case GDM_CONTROLLER_DISCONNECTED_5: case GDM_CONTROLLER_DISCONNECTED_6: { message = "#str_dlg_reconnect_controller"; break; } case GDM_NEEDS_INSTALL: { message = "#str_dlg_game_install_message"; break; } case GDM_ERROR_JOIN_TWO_PROFILES_ONE_BOX: { message.Append( "online_join_error_two_profiles_one_box" ); break; } case GDM_WARNING_PLAYING_COOP_SOLO: { message = "#str_online_lotw_solo_warning_alt_05"; break; } case GDM_MULTI_COOP_QUIT_LOSE_LEADERBOARDS: { message = "#str_online_confirm_coop_quit_game"; break; } case GDM_CORRUPT_CONTINUE: { message = "#str_corrupt_save_load"; break; } case GDM_MULTI_VDM_QUIT_LOSE_LEADERBOARDS: { message = "#str_online_confirm_quit_game"; break; } case GDM_WARNING_PLAYING_VDM_SOLO: { message = "#str_online_cr_custom_game_no_stats"; break; } case GDM_NO_GUEST_SUPPORT: { message = "#str_dlg_ps3_incorrect_online_permissions"; break; } case GDM_DISC_SWAP_CONFIRMATION: { message = "#str_dlg_disc_swap_confirmation"; break; } case GDM_ERROR_LOADING_PROFILE: { message.Append( "error_loading_profile" ); break; } case GDM_CANNOT_INVITE_LOBBY_FULL: { message = "#str_online_join_error_full"; break; } case GDM_WARNING_FOR_NEW_DEVICE_ABOUT_TO_LOSE_PROGRESS: { message = "#str_dlg_360_new_device_selected"; break; } case GDM_DISCONNECTED: { message = "#str_online_connection_error_03"; break; } case GDM_INCOMPATIBLE_NEWER_SAVE: { message = "#str_dlg_newer_incompatible_savegame"; break; } case GDM_ACHIEVEMENTS_DISABLED_DUE_TO_CHEATING: { message = "#str_dlg_achievements_disabled_due_to_cheating"; break; } case GDM_INCOMPATIBLE_POINTER_SIZE: { message = "#str_dlg_pointer_size_mismatch"; break; } case GDM_TEXTUREDETAIL_RESTARTREQUIRED: { message = "#str_swf_texture_restart"; break; } case GDM_TEXTUREDETAIL_INSUFFICIENT_CPU: { message = "#str_swf_insufficient_cores"; break; } case GDM_CALCULATING_BENCHMARK: { message = "#str_swf_calc_benchmark"; break; } case GDM_DISPLAY_BENCHMARK: { message = "BENCHMARK SCORE = "; break; } case GDM_DISPLAY_CHANGE_FAILED: { message = "#str_swf_display_changes_failed"; break; } case GDM_GPU_TRANSCODE_FAILED: { message = "#str_swf_gpu_transcode_failed"; break; } case GDM_OUT_OF_MEMORY: { message = "#str_swf_failed_level_load"; break; } case GDM_CORRUPT_PROFILE: { message = "#str_dlg_corrupt_profile"; break; } case GDM_PROFILE_TOO_OUT_OF_DATE_DEVELOPMENT_ONLY: { message = "#str_dlg_profile_too_out_of_date_development_only"; break; } case GDM_INSTALLING_TROPHIES: { title = "#str_dlg_ps3_trophy_install_heading"; message = "#str_dlg_ps3_trophy_installing"; break; } case GDM_XBOX_DEPLOYMENT_TYPE_FAIL: { message = "#str_dlg_360_installed_continue"; break; } case GDM_GAME_RESTART_REQUIRED: { message = "#str_dlg_game_restart_required"; break; } default: { message = "MESSAGE TYPE NOT DEFINED"; break; } } return message; } /* ================================================ idCommonDialog::HandleDialogEvent ================================================ */ bool idCommonDialog::HandleDialogEvent( const sysEvent_t* sev ) { if( dialog != NULL && dialog->IsLoaded() && dialog->IsActive() ) { if( saveIndicator->IsActive() ) { return false; } else { if( dialog->HandleEvent( sev ) ) { idKeyInput::ClearStates(); // TODO_D3_PORT //sys->ClearEvents(); } } return true; } return false; } /* ================================================ idCommonDialog::IsDialogActive ================================================ */ bool idCommonDialog::IsDialogActive() { if( dialog != NULL ) { return dialog->IsActive(); } return false; } CONSOLE_COMMAND( commonDialogClear, "clears all dialogs that may be hung", 0 ) { common->Dialog().ClearAllDialogHack(); } CONSOLE_COMMAND( testShowDialog, "show a dialog", 0 ) { int dialogId = atoi( args.Argv( 1 ) ); common->Dialog().AddDialog( ( gameDialogMessages_t )dialogId, DIALOG_ACCEPT, NULL, NULL, false ); } CONSOLE_COMMAND( testShowDynamicDialog, "show a dynamic dialog", 0 ) { class idSWFScriptFunction_Continue : public idSWFScriptFunction_RefCounted { public: idSWFScriptVar Call( idSWFScriptObject* thisObject, const idSWFParmList& parms ) { common->Dialog().ClearDialog( GDM_INSUFFICENT_STORAGE_SPACE ); return idSWFScriptVar(); } }; idStaticList< idSWFScriptFunction*, 4 > callbacks; idStaticList< idStrId, 4 > optionText; callbacks.Append( new( TAG_SWF ) idSWFScriptFunction_Continue() ); optionText.Append( idStrId( "#str_swf_continue" ) ); // build custom space required string // #str_dlg_space_required ~= "There is insufficient storage available. Please free %s and try again." idStr format = idStrId( "#str_dlg_space_required" ).GetLocalizedString(); idStr size; int requiredSpaceInBytes = 150000; if( requiredSpaceInBytes > ( 1024 * 1024 ) ) { size = va( "%.1f MB", ( float ) requiredSpaceInBytes / ( 1024.0f * 1024.0f ) ); } else { size = va( "%.0f KB", ( float ) requiredSpaceInBytes / 1024.0f ); } idStr msg = va( format.c_str(), size.c_str() ); common->Dialog().AddDynamicDialog( GDM_INSUFFICENT_STORAGE_SPACE, callbacks, optionText, true, msg ); } CONSOLE_COMMAND( testShowDialogBug, "show a dynamic dialog", 0 ) { common->Dialog().ShowSaveIndicator( true ); common->Dialog().ShowSaveIndicator( false ); // This locks the game because it thinks it's paused because we're passing in pause = true but the // dialog isn't ever added because of the abuse of dialog->isActive when the save indicator is shown. int dialogId = atoi( args.Argv( 1 ) ); common->Dialog().AddDialog( ( gameDialogMessages_t )dialogId, DIALOG_ACCEPT, NULL, NULL, true ); }