Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1081 lines
35 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Manages the set of application configuration options.
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "Options.h"
  8. #include "hammer.h"
  9. #include "MainFrm.h"
  10. #include "mapdoc.h"
  11. #include "KeyValues.h"
  12. #include "ConfigManager.h"
  13. #include "GlobalFunctions.h"
  14. #include "CustomMessages.h"
  15. #include "OptionProperties.h"
  16. #include <process.h>
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. const char GAMECFG_SIG[] = "Game Configurations File\r\n\x1a";
  20. const float GAMECFG_VERSION = 1.4f;
  21. static const char *pszGeneral = "General";
  22. static const char *pszView2D = "2D Views";
  23. static const char *pszView3D = "3D Views";
  24. static const char *g_szColors = "Custom2DColors";
  25. const int iThisVersion = 2;
  26. // So File | Open will be in the right directory.
  27. char *g_pMapDir = NULL;
  28. //-----------------------------------------------------------------------------
  29. // Purpose:
  30. //-----------------------------------------------------------------------------
  31. COptionsConfigs::COptionsConfigs(void)
  32. {
  33. nConfigs = 0;
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. // Output :
  38. //-----------------------------------------------------------------------------
  39. COptionsConfigs::~COptionsConfigs(void)
  40. {
  41. for (int i = 0; i < nConfigs; i++)
  42. {
  43. CGameConfig *pConfig = Configs[i];
  44. if (!pConfig)
  45. continue;
  46. delete pConfig;
  47. }
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Purpose:
  51. // Output :
  52. //-----------------------------------------------------------------------------
  53. CGameConfig *COptionsConfigs::AddConfig(void)
  54. {
  55. CGameConfig *pConfig = new CGameConfig;
  56. Configs.SetAtGrow(nConfigs++, pConfig);
  57. return pConfig;
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. // Input : dwID -
  62. // piIndex -
  63. // Output :
  64. //-----------------------------------------------------------------------------
  65. CGameConfig *COptionsConfigs::FindConfig(DWORD dwID, int *piIndex)
  66. {
  67. for(int i = 0; i < nConfigs; i++)
  68. {
  69. if(Configs[i]->dwID == dwID)
  70. {
  71. if(piIndex)
  72. piIndex[0] = i;
  73. return Configs[i];
  74. }
  75. }
  76. return NULL;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Looks for a game configuration with a given mod directory.
  80. //-----------------------------------------------------------------------------
  81. CGameConfig *COptionsConfigs::FindConfigForGame(const char *szGame)
  82. {
  83. for (int i = 0; i < nConfigs; i++)
  84. {
  85. char *pszGameDir = Configs[i]->m_szModDir;
  86. if ( Q_stricmp( pszGameDir, szGame ) == 0 )
  87. return Configs[i];
  88. }
  89. return NULL;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. // Output : Returns the number of game configurations successfully imported.
  94. //-----------------------------------------------------------------------------
  95. int COptionsConfigs::ImportOldGameConfigs(const char *pszFileName)
  96. {
  97. int nConfigsRead = 0;
  98. char szRootDir[MAX_PATH];
  99. char szFullPath[MAX_PATH];
  100. APP()->GetDirectory(DIR_PROGRAM, szRootDir);
  101. Q_MakeAbsolutePath( szFullPath, MAX_PATH, pszFileName, szRootDir );
  102. std::fstream file( szFullPath, std::ios::in | std::ios::binary );
  103. if (file.is_open())
  104. {
  105. // Read sig.
  106. char szSig[sizeof(GAMECFG_SIG)];
  107. file.read(szSig, sizeof szSig);
  108. if (!memcmp(szSig, GAMECFG_SIG, sizeof szSig))
  109. {
  110. // Read version.
  111. float fThisVersion;
  112. file.read((char *)&fThisVersion, sizeof(fThisVersion));
  113. if ((fThisVersion >= 1.0) && (fThisVersion <= GAMECFG_VERSION))
  114. {
  115. // Read number of configs.
  116. int nTotalConfigs;
  117. file.read((char *)&nTotalConfigs, sizeof(nTotalConfigs));
  118. // Load each config.
  119. for (int i = 0; i < nTotalConfigs; i++)
  120. {
  121. CGameConfig *pConfig = AddConfig();
  122. pConfig->Import(file, fThisVersion);
  123. nConfigsRead++;
  124. if (!g_pMapDir)
  125. {
  126. g_pMapDir = (char *)pConfig->szMapDir;
  127. }
  128. }
  129. }
  130. }
  131. file.close();
  132. }
  133. return(nConfigsRead);
  134. }
  135. // Our call to "new" will be hosed without this header
  136. #include "tier0/memdbgoff.h"
  137. //-----------------------------------------------------------------------------
  138. // Purpose:
  139. // Output : Returns true on success, false on failure.
  140. //-----------------------------------------------------------------------------
  141. bool COptionsConfigs::ResetGameConfigs( bool bOverwrite )
  142. {
  143. CGameConfigManager mgr;
  144. int nNumLoaded = 0;
  145. mgr.SetBaseDirectory( m_strConfigDir );
  146. if ( bOverwrite )
  147. {
  148. // Reset the configurations on the disk
  149. mgr.ResetConfigs();
  150. // Load the newly changed game configs
  151. nNumLoaded = LoadGameConfigs();
  152. }
  153. else
  154. {
  155. // Simply get the keyvalue block from the manager and parse that
  156. KeyValues *pDefaultConfigs = new KeyValues( "Defaults" );
  157. if ( mgr.GetDefaultGameBlock( pDefaultConfigs ) == false )
  158. return false;
  159. // Load from the blocks
  160. nNumLoaded = LoadGameConfigsBlock( pDefaultConfigs );
  161. // Clean up
  162. pDefaultConfigs->deleteThis();
  163. }
  164. return ( nNumLoaded > 0 );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose:
  168. // Input : *pBlock -
  169. // Output : int
  170. //-----------------------------------------------------------------------------
  171. int COptionsConfigs::LoadGameConfigsBlock( KeyValues *pBlock )
  172. {
  173. if ( pBlock == NULL )
  174. return 0;
  175. int nConfigsRead = 0;
  176. for ( KeyValues *pKey = pBlock->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
  177. {
  178. CGameConfig *pConfig = AddConfig();
  179. if ( pConfig != NULL )
  180. {
  181. if ( pConfig->Load( pKey ) )
  182. {
  183. nConfigsRead++;
  184. }
  185. }
  186. }
  187. return nConfigsRead;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: Loads all the game configs from disk.
  191. // Output : Returns the number of game configurations successfully loaded.
  192. //-----------------------------------------------------------------------------
  193. int COptionsConfigs::LoadGameConfigs()
  194. {
  195. //
  196. // Read game configs - this is from an external file so we can distribute it
  197. // with the editor as a set of defaults.
  198. //
  199. // Older versions of the editor used a binary file. Try that first.
  200. //
  201. int nConfigsRead = ImportOldGameConfigs("GameCfg.wc");
  202. if (nConfigsRead > 0)
  203. {
  204. // This will cause a double conversion, from .wc to .ini to .txt, but oh well...
  205. char szRootDir[MAX_PATH];
  206. char szFullPath[MAX_PATH];
  207. APP()->GetDirectory(DIR_PROGRAM, szRootDir);
  208. Q_MakeAbsolutePath( szFullPath, MAX_PATH, "GameCfg.wc", szRootDir );
  209. remove( szFullPath );
  210. char szSaveName[MAX_PATH];
  211. strcpy(szSaveName, m_strConfigDir);
  212. Q_AppendSlash(szSaveName, sizeof(szSaveName));
  213. Q_strcat(szSaveName, "GameCfg.ini", sizeof(szSaveName));
  214. SaveGameConfigs();
  215. return(nConfigsRead);
  216. }
  217. CGameConfigManager mgr;
  218. if ( !mgr.LoadConfigs( m_strConfigDir ) )
  219. return 0;
  220. KeyValues *pGame = mgr.GetGameBlock();
  221. if (!pGame)
  222. return 0;
  223. // Install the message handler for error messages.
  224. GDSetMessageFunc(Msg);
  225. // Load from the blocks
  226. nConfigsRead = LoadGameConfigsBlock( pGame );
  227. return nConfigsRead;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose: Saves all the cgame configurations to disk.
  231. // Input : *pszFileName -
  232. //-----------------------------------------------------------------------------
  233. void COptionsConfigs::SaveGameConfigs()
  234. {
  235. // Only do this if we've got configs to save!
  236. if ( GetGameConfigCount() == 0 )
  237. return;
  238. CGameConfigManager mgr;
  239. if ( mgr.LoadConfigs( m_strConfigDir ) == false )
  240. return;
  241. // Get the global configuration data
  242. KeyValues *pGame = mgr.GetGameBlock();
  243. // For each Hammer known configuation, update the values in the global configs
  244. for ( int i = 0; i < nConfigs; i++ )
  245. {
  246. KeyValues *pConfig = pGame->FindKey(Configs.GetAt(i)->szName);
  247. // Add the configuration if it wasn't found
  248. if ( pConfig == NULL )
  249. {
  250. pConfig = pGame->CreateNewKey();
  251. if ( pConfig == NULL )
  252. {
  253. // FIXME: fatal error
  254. return;
  255. }
  256. }
  257. // Update the changes
  258. Configs.GetAt(i)->Save(pConfig);
  259. }
  260. // For each global configuration, remove any configs Hammer has deleted
  261. bool bFoundConfig;
  262. KeyValues *pConfig = pGame->GetFirstTrueSubKey();
  263. while ( pConfig != NULL )
  264. {
  265. // Search through all the configs Hammer knows of for a matching name
  266. bFoundConfig = false;
  267. for ( int i = 0; i < nConfigs; i++ )
  268. {
  269. if ( !Q_stricmp( pConfig->GetName(), Configs.GetAt(i)->szName ) )
  270. {
  271. bFoundConfig = true;
  272. break;
  273. }
  274. }
  275. // Move along to the next config
  276. if ( bFoundConfig )
  277. {
  278. pConfig = pConfig->GetNextTrueSubKey();
  279. continue;
  280. }
  281. // Delete the configuration block if we didn't find it
  282. KeyValues *pNextConfig = pConfig->GetNextTrueSubKey();
  283. pGame->RemoveSubKey( pConfig );
  284. pConfig->deleteThis();
  285. pConfig = pNextConfig;
  286. }
  287. // Save the resulting changes
  288. mgr.SaveConfigs( m_strConfigDir );
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose:
  292. //-----------------------------------------------------------------------------
  293. COptions::COptions(void)
  294. {
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose: Looks for the Valve Hammer Editor registry settings and returns whether
  298. // they were found.
  299. //-----------------------------------------------------------------------------
  300. static bool HammerSettingsFound(void)
  301. {
  302. bool bFound = false;
  303. HKEY hkeySoftware;
  304. if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ | KEY_WRITE, &hkeySoftware) == ERROR_SUCCESS)
  305. {
  306. HKEY hkeyValve;
  307. if (RegOpenKeyEx(hkeySoftware, "Valve", 0, KEY_READ | KEY_WRITE, &hkeyValve) == ERROR_SUCCESS)
  308. {
  309. HKEY hkeyHammer;
  310. if (RegOpenKeyEx(hkeyValve, "Hammer", 0, KEY_READ | KEY_WRITE, &hkeyHammer) == ERROR_SUCCESS)
  311. {
  312. HKEY hkeyConfigured;
  313. if (RegOpenKeyEx(hkeyHammer, "Configured", 0, KEY_READ | KEY_WRITE, &hkeyConfigured) == ERROR_SUCCESS)
  314. {
  315. bFound = true;
  316. RegCloseKey(hkeyConfigured);
  317. }
  318. RegCloseKey(hkeyHammer);
  319. }
  320. RegCloseKey(hkeyValve);
  321. }
  322. RegCloseKey(hkeySoftware);
  323. }
  324. return bFound;
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Purpose: Looks for the Valve Hammer Editor registry settings and returns whether
  328. // they were found.
  329. //-----------------------------------------------------------------------------
  330. static bool ValveHammerEditorSettingsFound(void)
  331. {
  332. bool bFound = false;
  333. HKEY hkeySoftware;
  334. if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ | KEY_WRITE, &hkeySoftware) == ERROR_SUCCESS)
  335. {
  336. HKEY hkeyValve;
  337. if (RegOpenKeyEx(hkeySoftware, "Valve", 0, KEY_READ | KEY_WRITE, &hkeyValve) == ERROR_SUCCESS)
  338. {
  339. HKEY hkeyHammer;
  340. if (RegOpenKeyEx(hkeyValve, "Valve Hammer Editor", 0, KEY_READ | KEY_WRITE, &hkeyHammer) == ERROR_SUCCESS)
  341. {
  342. HKEY hkeyConfigured;
  343. if (RegOpenKeyEx(hkeyHammer, "Configured", 0, KEY_READ | KEY_WRITE, &hkeyConfigured) == ERROR_SUCCESS)
  344. {
  345. bFound = true;
  346. RegCloseKey(hkeyConfigured);
  347. }
  348. RegCloseKey(hkeyHammer);
  349. }
  350. RegCloseKey(hkeyValve);
  351. }
  352. RegCloseKey(hkeySoftware);
  353. }
  354. return bFound;
  355. }
  356. //-----------------------------------------------------------------------------
  357. // Purpose: Looks for the Worldcraft registry settings and returns whether they
  358. // were found.
  359. //-----------------------------------------------------------------------------
  360. static bool WorldcraftSettingsFound(void)
  361. {
  362. bool bFound = false;
  363. HKEY hkeySoftware;
  364. if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ | KEY_WRITE, &hkeySoftware) == ERROR_SUCCESS)
  365. {
  366. HKEY hkeyValve;
  367. if (RegOpenKeyEx(hkeySoftware, "Valve", 0, KEY_READ | KEY_WRITE, &hkeyValve) == ERROR_SUCCESS)
  368. {
  369. HKEY hkeyWorldcraft;
  370. if (RegOpenKeyEx(hkeyValve, "Worldcraft", 0, KEY_READ | KEY_WRITE, &hkeyWorldcraft) == ERROR_SUCCESS)
  371. {
  372. bFound = true;
  373. RegCloseKey(hkeyWorldcraft);
  374. }
  375. RegCloseKey(hkeyValve);
  376. }
  377. RegCloseKey(hkeySoftware);
  378. }
  379. return bFound;
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose:
  383. //-----------------------------------------------------------------------------
  384. bool COptions::Init(void)
  385. {
  386. //
  387. // If the we have no registry settings and the "Valve Hammer Editor" registry tree exists,
  388. // import settings from there. If that isn't found, try "Worldcraft".
  389. //
  390. bool bWCSettingsFound = false;
  391. bool bVHESettingsFound = false;
  392. if (!HammerSettingsFound())
  393. {
  394. bVHESettingsFound = ValveHammerEditorSettingsFound();
  395. if (!bVHESettingsFound)
  396. {
  397. bWCSettingsFound = WorldcraftSettingsFound();
  398. }
  399. }
  400. if (bVHESettingsFound)
  401. {
  402. APP()->BeginImportVHESettings();
  403. }
  404. else if (bWCSettingsFound)
  405. {
  406. APP()->BeginImportWCSettings();
  407. }
  408. SetDefaults();
  409. if (!Read())
  410. {
  411. return false;
  412. }
  413. if (bVHESettingsFound || bWCSettingsFound)
  414. {
  415. APP()->EndImportSettings();
  416. }
  417. //
  418. // Notify appropriate windows of new settings.
  419. // dvs: is all this necessary?
  420. //
  421. CMainFrame *pMainWnd = GetMainWnd();
  422. if (pMainWnd != NULL)
  423. {
  424. pMainWnd->SetBrightness(textures.fBrightness);
  425. pMainWnd->UpdateAllDocViews( MAPVIEW_OPTIONS_CHANGED );
  426. // FIXME: can't do this before the filesystem is initialized
  427. //pMainWnd->GlobalNotify(WM_GAME_CHANGED);
  428. }
  429. return true;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose: Enables or disables texture locking.
  433. // Input : b - TRUE to enable texture locking, FALSE to disable.
  434. // Output : Returns the previous value of the texture locking flag.
  435. //-----------------------------------------------------------------------------
  436. BOOL COptions::SetLockingTextures(BOOL b)
  437. {
  438. BOOL bOld = general.bLockingTextures;
  439. general.bLockingTextures = b;
  440. return(bOld);
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose: Returns TRUE if texture locking is enabled, FALSE if not.
  444. //-----------------------------------------------------------------------------
  445. BOOL COptions::IsLockingTextures(void)
  446. {
  447. return(general.bLockingTextures);
  448. }
  449. BOOL COptions::SetScaleLockingTextures(BOOL b)
  450. {
  451. BOOL bOld = general.bScaleLockingTextures;
  452. general.bScaleLockingTextures = b;
  453. return(bOld);
  454. }
  455. BOOL COptions::IsScaleLockingTextures(void)
  456. {
  457. return general.bScaleLockingTextures;
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Purpose: Returns whether new faces should be world aligned or face aligned.
  461. //-----------------------------------------------------------------------------
  462. TextureAlignment_t COptions::GetTextureAlignment(void)
  463. {
  464. return(general.eTextureAlignment);
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose: Sets whether new faces should be world aligned or face aligned.
  468. // Input : eTextureAlignment - TEXTURE_ALIGN_WORLD or TEXTURE_ALIGN_FACE.
  469. // Output : Returns the old setting for texture alignment.
  470. //-----------------------------------------------------------------------------
  471. TextureAlignment_t COptions::SetTextureAlignment(TextureAlignment_t eTextureAlignment)
  472. {
  473. TextureAlignment_t eOld = general.eTextureAlignment;
  474. general.eTextureAlignment = eTextureAlignment;
  475. return(eOld);
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: Returns whether helpers should be hidden or shown.
  479. //-----------------------------------------------------------------------------
  480. bool COptions::GetShowHelpers(void)
  481. {
  482. return (general.bShowHelpers == TRUE);
  483. }
  484. bool COptions::IsVGUIModelBrowserEnabled()
  485. {
  486. return (general.bUseVGUIModelBrowser == TRUE);
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose: Sets whether helpers should be hidden or shown.
  490. //-----------------------------------------------------------------------------
  491. void COptions::SetShowHelpers(bool bShow)
  492. {
  493. general.bShowHelpers = bShow ? TRUE : FALSE;
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Purpose: Loads the application configuration settings.
  497. // Output : Returns TRUE on success, FALSE on failure.
  498. //-----------------------------------------------------------------------------
  499. bool COptions::Read(void)
  500. {
  501. if (!APP()->GetProfileInt("Configured", "Configured", 0))
  502. {
  503. return false;
  504. }
  505. DWORD dwTime = APP()->GetProfileInt("Configured", "Installed", time(NULL));
  506. CTimeSpan ts(time(NULL) - dwTime);
  507. uDaysSinceInstalled = ts.GetDays();
  508. int i, iSize;
  509. CString str;
  510. // read texture info - it's stored in the general section from
  511. // an old version, but this doesn't matter much.
  512. iSize = APP()->GetProfileInt(pszGeneral, "TextureFileCount", 0);
  513. if(iSize)
  514. {
  515. // make sure default is removed
  516. textures.nTextureFiles = 0;
  517. textures.TextureFiles.RemoveAll();
  518. // read texture file names
  519. for(i = 0; i < iSize; i++)
  520. {
  521. str.Format("TextureFile%d", i);
  522. str = APP()->GetProfileString(pszGeneral, str);
  523. if(GetFileAttributes(str) == 0xffffffff)
  524. {
  525. // can't find
  526. continue;
  527. }
  528. textures.TextureFiles.Add(str);
  529. textures.nTextureFiles++;
  530. }
  531. }
  532. else
  533. {
  534. // SetDefaults() added 'textures.wad' to the list
  535. }
  536. textures.fBrightness = float(APP()->GetProfileInt(pszGeneral, "Brightness", 10)) / 10.0;
  537. // load general info
  538. general.nMaxCameras = APP()->GetProfileInt(pszGeneral, "Max Cameras", 100);
  539. general.iUndoLevels = APP()->GetProfileInt(pszGeneral, "Undo Levels", 50);
  540. general.bLockingTextures = APP()->GetProfileInt(pszGeneral, "Locking Textures", TRUE);
  541. general.bScaleLockingTextures = APP()->GetProfileInt(pszGeneral, "Scale Locking Textures", FALSE);
  542. general.eTextureAlignment = (TextureAlignment_t)APP()->GetProfileInt(pszGeneral, "Texture Alignment", TEXTURE_ALIGN_WORLD);
  543. general.bLoadwinpos = APP()->GetProfileInt(pszGeneral, "Load Default Positions", TRUE);
  544. general.bIndependentwin = APP()->GetProfileInt(pszGeneral, "Independent Windows", FALSE);
  545. general.bGroupWhileIgnore = APP()->GetProfileInt(pszGeneral, "GroupWhileIgnore", FALSE);
  546. general.bStretchArches = APP()->GetProfileInt(pszGeneral, "StretchArches", TRUE);
  547. general.bShowHelpers = APP()->GetProfileInt(pszGeneral, "Show Helpers", TRUE);
  548. general.bCheckVisibleMapErrors = APP()->GetProfileInt(pszGeneral, "Visible Map Errors", FALSE);
  549. general.iTimeBetweenSaves = APP()->GetProfileInt(pszGeneral, "Time Between Saves", 15);
  550. general.iMaxAutosaveSpace = APP()->GetProfileInt(pszGeneral, "Max Autosave Space", 100);
  551. general.iMaxAutosavesPerMap = APP()->GetProfileInt(pszGeneral, "Max Saves Per Map", 5);
  552. general.bEnableAutosave = APP()->GetProfileInt(pszGeneral, "Autosaves Enabled", 1);
  553. general.bClosedCorrectly = APP()->GetProfileInt(pszGeneral, "Closed Correctly", TRUE);
  554. general.bUseVGUIModelBrowser = APP()->GetProfileInt(pszGeneral, "VGUI Model Browser", TRUE);
  555. general.bShowHiddenTargetsAsBroken = APP()->GetProfileInt(pszGeneral, "Show Hidden Targets As Broken", TRUE);
  556. general.bRadiusCulling = APP()->GetProfileInt(pszGeneral, "Use Radius Culling", FALSE);
  557. char szDefaultAutosavePath[MAX_PATH];
  558. V_strcpy_safe( szDefaultAutosavePath, APP()->GetProfileString( pszGeneral, "Directory", "C:" ) );
  559. V_strcpy_safe( szDefaultAutosavePath, "\\HammerAutosave\\" );
  560. strcpy( general.szAutosaveDir, APP()->GetProfileString("General", "Autosave Dir", szDefaultAutosavePath));
  561. if ( Q_strlen( general.szAutosaveDir ) == 0 )
  562. {
  563. strcpy( general.szAutosaveDir, szDefaultAutosavePath );
  564. }
  565. APP()->SetDirectory( DIR_AUTOSAVE, general.szAutosaveDir );
  566. // read view2d
  567. view2d.bCrosshairs = APP()->GetProfileInt(pszView2D, "Crosshairs", FALSE);
  568. view2d.bGroupCarve = APP()->GetProfileInt(pszView2D, "GroupCarve", TRUE);
  569. view2d.bScrollbars = APP()->GetProfileInt(pszView2D, "Scrollbars", TRUE);
  570. view2d.bRotateConstrain = APP()->GetProfileInt(pszView2D, "RotateConstrain", FALSE);
  571. view2d.bDrawVertices = APP()->GetProfileInt(pszView2D, "Draw Vertices", TRUE);
  572. view2d.bDrawModels = APP()->GetProfileInt(pszView2D, "Draw Models", TRUE);
  573. view2d.bWhiteOnBlack = APP()->GetProfileInt(pszView2D, "WhiteOnBlack", TRUE);
  574. view2d.bGridHigh1024 = APP()->GetProfileInt(pszView2D, "GridHigh1024", TRUE);
  575. view2d.bGridHigh10 = APP()->GetProfileInt(pszView2D, "GridHigh10", TRUE);
  576. view2d.bHideSmallGrid = APP()->GetProfileInt(pszView2D, "HideSmallGrid", TRUE);
  577. view2d.bNudge = APP()->GetProfileInt(pszView2D, "Nudge", FALSE);
  578. view2d.bOrientPrimitives = APP()->GetProfileInt(pszView2D, "OrientPrimitives", FALSE);
  579. view2d.bAutoSelect = APP()->GetProfileInt(pszView2D, "AutoSelect", FALSE);
  580. view2d.bSelectbyhandles = APP()->GetProfileInt(pszView2D, "SelectByHandles", FALSE);
  581. view2d.iGridIntensity = APP()->GetProfileInt(pszView2D, "GridIntensity", 30);
  582. view2d.iDefaultGrid = APP()->GetProfileInt(pszView2D, "Default Grid", 64);
  583. view2d.iGridHighSpec = APP()->GetProfileInt(pszView2D, "GridHighSpec", 8);
  584. view2d.bKeepclonegroup = APP()->GetProfileInt(pszView2D, "Keepclonegroup", TRUE);
  585. view2d.bGridHigh64 = APP()->GetProfileInt(pszView2D, "Gridhigh64", TRUE);
  586. view2d.bGridDots = APP()->GetProfileInt(pszView2D, "GridDots", FALSE);
  587. view2d.bCenteroncamera = APP()->GetProfileInt(pszView2D, "Centeroncamera", FALSE);
  588. view2d.bUsegroupcolors = APP()->GetProfileInt(pszView2D, "Usegroupcolors", TRUE);
  589. // read view3d
  590. view3d.bHardware = APP()->GetProfileInt(pszView3D, "Hardware", FALSE);
  591. view3d.bReverseY = APP()->GetProfileInt(pszView3D, "Reverse Y", TRUE);
  592. view3d.iBackPlane = APP()->GetProfileInt(pszView3D, "BackPlane", 5000);
  593. view3d.bUseMouseLook = APP()->GetProfileInt(pszView3D, "UseMouseLook", TRUE);
  594. view3d.nModelDistance = APP()->GetProfileInt(pszView3D, "ModelDistance", 400);
  595. view3d.nDetailDistance = APP()->GetProfileInt(pszView3D, "DetailDistance", 1200);
  596. view3d.bAnimateModels = APP()->GetProfileInt(pszView3D, "AnimateModels", FALSE);
  597. view3d.nForwardSpeedMax = APP()->GetProfileInt(pszView3D, "ForwardSpeedMax", 1000);
  598. view3d.nTimeToMaxSpeed = APP()->GetProfileInt(pszView3D, "TimeToMaxSpeed", 500);
  599. view3d.bFilterTextures = APP()->GetProfileInt(pszView3D, "FilterTextures", TRUE);
  600. view3d.bReverseSelection = APP()->GetProfileInt(pszView3D, "ReverseSelection", FALSE);
  601. view3d.fFOV = 90;
  602. view3d.fLightConeLength = 10;
  603. ReadColorSettings();
  604. //
  605. // If we can't load any game configurations, pop up the options screen.
  606. //
  607. if (configs.LoadGameConfigs() == 0)
  608. {
  609. if (!RunConfigurationDialog())
  610. return false;
  611. }
  612. //
  613. // By default use the first config.
  614. //
  615. if (configs.nConfigs > 0)
  616. {
  617. g_pGameConfig = configs.Configs.GetAt(0);
  618. }
  619. return true;
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Purpose:
  623. // Output : Returns true on success, false on failure.
  624. //-----------------------------------------------------------------------------
  625. bool COptions::RunConfigurationDialog()
  626. {
  627. CString strText;
  628. strText.LoadString(IDS_NO_CONFIGS_AVAILABLE);
  629. if (MessageBox(NULL, strText, "First Time Setup", MB_ICONQUESTION | MB_YESNO) == IDYES)
  630. {
  631. APP()->OpenURL(ID_HELP_FIRST_TIME_SETUP, GetMainWnd()->GetSafeHwnd());
  632. }
  633. COptionProperties dlg("Configure Hammer");
  634. do
  635. {
  636. if (dlg.DoModal() != IDOK)
  637. {
  638. return false;
  639. }
  640. if (configs.nConfigs == 0)
  641. {
  642. MessageBox(NULL, "You must create at least one game configuration before using Hammer.", "First Time Setup", MB_ICONEXCLAMATION | MB_OK);
  643. }
  644. } while (configs.nConfigs == 0);
  645. Options.Write( TRUE, TRUE );
  646. return true;
  647. }
  648. //-----------------------------------------------------------------------------
  649. // Purpose:
  650. //-----------------------------------------------------------------------------
  651. void COptions::ReadColorSettings(void)
  652. {
  653. colors.bUseCustom = (APP()->GetProfileInt(g_szColors, "UseCustom", 0) != 0);
  654. if (colors.bUseCustom)
  655. {
  656. colors.clrAxis = APP()->GetProfileColor(g_szColors, "Grid0", 0 , 100, 100);
  657. colors.bScaleAxisColor = (APP()->GetProfileInt(g_szColors, "ScaleGrid0", 0) != 0);
  658. colors.clrGrid = APP()->GetProfileColor(g_szColors, "Grid", 50 , 50, 50);
  659. colors.bScaleGridColor = (APP()->GetProfileInt(g_szColors, "ScaleGrid", 1) != 0);
  660. colors.clrGrid10 = APP()->GetProfileColor(g_szColors, "Grid10", 40 , 40, 40);
  661. colors.bScaleGrid10Color = (APP()->GetProfileInt(g_szColors, "ScaleGrid10", 1) != 0);
  662. colors.clrGrid1024 = APP()->GetProfileColor(g_szColors, "Grid1024", 40 , 40, 40);
  663. colors.bScaleGrid1024Color = (APP()->GetProfileInt(g_szColors, "ScaleGrid1024", 1) != 0);
  664. colors.clrGridDot = APP()->GetProfileColor(g_szColors, "GridDot", 128, 128, 128);
  665. colors.bScaleGridDotColor = (APP()->GetProfileInt(g_szColors, "ScaleGridDot", 1) != 0);
  666. colors.clrBrush = APP()->GetProfileColor(g_szColors, "LineColor", 0, 0, 0);
  667. colors.clrEntity = APP()->GetProfileColor(g_szColors, "Entity", 220, 30, 220);
  668. colors.clrVertex = APP()->GetProfileColor(g_szColors, "Vertex", 0, 0, 0);
  669. colors.clrBackground = APP()->GetProfileColor(g_szColors, "Background", 0, 0, 0);
  670. colors.clrToolHandle = APP()->GetProfileColor(g_szColors, "HandleColor", 0, 0, 0);
  671. colors.clrToolBlock = APP()->GetProfileColor(g_szColors, "BoxColor", 0, 0, 0);
  672. colors.clrToolSelection = APP()->GetProfileColor(g_szColors, "ToolSelect", 0, 0, 0);
  673. colors.clrToolMorph = APP()->GetProfileColor(g_szColors, "Morph", 255, 0, 0);
  674. colors.clrToolPath = APP()->GetProfileColor(g_szColors, "Path", 255, 0, 0);
  675. colors.clrSelection = APP()->GetProfileColor(g_szColors, "Selection", 220, 0, 0);
  676. colors.clrToolDrag = APP()->GetProfileColor(g_szColors, "ToolDrag", 255, 255, 0);
  677. }
  678. else
  679. {
  680. if (Options.view2d.bWhiteOnBlack)
  681. {
  682. // BLACK BACKGROUND
  683. colors.clrBackground = RGB(0, 0, 0);
  684. colors.clrGrid = RGB(255, 255, 255);
  685. colors.clrGridDot = RGB(255, 255, 255);
  686. colors.clrGrid1024 = RGB(100, 50, 5);
  687. colors.clrGrid10 = RGB(255, 255, 255);
  688. colors.clrAxis = RGB(0, 100, 100);
  689. colors.clrBrush = RGB(255, 255, 255);
  690. colors.clrVertex = RGB(255, 255, 255);
  691. colors.clrToolHandle = RGB(255, 255, 255);
  692. colors.clrToolBlock = RGB(255, 255, 255);
  693. colors.clrToolDrag = RGB(255, 255, 0);
  694. }
  695. else
  696. {
  697. // WHITE BACKGROUND
  698. colors.clrBackground = RGB(255, 255, 255);
  699. colors.clrGrid = RGB(50, 50, 50);
  700. colors.clrGridDot = RGB(40, 40, 40);
  701. colors.clrGrid1024 = RGB(200, 100, 10);
  702. colors.clrGrid10 = RGB(40, 40, 40);
  703. colors.clrAxis = RGB(0, 100, 100);
  704. colors.clrBrush = RGB(0, 0, 0);
  705. colors.clrVertex = RGB(0, 0, 0);
  706. colors.clrToolHandle = RGB(0, 0, 0);
  707. colors.clrToolBlock = RGB(0, 0, 0);
  708. colors.clrToolDrag = RGB(0, 0, 255);
  709. }
  710. colors.bScaleAxisColor = false;
  711. colors.bScaleGridColor = true;
  712. colors.bScaleGrid10Color = true;
  713. colors.bScaleGrid1024Color = false;
  714. colors.bScaleGridDotColor = true;
  715. colors.clrToolSelection = RGB(255, 255, 0);
  716. colors.clrSelection = RGB(255, 0, 0);
  717. colors.clrToolMorph = RGB(255, 0, 0);
  718. colors.clrToolPath = RGB(255, 0, 0);
  719. colors.clrEntity = RGB(220, 30, 220);
  720. colors.clrModelCollisionWireframe = RGB( 255, 255, 0 );
  721. colors.clrModelCollisionWireframeDisabled = RGB( 220, 30, 220 );
  722. }
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose:
  726. // Input : fOverwrite -
  727. //-----------------------------------------------------------------------------
  728. void COptions::Write( BOOL fOverwrite, BOOL fSaveConfigs )
  729. {
  730. APP()->WriteProfileInt("Configured", "Configured", iThisVersion);
  731. int i, iSize;
  732. CString str;
  733. // write texture info - remember, it's stored in general
  734. iSize = textures.nTextureFiles;
  735. APP()->WriteProfileInt(pszGeneral, "TextureFileCount", iSize);
  736. for(i = 0; i < iSize; i++)
  737. {
  738. str.Format("TextureFile%d", i);
  739. APP()->WriteProfileString(pszGeneral, str, textures.TextureFiles[i]);
  740. }
  741. APP()->WriteProfileInt(pszGeneral, "Brightness", int(textures.fBrightness * 10));
  742. // write general
  743. APP()->WriteProfileInt(pszGeneral, "Max Cameras", general.nMaxCameras);
  744. APP()->WriteProfileInt(pszGeneral, "Undo Levels", general.iUndoLevels);
  745. APP()->WriteProfileInt(pszGeneral, "Locking Textures", general.bLockingTextures);
  746. APP()->WriteProfileInt(pszGeneral, "Scale Locking Textures", general.bScaleLockingTextures);
  747. APP()->WriteProfileInt(pszGeneral, "Texture Alignment", general.eTextureAlignment);
  748. APP()->WriteProfileInt(pszGeneral, "Independent Windows", general.bIndependentwin);
  749. APP()->WriteProfileInt(pszGeneral, "Load Default Positions", general.bLoadwinpos);
  750. APP()->WriteProfileInt(pszGeneral, "GroupWhileIgnore", general.bGroupWhileIgnore);
  751. APP()->WriteProfileInt(pszGeneral, "StretchArches", general.bStretchArches);
  752. APP()->WriteProfileInt(pszGeneral, "Show Helpers", general.bShowHelpers);
  753. APP()->WriteProfileInt(pszGeneral, "Visible Map Errors", general.bCheckVisibleMapErrors);
  754. APP()->WriteProfileInt(pszGeneral, "Time Between Saves", general.iTimeBetweenSaves);
  755. APP()->WriteProfileInt(pszGeneral, "Max Autosave Space", general.iMaxAutosaveSpace);
  756. APP()->WriteProfileInt(pszGeneral, "Max Saves Per Map", general.iMaxAutosavesPerMap);
  757. APP()->WriteProfileInt(pszGeneral, "Autosaves Enabled", general.bEnableAutosave);
  758. APP()->WriteProfileInt(pszGeneral, "Closed Correctly", general.bClosedCorrectly);
  759. APP()->WriteProfileString(pszGeneral, "Autosave Dir", general.szAutosaveDir);
  760. APP()->SetDirectory( DIR_AUTOSAVE, general.szAutosaveDir );
  761. APP()->WriteProfileInt(pszGeneral, "VGUI Model Browser", general.bUseVGUIModelBrowser );
  762. APP()->WriteProfileInt(pszGeneral, "Show Hidden Targets As Broken", general.bShowHiddenTargetsAsBroken);
  763. APP()->WriteProfileInt(pszGeneral, "Use Radius Culling", general.bRadiusCulling);
  764. // write view2d
  765. APP()->WriteProfileInt(pszView2D, "Crosshairs", view2d.bCrosshairs);
  766. APP()->WriteProfileInt(pszView2D, "GroupCarve", view2d.bGroupCarve);
  767. APP()->WriteProfileInt(pszView2D, "Scrollbars", view2d.bScrollbars);
  768. APP()->WriteProfileInt(pszView2D, "RotateConstrain", view2d.bRotateConstrain);
  769. APP()->WriteProfileInt(pszView2D, "Draw Vertices", view2d.bDrawVertices);
  770. APP()->WriteProfileInt(pszView2D, "Draw Models", view2d.bDrawModels);
  771. APP()->WriteProfileInt(pszView2D, "Default Grid", view2d.iDefaultGrid);
  772. APP()->WriteProfileInt(pszView2D, "WhiteOnBlack", view2d.bWhiteOnBlack);
  773. APP()->WriteProfileInt(pszView2D, "GridHigh1024", view2d.bGridHigh1024);
  774. APP()->WriteProfileInt(pszView2D, "GridHigh10", view2d.bGridHigh10);
  775. APP()->WriteProfileInt(pszView2D, "GridIntensity", view2d.iGridIntensity);
  776. APP()->WriteProfileInt(pszView2D, "HideSmallGrid", view2d.bHideSmallGrid);
  777. APP()->WriteProfileInt(pszView2D, "Nudge", view2d.bNudge);
  778. APP()->WriteProfileInt(pszView2D, "OrientPrimitives", view2d.bOrientPrimitives);
  779. APP()->WriteProfileInt(pszView2D, "AutoSelect", view2d.bAutoSelect);
  780. APP()->WriteProfileInt(pszView2D, "SelectByHandles", view2d.bSelectbyhandles);
  781. APP()->WriteProfileInt(pszView2D, "GridHighSpec", view2d.iGridHighSpec);
  782. APP()->WriteProfileInt(pszView2D, "KeepCloneGroup", view2d.bKeepclonegroup);
  783. APP()->WriteProfileInt(pszView2D, "Gridhigh64", view2d.bGridHigh64);
  784. APP()->WriteProfileInt(pszView2D, "GridDots", view2d.bGridDots);
  785. APP()->WriteProfileInt(pszView2D, "Centeroncamera", view2d.bCenteroncamera);
  786. APP()->WriteProfileInt(pszView2D, "Usegroupcolors", view2d.bUsegroupcolors);
  787. // write view3d
  788. APP()->WriteProfileInt(pszView3D, "Hardware", view3d.bHardware);
  789. APP()->WriteProfileInt(pszView3D, "Reverse Y", view3d.bReverseY);
  790. APP()->WriteProfileInt(pszView3D, "BackPlane", view3d.iBackPlane);
  791. APP()->WriteProfileInt(pszView3D, "UseMouseLook", view3d.bUseMouseLook);
  792. APP()->WriteProfileInt(pszView3D, "ModelDistance", view3d.nModelDistance);
  793. APP()->WriteProfileInt(pszView3D, "DetailDistance", view3d.nDetailDistance);
  794. APP()->WriteProfileInt(pszView3D, "AnimateModels", view3d.bAnimateModels);
  795. APP()->WriteProfileInt(pszView3D, "ForwardSpeedMax", view3d.nForwardSpeedMax);
  796. APP()->WriteProfileInt(pszView3D, "TimeToMaxSpeed", view3d.nTimeToMaxSpeed);
  797. APP()->WriteProfileInt(pszView3D, "FilterTextures", view3d.bFilterTextures);
  798. APP()->WriteProfileInt(pszView3D, "ReverseSelection", view3d.bReverseSelection);
  799. //
  800. // We don't write custom color settings because there is no GUI for them yet.
  801. //
  802. // Write out the game configurations
  803. if ( fSaveConfigs )
  804. {
  805. configs.SaveGameConfigs();
  806. }
  807. }
  808. void COptions::SetClosedCorrectly(BOOL bClosed)
  809. {
  810. APP()->WriteProfileInt( pszGeneral, "Closed Correctly", bClosed );
  811. }
  812. //-----------------------------------------------------------------------------
  813. // Purpose:
  814. //-----------------------------------------------------------------------------
  815. void COptions::SetDefaults(void)
  816. {
  817. BOOL bWrite = FALSE;
  818. if (APP()->GetProfileInt("Configured", "Configured", 0) != iThisVersion)
  819. {
  820. bWrite = TRUE;
  821. }
  822. if (APP()->GetProfileInt("Configured", "Installed", 42151) == 42151)
  823. {
  824. APP()->WriteProfileInt("Configured", "Installed", time(NULL));
  825. }
  826. uDaysSinceInstalled = 0;
  827. // textures
  828. textures.nTextureFiles = 1;
  829. textures.TextureFiles.Add("textures.wad");
  830. textures.fBrightness = 1.0;
  831. // general
  832. general.bIndependentwin = FALSE;
  833. general.bLoadwinpos = TRUE;
  834. general.iUndoLevels = 50;
  835. general.nMaxCameras = 100;
  836. general.bGroupWhileIgnore = FALSE;
  837. general.bStretchArches = TRUE;
  838. general.bLockingTextures = TRUE;
  839. general.bScaleLockingTextures = FALSE;
  840. general.bShowHelpers = TRUE;
  841. general.iTimeBetweenSaves = 15;
  842. general.iMaxAutosaveSpace = 100;
  843. general.iMaxAutosavesPerMap = 5;
  844. general.bEnableAutosave = TRUE;
  845. general.bClosedCorrectly = TRUE;
  846. general.bUseVGUIModelBrowser = TRUE;
  847. general.bShowCollisionModels = FALSE;
  848. general.bShowDetailObjects = TRUE;
  849. general.bShowNoDrawBrushes = TRUE;
  850. // view2d
  851. view2d.bCrosshairs = FALSE;
  852. view2d.bGroupCarve = TRUE;
  853. view2d.bScrollbars = TRUE;
  854. view2d.bRotateConstrain = FALSE;
  855. view2d.bDrawVertices = TRUE;
  856. view2d.bDrawModels = TRUE;
  857. view2d.iDefaultGrid = 64;
  858. view2d.bWhiteOnBlack = TRUE;
  859. view2d.bGridHigh1024 = TRUE;
  860. view2d.bGridHigh10 = TRUE;
  861. view2d.iGridIntensity = 30;
  862. view2d.bHideSmallGrid = TRUE;
  863. view2d.bNudge = FALSE;
  864. view2d.bOrientPrimitives = FALSE;
  865. view2d.bAutoSelect = FALSE;
  866. view2d.bSelectbyhandles = FALSE;
  867. view2d.iGridHighSpec = 8;
  868. view2d.bKeepclonegroup = TRUE;
  869. view2d.bGridHigh64 = FALSE;
  870. view2d.bGridDots = FALSE;
  871. view2d.bCenteroncamera = FALSE;
  872. view2d.bUsegroupcolors = TRUE;
  873. // view3d
  874. view3d.bUseMouseLook = TRUE;
  875. view3d.bHardware = FALSE;
  876. view3d.bReverseY = FALSE;
  877. view3d.iBackPlane = 5000;
  878. view3d.nModelDistance = 400;
  879. view3d.nDetailDistance = 1200;
  880. view3d.bAnimateModels = FALSE;
  881. view3d.nForwardSpeedMax = 1000;
  882. view3d.nTimeToMaxSpeed = 500;
  883. view3d.bFilterTextures = TRUE;
  884. view3d.bReverseSelection = FALSE;
  885. view3d.bPreviewModelFade = false;
  886. if ( bWrite )
  887. {
  888. Write( FALSE, FALSE );
  889. }
  890. }
  891. //-----------------------------------------------------------------------------
  892. // Purpose: This is called by the user interface itself when changes are made.
  893. // tells the COptions object to notify the parts of the interface.
  894. // Input : dwOptionsChanged - Flags indicating which options changed.
  895. //-----------------------------------------------------------------------------
  896. void COptions::PerformChanges(DWORD dwOptionsChanged)
  897. {
  898. CMainFrame *pMainWnd = GetMainWnd();
  899. if (dwOptionsChanged & secTextures)
  900. {
  901. if (pMainWnd != NULL)
  902. {
  903. pMainWnd->SetBrightness(textures.fBrightness);
  904. }
  905. }
  906. if (dwOptionsChanged & secView2D)
  907. {
  908. ReadColorSettings();
  909. if (pMainWnd != NULL)
  910. {
  911. pMainWnd->UpdateAllDocViews( MAPVIEW_UPDATE_ONLY_2D | MAPVIEW_OPTIONS_CHANGED | MAPVIEW_RENDER_NOW );
  912. }
  913. }
  914. if (dwOptionsChanged & secView3D)
  915. {
  916. if (pMainWnd != NULL)
  917. {
  918. pMainWnd->UpdateAllDocViews(MAPVIEW_UPDATE_ONLY_3D | MAPVIEW_OPTIONS_CHANGED | MAPVIEW_RENDER_NOW );
  919. }
  920. }
  921. if (dwOptionsChanged & secConfigs)
  922. {
  923. if (pMainWnd != NULL)
  924. {
  925. pMainWnd->GlobalNotify(WM_GAME_CHANGED);
  926. }
  927. }
  928. }