1 /*
2 ** c_cvars.cpp
3 ** Defines all the different console variable types
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 ** notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 ** notice, this list of conditions and the following disclaimer in the
17 ** documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 ** derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34
35 #include <string.h>
36 #include <stdio.h>
37 #include <assert.h>
38
39 #include "cmdlib.h"
40 #include "configfile.h"
41 #include "c_console.h"
42 #include "c_dispatch.h"
43
44 #include "doomstat.h"
45 #include "c_cvars.h"
46 #include "d_player.h"
47
48 #include "d_netinf.h"
49
50 #include "i_system.h"
51 #include "v_palette.h"
52 #include "v_video.h"
53 #include "colormatcher.h"
54
55 struct FLatchedValue
56 {
57 FBaseCVar *Variable;
58 UCVarValue Value;
59 ECVarType Type;
60 };
61
62 static TArray<FLatchedValue> LatchedValues;
63
64 bool FBaseCVar::m_DoNoSet = false;
65 bool FBaseCVar::m_UseCallback = false;
66
67 FBaseCVar *CVars = NULL;
68
69 int cvar_defflags;
70
FBaseCVar(const FBaseCVar & var)71 FBaseCVar::FBaseCVar (const FBaseCVar &var)
72 {
73 I_FatalError ("Use of cvar copy constructor");
74 }
75
FBaseCVar(const char * var_name,DWORD flags,void (* callback)(FBaseCVar &))76 FBaseCVar::FBaseCVar (const char *var_name, DWORD flags, void (*callback)(FBaseCVar &))
77 {
78 FBaseCVar *var;
79
80 var = FindCVar (var_name, NULL);
81
82 m_Callback = callback;
83 Flags = 0;
84 Name = NULL;
85
86 if (var_name)
87 {
88 C_AddTabCommand (var_name);
89 Name = copystring (var_name);
90 m_Next = CVars;
91 CVars = this;
92 }
93
94 if (var)
95 {
96 ECVarType type;
97 UCVarValue value;
98
99 value = var->GetFavoriteRep (&type);
100 ForceSet (value, type);
101
102 if (var->Flags & CVAR_AUTO)
103 delete var;
104 else
105 var->~FBaseCVar();
106
107 Flags = flags;
108 }
109 else
110 {
111 Flags = flags | CVAR_ISDEFAULT;
112 }
113 }
114
~FBaseCVar()115 FBaseCVar::~FBaseCVar ()
116 {
117 if (Name)
118 {
119 FBaseCVar *var, *prev;
120
121 var = FindCVar (Name, &prev);
122
123 if (var == this)
124 {
125 if (prev)
126 prev->m_Next = m_Next;
127 else
128 CVars = m_Next;
129 }
130 C_RemoveTabCommand(Name);
131 delete[] Name;
132 }
133 }
134
ForceSet(UCVarValue value,ECVarType type,bool nouserinfosend)135 void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend)
136 {
137 DoSet (value, type);
138 if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE))
139 D_UserInfoChanged (this);
140 if (m_UseCallback)
141 Callback ();
142
143 Flags &= ~CVAR_ISDEFAULT;
144 }
145
SetGenericRep(UCVarValue value,ECVarType type)146 void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type)
147 {
148 if ((Flags & CVAR_NOSET) && m_DoNoSet)
149 {
150 return;
151 }
152 else if ((Flags & CVAR_LATCH) && gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP)
153 {
154 FLatchedValue latch;
155
156 latch.Variable = this;
157 latch.Type = type;
158 if (type != CVAR_String)
159 latch.Value = value;
160 else
161 latch.Value.String = copystring(value.String);
162 LatchedValues.Push (latch);
163 }
164 else if ((Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
165 {
166 if (netgame && !players[consoleplayer].settings_controller)
167 {
168 Printf ("Only setting controllers can change %s\n", Name);
169 return;
170 }
171 D_SendServerInfoChange (this, value, type);
172 }
173 else
174 {
175 ForceSet (value, type);
176 }
177 }
178
ToBool(UCVarValue value,ECVarType type)179 bool FBaseCVar::ToBool (UCVarValue value, ECVarType type)
180 {
181 switch (type)
182 {
183 case CVAR_Bool:
184 return value.Bool;
185
186 case CVAR_Int:
187 return !!value.Int;
188
189 case CVAR_Float:
190 return value.Float != 0.f;
191
192 case CVAR_String:
193 if (stricmp (value.String, "true") == 0)
194 return true;
195 else if (stricmp (value.String, "false") == 0)
196 return false;
197 else
198 return !!strtol (value.String, NULL, 0);
199
200 case CVAR_GUID:
201 return false;
202
203 default:
204 return false;
205 }
206 }
207
ToInt(UCVarValue value,ECVarType type)208 int FBaseCVar::ToInt (UCVarValue value, ECVarType type)
209 {
210 int res;
211 #if __GNUC__ <= 2
212 float tmp;
213 #endif
214
215 switch (type)
216 {
217 case CVAR_Bool: res = (int)value.Bool; break;
218 case CVAR_Int: res = value.Int; break;
219 #if __GNUC__ <= 2
220 case CVAR_Float: tmp = value.Float; res = (int)tmp; break;
221 #else
222 case CVAR_Float: res = (int)value.Float; break;
223 #endif
224 case CVAR_String:
225 {
226 if (stricmp (value.String, "true") == 0)
227 res = 1;
228 else if (stricmp (value.String, "false") == 0)
229 res = 0;
230 else
231 res = strtol (value.String, NULL, 0);
232 break;
233 }
234 case CVAR_GUID: res = 0; break;
235 default: res = 0; break;
236 }
237 return res;
238 }
239
ToFloat(UCVarValue value,ECVarType type)240 float FBaseCVar::ToFloat (UCVarValue value, ECVarType type)
241 {
242 switch (type)
243 {
244 case CVAR_Bool:
245 return (float)value.Bool;
246
247 case CVAR_Int:
248 return (float)value.Int;
249
250 case CVAR_Float:
251 return value.Float;
252
253 case CVAR_String:
254 return (float)strtod (value.String, NULL);
255
256 case CVAR_GUID:
257 return 0.f;
258
259 default:
260 return 0.f;
261 }
262 }
263
264 static char cstrbuf[40];
265 static GUID cGUID;
266 static char truestr[] = "true";
267 static char falsestr[] = "false";
268
ToString(UCVarValue value,ECVarType type)269 const char *FBaseCVar::ToString (UCVarValue value, ECVarType type)
270 {
271 switch (type)
272 {
273 case CVAR_Bool:
274 return value.Bool ? truestr : falsestr;
275
276 case CVAR_String:
277 return value.String;
278
279 case CVAR_Int:
280 mysnprintf (cstrbuf, countof(cstrbuf), "%i", value.Int);
281 break;
282
283 case CVAR_Float:
284 mysnprintf (cstrbuf, countof(cstrbuf), "%g", value.Float);
285 break;
286
287 case CVAR_GUID:
288 FormatGUID (cstrbuf, countof(cstrbuf), *value.pGUID);
289 break;
290
291 default:
292 strcpy (cstrbuf, "<huh?>");
293 break;
294 }
295 return cstrbuf;
296 }
297
ToGUID(UCVarValue value,ECVarType type)298 const GUID *FBaseCVar::ToGUID (UCVarValue value, ECVarType type)
299 {
300 UCVarValue trans;
301
302 switch (type)
303 {
304 case CVAR_String:
305 trans = FromString (value.String, CVAR_GUID);
306 return trans.pGUID;
307
308 case CVAR_GUID:
309 return value.pGUID;
310
311 default:
312 return NULL;
313 }
314 }
315
FromBool(bool value,ECVarType type)316 UCVarValue FBaseCVar::FromBool (bool value, ECVarType type)
317 {
318 UCVarValue ret;
319
320 switch (type)
321 {
322 case CVAR_Bool:
323 ret.Bool = value;
324 break;
325
326 case CVAR_Int:
327 ret.Int = value;
328 break;
329
330 case CVAR_Float:
331 ret.Float = value;
332 break;
333
334 case CVAR_String:
335 ret.String = value ? truestr : falsestr;
336 break;
337
338 case CVAR_GUID:
339 ret.pGUID = NULL;
340 break;
341
342 default:
343 break;
344 }
345
346 return ret;
347 }
348
FromInt(int value,ECVarType type)349 UCVarValue FBaseCVar::FromInt (int value, ECVarType type)
350 {
351 UCVarValue ret;
352
353 switch (type)
354 {
355 case CVAR_Bool:
356 ret.Bool = value != 0;
357 break;
358
359 case CVAR_Int:
360 ret.Int = value;
361 break;
362
363 case CVAR_Float:
364 ret.Float = (float)value;
365 break;
366
367 case CVAR_String:
368 mysnprintf (cstrbuf, countof(cstrbuf), "%i", value);
369 ret.String = cstrbuf;
370 break;
371
372 case CVAR_GUID:
373 ret.pGUID = NULL;
374 break;
375
376 default:
377 break;
378 }
379
380 return ret;
381 }
382
FromFloat(float value,ECVarType type)383 UCVarValue FBaseCVar::FromFloat (float value, ECVarType type)
384 {
385 UCVarValue ret;
386
387 switch (type)
388 {
389 case CVAR_Bool:
390 ret.Bool = value != 0.f;
391 break;
392
393 case CVAR_Int:
394 ret.Int = (int)value;
395 break;
396
397 case CVAR_Float:
398 ret.Float = value;
399 break;
400
401 case CVAR_String:
402 mysnprintf (cstrbuf, countof(cstrbuf), "%g", value);
403 ret.String = cstrbuf;
404 break;
405
406 case CVAR_GUID:
407 ret.pGUID = NULL;
408 break;
409
410 default:
411 break;
412 }
413
414 return ret;
415 }
416
HexToByte(const char * hex)417 static BYTE HexToByte (const char *hex)
418 {
419 BYTE v = 0;
420 for (int i = 0; i < 2; ++i)
421 {
422 v <<= 4;
423 if (hex[i] >= '0' && hex[i] <= '9')
424 {
425 v += hex[i] - '0';
426 }
427 else if (hex[i] >= 'A' && hex[i] <= 'F')
428 {
429 v += hex[i] - 'A';
430 }
431 else // The string is already verified to contain valid hexits
432 {
433 v += hex[i] - 'a';
434 }
435 }
436 return v;
437 }
438
FromString(const char * value,ECVarType type)439 UCVarValue FBaseCVar::FromString (const char *value, ECVarType type)
440 {
441 UCVarValue ret;
442 int i;
443
444 switch (type)
445 {
446 case CVAR_Bool:
447 if (stricmp (value, "true") == 0)
448 ret.Bool = true;
449 else if (stricmp (value, "false") == 0)
450 ret.Bool = false;
451 else
452 ret.Bool = strtol (value, NULL, 0) != 0;
453 break;
454
455 case CVAR_Int:
456 if (stricmp (value, "true") == 0)
457 ret.Int = 1;
458 else if (stricmp (value, "false") == 0)
459 ret.Int = 0;
460 else
461 ret.Int = strtol (value, NULL, 0);
462 break;
463
464 case CVAR_Float:
465 ret.Float = (float)strtod (value, NULL);
466 break;
467
468 case CVAR_String:
469 ret.String = const_cast<char *>(value);
470 break;
471
472 case CVAR_GUID:
473 // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
474 // 01234567890123456789012345678901234567
475 // 0 1 2 3
476
477 ret.pGUID = NULL;
478 if (value == NULL)
479 {
480 break;
481 }
482 for (i = 0; value[i] != 0 && i < 38; i++)
483 {
484 switch (i)
485 {
486 case 0:
487 if (value[i] != '{')
488 break;
489 case 9:
490 case 14:
491 case 19:
492 case 24:
493 if (value[i] != '-')
494 break;
495 case 37:
496 if (value[i] != '}')
497 break;
498 default:
499 if (value[i] < '0' ||
500 (value[i] > '9' && value[i] < 'A') ||
501 (value[i] > 'F' && value[i] < 'a') ||
502 value[i] > 'f')
503 break;
504 }
505 }
506 if (i == 38 && value[i] == 0)
507 {
508 cGUID.Data1 = strtoul (value + 1, NULL, 16);
509 cGUID.Data2 = (WORD)strtoul (value + 10, NULL, 16);
510 cGUID.Data3 = (WORD)strtoul (value + 15, NULL, 16);
511 cGUID.Data4[0] = HexToByte (value + 20);
512 cGUID.Data4[1] = HexToByte (value + 22);
513 cGUID.Data4[2] = HexToByte (value + 25);
514 cGUID.Data4[3] = HexToByte (value + 27);
515 cGUID.Data4[4] = HexToByte (value + 29);
516 cGUID.Data4[5] = HexToByte (value + 31);
517 cGUID.Data4[6] = HexToByte (value + 33);
518 cGUID.Data4[7] = HexToByte (value + 35);
519 ret.pGUID = &cGUID;
520 }
521 break;
522
523 default:
524 break;
525 }
526
527 return ret;
528 }
529
FromGUID(const GUID & guid,ECVarType type)530 UCVarValue FBaseCVar::FromGUID (const GUID &guid, ECVarType type)
531 {
532 UCVarValue ret;
533
534 switch (type)
535 {
536 case CVAR_Bool:
537 ret.Bool = false;
538 break;
539
540 case CVAR_Int:
541 ret.Int = 0;
542 break;
543
544 case CVAR_Float:
545 ret.Float = 0.f;
546 break;
547
548 case CVAR_String:
549 ret.pGUID = &guid;
550 ret.String = ToString (ret, CVAR_GUID);
551 break;
552
553 case CVAR_GUID:
554 ret.pGUID = &guid;
555 break;
556
557 default:
558 break;
559 }
560
561 return ret;
562 }
cvar_set(const char * var_name,const char * val)563 FBaseCVar *cvar_set (const char *var_name, const char *val)
564 {
565 FBaseCVar *var;
566
567 if ( (var = FindCVar (var_name, NULL)) )
568 {
569 UCVarValue value;
570 value.String = const_cast<char *>(val);
571 var->SetGenericRep (value, CVAR_String);
572 }
573
574 return var;
575 }
576
cvar_forceset(const char * var_name,const char * val)577 FBaseCVar *cvar_forceset (const char *var_name, const char *val)
578 {
579 FBaseCVar *var;
580 UCVarValue vval;
581
582 if ( (var = FindCVar (var_name, NULL)) )
583 {
584 vval.String = const_cast<char *>(val);
585 var->ForceSet (vval, CVAR_String);
586 }
587
588 return var;
589 }
590
EnableNoSet()591 void FBaseCVar::EnableNoSet ()
592 {
593 m_DoNoSet = true;
594 }
595
EnableCallbacks()596 void FBaseCVar::EnableCallbacks ()
597 {
598 m_UseCallback = true;
599 FBaseCVar *cvar = CVars;
600
601 while (cvar)
602 {
603 if (!(cvar->Flags & CVAR_NOINITCALL))
604 {
605 cvar->Callback ();
606 }
607 cvar = cvar->m_Next;
608 }
609 }
610
DisableCallbacks()611 void FBaseCVar::DisableCallbacks ()
612 {
613 m_UseCallback = false;
614 }
615
616 //
617 // Boolean cvar implementation
618 //
619
FBoolCVar(const char * name,bool def,DWORD flags,void (* callback)(FBoolCVar &))620 FBoolCVar::FBoolCVar (const char *name, bool def, DWORD flags, void (*callback)(FBoolCVar &))
621 : FBaseCVar (name, flags, reinterpret_cast<void (*)(FBaseCVar &)>(callback))
622 {
623 DefaultValue = def;
624 if (Flags & CVAR_ISDEFAULT)
625 Value = def;
626 }
627
GetRealType() const628 ECVarType FBoolCVar::GetRealType () const
629 {
630 return CVAR_Bool;
631 }
632
GetGenericRep(ECVarType type) const633 UCVarValue FBoolCVar::GetGenericRep (ECVarType type) const
634 {
635 return FromBool (Value, type);
636 }
637
GetFavoriteRep(ECVarType * type) const638 UCVarValue FBoolCVar::GetFavoriteRep (ECVarType *type) const
639 {
640 UCVarValue ret;
641 *type = CVAR_Bool;
642 ret.Bool = Value;
643 return ret;
644 }
645
GetGenericRepDefault(ECVarType type) const646 UCVarValue FBoolCVar::GetGenericRepDefault (ECVarType type) const
647 {
648 return FromBool (DefaultValue, type);
649 }
650
GetFavoriteRepDefault(ECVarType * type) const651 UCVarValue FBoolCVar::GetFavoriteRepDefault (ECVarType *type) const
652 {
653 UCVarValue ret;
654 *type = CVAR_Bool;
655 ret.Bool = DefaultValue;
656 return ret;
657 }
658
SetGenericRepDefault(UCVarValue value,ECVarType type)659 void FBoolCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
660 {
661 DefaultValue = ToBool (value, type);
662 if (Flags & CVAR_ISDEFAULT)
663 {
664 SetGenericRep (value, type);
665 Flags |= CVAR_ISDEFAULT;
666 }
667 }
668
DoSet(UCVarValue value,ECVarType type)669 void FBoolCVar::DoSet (UCVarValue value, ECVarType type)
670 {
671 Value = ToBool (value, type);
672 }
673
674 //
675 // Integer cvar implementation
676 //
677
FIntCVar(const char * name,int def,DWORD flags,void (* callback)(FIntCVar &))678 FIntCVar::FIntCVar (const char *name, int def, DWORD flags, void (*callback)(FIntCVar &))
679 : FBaseCVar (name, flags, reinterpret_cast<void (*)(FBaseCVar &)>(callback))
680 {
681 DefaultValue = def;
682 if (Flags & CVAR_ISDEFAULT)
683 Value = def;
684 }
685
GetRealType() const686 ECVarType FIntCVar::GetRealType () const
687 {
688 return CVAR_Int;
689 }
690
GetGenericRep(ECVarType type) const691 UCVarValue FIntCVar::GetGenericRep (ECVarType type) const
692 {
693 return FromInt (Value, type);
694 }
695
GetFavoriteRep(ECVarType * type) const696 UCVarValue FIntCVar::GetFavoriteRep (ECVarType *type) const
697 {
698 UCVarValue ret;
699 *type = CVAR_Int;
700 ret.Int = Value;
701 return ret;
702 }
703
GetGenericRepDefault(ECVarType type) const704 UCVarValue FIntCVar::GetGenericRepDefault (ECVarType type) const
705 {
706 return FromInt (DefaultValue, type);
707 }
708
GetFavoriteRepDefault(ECVarType * type) const709 UCVarValue FIntCVar::GetFavoriteRepDefault (ECVarType *type) const
710 {
711 UCVarValue ret;
712 *type = CVAR_Int;
713 ret.Int = DefaultValue;
714 return ret;
715 }
716
SetGenericRepDefault(UCVarValue value,ECVarType type)717 void FIntCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
718 {
719 DefaultValue = ToInt (value, type);
720 if (Flags & CVAR_ISDEFAULT)
721 {
722 SetGenericRep (value, type);
723 Flags |= CVAR_ISDEFAULT;
724 }
725 }
726
DoSet(UCVarValue value,ECVarType type)727 void FIntCVar::DoSet (UCVarValue value, ECVarType type)
728 {
729 Value = ToInt (value, type);
730 }
731
732 //
733 // Floating point cvar implementation
734 //
735
FFloatCVar(const char * name,float def,DWORD flags,void (* callback)(FFloatCVar &))736 FFloatCVar::FFloatCVar (const char *name, float def, DWORD flags, void (*callback)(FFloatCVar &))
737 : FBaseCVar (name, flags, reinterpret_cast<void (*)(FBaseCVar &)>(callback))
738 {
739 DefaultValue = def;
740 if (Flags & CVAR_ISDEFAULT)
741 Value = def;
742 }
743
GetRealType() const744 ECVarType FFloatCVar::GetRealType () const
745 {
746 return CVAR_Float;
747 }
748
GetGenericRep(ECVarType type) const749 UCVarValue FFloatCVar::GetGenericRep (ECVarType type) const
750 {
751 return FromFloat (Value, type);
752 }
753
GetFavoriteRep(ECVarType * type) const754 UCVarValue FFloatCVar::GetFavoriteRep (ECVarType *type) const
755 {
756 UCVarValue ret;
757 *type = CVAR_Float;
758 ret.Float = Value;
759 return ret;
760 }
761
GetGenericRepDefault(ECVarType type) const762 UCVarValue FFloatCVar::GetGenericRepDefault (ECVarType type) const
763 {
764 return FromFloat (DefaultValue, type);
765 }
766
GetFavoriteRepDefault(ECVarType * type) const767 UCVarValue FFloatCVar::GetFavoriteRepDefault (ECVarType *type) const
768 {
769 UCVarValue ret;
770 *type = CVAR_Float;
771 ret.Float = DefaultValue;
772 return ret;
773 }
774
SetGenericRepDefault(UCVarValue value,ECVarType type)775 void FFloatCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
776 {
777 DefaultValue = ToFloat (value, type);
778 if (Flags & CVAR_ISDEFAULT)
779 {
780 SetGenericRep (value, type);
781 Flags |= CVAR_ISDEFAULT;
782 }
783 }
784
DoSet(UCVarValue value,ECVarType type)785 void FFloatCVar::DoSet (UCVarValue value, ECVarType type)
786 {
787 Value = ToFloat (value, type);
788 }
789
790 //
791 // String cvar implementation
792 //
793
FStringCVar(const char * name,const char * def,DWORD flags,void (* callback)(FStringCVar &))794 FStringCVar::FStringCVar (const char *name, const char *def, DWORD flags, void (*callback)(FStringCVar &))
795 : FBaseCVar (name, flags, reinterpret_cast<void (*)(FBaseCVar &)>(callback))
796 {
797 DefaultValue = copystring (def);
798 if (Flags & CVAR_ISDEFAULT)
799 Value = copystring (def);
800 else
801 Value = NULL;
802 }
803
~FStringCVar()804 FStringCVar::~FStringCVar ()
805 {
806 if (Value != NULL)
807 {
808 delete[] Value;
809 }
810 delete[] DefaultValue;
811 }
812
GetRealType() const813 ECVarType FStringCVar::GetRealType () const
814 {
815 return CVAR_String;
816 }
817
GetGenericRep(ECVarType type) const818 UCVarValue FStringCVar::GetGenericRep (ECVarType type) const
819 {
820 return FromString (Value, type);
821 }
822
GetFavoriteRep(ECVarType * type) const823 UCVarValue FStringCVar::GetFavoriteRep (ECVarType *type) const
824 {
825 UCVarValue ret;
826 *type = CVAR_String;
827 ret.String = Value;
828 return ret;
829 }
830
GetGenericRepDefault(ECVarType type) const831 UCVarValue FStringCVar::GetGenericRepDefault (ECVarType type) const
832 {
833 return FromString (DefaultValue, type);
834 }
835
GetFavoriteRepDefault(ECVarType * type) const836 UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const
837 {
838 UCVarValue ret;
839 *type = CVAR_String;
840 ret.String = DefaultValue;
841 return ret;
842 }
843
SetGenericRepDefault(UCVarValue value,ECVarType type)844 void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
845 {
846 ReplaceString(&DefaultValue, ToString(value, type));
847 if (Flags & CVAR_ISDEFAULT)
848 {
849 SetGenericRep (value, type);
850 Flags |= CVAR_ISDEFAULT;
851 }
852 }
853
DoSet(UCVarValue value,ECVarType type)854 void FStringCVar::DoSet (UCVarValue value, ECVarType type)
855 {
856 ReplaceString (&Value, ToString (value, type));
857 }
858
859 //
860 // Color cvar implementation
861 //
862
FColorCVar(const char * name,int def,DWORD flags,void (* callback)(FColorCVar &))863 FColorCVar::FColorCVar (const char *name, int def, DWORD flags, void (*callback)(FColorCVar &))
864 : FIntCVar (name, def, flags, reinterpret_cast<void (*)(FIntCVar &)>(callback))
865 {
866 }
867
GetRealType() const868 ECVarType FColorCVar::GetRealType () const
869 {
870 return CVAR_Color;
871 }
872
GetGenericRep(ECVarType type) const873 UCVarValue FColorCVar::GetGenericRep (ECVarType type) const
874 {
875 return FromInt2 (Value, type);
876 }
877
GetGenericRepDefault(ECVarType type) const878 UCVarValue FColorCVar::GetGenericRepDefault (ECVarType type) const
879 {
880 return FromInt2 (DefaultValue, type);
881 }
882
SetGenericRepDefault(UCVarValue value,ECVarType type)883 void FColorCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
884 {
885 DefaultValue = ToInt2 (value, type);
886 if (Flags & CVAR_ISDEFAULT)
887 {
888 SetGenericRep (value, type);
889 Flags |= CVAR_ISDEFAULT;
890 }
891 }
892
DoSet(UCVarValue value,ECVarType type)893 void FColorCVar::DoSet (UCVarValue value, ECVarType type)
894 {
895 Value = ToInt2 (value, type);
896 if (screen)
897 Index = ColorMatcher.Pick (RPART(Value), GPART(Value), BPART(Value));
898 }
899
FromInt2(int value,ECVarType type)900 UCVarValue FColorCVar::FromInt2 (int value, ECVarType type)
901 {
902 if (type == CVAR_String)
903 {
904 UCVarValue ret;
905 mysnprintf (cstrbuf, countof(cstrbuf), "%02x %02x %02x",
906 RPART(value), GPART(value), BPART(value));
907 ret.String = cstrbuf;
908 return ret;
909 }
910 return FromInt (value, type);
911 }
912
ToInt2(UCVarValue value,ECVarType type)913 int FColorCVar::ToInt2 (UCVarValue value, ECVarType type)
914 {
915 int ret;
916
917 if (type == CVAR_String)
918 {
919 FString string;
920 // Only allow named colors after the screen exists (i.e. after
921 // we've got some lumps loaded, so X11R6RGB can be read). Since
922 // the only time this might be called before that is when loading
923 // zdoom.ini, this shouldn't be a problem.
924 if (screen && !(string = V_GetColorStringByName (value.String)).IsEmpty() )
925 {
926 ret = V_GetColorFromString (NULL, string);
927 }
928 else
929 {
930 ret = V_GetColorFromString (NULL, value.String);
931 }
932 }
933 else
934 {
935 ret = ToInt (value, type);
936 }
937 return ret;
938 }
939
940 //
941 // GUID cvar implementation
942 //
943
FGUIDCVar(const char * name,const GUID * def,DWORD flags,void (* callback)(FGUIDCVar &))944 FGUIDCVar::FGUIDCVar (const char *name, const GUID *def, DWORD flags, void (*callback)(FGUIDCVar &))
945 : FBaseCVar (name, flags, reinterpret_cast<void (*)(FBaseCVar &)>(callback))
946 {
947 if (def != NULL)
948 {
949 DefaultValue = *def;
950 if (Flags & CVAR_ISDEFAULT)
951 Value = *def;
952 }
953 else
954 {
955 memset (&Value, 0, sizeof(DefaultValue));
956 memset (&DefaultValue, 0, sizeof(DefaultValue));
957 }
958 }
959
GetRealType() const960 ECVarType FGUIDCVar::GetRealType () const
961 {
962 return CVAR_GUID;
963 }
964
GetGenericRep(ECVarType type) const965 UCVarValue FGUIDCVar::GetGenericRep (ECVarType type) const
966 {
967 return FromGUID (Value, type);
968 }
969
GetFavoriteRep(ECVarType * type) const970 UCVarValue FGUIDCVar::GetFavoriteRep (ECVarType *type) const
971 {
972 UCVarValue ret;
973 *type = CVAR_GUID;
974 ret.pGUID = &Value;
975 return ret;
976 }
977
GetGenericRepDefault(ECVarType type) const978 UCVarValue FGUIDCVar::GetGenericRepDefault (ECVarType type) const
979 {
980 return FromGUID (DefaultValue, type);
981 }
982
GetFavoriteRepDefault(ECVarType * type) const983 UCVarValue FGUIDCVar::GetFavoriteRepDefault (ECVarType *type) const
984 {
985 UCVarValue ret;
986 *type = CVAR_GUID;
987 ret.pGUID = &DefaultValue;
988 return ret;
989 }
990
SetGenericRepDefault(UCVarValue value,ECVarType type)991 void FGUIDCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
992 {
993 const GUID *guid = ToGUID (value, type);
994 if (guid != NULL)
995 {
996 Value = *guid;
997 if (Flags & CVAR_ISDEFAULT)
998 {
999 SetGenericRep (value, type);
1000 Flags |= CVAR_ISDEFAULT;
1001 }
1002 }
1003 }
1004
DoSet(UCVarValue value,ECVarType type)1005 void FGUIDCVar::DoSet (UCVarValue value, ECVarType type)
1006 {
1007 const GUID *guid = ToGUID (value, type);
1008 if (guid != NULL)
1009 {
1010 Value = *guid;
1011 }
1012 }
1013
1014 //
1015 // More base cvar stuff
1016 //
1017
ResetColors()1018 void FBaseCVar::ResetColors ()
1019 {
1020 FBaseCVar *var = CVars;
1021
1022 while (var)
1023 {
1024 if (var->GetRealType () == CVAR_Color)
1025 {
1026 var->DoSet (var->GetGenericRep (CVAR_Int), CVAR_Int);
1027 }
1028 var = var->m_Next;
1029 }
1030 }
1031
ResetToDefault()1032 void FBaseCVar::ResetToDefault ()
1033 {
1034 if (!(Flags & CVAR_ISDEFAULT))
1035 {
1036 UCVarValue val;
1037 ECVarType type;
1038
1039 val = GetFavoriteRepDefault (&type);
1040 SetGenericRep (val, type);
1041 Flags |= CVAR_ISDEFAULT;
1042 }
1043 }
1044
1045 //
1046 // Flag cvar implementation
1047 //
1048 // This type of cvar is not a "real" cvar. Instead, it gets and sets
1049 // the value of a FIntCVar, modifying it bit-by-bit. As such, it has
1050 // no default, and is not written to the .cfg or transferred around
1051 // the network. The "host" cvar is responsible for that.
1052 //
1053
FFlagCVar(const char * name,FIntCVar & realvar,DWORD bitval)1054 FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, DWORD bitval)
1055 : FBaseCVar (name, 0, NULL),
1056 ValueVar (realvar),
1057 BitVal (bitval)
1058 {
1059 int bit;
1060
1061 Flags &= ~CVAR_ISDEFAULT;
1062
1063 assert (bitval != 0);
1064
1065 bit = 0;
1066 while ((bitval >>= 1) != 0)
1067 {
1068 ++bit;
1069 }
1070 BitNum = bit;
1071
1072 assert ((1u << BitNum) == BitVal);
1073 }
1074
GetRealType() const1075 ECVarType FFlagCVar::GetRealType () const
1076 {
1077 return CVAR_Dummy;
1078 }
1079
GetGenericRep(ECVarType type) const1080 UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const
1081 {
1082 return FromBool ((ValueVar & BitVal) != 0, type);
1083 }
1084
GetFavoriteRep(ECVarType * type) const1085 UCVarValue FFlagCVar::GetFavoriteRep (ECVarType *type) const
1086 {
1087 UCVarValue ret;
1088 *type = CVAR_Bool;
1089 ret.Bool = (ValueVar & BitVal) != 0;
1090 return ret;
1091 }
1092
GetGenericRepDefault(ECVarType type) const1093 UCVarValue FFlagCVar::GetGenericRepDefault (ECVarType type) const
1094 {
1095 ECVarType dummy;
1096 UCVarValue def;
1097 def = ValueVar.GetFavoriteRepDefault (&dummy);
1098 return FromBool ((def.Int & BitVal) != 0, type);
1099 }
1100
GetFavoriteRepDefault(ECVarType * type) const1101 UCVarValue FFlagCVar::GetFavoriteRepDefault (ECVarType *type) const
1102 {
1103 ECVarType dummy;
1104 UCVarValue def;
1105 def = ValueVar.GetFavoriteRepDefault (&dummy);
1106 def.Bool = (def.Int & BitVal) != 0;
1107 *type = CVAR_Bool;
1108 return def;
1109 }
1110
SetGenericRepDefault(UCVarValue value,ECVarType type)1111 void FFlagCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
1112 {
1113 bool newdef = ToBool (value, type);
1114 ECVarType dummy;
1115 UCVarValue def;
1116 def = ValueVar.GetFavoriteRepDefault (&dummy);
1117 if (newdef)
1118 def.Int |= BitVal;
1119 else
1120 def.Int &= ~BitVal;
1121 ValueVar.SetGenericRepDefault (def, CVAR_Int);
1122 }
1123
DoSet(UCVarValue value,ECVarType type)1124 void FFlagCVar::DoSet (UCVarValue value, ECVarType type)
1125 {
1126 bool newval = ToBool (value, type);
1127
1128 // Server cvars that get changed by this need to use a special message, because
1129 // changes are not processed until the next net update. This is a problem with
1130 // exec scripts because all flags will base their changes off of the value of
1131 // the "master" cvar at the time the script was run, overriding any changes
1132 // another flag might have made to the same cvar earlier in the script.
1133 if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
1134 {
1135 if (netgame && !players[consoleplayer].settings_controller)
1136 {
1137 Printf ("Only setting controllers can change %s\n", Name);
1138 return;
1139 }
1140 D_SendServerFlagChange (&ValueVar, BitNum, newval);
1141 }
1142 else
1143 {
1144 int val = *ValueVar;
1145 if (newval)
1146 val |= BitVal;
1147 else
1148 val &= ~BitVal;
1149 ValueVar = val;
1150 }
1151 }
1152
1153 //
1154 // Mask cvar implementation
1155 //
1156 // Similar to FFlagCVar but can have multiple bits
1157 //
1158
FMaskCVar(const char * name,FIntCVar & realvar,DWORD bitval)1159 FMaskCVar::FMaskCVar (const char *name, FIntCVar &realvar, DWORD bitval)
1160 : FBaseCVar (name, 0, NULL),
1161 ValueVar (realvar),
1162 BitVal (bitval)
1163 {
1164 int bit;
1165
1166 Flags &= ~CVAR_ISDEFAULT;
1167
1168 assert (bitval != 0);
1169
1170 bit = 0;
1171 while ((bitval & 1) == 0)
1172 {
1173 ++bit;
1174 bitval >>= 1;
1175 }
1176 BitNum = bit;
1177 }
1178
GetRealType() const1179 ECVarType FMaskCVar::GetRealType () const
1180 {
1181 return CVAR_Dummy;
1182 }
1183
GetGenericRep(ECVarType type) const1184 UCVarValue FMaskCVar::GetGenericRep (ECVarType type) const
1185 {
1186 return FromInt ((ValueVar & BitVal) >> BitNum, type);
1187 }
1188
GetFavoriteRep(ECVarType * type) const1189 UCVarValue FMaskCVar::GetFavoriteRep (ECVarType *type) const
1190 {
1191 UCVarValue ret;
1192 *type = CVAR_Int;
1193 ret.Int = (ValueVar & BitVal) >> BitNum;
1194 return ret;
1195 }
1196
GetGenericRepDefault(ECVarType type) const1197 UCVarValue FMaskCVar::GetGenericRepDefault (ECVarType type) const
1198 {
1199 ECVarType dummy;
1200 UCVarValue def;
1201 def = ValueVar.GetFavoriteRepDefault (&dummy);
1202 return FromInt ((def.Int & BitVal) >> BitNum, type);
1203 }
1204
GetFavoriteRepDefault(ECVarType * type) const1205 UCVarValue FMaskCVar::GetFavoriteRepDefault (ECVarType *type) const
1206 {
1207 ECVarType dummy;
1208 UCVarValue def;
1209 def = ValueVar.GetFavoriteRepDefault (&dummy);
1210 def.Int = (def.Int & BitVal) >> BitNum;
1211 *type = CVAR_Int;
1212 return def;
1213 }
1214
SetGenericRepDefault(UCVarValue value,ECVarType type)1215 void FMaskCVar::SetGenericRepDefault (UCVarValue value, ECVarType type)
1216 {
1217 int val = ToInt(value, type) << BitNum;
1218 ECVarType dummy;
1219 UCVarValue def;
1220 def = ValueVar.GetFavoriteRepDefault (&dummy);
1221 def.Int &= ~BitVal;
1222 def.Int |= val;
1223 ValueVar.SetGenericRepDefault (def, CVAR_Int);
1224 }
1225
DoSet(UCVarValue value,ECVarType type)1226 void FMaskCVar::DoSet (UCVarValue value, ECVarType type)
1227 {
1228 int val = ToInt(value, type) << BitNum;
1229
1230 // Server cvars that get changed by this need to use a special message, because
1231 // changes are not processed until the next net update. This is a problem with
1232 // exec scripts because all flags will base their changes off of the value of
1233 // the "master" cvar at the time the script was run, overriding any changes
1234 // another flag might have made to the same cvar earlier in the script.
1235 if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback)
1236 {
1237 if (netgame && !players[consoleplayer].settings_controller)
1238 {
1239 Printf ("Only setting controllers can change %s\n", Name);
1240 return;
1241 }
1242 // Ugh...
1243 for(int i = 0; i < 32; i++)
1244 {
1245 if (BitVal & (1<<i))
1246 {
1247 D_SendServerFlagChange (&ValueVar, i, !!(val & (1<<i)));
1248 }
1249 }
1250 }
1251 else
1252 {
1253 int vval = *ValueVar;
1254 vval &= ~BitVal;
1255 vval |= val;
1256 ValueVar = vval;
1257 }
1258 }
1259
1260
1261 ////////////////////////////////////////////////////////////////////////
sortcvars(const void * a,const void * b)1262 static int STACK_ARGS sortcvars (const void *a, const void *b)
1263 {
1264 return strcmp (((*(FBaseCVar **)a))->GetName(), ((*(FBaseCVar **)b))->GetName());
1265 }
1266
FilterCompactCVars(TArray<FBaseCVar * > & cvars,DWORD filter)1267 void FilterCompactCVars (TArray<FBaseCVar *> &cvars, DWORD filter)
1268 {
1269 // Accumulate all cvars that match the filter flags.
1270 for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
1271 {
1272 if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE))
1273 cvars.Push(cvar);
1274 }
1275 // Now sort them, so they're in a deterministic order and not whatever
1276 // order the linker put them in.
1277 if (cvars.Size() > 0)
1278 {
1279 qsort(&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars);
1280 }
1281 }
1282
C_WriteCVars(BYTE ** demo_p,DWORD filter,bool compact)1283 void C_WriteCVars (BYTE **demo_p, DWORD filter, bool compact)
1284 {
1285 FString dump = C_GetMassCVarString(filter, compact);
1286 size_t dumplen = dump.Len() + 1; // include terminating \0
1287 memcpy(*demo_p, dump.GetChars(), dumplen);
1288 *demo_p += dumplen;
1289 }
1290
C_GetMassCVarString(DWORD filter,bool compact)1291 FString C_GetMassCVarString (DWORD filter, bool compact)
1292 {
1293 FBaseCVar *cvar;
1294 FString dump;
1295
1296 if (compact)
1297 {
1298 TArray<FBaseCVar *> cvars;
1299 dump.AppendFormat("\\\\%ux", filter);
1300 FilterCompactCVars(cvars, filter);
1301 while (cvars.Pop (cvar))
1302 {
1303 UCVarValue val = cvar->GetGenericRep(CVAR_String);
1304 dump << '\\' << val.String;
1305 }
1306 }
1307 else
1308 {
1309 for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
1310 {
1311 if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE)))
1312 {
1313 UCVarValue val = cvar->GetGenericRep(CVAR_String);
1314 dump << '\\' << cvar->GetName() << '\\' << val.String;
1315 }
1316 }
1317 }
1318 return dump;
1319 }
1320
C_ReadCVars(BYTE ** demo_p)1321 void C_ReadCVars (BYTE **demo_p)
1322 {
1323 char *ptr = *((char **)demo_p);
1324 char *breakpt;
1325
1326 if (*ptr++ != '\\')
1327 return;
1328
1329 if (*ptr == '\\')
1330 { // compact mode
1331 TArray<FBaseCVar *> cvars;
1332 FBaseCVar *cvar;
1333 DWORD filter;
1334
1335 ptr++;
1336 breakpt = strchr (ptr, '\\');
1337 *breakpt = 0;
1338 filter = strtoul (ptr, NULL, 16);
1339 *breakpt = '\\';
1340 ptr = breakpt + 1;
1341
1342 FilterCompactCVars (cvars, filter);
1343
1344 while (cvars.Pop (cvar))
1345 {
1346 UCVarValue val;
1347 breakpt = strchr (ptr, '\\');
1348 if (breakpt)
1349 *breakpt = 0;
1350 val.String = ptr;
1351 cvar->ForceSet (val, CVAR_String);
1352 if (breakpt)
1353 {
1354 *breakpt = '\\';
1355 ptr = breakpt + 1;
1356 }
1357 else
1358 break;
1359 }
1360 }
1361 else
1362 {
1363 char *value;
1364
1365 while ( (breakpt = strchr (ptr, '\\')) )
1366 {
1367 *breakpt = 0;
1368 value = breakpt + 1;
1369 if ( (breakpt = strchr (value, '\\')) )
1370 *breakpt = 0;
1371
1372 cvar_set (ptr, value);
1373
1374 *(value - 1) = '\\';
1375 if (breakpt)
1376 {
1377 *breakpt = '\\';
1378 ptr = breakpt + 1;
1379 }
1380 else
1381 {
1382 break;
1383 }
1384 }
1385 }
1386 *demo_p += strlen (*((char **)demo_p)) + 1;
1387 }
1388
1389 struct FCVarBackup
1390 {
1391 FString Name, String;
1392 };
1393 static TArray<FCVarBackup> CVarBackups;
1394
C_BackupCVars(void)1395 void C_BackupCVars (void)
1396 {
1397 assert(CVarBackups.Size() == 0);
1398 CVarBackups.Clear();
1399
1400 FCVarBackup backup;
1401
1402 for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next)
1403 {
1404 if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) && !(cvar->Flags & CVAR_LATCH))
1405 {
1406 backup.Name = cvar->GetName();
1407 backup.String = cvar->GetGenericRep(CVAR_String).String;
1408 CVarBackups.Push(backup);
1409 }
1410 }
1411 }
1412
C_RestoreCVars(void)1413 void C_RestoreCVars (void)
1414 {
1415 for (unsigned int i = 0; i < CVarBackups.Size(); ++i)
1416 {
1417 cvar_set(CVarBackups[i].Name, CVarBackups[i].String);
1418 }
1419 C_ForgetCVars();
1420 }
1421
C_ForgetCVars(void)1422 void C_ForgetCVars (void)
1423 {
1424 CVarBackups.Clear();
1425 }
1426
FindCVar(const char * var_name,FBaseCVar ** prev)1427 FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev)
1428 {
1429 FBaseCVar *var;
1430 FBaseCVar *dummy;
1431
1432 if (var_name == NULL)
1433 return NULL;
1434
1435 if (prev == NULL)
1436 prev = &dummy;
1437
1438 var = CVars;
1439 *prev = NULL;
1440 while (var)
1441 {
1442 if (stricmp (var->GetName (), var_name) == 0)
1443 break;
1444 *prev = var;
1445 var = var->m_Next;
1446 }
1447 return var;
1448 }
1449
FindCVarSub(const char * var_name,int namelen)1450 FBaseCVar *FindCVarSub (const char *var_name, int namelen)
1451 {
1452 FBaseCVar *var;
1453
1454 if (var_name == NULL)
1455 return NULL;
1456
1457 var = CVars;
1458 while (var)
1459 {
1460 const char *probename = var->GetName ();
1461
1462 if (strnicmp (probename, var_name, namelen) == 0 &&
1463 probename[namelen] == 0)
1464 {
1465 break;
1466 }
1467 var = var->m_Next;
1468 }
1469 return var;
1470 }
1471
1472 //===========================================================================
1473 //
1474 // C_CreateCVar
1475 //
1476 // Create a new cvar with the specified name and type. It should not already
1477 // exist.
1478 //
1479 //===========================================================================
1480
C_CreateCVar(const char * var_name,ECVarType var_type,DWORD flags)1481 FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags)
1482 {
1483 assert(FindCVar(var_name, NULL) == NULL);
1484 flags |= CVAR_AUTO;
1485 switch (var_type)
1486 {
1487 case CVAR_Bool: return new FBoolCVar(var_name, 0, flags);
1488 case CVAR_Int: return new FIntCVar(var_name, 0, flags);
1489 case CVAR_Float: return new FFloatCVar(var_name, 0, flags);
1490 case CVAR_String: return new FStringCVar(var_name, NULL, flags);
1491 case CVAR_Color: return new FColorCVar(var_name, 0, flags);
1492 default: return NULL;
1493 }
1494 }
1495
UnlatchCVars(void)1496 void UnlatchCVars (void)
1497 {
1498 FLatchedValue var;
1499
1500 while (LatchedValues.Pop (var))
1501 {
1502 DWORD oldflags = var.Variable->Flags;
1503 var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO);
1504 var.Variable->SetGenericRep (var.Value, var.Type);
1505 if (var.Type == CVAR_String)
1506 delete[] var.Value.String;
1507 var.Variable->Flags = oldflags;
1508 }
1509 }
1510
DestroyCVarsFlagged(DWORD flags)1511 void DestroyCVarsFlagged (DWORD flags)
1512 {
1513 FBaseCVar *cvar = CVars;
1514 FBaseCVar *next = cvar;
1515
1516 while(cvar)
1517 {
1518 next = cvar->m_Next;
1519
1520 if(cvar->Flags & flags)
1521 delete cvar;
1522
1523 cvar = next;
1524 }
1525 }
1526
C_SetCVarsToDefaults(void)1527 void C_SetCVarsToDefaults (void)
1528 {
1529 FBaseCVar *cvar = CVars;
1530
1531 while (cvar)
1532 {
1533 // Only default save-able cvars
1534 if (cvar->Flags & CVAR_ARCHIVE)
1535 {
1536 UCVarValue val;
1537 ECVarType type;
1538 val = cvar->GetFavoriteRepDefault (&type);
1539 cvar->SetGenericRep (val, type);
1540 }
1541 cvar = cvar->m_Next;
1542 }
1543 }
1544
C_ArchiveCVars(FConfigFile * f,uint32 filter)1545 void C_ArchiveCVars (FConfigFile *f, uint32 filter)
1546 {
1547 FBaseCVar *cvar = CVars;
1548
1549 while (cvar)
1550 {
1551 if ((cvar->Flags &
1552 (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE))
1553 == filter)
1554 {
1555 UCVarValue val;
1556 val = cvar->GetGenericRep (CVAR_String);
1557 f->SetValueForKey (cvar->GetName (), val.String);
1558 }
1559 cvar = cvar->m_Next;
1560 }
1561 }
1562
CmdSet(const char * newval)1563 void FBaseCVar::CmdSet (const char *newval)
1564 {
1565 UCVarValue val;
1566
1567 // Casting away the const is safe in this case.
1568 val.String = const_cast<char *>(newval);
1569 SetGenericRep (val, CVAR_String);
1570
1571 if (GetFlags() & CVAR_NOSET)
1572 Printf ("%s is write protected.\n", GetName());
1573 else if (GetFlags() & CVAR_LATCH)
1574 Printf ("%s will be changed for next game.\n", GetName());
1575 }
1576
CCMD(set)1577 CCMD (set)
1578 {
1579 if (argv.argc() != 3)
1580 {
1581 Printf ("usage: set <variable> <value>\n");
1582 }
1583 else
1584 {
1585 FBaseCVar *var;
1586
1587 var = FindCVar (argv[1], NULL);
1588 if (var == NULL)
1589 var = new FStringCVar (argv[1], NULL, CVAR_AUTO | CVAR_UNSETTABLE | cvar_defflags);
1590
1591 var->CmdSet (argv[2]);
1592 }
1593 }
1594
CCMD(unset)1595 CCMD (unset)
1596 {
1597 if (argv.argc() != 2)
1598 {
1599 Printf ("usage: unset <variable>\n");
1600 }
1601 else
1602 {
1603 FBaseCVar *var = FindCVar (argv[1], NULL);
1604 if (var != NULL)
1605 {
1606 if (var->GetFlags() & CVAR_UNSETTABLE)
1607 {
1608 delete var;
1609 }
1610 else
1611 {
1612 Printf ("Cannot unset %s\n", argv[1]);
1613 }
1614 }
1615 }
1616 }
1617
CCMD(get)1618 CCMD (get)
1619 {
1620 FBaseCVar *var, *prev;
1621
1622 if (argv.argc() >= 2)
1623 {
1624 if ( (var = FindCVar (argv[1], &prev)) )
1625 {
1626 UCVarValue val;
1627 val = var->GetGenericRep (CVAR_String);
1628 Printf ("\"%s\" is \"%s\"\n", var->GetName(), val.String);
1629 }
1630 else
1631 {
1632 Printf ("\"%s\" is unset\n", argv[1]);
1633 }
1634 }
1635 else
1636 {
1637 Printf ("get: need variable name\n");
1638 }
1639 }
1640
CCMD(toggle)1641 CCMD (toggle)
1642 {
1643 FBaseCVar *var, *prev;
1644 UCVarValue val;
1645
1646 if (argv.argc() > 1)
1647 {
1648 if ( (var = FindCVar (argv[1], &prev)) )
1649 {
1650 val = var->GetGenericRep (CVAR_Bool);
1651 val.Bool = !val.Bool;
1652 var->SetGenericRep (val, CVAR_Bool);
1653 Printf ("\"%s\" is \"%s\"\n", var->GetName(),
1654 val.Bool ? "true" : "false");
1655 }
1656 }
1657 }
1658
ListVars(const char * filter,bool plain)1659 void FBaseCVar::ListVars (const char *filter, bool plain)
1660 {
1661 FBaseCVar *var = CVars;
1662 int count = 0;
1663
1664 while (var)
1665 {
1666 if (CheckWildcards (filter, var->GetName()))
1667 {
1668 DWORD flags = var->GetFlags();
1669 if (plain)
1670 { // plain formatting does not include user-defined cvars
1671 if (!(flags & CVAR_UNSETTABLE))
1672 {
1673 ++count;
1674 Printf ("%s : %s\n", var->GetName(), var->GetGenericRep(CVAR_String).String);
1675 }
1676 }
1677 else
1678 {
1679 ++count;
1680 Printf ("%c%c%c%c%c %s = %s\n",
1681 flags & CVAR_ARCHIVE ? 'A' : ' ',
1682 flags & CVAR_USERINFO ? 'U' :
1683 flags & CVAR_SERVERINFO ? 'S' :
1684 flags & CVAR_AUTO ? 'C' : ' ',
1685 flags & CVAR_NOSET ? '-' :
1686 flags & CVAR_LATCH ? 'L' :
1687 flags & CVAR_UNSETTABLE ? '*' : ' ',
1688 flags & CVAR_MOD ? 'M' : ' ',
1689 flags & CVAR_IGNORE ? 'X' : ' ',
1690 var->GetName(),
1691 var->GetGenericRep(CVAR_String).String);
1692 }
1693 }
1694 var = var->m_Next;
1695 }
1696 Printf ("%d cvars\n", count);
1697 }
1698
CCMD(cvarlist)1699 CCMD (cvarlist)
1700 {
1701 if (argv.argc() == 1)
1702 {
1703 FBaseCVar::ListVars (NULL, false);
1704 }
1705 else
1706 {
1707 FBaseCVar::ListVars (argv[1], false);
1708 }
1709 }
1710
CCMD(cvarlistplain)1711 CCMD (cvarlistplain)
1712 {
1713 FBaseCVar::ListVars (NULL, true);
1714 }
1715
CCMD(archivecvar)1716 CCMD (archivecvar)
1717 {
1718
1719 if (argv.argc() == 1)
1720 {
1721 Printf ("Usage: archivecvar <cvar>\n");
1722 }
1723 else
1724 {
1725 FBaseCVar *var = FindCVar (argv[1], NULL);
1726
1727 if (var != NULL && (var->GetFlags() & CVAR_AUTO))
1728 {
1729 var->SetArchiveBit ();
1730 }
1731 }
1732 }
1733