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