diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 99eda461e..72c97c19d 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,13 @@ February 16, 2008 (Changes by Graf Zahl) +- Added patch by Karate Chris: + - The net arbitrator can add or remove players to an access list so they + can or cannot control game settings: + * net_addcontroller - Adds a player to the control list. Only net arbitrators have access to this command. + * net_removecontroller - Removes a player from the control list. Only net arbitrators have access to this command. + * net_listcontrollers - Lists the players who are able to control the game settings. + - Fixed: The 'Printf'' occurrences in the 'addplayerclass' console command were all missing a '\n' at the end. + - Enhanced the 'playerinfo' console command so more information about each setting is shown. + - Added customizable pickup flash. - Added option to show shorter messages for save game and screenshot confirmation. Also added this to the 'Messages' menu. diff --git a/src/b_bot.cpp b/src/b_bot.cpp index 82ff3323e..8c0a9e3e0 100644 --- a/src/b_bot.cpp +++ b/src/b_bot.cpp @@ -31,9 +31,9 @@ CCMD (addbot) return; } - if (consoleplayer != Net_Arbitrator) + if (!players[consoleplayer].settings_controller) { - Printf ("Only player %d can add bots\n", Net_Arbitrator + 1); + Printf ("Only setting controllers can add bots\n"); return; } @@ -78,17 +78,17 @@ extern bool CheckCheatmode (); CCMD (freeze) { - if (CheckCheatmode ()) - return; + if (CheckCheatmode ()) + return; - if (netgame && consoleplayer != Net_Arbitrator) - { - Printf ("Only player %d can use freeze mode\n", Net_Arbitrator + 1); - return; - } + if (netgame && !players[consoleplayer].settings_controller) + { + Printf ("Only setting controllers can use freeze mode\n"); + return; + } - Net_WriteByte (DEM_GENERICCHEAT); - Net_WriteByte (CHT_FREEZE); + Net_WriteByte (DEM_GENERICCHEAT); + Net_WriteByte (CHT_FREEZE); } CCMD (listbots) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index bd9618e84..46208a840 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -315,9 +315,9 @@ CCMD (changemap) return; } - if (who->player - players != Net_Arbitrator && multiplayer) + if (!players[who->player - players].settings_controller && netgame) { - Printf ("Only player %d can change the map.\n", Net_Arbitrator+1); + Printf ("Only setting controllers can change the map.\n"); return; } @@ -589,7 +589,7 @@ CCMD (fov) } else { - Printf ("The arbitrator has disabled FOV changes.\n"); + Printf ("A setting controller has disabled FOV changes.\n"); return; } } diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 9393db8de..7a6f316d6 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1,1593 +1,1593 @@ -/* -** c_cvars.cpp -** Defines all the different console variable types -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include -#include -#include - -#include "cmdlib.h" -#include "configfile.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "m_alloc.h" - -#include "doomstat.h" -#include "c_cvars.h" -#include "d_player.h" - -#include "d_netinf.h" - -#include "i_system.h" -#include "v_palette.h" -#include "v_video.h" - -struct FLatchedValue -{ - FBaseCVar *Variable; - UCVarValue Value; - ECVarType Type; -}; - -static TArray LatchedValues; - -bool FBaseCVar::m_DoNoSet = false; -bool FBaseCVar::m_UseCallback = false; - -FBaseCVar *CVars = NULL; - -int cvar_defflags; - -FBaseCVar::FBaseCVar (const FBaseCVar &var) -{ - I_FatalError ("Use of cvar copy constructor"); -} - -FBaseCVar::FBaseCVar (const char *var_name, DWORD flags, void (*callback)(FBaseCVar &)) -{ - FBaseCVar *var; - - var = FindCVar (var_name, NULL); - - m_Callback = callback; - Flags = 0; - Name = NULL; - - if (var_name) - { - C_AddTabCommand (var_name); - Name = copystring (var_name); - m_Next = CVars; - CVars = this; - } - - if (var) - { - ECVarType type; - UCVarValue value; - - value = var->GetFavoriteRep (&type); - ForceSet (value, type); - - if (var->Flags & CVAR_AUTO) - delete var; - else - var->~FBaseCVar(); - - Flags = flags; - } - else - { - Flags = flags | CVAR_ISDEFAULT; - } -} - -FBaseCVar::~FBaseCVar () -{ - if (Name) - { - FBaseCVar *var, *prev; - - var = FindCVar (Name, &prev); - - if (var == this) - { - if (prev) - prev->m_Next = m_Next; - else - CVars = m_Next; - } - delete[] Name; - } -} - -void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) -{ - DoSet (value, type); - if (Flags & CVAR_USERINFO) - D_UserInfoChanged (this); - if (m_UseCallback) - Callback (); - - Flags &= ~CVAR_ISDEFAULT; -} - -void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) -{ - if ((Flags & CVAR_NOSET) && m_DoNoSet) - { - return; - } - else if ((Flags & CVAR_LATCH) && gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP) - { - FLatchedValue latch; - - latch.Variable = this; - latch.Type = type; - if (type != CVAR_String) - latch.Value = value; - else - latch.Value.String = copystring(value.String); - LatchedValues.Push (latch); - } - else if ((Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) - { - if (netgame && consoleplayer != Net_Arbitrator) - { - Printf ("Only player %d can change %s\n", Net_Arbitrator+1, Name); - return; - } - D_SendServerInfoChange (this, value, type); - } - else - { - ForceSet (value, type); - } -} - -bool FBaseCVar::ToBool (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return value.Bool; - - case CVAR_Int: - return !!value.Int; - - case CVAR_Float: - return value.Float != 0.f; - - case CVAR_String: - if (stricmp (value.String, "true") == 0) - return true; - else if (stricmp (value.String, "false") == 0) - return false; - else - return !!strtol (value.String, NULL, 0); - - case CVAR_GUID: - return false; - - default: - return false; - } -} - -int FBaseCVar::ToInt (UCVarValue value, ECVarType type) -{ - int res; -#if __GNUC__ <= 2 - float tmp; -#endif - - switch (type) - { - case CVAR_Bool: res = (int)value.Bool; break; - case CVAR_Int: res = value.Int; break; -#if __GNUC__ <= 2 - case CVAR_Float: tmp = value.Float; res = (int)tmp; break; -#else - case CVAR_Float: res = (int)value.Float; break; -#endif - case CVAR_String: res = strtol (value.String, NULL, 0); break; - case CVAR_GUID: res = 0; break; - default: res = 0; break; - } - return res; -} - -float FBaseCVar::ToFloat (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return (float)value.Bool; - - case CVAR_Int: - return (float)value.Int; - - case CVAR_Float: - return value.Float; - - case CVAR_String: - return strtod (value.String, NULL); - - case CVAR_GUID: - return 0.f; - - default: - return 0.f; - } -} - -static char cstrbuf[40]; -static GUID cGUID; -static char truestr[] = "true"; -static char falsestr[] = "false"; - -char *FBaseCVar::ToString (UCVarValue value, ECVarType type) -{ - switch (type) - { - case CVAR_Bool: - return value.Bool ? truestr : falsestr; - - case CVAR_String: - return value.String; - - case CVAR_Int: - sprintf (cstrbuf, "%i", value.Int); - break; - - case CVAR_Float: - sprintf (cstrbuf, "%g", value.Float); - break; - - case CVAR_GUID: - FormatGUID (cstrbuf, *value.pGUID); - break; - - default: - strcpy (cstrbuf, ""); - break; - } - return cstrbuf; -} - -const GUID *FBaseCVar::ToGUID (UCVarValue value, ECVarType type) -{ - UCVarValue trans; - - switch (type) - { - case CVAR_String: - trans = FromString (value.String, CVAR_GUID); - return trans.pGUID; - - case CVAR_GUID: - return value.pGUID; - - default: - return NULL; - } -} - -UCVarValue FBaseCVar::FromBool (bool value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value; - break; - - case CVAR_Int: - ret.Int = value; - break; - - case CVAR_Float: - ret.Float = value; - break; - - case CVAR_String: - ret.String = value ? truestr : falsestr; - break; - - case CVAR_GUID: - ret.pGUID = NULL; - break; - - default: - break; - } - - return ret; -} - -UCVarValue FBaseCVar::FromInt (int value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value != 0; - break; - - case CVAR_Int: - ret.Int = value; - break; - - case CVAR_Float: - ret.Float = (float)value; - break; - - case CVAR_String: - sprintf (cstrbuf, "%i", value); - ret.String = cstrbuf; - break; - - case CVAR_GUID: - ret.pGUID = NULL; - break; - - default: - break; - } - - return ret; -} - -UCVarValue FBaseCVar::FromFloat (float value, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = value != 0.f; - break; - - case CVAR_Int: - ret.Int = (int)value; - break; - - case CVAR_Float: - ret.Float = value; - break; - - case CVAR_String: - sprintf (cstrbuf, "%g", value); - ret.String = cstrbuf; - break; - - case CVAR_GUID: - ret.pGUID = NULL; - break; - - default: - break; - } - - return ret; -} - -static BYTE HexToByte (const char *hex) -{ - BYTE v = 0; - for (int i = 0; i < 2; ++i) - { - v <<= 4; - if (hex[i] >= '0' && hex[i] <= '9') - { - v += hex[i] - '0'; - } - else if (hex[i] >= 'A' && hex[i] <= 'F') - { - v += hex[i] - 'A'; - } - else // The string is already verified to contain valid hexits - { - v += hex[i] - 'a'; - } - } - return v; -} - -UCVarValue FBaseCVar::FromString (const char *value, ECVarType type) -{ - UCVarValue ret; - int i; - - switch (type) - { - case CVAR_Bool: - if (stricmp (value, "true") == 0) - ret.Bool = true; - else if (stricmp (value, "false") == 0) - ret.Bool = false; - else - ret.Bool = strtol (value, NULL, 0) != 0; - break; - - case CVAR_Int: - ret.Int = strtol (value, NULL, 0); - break; - - case CVAR_Float: - ret.Float = (float)strtod (value, NULL); - break; - - case CVAR_String: - ret.String = const_cast(value); - break; - - case CVAR_GUID: - // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} - // 01234567890123456789012345678901234567 - // 0 1 2 3 - - ret.pGUID = NULL; - for (i = 0; i < 38; ++i) - { - if (value[i] == 0) - { - break; - } - bool goodv = true; - switch (i) - { - case 0: - if (value[i] != '{') - goodv = false; - break; - case 9: - case 14: - case 19: - case 24: - if (value[i] != '-') - goodv = false; - break; - case 37: - if (value[i] != '}') - goodv = false; - break; - default: - if (value[i] < '0' && value[i] > '9' && - value[i] < 'A' && value[i] > 'F' && - value[i] < 'a' && value[i] > 'f') - { - goodv = false; - } - break; - } - } - if (i == 38 && value[i] == 0) - { - cGUID.Data1 = strtoul (value + 1, NULL, 16); - cGUID.Data2 = strtoul (value + 10, NULL, 16); - cGUID.Data3 = strtoul (value + 15, NULL, 16); - cGUID.Data4[0] = HexToByte (value + 20); - cGUID.Data4[1] = HexToByte (value + 22); - cGUID.Data4[2] = HexToByte (value + 25); - cGUID.Data4[3] = HexToByte (value + 27); - cGUID.Data4[4] = HexToByte (value + 29); - cGUID.Data4[5] = HexToByte (value + 31); - cGUID.Data4[6] = HexToByte (value + 33); - cGUID.Data4[7] = HexToByte (value + 35); - ret.pGUID = &cGUID; - } - break; - - default: - break; - } - - return ret; -} - -UCVarValue FBaseCVar::FromGUID (const GUID &guid, ECVarType type) -{ - UCVarValue ret; - - switch (type) - { - case CVAR_Bool: - ret.Bool = false; - break; - - case CVAR_Int: - ret.Int = 0; - break; - - case CVAR_Float: - ret.Float = 0.f; - break; - - case CVAR_String: - ret.pGUID = &guid; - ret.String = ToString (ret, CVAR_GUID); - break; - - case CVAR_GUID: - ret.pGUID = &guid; - break; - - default: - break; - } - - return ret; -} -FBaseCVar *cvar_set (const char *var_name, const char *val) -{ - FBaseCVar *var; - - if ( (var = FindCVar (var_name, NULL)) ) - { - UCVarValue value; - value.String = const_cast(val); - var->SetGenericRep (value, CVAR_String); - } - - return var; -} - -FBaseCVar *cvar_forceset (const char *var_name, const char *val) -{ - FBaseCVar *var; - UCVarValue vval; - - if ( (var = FindCVar (var_name, NULL)) ) - { - vval.String = const_cast(val); - var->ForceSet (vval, CVAR_String); - } - - return var; -} - -void FBaseCVar::EnableNoSet () -{ - m_DoNoSet = true; -} - -void FBaseCVar::EnableCallbacks () -{ - m_UseCallback = true; - FBaseCVar *cvar = CVars; - - while (cvar) - { - if (!(cvar->Flags & CVAR_NOINITCALL)) - { - cvar->Callback (); - } - cvar = cvar->m_Next; - } -} - -// -// Boolean cvar implementation -// - -FBoolCVar::FBoolCVar (const char *name, bool def, DWORD flags, void (*callback)(FBoolCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FBoolCVar::GetRealType () const -{ - return CVAR_Bool; -} - -UCVarValue FBoolCVar::GetGenericRep (ECVarType type) const -{ - return FromBool (Value, type); -} - -UCVarValue FBoolCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = Value; - return ret; -} - -UCVarValue FBoolCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromBool (DefaultValue, type); -} - -UCVarValue FBoolCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = DefaultValue; - return ret; -} - -void FBoolCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToBool (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FBoolCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToBool (value, type); -} - -// -// Integer cvar implementation -// - -FIntCVar::FIntCVar (const char *name, int def, DWORD flags, void (*callback)(FIntCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FIntCVar::GetRealType () const -{ - return CVAR_Int; -} - -UCVarValue FIntCVar::GetGenericRep (ECVarType type) const -{ - return FromInt (Value, type); -} - -UCVarValue FIntCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Int; - ret.Int = Value; - return ret; -} - -UCVarValue FIntCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromInt (DefaultValue, type); -} - -UCVarValue FIntCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Int; - ret.Int = DefaultValue; - return ret; -} - -void FIntCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToInt (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FIntCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToInt (value, type); -} - -// -// Floating point cvar implementation -// - -FFloatCVar::FFloatCVar (const char *name, float def, DWORD flags, void (*callback)(FFloatCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = def; - if (Flags & CVAR_ISDEFAULT) - Value = def; -} - -ECVarType FFloatCVar::GetRealType () const -{ - return CVAR_Float; -} - -UCVarValue FFloatCVar::GetGenericRep (ECVarType type) const -{ - return FromFloat (Value, type); -} - -UCVarValue FFloatCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Float; - ret.Float = Value; - return ret; -} - -UCVarValue FFloatCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromFloat (DefaultValue, type); -} - -UCVarValue FFloatCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Float; - ret.Float = DefaultValue; - return ret; -} - -void FFloatCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToFloat (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FFloatCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToFloat (value, type); -} - -// -// String cvar implementation -// - -FStringCVar::FStringCVar (const char *name, const char *def, DWORD flags, void (*callback)(FStringCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - DefaultValue = copystring (def); - if (Flags & CVAR_ISDEFAULT) - Value = copystring (def); - else - Value = NULL; -} - -FStringCVar::~FStringCVar () -{ - if (Value != NULL) - { - delete[] Value; - } - delete[] DefaultValue; -} - -ECVarType FStringCVar::GetRealType () const -{ - return CVAR_String; -} - -UCVarValue FStringCVar::GetGenericRep (ECVarType type) const -{ - return FromString (Value, type); -} - -UCVarValue FStringCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_String; - ret.String = Value; - return ret; -} - -UCVarValue FStringCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromString (DefaultValue, type); -} - -UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_String; - ret.String = DefaultValue; - return ret; -} - -void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - if (DefaultValue) - delete[] DefaultValue; - DefaultValue = ToString (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FStringCVar::DoSet (UCVarValue value, ECVarType type) -{ - ReplaceString (&Value, ToString (value, type)); -} - -// -// Color cvar implementation -// - -FColorCVar::FColorCVar (const char *name, int def, DWORD flags, void (*callback)(FColorCVar &)) -: FIntCVar (name, def, flags, reinterpret_cast(callback)) -{ -} - -ECVarType FColorCVar::GetRealType () const -{ - return CVAR_Color; -} - -UCVarValue FColorCVar::GetGenericRep (ECVarType type) const -{ - return FromInt2 (Value, type); -} - -UCVarValue FColorCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromInt2 (DefaultValue, type); -} - -void FColorCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - DefaultValue = ToInt2 (value, type); - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } -} - -void FColorCVar::DoSet (UCVarValue value, ECVarType type) -{ - Value = ToInt2 (value, type); - if (screen) - Index = ColorMatcher.Pick (RPART(Value), GPART(Value), BPART(Value)); -} - -UCVarValue FColorCVar::FromInt2 (int value, ECVarType type) -{ - if (type == CVAR_String) - { - UCVarValue ret; - sprintf (cstrbuf, "%02x %02x %02x", - RPART(value), GPART(value), BPART(value)); - ret.String = cstrbuf; - return ret; - } - return FromInt (value, type); -} - -int FColorCVar::ToInt2 (UCVarValue value, ECVarType type) -{ - int ret; - - if (type == CVAR_String) - { - FString string; - // Only allow named colors after the screen exists (i.e. after - // we've got some lumps loaded, so X11R6RGB can be read). Since - // the only time this might be called before that is when loading - // zdoom.ini, this shouldn't be a problem. - if (screen && !(string = V_GetColorStringByName (value.String)).IsEmpty() ) - { - ret = V_GetColorFromString (NULL, string); - } - else - { - ret = V_GetColorFromString (NULL, value.String); - } - } - else - { - ret = ToInt (value, type); - } - return ret; -} - -// -// GUID cvar implementation -// - -FGUIDCVar::FGUIDCVar (const char *name, const GUID *def, DWORD flags, void (*callback)(FGUIDCVar &)) -: FBaseCVar (name, flags, reinterpret_cast(callback)) -{ - if (def != NULL) - { - DefaultValue = *def; - if (Flags & CVAR_ISDEFAULT) - Value = *def; - } - else - { - memset (&Value, 0, sizeof(DefaultValue)); - memset (&DefaultValue, 0, sizeof(DefaultValue)); - } -} - -ECVarType FGUIDCVar::GetRealType () const -{ - return CVAR_GUID; -} - -UCVarValue FGUIDCVar::GetGenericRep (ECVarType type) const -{ - return FromGUID (Value, type); -} - -UCVarValue FGUIDCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_GUID; - ret.pGUID = &Value; - return ret; -} - -UCVarValue FGUIDCVar::GetGenericRepDefault (ECVarType type) const -{ - return FromGUID (DefaultValue, type); -} - -UCVarValue FGUIDCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_GUID; - ret.pGUID = &DefaultValue; - return ret; -} - -void FGUIDCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - const GUID *guid = ToGUID (value, type); - if (guid != NULL) - { - Value = *guid; - if (Flags & CVAR_ISDEFAULT) - { - SetGenericRep (value, type); - Flags |= CVAR_ISDEFAULT; - } - } -} - -void FGUIDCVar::DoSet (UCVarValue value, ECVarType type) -{ - const GUID *guid = ToGUID (value, type); - if (guid != NULL) - { - Value = *guid; - } -} - -// -// More base cvar stuff -// - -void FBaseCVar::ResetColors () -{ - FBaseCVar *var = CVars; - - while (var) - { - if (var->GetRealType () == CVAR_Color) - { - var->DoSet (var->GetGenericRep (CVAR_Int), CVAR_Int); - } - var = var->m_Next; - } -} - -void FBaseCVar::ResetToDefault () -{ - if (!(Flags & CVAR_ISDEFAULT)) - { - UCVarValue val; - ECVarType type; - - val = GetFavoriteRepDefault (&type); - SetGenericRep (val, type); - Flags |= CVAR_ISDEFAULT; - } -} - -// -// Flag cvar implementation -// -// This type of cvar is not a "real" cvar. Instead, it gets and sets -// the value of a FIntCVar, modifying it bit-by-bit. As such, it has -// no default, and is not written to the .cfg or transferred around -// the network. The "host" cvar is responsible for that. -// - -FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, DWORD bitval) -: FBaseCVar (name, 0, NULL), -ValueVar (realvar), -BitVal (bitval) -{ - int bit; - - Flags &= ~CVAR_ISDEFAULT; - - assert (bitval != 0); - - bit = 0; - while ((bitval >>= 1) != 0) - { - ++bit; - } - BitNum = bit; - - assert ((1u << BitNum) == BitVal); -} - -ECVarType FFlagCVar::GetRealType () const -{ - return CVAR_Dummy; -} - -UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const -{ - return FromBool ((ValueVar & BitVal) != 0, type); -} - -UCVarValue FFlagCVar::GetFavoriteRep (ECVarType *type) const -{ - UCVarValue ret; - *type = CVAR_Bool; - ret.Bool = (ValueVar & BitVal) != 0; - return ret; -} - -UCVarValue FFlagCVar::GetGenericRepDefault (ECVarType type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - return FromBool ((def.Int & BitVal) != 0, type); -} - -UCVarValue FFlagCVar::GetFavoriteRepDefault (ECVarType *type) const -{ - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - def.Bool = (def.Int & BitVal) != 0; - *type = CVAR_Bool; - return def; -} - -void FFlagCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) -{ - bool newdef = ToBool (value, type); - ECVarType dummy; - UCVarValue def; - def = ValueVar.GetFavoriteRepDefault (&dummy); - if (newdef) - def.Int |= BitVal; - else - def.Int &= ~BitVal; - ValueVar.SetGenericRepDefault (def, CVAR_Int); -} - -void FFlagCVar::DoSet (UCVarValue value, ECVarType type) -{ - bool newval = ToBool (value, type); - - // Server cvars that get changed by this need to use a special message, because - // changes are not processed until the next net update. This is a problem with - // exec scripts because all flags will base their changes off of the value of - // the "master" cvar at the time the script was run, overriding any changes - // another flag might have made to the same cvar earlier in the script. - if ((ValueVar.Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) - { - if (netgame && consoleplayer != Net_Arbitrator) - { - Printf ("Only player %d can change %s\n", Net_Arbitrator+1, Name); - return; - } - D_SendServerFlagChange (&ValueVar, BitNum, newval); - } - else - { - int val = *ValueVar; - if (newval) - val |= BitVal; - else - val &= ~BitVal; - ValueVar = val; - } -} - -//////////////////////////////////////////////////////////////////////// -static int STACK_ARGS sortcvars (const void *a, const void *b) -{ - return strcmp (((*(FBaseCVar **)a))->GetName(), ((*(FBaseCVar **)b))->GetName()); -} - -void FilterCompactCVars (TArray &cvars, DWORD filter) -{ - FBaseCVar *cvar = CVars; - while (cvar) - { - if (cvar->Flags & filter) - cvars.Push (cvar); - cvar = cvar->m_Next; - } - if (cvars.Size () > 0) - { - cvars.ShrinkToFit (); - qsort (&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); - } -} - -void C_WriteCVars (BYTE **demo_p, DWORD filter, bool compact) -{ - FBaseCVar *cvar = CVars; - BYTE *ptr = *demo_p; - - if (compact) - { - TArray cvars; - ptr += sprintf ((char *)ptr, "\\\\%ux", filter); - FilterCompactCVars (cvars, filter); - while (cvars.Pop (cvar)) - { - UCVarValue val = cvar->GetGenericRep (CVAR_String); - ptr += sprintf ((char *)ptr, "\\%s", val.String); - } - } - else - { - cvar = CVars; - while (cvar) - { - if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSAVE)) - { - UCVarValue val = cvar->GetGenericRep (CVAR_String); - ptr += sprintf ((char *)ptr, "\\%s\\%s", - cvar->GetName (), val.String); - } - cvar = cvar->m_Next; - } - } - - *demo_p = ptr + 1; -} - -void C_ReadCVars (BYTE **demo_p) -{ - char *ptr = *((char **)demo_p); - char *breakpt; - - if (*ptr++ != '\\') - return; - - if (*ptr == '\\') - { // compact mode - TArray cvars; - FBaseCVar *cvar; - DWORD filter; - - ptr++; - breakpt = strchr (ptr, '\\'); - *breakpt = 0; - filter = strtoul (ptr, NULL, 16); - *breakpt = '\\'; - ptr = breakpt + 1; - - FilterCompactCVars (cvars, filter); - - while (cvars.Pop (cvar)) - { - UCVarValue val; - breakpt = strchr (ptr, '\\'); - if (breakpt) - *breakpt = 0; - val.String = ptr; - cvar->ForceSet (val, CVAR_String); - if (breakpt) - { - *breakpt = '\\'; - ptr = breakpt + 1; - } - else - break; - } - } - else - { - char *value; - - while ( (breakpt = strchr (ptr, '\\')) ) - { - *breakpt = 0; - value = breakpt + 1; - if ( (breakpt = strchr (value, '\\')) ) - *breakpt = 0; - - cvar_set (ptr, value); - - *(value - 1) = '\\'; - if (breakpt) - { - *breakpt = '\\'; - ptr = breakpt + 1; - } - else - { - break; - } - } - } - *demo_p += strlen (*((char **)demo_p)) + 1; -} - -static struct backup_s -{ - char *name, *string; -} CVarBackups[MAX_DEMOCVARS]; - -static int numbackedup = 0; - -void C_BackupCVars (void) -{ - struct backup_s *backup = CVarBackups; - FBaseCVar *cvar = CVars; - - while (cvar) - { - if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) - && !(cvar->Flags & CVAR_LATCH)) - { - if (backup == &CVarBackups[MAX_DEMOCVARS]) - I_Error ("C_BackupDemoCVars: Too many cvars to save (%d)", MAX_DEMOCVARS); - backup->name = copystring (cvar->GetName()); - backup->string = copystring (cvar->GetGenericRep (CVAR_String).String); - backup++; - } - cvar = cvar->m_Next; - } - numbackedup = backup - CVarBackups; -} - -void C_RestoreCVars (void) -{ - struct backup_s *backup = CVarBackups; - int i; - - for (i = numbackedup; i; i--, backup++) - { - cvar_set (backup->name, backup->string); - delete[] backup->name; - delete[] backup->string; - backup->name = backup->string = NULL; - } - numbackedup = 0; -} - -FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev) -{ - FBaseCVar *var; - FBaseCVar *dummy; - - if (var_name == NULL) - return NULL; - - if (prev == NULL) - prev = &dummy; - - var = CVars; - *prev = NULL; - while (var) - { - if (stricmp (var->GetName (), var_name) == 0) - break; - *prev = var; - var = var->m_Next; - } - return var; -} - -FBaseCVar *FindCVarSub (const char *var_name, int namelen) -{ - FBaseCVar *var; - - if (var_name == NULL) - return NULL; - - var = CVars; - while (var) - { - const char *probename = var->GetName (); - - if (strnicmp (probename, var_name, namelen) == 0 && - probename[namelen] == 0) - { - break; - } - var = var->m_Next; - } - return var; -} - -void UnlatchCVars (void) -{ - FLatchedValue var; - - while (LatchedValues.Pop (var)) - { - DWORD oldflags = var.Variable->Flags; - var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO); - var.Variable->SetGenericRep (var.Value, var.Type); - if (var.Type == CVAR_String) - delete[] var.Value.String; - var.Variable->Flags = oldflags; - } -} - -void C_SetCVarsToDefaults (void) -{ - FBaseCVar *cvar = CVars; - - while (cvar) - { - // Only default save-able cvars - if (cvar->Flags & CVAR_ARCHIVE) - { - UCVarValue val; - ECVarType type; - val = cvar->GetFavoriteRepDefault (&type); - cvar->SetGenericRep (val, type); - } - cvar = cvar->m_Next; - } -} - -void C_ArchiveCVars (FConfigFile *f, int type) -{ - // type 0: Game-specific cvars - // type 1: Global cvars - // type 2: Unknown cvars - // type 3: Unknown global cvars - // type 4: User info cvars - // type 5: Server info cvars - static const DWORD filters[6] = - { - CVAR_ARCHIVE, - CVAR_ARCHIVE|CVAR_GLOBALCONFIG, - CVAR_ARCHIVE|CVAR_AUTO, - CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO, - CVAR_ARCHIVE|CVAR_USERINFO, - CVAR_ARCHIVE|CVAR_SERVERINFO - }; - - FBaseCVar *cvar = CVars; - DWORD filter; - - filter = filters[type]; - - while (cvar) - { - if ((cvar->Flags & - (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) - == filter) - { - UCVarValue val; - val = cvar->GetGenericRep (CVAR_String); - f->SetValueForKey (cvar->GetName (), val.String); - } - cvar = cvar->m_Next; - } -} - -void FBaseCVar::CmdSet (const char *newval) -{ - UCVarValue val; - - // Casting away the const is safe in this case. - val.String = const_cast(newval); - SetGenericRep (val, CVAR_String); - - if (GetFlags() & CVAR_NOSET) - Printf ("%s is write protected.\n", GetName()); - else if (GetFlags() & CVAR_LATCH) - Printf ("%s will be changed for next game.\n", GetName()); -} - -CCMD (set) -{ - if (argv.argc() != 3) - { - Printf ("usage: set \n"); - } - else - { - FBaseCVar *var; - - var = FindCVar (argv[1], NULL); - if (var == NULL) - var = new FStringCVar (argv[1], NULL, CVAR_AUTO | CVAR_UNSETTABLE | cvar_defflags); - - var->CmdSet (argv[2]); - } -} - -CCMD (unset) -{ - if (argv.argc() != 2) - { - Printf ("usage: unset \n"); - } - else - { - FBaseCVar *var = FindCVar (argv[1], NULL); - if (var != NULL) - { - if (var->GetFlags() & CVAR_UNSETTABLE) - { - delete var; - } - else - { - Printf ("Cannot unset %s\n", argv[1]); - } - } - } -} - -CCMD (get) -{ - FBaseCVar *var, *prev; - - if (argv.argc() >= 2) - { - if ( (var = FindCVar (argv[1], &prev)) ) - { - UCVarValue val; - val = var->GetGenericRep (CVAR_String); - Printf ("\"%s\" is \"%s\"\n", var->GetName(), val.String); - } - else - { - Printf ("\"%s\" is unset\n", argv[1]); - } - } - else - { - Printf ("get: need variable name\n"); - } -} - -CCMD (toggle) -{ - FBaseCVar *var, *prev; - UCVarValue val; - - if (argv.argc() > 1) - { - if ( (var = FindCVar (argv[1], &prev)) ) - { - val = var->GetGenericRep (CVAR_Bool); - val.Bool = !val.Bool; - var->SetGenericRep (val, CVAR_Bool); - Printf ("\"%s\" is \"%s\"\n", var->GetName(), - val.Bool ? "true" : "false"); - } - } -} - -void FBaseCVar::ListVars (const char *filter, bool plain) -{ - FBaseCVar *var = CVars; - int count = 0; - - while (var) - { - if (CheckWildcards (filter, var->GetName())) - { - DWORD flags = var->GetFlags(); - UCVarValue val; - - val = var->GetGenericRep (CVAR_String); - if (plain) - { // plain formatting does not include user-defined cvars - if (!(flags & CVAR_UNSETTABLE)) - { - ++count; - Printf ("%s : %s\n", var->GetName(), var->GetGenericRep(CVAR_String).String); - } - } - else - { - ++count; - Printf ("%c%c%c %s : :%s\n", - flags & CVAR_ARCHIVE ? 'A' : ' ', - flags & CVAR_USERINFO ? 'U' : - flags & CVAR_SERVERINFO ? 'S' : - flags & CVAR_AUTO ? 'C' : ' ', - flags & CVAR_NOSET ? '-' : - flags & CVAR_LATCH ? 'L' : - flags & CVAR_UNSETTABLE ? '*' : ' ', - var->GetName(), - var->GetGenericRep (CVAR_String).String); - } - } - var = var->m_Next; - } - Printf ("%d cvars\n", count); -} - -CCMD (cvarlist) -{ - if (argv.argc() == 1) - { - FBaseCVar::ListVars (NULL, false); - } - else - { - FBaseCVar::ListVars (argv[1], false); - } -} - -CCMD (cvarlistplain) -{ - FBaseCVar::ListVars (NULL, true); -} - -CCMD (archivecvar) -{ - - if (argv.argc() == 1) - { - Printf ("Usage: archivecvar \n"); - } - else - { - FBaseCVar *var = FindCVar (argv[1], NULL); - - if (var != NULL && (var->GetFlags() & CVAR_AUTO)) - { - var->SetArchiveBit (); - } - } -} +/* +** c_cvars.cpp +** Defines all the different console variable types +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include + +#include "cmdlib.h" +#include "configfile.h" +#include "c_console.h" +#include "c_dispatch.h" +#include "m_alloc.h" + +#include "doomstat.h" +#include "c_cvars.h" +#include "d_player.h" + +#include "d_netinf.h" + +#include "i_system.h" +#include "v_palette.h" +#include "v_video.h" + +struct FLatchedValue +{ + FBaseCVar *Variable; + UCVarValue Value; + ECVarType Type; +}; + +static TArray LatchedValues; + +bool FBaseCVar::m_DoNoSet = false; +bool FBaseCVar::m_UseCallback = false; + +FBaseCVar *CVars = NULL; + +int cvar_defflags; + +FBaseCVar::FBaseCVar (const FBaseCVar &var) +{ + I_FatalError ("Use of cvar copy constructor"); +} + +FBaseCVar::FBaseCVar (const char *var_name, DWORD flags, void (*callback)(FBaseCVar &)) +{ + FBaseCVar *var; + + var = FindCVar (var_name, NULL); + + m_Callback = callback; + Flags = 0; + Name = NULL; + + if (var_name) + { + C_AddTabCommand (var_name); + Name = copystring (var_name); + m_Next = CVars; + CVars = this; + } + + if (var) + { + ECVarType type; + UCVarValue value; + + value = var->GetFavoriteRep (&type); + ForceSet (value, type); + + if (var->Flags & CVAR_AUTO) + delete var; + else + var->~FBaseCVar(); + + Flags = flags; + } + else + { + Flags = flags | CVAR_ISDEFAULT; + } +} + +FBaseCVar::~FBaseCVar () +{ + if (Name) + { + FBaseCVar *var, *prev; + + var = FindCVar (Name, &prev); + + if (var == this) + { + if (prev) + prev->m_Next = m_Next; + else + CVars = m_Next; + } + delete[] Name; + } +} + +void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) +{ + DoSet (value, type); + if (Flags & CVAR_USERINFO) + D_UserInfoChanged (this); + if (m_UseCallback) + Callback (); + + Flags &= ~CVAR_ISDEFAULT; +} + +void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type) +{ + if ((Flags & CVAR_NOSET) && m_DoNoSet) + { + return; + } + else if ((Flags & CVAR_LATCH) && gamestate != GS_FULLCONSOLE && gamestate != GS_STARTUP) + { + FLatchedValue latch; + + latch.Variable = this; + latch.Type = type; + if (type != CVAR_String) + latch.Value = value; + else + latch.Value.String = copystring(value.String); + LatchedValues.Push (latch); + } + else if ((Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) + { + if (netgame && !players[consoleplayer].settings_controller) + { + Printf ("Only setting controllers can change %s\n", Name); + return; + } + D_SendServerInfoChange (this, value, type); + } + else + { + ForceSet (value, type); + } +} + +bool FBaseCVar::ToBool (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return value.Bool; + + case CVAR_Int: + return !!value.Int; + + case CVAR_Float: + return value.Float != 0.f; + + case CVAR_String: + if (stricmp (value.String, "true") == 0) + return true; + else if (stricmp (value.String, "false") == 0) + return false; + else + return !!strtol (value.String, NULL, 0); + + case CVAR_GUID: + return false; + + default: + return false; + } +} + +int FBaseCVar::ToInt (UCVarValue value, ECVarType type) +{ + int res; +#if __GNUC__ <= 2 + float tmp; +#endif + + switch (type) + { + case CVAR_Bool: res = (int)value.Bool; break; + case CVAR_Int: res = value.Int; break; +#if __GNUC__ <= 2 + case CVAR_Float: tmp = value.Float; res = (int)tmp; break; +#else + case CVAR_Float: res = (int)value.Float; break; +#endif + case CVAR_String: res = strtol (value.String, NULL, 0); break; + case CVAR_GUID: res = 0; break; + default: res = 0; break; + } + return res; +} + +float FBaseCVar::ToFloat (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return (float)value.Bool; + + case CVAR_Int: + return (float)value.Int; + + case CVAR_Float: + return value.Float; + + case CVAR_String: + return strtod (value.String, NULL); + + case CVAR_GUID: + return 0.f; + + default: + return 0.f; + } +} + +static char cstrbuf[40]; +static GUID cGUID; +static char truestr[] = "true"; +static char falsestr[] = "false"; + +char *FBaseCVar::ToString (UCVarValue value, ECVarType type) +{ + switch (type) + { + case CVAR_Bool: + return value.Bool ? truestr : falsestr; + + case CVAR_String: + return value.String; + + case CVAR_Int: + sprintf (cstrbuf, "%i", value.Int); + break; + + case CVAR_Float: + sprintf (cstrbuf, "%g", value.Float); + break; + + case CVAR_GUID: + FormatGUID (cstrbuf, *value.pGUID); + break; + + default: + strcpy (cstrbuf, ""); + break; + } + return cstrbuf; +} + +const GUID *FBaseCVar::ToGUID (UCVarValue value, ECVarType type) +{ + UCVarValue trans; + + switch (type) + { + case CVAR_String: + trans = FromString (value.String, CVAR_GUID); + return trans.pGUID; + + case CVAR_GUID: + return value.pGUID; + + default: + return NULL; + } +} + +UCVarValue FBaseCVar::FromBool (bool value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value; + break; + + case CVAR_Int: + ret.Int = value; + break; + + case CVAR_Float: + ret.Float = value; + break; + + case CVAR_String: + ret.String = value ? truestr : falsestr; + break; + + case CVAR_GUID: + ret.pGUID = NULL; + break; + + default: + break; + } + + return ret; +} + +UCVarValue FBaseCVar::FromInt (int value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value != 0; + break; + + case CVAR_Int: + ret.Int = value; + break; + + case CVAR_Float: + ret.Float = (float)value; + break; + + case CVAR_String: + sprintf (cstrbuf, "%i", value); + ret.String = cstrbuf; + break; + + case CVAR_GUID: + ret.pGUID = NULL; + break; + + default: + break; + } + + return ret; +} + +UCVarValue FBaseCVar::FromFloat (float value, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = value != 0.f; + break; + + case CVAR_Int: + ret.Int = (int)value; + break; + + case CVAR_Float: + ret.Float = value; + break; + + case CVAR_String: + sprintf (cstrbuf, "%g", value); + ret.String = cstrbuf; + break; + + case CVAR_GUID: + ret.pGUID = NULL; + break; + + default: + break; + } + + return ret; +} + +static BYTE HexToByte (const char *hex) +{ + BYTE v = 0; + for (int i = 0; i < 2; ++i) + { + v <<= 4; + if (hex[i] >= '0' && hex[i] <= '9') + { + v += hex[i] - '0'; + } + else if (hex[i] >= 'A' && hex[i] <= 'F') + { + v += hex[i] - 'A'; + } + else // The string is already verified to contain valid hexits + { + v += hex[i] - 'a'; + } + } + return v; +} + +UCVarValue FBaseCVar::FromString (const char *value, ECVarType type) +{ + UCVarValue ret; + int i; + + switch (type) + { + case CVAR_Bool: + if (stricmp (value, "true") == 0) + ret.Bool = true; + else if (stricmp (value, "false") == 0) + ret.Bool = false; + else + ret.Bool = strtol (value, NULL, 0) != 0; + break; + + case CVAR_Int: + ret.Int = strtol (value, NULL, 0); + break; + + case CVAR_Float: + ret.Float = (float)strtod (value, NULL); + break; + + case CVAR_String: + ret.String = const_cast(value); + break; + + case CVAR_GUID: + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + // 01234567890123456789012345678901234567 + // 0 1 2 3 + + ret.pGUID = NULL; + for (i = 0; i < 38; ++i) + { + if (value[i] == 0) + { + break; + } + bool goodv = true; + switch (i) + { + case 0: + if (value[i] != '{') + goodv = false; + break; + case 9: + case 14: + case 19: + case 24: + if (value[i] != '-') + goodv = false; + break; + case 37: + if (value[i] != '}') + goodv = false; + break; + default: + if (value[i] < '0' && value[i] > '9' && + value[i] < 'A' && value[i] > 'F' && + value[i] < 'a' && value[i] > 'f') + { + goodv = false; + } + break; + } + } + if (i == 38 && value[i] == 0) + { + cGUID.Data1 = strtoul (value + 1, NULL, 16); + cGUID.Data2 = strtoul (value + 10, NULL, 16); + cGUID.Data3 = strtoul (value + 15, NULL, 16); + cGUID.Data4[0] = HexToByte (value + 20); + cGUID.Data4[1] = HexToByte (value + 22); + cGUID.Data4[2] = HexToByte (value + 25); + cGUID.Data4[3] = HexToByte (value + 27); + cGUID.Data4[4] = HexToByte (value + 29); + cGUID.Data4[5] = HexToByte (value + 31); + cGUID.Data4[6] = HexToByte (value + 33); + cGUID.Data4[7] = HexToByte (value + 35); + ret.pGUID = &cGUID; + } + break; + + default: + break; + } + + return ret; +} + +UCVarValue FBaseCVar::FromGUID (const GUID &guid, ECVarType type) +{ + UCVarValue ret; + + switch (type) + { + case CVAR_Bool: + ret.Bool = false; + break; + + case CVAR_Int: + ret.Int = 0; + break; + + case CVAR_Float: + ret.Float = 0.f; + break; + + case CVAR_String: + ret.pGUID = &guid; + ret.String = ToString (ret, CVAR_GUID); + break; + + case CVAR_GUID: + ret.pGUID = &guid; + break; + + default: + break; + } + + return ret; +} +FBaseCVar *cvar_set (const char *var_name, const char *val) +{ + FBaseCVar *var; + + if ( (var = FindCVar (var_name, NULL)) ) + { + UCVarValue value; + value.String = const_cast(val); + var->SetGenericRep (value, CVAR_String); + } + + return var; +} + +FBaseCVar *cvar_forceset (const char *var_name, const char *val) +{ + FBaseCVar *var; + UCVarValue vval; + + if ( (var = FindCVar (var_name, NULL)) ) + { + vval.String = const_cast(val); + var->ForceSet (vval, CVAR_String); + } + + return var; +} + +void FBaseCVar::EnableNoSet () +{ + m_DoNoSet = true; +} + +void FBaseCVar::EnableCallbacks () +{ + m_UseCallback = true; + FBaseCVar *cvar = CVars; + + while (cvar) + { + if (!(cvar->Flags & CVAR_NOINITCALL)) + { + cvar->Callback (); + } + cvar = cvar->m_Next; + } +} + +// +// Boolean cvar implementation +// + +FBoolCVar::FBoolCVar (const char *name, bool def, DWORD flags, void (*callback)(FBoolCVar &)) +: FBaseCVar (name, flags, reinterpret_cast(callback)) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FBoolCVar::GetRealType () const +{ + return CVAR_Bool; +} + +UCVarValue FBoolCVar::GetGenericRep (ECVarType type) const +{ + return FromBool (Value, type); +} + +UCVarValue FBoolCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = Value; + return ret; +} + +UCVarValue FBoolCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromBool (DefaultValue, type); +} + +UCVarValue FBoolCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = DefaultValue; + return ret; +} + +void FBoolCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToBool (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FBoolCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToBool (value, type); +} + +// +// Integer cvar implementation +// + +FIntCVar::FIntCVar (const char *name, int def, DWORD flags, void (*callback)(FIntCVar &)) +: FBaseCVar (name, flags, reinterpret_cast(callback)) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FIntCVar::GetRealType () const +{ + return CVAR_Int; +} + +UCVarValue FIntCVar::GetGenericRep (ECVarType type) const +{ + return FromInt (Value, type); +} + +UCVarValue FIntCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Int; + ret.Int = Value; + return ret; +} + +UCVarValue FIntCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromInt (DefaultValue, type); +} + +UCVarValue FIntCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Int; + ret.Int = DefaultValue; + return ret; +} + +void FIntCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToInt (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FIntCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToInt (value, type); +} + +// +// Floating point cvar implementation +// + +FFloatCVar::FFloatCVar (const char *name, float def, DWORD flags, void (*callback)(FFloatCVar &)) +: FBaseCVar (name, flags, reinterpret_cast(callback)) +{ + DefaultValue = def; + if (Flags & CVAR_ISDEFAULT) + Value = def; +} + +ECVarType FFloatCVar::GetRealType () const +{ + return CVAR_Float; +} + +UCVarValue FFloatCVar::GetGenericRep (ECVarType type) const +{ + return FromFloat (Value, type); +} + +UCVarValue FFloatCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Float; + ret.Float = Value; + return ret; +} + +UCVarValue FFloatCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromFloat (DefaultValue, type); +} + +UCVarValue FFloatCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Float; + ret.Float = DefaultValue; + return ret; +} + +void FFloatCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToFloat (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FFloatCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToFloat (value, type); +} + +// +// String cvar implementation +// + +FStringCVar::FStringCVar (const char *name, const char *def, DWORD flags, void (*callback)(FStringCVar &)) +: FBaseCVar (name, flags, reinterpret_cast(callback)) +{ + DefaultValue = copystring (def); + if (Flags & CVAR_ISDEFAULT) + Value = copystring (def); + else + Value = NULL; +} + +FStringCVar::~FStringCVar () +{ + if (Value != NULL) + { + delete[] Value; + } + delete[] DefaultValue; +} + +ECVarType FStringCVar::GetRealType () const +{ + return CVAR_String; +} + +UCVarValue FStringCVar::GetGenericRep (ECVarType type) const +{ + return FromString (Value, type); +} + +UCVarValue FStringCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_String; + ret.String = Value; + return ret; +} + +UCVarValue FStringCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromString (DefaultValue, type); +} + +UCVarValue FStringCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_String; + ret.String = DefaultValue; + return ret; +} + +void FStringCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + if (DefaultValue) + delete[] DefaultValue; + DefaultValue = ToString (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FStringCVar::DoSet (UCVarValue value, ECVarType type) +{ + ReplaceString (&Value, ToString (value, type)); +} + +// +// Color cvar implementation +// + +FColorCVar::FColorCVar (const char *name, int def, DWORD flags, void (*callback)(FColorCVar &)) +: FIntCVar (name, def, flags, reinterpret_cast(callback)) +{ +} + +ECVarType FColorCVar::GetRealType () const +{ + return CVAR_Color; +} + +UCVarValue FColorCVar::GetGenericRep (ECVarType type) const +{ + return FromInt2 (Value, type); +} + +UCVarValue FColorCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromInt2 (DefaultValue, type); +} + +void FColorCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + DefaultValue = ToInt2 (value, type); + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } +} + +void FColorCVar::DoSet (UCVarValue value, ECVarType type) +{ + Value = ToInt2 (value, type); + if (screen) + Index = ColorMatcher.Pick (RPART(Value), GPART(Value), BPART(Value)); +} + +UCVarValue FColorCVar::FromInt2 (int value, ECVarType type) +{ + if (type == CVAR_String) + { + UCVarValue ret; + sprintf (cstrbuf, "%02x %02x %02x", + RPART(value), GPART(value), BPART(value)); + ret.String = cstrbuf; + return ret; + } + return FromInt (value, type); +} + +int FColorCVar::ToInt2 (UCVarValue value, ECVarType type) +{ + int ret; + + if (type == CVAR_String) + { + FString string; + // Only allow named colors after the screen exists (i.e. after + // we've got some lumps loaded, so X11R6RGB can be read). Since + // the only time this might be called before that is when loading + // zdoom.ini, this shouldn't be a problem. + if (screen && !(string = V_GetColorStringByName (value.String)).IsEmpty() ) + { + ret = V_GetColorFromString (NULL, string); + } + else + { + ret = V_GetColorFromString (NULL, value.String); + } + } + else + { + ret = ToInt (value, type); + } + return ret; +} + +// +// GUID cvar implementation +// + +FGUIDCVar::FGUIDCVar (const char *name, const GUID *def, DWORD flags, void (*callback)(FGUIDCVar &)) +: FBaseCVar (name, flags, reinterpret_cast(callback)) +{ + if (def != NULL) + { + DefaultValue = *def; + if (Flags & CVAR_ISDEFAULT) + Value = *def; + } + else + { + memset (&Value, 0, sizeof(DefaultValue)); + memset (&DefaultValue, 0, sizeof(DefaultValue)); + } +} + +ECVarType FGUIDCVar::GetRealType () const +{ + return CVAR_GUID; +} + +UCVarValue FGUIDCVar::GetGenericRep (ECVarType type) const +{ + return FromGUID (Value, type); +} + +UCVarValue FGUIDCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_GUID; + ret.pGUID = &Value; + return ret; +} + +UCVarValue FGUIDCVar::GetGenericRepDefault (ECVarType type) const +{ + return FromGUID (DefaultValue, type); +} + +UCVarValue FGUIDCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_GUID; + ret.pGUID = &DefaultValue; + return ret; +} + +void FGUIDCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + const GUID *guid = ToGUID (value, type); + if (guid != NULL) + { + Value = *guid; + if (Flags & CVAR_ISDEFAULT) + { + SetGenericRep (value, type); + Flags |= CVAR_ISDEFAULT; + } + } +} + +void FGUIDCVar::DoSet (UCVarValue value, ECVarType type) +{ + const GUID *guid = ToGUID (value, type); + if (guid != NULL) + { + Value = *guid; + } +} + +// +// More base cvar stuff +// + +void FBaseCVar::ResetColors () +{ + FBaseCVar *var = CVars; + + while (var) + { + if (var->GetRealType () == CVAR_Color) + { + var->DoSet (var->GetGenericRep (CVAR_Int), CVAR_Int); + } + var = var->m_Next; + } +} + +void FBaseCVar::ResetToDefault () +{ + if (!(Flags & CVAR_ISDEFAULT)) + { + UCVarValue val; + ECVarType type; + + val = GetFavoriteRepDefault (&type); + SetGenericRep (val, type); + Flags |= CVAR_ISDEFAULT; + } +} + +// +// Flag cvar implementation +// +// This type of cvar is not a "real" cvar. Instead, it gets and sets +// the value of a FIntCVar, modifying it bit-by-bit. As such, it has +// no default, and is not written to the .cfg or transferred around +// the network. The "host" cvar is responsible for that. +// + +FFlagCVar::FFlagCVar (const char *name, FIntCVar &realvar, DWORD bitval) +: FBaseCVar (name, 0, NULL), +ValueVar (realvar), +BitVal (bitval) +{ + int bit; + + Flags &= ~CVAR_ISDEFAULT; + + assert (bitval != 0); + + bit = 0; + while ((bitval >>= 1) != 0) + { + ++bit; + } + BitNum = bit; + + assert ((1u << BitNum) == BitVal); +} + +ECVarType FFlagCVar::GetRealType () const +{ + return CVAR_Dummy; +} + +UCVarValue FFlagCVar::GetGenericRep (ECVarType type) const +{ + return FromBool ((ValueVar & BitVal) != 0, type); +} + +UCVarValue FFlagCVar::GetFavoriteRep (ECVarType *type) const +{ + UCVarValue ret; + *type = CVAR_Bool; + ret.Bool = (ValueVar & BitVal) != 0; + return ret; +} + +UCVarValue FFlagCVar::GetGenericRepDefault (ECVarType type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + return FromBool ((def.Int & BitVal) != 0, type); +} + +UCVarValue FFlagCVar::GetFavoriteRepDefault (ECVarType *type) const +{ + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + def.Bool = (def.Int & BitVal) != 0; + *type = CVAR_Bool; + return def; +} + +void FFlagCVar::SetGenericRepDefault (UCVarValue value, ECVarType type) +{ + bool newdef = ToBool (value, type); + ECVarType dummy; + UCVarValue def; + def = ValueVar.GetFavoriteRepDefault (&dummy); + if (newdef) + def.Int |= BitVal; + else + def.Int &= ~BitVal; + ValueVar.SetGenericRepDefault (def, CVAR_Int); +} + +void FFlagCVar::DoSet (UCVarValue value, ECVarType type) +{ + bool newval = ToBool (value, type); + + // Server cvars that get changed by this need to use a special message, because + // changes are not processed until the next net update. This is a problem with + // exec scripts because all flags will base their changes off of the value of + // the "master" cvar at the time the script was run, overriding any changes + // another flag might have made to the same cvar earlier in the script. + if ((ValueVar.Flags & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) + { + if (netgame && !players[consoleplayer].settings_controller) + { + Printf ("Only setting controllers can change %s\n", Name); + return; + } + D_SendServerFlagChange (&ValueVar, BitNum, newval); + } + else + { + int val = *ValueVar; + if (newval) + val |= BitVal; + else + val &= ~BitVal; + ValueVar = val; + } +} + +//////////////////////////////////////////////////////////////////////// +static int STACK_ARGS sortcvars (const void *a, const void *b) +{ + return strcmp (((*(FBaseCVar **)a))->GetName(), ((*(FBaseCVar **)b))->GetName()); +} + +void FilterCompactCVars (TArray &cvars, DWORD filter) +{ + FBaseCVar *cvar = CVars; + while (cvar) + { + if (cvar->Flags & filter) + cvars.Push (cvar); + cvar = cvar->m_Next; + } + if (cvars.Size () > 0) + { + cvars.ShrinkToFit (); + qsort (&cvars[0], cvars.Size(), sizeof(FBaseCVar *), sortcvars); + } +} + +void C_WriteCVars (BYTE **demo_p, DWORD filter, bool compact) +{ + FBaseCVar *cvar = CVars; + BYTE *ptr = *demo_p; + + if (compact) + { + TArray cvars; + ptr += sprintf ((char *)ptr, "\\\\%ux", filter); + FilterCompactCVars (cvars, filter); + while (cvars.Pop (cvar)) + { + UCVarValue val = cvar->GetGenericRep (CVAR_String); + ptr += sprintf ((char *)ptr, "\\%s", val.String); + } + } + else + { + cvar = CVars; + while (cvar) + { + if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSAVE)) + { + UCVarValue val = cvar->GetGenericRep (CVAR_String); + ptr += sprintf ((char *)ptr, "\\%s\\%s", + cvar->GetName (), val.String); + } + cvar = cvar->m_Next; + } + } + + *demo_p = ptr + 1; +} + +void C_ReadCVars (BYTE **demo_p) +{ + char *ptr = *((char **)demo_p); + char *breakpt; + + if (*ptr++ != '\\') + return; + + if (*ptr == '\\') + { // compact mode + TArray cvars; + FBaseCVar *cvar; + DWORD filter; + + ptr++; + breakpt = strchr (ptr, '\\'); + *breakpt = 0; + filter = strtoul (ptr, NULL, 16); + *breakpt = '\\'; + ptr = breakpt + 1; + + FilterCompactCVars (cvars, filter); + + while (cvars.Pop (cvar)) + { + UCVarValue val; + breakpt = strchr (ptr, '\\'); + if (breakpt) + *breakpt = 0; + val.String = ptr; + cvar->ForceSet (val, CVAR_String); + if (breakpt) + { + *breakpt = '\\'; + ptr = breakpt + 1; + } + else + break; + } + } + else + { + char *value; + + while ( (breakpt = strchr (ptr, '\\')) ) + { + *breakpt = 0; + value = breakpt + 1; + if ( (breakpt = strchr (value, '\\')) ) + *breakpt = 0; + + cvar_set (ptr, value); + + *(value - 1) = '\\'; + if (breakpt) + { + *breakpt = '\\'; + ptr = breakpt + 1; + } + else + { + break; + } + } + } + *demo_p += strlen (*((char **)demo_p)) + 1; +} + +static struct backup_s +{ + char *name, *string; +} CVarBackups[MAX_DEMOCVARS]; + +static int numbackedup = 0; + +void C_BackupCVars (void) +{ + struct backup_s *backup = CVarBackups; + FBaseCVar *cvar = CVars; + + while (cvar) + { + if ((cvar->Flags & (CVAR_SERVERINFO|CVAR_DEMOSAVE)) + && !(cvar->Flags & CVAR_LATCH)) + { + if (backup == &CVarBackups[MAX_DEMOCVARS]) + I_Error ("C_BackupDemoCVars: Too many cvars to save (%d)", MAX_DEMOCVARS); + backup->name = copystring (cvar->GetName()); + backup->string = copystring (cvar->GetGenericRep (CVAR_String).String); + backup++; + } + cvar = cvar->m_Next; + } + numbackedup = backup - CVarBackups; +} + +void C_RestoreCVars (void) +{ + struct backup_s *backup = CVarBackups; + int i; + + for (i = numbackedup; i; i--, backup++) + { + cvar_set (backup->name, backup->string); + delete[] backup->name; + delete[] backup->string; + backup->name = backup->string = NULL; + } + numbackedup = 0; +} + +FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev) +{ + FBaseCVar *var; + FBaseCVar *dummy; + + if (var_name == NULL) + return NULL; + + if (prev == NULL) + prev = &dummy; + + var = CVars; + *prev = NULL; + while (var) + { + if (stricmp (var->GetName (), var_name) == 0) + break; + *prev = var; + var = var->m_Next; + } + return var; +} + +FBaseCVar *FindCVarSub (const char *var_name, int namelen) +{ + FBaseCVar *var; + + if (var_name == NULL) + return NULL; + + var = CVars; + while (var) + { + const char *probename = var->GetName (); + + if (strnicmp (probename, var_name, namelen) == 0 && + probename[namelen] == 0) + { + break; + } + var = var->m_Next; + } + return var; +} + +void UnlatchCVars (void) +{ + FLatchedValue var; + + while (LatchedValues.Pop (var)) + { + DWORD oldflags = var.Variable->Flags; + var.Variable->Flags &= ~(CVAR_LATCH | CVAR_SERVERINFO); + var.Variable->SetGenericRep (var.Value, var.Type); + if (var.Type == CVAR_String) + delete[] var.Value.String; + var.Variable->Flags = oldflags; + } +} + +void C_SetCVarsToDefaults (void) +{ + FBaseCVar *cvar = CVars; + + while (cvar) + { + // Only default save-able cvars + if (cvar->Flags & CVAR_ARCHIVE) + { + UCVarValue val; + ECVarType type; + val = cvar->GetFavoriteRepDefault (&type); + cvar->SetGenericRep (val, type); + } + cvar = cvar->m_Next; + } +} + +void C_ArchiveCVars (FConfigFile *f, int type) +{ + // type 0: Game-specific cvars + // type 1: Global cvars + // type 2: Unknown cvars + // type 3: Unknown global cvars + // type 4: User info cvars + // type 5: Server info cvars + static const DWORD filters[6] = + { + CVAR_ARCHIVE, + CVAR_ARCHIVE|CVAR_GLOBALCONFIG, + CVAR_ARCHIVE|CVAR_AUTO, + CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO, + CVAR_ARCHIVE|CVAR_USERINFO, + CVAR_ARCHIVE|CVAR_SERVERINFO + }; + + FBaseCVar *cvar = CVars; + DWORD filter; + + filter = filters[type]; + + while (cvar) + { + if ((cvar->Flags & + (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) + == filter) + { + UCVarValue val; + val = cvar->GetGenericRep (CVAR_String); + f->SetValueForKey (cvar->GetName (), val.String); + } + cvar = cvar->m_Next; + } +} + +void FBaseCVar::CmdSet (const char *newval) +{ + UCVarValue val; + + // Casting away the const is safe in this case. + val.String = const_cast(newval); + SetGenericRep (val, CVAR_String); + + if (GetFlags() & CVAR_NOSET) + Printf ("%s is write protected.\n", GetName()); + else if (GetFlags() & CVAR_LATCH) + Printf ("%s will be changed for next game.\n", GetName()); +} + +CCMD (set) +{ + if (argv.argc() != 3) + { + Printf ("usage: set \n"); + } + else + { + FBaseCVar *var; + + var = FindCVar (argv[1], NULL); + if (var == NULL) + var = new FStringCVar (argv[1], NULL, CVAR_AUTO | CVAR_UNSETTABLE | cvar_defflags); + + var->CmdSet (argv[2]); + } +} + +CCMD (unset) +{ + if (argv.argc() != 2) + { + Printf ("usage: unset \n"); + } + else + { + FBaseCVar *var = FindCVar (argv[1], NULL); + if (var != NULL) + { + if (var->GetFlags() & CVAR_UNSETTABLE) + { + delete var; + } + else + { + Printf ("Cannot unset %s\n", argv[1]); + } + } + } +} + +CCMD (get) +{ + FBaseCVar *var, *prev; + + if (argv.argc() >= 2) + { + if ( (var = FindCVar (argv[1], &prev)) ) + { + UCVarValue val; + val = var->GetGenericRep (CVAR_String); + Printf ("\"%s\" is \"%s\"\n", var->GetName(), val.String); + } + else + { + Printf ("\"%s\" is unset\n", argv[1]); + } + } + else + { + Printf ("get: need variable name\n"); + } +} + +CCMD (toggle) +{ + FBaseCVar *var, *prev; + UCVarValue val; + + if (argv.argc() > 1) + { + if ( (var = FindCVar (argv[1], &prev)) ) + { + val = var->GetGenericRep (CVAR_Bool); + val.Bool = !val.Bool; + var->SetGenericRep (val, CVAR_Bool); + Printf ("\"%s\" is \"%s\"\n", var->GetName(), + val.Bool ? "true" : "false"); + } + } +} + +void FBaseCVar::ListVars (const char *filter, bool plain) +{ + FBaseCVar *var = CVars; + int count = 0; + + while (var) + { + if (CheckWildcards (filter, var->GetName())) + { + DWORD flags = var->GetFlags(); + UCVarValue val; + + val = var->GetGenericRep (CVAR_String); + if (plain) + { // plain formatting does not include user-defined cvars + if (!(flags & CVAR_UNSETTABLE)) + { + ++count; + Printf ("%s : %s\n", var->GetName(), var->GetGenericRep(CVAR_String).String); + } + } + else + { + ++count; + Printf ("%c%c%c %s : :%s\n", + flags & CVAR_ARCHIVE ? 'A' : ' ', + flags & CVAR_USERINFO ? 'U' : + flags & CVAR_SERVERINFO ? 'S' : + flags & CVAR_AUTO ? 'C' : ' ', + flags & CVAR_NOSET ? '-' : + flags & CVAR_LATCH ? 'L' : + flags & CVAR_UNSETTABLE ? '*' : ' ', + var->GetName(), + var->GetGenericRep (CVAR_String).String); + } + } + var = var->m_Next; + } + Printf ("%d cvars\n", count); +} + +CCMD (cvarlist) +{ + if (argv.argc() == 1) + { + FBaseCVar::ListVars (NULL, false); + } + else + { + FBaseCVar::ListVars (argv[1], false); + } +} + +CCMD (cvarlistplain) +{ + FBaseCVar::ListVars (NULL, true); +} + +CCMD (archivecvar) +{ + + if (argv.argc() == 1) + { + Printf ("Usage: archivecvar \n"); + } + else + { + FBaseCVar *var = FindCVar (argv[1], NULL); + + if (var != NULL && (var->GetFlags() & CVAR_AUTO)) + { + var->SetArchiveBit (); + } + } +} diff --git a/src/d_net.cpp b/src/d_net.cpp index 9fbcb6155..53d90068f 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -649,6 +649,7 @@ void PlayerIsGone (int netnode, int netconsole) if (playeringame[i] && !players[i].isbot) { Net_Arbitrator = i; + players[i].settings_controller = true; Printf ("%s is the new arbitrator\n", players[i].userinfo.netname); break; } @@ -1580,6 +1581,8 @@ void D_CheckNetGame (void) I_InitNetwork (); if (doomcom.id != DOOMCOM_ID) I_FatalError ("Doomcom buffer invalid!"); + + players[0].settings_controller = true; consoleplayer = doomcom.consoleplayer; @@ -2313,6 +2316,26 @@ void Net_DoCommand (int type, BYTE **stream, int player) playerswiping &= ~(1 << player); break; + case DEM_ADDCONTROLLER: + { + BYTE playernum = ReadByte (stream); + players[playernum].settings_controller = true; + + if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) + Printf ("%s has been added to the controller list.\n", players[playernum].userinfo.netname); + } + break; + + case DEM_DELCONTROLLER: + { + BYTE playernum = ReadByte (stream); + players[playernum].settings_controller = false; + + if (consoleplayer == playernum || consoleplayer == Net_Arbitrator) + Printf ("%s has been removed from the controller list.\n", players[playernum].userinfo.netname); + } + break; + default: I_Error ("Unknown net command: %d", type); break; @@ -2362,6 +2385,8 @@ void Net_SkipCommand (int type, BYTE **stream) case DEM_DROPPLAYER: case DEM_FOV: case DEM_MYFOV: + case DEM_ADDCONTROLLER: + case DEM_DELCONTROLLER: skip = 1; break; @@ -2417,3 +2442,132 @@ CCMD (pings) Printf ("% 4d %s\n", currrecvtime[i] - lastrecvtime[i], players[i].userinfo.netname); } + +//========================================================================== +// +// Network_Controller +// +// Implement players who have the ability to change settings in a network +// game. +// +//========================================================================== + +static void Network_Controller (int playernum, bool add) +{ + if (consoleplayer != Net_Arbitrator) + { + Printf ("This command is only accessible to the net arbitrator.\n"); + return; + } + + if (players[playernum].settings_controller && add) + { + Printf ("%s is already on the setting controller list.\n", players[playernum].userinfo.netname); + return; + } + + if (!players[playernum].settings_controller && !add) + { + Printf ("%s is not on the setting controller list.\n", players[playernum].userinfo.netname); + return; + } + + if (!playeringame[playernum]) + { + Printf ("Player (%d) not found!\n"); + return; + } + + if (players[playernum].isbot) + { + Printf ("Bots cannot be added to the controller list.\n"); + return; + } + + if (playernum == Net_Arbitrator) + { + Printf ("The net arbitrator cannot have their status changed on this list.\n"); + return; + } + + if (add) + Net_WriteByte (DEM_ADDCONTROLLER); + else + Net_WriteByte (DEM_DELCONTROLLER); + + Net_WriteByte (playernum); +} + +//========================================================================== +// +// CCMD net_addcontroller +// +//========================================================================== + +CCMD (net_addcontroller) +{ + if (!netgame) + { + Printf ("This command can only be used when playing a net game.\n"); + return; + } + + if (argv.argc () < 2) + { + Printf ("Usage: net_addcontroller \n"); + return; + } + + Network_Controller (atoi (argv[1]), true); +} + +//========================================================================== +// +// CCMD net_removecontroller +// +//========================================================================== + +CCMD (net_removecontroller) +{ + if (!netgame) + { + Printf ("This command can only be used when playing a net game.\n"); + return; + } + + if (argv.argc () < 2) + { + Printf ("Usage: net_removecontroller \n"); + return; + } + + Network_Controller (atoi (argv[1]), false); +} + +//========================================================================== +// +// CCMD net_listcontrollers +// +//========================================================================== + +CCMD (net_listcontrollers) +{ + if (!netgame) + { + Printf ("This command can only be used when playing a net game.\n"); + return; + } + + Printf ("The following players can change the game settings:\n"); + + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + if (players[i].settings_controller) + { + Printf ("- %s\n", players[i].userinfo.netname); + } + } +} diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index db91e781e..b2a21a58f 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -823,15 +823,18 @@ CCMD (playerinfo) else { int i = atoi (argv[1]); - Printf ("Name: %s\n", players[i].userinfo.netname); - Printf ("Team: %d\n", players[i].userinfo.team); - Printf ("Aimdist: %d\n", players[i].userinfo.aimdist); - Printf ("Color: %06x\n", players[i].userinfo.color); - Printf ("Skin: %d\n", players[i].userinfo.skin); - Printf ("Gender: %d\n", players[i].userinfo.gender); - Printf ("NeverSwitch: %d\n", players[i].userinfo.neverswitch); - Printf ("MoveBob: %g\n", players[i].userinfo.MoveBob/65536.f); - Printf ("StillBob: %g\n", players[i].userinfo.StillBob/65536.f); - Printf ("PlayerClass: %d\n", players[i].userinfo.PlayerClass); + userinfo_t *ui = &players[i].userinfo; + Printf ("Name: %s\n", ui->netname); + Printf ("Team: %s (%d)\n", ui->team == TEAM_None ? "None" : teams[ui->team].name, ui->team); + Printf ("Aimdist: %d\n", ui->aimdist); + Printf ("Color: %06x\n", ui->color); + Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin); + Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender); + Printf ("NeverSwitch: %d\n", ui->neverswitch); + Printf ("MoveBob: %g\n", ui->MoveBob/65536.f); + Printf ("StillBob: %g\n", ui->StillBob/65536.f); + Printf ("PlayerClass: %s (%d)\n", + ui->PlayerClass == -1 ? "Random" : PlayerClasses[ui->PlayerClass].Type->Meta.GetMetaString (APMETA_DisplayName), + ui->PlayerClass); } } diff --git a/src/d_player.h b/src/d_player.h index 72be0e890..e51c123d9 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -280,6 +280,8 @@ public: // pointed to by this. Allows bot to roam to it if // necessary. + bool settings_controller; // Player can control game settings. + //Skills struct botskill_t skill; diff --git a/src/d_protocol.h b/src/d_protocol.h index dde9a6c61..104d307e6 100644 --- a/src/d_protocol.h +++ b/src/d_protocol.h @@ -147,6 +147,8 @@ enum EDemoCommand DEM_WIPEON, // 45 Player started a screen wipe DEM_WIPEOFF, // 46 Player finished a screen wipe DEM_TAKECHEAT, // 47 String: item to take, Word: quantity + DEM_ADDCONTROLLER, // 48 Player to add to the controller list. + DEM_DELCONTROLLER, // 49 Player to remove from the controller list. }; // The following are implemented by cht_DoCheat in m_cheat.cpp diff --git a/src/p_user.cpp b/src/p_user.cpp index 4f8c02bd4..4265e9ca5 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -143,15 +143,15 @@ CCMD (addplayerclass) if (!ti) { - Printf ("Unknown player class '%s'", argv[1]); + Printf ("Unknown player class '%s'\n", argv[1]); } else if (!ti->IsDescendantOf (RUNTIME_CLASS (APlayerPawn))) { - Printf ("Invalid player class '%s'", argv[1]); + Printf ("Invalid player class '%s'\n", argv[1]); } else if (ti->Meta.GetMetaString (APMETA_DisplayName) == NULL) { - Printf ("Missing displayname for player class '%s'", argv[1]); + Printf ("Missing displayname for player class '%s'\n", argv[1]); } else { @@ -169,7 +169,7 @@ CCMD (addplayerclass) } else { - Printf ("Unknown flag '%s' for player class '%s'", argv[arg], argv[1]); + Printf ("Unknown flag '%s' for player class '%s'\n", argv[arg], argv[1]); } arg++;