You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
688 lines
20 KiB
688 lines
20 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Defines a connection (output-to-input) between two entities.
|
|
//
|
|
// The behavior in-game is as follows:
|
|
//
|
|
// When the given output in the source entity is triggered, the given
|
|
// input in the target entity is called after a specified delay, and
|
|
// the parameter override (if any) is passed to the input handler. If
|
|
// there is no parameter override, the default parameter is passed.
|
|
//
|
|
// This behavior will occur a specified number of times before the
|
|
// connection between the two entities is removed.
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "stdafx.h"
|
|
#include "EntityConnection.h"
|
|
#include "MapEntity.h"
|
|
#include "MapDoc.h"
|
|
#include "MapWorld.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include <tier0/memdbgon.h>
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Constructor.
|
|
//-----------------------------------------------------------------------------
|
|
CEntityConnection::CEntityConnection(void)
|
|
{
|
|
memset(m_szSourceEntity, 0, sizeof(m_szSourceEntity));
|
|
memset(m_szTargetEntity, 0, sizeof(m_szTargetEntity));
|
|
memset(m_szOutput, 0, sizeof(m_szOutput));
|
|
memset(m_szInput, 0, sizeof(m_szInput));
|
|
memset(m_szParam, 0, sizeof(m_szParam));
|
|
|
|
m_pSourceEntityList = new CMapEntityList;
|
|
m_pTargetEntityList = new CMapEntityList;
|
|
|
|
m_fDelay = 0;
|
|
m_nTimesToFire = EVENT_FIRE_ALWAYS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Copy Constructor.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CEntityConnection::CEntityConnection( const CEntityConnection &Other )
|
|
{
|
|
m_pSourceEntityList = new CMapEntityList;
|
|
m_pTargetEntityList = new CMapEntityList;
|
|
|
|
*this = Other; // Invoke the Operator= to complete the construction job
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Destructor.
|
|
//-----------------------------------------------------------------------------
|
|
CEntityConnection::~CEntityConnection()
|
|
{
|
|
if ( m_pSourceEntityList )
|
|
{
|
|
m_pSourceEntityList->RemoveAll();
|
|
delete m_pSourceEntityList;
|
|
m_pSourceEntityList = NULL;
|
|
}
|
|
if ( m_pTargetEntityList )
|
|
{
|
|
m_pTargetEntityList->RemoveAll();
|
|
delete m_pTargetEntityList;
|
|
m_pTargetEntityList = NULL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Operator= overload. Makes 'this' identical to 'Other'.
|
|
//-----------------------------------------------------------------------------
|
|
CEntityConnection &CEntityConnection::operator =(const CEntityConnection &Other)
|
|
{
|
|
strcpy(m_szSourceEntity, Other.m_szSourceEntity);
|
|
strcpy(m_szTargetEntity, Other.m_szTargetEntity);
|
|
strcpy(m_szOutput, Other.m_szOutput);
|
|
strcpy(m_szInput, Other.m_szInput);
|
|
strcpy(m_szParam, Other.m_szParam);
|
|
m_fDelay = Other.m_fDelay;
|
|
m_nTimesToFire = Other.m_nTimesToFire;
|
|
|
|
// Invoke EntityList operator= to make copies.
|
|
*m_pSourceEntityList = *Other.m_pSourceEntityList;
|
|
*m_pTargetEntityList = *Other.m_pTargetEntityList;
|
|
|
|
return(*this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Sets a new Input Name and sets links to any matching entities
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CEntityConnection::SetSourceName(const char *pszName)
|
|
{
|
|
// Save the name of the entity(ies)
|
|
lstrcpyn(m_szSourceEntity, pszName ? pszName : "<<null>>", sizeof(m_szSourceEntity));
|
|
|
|
// Update the source entity list
|
|
// LinkSourceEntities(); // Changing the entity connection source name shouldnt change the source entity linkage, right?
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Sets a new Output Name and sets links to any matching entities
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CEntityConnection::SetTargetName(const char *pszName)
|
|
{
|
|
// Save the name of the entity(ies)
|
|
lstrcpyn(m_szTargetEntity, pszName ? pszName : "<<null>>", sizeof(m_szTargetEntity));
|
|
|
|
// Update the target entity list
|
|
LinkTargetEntities();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Links to any matching Source entities
|
|
//-----------------------------------------------------------------------------
|
|
void CEntityConnection::LinkSourceEntities()
|
|
{
|
|
// Empty out the existing entity list
|
|
m_pSourceEntityList->RemoveAll();
|
|
|
|
// Get a list of all the entities in the world
|
|
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
|
|
|
if (pDoc)
|
|
{
|
|
CMapWorld *pWorld = pDoc->GetMapWorld();
|
|
|
|
if (pWorld)
|
|
{
|
|
CMapEntityList matches;
|
|
pWorld->FindEntitiesByName( matches, m_szSourceEntity, false );
|
|
|
|
for ( int i = 0; i < matches.Count(); i++ )
|
|
{
|
|
CMapEntity *pEntity = matches.Element( i );
|
|
|
|
m_pSourceEntityList->AddToTail( pEntity );
|
|
//pEntity->Connection_Add( this ); // This should already be true on creation, investigate need for this func
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Links to any matching Target entities
|
|
//-----------------------------------------------------------------------------
|
|
void CEntityConnection::LinkTargetEntities()
|
|
{
|
|
// Unlink us from the downstream entities.
|
|
FOR_EACH_OBJ( *m_pTargetEntityList, pos )
|
|
{
|
|
CMapEntity *pEntity = m_pTargetEntityList->Element( pos );
|
|
pEntity->Upstream_Remove( this );
|
|
}
|
|
|
|
// Empty out the existing entity list
|
|
m_pTargetEntityList->RemoveAll();
|
|
|
|
// Get a list of all the entities in the world
|
|
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
|
|
|
if (pDoc)
|
|
{
|
|
CMapWorld *pWorld = pDoc->GetMapWorld();
|
|
|
|
if (pWorld)
|
|
{
|
|
CMapEntityList matches;
|
|
pWorld->FindEntitiesByName( matches, m_szTargetEntity, false );
|
|
|
|
for ( int i = 0; i < matches.Count(); i++ )
|
|
{
|
|
CMapEntity *pEntity = matches.Element( i );
|
|
|
|
m_pTargetEntityList->AddToTail( pEntity );
|
|
|
|
// Special -- Add this connection to the target entity connection list
|
|
pEntity->Upstream_Add( this );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Tells if any of the target entities are visible.
|
|
//------------------------------------------------------------------------------
|
|
bool CEntityConnection::AreAnyTargetEntitiesVisible()
|
|
{
|
|
CMapEntityList *pList = GetTargetEntityList();
|
|
for ( int iTarget=0; iTarget < pList->Count(); iTarget++ )
|
|
{
|
|
if ( pList->Element( iTarget )->IsVisible() )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Returns true if output string is valid for all this entity
|
|
//------------------------------------------------------------------------------
|
|
bool CEntityConnection::ValidateOutput(CMapEntity *pEntity, const char* pszOutput)
|
|
{
|
|
if (!pEntity)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
GDclass* pClass = pEntity->GetClass();
|
|
if (pClass != NULL)
|
|
{
|
|
if (pClass->FindOutput(pszOutput) == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose : Returns true if output string is valid for all the entities in
|
|
// the entity list
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
bool CEntityConnection::ValidateOutput(const CMapEntityList *pEntityList, const char* pszOutput)
|
|
{
|
|
if (!pEntityList)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FOR_EACH_OBJ( *pEntityList, pos )
|
|
{
|
|
CMapEntity* pEntity = pEntityList->Element(pos);
|
|
if (!ValidateOutput(pEntity,pszOutput))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Returns true if the given entity list contains an entity of the
|
|
// given target name
|
|
//------------------------------------------------------------------------------
|
|
bool CEntityConnection::ValidateTarget( const CMapEntityList *pEntityList, bool bVisibilityCheck, const char *pszTarget)
|
|
{
|
|
if (!pEntityList || !pszTarget)
|
|
return false;
|
|
|
|
// These procedural names are always assumed to exist.
|
|
if (!stricmp(pszTarget, "!activator") || !stricmp(pszTarget, "!caller") || !stricmp(pszTarget, "!player") || !stricmp(pszTarget, "!self"))
|
|
return true;
|
|
|
|
FOR_EACH_OBJ( *pEntityList, pos )
|
|
{
|
|
CMapEntity *pEntity = pEntityList->Element(pos);
|
|
if ( bVisibilityCheck && !pEntity->IsVisible() )
|
|
continue;
|
|
|
|
if (pEntity->NameMatches(pszTarget))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Returns true if all entities with the given target name
|
|
// have an input of the given input name
|
|
//------------------------------------------------------------------------------
|
|
bool CEntityConnection::ValidateInput(const char* pszTarget, const char *pszInput, bool bVisiblesOnly)
|
|
{
|
|
// Allow any input into !activator and !player.
|
|
// dvs: TODO: pass in the entity to resolve !self and check input list
|
|
if (!stricmp(pszTarget, "!activator") || !stricmp(pszTarget, "!caller") || !stricmp(pszTarget, "!player") || !stricmp(pszTarget, "!self"))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
|
CMapEntityList EntityList;
|
|
pDoc->FindEntitiesByName(EntityList, pszTarget, bVisiblesOnly);
|
|
|
|
if (EntityList.Count() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!MapEntityList_HasInput( &EntityList, pszInput))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Finds any output connections from this entity that are bad.
|
|
// "Bad" is defined as:
|
|
//
|
|
// 1) An output that this entity doesn't actually have.
|
|
// 2) Connecting to a nonexistent entity.
|
|
// 3) Connecting to a nonexistent input in an entity that exists.
|
|
//
|
|
// Input : pEntity - The entity to check for bad connections.
|
|
//-----------------------------------------------------------------------------
|
|
void CEntityConnection::FindBadConnections(CMapEntity *pEntity, bool bVisibilityCheck, CUtlVector<CEntityConnection *> &BadConnectionList, bool bIgnoreHiddenTargets)
|
|
{
|
|
BadConnectionList.RemoveAll();
|
|
|
|
if ((!pEntity) || (pEntity->Connections_GetCount() == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get a list of all the entities in the world
|
|
const CMapEntityList *pAllWorldEntities = NULL;
|
|
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
|
if (pDoc)
|
|
{
|
|
CMapWorld *pWorld = pDoc->GetMapWorld();
|
|
if (pWorld)
|
|
{
|
|
pAllWorldEntities = pWorld->EntityList_GetList();
|
|
}
|
|
}
|
|
|
|
// For each connection
|
|
int nConnCount = pEntity->Connections_GetCount();
|
|
for (int i = 0; i < nConnCount; i++)
|
|
{
|
|
CEntityConnection *pConnection = pEntity->Connections_Get(i);
|
|
if (pConnection != NULL)
|
|
{
|
|
if ( bIgnoreHiddenTargets )
|
|
{
|
|
if ( pConnection->GetTargetEntityList()->Count() > 0 && !pConnection->AreAnyTargetEntitiesVisible() )
|
|
continue;
|
|
}
|
|
|
|
// Check validity of output for this entity
|
|
if (!CEntityConnection::ValidateOutput(pEntity, pConnection->GetOutputName()))
|
|
{
|
|
BadConnectionList.AddToTail(pConnection);
|
|
}
|
|
// Check validity of target entity (is it in the map?)
|
|
else if (!CEntityConnection::ValidateTarget(pAllWorldEntities, bVisibilityCheck, pConnection->GetTargetName()))
|
|
{
|
|
BadConnectionList.AddToTail(pConnection);
|
|
}
|
|
// Check validity of input
|
|
else if (!CEntityConnection::ValidateInput(pConnection->GetTargetName(), pConnection->GetInputName(), true))
|
|
{
|
|
BadConnectionList.AddToTail(pConnection);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Check if all the output connections in the given entity are valid.
|
|
// Output : OUTPUTS_NONE if entity has no outputs
|
|
// OUTPUTS_GOOD if all entity outputs are good
|
|
// OUTPUTS_BAD if any entity output is bad
|
|
//------------------------------------------------------------------------------
|
|
int CEntityConnection::ValidateOutputConnections(CMapEntity *pEntity, bool bVisibilityCheck, bool bIgnoreHiddenTargets)
|
|
{
|
|
if (!pEntity)
|
|
{
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
if (pEntity->Connections_GetCount() == 0)
|
|
{
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
CUtlVector<CEntityConnection *> BadConnectionList;
|
|
FindBadConnections(pEntity, bVisibilityCheck, BadConnectionList, bIgnoreHiddenTargets);
|
|
|
|
if (BadConnectionList.Count() > 0)
|
|
{
|
|
return CONNECTION_BAD;
|
|
}
|
|
|
|
return CONNECTION_GOOD;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Fixes any output connections from this entity that are bad.
|
|
// Input : pEntity - The entity to fix.
|
|
//-----------------------------------------------------------------------------
|
|
void CEntityConnection::FixBadConnections(CMapEntity *pEntity, bool bVisibilityCheck )
|
|
{
|
|
CUtlVector<CEntityConnection *> BadConnectionList;
|
|
FindBadConnections(pEntity, bVisibilityCheck, BadConnectionList);
|
|
|
|
// Remove the bad connections.
|
|
int nBadConnCount = BadConnectionList.Count();
|
|
for (int i = 0; i < nBadConnCount; i++)
|
|
{
|
|
CEntityConnection *pConnection = BadConnectionList.Element(i);
|
|
pEntity->Connections_Remove( pConnection );
|
|
|
|
//
|
|
// Remove the connection from the upstream list of all entities it targets.
|
|
//
|
|
CMapEntityList *pTargetList = pConnection->GetTargetEntityList();
|
|
if ( pTargetList )
|
|
{
|
|
FOR_EACH_OBJ( *pTargetList, pos )
|
|
{
|
|
pEntity = pTargetList->Element( pos );
|
|
pEntity->Upstream_Remove( pConnection );
|
|
}
|
|
}
|
|
|
|
delete pConnection;
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose: Check if all the output connections in the given entity are valid.
|
|
// Output : INPUTS_NONE, // if entity list has no inputs
|
|
// INPUTS_GOOD, // if all entity inputs are good
|
|
// INPUTS_BAD, // if any entity input is bad
|
|
//------------------------------------------------------------------------------
|
|
int CEntityConnection::ValidateInputConnections(CMapEntity *pEntity, bool bVisibilityCheck)
|
|
{
|
|
if (!pEntity)
|
|
{
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
// No inputs if entity doesn't have a target name
|
|
const char *pszTargetName = pEntity->GetKeyValue("targetname");
|
|
if (!pszTargetName)
|
|
{
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
GDclass *pClass = pEntity->GetClass();
|
|
if (!pClass)
|
|
{
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
// Get a list of all the entities in the world
|
|
const CMapEntityList *pAllWorldEntities = NULL;
|
|
CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
|
|
if (pDoc)
|
|
{
|
|
CMapWorld *pWorld = pDoc->GetMapWorld();
|
|
if (pWorld)
|
|
{
|
|
pAllWorldEntities = pWorld->EntityList_GetList();
|
|
}
|
|
}
|
|
|
|
// Look at outputs from each entity in the world
|
|
|
|
bool bHaveConnection = false;
|
|
FOR_EACH_OBJ( *pAllWorldEntities, pos )
|
|
{
|
|
CMapEntity *pTestEntity = pAllWorldEntities->Element(pos);
|
|
if (pTestEntity == NULL)
|
|
continue;
|
|
|
|
if ( bVisibilityCheck && !pTestEntity->IsVisible() )
|
|
continue;
|
|
|
|
int nConnCount = pTestEntity->Connections_GetCount();
|
|
for (int i = 0; i < nConnCount; i++)
|
|
{
|
|
// If the connection targets me
|
|
CEntityConnection *pConnection = pTestEntity->Connections_Get(i);
|
|
if ( pConnection && pEntity->NameMatches( pConnection->GetTargetName() ) )
|
|
{
|
|
// Validate output
|
|
if (!ValidateOutput(pTestEntity, pConnection->GetOutputName()))
|
|
{
|
|
return CONNECTION_BAD;
|
|
}
|
|
|
|
// Validate input
|
|
if (pClass->FindInput(pConnection->GetInputName()) == NULL)
|
|
{
|
|
return CONNECTION_BAD;
|
|
}
|
|
|
|
// FIXME -- Validate the upstream connections the target entities.
|
|
bHaveConnection = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (bHaveConnection)
|
|
{
|
|
return CONNECTION_GOOD;
|
|
}
|
|
return CONNECTION_NONE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by delays. Used as a secondary sort by all other columns.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareDelaysSecondary(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
float fDelay1;
|
|
float fDelay2;
|
|
|
|
if (eDirection == Sort_Ascending)
|
|
{
|
|
fDelay1 = pConn1->GetDelay();
|
|
fDelay2 = pConn2->GetDelay();
|
|
}
|
|
else
|
|
{
|
|
fDelay1 = pConn2->GetDelay();
|
|
fDelay2 = pConn1->GetDelay();
|
|
}
|
|
|
|
if (fDelay1 < fDelay2)
|
|
{
|
|
return(-1);
|
|
}
|
|
else if (fDelay1 > fDelay2)
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by delays, does a secondary compare by output name.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareDelays(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
int nReturn = CompareDelaysSecondary(pConn1, pConn2, eDirection);
|
|
if (nReturn != 0)
|
|
{
|
|
return(nReturn);
|
|
}
|
|
|
|
//
|
|
// Always do a secondary sort by output name.
|
|
//
|
|
return(CompareOutputNames(pConn1, pConn2, Sort_Ascending));
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by output name, does a secondary compare by delay.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareOutputNames(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
int nReturn = 0;
|
|
|
|
if (eDirection == Sort_Ascending)
|
|
{
|
|
nReturn = stricmp(pConn1->GetOutputName(), pConn2->GetOutputName());
|
|
}
|
|
else
|
|
{
|
|
nReturn = stricmp(pConn2->GetOutputName(), pConn1->GetOutputName());
|
|
}
|
|
|
|
//
|
|
// Always do a secondary sort by delay.
|
|
//
|
|
if (nReturn == 0)
|
|
{
|
|
nReturn = CompareDelaysSecondary(pConn1, pConn2, Sort_Ascending);
|
|
}
|
|
|
|
return(nReturn);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by input name, does a secondary compare by delay.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareInputNames(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
int nReturn = 0;
|
|
|
|
if (eDirection == Sort_Ascending)
|
|
{
|
|
nReturn = stricmp(pConn1->GetInputName(), pConn2->GetInputName());
|
|
}
|
|
else
|
|
{
|
|
nReturn = stricmp(pConn2->GetInputName(), pConn1->GetInputName());
|
|
}
|
|
|
|
//
|
|
// Always do a secondary sort by delay.
|
|
//
|
|
if (nReturn == 0)
|
|
{
|
|
nReturn = CompareDelaysSecondary(pConn1, pConn2, Sort_Ascending);
|
|
}
|
|
|
|
return(nReturn);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by source name, does a secondary compare by delay.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareSourceNames(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
int nReturn = 0;
|
|
|
|
if (eDirection == Sort_Ascending)
|
|
{
|
|
nReturn = CompareEntityNames(pConn1->GetSourceName(), pConn2->GetSourceName());
|
|
}
|
|
else
|
|
{
|
|
nReturn = CompareEntityNames(pConn2->GetSourceName(), pConn1->GetSourceName());
|
|
}
|
|
|
|
//
|
|
// Always do a secondary sort by delay.
|
|
//
|
|
if (nReturn == 0)
|
|
{
|
|
nReturn = CompareDelaysSecondary(pConn1, pConn2, Sort_Ascending);
|
|
}
|
|
|
|
return(nReturn);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Compares by target name, does a secondary compare by delay.
|
|
//-----------------------------------------------------------------------------
|
|
int CALLBACK CEntityConnection::CompareTargetNames(CEntityConnection *pConn1, CEntityConnection *pConn2, SortDirection_t eDirection)
|
|
{
|
|
int nReturn = 0;
|
|
|
|
if (eDirection == Sort_Ascending)
|
|
{
|
|
nReturn = CompareEntityNames(pConn1->GetTargetName(), pConn2->GetTargetName());
|
|
}
|
|
else
|
|
{
|
|
nReturn = CompareEntityNames(pConn2->GetTargetName(), pConn1->GetTargetName());
|
|
}
|
|
|
|
//
|
|
// Always do a secondary sort by delay.
|
|
//
|
|
if (nReturn == 0)
|
|
{
|
|
nReturn = CompareDelaysSecondary(pConn1, pConn2, Sort_Ascending);
|
|
}
|
|
|
|
return(nReturn);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|