summaryrefslogtreecommitdiff
path: root/common/GameUI/scriptobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/GameUI/scriptobject.cpp')
-rw-r--r--common/GameUI/scriptobject.cpp1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/common/GameUI/scriptobject.cpp b/common/GameUI/scriptobject.cpp
new file mode 100644
index 0000000..e83f5fd
--- /dev/null
+++ b/common/GameUI/scriptobject.cpp
@@ -0,0 +1,1153 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+// CScriptObject and CDescription class definitions
+//
+#include "scriptobject.h"
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vgui_controls/Label.h>
+#include "filesystem.h"
+#include "tier1/convar.h"
+#include "cdll_int.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+static char token[ 1024 ];
+
+extern IVEngineClient *engine;
+
+void StripFloatTrailingZeros(char *str)
+{
+ // scan for a '.'
+ char *period = strchr(str, '.');
+ if (!period)
+ return;
+
+ // start at the end and scan back to the period
+ char *end = 0;
+ for ( end = str + strlen(str) - 1; end > period; --end )
+ {
+ if (*end == '0')
+ {
+ *end = '\0';
+ }
+ else
+ {
+ // we've hit a real value, stop truncating
+ break;
+ }
+ }
+
+ // if we've made it up to the period, kill that to
+ if ( *end == '.' )
+ {
+ *end = '\0';
+ }
+}
+
+/////////////////////
+objtypedesc_t objtypes[] =
+{
+ { O_BOOL , "BOOL" },
+ { O_NUMBER, "NUMBER" },
+ { O_LIST , "LIST" },
+ { O_STRING, "STRING" },
+ { O_OBSOLETE , "OBSOLETE" },
+ { O_SLIDER , "SLIDER" },
+ { O_CATEGORY, "CATEGORY" },
+};
+
+mpcontrol_t::mpcontrol_t( Panel *parent, char const *panelName )
+: Panel( parent, panelName )
+{
+ type = O_BADTYPE;
+ pControl = NULL;
+ pPrompt = NULL;
+ pScrObj = NULL;
+
+ next = NULL;
+
+ SetPaintBackgroundEnabled( false );
+}
+
+void mpcontrol_t::OnSizeChanged( int wide, int tall )
+{
+ int inset = 4;
+
+ if ( pPrompt )
+ {
+ int w = wide / 2;
+
+ if ( pControl )
+ {
+ pControl->SetBounds( w + 20, inset, w - 20, tall - 2 * inset );
+ }
+ pPrompt->SetBounds( 0, inset, w + 20, tall - 2 * inset );
+ }
+ else
+ {
+ if ( pControl )
+ {
+ pControl->SetBounds( 0, inset, wide, tall - 2 * inset );
+ }
+ }
+}
+
+CScriptListItem::CScriptListItem()
+{
+ pNext = NULL;
+ memset( szItemText, 0, 128 );
+ memset( szValue, 0, 256 );
+}
+
+CScriptListItem::CScriptListItem( char const *strItem, char const *strValue )
+{
+ pNext = NULL;
+ Q_strncpy( szItemText, strItem, sizeof( szItemText ) );
+ Q_strncpy( szValue , strValue, sizeof( szValue ) );
+}
+
+CScriptObject::CScriptObject( void )
+{
+ type = O_BOOL;
+ bSetInfo = false; // Prepend "Setinfo" to keyvalue pair in config?
+ pNext = NULL;
+ pListItems = NULL;
+ tooltip[0] = '\0';
+}
+
+CScriptObject::~CScriptObject()
+{
+ RemoveAndDeleteAllItems();
+}
+
+void CScriptObject::RemoveAndDeleteAllItems( void )
+{
+ CScriptListItem *p, *n;
+
+ p = pListItems;
+ while ( p )
+ {
+ n = p->pNext;
+ delete p;
+ p = n;
+ }
+ pListItems = NULL;
+}
+
+void CScriptObject::SetCurValue( char const *strValue )
+{
+ Q_strncpy( curValue, strValue, sizeof( curValue ) );
+
+ fcurValue = (float)atof( curValue );
+
+ if ( type == O_NUMBER || type == O_BOOL || type == O_SLIDER )
+ {
+ StripFloatTrailingZeros( curValue );
+ }
+}
+
+void CScriptObject::AddItem( CScriptListItem *pItem )
+{
+ // Link it into the end of the list;
+ CScriptListItem *p;
+ p = pListItems;
+ if ( !p )
+ {
+ pListItems = pItem;
+ pItem->pNext = NULL;
+ return;
+ }
+
+ while ( p )
+ {
+ if ( !p->pNext )
+ {
+ p->pNext = pItem;
+ pItem->pNext = NULL;
+ return;
+ }
+ p = p->pNext;
+ }
+}
+
+/*
+===================
+UTIL_StripInvalidCharacters
+
+Removes any possible formatting codes and double quote characters from the input string
+===================
+*/
+void UTIL_StripInvalidCharacters( char *pszInput, int maxlen )
+{
+ char szOutput[4096];
+ char *pIn, *pOut;
+
+ pIn = pszInput;
+ pOut = szOutput;
+
+ *pOut = '\0';
+
+ while ( *pIn )
+ {
+ if ( ( *pIn != '"' ) &&
+ ( *pIn != '%' ) )
+ {
+ *pOut++ = *pIn;
+ }
+ pIn++;
+ }
+
+ *pOut = '\0';
+
+ // Copy back over, in place
+ Q_strncpy( pszInput, szOutput, maxlen );
+}
+
+void FixupString( char *inString, int maxlen )
+{
+ char szBuffer[ 4096 ];
+ Q_strncpy( szBuffer, inString, sizeof( szBuffer ) );
+ UTIL_StripInvalidCharacters( szBuffer, sizeof( szBuffer ) );
+ Q_strncpy( inString, szBuffer, maxlen );
+}
+
+/*
+===================
+CleanFloat
+
+Removes any ".000" from the end of floats
+===================
+*/
+char * CleanFloat( float val )
+{
+ static int curstring = 0;
+ static char string[2][32];
+ curstring = ( curstring + 1 ) % 2;
+
+ Q_snprintf( string[curstring], sizeof( string[curstring] ), "%f", val );
+
+ char * str = string[curstring];
+
+ char * tmp = str;
+ if ( !str || !*str || !strchr( str, '.' ) )
+ return str;
+
+ while ( *tmp )
+ ++tmp;
+ --tmp;
+
+ while ( *tmp == '0' && tmp > str )
+ {
+ *tmp = 0;
+ --tmp;
+ }
+
+ if ( *tmp == '.' )
+ {
+ *tmp = 0;
+ }
+
+ return str;
+}
+
+void CScriptObject::WriteToScriptFile( FileHandle_t fp )
+{
+ if ( type == O_OBSOLETE )
+ return;
+
+ FixupString( cvarname, sizeof( cvarname ) );
+ g_pFullFileSystem->FPrintf( fp, "\t\"%s\"\r\n", cvarname );
+
+ g_pFullFileSystem->FPrintf( fp, "\t{\r\n" );
+
+ CScriptListItem *pItem;
+
+ FixupString( prompt, sizeof( prompt ) );
+ FixupString( tooltip, sizeof( tooltip ) );
+
+ switch ( type )
+ {
+ case O_BOOL:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ BOOL }\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%i\" }\r\n", (int)fcurValue ? 1 : 0 );
+ break;
+ case O_NUMBER:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ NUMBER %s %s }\r\n", CleanFloat(fMin), CleanFloat(fMax) );
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
+ break;
+ case O_STRING:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ STRING }\r\n" );
+ FixupString( curValue, sizeof( curValue ) );
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", curValue );
+ break;
+ case O_LIST:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{\r\n\t\t\tLIST\r\n" );
+
+ pItem = pListItems;
+ while ( pItem )
+ {
+ UTIL_StripInvalidCharacters( pItem->szItemText, sizeof( pItem->szItemText ) );
+ UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) );
+ g_pFullFileSystem->FPrintf( fp, "\t\t\t\"%s\" \"%s\"\r\n",
+ pItem->szItemText, pItem->szValue );
+
+ pItem = pItem->pNext;
+ }
+
+ g_pFullFileSystem->FPrintf( fp, "\t\t}\r\n");
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
+ break;
+ case O_SLIDER:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ SLIDER %s %s }\r\n", CleanFloat(fMin), CleanFloat(fMax) );
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) );
+ break;
+ case O_CATEGORY:
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt );
+ if ( tooltip && tooltip[0] )
+ {
+ g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", tooltip );
+ }
+ g_pFullFileSystem->FPrintf( fp, "\t\t{ CATEGORY }\r\n" );
+ break;
+ }
+
+ if ( bSetInfo )
+ g_pFullFileSystem->FPrintf( fp, "\t\tSetInfo\r\n" );
+
+ g_pFullFileSystem->FPrintf( fp, "\t}\r\n\r\n" );
+}
+
+void CScriptObject::WriteToFile( FileHandle_t fp )
+{
+ if ( type == O_OBSOLETE || type == O_CATEGORY )
+ return;
+
+ FixupString( cvarname, sizeof( cvarname ) );
+ g_pFullFileSystem->FPrintf( fp, "\"%s\"\t\t", cvarname );
+
+ CScriptListItem *pItem;
+ float fVal;
+
+ switch ( type )
+ {
+ case O_BOOL:
+ g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", fcurValue != 0.0 ? "1" : "0" );
+ break;
+ case O_NUMBER:
+ case O_SLIDER:
+ fVal = fcurValue;
+ if ( fMin != -1.0 )
+ fVal = max( fVal, fMin );
+ if ( fMax != -1.0 )
+ fVal = min( fVal, fMax );
+ g_pFullFileSystem->FPrintf( fp, "\"%f\"\r\n", fVal );
+ break;
+ case O_STRING:
+ FixupString( curValue, sizeof( curValue ) );
+ g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", curValue );
+ break;
+ case O_LIST:
+ pItem = pListItems;
+ while ( pItem )
+ {
+ if ( !Q_stricmp( pItem->szValue, curValue ) )
+ break;
+
+ pItem = pItem->pNext;
+ }
+
+ if ( pItem )
+ {
+ UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) );
+ g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", pItem->szValue );
+ }
+ else //Couln't find index
+ {
+ g_pFullFileSystem->FPrintf( fp, "\"0\"\r\n" );
+ }
+ break;
+ }
+}
+
+void CScriptObject::WriteToConfig( void )
+{
+ if ( type == O_OBSOLETE || type == O_CATEGORY )
+ return;
+
+ char *pszKey;
+ char szValue[2048];
+
+ pszKey = ( char * )cvarname;
+
+ CScriptListItem *pItem;
+ float fVal;
+
+ switch ( type )
+ {
+ case O_BOOL:
+ Q_snprintf( szValue, sizeof( szValue ), "%s", fcurValue != 0.0 ? "1" : "0" );
+ break;
+ case O_NUMBER:
+ case O_SLIDER:
+ fVal = fcurValue;
+ if ( fMin != -1.0 )
+ fVal = max( fVal, fMin );
+ if ( fMax != -1.0 )
+ fVal = min( fVal, fMax );
+ Q_snprintf( szValue, sizeof( szValue ), "%f", fVal );
+ break;
+ case O_STRING:
+ Q_snprintf( szValue, sizeof( szValue ), "\"%s\"", (char *)curValue );
+ UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) );
+ break;
+ case O_LIST:
+ pItem = pListItems;
+ while ( pItem )
+ {
+ if ( !Q_stricmp( pItem->szValue, curValue ) )
+ break;
+
+ pItem = pItem->pNext;
+ }
+
+ if ( pItem )
+ {
+ Q_snprintf( szValue, sizeof( szValue ), "%s", pItem->szValue );
+ UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) );
+ }
+ else //Couldn't find index
+ {
+ Q_strncpy( szValue, "0", sizeof( szValue ) );
+ }
+ break;
+ }
+
+ char command[ 256 ];
+ if ( bSetInfo )
+ {
+ Q_snprintf( command, sizeof(command), "setinfo %s \"%s\"\n", pszKey, szValue );
+ }
+ else
+ {
+ Q_snprintf( command, sizeof(command), "%s \"%s\"\n", pszKey, szValue );
+ }
+
+ engine->ClientCmd_Unrestricted( command );
+
+ // CFG_SetKey( g_szCurrentConfigFile, pszKey, szValue, bSetInfo );
+}
+
+
+objtype_t CScriptObject::GetType( char *pszType )
+{
+ int i;
+ int nTypes;
+
+ nTypes = sizeof( objtypes ) / sizeof( objtypedesc_t);
+
+ for ( i = 0; i < nTypes; i++ )
+ {
+ if ( !stricmp( objtypes[i].szDescription, pszType ) )
+ return objtypes[i].type;
+ }
+
+ return O_BADTYPE;
+}
+
+bool CScriptObject::ReadFromBuffer( const char **pBuffer, bool isNewObject )
+{
+ // Get the first token.
+ // The cvar we are setting
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( isNewObject )
+ {
+ Q_strncpy( cvarname, token, sizeof( cvarname ) );
+ }
+
+ // Parse the {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "{" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ // Parse the Prompt
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( isNewObject )
+ {
+ Q_strncpy( prompt, token, sizeof( prompt ) );
+ }
+
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ // If it's not a {, consider it the optional tooltip
+ if ( strcmp( token, "{" ) )
+ {
+ Q_strncpy( tooltip, token, sizeof( tooltip ) );
+
+ // Parse the next {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+ }
+
+ if ( strcmp( token, "{" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ // Now parse the type:
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ objtype_t newType = GetType( token );
+ if ( isNewObject )
+ {
+ type = newType;
+ }
+ if ( newType == O_BADTYPE )
+ {
+ Msg( "Type '%s' unknown", token );
+ return false;
+ }
+
+ // If it's a category, we're done.
+ if ( newType == O_CATEGORY )
+ {
+ // Parse the }
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ // Parse the final }
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+ return true;
+ }
+
+ switch ( newType )
+ {
+ case O_OBSOLETE:
+ case O_BOOL:
+ // Parse the next {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+ break;
+ case O_NUMBER:
+ case O_SLIDER:
+ // Parse the Min
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( isNewObject )
+ {
+ fMin = (float)atof( token );
+ }
+
+ // Parse the Min
+ *pBuffer = engine->ParseFile( *pBuffer, token , sizeof( token ));
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( isNewObject )
+ {
+ fMax = (float)atof( token );
+ }
+
+ // Parse the next {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+ break;
+ case O_STRING:
+ // Parse the next {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+ break;
+ case O_LIST:
+ // Parse items until we get the }
+ while ( 1 )
+ {
+ // Parse the next {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ // Done?
+ if ( !strcmp( token, "}" ) )
+ break;
+
+ //
+ // Add the item to a list somewhere
+ // AddItem( token )
+ char strItem[ 128 ];
+ char strValue[128];
+
+ Q_strncpy( strItem, token, sizeof( strItem ) );
+
+ // Parse the value
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ Q_strncpy( strValue, token, sizeof( strValue ) );
+
+ if ( isNewObject )
+ {
+ CScriptListItem *pItem;
+ pItem = new CScriptListItem( strItem, strValue );
+
+ AddItem( pItem );
+ }
+ }
+ break;
+ }
+
+ //
+ // Now read in the default value
+
+ // Parse the {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "{" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ // Parse the default
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ //if ( strlen( token ) <= 0 )
+ // return false;
+
+ // Set the values
+ Q_strncpy( defValue, token, sizeof( defValue ) );
+ fdefValue = (float)atof( token );
+
+ if (type == O_NUMBER || type == O_SLIDER)
+ {
+ StripFloatTrailingZeros( defValue );
+ }
+
+ SetCurValue( defValue );
+
+ // Parse the }
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ // Parse the final }
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( !stricmp( token, "SetInfo" ) )
+ {
+ bSetInfo = true;
+ // Parse the final }
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+ }
+
+ if ( strcmp( token, "}" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ return true;
+}
+
+/////////////////////////
+CDescription::CDescription( void )
+{
+ pObjList = NULL;
+}
+
+CDescription::~CDescription()
+{
+ CScriptObject *p, *n;
+
+ p = pObjList;
+ while ( p )
+ {
+ n = p->pNext;
+ p->pNext = NULL;
+ p->MarkForDeletion();
+ //delete p;
+ p = n;
+ }
+
+ pObjList = NULL;
+
+ if ( m_pszHintText )
+ free( m_pszHintText );
+ if ( m_pszDescriptionType )
+ free( m_pszDescriptionType );
+}
+
+CScriptObject * CDescription::FindObject( const char *pszObjectName )
+{
+ if ( !pszObjectName )
+ return NULL;
+
+ CScriptObject *p;
+ p = pObjList;
+ while ( p )
+ {
+ if ( !stricmp( pszObjectName, p->cvarname ) )
+ return p;
+ p = p->pNext;
+ }
+ return NULL;
+}
+
+void CDescription::AddObject( CScriptObject *pObj )
+{
+ CScriptObject *p;
+ p = pObjList;
+ if ( !p )
+ {
+ pObjList = pObj;
+ pObj->pNext = NULL;
+ return;
+ }
+
+ while ( p )
+ {
+ if ( !p->pNext )
+ {
+ p->pNext = pObj;
+ pObj->pNext = NULL;
+ return;
+ }
+ p = p->pNext;
+ }
+}
+
+bool CDescription::ReadFromBuffer( const char **pBuffer, bool bAllowNewObject )
+{
+ // Get the first token.
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ // Read VERSION #
+ if ( stricmp ( token, "VERSION" ) )
+ {
+ Msg( "Expecting 'VERSION', got '%s'", token );
+ return false;
+ }
+
+ // Parse in the version #
+ // Get the first token.
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ {
+ Msg( "Expecting version #" );
+ return false;
+ }
+
+ float fVer;
+ fVer = (float)atof( token );
+
+ if ( fVer != SCRIPT_VERSION )
+ {
+ Msg( "Version mismatch, expecting %f, got %f", SCRIPT_VERSION, fVer );
+ return false;
+ }
+
+ // Get the "DESCRIPTION"
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ // Read DESCRIPTION
+ if ( stricmp ( token, "DESCRIPTION" ) )
+ {
+ Msg( "Expecting 'DESCRIPTION', got '%s'", token );
+ return false;
+ }
+
+ // Parse in the description type
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ {
+ Msg( "Expecting '%s'", m_pszDescriptionType );
+ return false;
+ }
+
+ if ( stricmp ( token, m_pszDescriptionType ) )
+ {
+ Msg( "Expecting %s, got %s", m_pszDescriptionType, token );
+ return false;
+ }
+
+ // Parse the {
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ if ( strcmp( token, "{" ) )
+ {
+ Msg( "Expecting '{', got '%s'", token );
+ return false;
+ }
+
+ const char *pStart;
+ CScriptObject *pObj;
+ // Now read in the objects and link them in
+ while ( 1 )
+ {
+ pStart = *pBuffer;
+
+ // Get the first token.
+ *pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) );
+ if ( strlen( token ) <= 0 )
+ return false;
+
+ // Read "cvar name" or } when done
+ if ( !stricmp ( token, "}" ) )
+ break;
+
+ // Unget the token
+ *pBuffer = pStart;
+
+ // Create a new object
+ bool mustAdd = bAllowNewObject;
+ pObj = FindObject( token );
+ if ( pObj )
+ {
+ pObj->ReadFromBuffer( &pStart, false );
+ mustAdd = false; // already in list
+ }
+ else
+ {
+ pObj = new CScriptObject();
+ if ( !pObj )
+ {
+ Msg( "Couldn't create script object" );
+ return false;
+ }
+
+ if ( !pObj->ReadFromBuffer( &pStart, true ) )
+ {
+ delete pObj;
+ return false;
+ }
+
+ // throw away the object if we're not adding it.
+ if ( !mustAdd )
+ {
+ delete pObj;
+ }
+ }
+
+ *pBuffer = pStart;
+
+ // Add to list
+ // Fixme, move to end of list first
+ if ( mustAdd )
+ {
+ AddObject( pObj );
+ }
+ }
+
+ return true;
+}
+
+bool CDescription::InitFromFile( const char *pszFileName, bool bAllowNewObject /*= true*/ )
+{
+
+ // Load file into memory
+ FileHandle_t file = g_pFullFileSystem->Open( pszFileName, "rb" );
+ if ( !file )
+ return false;
+
+ int len =g_pFullFileSystem->Size( file );
+
+ // read the file
+ byte *buffer = new unsigned char[ len ];
+ Assert( buffer );
+ g_pFullFileSystem->Read( buffer, len, file );
+ g_pFullFileSystem->Close( file );
+
+ const char *pBuffer = (const char*)buffer;
+
+ ReadFromBuffer( &pBuffer, bAllowNewObject );
+
+ delete[] buffer;
+
+ return true;
+}
+
+void CDescription::WriteToFile( FileHandle_t fp )
+{
+ CScriptObject *pObj;
+
+ WriteFileHeader( fp );
+
+ pObj = pObjList;
+ while ( pObj )
+ {
+ pObj->WriteToFile( fp );
+ pObj = pObj->pNext;
+ }
+}
+
+void CDescription::WriteToConfig( void )
+{
+ CScriptObject *pObj;
+
+ pObj = pObjList;
+ while ( pObj )
+ {
+ pObj->WriteToConfig();
+ pObj = pObj->pNext;
+ }
+}
+
+void CDescription::WriteToScriptFile( FileHandle_t fp )
+{
+ CScriptObject *pObj;
+
+ WriteScriptHeader( fp );
+
+ pObj = pObjList;
+ while ( pObj )
+ {
+ pObj->WriteToScriptFile( fp );
+ pObj = pObj->pNext;
+ }
+
+ g_pFullFileSystem->FPrintf( fp, "}\r\n" );
+}
+
+void CDescription::TransferCurrentValues( const char *pszConfigFile )
+{
+ char szValue[ 1024 ];
+
+ CScriptObject *pObj;
+
+ pObj = pObjList;
+ while ( pObj )
+ {
+
+ /*
+ TODO: if/when prefixed keys are implemented
+ const char *value;
+ if ( pObj->bSetInfo )
+ {
+ value = engine->LocalPlayerInfo_ValueForKey( pObj->cvarname ); // use LocalPlayerInfo because PlayerInfo strips keys prefixed with "_"
+ }
+ else
+ {
+ value = engine->pfnGetCvarString( pObj->cvarname );
+ }
+ */
+
+ ConVarRef var( pObj->cvarname, true );
+ if ( !var.IsValid() )
+ {
+ if ( pObj->type != O_CATEGORY )
+ {
+ DevMsg( "Could not find '%s'\n", pObj->cvarname );
+ }
+ pObj = pObj->pNext;
+ continue;
+ }
+ const char *value = var.GetString();
+
+ if ( value && value[ 0 ] )
+ //if ( CFG_GetValue( pszConfigFile, pObj->cvarname, szValue ) )
+ {
+ Q_strncpy( szValue, value, sizeof( szValue ) );
+
+ // Fill in better default value
+ //
+ Q_strncpy( pObj->curValue, szValue, sizeof( pObj->curValue ) );
+ pObj->fcurValue = (float)atof( szValue );
+
+ Q_strncpy( pObj->defValue, szValue, sizeof( pObj->defValue ) );
+ pObj->fdefValue = (float)atof( szValue );
+ }
+
+ pObj = pObj->pNext;
+ }
+}
+
+void CDescription::setDescription( const char *pszDesc )
+{
+ m_pszDescriptionType = strdup( pszDesc );
+}
+
+void CDescription::setHint( const char *pszHint )
+{
+ m_pszHintText = strdup( pszHint );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor, load/save client settings object
+//-----------------------------------------------------------------------------
+CInfoDescription::CInfoDescription( void )
+ : CDescription( )
+{
+ setHint( "// NOTE: THIS FILE IS AUTOMATICALLY REGENERATED, \r\n\
+//DO NOT EDIT THIS HEADER, YOUR COMMENTS WILL BE LOST IF YOU DO\r\n\
+// User options script\r\n\
+//\r\n\
+// Format:\r\n\
+// Version [float]\r\n\
+// Options description followed by \r\n\
+// Options defaults\r\n\
+//\r\n\
+// Option description syntax:\r\n\
+//\r\n\
+// \"cvar\" { \"Prompt\" { type [ type info ] } { default } }\r\n\
+//\r\n\
+// type = \r\n\
+// BOOL (a yes/no toggle)\r\n\
+// STRING\r\n\
+// NUMBER\r\n\
+// LIST\r\n\
+//\r\n\
+// type info:\r\n\
+// BOOL no type info\r\n\
+// NUMBER min max range, use -1 -1 for no limits\r\n\
+// STRING no type info\r\n\
+// LIST "" delimited list of options value pairs\r\n\
+//\r\n\
+//\r\n\
+// default depends on type\r\n\
+// BOOL is \"0\" or \"1\"\r\n\
+// NUMBER is \"value\"\r\n\
+// STRING is \"value\"\r\n\
+// LIST is \"index\", where index \"0\" is the first element of the list\r\n\r\n\r\n" );
+
+ setDescription( "INFO_OPTIONS" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoDescription::WriteScriptHeader( FileHandle_t fp )
+{
+ char am_pm[] = "AM";
+ tm newtime;
+ VCRHook_LocalTime( &newtime );
+
+ g_pFullFileSystem->FPrintf( fp, (char *)getHint() );
+
+// Write out the comment and Cvar Info:
+ g_pFullFileSystem->FPrintf( fp, "// Half-Life User Info Configuration Layout Script (stores last settings chosen, too)\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
+ g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "VERSION %.1f\r\n\r\n", SCRIPT_VERSION );
+ g_pFullFileSystem->FPrintf( fp, "DESCRIPTION INFO_OPTIONS\r\n{\r\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoDescription::WriteFileHeader( FileHandle_t fp )
+{
+ char am_pm[] = "AM";
+ tm newtime;
+ VCRHook_LocalTime( &newtime );
+
+ g_pFullFileSystem->FPrintf( fp, "// Half-Life User Info Configuration Settings\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// DO NOT EDIT, GENERATED BY HALF-LIFE\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
+ g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
+}
+
+//----------------------------------------------------------------------------- \ No newline at end of file