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