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.
1154 lines
24 KiB
1154 lines
24 KiB
//========= 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" |
|
#include "vcrmode.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" ); |
|
} |
|
|
|
//-----------------------------------------------------------------------------
|
|
|