1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: cvar.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "network.h"
30 #include "sv_local.h"
31
32 // MACROS ------------------------------------------------------------------
33
34 // TYPES -------------------------------------------------------------------
35
36 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
37
38 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
39
40 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
41
42 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
43
44 // PUBLIC DATA DEFINITIONS -------------------------------------------------
45
46 // PRIVATE DATA DEFINITIONS ------------------------------------------------
47
48 VCvar* VCvar::Variables = NULL;
49 bool VCvar::Initialised = false;
50 bool VCvar::Cheating;
51
52 // CODE --------------------------------------------------------------------
53
54 //==========================================================================
55 //
56 // VCvar::VCvar
57 //
58 //==========================================================================
59
VCvar(const char * AName,const char * ADefault,int AFlags)60 VCvar::VCvar(const char* AName, const char* ADefault, int AFlags)
61 : Name(AName)
62 , DefaultString(ADefault)
63 , Flags(AFlags)
64 {
65 guard(VCvar::VCvar);
66 VCvar *prev = NULL;
67 for (VCvar *var = Variables; var; var = var->Next)
68 {
69 if (VStr::ICmp(var->Name, Name) < 0)
70 {
71 prev = var;
72 }
73 }
74
75 if (prev)
76 {
77 Next = prev->Next;
78 prev->Next = this;
79 }
80 else
81 {
82 Next = Variables;
83 Variables = this;
84 }
85
86 if (Initialised)
87 {
88 Register();
89 }
90 unguard;
91 }
92
93 //==========================================================================
94 //
95 // VCvar::VCvar
96 //
97 //==========================================================================
98
VCvar(const char * AName,const VStr & ADefault,int AFlags)99 VCvar::VCvar(const char* AName, const VStr& ADefault, int AFlags)
100 : Name(AName)
101 , Flags(AFlags | CVAR_Delete)
102 {
103 guard(VCvar::VCvar);
104 char* Tmp = new char[ADefault.Length() + 1];
105 VStr::Cpy(Tmp, *ADefault);
106 DefaultString = Tmp;
107
108 VCvar *prev = NULL;
109 for (VCvar *var = Variables; var; var = var->Next)
110 {
111 if (VStr::ICmp(var->Name, Name) < 0)
112 {
113 prev = var;
114 }
115 }
116
117 if (prev)
118 {
119 Next = prev->Next;
120 prev->Next = this;
121 }
122 else
123 {
124 Next = Variables;
125 Variables = this;
126 }
127
128 check(Initialised);
129 Register();
130 unguard;
131 }
132
133 //==========================================================================
134 //
135 // VCvar::Register
136 //
137 //==========================================================================
138
Register()139 void VCvar::Register()
140 {
141 guard(VCvar::Register);
142 VCommand::AddToAutoComplete(Name);
143 DoSet(DefaultString);
144 unguard;
145 }
146
147 //==========================================================================
148 //
149 // VCvar::Set
150 //
151 //==========================================================================
152
Set(int value)153 void VCvar::Set(int value)
154 {
155 guard(VCvar::Set);
156 Set(VStr(value));
157 unguard;
158 }
159
160 //==========================================================================
161 //
162 // VCvar::Set
163 //
164 //==========================================================================
165
Set(float value)166 void VCvar::Set(float value)
167 {
168 guard(VCvar::Set);
169 Set(VStr(value));
170 unguard;
171 }
172
173 //==========================================================================
174 //
175 // VCvar::Set
176 //
177 //==========================================================================
178
Set(const VStr & AValue)179 void VCvar::Set(const VStr& AValue)
180 {
181 guard(VCvar::Set);
182 if (Flags & CVAR_Latch)
183 {
184 LatchedString = AValue;
185 return;
186 }
187
188 if (Flags & CVAR_Cheat && !Cheating)
189 {
190 GCon->Log(VStr(Name) + " cannot be changed while cheating is disabled");
191 return;
192 }
193
194 DoSet(AValue);
195
196 Flags |= CVAR_Modified;
197 unguard;
198 }
199
200 //==========================================================================
201 //
202 // VCvar::DoSet
203 //
204 // Does the actual value assignement
205 //
206 //==========================================================================
207
DoSet(const VStr & AValue)208 void VCvar::DoSet(const VStr& AValue)
209 {
210 guard(VCvar::DoSet);
211 StringValue = AValue;
212 IntValue = superatoi(*StringValue);
213 FloatValue = atof(*StringValue);
214
215 #ifdef CLIENT
216 if (Flags & CVAR_UserInfo)
217 {
218 Info_SetValueForKey(cls.userinfo, Name, *StringValue);
219 if (cl)
220 {
221 if (GGameInfo->NetMode == NM_TitleMap ||
222 GGameInfo->NetMode == NM_Standalone ||
223 GGameInfo->NetMode == NM_ListenServer)
224 {
225 VCommand::ExecuteString(VStr("setinfo \"") + Name + "\" \"" +
226 StringValue + "\"\n", VCommand::SRC_Client, cl);
227 }
228 else if (cl->Net)
229 {
230 cl->Net->SendCommand(VStr("setinfo \"") + Name + "\" \"" +
231 StringValue + "\"\n");
232 }
233 }
234 }
235 #endif
236
237 #ifdef SERVER
238 if (Flags & CVAR_ServerInfo)
239 {
240 Info_SetValueForKey(svs.serverinfo, Name, *StringValue);
241 if (GGameInfo && GGameInfo->NetMode != NM_None &&
242 GGameInfo->NetMode != NM_Client)
243 {
244 for (int i = 0; i < MAXPLAYERS; i++)
245 {
246 if (GGameInfo->Players[i])
247 {
248 GGameInfo->Players[i]->eventClientSetServerInfo(
249 Name, StringValue);
250 }
251 }
252 }
253 }
254 #endif
255 unguard;
256 }
257
258 //==========================================================================
259 //
260 // VCvar::IsModified
261 //
262 //==========================================================================
263
IsModified()264 bool VCvar::IsModified()
265 {
266 guard(VCvar::IsModified);
267 bool ret = !!(Flags & CVAR_Modified);
268 // Clear modified flag.
269 Flags &= ~CVAR_Modified;
270 return ret;
271 unguard;
272 }
273
274 //==========================================================================
275 //
276 // VCvar::Init
277 //
278 //==========================================================================
279
Init()280 void VCvar::Init()
281 {
282 guard(VCvar::Init);
283 for (VCvar *var = Variables; var; var = var->Next)
284 {
285 var->Register();
286 }
287 Initialised = true;
288 unguard;
289 }
290
291 //==========================================================================
292 //
293 // VCvar::Shutdown
294 //
295 //==========================================================================
296
Shutdown()297 void VCvar::Shutdown()
298 {
299 guard(VCvar::Shutdown);
300 for (VCvar* var = Variables; var;)
301 {
302 VCvar* Next = var->Next;
303 var->StringValue.Clean();
304 var->LatchedString.Clean();
305 if (var->Flags & CVAR_Delete)
306 {
307 delete[] const_cast<char*>(var->DefaultString);
308 var->DefaultString = NULL;
309 delete var;
310 var = NULL;
311 }
312 var = Next;
313 }
314 Initialised = false;
315 unguard;
316 }
317
318 //==========================================================================
319 //
320 // VCvar::Unlatch
321 //
322 //==========================================================================
323
Unlatch()324 void VCvar::Unlatch()
325 {
326 guard(VCvar::Unlatch);
327 for (VCvar* cvar = Variables; cvar; cvar = cvar->Next)
328 {
329 if (cvar->LatchedString.IsNotEmpty())
330 {
331 cvar->DoSet(cvar->LatchedString);
332 cvar->LatchedString.Clean();
333 }
334 }
335 unguard;
336 }
337
338 //==========================================================================
339 //
340 // VCvar::SetCheating
341 //
342 //==========================================================================
343
SetCheating(bool new_state)344 void VCvar::SetCheating(bool new_state)
345 {
346 guard(VCvar::SetCheating);
347 Cheating = new_state;
348 if (!Cheating)
349 {
350 for (VCvar *cvar = Variables; cvar; cvar = cvar->Next)
351 {
352 if (cvar->Flags & CVAR_Cheat)
353 {
354 cvar->DoSet(cvar->DefaultString);
355 }
356 }
357 }
358 unguard;
359 }
360
361 //==========================================================================
362 //
363 // VCvar::FindVariable
364 //
365 //==========================================================================
366
FindVariable(const char * name)367 VCvar* VCvar::FindVariable(const char* name)
368 {
369 guard(VCvar::FindVariable);
370 for (VCvar* cvar = Variables; cvar; cvar = cvar->Next)
371 {
372 if (!VStr::ICmp(name, cvar->Name))
373 {
374 return cvar;
375 }
376 }
377 return NULL;
378 unguard;
379 }
380
381 //==========================================================================
382 //
383 // VCvar::GetInt
384 //
385 //==========================================================================
386
GetInt(const char * var_name)387 int VCvar::GetInt(const char* var_name)
388 {
389 guard(VCvar::GetInt);
390 VCvar* var = FindVariable(var_name);
391 if (!var)
392 return 0;
393 return var->IntValue;
394 unguard;
395 }
396
397 //==========================================================================
398 //
399 // VCvar::GetFloat
400 //
401 //==========================================================================
402
GetFloat(const char * var_name)403 float VCvar::GetFloat(const char* var_name)
404 {
405 guard(VCvar::GetFloat);
406 VCvar* var = FindVariable(var_name);
407 if (!var)
408 return 0;
409 return var->FloatValue;
410 unguard;
411 }
412
413 //==========================================================================
414 //
415 // GetCharp
416 //
417 //==========================================================================
418
GetCharp(const char * var_name)419 const char* VCvar::GetCharp(const char* var_name)
420 {
421 guard(VCvar::GetCharp);
422 VCvar* var = FindVariable(var_name);
423 if (!var)
424 {
425 return "";
426 }
427 return *var->StringValue;
428 unguard;
429 }
430
431 //==========================================================================
432 //
433 // VCvar::GetString
434 //
435 //==========================================================================
436
GetString(const char * var_name)437 VStr VCvar::GetString(const char* var_name)
438 {
439 guard(VCvar::GetString);
440 VCvar* var = FindVariable(var_name);
441 if (!var)
442 {
443 return VStr();
444 }
445 return var->StringValue;
446 unguard;
447 }
448
449 //==========================================================================
450 //
451 // VCvar::Set
452 //
453 //==========================================================================
454
Set(const char * var_name,int value)455 void VCvar::Set(const char* var_name, int value)
456 {
457 guard(VCvar::Set);
458 VCvar* var = FindVariable(var_name);
459 if (!var)
460 {
461 Sys_Error("Cvar_Set: variable %s not found\n", var_name);
462 }
463 var->Set(value);
464 unguard;
465 }
466
467 //==========================================================================
468 //
469 // VCvar::Set
470 //
471 //==========================================================================
472
Set(const char * var_name,float value)473 void VCvar::Set(const char* var_name, float value)
474 {
475 guard(VCvar::Set);
476 VCvar* var = FindVariable(var_name);
477 if (!var)
478 {
479 Sys_Error("Cvar_Set: variable %s not found\n", var_name);
480 }
481 var->Set(value);
482 unguard;
483 }
484
485 //==========================================================================
486 //
487 // VCvar::Set
488 //
489 //==========================================================================
490
Set(const char * var_name,const VStr & value)491 void VCvar::Set(const char* var_name, const VStr& value)
492 {
493 guard(VCvar::Set);
494 VCvar* var = FindVariable(var_name);
495 if (!var)
496 {
497 Sys_Error("Cvar_SetString: variable %s not found\n", var_name);
498 }
499 var->Set(value);
500 unguard;
501 }
502
503 //==========================================================================
504 //
505 // VCvar::Command
506 //
507 //==========================================================================
508
Command(const TArray<VStr> & Args)509 bool VCvar::Command(const TArray<VStr>& Args)
510 {
511 guard(VCvar::Command);
512 VCvar* cvar = FindVariable(*Args[0]);
513 if (!cvar)
514 {
515 return false;
516 }
517
518 // perform a variable print or set
519 if (Args.Num() == 1)
520 {
521 GCon->Log(VStr(cvar->Name) + " is \"" + cvar->StringValue + "\"");
522 if (cvar->Flags & CVAR_Latch && cvar->LatchedString.IsNotEmpty())
523 GCon->Log(VStr("Latched \"") + cvar->LatchedString + "\"");
524 }
525 else
526 {
527 if (cvar->Flags & CVAR_Rom)
528 {
529 GCon->Logf("%s is read-only", cvar->Name);
530 }
531 else if (cvar->Flags & CVAR_Init && host_initialised)
532 {
533 GCon->Logf("%s can be set only from command-line", cvar->Name);
534 }
535 else
536 {
537 cvar->Set(Args[1]);
538 }
539 }
540 return true;
541 unguard;
542 }
543
544 //==========================================================================
545 //
546 // VCvar::WriteVariables
547 //
548 //==========================================================================
549
WriteVariables(FILE * f)550 void VCvar::WriteVariables(FILE* f)
551 {
552 guard(VCvar::WriteVariables);
553 for (VCvar* cvar = Variables; cvar; cvar = cvar->Next)
554 {
555 if (cvar->Flags & CVAR_Archive)
556 {
557 fprintf(f, "%s\t\t\"%s\"\n", cvar->Name, *cvar->StringValue);
558 }
559 }
560 unguard;
561 }
562
563 //==========================================================================
564 //
565 // COMMAND CvarList
566 //
567 //==========================================================================
568
COMMAND(CvarList)569 COMMAND(CvarList)
570 {
571 guard(COMMAND CvarList);
572 int count = 0;
573 for (VCvar *cvar = VCvar::Variables; cvar; cvar = cvar->Next)
574 {
575 GCon->Log(VStr(cvar->Name) + " - \"" + cvar->StringValue + "\"");
576 count++;
577 }
578 GCon->Logf("%d variables.", count);
579 unguard;
580 }
581