diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/editgameclass.cpp | |
| download | archived-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.cpp | 680 |
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); +} |