summaryrefslogtreecommitdiff
path: root/hammer/editgameclass.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/editgameclass.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/editgameclass.cpp')
-rw-r--r--hammer/editgameclass.cpp680
1 files changed, 680 insertions, 0 deletions
diff --git a/hammer/editgameclass.cpp b/hammer/editgameclass.cpp
new file mode 100644
index 0000000..09d1acb
--- /dev/null
+++ b/hammer/editgameclass.cpp
@@ -0,0 +1,680 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements a class that encapsulates much of the functionality
+// of entities. CMapWorld and CMapEntity are both derived from this
+// class.
+//
+// CEditGameClass-derived objects have the following properties:
+//
+// Key/value pairs - A list of string pairs that hold data properties
+// of the object. Each property has a unique name.
+//
+// Connections - A list of outputs in this object that are connected to
+// inputs in another entity.
+//
+//=============================================================================//
+
+#include "stdafx.h"
+#include "ChunkFile.h"
+#include "fgdlib/GameData.h"
+#include "GameConfig.h"
+#include "EditGameClass.h"
+#include "MapEntity.h"
+#include "mathlib/Mathlib.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+//
+// An empty string returned by GetComments when we have no comments set.
+//
+char *CEditGameClass::g_pszEmpty = "";
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor. Initializes data members.
+//-----------------------------------------------------------------------------
+CEditGameClass::CEditGameClass(void)
+{
+ m_pClass = NULL;
+ m_szClass[0] = '\0';
+ m_pszComments = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor. Frees memory.
+//-----------------------------------------------------------------------------
+CEditGameClass::~CEditGameClass(void)
+{
+ delete m_pszComments;
+
+ Connections_RemoveAll();
+ Upstream_RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pConnection -
+//-----------------------------------------------------------------------------
+void CEditGameClass::Connections_Add(CEntityConnection *pConnection)
+{
+#if defined(_DEBUG) && 0
+ LPCTSTR pszTargetName = GetKeyValue("targetname");
+ if ( pszTargetName && !strcmp(pszTargetName, "zapperpod7_rotator") )
+ {
+ // Set breakpoint here for debugging this entity's visiblity
+ int foo = 0;
+ }
+#endif
+
+ if ( m_Connections.Find(pConnection) == -1 )
+ m_Connections.AddToTail(pConnection);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pConnection -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CEditGameClass::Connections_Remove(CEntityConnection *pConnection)
+{
+ int nIndex = m_Connections.Find(pConnection);
+ if (nIndex != -1)
+ {
+ m_Connections.Remove(nIndex);
+ return(true);
+ }
+
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// NOTE: unlike Connections_Remove, this actually frees each connection!!
+//-----------------------------------------------------------------------------
+void CEditGameClass::Connections_RemoveAll()
+{
+ //
+ // Remove all our connections from their targets' upstream lists.
+ //
+ int nConnectionsCount = m_Connections.Count();
+ for (int nConnection = 0; nConnection < nConnectionsCount; nConnection++)
+ {
+ CEntityConnection *pConnection = m_Connections.Element( nConnection );
+
+#if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
+ CMapEntityList *pTargetList = pConnection->GetTargetEntityList();
+ if ( pTargetList )
+ {
+ FOR_EACH_OBJ( *pTargetList, pos )
+ {
+ CMapEntity *pEntity = pTargetList->Element( pos );
+ pEntity->Upstream_Remove( pConnection );
+ }
+ }
+#endif
+
+ delete pConnection;
+ }
+
+ m_Connections.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditGameClass::Connections_FixBad(bool bRelink)
+{
+ int nConnectionsCount = m_Connections.Count();
+ for (int nConnections = 0; nConnections < nConnectionsCount; nConnections++)
+ {
+ CEntityConnection *pConnection = m_Connections.Element(nConnections);
+ CMapEntityList *pTargetEntities = pConnection->GetTargetEntityList();
+ int nEntityCount = pTargetEntities->Count();
+
+ for ( int nEntities = 0; nEntities < nEntityCount; nEntities++ )
+ {
+ CMapEntity *pEntity = pTargetEntities->Element(nEntities);
+ pEntity->Upstream_Remove( pConnection );
+ }
+
+ if ( bRelink )
+ pConnection->LinkTargetEntities();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pConnection -
+//-----------------------------------------------------------------------------
+void CEditGameClass::Upstream_Add(CEntityConnection *pConnection)
+{
+#if defined(_DEBUG) && 0
+ LPCTSTR pszTargetName = GetKeyValue("targetname");
+ if ( pszTargetName && !strcmp(pszTargetName, "zapperpod7_rotator") )
+ {
+ // Set breakpoint here for debugging this entity's visiblity
+ int foo = 0;
+ }
+#endif
+
+#if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
+ if ( m_Upstream.Find(pConnection) == -1 )
+ m_Upstream.AddToTail(pConnection);
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pConnection -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CEditGameClass::Upstream_Remove(CEntityConnection *pConnection)
+{
+ int nIndex = m_Upstream.Find(pConnection);
+ if (nIndex != -1)
+ {
+ m_Upstream.Remove(nIndex);
+ return(true);
+ }
+
+ return(false);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditGameClass::Upstream_RemoveAll(void)
+{
+#if defined( ENTITY_MAINTAIN_UPSTREAM_LISTS )
+ //
+ // Remove all our connections from their targets' upstream lists.
+ //
+ int nUpstreamCount = m_Upstream.Count();
+ for (int nConnection = 0; nConnection < nUpstreamCount; nConnection++)
+ {
+ CEntityConnection *pConnection = m_Upstream.Element( nConnection );
+
+ CMapEntityList *pSourceList = pConnection->GetSourceEntityList();
+ if ( pSourceList )
+ {
+ FOR_EACH_OBJ( *pSourceList, pos )
+ {
+ CMapEntity *pEntity = pSourceList->Element( pos );
+ pEntity->Connection_Remove( pConnection );
+ }
+ }
+ }
+#endif
+
+ m_Upstream.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditGameClass::Upstream_FixBad()
+{
+#if defined(_DEBUG) && 0
+ LPCTSTR pszTargetName = GetKeyValue("targetname");
+ if ( pszTargetName && !strcmp(pszTargetName, "cave_guard_seq1") )
+ {
+ // Set breakpoint here for debugging this entity
+ int foo = 0;
+ }
+#endif
+
+ int nUpstreamCount = m_Upstream.Count();
+ for (int nUpstream = 0; nUpstream < nUpstreamCount; nUpstream++)
+ {
+ CEntityConnection *pUpstream = m_Upstream.Element(nUpstream);
+ pUpstream->LinkTargetEntities();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszClass -
+// bLoading -
+//-----------------------------------------------------------------------------
+void CEditGameClass::SetClass(LPCTSTR pszClass, bool bLoading)
+{
+ extern GameData *pGD;
+ strcpy(m_szClass, pszClass);
+
+ StripEdgeWhiteSpace(m_szClass);
+
+ if (pGD)
+ {
+ m_pClass = pGD->ClassForName(m_szClass);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Copies the data from a given CEditGameClass object into this one.
+// Input : pFrom - Object to copy.
+// Output : Returns a pointer to this.
+//-----------------------------------------------------------------------------
+CEditGameClass *CEditGameClass::CopyFrom(CEditGameClass *pFrom)
+{
+ m_pClass = pFrom->m_pClass;
+ strcpy( m_szClass, pFrom->m_szClass );
+
+ //
+ // Copy all the keys.
+ //
+ m_KeyValues.RemoveAll();
+ for ( int i=pFrom->GetFirstKeyValue(); i != pFrom->GetInvalidKeyValue(); i=pFrom->GetNextKeyValue( i ) )
+ {
+ m_KeyValues.SetValue(pFrom->GetKey(i), pFrom->GetKeyValue(i));
+ }
+
+ //
+ // Copy all the connections objects
+ //
+ Connections_RemoveAll();
+ int nConnCount = pFrom->Connections_GetCount();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConn = pFrom->Connections_Get(i);
+ CEntityConnection *pNewConn = new CEntityConnection( *pConn );
+ Connections_Add(pNewConn);
+ }
+
+ //
+ // Copy the comments.
+ //
+ SetComments(pFrom->GetComments());
+
+ return(this);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Applies the default keys for this object's game class. Called when
+// the entity's class is changed.
+//-----------------------------------------------------------------------------
+void CEditGameClass::GetDefaultKeys( void )
+{
+ if ( m_pClass != NULL )
+ {
+ //
+ // For each variable from the base class...
+ //
+ int nVariableCount = m_pClass->GetVariableCount();
+ for ( int i = 0; i < nVariableCount; i++ )
+ {
+ GDinputvariable *pVar = m_pClass->GetVariableAt(i);
+ Assert(pVar != NULL);
+
+ if (pVar != NULL)
+ {
+ int iIndex;
+ LPCTSTR p = m_KeyValues.GetValue(pVar->GetName(), &iIndex);
+
+ //
+ // If the variable is not present in this object, set the default value.
+ //
+ if (p == NULL)
+ {
+ MDkeyvalue tmpkv;
+ pVar->ResetDefaults();
+ pVar->ToKeyValue(&tmpkv);
+
+ //
+ // Only set the key value if it is non-zero.
+ //
+ if ((tmpkv.szKey[0] != 0) && (tmpkv.szValue[0] != 0) && (stricmp(tmpkv.szValue, "0")))
+ {
+ SetKeyValue(tmpkv.szKey, tmpkv.szValue);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns this object's angles as a vector of the form:
+// [0] PITCH [1] YAW [2] ROLL
+//-----------------------------------------------------------------------------
+void CEditGameClass::GetAngles(QAngle &vecAngles)
+{
+ vecAngles = vec3_angle;
+ const char *pszAngles = GetKeyValue("angles");
+ if (pszAngles != NULL)
+ {
+ sscanf(pszAngles, "%f %f %f", &vecAngles[PITCH], &vecAngles[YAW], &vecAngles[ROLL]);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets a new yaw, overriding any existing angles. Uses special values
+// for yaw to indicate pointing straight up or straight down.
+//
+// This method of representing orientation is obsolete; this code is
+// only for importing old RMF or MAP files.
+//
+// Input : a - Value for angle.
+//-----------------------------------------------------------------------------
+void CEditGameClass::ImportAngle(int nAngle)
+{
+ QAngle vecAngles;
+ vecAngles.Init();
+
+ if (nAngle == -1) // UP
+ {
+ vecAngles[PITCH] = -90;
+ }
+ else if (nAngle == -2) // DOWN
+ {
+ vecAngles[PITCH] = 90;
+ }
+ else
+ {
+ vecAngles[YAW] = nAngle;
+ }
+
+ SetAngles(vecAngles);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets this object's angles as a vector of the form:
+// [0] PITCH [1] YAW [2] ROLL
+//-----------------------------------------------------------------------------
+void CEditGameClass::SetAngles(const QAngle &vecAngles)
+{
+ char szAngles[80];
+ sprintf(szAngles, "%g %g %g", (double)vecAngles[PITCH], (double)vecAngles[YAW], (double)vecAngles[ROLL]);
+ SetKeyValue("angles", szAngles);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pFile -
+// Output : ChunkFileResult_t
+//-----------------------------------------------------------------------------
+ChunkFileResult_t CEditGameClass::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
+{
+ ChunkFileResult_t eResult = pFile->WriteKeyValue("classname", m_szClass);
+
+ if (eResult != ChunkFile_Ok)
+ {
+ return(eResult);
+ }
+
+ //
+ // Determine whether we have a game data class. This will help us decide which keys
+ // to write.
+ //
+ GDclass *pGameDataClass = NULL;
+ if (pGD != NULL)
+ {
+ pGameDataClass = pGD->ClassForName(m_szClass);
+ }
+
+ //
+ // Consider all the keyvalues in this object for serialization.
+ //
+ for ( int z=m_KeyValues.GetFirst(); z != m_KeyValues.GetInvalidIndex(); z=m_KeyValues.GetNext( z ) )
+ {
+ MDkeyvalue &KeyValue = m_KeyValues.GetKeyValue(z);
+
+ //
+ // Don't write keys that were already written above.
+ //
+ bool bAlreadyWritten = false;
+ if (!stricmp(KeyValue.szKey, "classname"))
+ {
+ bAlreadyWritten = true;
+ }
+
+ //
+ // If the variable wasn't already written above.
+ //
+ if (!bAlreadyWritten)
+ {
+ //
+ // Write it to the MAP file.
+ //
+ eResult = pFile->WriteKeyValue(KeyValue.szKey, KeyValue.szValue);
+ if (eResult != ChunkFile_Ok)
+ {
+ return(eResult);
+ }
+ }
+ }
+
+ //
+ // If we have a game data class, for each keyvalue in the class definition, write out all keys
+ // that are not present in the object and whose defaults are nonzero in the class definition.
+ //
+ if (pGameDataClass != NULL)
+ {
+ //
+ // For each variable from the base class...
+ //
+ int nVariableCount = pGameDataClass->GetVariableCount();
+ for (int i = 0; i < nVariableCount; i++)
+ {
+ GDinputvariable *pVar = pGameDataClass->GetVariableAt(i);
+ Assert(pVar != NULL);
+
+ if (pVar != NULL)
+ {
+ int iIndex;
+ LPCTSTR p = m_KeyValues.GetValue(pVar->GetName(), &iIndex);
+
+ //
+ // If the variable is not present in this object, write out the default value.
+ //
+ if (p == NULL)
+ {
+ MDkeyvalue TempKey;
+ pVar->ResetDefaults();
+ pVar->ToKeyValue(&TempKey);
+
+ //
+ // Only write the key value if it is non-zero.
+ //
+ if ((TempKey.szKey[0] != 0) && (TempKey.szValue[0] != 0) && (stricmp(TempKey.szValue, "0")))
+ {
+ eResult = pFile->WriteKeyValue(TempKey.szKey, TempKey.szValue);
+ if (eResult != ChunkFile_Ok)
+ {
+ return(eResult);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Save all the connections.
+ //
+ if ((eResult == ChunkFile_Ok) && (Connections_GetCount() > 0))
+ {
+ eResult = pFile->BeginChunk("connections");
+ if (eResult == ChunkFile_Ok)
+ {
+ int nConnCount = Connections_GetCount();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConnection = Connections_Get(i);
+ if (pConnection != NULL)
+ {
+ char szTemp[512];
+
+ sprintf(szTemp, "%s,%s,%s,%g,%d", pConnection->GetTargetName(), pConnection->GetInputName(), pConnection->GetParam(), pConnection->GetDelay(), pConnection->GetTimesToFire());
+ eResult = pFile->WriteKeyValue(pConnection->GetOutputName(), szTemp);
+
+ if (eResult != ChunkFile_Ok)
+ {
+ return(eResult);
+ }
+ }
+ }
+
+ eResult = pFile->EndChunk();
+ }
+ }
+
+ return(eResult);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds a connection from a keyvalue pair.
+// Input : szKey - Contains the name of the output.
+// szValue - Contains the target, input, delay, and parameter, comma delimited.
+// pEditGameClass - Entity to receive the connection.
+// Output : Returns ChunkFile_Ok if the data was well-formed, ChunkFile_Fail if not.
+//-----------------------------------------------------------------------------
+ChunkFileResult_t CEditGameClass::LoadKeyCallback(const char *szKey, const char *szValue, CEditGameClass *pEditGameClass)
+{
+ CEntityConnection *pConnection = new CEntityConnection;
+
+ // Set the "source" name to be the name of the pEditGameClass' targetname
+ pConnection->SetSourceName( pEditGameClass->GetKeyValue("targetname") ); // Use the classname if no targetname is defined?
+
+ // Set the "output" from the passed in parameter
+ pConnection->SetOutputName(szKey);
+
+ char szToken[MAX_PATH];
+
+ //
+ // Parse the target name.
+ //
+ const char *psz = nexttoken(szToken, szValue, ',');
+ if (szToken[0] != '\0')
+ {
+ pConnection->SetTargetName(szToken);
+ }
+
+ //
+ // Parse the input name.
+ //
+ psz = nexttoken(szToken, psz, ',');
+ if (szToken[0] != '\0')
+ {
+ pConnection->SetInputName(szToken);
+ }
+
+ //
+ // Parse the parameter override.
+ //
+ psz = nexttoken(szToken, psz, ',');
+ if (szToken[0] != '\0')
+ {
+ pConnection->SetParam(szToken);
+ }
+
+ //
+ // Parse the delay.
+ //
+ psz = nexttoken(szToken, psz, ',');
+ if (szToken[0] != '\0')
+ {
+ pConnection->SetDelay((float)atof(szToken));
+ }
+
+ //
+ // Parse the number of times to fire the output.
+ //
+ nexttoken(szToken, psz, ',');
+ if (szToken[0] != '\0')
+ {
+ pConnection->SetTimesToFire(atoi(szToken));
+ }
+
+ pEditGameClass->Connections_Add(pConnection); // Does this belong here or SetSourceName or LinkSourceEntities??
+
+ return(ChunkFile_Ok);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pFile -
+// *pEntity -
+// Output : ChunkFileResult_t
+//-----------------------------------------------------------------------------
+ChunkFileResult_t CEditGameClass::LoadConnectionsCallback(CChunkFile *pFile, CEditGameClass *pEditGameClass)
+{
+ return(pFile->ReadChunk((KeyHandler_t)LoadKeyCallback, pEditGameClass));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns all the spawnflags.
+//-----------------------------------------------------------------------------
+unsigned long CEditGameClass::GetSpawnFlags(void)
+{
+ LPCTSTR pszVal = GetKeyValue("spawnflags");
+ if (pszVal == NULL)
+ {
+ return(0);
+ }
+
+ unsigned long val = 0;
+ sscanf( pszVal, "%lu", &val );
+ return val;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if a given spawnflag (or flags) is set, false if not.
+//-----------------------------------------------------------------------------
+bool CEditGameClass::GetSpawnFlag(unsigned long nFlags)
+{
+ unsigned long nSpawnFlags = GetSpawnFlags();
+ return((nSpawnFlags & nFlags) != 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the given spawnflag (or flags) to the given state.
+// Input : nFlag - Flag values to set or clear (ie 1, 2, 4, 8, 16, etc.)
+// bSet - True to set the flags, false to clear them.
+//-----------------------------------------------------------------------------
+void CEditGameClass::SetSpawnFlag(unsigned long nFlags, bool bSet)
+{
+ unsigned long nSpawnFlags = GetSpawnFlags();
+
+ if (bSet)
+ {
+ nSpawnFlags |= nFlags;
+ }
+ else
+ {
+ nSpawnFlags &= ~nFlags;
+ }
+
+ SetSpawnFlags(nSpawnFlags);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets all the spawnflags at once.
+// Input : nSpawnFlags - New value for spawnflags.
+//-----------------------------------------------------------------------------
+void CEditGameClass::SetSpawnFlags(unsigned long nSpawnFlags)
+{
+ char szValue[80];
+ V_snprintf( szValue, sizeof( szValue ), "%lu", nSpawnFlags );
+ SetKeyValue("spawnflags", nSpawnFlags);
+}