Added support for custom VScript procedural targets

This commit is contained in:
Blixibon
2022-01-17 11:44:40 -06:00
parent 2be559d50d
commit 4fdc0624a9
5 changed files with 346 additions and 72 deletions

View File

@@ -22,6 +22,7 @@
#include "npc_playercompanion.h"
#ifdef MAPBASE
#include "hl2_player.h"
#include "mapbase_matchers_base.h"
#endif
#endif // HL2_DLL
@@ -78,6 +79,15 @@ public:
// IEntityListener
virtual void OnEntityCreated( CBaseEntity *pEntity ) {}
virtual void OnEntitySpawned( CBaseEntity *pEntity )
{
// From Alien Swarm SDK
if ( ShouldAddEntity( pEntity ) )
{
RemoveEntity( pEntity );
AddEntity( pEntity );
}
}
virtual void OnEntityDeleted( CBaseEntity *pEntity )
{
if ( !(pEntity->GetFlags() & FL_AIMTARGET) )
@@ -105,6 +115,10 @@ public:
memcpy( pList, m_targetList.Base(), sizeof(CBaseEntity *) * count );
return count;
}
CBaseEntity *ListElement( int iIndex ) // From Alien Swarm SDK
{
return m_targetList[iIndex];
}
private:
CUtlVector<CBaseEntity *> m_targetList;
@@ -120,6 +134,10 @@ int AimTarget_ListCopy( CBaseEntity *pList[], int listMax )
{
return g_AimManager.ListCopy( pList, listMax );
}
CBaseEntity *AimTarget_ListElement( int iIndex )
{
return g_AimManager.ListElement( iIndex );
}
void AimTarget_ForceRepopulateList()
{
g_AimManager.ForceRepopulateList();
@@ -293,6 +311,10 @@ CBaseEntityClassList::~CBaseEntityClassList()
{
}
#ifdef MAPBASE_VSCRIPT
static CUtlVector<CustomProcedural_t> g_CustomProcedurals;
#endif
CGlobalEntityList::CGlobalEntityList()
{
m_iHighestEnt = m_iNumEnts = m_iNumEdicts = 0;
@@ -380,6 +402,18 @@ void CGlobalEntityList::Clear( void )
// free the memory
g_DeleteList.Purge();
#ifdef _DEBUG // From Alien Swarm SDK
for ( UtlHashHandle_t handle = g_EntsByClassname.GetFirstHandle(); g_EntsByClassname.IsValidHandle(handle); handle = g_EntsByClassname.GetNextHandle(handle) )
{
EntsByStringList_t &element = g_EntsByClassname[handle];
Assert( element.pHead == NULL );
}
#endif
#ifdef MAPBASE_VSCRIPT
g_CustomProcedurals.Purge();
#endif
CBaseEntity::m_nDebugPlayer = -1;
CBaseEntity::m_bInDebugSelect = false;
m_iHighestEnt = 0;
@@ -516,6 +550,43 @@ CBaseEntity *CGlobalEntityList::FindEntityByClassname( CBaseEntity *pStartEntity
return NULL;
}
// From Alien Swarm SDK
CBaseEntity *CGlobalEntityList::FindEntityByClassnameFast( CBaseEntity *pStartEntity, string_t iszClassname )
{
/*
if ( pStartEntity )
{
return pStartEntity->m_pNextByClass;
}
EntsByStringList_t key = { iszClassname };
UtlHashHandle_t hEntry = g_EntsByClassname.Find( key );
if ( hEntry != g_EntsByClassname.InvalidHandle() )
{
return g_EntsByClassname[hEntry].pHead;
}
*/
const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
for ( ;pInfo; pInfo = pInfo->m_pNext )
{
CBaseEntity *pEntity = (CBaseEntity *)pInfo->m_pEntity;
if ( !pEntity )
{
DevWarning( "NULL entity in global entity list!\n" );
continue;
}
if ( pEntity->m_iClassname == iszClassname)
{
return pEntity;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Finds an entity given a procedural name.
@@ -633,6 +704,93 @@ CBaseEntity *CGlobalEntityList::FindEntityProcedural( const char *szName, CBaseE
}
#ifdef MAPBASE_VSCRIPT
//-----------------------------------------------------------------------------
// Purpose: Finds an entity given a custom procedural name.
// Input : szName - The procedural name to search for, should start with '!'.
// pSearchingEntity -
// pActivator - The activator entity if this was called from an input
// or Use handler.
//-----------------------------------------------------------------------------
CBaseEntity *CGlobalEntityList::FindEntityCustomProcedural( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
const char *pName = szName;
//
// Check for the name escape character.
//
if ( szName[0] == '!' )
pName = szName + 1;
//
// Look through the custom procedural list.
//
for (int i = 0; i < g_CustomProcedurals.Count(); i++)
{
if (Matcher_NamesMatch( g_CustomProcedurals[i].szName, pName ))
{
if (pStartEntity && g_CustomProcedurals[i].bCanReturnMultiple == false)
return NULL;
// name, startEntity, searchingEntity, activator, caller
ScriptVariant_t functionReturn;
ScriptVariant_t args[] = {
ScriptVariant_t( pName ),
ScriptVariant_t( ToHScript( pStartEntity ) ),
ScriptVariant_t( ToHScript( pSearchingEntity ) ),
ScriptVariant_t( ToHScript( pActivator ) ),
ScriptVariant_t( ToHScript( pCaller ) ),
};
g_pScriptVM->ExecuteFunction( g_CustomProcedurals[i].hFunc, args, 5, &functionReturn, NULL, true );
return ToEnt( functionReturn.m_hScript );
}
}
return NULL;
}
void CGlobalEntityList::AddCustomProcedural( const char *pszName, HSCRIPT hFunc, bool bCanReturnMultiple )
{
//
// Check for any existing custom procedurals to replace.
//
for (int i = 0; i < g_CustomProcedurals.Count(); i++)
{
if (FStrEq( pszName, g_CustomProcedurals[i].szName ))
{
g_CustomProcedurals.FastRemove( i );
break;
}
}
//
// Add a new custom procedural.
//
int i = g_CustomProcedurals.AddToTail();
g_CustomProcedurals[i].szName = pszName;
g_CustomProcedurals[i].hFunc = hFunc;
g_CustomProcedurals[i].bCanReturnMultiple = bCanReturnMultiple;
}
void CGlobalEntityList::RemoveCustomProcedural( const char *pszName )
{
//
// Remove the specified custom procedural.
//
for (int i = 0; i < g_CustomProcedurals.Count(); i++)
{
if (FStrEq( pszName, g_CustomProcedurals[i].szName ))
{
g_CustomProcedurals.FastRemove( i );
break;
}
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Iterates the entities with a given name.
// Input : pStartEntity - Last entity found, NULL to start a new iteration.
@@ -647,6 +805,16 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con
if ( szName[0] == '!' )
{
#ifdef MAPBASE
if (g_CustomProcedurals.Count() > 0)
{
// Search for a custom procedural
CBaseEntity *ent = FindEntityCustomProcedural( pStartEntity, szName, pSearchingEntity, pActivator, pCaller );
if (ent != NULL)
return ent;
}
#endif
//
// Avoid an infinite loop, only find one match per procedural search!
//
@@ -682,6 +850,35 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con
return NULL;
}
// From Alien Swarm SDK
CBaseEntity *CGlobalEntityList::FindEntityByNameFast( CBaseEntity *pStartEntity, string_t iszName )
{
if ( iszName == NULL_STRING || STRING(iszName)[0] == 0 )
return NULL;
const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo();
for ( ;pInfo; pInfo = pInfo->m_pNext )
{
CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity;
if ( !ent )
{
DevWarning( "NULL entity in global entity list!\n" );
continue;
}
if ( !ent->m_iName.Get() )
continue;
if ( ent->m_iName.Get() == iszName )
{
return ent;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pStartEntity -
@@ -899,6 +1096,80 @@ CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest( const char *szName
}
// From Alien Swarm SDK
CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearestFast( string_t iszName, const Vector &vecSrc, float flRadius )
{
CBaseEntity *pEntity = NULL;
//
// Check for matching class names within the search radius.
//
float flMaxDist2 = flRadius * flRadius;
if (flMaxDist2 == 0)
{
flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH;
}
CBaseEntity *pSearch = NULL;
while ((pSearch = gEntList.FindEntityByClassnameFast( pSearch, iszName )) != NULL)
{
if ( !pSearch->edict() )
continue;
float flDist2 = (pSearch->GetAbsOrigin() - vecSrc).LengthSqr();
if (flMaxDist2 > flDist2)
{
pEntity = pSearch;
flMaxDist2 = flDist2;
}
}
return pEntity;
}
//-----------------------------------------------------------------------------
// Purpose: Finds the nearest entity by class name withing given search radius.
// From Alien Swarm SDK
// Input : szName - Entity name to search for. Treated as a target name first,
// then as an entity class name, ie "info_target".
// vecSrc - Center of search radius.
// flRadius - Search radius for classname search, 0 to search everywhere.
// Output : Returns a pointer to the found entity, NULL if none.
//-----------------------------------------------------------------------------
CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest2D( const char *szName, const Vector &vecSrc, float flRadius )
{
CBaseEntity *pEntity = NULL;
//
// Check for matching class names within the search radius.
//
float flMaxDist2 = flRadius * flRadius;
if (flMaxDist2 == 0)
{
flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH;
}
CBaseEntity *pSearch = NULL;
while ((pSearch = gEntList.FindEntityByClassname( pSearch, szName )) != NULL)
{
if ( !pSearch->edict() )
continue;
float flDist2 = (pSearch->GetAbsOrigin().AsVector2D() - vecSrc.AsVector2D()).LengthSqr();
if (flMaxDist2 > flDist2)
{
pEntity = pSearch;
flMaxDist2 = flDist2;
}
}
return pEntity;
}
//-----------------------------------------------------------------------------
// Purpose: Finds the first entity within radius distance by class name.