DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

CVarSystem.cpp (31997B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "../idlib/precompiled.h"
     30 #pragma hdrstop
     31 
     32 idCVar * idCVar::staticVars = NULL;
     33 
     34 extern idCVar net_allowCheats;
     35 
     36 /*
     37 ===============================================================================
     38 
     39 	idInternalCVar
     40 
     41 ===============================================================================
     42 */
     43 
     44 class idInternalCVar : public idCVar {
     45 	friend class idCVarSystemLocal;
     46 public:
     47 							idInternalCVar();
     48 							idInternalCVar( const char *newName, const char *newValue, int newFlags );
     49 							idInternalCVar( const idCVar *cvar );
     50 	virtual					~idInternalCVar();
     51 
     52 	const char **			CopyValueStrings( const char **strings );
     53 	void					Update( const idCVar *cvar );
     54 	void					UpdateValue();
     55 	void					UpdateCheat();
     56 	void					Set( const char *newValue, bool force, bool fromServer );
     57 	void					Reset();
     58 
     59 private:
     60 	idStr					nameString;				// name
     61 	idStr					resetString;			// resetting will change to this value
     62 	idStr					valueString;			// value
     63 	idStr					descriptionString;		// description
     64 
     65 	virtual const char *	InternalGetResetString() const;
     66 
     67 	virtual void			InternalSetString( const char *newValue );
     68 	virtual void			InternalServerSetString( const char *newValue );
     69 	virtual void			InternalSetBool( const bool newValue );
     70 	virtual void			InternalSetInteger( const int newValue );
     71 	virtual void			InternalSetFloat( const float newValue );
     72 };
     73 
     74 /*
     75 ============
     76 idInternalCVar::idInternalCVar
     77 ============
     78 */
     79 idInternalCVar::idInternalCVar() {
     80 }
     81 
     82 /*
     83 ============
     84 idInternalCVar::idInternalCVar
     85 ============
     86 */
     87 idInternalCVar::idInternalCVar( const char *newName, const char *newValue, int newFlags ) {
     88 	nameString = newName;
     89 	name = nameString.c_str();
     90 	valueString = newValue;
     91 	value = valueString.c_str();
     92 	resetString = newValue;
     93 	descriptionString = "";
     94 	description = descriptionString.c_str();
     95 	flags = ( newFlags & ~CVAR_STATIC ) | CVAR_MODIFIED;
     96 	valueMin = 1;
     97 	valueMax = -1;
     98 	valueStrings = NULL;
     99 	valueCompletion = 0;
    100 	UpdateValue();
    101 	UpdateCheat();
    102 	internalVar = this;
    103 }
    104 
    105 /*
    106 ============
    107 idInternalCVar::idInternalCVar
    108 ============
    109 */
    110 idInternalCVar::idInternalCVar( const idCVar *cvar ) {
    111 	nameString = cvar->GetName();
    112 	name = nameString.c_str();
    113 	valueString = cvar->GetString();
    114 	value = valueString.c_str();
    115 	resetString = cvar->GetString();
    116 	descriptionString = cvar->GetDescription();
    117 	description = descriptionString.c_str();
    118 	flags = cvar->GetFlags() | CVAR_MODIFIED;
    119 	valueMin = cvar->GetMinValue();
    120 	valueMax = cvar->GetMaxValue();
    121 	valueStrings = CopyValueStrings( cvar->GetValueStrings() );
    122 	valueCompletion = cvar->GetValueCompletion();
    123 	UpdateValue();
    124 	UpdateCheat();
    125 	internalVar = this;
    126 }
    127 
    128 /*
    129 ============
    130 idInternalCVar::~idInternalCVar
    131 ============
    132 */
    133 idInternalCVar::~idInternalCVar() {
    134 	Mem_Free( valueStrings );
    135 	valueStrings = NULL;
    136 }
    137 
    138 
    139 /*
    140 ============
    141 idInternalCVar::CopyValueStrings
    142 ============
    143 */
    144 const char **idInternalCVar::CopyValueStrings( const char **strings ) {
    145 	int i, totalLength;
    146 	const char **ptr;
    147 	char *str;
    148 
    149 	if ( !strings ) {
    150 		return NULL;
    151 	}
    152 
    153 	totalLength = 0;
    154 	for ( i = 0; strings[i] != NULL; i++ ) {
    155 		totalLength += idStr::Length( strings[i] ) + 1;
    156 	}
    157 
    158 	ptr = (const char **) Mem_Alloc( ( i + 1 ) * sizeof( char * ) + totalLength, TAG_CVAR );
    159 	str = (char *) (((byte *)ptr) + ( i + 1 ) * sizeof( char * ) );
    160 
    161 	for ( i = 0; strings[i] != NULL; i++ ) {
    162 		ptr[i] = str;
    163 		strcpy( str, strings[i] );
    164 		str += idStr::Length( strings[i] ) + 1;
    165 	}
    166 	ptr[i] = NULL;
    167 
    168 	return ptr;
    169 }
    170 
    171 /*
    172 ============
    173 idInternalCVar::Update
    174 ============
    175 */
    176 void idInternalCVar::Update( const idCVar *cvar ) {
    177 
    178 	// if this is a statically declared variable
    179 	if ( cvar->GetFlags() & CVAR_STATIC ) {
    180 
    181 		if ( flags & CVAR_STATIC ) {
    182 
    183 			// the code has more than one static declaration of the same variable, make sure they have the same properties
    184 			if ( resetString.Icmp( cvar->GetString() ) != 0 ) {
    185 				common->Warning( "CVar '%s' declared multiple times with different initial value", nameString.c_str() );
    186 			}
    187 			if ( ( flags & (CVAR_BOOL|CVAR_INTEGER|CVAR_FLOAT) ) != ( cvar->GetFlags() & (CVAR_BOOL|CVAR_INTEGER|CVAR_FLOAT) ) ) {
    188 				common->Warning( "CVar '%s' declared multiple times with different type", nameString.c_str() );
    189 			}
    190 			if ( valueMin != cvar->GetMinValue() || valueMax != cvar->GetMaxValue() ) {
    191 				common->Warning( "CVar '%s' declared multiple times with different minimum/maximum", nameString.c_str() );
    192 			}
    193 
    194 		}
    195 
    196 		// the code is now specifying a variable that the user already set a value for, take the new value as the reset value
    197 		resetString = cvar->GetString();
    198 		descriptionString = cvar->GetDescription();
    199 		description = descriptionString.c_str();
    200 		valueMin = cvar->GetMinValue();
    201 		valueMax = cvar->GetMaxValue();
    202 		Mem_Free( valueStrings );
    203 		valueStrings = CopyValueStrings( cvar->GetValueStrings() );
    204 		valueCompletion = cvar->GetValueCompletion();
    205 		UpdateValue();
    206 		cvarSystem->SetModifiedFlags( cvar->GetFlags() );
    207 	}
    208 
    209 	flags |= cvar->GetFlags();
    210 
    211 	UpdateCheat();
    212 
    213 	// only allow one non-empty reset string without a warning
    214 	if ( resetString.Length() == 0 ) {
    215 		resetString = cvar->GetString();
    216 	} else if ( cvar->GetString()[0] && resetString.Cmp( cvar->GetString() ) != 0 ) {
    217 		common->Warning( "cvar \"%s\" given initial values: \"%s\" and \"%s\"\n", nameString.c_str(), resetString.c_str(), cvar->GetString() );
    218 	}
    219 }
    220 
    221 /*
    222 ============
    223 idInternalCVar::UpdateValue
    224 ============
    225 */
    226 void idInternalCVar::UpdateValue() {
    227 	bool clamped = false;
    228 
    229 	if ( flags & CVAR_BOOL ) {
    230 		integerValue = ( atoi( value ) != 0 );
    231 		floatValue = integerValue;
    232 		if ( idStr::Icmp( value, "0" ) != 0 && idStr::Icmp( value, "1" ) != 0 ) {
    233 			valueString = idStr( (bool)( integerValue != 0 ) );
    234 			value = valueString.c_str();
    235 		}
    236 	} else if ( flags & CVAR_INTEGER ) {
    237 		integerValue = (int)atoi( value );
    238 		if ( valueMin < valueMax ) {
    239 			if ( integerValue < valueMin ) {
    240 				integerValue = (int)valueMin;
    241 				clamped = true;
    242 			} else if ( integerValue > valueMax ) {
    243 				integerValue = (int)valueMax;
    244 				clamped = true;
    245 			}
    246 		}
    247 		if ( clamped || !idStr::IsNumeric( value ) || idStr::FindChar( value, '.' ) ) {
    248 			valueString = idStr( integerValue );
    249 			value = valueString.c_str();
    250 		}
    251 		floatValue = (float)integerValue;
    252 	} else if ( flags & CVAR_FLOAT ) {
    253 		floatValue = (float)atof( value );
    254 		if ( valueMin < valueMax ) {
    255 			if ( floatValue < valueMin ) {
    256 				floatValue = valueMin;
    257 				clamped = true;
    258 			} else if ( floatValue > valueMax ) {
    259 				floatValue = valueMax;
    260 				clamped = true;
    261 			}
    262 		}
    263 		if ( clamped || !idStr::IsNumeric( value ) ) {
    264 			valueString = idStr( floatValue );
    265 			value = valueString.c_str();
    266 		}
    267 		integerValue = (int)floatValue;
    268 	} else {
    269 		if ( valueStrings && valueStrings[0] ) {
    270 			integerValue = 0;
    271 			for ( int i = 0; valueStrings[i]; i++ ) {
    272 				if ( valueString.Icmp( valueStrings[i] ) == 0 ) {
    273 					integerValue = i;
    274 					break;
    275 				}
    276 			}
    277 			valueString = valueStrings[integerValue];
    278 			value = valueString.c_str();
    279 			floatValue = (float)integerValue;
    280 		} else if ( valueString.Length() < 32 ) {
    281 			floatValue = (float)atof( value );
    282 			integerValue = (int)floatValue;
    283 		} else {
    284 			floatValue = 0.0f;
    285 			integerValue = 0;
    286 		}
    287 	}
    288 }
    289 
    290 /*
    291 ============
    292 idInternalCVar::UpdateCheat
    293 ============
    294 */
    295 void idInternalCVar::UpdateCheat() {
    296 	// all variables are considered cheats except for a few types
    297 	if ( flags & ( CVAR_NOCHEAT | CVAR_INIT | CVAR_ROM | CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NETWORKSYNC ) ) {
    298 		flags &= ~CVAR_CHEAT;
    299 	} else {
    300 		flags |= CVAR_CHEAT;
    301 	}
    302 }
    303 
    304 /*
    305 ============
    306 idInternalCVar::Set
    307 ============
    308 */
    309 void idInternalCVar::Set( const char *newValue, bool force, bool fromServer ) {
    310 	if ( common->IsMultiplayer() && !fromServer ) {
    311 #ifndef ID_TYPEINFO
    312 		if ( ( flags & CVAR_NETWORKSYNC ) && common->IsClient() ) {
    313 			common->Printf( "%s is a synced over the network and cannot be changed on a multiplayer client.\n", nameString.c_str() );
    314 			return;
    315 		}
    316 #endif
    317 		if ( ( flags & CVAR_CHEAT ) && !net_allowCheats.GetBool() ) {
    318 			common->Printf( "%s cannot be changed in multiplayer.\n", nameString.c_str() );
    319 			return;
    320 		}	
    321 	}
    322 
    323 	if ( !newValue ) {
    324 		newValue = resetString.c_str();
    325 	}
    326 
    327 	if ( !force ) {
    328 		if ( flags & CVAR_ROM ) {
    329 			common->Printf( "%s is read only.\n", nameString.c_str() );
    330 			return;
    331 		}
    332 
    333 		if ( flags & CVAR_INIT ) {
    334 			common->Printf( "%s is write protected.\n", nameString.c_str() );
    335 			return;
    336 		}
    337 	}
    338 
    339 	if ( valueString.Icmp( newValue ) == 0 ) {
    340 		return;
    341 	}
    342 
    343 	valueString = newValue;
    344 	value = valueString.c_str();
    345 	UpdateValue();
    346 
    347 	SetModified();
    348 	cvarSystem->SetModifiedFlags( flags );
    349 }
    350 
    351 /*
    352 ============
    353 idInternalCVar::Reset
    354 ============
    355 */
    356 void idInternalCVar::Reset() {
    357 	valueString = resetString;
    358 	value = valueString.c_str();
    359 	UpdateValue();
    360 }
    361 
    362 /*
    363 ============
    364 idInternalCVar::InternalGetResetString
    365 ============
    366 */
    367 const char * idInternalCVar::InternalGetResetString() const {
    368 	return resetString;
    369 }
    370 
    371 /*
    372 ============
    373 idInternalCVar::InternalSetString
    374 ============
    375 */
    376 void idInternalCVar::InternalSetString( const char *newValue ) {
    377 	Set( newValue, true, false );
    378 }
    379 
    380 /*
    381 ===============
    382 idInternalCVar::InternalServerSetString
    383 ===============
    384 */
    385 void idInternalCVar::InternalServerSetString( const char *newValue ) {
    386 	Set( newValue, true, true );
    387 }
    388 
    389 /*
    390 ============
    391 idInternalCVar::InternalSetBool
    392 ============
    393 */
    394 void idInternalCVar::InternalSetBool( const bool newValue ) {
    395 	Set( idStr( newValue ), true, false );
    396 }
    397 
    398 /*
    399 ============
    400 idInternalCVar::InternalSetInteger
    401 ============
    402 */
    403 void idInternalCVar::InternalSetInteger( const int newValue ) {
    404 	Set( idStr( newValue ), true, false );
    405 }
    406 
    407 /*
    408 ============
    409 idInternalCVar::InternalSetFloat
    410 ============
    411 */
    412 void idInternalCVar::InternalSetFloat( const float newValue ) {
    413 	Set( idStr( newValue ), true, false );
    414 }
    415 
    416 
    417 /*
    418 ===============================================================================
    419 
    420 	idCVarSystemLocal
    421 
    422 ===============================================================================
    423 */
    424 
    425 class idCVarSystemLocal : public idCVarSystem {
    426 public:
    427 							idCVarSystemLocal();
    428 
    429 	virtual					~idCVarSystemLocal() {}
    430 
    431 	virtual void			Init();
    432 	virtual void			Shutdown();
    433 	virtual bool			IsInitialized() const;
    434 
    435 	virtual void			Register( idCVar *cvar );
    436 
    437 	virtual idCVar *		Find( const char *name );
    438 
    439 	virtual void			SetCVarString( const char *name, const char *value, int flags = 0 );
    440 	virtual void			SetCVarBool( const char *name, const bool value, int flags = 0 );
    441 	virtual void			SetCVarInteger( const char *name, const int value, int flags = 0 );
    442 	virtual void			SetCVarFloat( const char *name, const float value, int flags = 0 );
    443 
    444 	virtual const char *	GetCVarString( const char *name ) const;
    445 	virtual bool			GetCVarBool( const char *name ) const;
    446 	virtual int				GetCVarInteger( const char *name ) const;
    447 	virtual float			GetCVarFloat( const char *name ) const;
    448 
    449 	virtual bool			Command( const idCmdArgs &args );
    450 
    451 	virtual void			CommandCompletion( void(*callback)( const char *s ) );
    452 	virtual void			ArgCompletion( const char *cmdString, void(*callback)( const char *s ) );
    453 
    454 	virtual void			SetModifiedFlags( int flags );
    455 	virtual int				GetModifiedFlags() const;
    456 	virtual void			ClearModifiedFlags( int flags );
    457 
    458 	virtual void			ResetFlaggedVariables( int flags );
    459 	virtual void			RemoveFlaggedAutoCompletion( int flags );
    460 	virtual void			WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const;
    461 
    462 	virtual void			MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const;
    463 	virtual void			SetCVarsFromDict( const idDict &dict );
    464 
    465 	void					RegisterInternal( idCVar *cvar );
    466 	idInternalCVar *		FindInternal( const char *name ) const;
    467 	void					SetInternal( const char *name, const char *value, int flags );
    468 
    469 private:
    470 	bool					initialized;
    471 	idList<idInternalCVar*, TAG_CVAR>	cvars;
    472 	idHashIndex				cvarHash;
    473 	int						modifiedFlags;
    474 
    475 private:
    476 	static void				Toggle_f( const idCmdArgs &args );
    477 	static void				Set_f( const idCmdArgs &args );
    478 	static void				Reset_f( const idCmdArgs &args );
    479 	static void				ListByFlags( const idCmdArgs &args, cvarFlags_t flags );
    480 	static void				List_f( const idCmdArgs &args );
    481 	static void				Restart_f( const idCmdArgs &args );
    482 	static void				CvarAdd_f( const idCmdArgs &args );
    483 };
    484 
    485 idCVarSystemLocal			localCVarSystem;
    486 idCVarSystem *				cvarSystem = &localCVarSystem;
    487 
    488 #define NUM_COLUMNS				77		// 78 - 1
    489 #define NUM_NAME_CHARS			33
    490 #define NUM_DESCRIPTION_CHARS	( NUM_COLUMNS - NUM_NAME_CHARS )
    491 #define FORMAT_STRING			"%-32s "
    492 
    493 const char *CreateColumn( const char *text, int columnWidth, const char *indent, idStr &string ) {
    494 	int i, lastLine;
    495 
    496 	string.Clear();
    497 	for ( lastLine = i = 0; text[i] != '\0'; i++ ) {
    498 		if ( i - lastLine >= columnWidth || text[i] == '\n' ) {
    499 			while( i > 0 && text[i] > ' ' && text[i] != '/' && text[i] != ',' && text[i] != '\\' ) {
    500 				i--;
    501 			}
    502 			while( lastLine < i ) {
    503 				string.Append( text[lastLine++] );
    504 			}
    505 			string.Append( indent );
    506 			lastLine++;
    507 		}
    508 	}
    509 	while( lastLine < i ) {
    510 		string.Append( text[lastLine++] );
    511 	}
    512 	return string.c_str();
    513 }
    514 
    515 /*
    516 ============
    517 idCVarSystemLocal::FindInternal
    518 ============
    519 */
    520 idInternalCVar *idCVarSystemLocal::FindInternal( const char *name ) const {
    521 	int hash = cvarHash.GenerateKey( name, false );
    522 	for ( int i = cvarHash.First( hash ); i != -1; i = cvarHash.Next( i ) ) {
    523 		if ( cvars[i]->nameString.Icmp( name ) == 0 ) {
    524 			return cvars[i];
    525 		}
    526 	}
    527 	return NULL;
    528 }
    529 
    530 /*
    531 ============
    532 idCVarSystemLocal::SetInternal
    533 ============
    534 */
    535 void idCVarSystemLocal::SetInternal( const char *name, const char *value, int flags ) {
    536 	int hash;
    537 	idInternalCVar *internal;
    538 
    539 	internal = FindInternal( name );
    540 
    541 	if ( internal ) {
    542 		internal->InternalSetString( value );
    543 		internal->flags |= flags & ~CVAR_STATIC;
    544 		internal->UpdateCheat();
    545 	} else {
    546 		internal = new (TAG_SYSTEM) idInternalCVar( name, value, flags );
    547 		hash = cvarHash.GenerateKey( internal->nameString.c_str(), false );
    548 		cvarHash.Add( hash, cvars.Append( internal ) );
    549 	}
    550 }
    551 
    552 /*
    553 ============
    554 idCVarSystemLocal::idCVarSystemLocal
    555 ============
    556 */
    557 idCVarSystemLocal::idCVarSystemLocal() {
    558 	initialized = false;
    559 	modifiedFlags = 0;
    560 }
    561 
    562 /*
    563 ============
    564 idCVarSystemLocal::Init
    565 ============
    566 */
    567 void idCVarSystemLocal::Init() {
    568 
    569 	modifiedFlags = 0;
    570 
    571 	cmdSystem->AddCommand( "toggle", Toggle_f, CMD_FL_SYSTEM, "toggles a cvar" );
    572 	cmdSystem->AddCommand( "set", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
    573 	cmdSystem->AddCommand( "seta", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
    574 	cmdSystem->AddCommand( "sets", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
    575 	cmdSystem->AddCommand( "sett", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
    576 	cmdSystem->AddCommand( "setu", Set_f, CMD_FL_SYSTEM, "sets a cvar" );
    577 	cmdSystem->AddCommand( "reset", Reset_f, CMD_FL_SYSTEM, "resets a cvar" );
    578 	cmdSystem->AddCommand( "listCvars", List_f, CMD_FL_SYSTEM, "lists cvars" );
    579 	cmdSystem->AddCommand( "cvar_restart", Restart_f, CMD_FL_SYSTEM, "restart the cvar system" );
    580 	cmdSystem->AddCommand( "cvarAdd", CvarAdd_f, CMD_FL_SYSTEM, "adds a value to a numeric cvar" );
    581 
    582 	initialized = true;
    583 }
    584 
    585 /*
    586 ============
    587 idCVarSystemLocal::Shutdown
    588 ============
    589 */
    590 void idCVarSystemLocal::Shutdown() {
    591 	cvars.DeleteContents( true );
    592 	cvarHash.Free();
    593 	initialized = false;
    594 }
    595 
    596 /*
    597 ============
    598 idCVarSystemLocal::IsInitialized
    599 ============
    600 */
    601 bool idCVarSystemLocal::IsInitialized() const {
    602 	return initialized;
    603 }
    604 
    605 /*
    606 ============
    607 idCVarSystemLocal::Register
    608 ============
    609 */
    610 void idCVarSystemLocal::Register( idCVar *cvar ) {
    611 	int hash;
    612 	idInternalCVar *internal;
    613 
    614 	cvar->SetInternalVar( cvar );
    615 
    616 	internal = FindInternal( cvar->GetName() );
    617 
    618 	if ( internal ) {
    619 		internal->Update( cvar );
    620 	} else {
    621 		internal = new (TAG_SYSTEM) idInternalCVar( cvar );
    622 		hash = cvarHash.GenerateKey( internal->nameString.c_str(), false );
    623 		cvarHash.Add( hash, cvars.Append( internal ) );
    624 	}
    625 
    626 	cvar->SetInternalVar( internal );
    627 }
    628 
    629 /*
    630 ============
    631 idCVarSystemLocal::Find
    632 ============
    633 */
    634 idCVar *idCVarSystemLocal::Find( const char *name ) {
    635 	return FindInternal( name );
    636 }
    637 
    638 /*
    639 ============
    640 idCVarSystemLocal::SetCVarString
    641 ============
    642 */
    643 void idCVarSystemLocal::SetCVarString( const char *name, const char *value, int flags ) {
    644 	SetInternal( name, value, flags );
    645 }
    646 
    647 /*
    648 ============
    649 idCVarSystemLocal::SetCVarBool
    650 ============
    651 */
    652 void idCVarSystemLocal::SetCVarBool( const char *name, const bool value, int flags ) {
    653 	SetInternal( name, idStr( value ), flags );
    654 }
    655 
    656 /*
    657 ============
    658 idCVarSystemLocal::SetCVarInteger
    659 ============
    660 */
    661 void idCVarSystemLocal::SetCVarInteger( const char *name, const int value, int flags ) {
    662 	SetInternal( name, idStr( value ), flags );
    663 }
    664 
    665 /*
    666 ============
    667 idCVarSystemLocal::SetCVarFloat
    668 ============
    669 */
    670 void idCVarSystemLocal::SetCVarFloat( const char *name, const float value, int flags ) {
    671 	SetInternal( name, idStr( value ), flags );
    672 }
    673 
    674 /*
    675 ============
    676 idCVarSystemLocal::GetCVarString
    677 ============
    678 */
    679 const char *idCVarSystemLocal::GetCVarString( const char *name ) const {
    680 	idInternalCVar *internal = FindInternal( name );
    681 	if ( internal ) {
    682 		return internal->GetString();
    683 	}
    684 	return "";
    685 }
    686 
    687 /*
    688 ============
    689 idCVarSystemLocal::GetCVarBool
    690 ============
    691 */
    692 bool idCVarSystemLocal::GetCVarBool( const char *name ) const {
    693 	idInternalCVar *internal = FindInternal( name );
    694 	if ( internal ) {
    695 		return internal->GetBool();
    696 	}
    697 	return false;
    698 }
    699 
    700 /*
    701 ============
    702 idCVarSystemLocal::GetCVarInteger
    703 ============
    704 */
    705 int idCVarSystemLocal::GetCVarInteger( const char *name ) const {
    706 	idInternalCVar *internal = FindInternal( name );
    707 	if ( internal ) {
    708 		return internal->GetInteger();
    709 	}
    710 	return 0;
    711 }
    712 
    713 /*
    714 ============
    715 idCVarSystemLocal::GetCVarFloat
    716 ============
    717 */
    718 float idCVarSystemLocal::GetCVarFloat( const char *name ) const {
    719 	idInternalCVar *internal = FindInternal( name );
    720 	if ( internal ) {
    721 		return internal->GetFloat();
    722 	}
    723 	return 0.0f;
    724 }
    725 
    726 /*
    727 ============
    728 idCVarSystemLocal::Command
    729 ============
    730 */
    731 bool idCVarSystemLocal::Command( const idCmdArgs &args ) {
    732 	idInternalCVar *internal;
    733 
    734 	internal = FindInternal( args.Argv( 0 ) );
    735 
    736 	if ( internal == NULL ) {
    737 		return false;
    738 	}
    739 
    740 	if ( args.Argc() == 1 ) {
    741 		// print the variable
    742 		common->Printf( "\"%s\" is:\"%s\"" S_COLOR_WHITE " default:\"%s\"\n",
    743 					internal->nameString.c_str(), internal->valueString.c_str(), internal->resetString.c_str() );
    744 		if ( idStr::Length( internal->GetDescription() ) > 0 ) {
    745 			common->Printf( S_COLOR_WHITE "%s\n", internal->GetDescription() );
    746 		}
    747 	} else {
    748 		// set the value
    749 		internal->Set( args.Args(), false, false );
    750 	}
    751 	return true;
    752 }
    753 
    754 /*
    755 ============
    756 idCVarSystemLocal::CommandCompletion
    757 ============
    758 */
    759 void idCVarSystemLocal::CommandCompletion( void(*callback)( const char *s ) ) {
    760 	for( int i = 0; i < cvars.Num(); i++ ) {
    761 		callback( cvars[i]->GetName() );
    762 	}
    763 }
    764 
    765 /*
    766 ============
    767 idCVarSystemLocal::ArgCompletion
    768 ============
    769 */
    770 void idCVarSystemLocal::ArgCompletion( const char *cmdString, void(*callback)( const char *s ) ) {
    771 	idCmdArgs args;
    772 
    773 	args.TokenizeString( cmdString, false );
    774 
    775 	for( int i = 0; i < cvars.Num(); i++ ) {
    776 		if ( !cvars[i]->valueCompletion ) {
    777 			continue;
    778 		}
    779 		if ( idStr::Icmp( args.Argv( 0 ), cvars[i]->nameString.c_str() ) == 0 ) {
    780 			cvars[i]->valueCompletion( args, callback );
    781 			break;
    782 		}
    783 	}
    784 }
    785 
    786 /*
    787 ============
    788 idCVarSystemLocal::SetModifiedFlags
    789 ============
    790 */
    791 void idCVarSystemLocal::SetModifiedFlags( int flags ) {
    792 	modifiedFlags |= flags;
    793 }
    794 
    795 /*
    796 ============
    797 idCVarSystemLocal::GetModifiedFlags
    798 ============
    799 */
    800 int idCVarSystemLocal::GetModifiedFlags() const {
    801 	return modifiedFlags;
    802 }
    803 
    804 /*
    805 ============
    806 idCVarSystemLocal::ClearModifiedFlags
    807 ============
    808 */
    809 void idCVarSystemLocal::ClearModifiedFlags( int flags ) {
    810 	modifiedFlags &= ~flags;
    811 }
    812 
    813 /*
    814 ============
    815 idCVarSystemLocal::ResetFlaggedVariables
    816 ============
    817 */
    818 void idCVarSystemLocal::ResetFlaggedVariables( int flags ) {
    819 	for( int i = 0; i < cvars.Num(); i++ ) {
    820 		idInternalCVar *cvar = cvars[i];
    821 		if ( cvar->GetFlags() & flags ) {
    822 			cvar->Set( NULL, true, true );
    823 		}
    824 	}
    825 }
    826 
    827 /*
    828 ============
    829 idCVarSystemLocal::RemoveFlaggedAutoCompletion
    830 ============
    831 */
    832 void idCVarSystemLocal::RemoveFlaggedAutoCompletion( int flags ) {
    833 	for( int i = 0; i < cvars.Num(); i++ ) {
    834 		idInternalCVar *cvar = cvars[i];
    835 		if ( cvar->GetFlags() & flags ) {
    836 			cvar->valueCompletion = NULL;
    837 		}
    838 	}
    839 }
    840 
    841 /*
    842 ============
    843 idCVarSystemLocal::WriteFlaggedVariables
    844 
    845 Appends lines containing "set variable value" for all variables
    846 with the "flags" flag set to true.
    847 ============
    848 */
    849 void idCVarSystemLocal::WriteFlaggedVariables( int flags, const char *setCmd, idFile *f ) const {
    850 	for( int i = 0; i < cvars.Num(); i++ ) {
    851 		idInternalCVar *cvar = cvars[i];
    852 		if ( cvar->GetFlags() & flags ) {
    853 			f->Printf( "%s %s \"%s\"\n", setCmd, cvar->GetName(), cvar->GetString() );
    854 		}
    855 	}
    856 }
    857 
    858 /*
    859 ============
    860 idCVarSystemLocal::MoveCVarsToDict
    861 ============
    862 */
    863 void idCVarSystemLocal::MoveCVarsToDict( int flags, idDict & dict, bool onlyModified ) const {
    864 	dict.Clear();
    865 	for( int i = 0; i < cvars.Num(); i++ ) {
    866 		idCVar *cvar = cvars[i];
    867 		if ( cvar->GetFlags() & flags ) {
    868 			if ( onlyModified && idStr::Icmp( cvar->GetString(), cvar->GetDefaultString() ) == 0 ) {
    869 				continue;
    870 			}
    871 			dict.Set( cvar->GetName(), cvar->GetString() );
    872 		}
    873 	}
    874 }
    875 
    876 /*
    877 ============
    878 idCVarSystemLocal::SetCVarsFromDict
    879 ============
    880 */
    881 void idCVarSystemLocal::SetCVarsFromDict( const idDict &dict ) {
    882 	idInternalCVar *internal;
    883 
    884 	for( int i = 0; i < dict.GetNumKeyVals(); i++ ) {
    885 		const idKeyValue *kv = dict.GetKeyVal( i );
    886 		internal = FindInternal( kv->GetKey() );
    887 		if ( internal ) {
    888 			internal->InternalServerSetString( kv->GetValue() );
    889 		}
    890 	}
    891 }
    892 
    893 /*
    894 ============
    895 idCVarSystemLocal::Toggle_f
    896 ============
    897 */
    898 void idCVarSystemLocal::Toggle_f( const idCmdArgs &args ) {
    899 	int argc, i;
    900 	float current, set;
    901 	const char *text;
    902 
    903 	argc = args.Argc();
    904 	if ( argc < 2 ) {
    905 		common->Printf ("usage:\n"
    906 			"   toggle <variable>  - toggles between 0 and 1\n"
    907 			"   toggle <variable> <value> - toggles between 0 and <value>\n"
    908 			"   toggle <variable> [string 1] [string 2]...[string n] - cycles through all strings\n");
    909 		return;
    910 	}
    911 
    912 	idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
    913 
    914 	if ( cvar == NULL ) {
    915 		common->Warning( "Toggle_f: cvar \"%s\" not found", args.Argv( 1 ) );
    916 		return;
    917 	}
    918 
    919 	if ( argc > 3 ) {
    920 		// cycle through multiple values
    921 		text = cvar->GetString();
    922 		for( i = 2; i < argc; i++ ) {
    923 			if ( !idStr::Icmp( text, args.Argv( i ) ) ) {
    924 				// point to next value
    925 				i++;
    926 				break;
    927 			}
    928 		}
    929 		if ( i >= argc ) {
    930 			i = 2;
    931 		}
    932 
    933 		common->Printf( "set %s = %s\n", args.Argv(1), args.Argv( i ) );
    934 		cvar->Set( va("%s", args.Argv( i ) ), false, false );
    935 	} else {
    936 		// toggle between 0 and 1
    937 		current = cvar->GetFloat();
    938 		if ( argc == 3 ) {
    939 			set = atof( args.Argv( 2 ) );
    940 		} else {
    941 			set = 1.0f;
    942 		}
    943 		if ( current == 0.0f ) {
    944 			current = set;
    945 		} else {
    946 			current = 0.0f;
    947 		}
    948 		common->Printf( "set %s = %f\n", args.Argv(1), current );
    949 		cvar->Set( idStr( current ), false, false );
    950 	}
    951 }
    952 
    953 /*
    954 ============
    955 idCVarSystemLocal::Set_f
    956 ============
    957 */
    958 void idCVarSystemLocal::Set_f( const idCmdArgs &args ) {
    959 	const char *str;
    960 
    961 	str = args.Args( 2, args.Argc() - 1 );
    962 	localCVarSystem.SetCVarString( args.Argv(1), str );
    963 }
    964 
    965 /*
    966 ============
    967 idCVarSystemLocal::Reset_f
    968 ============
    969 */
    970 void idCVarSystemLocal::Reset_f( const idCmdArgs &args ) {
    971 	idInternalCVar *cvar;
    972 
    973 	if ( args.Argc() != 2 ) {
    974 		common->Printf ("usage: reset <variable>\n");
    975 		return;
    976 	}
    977 	cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
    978 	if ( !cvar ) {
    979 		return;
    980 	}
    981 
    982 	cvar->Reset();
    983 }
    984 
    985 /*
    986 ============
    987 idCVarSystemLocal::CvarAdd_f
    988 ============
    989 */
    990 void idCVarSystemLocal::CvarAdd_f( const idCmdArgs &args ) {
    991 	if ( args.Argc() != 3 ) {
    992 		common->Printf ("usage: cvarAdd <variable> <value>\n");
    993 	}
    994 
    995 	idInternalCVar *cvar = localCVarSystem.FindInternal( args.Argv( 1 ) );
    996 	if ( !cvar ) {
    997 		return;
    998 	}
    999 
   1000 	const float newValue = cvar->GetFloat() + atof( args.Argv( 2 ) );
   1001 	cvar->SetFloat( newValue );
   1002 	common->Printf( "%s = %f\n", cvar->GetName(), newValue );
   1003 }
   1004 //
   1005 ///*
   1006 //================================================
   1007 //idSort_CommandDef 
   1008 //================================================
   1009 //*/
   1010 //class idSort_InternalCVar : public idSort_Quick< const idInternalCVar *, idSort_InternalCVar > {
   1011 //public:
   1012 //	int Compare( const idInternalCVar * & a, const idInternalCVar * & b ) const { return idStr::Icmp( a.GetName(), b.GetName() ); }
   1013 //};
   1014 
   1015 void idCVarSystemLocal::ListByFlags( const idCmdArgs &args, cvarFlags_t flags ) {
   1016 	int i, argNum;
   1017 	idStr match, indent, string;
   1018 	const idInternalCVar *cvar;
   1019 	idList<const idInternalCVar *, TAG_CVAR>cvarList;
   1020 
   1021 	enum {
   1022 		SHOW_VALUE,
   1023 		SHOW_DESCRIPTION,
   1024 		SHOW_TYPE,
   1025 		SHOW_FLAGS
   1026 	} show;
   1027 
   1028 	argNum = 1;
   1029 	show = SHOW_VALUE;
   1030 
   1031 	if ( idStr::Icmp( args.Argv( argNum ), "-" ) == 0 || idStr::Icmp( args.Argv( argNum ), "/" ) == 0 ) {
   1032 		if ( idStr::Icmp( args.Argv( argNum + 1 ), "help" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "?" ) == 0 ) {
   1033 			argNum = 3;
   1034 			show = SHOW_DESCRIPTION;
   1035 		} else if ( idStr::Icmp( args.Argv( argNum + 1 ), "type" ) == 0 || idStr::Icmp( args.Argv( argNum + 1 ), "range" ) == 0 ) {
   1036 			argNum = 3;
   1037 			show = SHOW_TYPE;
   1038 		} else if ( idStr::Icmp( args.Argv( argNum + 1 ), "flags" ) == 0 ) {
   1039 			argNum = 3;
   1040 			show = SHOW_FLAGS;
   1041 		}
   1042 	}
   1043 
   1044 	if ( args.Argc() > argNum ) {
   1045 		match = args.Args( argNum, -1 );
   1046 		match.Replace( " ", "" );
   1047 	} else {
   1048 		match = "";
   1049 	}
   1050 
   1051 	for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) {
   1052 		cvar = localCVarSystem.cvars[i];
   1053 
   1054 		if ( !( cvar->GetFlags() & flags ) ) {
   1055 			continue;
   1056 		}
   1057 
   1058 		if ( match.Length() && !cvar->nameString.Filter( match, false ) ) {
   1059 			continue;
   1060 		}
   1061 
   1062 		cvarList.Append( cvar );
   1063 	}
   1064 
   1065 	//cvarList.SortWithTemplate( idSort_InternalCVar() );
   1066 
   1067 	switch( show ) {
   1068 		case SHOW_VALUE: {
   1069 			for ( i = 0; i < cvarList.Num(); i++ ) {
   1070 				cvar = cvarList[i];
   1071 				common->Printf( FORMAT_STRING S_COLOR_WHITE "\"%s\"\n", cvar->nameString.c_str(), cvar->valueString.c_str() );
   1072 			}
   1073 			break;
   1074 		}
   1075 		case SHOW_DESCRIPTION: {
   1076 			indent.Fill( ' ', NUM_NAME_CHARS );
   1077 			indent.Insert( "\n", 0 );
   1078 
   1079 			for ( i = 0; i < cvarList.Num(); i++ ) {
   1080 				cvar = cvarList[i];
   1081 				common->Printf( FORMAT_STRING S_COLOR_WHITE "%s\n", cvar->nameString.c_str(), CreateColumn( cvar->GetDescription(), NUM_DESCRIPTION_CHARS, indent, string ) );
   1082 			}
   1083 			break;
   1084 		}
   1085 		case SHOW_TYPE: {
   1086 			for ( i = 0; i < cvarList.Num(); i++ ) {
   1087 				cvar = cvarList[i];
   1088 				if ( cvar->GetFlags() & CVAR_BOOL ) {
   1089 					common->Printf( FORMAT_STRING S_COLOR_CYAN "bool\n", cvar->GetName() );
   1090 				} else if ( cvar->GetFlags() & CVAR_INTEGER ) {
   1091 					if ( cvar->GetMinValue() < cvar->GetMaxValue() ) {
   1092 						common->Printf( FORMAT_STRING S_COLOR_GREEN "int " S_COLOR_WHITE "[%d, %d]\n", cvar->GetName(), (int) cvar->GetMinValue(), (int) cvar->GetMaxValue() );
   1093 					} else {
   1094 						common->Printf( FORMAT_STRING S_COLOR_GREEN "int\n", cvar->GetName() );
   1095 					}
   1096 				} else if ( cvar->GetFlags() & CVAR_FLOAT ) {
   1097 					if ( cvar->GetMinValue() < cvar->GetMaxValue() ) {
   1098 						common->Printf( FORMAT_STRING S_COLOR_RED "float " S_COLOR_WHITE "[%s, %s]\n", cvar->GetName(), idStr( cvar->GetMinValue() ).c_str(), idStr( cvar->GetMaxValue() ).c_str() );
   1099 					} else {
   1100 						common->Printf( FORMAT_STRING S_COLOR_RED "float\n", cvar->GetName() );
   1101 					}
   1102 				} else if ( cvar->GetValueStrings() ) {
   1103 					common->Printf( FORMAT_STRING S_COLOR_WHITE "string " S_COLOR_WHITE "[", cvar->GetName() );
   1104 					for ( int j = 0; cvar->GetValueStrings()[j] != NULL; j++ ) {
   1105 						if ( j ) {
   1106 							common->Printf( S_COLOR_WHITE ", %s", cvar->GetValueStrings()[j] );
   1107 						} else {
   1108 							common->Printf( S_COLOR_WHITE "%s", cvar->GetValueStrings()[j] );
   1109 						}
   1110 					}
   1111 					common->Printf( S_COLOR_WHITE "]\n" );
   1112 				} else {
   1113 					common->Printf( FORMAT_STRING S_COLOR_WHITE "string\n", cvar->GetName() );
   1114 				}
   1115 			}
   1116 			break;
   1117 		}
   1118 		case SHOW_FLAGS: {
   1119 			for ( i = 0; i < cvarList.Num(); i++ ) {
   1120 				cvar = cvarList[i];
   1121 				common->Printf( FORMAT_STRING, cvar->GetName() );
   1122 				string = "";
   1123 				if ( cvar->GetFlags() & CVAR_BOOL ) {
   1124 					string += S_COLOR_CYAN "B ";
   1125 				} else if ( cvar->GetFlags() & CVAR_INTEGER ) {
   1126 					string += S_COLOR_GREEN "I ";
   1127 				} else if ( cvar->GetFlags() & CVAR_FLOAT ) {
   1128 					string += S_COLOR_RED "F ";
   1129 				} else {
   1130 					string += S_COLOR_WHITE "S ";
   1131 				}
   1132 				if ( cvar->GetFlags() & CVAR_SYSTEM ) {
   1133 					string += S_COLOR_WHITE "SYS  ";
   1134 				} else if ( cvar->GetFlags() & CVAR_RENDERER ) {
   1135 					string += S_COLOR_WHITE "RNDR ";
   1136 				} else if ( cvar->GetFlags() & CVAR_SOUND ) {
   1137 					string += S_COLOR_WHITE "SND  ";
   1138 				} else if ( cvar->GetFlags() & CVAR_GUI ) {
   1139 					string += S_COLOR_WHITE "GUI  ";
   1140 				} else if ( cvar->GetFlags() & CVAR_GAME ) {
   1141 					string += S_COLOR_WHITE "GAME ";
   1142 				} else if ( cvar->GetFlags() & CVAR_TOOL ) {
   1143 					string += S_COLOR_WHITE "TOOL ";
   1144 				} else {
   1145 					string += S_COLOR_WHITE "     ";
   1146 				}
   1147 				string += ( cvar->GetFlags() & CVAR_SERVERINFO ) ?	"SI "	: "   ";
   1148 				string += ( cvar->GetFlags() & CVAR_STATIC ) ?		"ST "	: "   ";
   1149 				string += ( cvar->GetFlags() & CVAR_CHEAT ) ?		"CH "	: "   ";
   1150 				string += ( cvar->GetFlags() & CVAR_INIT ) ?		"IN "	: "   ";
   1151 				string += ( cvar->GetFlags() & CVAR_ROM ) ?			"RO "	: "   ";
   1152 				string += ( cvar->GetFlags() & CVAR_ARCHIVE ) ?		"AR "	: "   ";
   1153 				string += ( cvar->GetFlags() & CVAR_MODIFIED ) ?	"MO "	: "   ";
   1154 				string += "\n";
   1155 				common->Printf( string );
   1156 			}
   1157 			break;
   1158 		}
   1159 	}
   1160 
   1161 	common->Printf( "\n%i cvars listed\n\n", cvarList.Num() );
   1162 	common->Printf(	"listCvar [search string]          = list cvar values\n"
   1163 				"listCvar -help [search string]    = list cvar descriptions\n"
   1164 				"listCvar -type [search string]    = list cvar types\n"
   1165 				"listCvar -flags [search string]   = list cvar flags\n" );
   1166 }
   1167 
   1168 /*
   1169 ============
   1170 idCVarSystemLocal::List_f
   1171 ============
   1172 */
   1173 void idCVarSystemLocal::List_f( const idCmdArgs &args ) {
   1174 	ListByFlags( args, CVAR_ALL );
   1175 }
   1176 
   1177 /*
   1178 ============
   1179 idCVarSystemLocal::Restart_f
   1180 ============
   1181 */
   1182 void idCVarSystemLocal::Restart_f( const idCmdArgs &args ) {
   1183 	int i, hash;
   1184 	idInternalCVar *cvar;
   1185 
   1186 	for ( i = 0; i < localCVarSystem.cvars.Num(); i++ ) {
   1187 		cvar = localCVarSystem.cvars[i];
   1188 
   1189 		// don't mess with rom values
   1190 		if ( cvar->flags & ( CVAR_ROM | CVAR_INIT ) ) {
   1191 			continue;
   1192 		}
   1193 
   1194 		// throw out any variables the user created
   1195 		if ( !( cvar->flags & CVAR_STATIC ) ) {
   1196 			hash = localCVarSystem.cvarHash.GenerateKey( cvar->nameString, false );
   1197 			delete cvar;
   1198 			localCVarSystem.cvars.RemoveIndex( i );
   1199 			localCVarSystem.cvarHash.RemoveIndex( hash, i );
   1200 			i--;
   1201 			continue;
   1202 		}
   1203 
   1204 		cvar->Reset();
   1205 	}
   1206 }