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.

1152 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. // CScriptObject and CDescription class definitions
  9. //
  10. #include "scriptobject.h"
  11. #include <time.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <vgui_controls/Label.h>
  15. #include "filesystem.h"
  16. #include "tier1/convar.h"
  17. #include "cdll_int.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. using namespace vgui;
  21. static char token[ 1024 ];
  22. extern IVEngineClient *engine;
  23. void StripFloatTrailingZeros(char *str)
  24. {
  25. // scan for a '.'
  26. char *period = strchr(str, '.');
  27. if (!period)
  28. return;
  29. // start at the end and scan back to the period
  30. char *end = 0;
  31. for ( end = str + strlen(str) - 1; end > period; --end )
  32. {
  33. if (*end == '0')
  34. {
  35. *end = '\0';
  36. }
  37. else
  38. {
  39. // we've hit a real value, stop truncating
  40. break;
  41. }
  42. }
  43. // if we've made it up to the period, kill that to
  44. if ( *end == '.' )
  45. {
  46. *end = '\0';
  47. }
  48. }
  49. /////////////////////
  50. objtypedesc_t objtypes[] =
  51. {
  52. { O_BOOL , "BOOL" },
  53. { O_NUMBER, "NUMBER" },
  54. { O_LIST , "LIST" },
  55. { O_STRING, "STRING" },
  56. { O_OBSOLETE , "OBSOLETE" },
  57. { O_SLIDER , "SLIDER" },
  58. { O_CATEGORY, "CATEGORY" },
  59. };
  60. mpcontrol_t::mpcontrol_t( Panel *parent, char const *panelName )
  61. : Panel( parent, panelName )
  62. {
  63. type = O_BADTYPE;
  64. pControl = NULL;
  65. pPrompt = NULL;
  66. pScrObj = NULL;
  67. next = NULL;
  68. SetPaintBackgroundEnabled( false );
  69. }
  70. void mpcontrol_t::OnSizeChanged( int wide, int tall )
  71. {
  72. int inset = 4;
  73. if ( pPrompt )
  74. {
  75. int w = wide / 2;
  76. if ( pControl )
  77. {
  78. pControl->SetBounds( w + 20, inset, w - 20, tall - 2 * inset );
  79. }
  80. pPrompt->SetBounds( 0, inset, w + 20, tall - 2 * inset );
  81. }
  82. else
  83. {
  84. if ( pControl )
  85. {
  86. pControl->SetBounds( 0, inset, wide, tall - 2 * inset );
  87. }
  88. }
  89. }
  90. CScriptListItem::CScriptListItem()
  91. {
  92. pNext = NULL;
  93. memset( szItemText, 0, 128 );
  94. memset( szValue, 0, 256 );
  95. }
  96. CScriptListItem::CScriptListItem( char const *strItem, char const *strValue )
  97. {
  98. pNext = NULL;
  99. Q_strncpy( szItemText, strItem, sizeof( szItemText ) );
  100. Q_strncpy( szValue , strValue, sizeof( szValue ) );
  101. }
  102. CScriptObject::CScriptObject( void )
  103. {
  104. type = O_BOOL;
  105. bSetInfo = false; // Prepend "Setinfo" to keyvalue pair in config?
  106. pNext = NULL;
  107. pListItems = NULL;
  108. tooltip[0] = '\0';
  109. }
  110. CScriptObject::~CScriptObject()
  111. {
  112. RemoveAndDeleteAllItems();
  113. }
  114. void CScriptObject::RemoveAndDeleteAllItems( void )
  115. {
  116. CScriptListItem *p, *n;
  117. p = pListItems;
  118. while ( p )
  119. {
  120. n = p->pNext;
  121. delete p;
  122. p = n;
  123. }
  124. pListItems = NULL;
  125. }
  126. void CScriptObject::SetCurValue( char const *strValue )
  127. {
  128. Q_strncpy( curValue, strValue, sizeof( curValue ) );
  129. fcurValue = (float)atof( curValue );
  130. if ( type == O_NUMBER || type == O_BOOL || type == O_SLIDER )
  131. {
  132. StripFloatTrailingZeros( curValue );
  133. }
  134. }
  135. void CScriptObject::AddItem( CScriptListItem *pItem )
  136. {
  137. // Link it into the end of the list;
  138. CScriptListItem *p;
  139. p = pListItems;
  140. if ( !p )
  141. {
  142. pListItems = pItem;
  143. pItem->pNext = NULL;
  144. return;
  145. }
  146. while ( p )
  147. {
  148. if ( !p->pNext )
  149. {
  150. p->pNext = pItem;
  151. pItem->pNext = NULL;
  152. return;
  153. }
  154. p = p->pNext;
  155. }
  156. }
  157. /*
  158. ===================
  159. UTIL_StripInvalidCharacters
  160. Removes any possible formatting codes and double quote characters from the input string
  161. ===================
  162. */
  163. void UTIL_StripInvalidCharacters( char *pszInput, int maxlen )
  164. {
  165. char szOutput[4096];
  166. char *pIn, *pOut;
  167. pIn = pszInput;
  168. pOut = szOutput;
  169. *pOut = '\0';
  170. while ( *pIn )
  171. {
  172. if ( ( *pIn != '"' ) &&
  173. ( *pIn != '%' ) )
  174. {
  175. *pOut++ = *pIn;
  176. }
  177. pIn++;
  178. }
  179. *pOut = '\0';
  180. // Copy back over, in place
  181. Q_strncpy( pszInput, szOutput, maxlen );
  182. }
  183. void FixupString( char *inString, int maxlen )
  184. {
  185. char szBuffer[ 4096 ];
  186. Q_strncpy( szBuffer, inString, sizeof( szBuffer ) );
  187. UTIL_StripInvalidCharacters( szBuffer, sizeof( szBuffer ) );
  188. Q_strncpy( inString, szBuffer, maxlen );
  189. }
  190. /*
  191. ===================
  192. CleanFloat
  193. Removes any ".000" from the end of floats
  194. ===================
  195. */
  196. char * CleanFloat( float val )
  197. {
  198. static int curstring = 0;
  199. static char string[2][32];
  200. curstring = ( curstring + 1 ) % 2;
  201. Q_snprintf( string[curstring], sizeof( string[curstring] ), "%f", val );
  202. char * str = string[curstring];
  203. char * tmp = str;
  204. if ( !str || !*str || !strchr( str, '.' ) )
  205. return str;
  206. while ( *tmp )
  207. ++tmp;
  208. --tmp;
  209. while ( *tmp == '0' && tmp > str )
  210. {
  211. *tmp = 0;
  212. --tmp;
  213. }
  214. if ( *tmp == '.' )
  215. {
  216. *tmp = 0;
  217. }
  218. return str;
  219. }
  220. void CScriptObject::WriteToScriptFile( FileHandle_t fp )
  221. {
  222. if ( type == O_OBSOLETE )
  223. return;
  224. FixupString( cvarname, sizeof( cvarname ) );
  225. g_pFullFileSystem->FPrintf( fp, "\t\"%s\"\r\n", cvarname );
  226. g_pFullFileSystem->FPrintf( fp, "\t{\r\n" );
  227. CScriptListItem *pItem;
  228. FixupString( prompt, sizeof( prompt ) );
  229. FixupString( tooltip, sizeof( tooltip ) );
  230. switch ( type )
  231. {
  232. case O_BOOL:
  233. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  234. if ( tooltip && tooltip[0] )
  235. {
  236. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  237. }
  238. g_pFullFileSystem->FPrintf( fp, "\t\t{ BOOL }\r\n" );
  239. g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%i\" }\r\n", (int)fcurValue ? 1 : 0 );
  240. break;
  241. case O_NUMBER:
  242. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  243. if ( tooltip && tooltip[0] )
  244. {
  245. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  246. }
  247. g_pFullFileSystem->FPrintf( fp, "\t\t{ NUMBER %s %s }\r\n", CleanFloat(fMin), CleanFloat(fMax) );
  248. g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
  249. break;
  250. case O_STRING:
  251. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  252. if ( tooltip && tooltip[0] )
  253. {
  254. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  255. }
  256. g_pFullFileSystem->FPrintf( fp, "\t\t{ STRING }\r\n" );
  257. FixupString( curValue, sizeof( curValue ) );
  258. g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", curValue );
  259. break;
  260. case O_LIST:
  261. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  262. if ( tooltip && tooltip[0] )
  263. {
  264. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  265. }
  266. g_pFullFileSystem->FPrintf( fp, "\t\t{\r\n\t\t\tLIST\r\n" );
  267. pItem = pListItems;
  268. while ( pItem )
  269. {
  270. UTIL_StripInvalidCharacters( pItem->szItemText, sizeof( pItem->szItemText ) );
  271. UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) );
  272. g_pFullFileSystem->FPrintf( fp, "\t\t\t\"%s\" \"%s\"\r\n",
  273. pItem->szItemText, pItem->szValue );
  274. pItem = pItem->pNext;
  275. }
  276. g_pFullFileSystem->FPrintf( fp, "\t\t}\r\n");
  277. g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
  278. break;
  279. case O_SLIDER:
  280. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  281. if ( tooltip && tooltip[0] )
  282. {
  283. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  284. }
  285. g_pFullFileSystem->FPrintf( fp, "\t\t{ SLIDER %s %s }\r\n", CleanFloat(fMin), CleanFloat(fMax) );
  286. g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
  287. break;
  288. case O_CATEGORY:
  289. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
  290. if ( tooltip && tooltip[0] )
  291. {
  292. g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
  293. }
  294. g_pFullFileSystem->FPrintf( fp, "\t\t{ CATEGORY }\r\n" );
  295. break;
  296. }
  297. if ( bSetInfo )
  298. g_pFullFileSystem->FPrintf( fp, "\t\tSetInfo\r\n" );
  299. g_pFullFileSystem->FPrintf( fp, "\t}\r\n\r\n" );
  300. }
  301. void CScriptObject::WriteToFile( FileHandle_t fp )
  302. {
  303. if ( type == O_OBSOLETE || type == O_CATEGORY )
  304. return;
  305. FixupString( cvarname, sizeof( cvarname ) );
  306. g_pFullFileSystem->FPrintf( fp, "\"%s\"\t\t", cvarname );
  307. CScriptListItem *pItem;
  308. float fVal;
  309. switch ( type )
  310. {
  311. case O_BOOL:
  312. g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", fcurValue != 0.0 ? "1" : "0" );
  313. break;
  314. case O_NUMBER:
  315. case O_SLIDER:
  316. fVal = fcurValue;
  317. if ( fMin != -1.0 )
  318. fVal = max( fVal, fMin );
  319. if ( fMax != -1.0 )
  320. fVal = min( fVal, fMax );
  321. g_pFullFileSystem->FPrintf( fp, "\"%f\"\r\n", fVal );
  322. break;
  323. case O_STRING:
  324. FixupString( curValue, sizeof( curValue ) );
  325. g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", curValue );
  326. break;
  327. case O_LIST:
  328. pItem = pListItems;
  329. while ( pItem )
  330. {
  331. if ( !Q_stricmp( pItem->szValue, curValue ) )
  332. break;
  333. pItem = pItem->pNext;
  334. }
  335. if ( pItem )
  336. {
  337. UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) );
  338. g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", pItem->szValue );
  339. }
  340. else //Couln't find index
  341. {
  342. g_pFullFileSystem->FPrintf( fp, "\"0\"\r\n" );
  343. }
  344. break;
  345. }
  346. }
  347. void CScriptObject::WriteToConfig( void )
  348. {
  349. if ( type == O_OBSOLETE || type == O_CATEGORY )
  350. return;
  351. char *pszKey;
  352. char szValue[2048];
  353. pszKey = ( char * )cvarname;
  354. CScriptListItem *pItem;
  355. float fVal;
  356. switch ( type )
  357. {
  358. case O_BOOL:
  359. Q_snprintf( szValue, sizeof( szValue ), "%s", fcurValue != 0.0 ? "1" : "0" );
  360. break;
  361. case O_NUMBER:
  362. case O_SLIDER:
  363. fVal = fcurValue;
  364. if ( fMin != -1.0 )
  365. fVal = max( fVal, fMin );
  366. if ( fMax != -1.0 )
  367. fVal = min( fVal, fMax );
  368. Q_snprintf( szValue, sizeof( szValue ), "%f", fVal );
  369. break;
  370. case O_STRING:
  371. Q_snprintf( szValue, sizeof( szValue ), "\"%s\"", (char *)curValue );
  372. UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) );
  373. break;
  374. case O_LIST:
  375. pItem = pListItems;
  376. while ( pItem )
  377. {
  378. if ( !Q_stricmp( pItem->szValue, curValue ) )
  379. break;
  380. pItem = pItem->pNext;
  381. }
  382. if ( pItem )
  383. {
  384. Q_snprintf( szValue, sizeof( szValue ), "%s", pItem->szValue );
  385. UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) );
  386. }
  387. else //Couldn't find index
  388. {
  389. Q_strncpy( szValue, "0", sizeof( szValue ) );
  390. }
  391. break;
  392. }
  393. char command[ 256 ];
  394. if ( bSetInfo )
  395. {
  396. Q_snprintf( command, sizeof(command), "setinfo %s \"%s\"\n", pszKey, szValue );
  397. }
  398. else
  399. {
  400. Q_snprintf( command, sizeof(command), "%s \"%s\"\n", pszKey, szValue );
  401. }
  402. engine->ClientCmd_Unrestricted( command );
  403. // CFG_SetKey( g_szCurrentConfigFile, pszKey, szValue, bSetInfo );
  404. }
  405. objtype_t CScriptObject::GetType( char *pszType )
  406. {
  407. int i;
  408. int nTypes;
  409. nTypes = sizeof( objtypes ) / sizeof( objtypedesc_t);
  410. for ( i = 0; i < nTypes; i++ )
  411. {
  412. if ( !stricmp( objtypes[i].szDescription, pszType ) )
  413. return objtypes[i].type;
  414. }
  415. return O_BADTYPE;
  416. }
  417. bool CScriptObject::ReadFromBuffer( const char **pBuffer, bool isNewObject )
  418. {
  419. // Get the first token.
  420. // The cvar we are setting
  421. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  422. if ( strlen( token ) <= 0 )
  423. return false;
  424. if ( isNewObject )
  425. {
  426. Q_strncpy( cvarname, token, sizeof( cvarname ) );
  427. }
  428. // Parse the {
  429. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  430. if ( strlen( token ) <= 0 )
  431. return false;
  432. if ( strcmp( token, "{" ) )
  433. {
  434. Msg( "Expecting '{', got '%s'", token );
  435. return false;
  436. }
  437. // Parse the Prompt
  438. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  439. if ( strlen( token ) <= 0 )
  440. return false;
  441. if ( isNewObject )
  442. {
  443. Q_strncpy( prompt, token, sizeof( prompt ) );
  444. }
  445. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  446. if ( strlen( token ) <= 0 )
  447. return false;
  448. // If it's not a {, consider it the optional tooltip
  449. if ( strcmp( token, "{" ) )
  450. {
  451. Q_strncpy( tooltip, token, sizeof( tooltip ) );
  452. // Parse the next {
  453. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  454. if ( strlen( token ) <= 0 )
  455. return false;
  456. }
  457. if ( strcmp( token, "{" ) )
  458. {
  459. Msg( "Expecting '{', got '%s'", token );
  460. return false;
  461. }
  462. // Now parse the type:
  463. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  464. if ( strlen( token ) <= 0 )
  465. return false;
  466. objtype_t newType = GetType( token );
  467. if ( isNewObject )
  468. {
  469. type = newType;
  470. }
  471. if ( newType == O_BADTYPE )
  472. {
  473. Msg( "Type '%s' unknown", token );
  474. return false;
  475. }
  476. // If it's a category, we're done.
  477. if ( newType == O_CATEGORY )
  478. {
  479. // Parse the }
  480. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  481. if ( strlen( token ) <= 0 )
  482. return false;
  483. if ( strcmp( token, "}" ) )
  484. {
  485. Msg( "Expecting '{', got '%s'", token );
  486. return false;
  487. }
  488. // Parse the final }
  489. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  490. if ( strlen( token ) <= 0 )
  491. return false;
  492. if ( strcmp( token, "}" ) )
  493. {
  494. Msg( "Expecting '{', got '%s'", token );
  495. return false;
  496. }
  497. return true;
  498. }
  499. switch ( newType )
  500. {
  501. case O_OBSOLETE:
  502. case O_BOOL:
  503. // Parse the next {
  504. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  505. if ( strlen( token ) <= 0 )
  506. return false;
  507. if ( strcmp( token, "}" ) )
  508. {
  509. Msg( "Expecting '{', got '%s'", token );
  510. return false;
  511. }
  512. break;
  513. case O_NUMBER:
  514. case O_SLIDER:
  515. // Parse the Min
  516. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  517. if ( strlen( token ) <= 0 )
  518. return false;
  519. if ( isNewObject )
  520. {
  521. fMin = (float)atof( token );
  522. }
  523. // Parse the Min
  524. *pBuffer = engine->ParseFile( *pBuffer, token , sizeof( token ));
  525. if ( strlen( token ) <= 0 )
  526. return false;
  527. if ( isNewObject )
  528. {
  529. fMax = (float)atof( token );
  530. }
  531. // Parse the next {
  532. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  533. if ( strlen( token ) <= 0 )
  534. return false;
  535. if ( strcmp( token, "}" ) )
  536. {
  537. Msg( "Expecting '{', got '%s'", token );
  538. return false;
  539. }
  540. break;
  541. case O_STRING:
  542. // Parse the next {
  543. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  544. if ( strlen( token ) <= 0 )
  545. return false;
  546. if ( strcmp( token, "}" ) )
  547. {
  548. Msg( "Expecting '{', got '%s'", token );
  549. return false;
  550. }
  551. break;
  552. case O_LIST:
  553. // Parse items until we get the }
  554. while ( 1 )
  555. {
  556. // Parse the next {
  557. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  558. if ( strlen( token ) <= 0 )
  559. return false;
  560. // Done?
  561. if ( !strcmp( token, "}" ) )
  562. break;
  563. //
  564. // Add the item to a list somewhere
  565. // AddItem( token )
  566. char strItem[ 128 ];
  567. char strValue[128];
  568. Q_strncpy( strItem, token, sizeof( strItem ) );
  569. // Parse the value
  570. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  571. if ( strlen( token ) <= 0 )
  572. return false;
  573. Q_strncpy( strValue, token, sizeof( strValue ) );
  574. if ( isNewObject )
  575. {
  576. CScriptListItem *pItem;
  577. pItem = new CScriptListItem( strItem, strValue );
  578. AddItem( pItem );
  579. }
  580. }
  581. break;
  582. }
  583. //
  584. // Now read in the default value
  585. // Parse the {
  586. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  587. if ( strlen( token ) <= 0 )
  588. return false;
  589. if ( strcmp( token, "{" ) )
  590. {
  591. Msg( "Expecting '{', got '%s'", token );
  592. return false;
  593. }
  594. // Parse the default
  595. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  596. //if ( strlen( token ) <= 0 )
  597. // return false;
  598. // Set the values
  599. Q_strncpy( defValue, token, sizeof( defValue ) );
  600. fdefValue = (float)atof( token );
  601. if (type == O_NUMBER || type == O_SLIDER)
  602. {
  603. StripFloatTrailingZeros( defValue );
  604. }
  605. SetCurValue( defValue );
  606. // Parse the }
  607. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  608. if ( strlen( token ) <= 0 )
  609. return false;
  610. if ( strcmp( token, "}" ) )
  611. {
  612. Msg( "Expecting '{', got '%s'", token );
  613. return false;
  614. }
  615. // Parse the final }
  616. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  617. if ( strlen( token ) <= 0 )
  618. return false;
  619. if ( !stricmp( token, "SetInfo" ) )
  620. {
  621. bSetInfo = true;
  622. // Parse the final }
  623. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  624. if ( strlen( token ) <= 0 )
  625. return false;
  626. }
  627. if ( strcmp( token, "}" ) )
  628. {
  629. Msg( "Expecting '{', got '%s'", token );
  630. return false;
  631. }
  632. return true;
  633. }
  634. /////////////////////////
  635. CDescription::CDescription( void )
  636. {
  637. pObjList = NULL;
  638. }
  639. CDescription::~CDescription()
  640. {
  641. CScriptObject *p, *n;
  642. p = pObjList;
  643. while ( p )
  644. {
  645. n = p->pNext;
  646. p->pNext = NULL;
  647. p->MarkForDeletion();
  648. //delete p;
  649. p = n;
  650. }
  651. pObjList = NULL;
  652. if ( m_pszHintText )
  653. free( m_pszHintText );
  654. if ( m_pszDescriptionType )
  655. free( m_pszDescriptionType );
  656. }
  657. CScriptObject * CDescription::FindObject( const char *pszObjectName )
  658. {
  659. if ( !pszObjectName )
  660. return NULL;
  661. CScriptObject *p;
  662. p = pObjList;
  663. while ( p )
  664. {
  665. if ( !stricmp( pszObjectName, p->cvarname ) )
  666. return p;
  667. p = p->pNext;
  668. }
  669. return NULL;
  670. }
  671. void CDescription::AddObject( CScriptObject *pObj )
  672. {
  673. CScriptObject *p;
  674. p = pObjList;
  675. if ( !p )
  676. {
  677. pObjList = pObj;
  678. pObj->pNext = NULL;
  679. return;
  680. }
  681. while ( p )
  682. {
  683. if ( !p->pNext )
  684. {
  685. p->pNext = pObj;
  686. pObj->pNext = NULL;
  687. return;
  688. }
  689. p = p->pNext;
  690. }
  691. }
  692. bool CDescription::ReadFromBuffer( const char **pBuffer, bool bAllowNewObject )
  693. {
  694. // Get the first token.
  695. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  696. if ( strlen( token ) <= 0 )
  697. return false;
  698. // Read VERSION #
  699. if ( stricmp ( token, "VERSION" ) )
  700. {
  701. Msg( "Expecting 'VERSION', got '%s'", token );
  702. return false;
  703. }
  704. // Parse in the version #
  705. // Get the first token.
  706. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  707. if ( strlen( token ) <= 0 )
  708. {
  709. Msg( "Expecting version #" );
  710. return false;
  711. }
  712. float fVer;
  713. fVer = (float)atof( token );
  714. if ( fVer != SCRIPT_VERSION )
  715. {
  716. Msg( "Version mismatch, expecting %f, got %f", SCRIPT_VERSION, fVer );
  717. return false;
  718. }
  719. // Get the "DESCRIPTION"
  720. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  721. if ( strlen( token ) <= 0 )
  722. return false;
  723. // Read DESCRIPTION
  724. if ( stricmp ( token, "DESCRIPTION" ) )
  725. {
  726. Msg( "Expecting 'DESCRIPTION', got '%s'", token );
  727. return false;
  728. }
  729. // Parse in the description type
  730. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  731. if ( strlen( token ) <= 0 )
  732. {
  733. Msg( "Expecting '%s'", m_pszDescriptionType );
  734. return false;
  735. }
  736. if ( stricmp ( token, m_pszDescriptionType ) )
  737. {
  738. Msg( "Expecting %s, got %s", m_pszDescriptionType, token );
  739. return false;
  740. }
  741. // Parse the {
  742. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  743. if ( strlen( token ) <= 0 )
  744. return false;
  745. if ( strcmp( token, "{" ) )
  746. {
  747. Msg( "Expecting '{', got '%s'", token );
  748. return false;
  749. }
  750. const char *pStart;
  751. CScriptObject *pObj;
  752. // Now read in the objects and link them in
  753. while ( 1 )
  754. {
  755. pStart = *pBuffer;
  756. // Get the first token.
  757. *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
  758. if ( strlen( token ) <= 0 )
  759. return false;
  760. // Read "cvar name" or } when done
  761. if ( !stricmp ( token, "}" ) )
  762. break;
  763. // Unget the token
  764. *pBuffer = pStart;
  765. // Create a new object
  766. bool mustAdd = bAllowNewObject;
  767. pObj = FindObject( token );
  768. if ( pObj )
  769. {
  770. pObj->ReadFromBuffer( &pStart, false );
  771. mustAdd = false; // already in list
  772. }
  773. else
  774. {
  775. pObj = new CScriptObject();
  776. if ( !pObj )
  777. {
  778. Msg( "Couldn't create script object" );
  779. return false;
  780. }
  781. if ( !pObj->ReadFromBuffer( &pStart, true ) )
  782. {
  783. delete pObj;
  784. return false;
  785. }
  786. // throw away the object if we're not adding it.
  787. if ( !mustAdd )
  788. {
  789. delete pObj;
  790. }
  791. }
  792. *pBuffer = pStart;
  793. // Add to list
  794. // Fixme, move to end of list first
  795. if ( mustAdd )
  796. {
  797. AddObject( pObj );
  798. }
  799. }
  800. return true;
  801. }
  802. bool CDescription::InitFromFile( const char *pszFileName, bool bAllowNewObject /*= true*/ )
  803. {
  804. // Load file into memory
  805. FileHandle_t file = g_pFullFileSystem->Open( pszFileName, "rb" );
  806. if ( !file )
  807. return false;
  808. int len =g_pFullFileSystem->Size( file );
  809. // read the file
  810. byte *buffer = new unsigned char[ len ];
  811. Assert( buffer );
  812. g_pFullFileSystem->Read( buffer, len, file );
  813. g_pFullFileSystem->Close( file );
  814. const char *pBuffer = (const char*)buffer;
  815. ReadFromBuffer( &pBuffer, bAllowNewObject );
  816. delete[] buffer;
  817. return true;
  818. }
  819. void CDescription::WriteToFile( FileHandle_t fp )
  820. {
  821. CScriptObject *pObj;
  822. WriteFileHeader( fp );
  823. pObj = pObjList;
  824. while ( pObj )
  825. {
  826. pObj->WriteToFile( fp );
  827. pObj = pObj->pNext;
  828. }
  829. }
  830. void CDescription::WriteToConfig( void )
  831. {
  832. CScriptObject *pObj;
  833. pObj = pObjList;
  834. while ( pObj )
  835. {
  836. pObj->WriteToConfig();
  837. pObj = pObj->pNext;
  838. }
  839. }
  840. void CDescription::WriteToScriptFile( FileHandle_t fp )
  841. {
  842. CScriptObject *pObj;
  843. WriteScriptHeader( fp );
  844. pObj = pObjList;
  845. while ( pObj )
  846. {
  847. pObj->WriteToScriptFile( fp );
  848. pObj = pObj->pNext;
  849. }
  850. g_pFullFileSystem->FPrintf( fp, "}\r\n" );
  851. }
  852. void CDescription::TransferCurrentValues( const char *pszConfigFile )
  853. {
  854. char szValue[ 1024 ];
  855. CScriptObject *pObj;
  856. pObj = pObjList;
  857. while ( pObj )
  858. {
  859. /*
  860. TODO: if/when prefixed keys are implemented
  861. const char *value;
  862. if ( pObj->bSetInfo )
  863. {
  864. value = engine->LocalPlayerInfo_ValueForKey( pObj->cvarname ); // use LocalPlayerInfo because PlayerInfo strips keys prefixed with "_"
  865. }
  866. else
  867. {
  868. value = engine->pfnGetCvarString( pObj->cvarname );
  869. }
  870. */
  871. ConVarRef var( pObj->cvarname, true );
  872. if ( !var.IsValid() )
  873. {
  874. if ( pObj->type != O_CATEGORY )
  875. {
  876. DevMsg( "Could not find '%s'\n", pObj->cvarname );
  877. }
  878. pObj = pObj->pNext;
  879. continue;
  880. }
  881. const char *value = var.GetString();
  882. if ( value && value[ 0 ] )
  883. //if ( CFG_GetValue( pszConfigFile, pObj->cvarname, szValue ) )
  884. {
  885. Q_strncpy( szValue, value, sizeof( szValue ) );
  886. // Fill in better default value
  887. //
  888. Q_strncpy( pObj->curValue, szValue, sizeof( pObj->curValue ) );
  889. pObj->fcurValue = (float)atof( szValue );
  890. Q_strncpy( pObj->defValue, szValue, sizeof( pObj->defValue ) );
  891. pObj->fdefValue = (float)atof( szValue );
  892. }
  893. pObj = pObj->pNext;
  894. }
  895. }
  896. void CDescription::setDescription( const char *pszDesc )
  897. {
  898. m_pszDescriptionType = strdup( pszDesc );
  899. }
  900. void CDescription::setHint( const char *pszHint )
  901. {
  902. m_pszHintText = strdup( pszHint );
  903. }
  904. //-----------------------------------------------------------------------------
  905. // Purpose: Constructor, load/save client settings object
  906. //-----------------------------------------------------------------------------
  907. CInfoDescription::CInfoDescription( void )
  908. : CDescription( )
  909. {
  910. setHint( "// NOTE: THIS FILE IS AUTOMATICALLY REGENERATED, \r\n\
  911. //DO NOT EDIT THIS HEADER, YOUR COMMENTS WILL BE LOST IF YOU DO\r\n\
  912. // User options script\r\n\
  913. //\r\n\
  914. // Format:\r\n\
  915. // Version [float]\r\n\
  916. // Options description followed by \r\n\
  917. // Options defaults\r\n\
  918. //\r\n\
  919. // Option description syntax:\r\n\
  920. //\r\n\
  921. // \"cvar\" { \"Prompt\" { type [ type info ] } { default } }\r\n\
  922. //\r\n\
  923. // type = \r\n\
  924. // BOOL (a yes/no toggle)\r\n\
  925. // STRING\r\n\
  926. // NUMBER\r\n\
  927. // LIST\r\n\
  928. //\r\n\
  929. // type info:\r\n\
  930. // BOOL no type info\r\n\
  931. // NUMBER min max range, use -1 -1 for no limits\r\n\
  932. // STRING no type info\r\n\
  933. // LIST "" delimited list of options value pairs\r\n\
  934. //\r\n\
  935. //\r\n\
  936. // default depends on type\r\n\
  937. // BOOL is \"0\" or \"1\"\r\n\
  938. // NUMBER is \"value\"\r\n\
  939. // STRING is \"value\"\r\n\
  940. // LIST is \"index\", where index \"0\" is the first element of the list\r\n\r\n\r\n" );
  941. setDescription( "INFO_OPTIONS" );
  942. }
  943. //-----------------------------------------------------------------------------
  944. // Purpose:
  945. //-----------------------------------------------------------------------------
  946. void CInfoDescription::WriteScriptHeader( FileHandle_t fp )
  947. {
  948. char am_pm[] = "AM";
  949. tm newtime;
  950. VCRHook_LocalTime( &newtime );
  951. g_pFullFileSystem->FPrintf( fp, (char *)getHint() );
  952. // Write out the comment and Cvar Info:
  953. g_pFullFileSystem->FPrintf( fp, "// Half-Life User Info Configuration Layout Script (stores last settings chosen, too)\r\n" );
  954. g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
  955. g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
  956. g_pFullFileSystem->FPrintf( fp, "VERSION %.1f\r\n\r\n", SCRIPT_VERSION );
  957. g_pFullFileSystem->FPrintf( fp, "DESCRIPTION INFO_OPTIONS\r\n{\r\n" );
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Purpose:
  961. //-----------------------------------------------------------------------------
  962. void CInfoDescription::WriteFileHeader( FileHandle_t fp )
  963. {
  964. char am_pm[] = "AM";
  965. tm newtime;
  966. VCRHook_LocalTime( &newtime );
  967. g_pFullFileSystem->FPrintf( fp, "// Half-Life User Info Configuration Settings\r\n" );
  968. g_pFullFileSystem->FPrintf( fp, "// DO NOT EDIT, GENERATED BY HALF-LIFE\r\n" );
  969. g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
  970. g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
  971. }
  972. //-----------------------------------------------------------------------------