aboutsummaryrefslogtreecommitdiff
path: root/mp/src/fgdlib/gdclass.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/fgdlib/gdclass.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/fgdlib/gdclass.cpp')
-rw-r--r--mp/src/fgdlib/gdclass.cpp2082
1 files changed, 1041 insertions, 1041 deletions
diff --git a/mp/src/fgdlib/gdclass.cpp b/mp/src/fgdlib/gdclass.cpp
index be07610e..1de57b6a 100644
--- a/mp/src/fgdlib/gdclass.cpp
+++ b/mp/src/fgdlib/gdclass.cpp
@@ -1,1041 +1,1041 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================
-
-#include "fgdlib/GameData.h" // FGDLIB: eliminate dependency
-#include "fgdlib/GDClass.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include <tier0/memdbgon.h>
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor.
-//-----------------------------------------------------------------------------
-GDclass::GDclass(void)
-{
- m_nVariables = 0;
- m_bBase = false;
- m_bSolid = false;
- m_bBase = false;
- m_bSolid = false;
- m_bModel = false;
- m_bMove = false;
- m_bKeyFrame = false;
- m_bPoint = false;
- m_bNPC = false;
- m_bFilter = false;
-
- m_bHalfGridSnap = false;
-
- m_bGotSize = false;
- m_bGotColor = false;
-
- m_rgbColor.r = 220;
- m_rgbColor.g = 30;
- m_rgbColor.b = 220;
- m_rgbColor.a = 0;
-
- m_pszDescription = NULL;
-
- for (int i = 0; i < 3; i++)
- {
- m_bmins[i] = -8;
- m_bmaxs[i] = 8;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor. Frees variable and helper lists.
-//-----------------------------------------------------------------------------
-GDclass::~GDclass(void)
-{
- //
- // Free variables.
- //
- int nCount = m_Variables.Count();
- for (int i = 0; i < nCount; i++)
- {
- GDinputvariable *pvi = m_Variables.Element(i);
- delete pvi;
- }
- m_Variables.RemoveAll();
-
- //
- // Free helpers.
- //
- nCount = m_Helpers.Count();
- for (int i = 0; i < nCount; i++)
- {
- CHelperInfo *pHelper = m_Helpers.Element(i);
- delete pHelper;
- }
- m_Helpers.RemoveAll();
-
- //
- // Free inputs.
- //
- nCount = m_Inputs.Count();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = m_Inputs.Element(i);
- delete pInput;
- }
- m_Inputs.RemoveAll();
-
- //
- // Free outputs.
- //
- nCount = m_Outputs.Count();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = m_Outputs.Element(i);
- delete pOutput;
- }
- m_Outputs.RemoveAll();
-
- delete m_pszDescription;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds the base class's variables to our variable list. Acquires the
-// base class's bounding box and color, if any.
-// Input : pszBase - Name of base class to add.
-//-----------------------------------------------------------------------------
-void GDclass::AddBase(GDclass *pBase)
-{
- int iBaseIndex;
- Parent->ClassForName(pBase->GetName(), &iBaseIndex);
-
- //
- // Add variables from base - update variable table
- //
- for (int i = 0; i < pBase->GetVariableCount(); i++)
- {
- GDinputvariable *pVar = pBase->GetVariableAt(i);
- AddVariable(pVar, pBase, iBaseIndex, i);
- }
-
- //
- // Add inputs from the base.
- // UNDONE: need to use references to inputs & outputs to conserve memory
- //
- int nCount = pBase->GetInputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = pBase->GetInput(i);
-
- CClassInput *pNew = new CClassInput;
- *pNew = *pInput;
- AddInput(pNew);
- }
-
- //
- // Add outputs from the base.
- //
- nCount = pBase->GetOutputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = pBase->GetOutput(i);
-
- CClassOutput *pNew = new CClassOutput;
- *pNew = *pOutput;
- AddOutput(pNew);
- }
-
- //
- // If we don't have a bounding box, try to get the base's box.
- //
- if (!m_bGotSize)
- {
- if (pBase->GetBoundBox(m_bmins, m_bmaxs))
- {
- m_bGotSize = true;
- }
- }
-
- //
- // If we don't have a color, use the base's color.
- //
- if (!m_bGotColor)
- {
- m_rgbColor = pBase->GetColor();
- m_bGotColor = true;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds the given GDInputVariable to this GDClass's list of variables.
-// Input : pVar -
-// pBase -
-// iBaseIndex -
-// iVarIndex -
-// Output : Returns TRUE if the pVar pointer was copied directly into this GDClass,
-// FALSE if not. If this function returns TRUE, pVar should not be
-// deleted by the caller.
-//-----------------------------------------------------------------------------
-BOOL GDclass::AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex)
-{
- int iThisIndex;
- GDinputvariable *pThisVar = VarForName(pVar->GetName(), &iThisIndex);
-
- //
- // Check to see if we are overriding an existing variable definition.
- //
- if (pThisVar != NULL)
- {
- //
- // Same name, different type. Flag this as an error.
- //
- if (pThisVar->GetType() != pVar->GetType())
- {
- return(false);
- }
-
- GDinputvariable *pAddVar;
- bool bReturn;
-
- //
- // Check to see if we need to combine a choices/flags array.
- //
- if (pVar->GetType() == ivFlags || pVar->GetType() == ivChoices)
- {
- //
- // Combine two variables' flags into a new variable. Add the new
- // variable to the local variable list and modify the old variable's
- // position in our variable map to reflect the new local variable.
- // This way, we can have multiple inheritance.
- //
- GDinputvariable *pNewVar = new GDinputvariable;
-
- *pNewVar = *pVar;
- pNewVar->Merge(*pThisVar);
-
- pAddVar = pNewVar;
- bReturn = false;
- }
- else
- {
- pAddVar = pVar;
- bReturn = true;
- }
-
- if (m_VariableMap[iThisIndex][0] == -1)
- {
- //
- // "pThisVar" is a leaf variable - we can remove since it is overridden.
- //
- int nIndex = m_Variables.Find(pThisVar);
- Assert(nIndex != -1);
- delete pThisVar;
-
- m_Variables.Element(nIndex) = pAddVar;
-
- //
- // No need to modify variable map - we just replaced
- // the pointer in the local variable list.
- //
- }
- else
- {
- //
- // "pThisVar" was declared in a base class - we can replace the reference in
- // our variable map with the new variable.
- //
- m_VariableMap[iThisIndex][0] = iBaseIndex;
-
- if (iBaseIndex == -1)
- {
- m_Variables.AddToTail(pAddVar);
- m_VariableMap[iThisIndex][1] = m_Variables.Count() - 1;
- }
- else
- {
- m_VariableMap[iThisIndex][1] = iVarIndex;
- }
- }
-
- return(bReturn);
- }
-
- //
- // New variable.
- //
- if (iBaseIndex == -1)
- {
- //
- // Variable declared in the leaf class definition - add it to the list.
- //
- m_Variables.AddToTail(pVar);
- }
-
- //
- // Too many variables already declared in this class definition - abort.
- //
- if (m_nVariables == GD_MAX_VARIABLES)
- {
- //CUtlString str;
- //str.Format("Too many gamedata variables for class \"%s\"", m_szName);
- //AfxMessageBox(str);
-
- return(false);
- }
-
- //
- // Add the variable to our list.
- //
- m_VariableMap[m_nVariables][0] = iBaseIndex;
- m_VariableMap[m_nVariables][1] = iVarIndex;
- ++m_nVariables;
-
- //
- // We added the pointer to our list of items (see Variables.AddToTail, above) so
- // we must return true here.
- //
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds an input by name.
-//-----------------------------------------------------------------------------
-CClassInput *GDclass::FindInput(const char *szName)
-{
- int nCount = GetInputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = GetInput(i);
- if (!stricmp(pInput->GetName(), szName))
- {
- return(pInput);
- }
- }
-
- return(NULL);
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds an output by name.
-//-----------------------------------------------------------------------------
-CClassOutput *GDclass::FindOutput(const char *szName)
-{
- int nCount = GetOutputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = GetOutput(i);
- if (!stricmp(pOutput->GetName(), szName))
- {
- return(pOutput);
- }
- }
-
- return(NULL);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the mins and maxs of the class's bounding box as read from the
-// FGD file. This controls the onscreen representation of any entities
-// derived from this class.
-// Input : pfMins - Receives minimum X, Y, and Z coordinates for the class.
-// pfMaxs - Receives maximum X, Y, and Z coordinates for the class.
-// Output : Returns TRUE if this class has a specified bounding box, FALSE if not.
-//-----------------------------------------------------------------------------
-BOOL GDclass::GetBoundBox(Vector& pfMins, Vector& pfMaxs)
-{
- if (m_bGotSize)
- {
- pfMins[0] = m_bmins[0];
- pfMins[1] = m_bmins[1];
- pfMins[2] = m_bmins[2];
-
- pfMaxs[0] = m_bmaxs[0];
- pfMaxs[1] = m_bmaxs[1];
- pfMaxs[2] = m_bmaxs[2];
- }
-
- return(m_bGotSize);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CHelperInfo *GDclass::GetHelper(int nIndex)
-{
- return m_Helpers.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CClassInput *GDclass::GetInput(int nIndex)
-{
- return m_Inputs.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CClassOutput *GDclass::GetOutput(int nIndex)
-{
- return m_Outputs.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : tr -
-// pGD -
-// Output : Returns TRUE if worth continuing, FALSE otherwise.
-//-----------------------------------------------------------------------------
-BOOL GDclass::InitFromTokens(TokenReader& tr, GameData *pGD)
-{
- Parent = pGD;
-
- //
- // Initialize VariableMap
- //
- for (int i = 0; i < GD_MAX_VARIABLES; i++)
- {
- m_VariableMap[i][0] = -1;
- m_VariableMap[i][1] = -1;
- }
-
- //
- // Parse all specifiers (base, size, color, etc.)
- //
- if (!ParseSpecifiers(tr))
- {
- return(FALSE);
- }
-
- //
- // Specifiers should be followed by an "="
- //
- if (!GDSkipToken(tr, OPERATOR, "="))
- {
- return(FALSE);
- }
-
- //
- // Parse the class name.
- //
- if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
- {
- return(FALSE);
- }
-
- //
- // Check next operator - if ":", we have a description - if "[",
- // we have no description.
- //
- char szToken[MAX_TOKEN];
- if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && IsToken(szToken, ":"))
- {
- // Skip ":"
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Free any existing description and set the pointer to NULL so that GDGetToken
- // allocates memory for us.
- //
- delete m_pszDescription;
- m_pszDescription = NULL;
-
- // Load description
- if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
- {
- return(FALSE);
- }
- }
-
- //
- // Opening square brace.
- //
- if (!GDSkipToken(tr, OPERATOR, "["))
- {
- return(FALSE);
- }
-
- //
- // Get class variables.
- //
- if (!ParseVariables(tr))
- {
- return(FALSE);
- }
-
- //
- // Closing square brace.
- //
- if (!GDSkipToken(tr, OPERATOR, "]"))
- {
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseBase(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- while (1)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- //
- // Find base class in list of classes.
- //
- GDclass *pBase = Parent->ClassForName(szToken);
- if (pBase == NULL)
- {
- GDError(tr, "undefined base class '%s", szToken);
- return(false);
- }
-
- AddBase(pBase);
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
- {
- return(false);
- }
-
- if (IsToken(szToken, ")"))
- {
- break;
- }
- else if (!IsToken(szToken, ","))
- {
- GDError(tr, "expecting ',' or ')', but found %s", szToken);
- return(false);
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseColor(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Red.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE r = atoi(szToken);
-
- //
- // Green.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE g = atoi(szToken);
-
- //
- // Blue.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE b = atoi(szToken);
-
- m_rgbColor.r = r;
- m_rgbColor.g = g;
- m_rgbColor.b = b;
- m_rgbColor.a = 0;
-
- m_bGotColor = true;
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Parses a helper from the FGD file. Helpers are of the following format:
-//
-// <helpername>(<parameter 0> <parameter 1> ... <parameter n>)
-//
-// When this function is called, the helper name has already been parsed.
-// Input : tr - Tokenreader to use for parsing.
-// pszHelperName - Name of the helper being declared.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseHelper(TokenReader &tr, char *pszHelperName)
-{
- char szToken[MAX_TOKEN];
-
- CHelperInfo *pHelper = new CHelperInfo;
- pHelper->SetName(pszHelperName);
-
- bool bCloseParen = false;
- while (!bCloseParen)
- {
- trtoken_t eType = tr.PeekTokenType(szToken,sizeof(szToken));
-
- if (eType == OPERATOR)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
- {
- delete pHelper;
- return(false);
- }
-
- if (IsToken(szToken, ")"))
- {
- bCloseParen = true;
- }
- else if (IsToken(szToken, "="))
- {
- delete pHelper;
- return(false);
- }
- }
- else
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), eType))
- {
- delete pHelper;
- return(false);
- }
- else
- {
- pHelper->AddParameter(szToken);
- }
- }
- }
-
- m_Helpers.AddToTail(pHelper);
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseSize(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Mins.
- //
- for (int i = 0; i < 3; i++)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
-
- m_bmins[i] = (float)atof(szToken);
- }
-
- if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR && IsToken(szToken, ","))
- {
- //
- // Skip ","
- //
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Get maxes.
- //
- for (int i = 0; i < 3; i++)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- m_bmaxs[i] = (float)atof(szToken);
- }
- }
- else
- {
- //
- // Split mins across origin.
- //
- for (int i = 0; i < 3; i++)
- {
- float div2 = m_bmins[i] / 2;
- m_bmaxs[i] = div2;
- m_bmins[i] = -div2;
- }
- }
-
- m_bGotSize = true;
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseSpecifiers(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- while (tr.PeekTokenType() == IDENT)
- {
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Handle specifiers that don't have any parens after them.
- //
- if (IsToken(szToken, "halfgridsnap"))
- {
- m_bHalfGridSnap = true;
- }
- else
- {
- //
- // Handle specifiers require parens after them.
- //
- if (!GDSkipToken(tr, OPERATOR, "("))
- {
- return(false);
- }
-
- if (IsToken(szToken, "base"))
- {
- if (!ParseBase(tr))
- {
- return(false);
- }
- }
- else if (IsToken(szToken, "size"))
- {
- if (!ParseSize(tr))
- {
- return(false);
- }
- }
- else if (IsToken(szToken, "color"))
- {
- if (!ParseColor(tr))
- {
- return(false);
- }
- }
- else if (!ParseHelper(tr, szToken))
- {
- return(false);
- }
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an input using a given token reader. If the input is
-// read successfully, the input is added to this class. If not, a
-// parsing failure is returned.
-// Input : tr - Token reader to use for parsing.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseInput(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "input"))
- {
- return(false);
- }
-
- CClassInput *pInput = new CClassInput;
-
- bool bReturn = ParseInputOutput(tr, pInput);
- if (bReturn)
- {
- AddInput(pInput);
- }
- else
- {
- delete pInput;
- }
-
- return(bReturn);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an input or output using a given token reader.
-// Input : tr - Token reader to use for parsing.
-// pInputOutput - Input or output to fill out.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Read the name.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- pInputOutput->SetName(szToken);
-
- //
- // Read the type.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, "("))
- {
- return(false);
- }
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- InputOutputType_t eType = pInputOutput->SetType(szToken);
- if (eType == iotInvalid)
- {
- GDError(tr, "bad input/output type '%s'", szToken);
- return(false);
- }
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- //
- // Check the next operator - if ':', we have a description.
- //
- if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && (IsToken(szToken, ":")))
- {
- //
- // Skip the ":".
- //
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Read the description.
- //
- char *pszDescription;
- if (!GDGetTokenDynamic(tr, &pszDescription, STRING))
- {
- return(false);
- }
-
- pInputOutput->SetDescription(pszDescription);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an output using a given token reader. If the output is
-// read successfully, the output is added to this class. If not, a
-// parsing failure is returned.
-// Input : tr - Token reader to use for parsing.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseOutput(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "output"))
- {
- return(false);
- }
-
- CClassOutput *pOutput = new CClassOutput;
-
- bool bReturn = ParseInputOutput(tr, pOutput);
- if (bReturn)
- {
- AddOutput(pOutput);
- }
- else
- {
- delete pOutput;
- }
-
- return(bReturn);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseVariables(TokenReader &tr)
-{
- while (1)
- {
- char szToken[MAX_TOKEN];
-
- if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR)
- {
- break;
- }
-
- if (!stricmp(szToken, "input"))
- {
- if (!ParseInput(tr))
- {
- return(false);
- }
-
- continue;
- }
-
- if (!stricmp(szToken, "output"))
- {
- if (!ParseOutput(tr))
- {
- return(false);
- }
-
- continue;
- }
-
- if (!stricmp(szToken, "key"))
- {
- GDGetToken(tr, szToken, sizeof(szToken));
- }
-
- GDinputvariable * var = new GDinputvariable;
- if (!var->InitFromTokens(tr))
- {
- delete var;
- return(false);
- }
-
- int nDupIndex;
- GDinputvariable *pDupVar = VarForName(var->GetName(), &nDupIndex);
-
- // check for duplicate variable definitions
- if (pDupVar)
- {
- // Same name, different type.
- if (pDupVar->GetType() != var->GetType())
- {
- char szError[_MAX_PATH];
-
- sprintf(szError, "%s: Variable '%s' is multiply defined with different types.", GetName(), var->GetName());
- GDError(tr, szError);
- }
- }
-
- if (!AddVariable(var, this, -1, m_Variables.Count()))
- {
- delete var;
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : iIndex -
-// Output : GDinputvariable *
-//-----------------------------------------------------------------------------
-GDinputvariable *GDclass::GetVariableAt(int iIndex)
-{
- if ( iIndex < 0 || iIndex >= m_nVariables )
- return NULL;
-
- if (m_VariableMap[iIndex][0] == -1)
- {
- return m_Variables.Element(m_VariableMap[iIndex][1]);
- }
-
- // find var's owner
- GDclass *pVarClass = Parent->GetClass(m_VariableMap[iIndex][0]);
-
- // find var in pVarClass
- return pVarClass->GetVariableAt(m_VariableMap[iIndex][1]);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-GDinputvariable *GDclass::VarForName(const char *pszName, int *piIndex)
-{
- for(int i = 0; i < GetVariableCount(); i++)
- {
- GDinputvariable *pVar = GetVariableAt(i);
- if(!strcmpi(pVar->GetName(), pszName))
- {
- if(piIndex)
- piIndex[0] = i;
- return pVar;
- }
- }
-
- return NULL;
-}
-
-void GDclass::GetHelperForGDVar( GDinputvariable *pVar, CUtlVector<const char *> *pszHelperName )
-{
- const char *pszName = pVar->GetName();
- for( int i = 0; i < GetHelperCount(); i++ )
- {
- CHelperInfo *pHelper = GetHelper( i );
- int nParamCount = pHelper->GetParameterCount();
- for ( int j = 0; j < nParamCount; j++ )
- {
- if ( !strcmpi( pszName, pHelper->GetParameter( j ) ) )
- {
- pszHelperName->AddToTail(pHelper->GetName());
- }
- }
- }
-}
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "fgdlib/GameData.h" // FGDLIB: eliminate dependency
+#include "fgdlib/GDClass.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+GDclass::GDclass(void)
+{
+ m_nVariables = 0;
+ m_bBase = false;
+ m_bSolid = false;
+ m_bBase = false;
+ m_bSolid = false;
+ m_bModel = false;
+ m_bMove = false;
+ m_bKeyFrame = false;
+ m_bPoint = false;
+ m_bNPC = false;
+ m_bFilter = false;
+
+ m_bHalfGridSnap = false;
+
+ m_bGotSize = false;
+ m_bGotColor = false;
+
+ m_rgbColor.r = 220;
+ m_rgbColor.g = 30;
+ m_rgbColor.b = 220;
+ m_rgbColor.a = 0;
+
+ m_pszDescription = NULL;
+
+ for (int i = 0; i < 3; i++)
+ {
+ m_bmins[i] = -8;
+ m_bmaxs[i] = 8;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor. Frees variable and helper lists.
+//-----------------------------------------------------------------------------
+GDclass::~GDclass(void)
+{
+ //
+ // Free variables.
+ //
+ int nCount = m_Variables.Count();
+ for (int i = 0; i < nCount; i++)
+ {
+ GDinputvariable *pvi = m_Variables.Element(i);
+ delete pvi;
+ }
+ m_Variables.RemoveAll();
+
+ //
+ // Free helpers.
+ //
+ nCount = m_Helpers.Count();
+ for (int i = 0; i < nCount; i++)
+ {
+ CHelperInfo *pHelper = m_Helpers.Element(i);
+ delete pHelper;
+ }
+ m_Helpers.RemoveAll();
+
+ //
+ // Free inputs.
+ //
+ nCount = m_Inputs.Count();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassInput *pInput = m_Inputs.Element(i);
+ delete pInput;
+ }
+ m_Inputs.RemoveAll();
+
+ //
+ // Free outputs.
+ //
+ nCount = m_Outputs.Count();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassOutput *pOutput = m_Outputs.Element(i);
+ delete pOutput;
+ }
+ m_Outputs.RemoveAll();
+
+ delete m_pszDescription;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the base class's variables to our variable list. Acquires the
+// base class's bounding box and color, if any.
+// Input : pszBase - Name of base class to add.
+//-----------------------------------------------------------------------------
+void GDclass::AddBase(GDclass *pBase)
+{
+ int iBaseIndex;
+ Parent->ClassForName(pBase->GetName(), &iBaseIndex);
+
+ //
+ // Add variables from base - update variable table
+ //
+ for (int i = 0; i < pBase->GetVariableCount(); i++)
+ {
+ GDinputvariable *pVar = pBase->GetVariableAt(i);
+ AddVariable(pVar, pBase, iBaseIndex, i);
+ }
+
+ //
+ // Add inputs from the base.
+ // UNDONE: need to use references to inputs & outputs to conserve memory
+ //
+ int nCount = pBase->GetInputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassInput *pInput = pBase->GetInput(i);
+
+ CClassInput *pNew = new CClassInput;
+ *pNew = *pInput;
+ AddInput(pNew);
+ }
+
+ //
+ // Add outputs from the base.
+ //
+ nCount = pBase->GetOutputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassOutput *pOutput = pBase->GetOutput(i);
+
+ CClassOutput *pNew = new CClassOutput;
+ *pNew = *pOutput;
+ AddOutput(pNew);
+ }
+
+ //
+ // If we don't have a bounding box, try to get the base's box.
+ //
+ if (!m_bGotSize)
+ {
+ if (pBase->GetBoundBox(m_bmins, m_bmaxs))
+ {
+ m_bGotSize = true;
+ }
+ }
+
+ //
+ // If we don't have a color, use the base's color.
+ //
+ if (!m_bGotColor)
+ {
+ m_rgbColor = pBase->GetColor();
+ m_bGotColor = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds the given GDInputVariable to this GDClass's list of variables.
+// Input : pVar -
+// pBase -
+// iBaseIndex -
+// iVarIndex -
+// Output : Returns TRUE if the pVar pointer was copied directly into this GDClass,
+// FALSE if not. If this function returns TRUE, pVar should not be
+// deleted by the caller.
+//-----------------------------------------------------------------------------
+BOOL GDclass::AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex)
+{
+ int iThisIndex;
+ GDinputvariable *pThisVar = VarForName(pVar->GetName(), &iThisIndex);
+
+ //
+ // Check to see if we are overriding an existing variable definition.
+ //
+ if (pThisVar != NULL)
+ {
+ //
+ // Same name, different type. Flag this as an error.
+ //
+ if (pThisVar->GetType() != pVar->GetType())
+ {
+ return(false);
+ }
+
+ GDinputvariable *pAddVar;
+ bool bReturn;
+
+ //
+ // Check to see if we need to combine a choices/flags array.
+ //
+ if (pVar->GetType() == ivFlags || pVar->GetType() == ivChoices)
+ {
+ //
+ // Combine two variables' flags into a new variable. Add the new
+ // variable to the local variable list and modify the old variable's
+ // position in our variable map to reflect the new local variable.
+ // This way, we can have multiple inheritance.
+ //
+ GDinputvariable *pNewVar = new GDinputvariable;
+
+ *pNewVar = *pVar;
+ pNewVar->Merge(*pThisVar);
+
+ pAddVar = pNewVar;
+ bReturn = false;
+ }
+ else
+ {
+ pAddVar = pVar;
+ bReturn = true;
+ }
+
+ if (m_VariableMap[iThisIndex][0] == -1)
+ {
+ //
+ // "pThisVar" is a leaf variable - we can remove since it is overridden.
+ //
+ int nIndex = m_Variables.Find(pThisVar);
+ Assert(nIndex != -1);
+ delete pThisVar;
+
+ m_Variables.Element(nIndex) = pAddVar;
+
+ //
+ // No need to modify variable map - we just replaced
+ // the pointer in the local variable list.
+ //
+ }
+ else
+ {
+ //
+ // "pThisVar" was declared in a base class - we can replace the reference in
+ // our variable map with the new variable.
+ //
+ m_VariableMap[iThisIndex][0] = iBaseIndex;
+
+ if (iBaseIndex == -1)
+ {
+ m_Variables.AddToTail(pAddVar);
+ m_VariableMap[iThisIndex][1] = m_Variables.Count() - 1;
+ }
+ else
+ {
+ m_VariableMap[iThisIndex][1] = iVarIndex;
+ }
+ }
+
+ return(bReturn);
+ }
+
+ //
+ // New variable.
+ //
+ if (iBaseIndex == -1)
+ {
+ //
+ // Variable declared in the leaf class definition - add it to the list.
+ //
+ m_Variables.AddToTail(pVar);
+ }
+
+ //
+ // Too many variables already declared in this class definition - abort.
+ //
+ if (m_nVariables == GD_MAX_VARIABLES)
+ {
+ //CUtlString str;
+ //str.Format("Too many gamedata variables for class \"%s\"", m_szName);
+ //AfxMessageBox(str);
+
+ return(false);
+ }
+
+ //
+ // Add the variable to our list.
+ //
+ m_VariableMap[m_nVariables][0] = iBaseIndex;
+ m_VariableMap[m_nVariables][1] = iVarIndex;
+ ++m_nVariables;
+
+ //
+ // We added the pointer to our list of items (see Variables.AddToTail, above) so
+ // we must return true here.
+ //
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds an input by name.
+//-----------------------------------------------------------------------------
+CClassInput *GDclass::FindInput(const char *szName)
+{
+ int nCount = GetInputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassInput *pInput = GetInput(i);
+ if (!stricmp(pInput->GetName(), szName))
+ {
+ return(pInput);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds an output by name.
+//-----------------------------------------------------------------------------
+CClassOutput *GDclass::FindOutput(const char *szName)
+{
+ int nCount = GetOutputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassOutput *pOutput = GetOutput(i);
+ if (!stricmp(pOutput->GetName(), szName))
+ {
+ return(pOutput);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the mins and maxs of the class's bounding box as read from the
+// FGD file. This controls the onscreen representation of any entities
+// derived from this class.
+// Input : pfMins - Receives minimum X, Y, and Z coordinates for the class.
+// pfMaxs - Receives maximum X, Y, and Z coordinates for the class.
+// Output : Returns TRUE if this class has a specified bounding box, FALSE if not.
+//-----------------------------------------------------------------------------
+BOOL GDclass::GetBoundBox(Vector& pfMins, Vector& pfMaxs)
+{
+ if (m_bGotSize)
+ {
+ pfMins[0] = m_bmins[0];
+ pfMins[1] = m_bmins[1];
+ pfMins[2] = m_bmins[2];
+
+ pfMaxs[0] = m_bmaxs[0];
+ pfMaxs[1] = m_bmaxs[1];
+ pfMaxs[2] = m_bmaxs[2];
+ }
+
+ return(m_bGotSize);
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CHelperInfo *GDclass::GetHelper(int nIndex)
+{
+ return m_Helpers.Element(nIndex);
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CClassInput *GDclass::GetInput(int nIndex)
+{
+ return m_Inputs.Element(nIndex);
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CClassOutput *GDclass::GetOutput(int nIndex)
+{
+ return m_Outputs.Element(nIndex);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : tr -
+// pGD -
+// Output : Returns TRUE if worth continuing, FALSE otherwise.
+//-----------------------------------------------------------------------------
+BOOL GDclass::InitFromTokens(TokenReader& tr, GameData *pGD)
+{
+ Parent = pGD;
+
+ //
+ // Initialize VariableMap
+ //
+ for (int i = 0; i < GD_MAX_VARIABLES; i++)
+ {
+ m_VariableMap[i][0] = -1;
+ m_VariableMap[i][1] = -1;
+ }
+
+ //
+ // Parse all specifiers (base, size, color, etc.)
+ //
+ if (!ParseSpecifiers(tr))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Specifiers should be followed by an "="
+ //
+ if (!GDSkipToken(tr, OPERATOR, "="))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Parse the class name.
+ //
+ if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Check next operator - if ":", we have a description - if "[",
+ // we have no description.
+ //
+ char szToken[MAX_TOKEN];
+ if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && IsToken(szToken, ":"))
+ {
+ // Skip ":"
+ tr.NextToken(szToken, sizeof(szToken));
+
+ //
+ // Free any existing description and set the pointer to NULL so that GDGetToken
+ // allocates memory for us.
+ //
+ delete m_pszDescription;
+ m_pszDescription = NULL;
+
+ // Load description
+ if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
+ {
+ return(FALSE);
+ }
+ }
+
+ //
+ // Opening square brace.
+ //
+ if (!GDSkipToken(tr, OPERATOR, "["))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Get class variables.
+ //
+ if (!ParseVariables(tr))
+ {
+ return(FALSE);
+ }
+
+ //
+ // Closing square brace.
+ //
+ if (!GDSkipToken(tr, OPERATOR, "]"))
+ {
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseBase(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ while (1)
+ {
+ if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
+ {
+ return(false);
+ }
+
+ //
+ // Find base class in list of classes.
+ //
+ GDclass *pBase = Parent->ClassForName(szToken);
+ if (pBase == NULL)
+ {
+ GDError(tr, "undefined base class '%s", szToken);
+ return(false);
+ }
+
+ AddBase(pBase);
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
+ {
+ return(false);
+ }
+
+ if (IsToken(szToken, ")"))
+ {
+ break;
+ }
+ else if (!IsToken(szToken, ","))
+ {
+ GDError(tr, "expecting ',' or ')', but found %s", szToken);
+ return(false);
+ }
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseColor(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ //
+ // Red.
+ //
+ if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
+ {
+ return(false);
+ }
+ BYTE r = atoi(szToken);
+
+ //
+ // Green.
+ //
+ if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
+ {
+ return(false);
+ }
+ BYTE g = atoi(szToken);
+
+ //
+ // Blue.
+ //
+ if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
+ {
+ return(false);
+ }
+ BYTE b = atoi(szToken);
+
+ m_rgbColor.r = r;
+ m_rgbColor.g = g;
+ m_rgbColor.b = b;
+ m_rgbColor.a = 0;
+
+ m_bGotColor = true;
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
+ {
+ return(false);
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses a helper from the FGD file. Helpers are of the following format:
+//
+// <helpername>(<parameter 0> <parameter 1> ... <parameter n>)
+//
+// When this function is called, the helper name has already been parsed.
+// Input : tr - Tokenreader to use for parsing.
+// pszHelperName - Name of the helper being declared.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseHelper(TokenReader &tr, char *pszHelperName)
+{
+ char szToken[MAX_TOKEN];
+
+ CHelperInfo *pHelper = new CHelperInfo;
+ pHelper->SetName(pszHelperName);
+
+ bool bCloseParen = false;
+ while (!bCloseParen)
+ {
+ trtoken_t eType = tr.PeekTokenType(szToken,sizeof(szToken));
+
+ if (eType == OPERATOR)
+ {
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
+ {
+ delete pHelper;
+ return(false);
+ }
+
+ if (IsToken(szToken, ")"))
+ {
+ bCloseParen = true;
+ }
+ else if (IsToken(szToken, "="))
+ {
+ delete pHelper;
+ return(false);
+ }
+ }
+ else
+ {
+ if (!GDGetToken(tr, szToken, sizeof(szToken), eType))
+ {
+ delete pHelper;
+ return(false);
+ }
+ else
+ {
+ pHelper->AddParameter(szToken);
+ }
+ }
+ }
+
+ m_Helpers.AddToTail(pHelper);
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseSize(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ //
+ // Mins.
+ //
+ for (int i = 0; i < 3; i++)
+ {
+ if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
+ {
+ return(false);
+ }
+
+ m_bmins[i] = (float)atof(szToken);
+ }
+
+ if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR && IsToken(szToken, ","))
+ {
+ //
+ // Skip ","
+ //
+ tr.NextToken(szToken, sizeof(szToken));
+
+ //
+ // Get maxes.
+ //
+ for (int i = 0; i < 3; i++)
+ {
+ if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
+ {
+ return(false);
+ }
+ m_bmaxs[i] = (float)atof(szToken);
+ }
+ }
+ else
+ {
+ //
+ // Split mins across origin.
+ //
+ for (int i = 0; i < 3; i++)
+ {
+ float div2 = m_bmins[i] / 2;
+ m_bmaxs[i] = div2;
+ m_bmins[i] = -div2;
+ }
+ }
+
+ m_bGotSize = true;
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
+ {
+ return(false);
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseSpecifiers(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ while (tr.PeekTokenType() == IDENT)
+ {
+ tr.NextToken(szToken, sizeof(szToken));
+
+ //
+ // Handle specifiers that don't have any parens after them.
+ //
+ if (IsToken(szToken, "halfgridsnap"))
+ {
+ m_bHalfGridSnap = true;
+ }
+ else
+ {
+ //
+ // Handle specifiers require parens after them.
+ //
+ if (!GDSkipToken(tr, OPERATOR, "("))
+ {
+ return(false);
+ }
+
+ if (IsToken(szToken, "base"))
+ {
+ if (!ParseBase(tr))
+ {
+ return(false);
+ }
+ }
+ else if (IsToken(szToken, "size"))
+ {
+ if (!ParseSize(tr))
+ {
+ return(false);
+ }
+ }
+ else if (IsToken(szToken, "color"))
+ {
+ if (!ParseColor(tr))
+ {
+ return(false);
+ }
+ }
+ else if (!ParseHelper(tr, szToken))
+ {
+ return(false);
+ }
+ }
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads an input using a given token reader. If the input is
+// read successfully, the input is added to this class. If not, a
+// parsing failure is returned.
+// Input : tr - Token reader to use for parsing.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseInput(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "input"))
+ {
+ return(false);
+ }
+
+ CClassInput *pInput = new CClassInput;
+
+ bool bReturn = ParseInputOutput(tr, pInput);
+ if (bReturn)
+ {
+ AddInput(pInput);
+ }
+ else
+ {
+ delete pInput;
+ }
+
+ return(bReturn);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads an input or output using a given token reader.
+// Input : tr - Token reader to use for parsing.
+// pInputOutput - Input or output to fill out.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput)
+{
+ char szToken[MAX_TOKEN];
+
+ //
+ // Read the name.
+ //
+ if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
+ {
+ return(false);
+ }
+
+ pInputOutput->SetName(szToken);
+
+ //
+ // Read the type.
+ //
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, "("))
+ {
+ return(false);
+ }
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
+ {
+ return(false);
+ }
+
+ InputOutputType_t eType = pInputOutput->SetType(szToken);
+ if (eType == iotInvalid)
+ {
+ GDError(tr, "bad input/output type '%s'", szToken);
+ return(false);
+ }
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
+ {
+ return(false);
+ }
+
+ //
+ // Check the next operator - if ':', we have a description.
+ //
+ if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && (IsToken(szToken, ":")))
+ {
+ //
+ // Skip the ":".
+ //
+ tr.NextToken(szToken, sizeof(szToken));
+
+ //
+ // Read the description.
+ //
+ char *pszDescription;
+ if (!GDGetTokenDynamic(tr, &pszDescription, STRING))
+ {
+ return(false);
+ }
+
+ pInputOutput->SetDescription(pszDescription);
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Reads an output using a given token reader. If the output is
+// read successfully, the output is added to this class. If not, a
+// parsing failure is returned.
+// Input : tr - Token reader to use for parsing.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseOutput(TokenReader &tr)
+{
+ char szToken[MAX_TOKEN];
+
+ if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "output"))
+ {
+ return(false);
+ }
+
+ CClassOutput *pOutput = new CClassOutput;
+
+ bool bReturn = ParseInputOutput(tr, pOutput);
+ if (bReturn)
+ {
+ AddOutput(pOutput);
+ }
+ else
+ {
+ delete pOutput;
+ }
+
+ return(bReturn);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &tr -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool GDclass::ParseVariables(TokenReader &tr)
+{
+ while (1)
+ {
+ char szToken[MAX_TOKEN];
+
+ if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR)
+ {
+ break;
+ }
+
+ if (!stricmp(szToken, "input"))
+ {
+ if (!ParseInput(tr))
+ {
+ return(false);
+ }
+
+ continue;
+ }
+
+ if (!stricmp(szToken, "output"))
+ {
+ if (!ParseOutput(tr))
+ {
+ return(false);
+ }
+
+ continue;
+ }
+
+ if (!stricmp(szToken, "key"))
+ {
+ GDGetToken(tr, szToken, sizeof(szToken));
+ }
+
+ GDinputvariable * var = new GDinputvariable;
+ if (!var->InitFromTokens(tr))
+ {
+ delete var;
+ return(false);
+ }
+
+ int nDupIndex;
+ GDinputvariable *pDupVar = VarForName(var->GetName(), &nDupIndex);
+
+ // check for duplicate variable definitions
+ if (pDupVar)
+ {
+ // Same name, different type.
+ if (pDupVar->GetType() != var->GetType())
+ {
+ char szError[_MAX_PATH];
+
+ sprintf(szError, "%s: Variable '%s' is multiply defined with different types.", GetName(), var->GetName());
+ GDError(tr, szError);
+ }
+ }
+
+ if (!AddVariable(var, this, -1, m_Variables.Count()))
+ {
+ delete var;
+ }
+ }
+
+ return(true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : iIndex -
+// Output : GDinputvariable *
+//-----------------------------------------------------------------------------
+GDinputvariable *GDclass::GetVariableAt(int iIndex)
+{
+ if ( iIndex < 0 || iIndex >= m_nVariables )
+ return NULL;
+
+ if (m_VariableMap[iIndex][0] == -1)
+ {
+ return m_Variables.Element(m_VariableMap[iIndex][1]);
+ }
+
+ // find var's owner
+ GDclass *pVarClass = Parent->GetClass(m_VariableMap[iIndex][0]);
+
+ // find var in pVarClass
+ return pVarClass->GetVariableAt(m_VariableMap[iIndex][1]);
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+GDinputvariable *GDclass::VarForName(const char *pszName, int *piIndex)
+{
+ for(int i = 0; i < GetVariableCount(); i++)
+ {
+ GDinputvariable *pVar = GetVariableAt(i);
+ if(!strcmpi(pVar->GetName(), pszName))
+ {
+ if(piIndex)
+ piIndex[0] = i;
+ return pVar;
+ }
+ }
+
+ return NULL;
+}
+
+void GDclass::GetHelperForGDVar( GDinputvariable *pVar, CUtlVector<const char *> *pszHelperName )
+{
+ const char *pszName = pVar->GetName();
+ for( int i = 0; i < GetHelperCount(); i++ )
+ {
+ CHelperInfo *pHelper = GetHelper( i );
+ int nParamCount = pHelper->GetParameterCount();
+ for ( int j = 0; j < nParamCount; j++ )
+ {
+ if ( !strcmpi( pszName, pHelper->GetParameter( j ) ) )
+ {
+ pszHelperName->AddToTail(pHelper->GetName());
+ }
+ }
+ }
+}
+
+
+