source-sdk-2013-mapbase/sp/src/game/server/ai_squad.cpp

901 lines
26 KiB
C++
Raw Normal View History

2013-12-03 07:31:46 +04:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Squad classes
//
//=============================================================================//
#include "cbase.h"
#include "ai_squad.h"
#include "ai_squadslot.h"
#include "ai_basenpc.h"
#include "saverestore_bitstring.h"
#include "saverestore_utlvector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
CAI_SquadManager g_AI_SquadManager;
//-----------------------------------------------------------------------------
// CAI_SquadManager
//
// Purpose: Manages all the squads in the system
//
//-----------------------------------------------------------------------------
CAI_Squad *CAI_SquadManager::FindSquad( string_t squadName )
{
CAI_Squad* pSquad = m_pSquads;
while (pSquad)
{
if (FStrEq(STRING(squadName),pSquad->GetName()))
{
return pSquad;
}
pSquad = pSquad->m_pNextSquad;
}
return NULL;
}
//-------------------------------------
CAI_Squad *CAI_SquadManager::CreateSquad(string_t squadName)
{
CAI_Squad *pResult = new CAI_Squad(squadName);
// ---------------------------------
// Only named squads get added to the squad list
if ( squadName != NULL_STRING )
{
pResult->m_pNextSquad = m_pSquads;
m_pSquads = pResult;
}
else
pResult->m_pNextSquad = NULL;
return pResult;
}
//-------------------------------------
int CAI_SquadManager::NumSquads()
{
int nSquads = 0;
CAI_Squad* pSquad = m_pSquads;
while (pSquad)
{
nSquads++;
pSquad = pSquad->GetNext();
}
return nSquads;
}
//-------------------------------------
void CAI_SquadManager::DeleteSquad( CAI_Squad *pSquad )
{
CAI_Squad *pCurSquad = m_pSquads;
if (pCurSquad == pSquad)
{
g_AI_SquadManager.m_pSquads = pCurSquad->m_pNextSquad;
}
else
{
while (pCurSquad)
{
if (pCurSquad->m_pNextSquad == pSquad)
{
pCurSquad->m_pNextSquad = pCurSquad->m_pNextSquad->m_pNextSquad;
break;
}
pCurSquad= pCurSquad->m_pNextSquad;
}
}
delete pSquad;
}
//-------------------------------------
// Purpose: Delete all the squads (called between levels / loads)
//-------------------------------------
void CAI_SquadManager::DeleteAllSquads(void)
{
CAI_Squad *squad = CAI_SquadManager::m_pSquads;
while (squad)
{
CAI_Squad *temp = squad->m_pNextSquad;
delete squad;
squad = temp;
}
CAI_SquadManager::m_pSquads = NULL;
}
Mapbase v6.0 - Fixed path_track paths saving as pointers instead of handles - Fixed player animations not falling to base class correctly - Fixed logic_externaldata creating garbage in trailing spaces - Added "SetHandModelSkin" input - Added unique colors for various types of console message, adjustable via convars - Added the ability to use map-specific weapon scripts - Added a way to display (placeholder) text entirely from Faceposer scenes - Added "autobreak" keyvalue to game_text, which automatically breaks long text into different lines - Added the ability to change a game_text's font (very limited) - Added LightToggle input to point_spotlight - Added Enable/DisableSprites on npc_manhack - Added ai_goal_police behavior from metrocops to Combine soldiers and citizens - Added func_precipitation particle rain systems from the Alien Swarm SDK - Added new func_precipitation spawnflags for controlling behavior in particle types - Added "mapbase_version" cvar which shows the version of Mapbase a mod might be running on - Fixed an oversight with NPC crouch activities which was causing npc_metropolice to stop firing in standoffs - Added toggleable patches to npc_combine AI which make soldiers less likely to stand around without shooting or rush to melee when not needed - Added key for custom logo font on env_credits scripts - Added SetSpeed and SetPushDir inputs for trigger_push - Added a bunch of I/O/KV to func_fish_pool to allow for more control over the fish - Added OnLostEnemy/Player support for npc_combine_camera - Added enhanced save/restore for the Response System, toggleable via convar - Added a convar which allows users to disable weapon autoswitching when picking up ammo - Split VScript base script into its own file - Added VScript descriptions for NPC squads and the manager class which handles them - Moved several classes, functions, etc. to the VScript library itself for future usage in other projects, like VBSP - Added VScript to VBSP with basic map file interfacing - Made some VScript documentation more clear due to deprecation of online documentation - Added VScript "hook" registration, creating a standardized system which shows up in script_help documentation - Added VScript-driven custom weapons - Added clientside VScript scopes - Added a bunch of weapon-related VScript functions - Split a bunch of cluttered VScript stuff into different files - Added VScript functions for "following" entities/bonemerging - Added VScript functions for grenades - Added a few more VScript trigger functions - Added OnDeath hook for VScript - Fixed documentation for aliased functions in VScript - Fixed $bumpmask not working on SDK_LightmappedGeneric - Made vertex blend swapping in Hammer use a constant instead of a combo (makes it easier to compile the shader, especially for $bumpmask's sake) - Fixed brush phong, etc. causing SDK_WorldVertexTransition to stop working - Added limited support for $envmapmask in the bumpmapping shader - Fixed more issues with parallax corrected cubemaps and instances - Made instance variable recursion consistent with VMFII
2020-11-26 05:26:55 +03:00
#ifdef MAPBASE_VSCRIPT
//-------------------------------------
// Purpose:
//-------------------------------------
HSCRIPT CAI_SquadManager::ScriptGetFirstSquad()
{
return m_pSquads ? g_pScriptVM->RegisterInstance( m_pSquads ) : NULL;
}
HSCRIPT CAI_SquadManager::ScriptGetNextSquad( HSCRIPT hStart )
{
CAI_Squad *pSquad = HScriptToClass<CAI_Squad>( hStart );
return (pSquad && pSquad->m_pNextSquad) ? g_pScriptVM->RegisterInstance( pSquad->m_pNextSquad ) : NULL;
}
//-------------------------------------
// Purpose:
//-------------------------------------
HSCRIPT CAI_SquadManager::ScriptFindSquad( const char *squadName )
{
CAI_Squad *pSquad = FindSquad( MAKE_STRING(squadName) );
return pSquad ? g_pScriptVM->RegisterInstance( pSquad ) : NULL;
}
HSCRIPT CAI_SquadManager::ScriptFindCreateSquad( const char *squadName )
{
CAI_Squad *pSquad = FindCreateSquad( MAKE_STRING( squadName ) );
return pSquad ? g_pScriptVM->RegisterInstance( pSquad ) : NULL;
}
BEGIN_SCRIPTDESC_ROOT( CAI_SquadManager, SCRIPT_SINGLETON "Manager for NPC squads." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFirstSquad, "GetFirstSquad", "Get the first squad in the squad list." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetNextSquad, "GetNextSquad", "Get the next squad in the squad list starting from the specified squad." )
DEFINE_SCRIPTFUNC_NAMED( ScriptFindSquad, "FindSquad", "Find the specified squad in the squad list. Returns null if none found." )
DEFINE_SCRIPTFUNC_NAMED( ScriptFindCreateSquad, "FindCreateSquad", "Find the specified squad in the squad list or create it if it doesn't exist." )
DEFINE_SCRIPTFUNC( NumSquads, "Get the number of squads in the list." )
END_SCRIPTDESC();
#endif
2013-12-03 07:31:46 +04:00
//-----------------------------------------------------------------------------
// CAI_Squad
//
// Purpose: Tracks enemies, squad slots, squad members
//
//-----------------------------------------------------------------------------
#ifdef PER_ENEMY_SQUADSLOTS
BEGIN_SIMPLE_DATADESC( AISquadEnemyInfo_t )
DEFINE_FIELD( hEnemy, FIELD_EHANDLE ),
DEFINE_BITSTRING( slots),
END_DATADESC()
#endif
BEGIN_SIMPLE_DATADESC( CAI_Squad )
// m_pNextSquad (rebuilt)
// m_Name (rebuilt)
// m_SquadMembers (rebuilt)
// m_SquadMembers.Count() (rebuilt)
DEFINE_FIELD( m_flSquadSoundWaitTime, FIELD_TIME ),
DEFINE_FIELD( m_nSquadSoundPriority, FIELD_INTEGER ),
DEFINE_FIELD( m_hSquadInflictor, FIELD_EHANDLE ),
DEFINE_AUTO_ARRAY( m_SquadData, FIELD_INTEGER ),
// m_pLastFoundEnemyInfo (think transient)
#ifdef PER_ENEMY_SQUADSLOTS
DEFINE_UTLVECTOR(m_EnemyInfos, FIELD_EMBEDDED ),
DEFINE_FIELD( m_flEnemyInfoCleanupTime, FIELD_TIME ),
#else
DEFINE_EMBEDDED( m_squadSlotsUsed ),
#endif
END_DATADESC()
Mapbase v6.0 - Fixed path_track paths saving as pointers instead of handles - Fixed player animations not falling to base class correctly - Fixed logic_externaldata creating garbage in trailing spaces - Added "SetHandModelSkin" input - Added unique colors for various types of console message, adjustable via convars - Added the ability to use map-specific weapon scripts - Added a way to display (placeholder) text entirely from Faceposer scenes - Added "autobreak" keyvalue to game_text, which automatically breaks long text into different lines - Added the ability to change a game_text's font (very limited) - Added LightToggle input to point_spotlight - Added Enable/DisableSprites on npc_manhack - Added ai_goal_police behavior from metrocops to Combine soldiers and citizens - Added func_precipitation particle rain systems from the Alien Swarm SDK - Added new func_precipitation spawnflags for controlling behavior in particle types - Added "mapbase_version" cvar which shows the version of Mapbase a mod might be running on - Fixed an oversight with NPC crouch activities which was causing npc_metropolice to stop firing in standoffs - Added toggleable patches to npc_combine AI which make soldiers less likely to stand around without shooting or rush to melee when not needed - Added key for custom logo font on env_credits scripts - Added SetSpeed and SetPushDir inputs for trigger_push - Added a bunch of I/O/KV to func_fish_pool to allow for more control over the fish - Added OnLostEnemy/Player support for npc_combine_camera - Added enhanced save/restore for the Response System, toggleable via convar - Added a convar which allows users to disable weapon autoswitching when picking up ammo - Split VScript base script into its own file - Added VScript descriptions for NPC squads and the manager class which handles them - Moved several classes, functions, etc. to the VScript library itself for future usage in other projects, like VBSP - Added VScript to VBSP with basic map file interfacing - Made some VScript documentation more clear due to deprecation of online documentation - Added VScript "hook" registration, creating a standardized system which shows up in script_help documentation - Added VScript-driven custom weapons - Added clientside VScript scopes - Added a bunch of weapon-related VScript functions - Split a bunch of cluttered VScript stuff into different files - Added VScript functions for "following" entities/bonemerging - Added VScript functions for grenades - Added a few more VScript trigger functions - Added OnDeath hook for VScript - Fixed documentation for aliased functions in VScript - Fixed $bumpmask not working on SDK_LightmappedGeneric - Made vertex blend swapping in Hammer use a constant instead of a combo (makes it easier to compile the shader, especially for $bumpmask's sake) - Fixed brush phong, etc. causing SDK_WorldVertexTransition to stop working - Added limited support for $envmapmask in the bumpmapping shader - Fixed more issues with parallax corrected cubemaps and instances - Made instance variable recursion consistent with VMFII
2020-11-26 05:26:55 +03:00
#ifdef MAPBASE_VSCRIPT
BEGIN_SCRIPTDESC_ROOT( CAI_Squad, "NPC squads used for schedule coordination, sharing information about enemies, etc." )
DEFINE_SCRIPTFUNC( GetName, "Get the squad's name." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetFirstMember, "GetFirstMember", "Get the squad's first member. The parameter is for whether to ignore silent members (see CAI_Squad::IsSilentMember() for more info)." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetMember, "GetMember", "Get one of the squad's members by their index." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetAnyMember, "GetAnyMember", "Randomly get any one of the squad's members." )
DEFINE_SCRIPTFUNC( NumMembers, "Get the squad's number of members. The parameter is for whether to ignore silent members (see CAI_Squad::IsSilentMember() for more info)." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSquadIndex, "GetSquadIndex", "Get the index of the specified NPC in the squad." )
DEFINE_SCRIPTFUNC_NAMED( ScriptUpdateEnemyMemory, "UpdateEnemyMemory", "Updates the squad's memory of an enemy. The first parameter is the updater, the second parameter is the enemy, and the third parameter is the position." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSquadMemberInRange, "SquadMemberInRange", "Get the first squad member found around the specified position in the specified range." )
DEFINE_SCRIPTFUNC_NAMED( ScriptNearestSquadMember, "NearestSquadMember", "Get the squad member nearest to the specified member." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetVisibleSquadMembers, "GetVisibleSquadMembers", "Get the number of squad members visible to the specified member." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSquadMemberNearestTo, "GetSquadMemberNearestTo", "Get the squad member nearest to a point." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsMember, "IsMember", "Returns true if the specified NPC is a member of the squad." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsLeader, "IsLeader", "Returns true if the specified NPC is the squad's leader." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetLeader, "GetLeader", "Get the squad's leader." )
DEFINE_SCRIPTFUNC_NAMED( ScriptAddToSquad, "AddToSquad", "Adds a NPC to the squad." )
DEFINE_SCRIPTFUNC_NAMED( ScriptRemoveFromSquad, "RemoveFromSquad", "Removes a NPC from the squad." )
DEFINE_SCRIPTFUNC_NAMED( ScriptIsSilentMember, "IsSilentMember", "Returns true if the specified NPC is a \"silent squad member\", which means it's only in squads for enemy information purposes and does not actually participate in any tactics. For example, this is used for npc_enemyfinder and vital allies (e.g. Alyx) in the player's squad. Please note that this does not check if the NPC is in the squad first." )
DEFINE_SCRIPTFUNC_NAMED( ScriptSetSquadData, "SetSquadData", "Set the squad data in the specified slot." )
DEFINE_SCRIPTFUNC_NAMED( ScriptGetSquadData, "GetSquadData", "Get the squad data in the specified slot." )
END_SCRIPTDESC();
#endif
2013-12-03 07:31:46 +04:00
//-------------------------------------
CAI_Squad::CAI_Squad(string_t newName)
#ifndef PER_ENEMY_SQUADSLOTS
: m_squadSlotsUsed(MAX_SQUADSLOTS)
#endif
{
Init( newName );
}
//-------------------------------------
CAI_Squad::CAI_Squad()
#ifndef PER_ENEMY_SQUADSLOTS
: m_squadSlotsUsed(MAX_SQUADSLOTS)
#endif
{
Init( NULL_STRING );
}
//-------------------------------------
void CAI_Squad::Init(string_t newName)
{
m_Name = AllocPooledString( STRING(newName) );
m_pNextSquad = NULL;
m_flSquadSoundWaitTime = 0;
m_SquadMembers.RemoveAll();
m_flSquadSoundWaitTime = 0;
SetSquadInflictor( NULL );
#ifdef PER_ENEMY_SQUADSLOTS
m_flEnemyInfoCleanupTime = 0;
m_pLastFoundEnemyInfo = NULL;
#endif
}
//-------------------------------------
CAI_Squad::~CAI_Squad(void)
{
}
//-------------------------------------
bool CAI_Squad::IsSilentMember( const CAI_BaseNPC *pNPC )
{
if ( !pNPC || ( pNPC->GetMoveType() == MOVETYPE_NONE && pNPC->GetSolid() == SOLID_NONE ) ) // a.k.a., enemy finder
return true;
return pNPC->IsSilentSquadMember();
}
//-------------------------------------
// Purpose: Removes an NPC from a squad
//-------------------------------------
void CAI_Squad::RemoveFromSquad( CAI_BaseNPC *pNPC, bool bDeath )
{
if ( !pNPC )
return;
// Find the index of this squad member
int member;
int myIndex = m_SquadMembers.Find(pNPC);
if (myIndex == -1)
{
Mapbase v6.1 - Added postprocess_controller entity from later versions of Source - Added env_dof_controller entity from later versions of Source - Added SDK_Engine_Post and DepthOfField shaders from the Momentum repo/Alien Swarm SDK - Fixed auto-breaking game_text/choreo text not null terminating - Fixed console groups showing up at the wrong developer levels - Added more mesages to console groups, including a new "NPC AI" console group - Fixed typos and added elaboration in various cvars, console messages, etc. - Fixed npc_metropolice not using frag grenades correctly when allowed to use them - Fixed npc_metropolice not registering stitching squad slots in AI - Fixed SetModel input late precache warning - Fixed env_global_light angles resetting upon loading a save - Fixed an issue with ScriptKeyValuesRead using the wrong name and having a memory leak - Allowed VScript functions which return null strings to actually return null instead of empty strings - Added VScript member variable documentation - Fixed VScript documentation lines sometimes mixing together - Fixed VScript singletons having a ! at the beginning of descriptions - Added Color struct to VScript and allowed color-related inputs to use it - Added more VScript functions for weapons, ammo, ragdolling, and response contexts - Added GameRules singleton for VScript - Exposed AI interaction system to VScript - Recovered some lost documentation from older revisions of the Mapbase wiki - Added a way to get the current game's load type in VScript - Fixed Precache/SpawnEntityFromTable not accounting for a few important field types - Added VScript functions for getting a player's eye vectors - Fixed a crash caused by removing the active weapon of a Combine soldier while it's firing - Changed the way metrocops deploy their manhacks so they could use their manhack death response properly - Fixed "Use Server" keyvalue on game_convar_mod not working - Adjusted CAI_Expresser in VScript
2020-12-17 06:38:23 +03:00
CGMsg( 1, CON_GROUP_NPC_AI, "ERROR: Attempting to remove non-existing squad member!\n" );
2013-12-03 07:31:46 +04:00
return;
}
m_SquadMembers.Remove(myIndex);
// Notify squad members of death
if ( bDeath )
{
for (member = 0; member < m_SquadMembers.Count(); member++)
{
CAI_BaseNPC* pSquadMem = m_SquadMembers[member];
if (pSquadMem)
{
pSquadMem->NotifyDeadFriend(pNPC);
}
}
}
pNPC->SetSquad(NULL);
pNPC->SetSquadName( NULL_STRING );
}
//-------------------------------------
// Purpose: Addes the given NPC to the squad
//-------------------------------------
void CAI_Squad::AddToSquad(CAI_BaseNPC *pNPC)
{
if ( !pNPC || !pNPC->IsAlive() )
{
Assert(0);
return;
}
if ( pNPC->GetSquad() == this )
return;
if ( pNPC->GetSquad() )
{
pNPC->GetSquad()->RemoveFromSquad(pNPC);
}
if (m_SquadMembers.Count() == MAX_SQUAD_MEMBERS)
{
Mapbase v6.1 - Added postprocess_controller entity from later versions of Source - Added env_dof_controller entity from later versions of Source - Added SDK_Engine_Post and DepthOfField shaders from the Momentum repo/Alien Swarm SDK - Fixed auto-breaking game_text/choreo text not null terminating - Fixed console groups showing up at the wrong developer levels - Added more mesages to console groups, including a new "NPC AI" console group - Fixed typos and added elaboration in various cvars, console messages, etc. - Fixed npc_metropolice not using frag grenades correctly when allowed to use them - Fixed npc_metropolice not registering stitching squad slots in AI - Fixed SetModel input late precache warning - Fixed env_global_light angles resetting upon loading a save - Fixed an issue with ScriptKeyValuesRead using the wrong name and having a memory leak - Allowed VScript functions which return null strings to actually return null instead of empty strings - Added VScript member variable documentation - Fixed VScript documentation lines sometimes mixing together - Fixed VScript singletons having a ! at the beginning of descriptions - Added Color struct to VScript and allowed color-related inputs to use it - Added more VScript functions for weapons, ammo, ragdolling, and response contexts - Added GameRules singleton for VScript - Exposed AI interaction system to VScript - Recovered some lost documentation from older revisions of the Mapbase wiki - Added a way to get the current game's load type in VScript - Fixed Precache/SpawnEntityFromTable not accounting for a few important field types - Added VScript functions for getting a player's eye vectors - Fixed a crash caused by removing the active weapon of a Combine soldier while it's firing - Changed the way metrocops deploy their manhacks so they could use their manhack death response properly - Fixed "Use Server" keyvalue on game_convar_mod not working - Adjusted CAI_Expresser in VScript
2020-12-17 06:38:23 +03:00
CGMsg( 1, CON_GROUP_NPC_AI, "Error!! Squad %s is too big!!! Replacing last member\n", STRING( this->m_Name ) );
2013-12-03 07:31:46 +04:00
m_SquadMembers.Remove(m_SquadMembers.Count()-1);
}
m_SquadMembers.AddToTail(pNPC);
pNPC->SetSquad( this );
pNPC->SetSquadName( m_Name );
if ( m_SquadMembers.Count() > 1 )
{
CAI_BaseNPC *pCopyFrom = m_SquadMembers[0];
CAI_Enemies *pEnemies = pCopyFrom->GetEnemies();
AIEnemiesIter_t iter;
AI_EnemyInfo_t *pInfo = pEnemies->GetFirst( &iter );
while ( pInfo )
{
pNPC->UpdateEnemyMemory( pInfo->hEnemy, pInfo->vLastKnownLocation, pCopyFrom );
pInfo = pEnemies->GetNext( &iter );
}
}
}
//-------------------------------------
CAI_BaseNPC *CAI_Squad::SquadMemberInRange( const Vector &vecLocation, float flDist )
{
for (int i = 0; i < m_SquadMembers.Count(); i++)
{
if (m_SquadMembers[i] != NULL && (vecLocation - m_SquadMembers[i]->GetAbsOrigin() ).Length2D() <= flDist)
return m_SquadMembers[i];
}
return NULL;
}
//-------------------------------------
// Purpose: Returns the nearest squad member to the given squad member
//-------------------------------------
CAI_BaseNPC *CAI_Squad::NearestSquadMember( CAI_BaseNPC *pMember )
{
float fBestDist = MAX_COORD_RANGE;
CAI_BaseNPC *fNearestEnt = NULL;
Vector fStartLoc = pMember->GetAbsOrigin();
for (int i = 0; i < m_SquadMembers.Count(); i++)
{
if (m_SquadMembers[i] != NULL)
{
float fDist = (fStartLoc - m_SquadMembers[i]->GetAbsOrigin()).Length();
if (m_SquadMembers[i] != pMember &&
fDist < fBestDist )
{
fBestDist = fDist;
fNearestEnt = m_SquadMembers[i];
}
}
}
return fNearestEnt;
}
//-------------------------------------
// Purpose: Return the number of squad members visible to the specified member
//-------------------------------------
int CAI_Squad::GetVisibleSquadMembers( CAI_BaseNPC *pMember )
{
int iCount = 0;
for (int i = 0; i < m_SquadMembers.Count(); i++)
{
// Make sure it's not the specified member
if ( m_SquadMembers[i] != NULL && pMember != m_SquadMembers[i] )
{
if ( pMember->FVisible( m_SquadMembers[i] ) )
{
iCount++;
}
}
}
return iCount;
}
//-------------------------------------
//
//-------------------------------------
CAI_BaseNPC *CAI_Squad::GetSquadMemberNearestTo( const Vector &vecLocation )
{
CAI_BaseNPC *pNearest = NULL;
float flNearest = FLT_MAX;
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
float flDist;
flDist = m_SquadMembers[i]->GetAbsOrigin().DistToSqr( vecLocation );
if( flDist < flNearest )
{
flNearest = flDist;
pNearest = m_SquadMembers[i];
}
}
Assert( pNearest != NULL );
return pNearest;
}
//-------------------------------------
// Purpose: Returns true if given entity is in the squad
//-------------------------------------
bool CAI_Squad::SquadIsMember( CBaseEntity *pMember )
{
CAI_BaseNPC *pNPC = pMember->MyNPCPointer();
if ( pNPC && pNPC->GetSquad() == this )
return true;
return false;
}
//-------------------------------------
bool CAI_Squad::IsLeader( CAI_BaseNPC *pNPC )
{
if ( IsSilentMember( pNPC ) )
return false;
if ( !pNPC )
return false;
if ( GetLeader() == pNPC )
return true;
return false;
}
//-------------------------------------
CAI_BaseNPC *CAI_Squad::GetLeader( void )
{
CAI_BaseNPC *pLeader = NULL;
int nSilentMembers = 0;
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
if ( !IsSilentMember( m_SquadMembers[i] ) )
{
if ( !pLeader )
pLeader = m_SquadMembers[i];
}
else
{
nSilentMembers++;
}
}
return ( m_SquadMembers.Count() - nSilentMembers > 1) ? pLeader : NULL;
}
//-----------------------------------------------------------------------------
CAI_BaseNPC *CAI_Squad::GetFirstMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers )
{
int i = 0;
if ( bIgnoreSilentMembers )
{
for ( ; i < m_SquadMembers.Count(); i++ )
{
if ( !IsSilentMember( m_SquadMembers[i] ) )
break;
}
}
if ( pIter )
*pIter = (AISquadIter_t)i;
if ( i >= m_SquadMembers.Count() )
return NULL;
return m_SquadMembers[i];
}
//-------------------------------------
CAI_BaseNPC *CAI_Squad::GetNextMember( AISquadIter_t *pIter, bool bIgnoreSilentMembers )
{
int &i = (int &)*pIter;
i++;
if ( bIgnoreSilentMembers )
{
for ( ; i < m_SquadMembers.Count(); i++ )
{
if ( !IsSilentMember( m_SquadMembers[i] ) )
break;
}
}
if ( i >= m_SquadMembers.Count() )
return NULL;
return m_SquadMembers[i];
}
//-------------------------------------
// Purpose: Alert everyone in the squad to the presence of a new enmey
//-------------------------------------
int CAI_Squad::NumMembers( bool bIgnoreSilentMembers )
{
int nSilentMembers = 0;
if ( bIgnoreSilentMembers )
{
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
if ( IsSilentMember( m_SquadMembers[i] ) )
nSilentMembers++;
}
}
return ( m_SquadMembers.Count() - nSilentMembers );
}
//-------------------------------------
// Purpose: Alert everyone in the squad to the presence of a new enmey
//-------------------------------------
void CAI_Squad::SquadNewEnemy( CBaseEntity *pEnemy )
{
if ( !pEnemy )
{
Mapbase v6.1 - Added postprocess_controller entity from later versions of Source - Added env_dof_controller entity from later versions of Source - Added SDK_Engine_Post and DepthOfField shaders from the Momentum repo/Alien Swarm SDK - Fixed auto-breaking game_text/choreo text not null terminating - Fixed console groups showing up at the wrong developer levels - Added more mesages to console groups, including a new "NPC AI" console group - Fixed typos and added elaboration in various cvars, console messages, etc. - Fixed npc_metropolice not using frag grenades correctly when allowed to use them - Fixed npc_metropolice not registering stitching squad slots in AI - Fixed SetModel input late precache warning - Fixed env_global_light angles resetting upon loading a save - Fixed an issue with ScriptKeyValuesRead using the wrong name and having a memory leak - Allowed VScript functions which return null strings to actually return null instead of empty strings - Added VScript member variable documentation - Fixed VScript documentation lines sometimes mixing together - Fixed VScript singletons having a ! at the beginning of descriptions - Added Color struct to VScript and allowed color-related inputs to use it - Added more VScript functions for weapons, ammo, ragdolling, and response contexts - Added GameRules singleton for VScript - Exposed AI interaction system to VScript - Recovered some lost documentation from older revisions of the Mapbase wiki - Added a way to get the current game's load type in VScript - Fixed Precache/SpawnEntityFromTable not accounting for a few important field types - Added VScript functions for getting a player's eye vectors - Fixed a crash caused by removing the active weapon of a Combine soldier while it's firing - Changed the way metrocops deploy their manhacks so they could use their manhack death response properly - Fixed "Use Server" keyvalue on game_convar_mod not working - Adjusted CAI_Expresser in VScript
2020-12-17 06:38:23 +03:00
CGMsg( 1, CON_GROUP_NPC_AI, "ERROR: SquadNewEnemy() - pEnemy is NULL!\n" );
2013-12-03 07:31:46 +04:00
return;
}
for (int i = 0; i < m_SquadMembers.Count(); i++)
{
CAI_BaseNPC *pMember = m_SquadMembers[i];
if (pMember)
{
// reset members who aren't activly engaged in fighting (only do this if the NPC's using the squad memory, or it'll fail)
if ( !pMember->GetEnemy() ||
( pMember->GetEnemy() != pEnemy &&
!pMember->HasCondition( COND_SEE_ENEMY) &&
gpGlobals->curtime - pMember->GetEnemyLastTimeSeen() > 3.0 ) )
{
// give them a new enemy
if( !hl2_episodic.GetBool() || pMember->IsValidEnemy(pEnemy) )
{
pMember->SetEnemy( pEnemy );
}
// pMember->SetLastAttackTime( 0 );
}
}
}
}
//-------------------------------------
// Purpose: Broadcast a message to all squad members
// Input: messageID - generic message handle
// data - generic data handle
// sender - who sent the message (NULL by default, if not, will not resend to the sender)
//-------------------------------------
int CAI_Squad::BroadcastInteraction( int interactionType, void *data, CBaseCombatCharacter *sender )
{
//Must have a squad
if ( m_SquadMembers.Count() == 0 )
return false;
//Broadcast to all members of the squad
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
CAI_BaseNPC *pMember = m_SquadMembers[i]->MyNPCPointer();
//Validate and don't send again to the sender
if ( ( pMember != NULL) && ( pMember != sender ) )
{
//Send it
pMember->DispatchInteraction( interactionType, data, sender );
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: is it ok to make a sound of the given priority? Check for conflicts
// Input : soundPriority -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_Squad::FOkToMakeSound( int soundPriority )
{
if (gpGlobals->curtime <= m_flSquadSoundWaitTime)
{
if ( soundPriority <= m_nSquadSoundPriority )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: A squad member made an exclusive sound. Keep track so other squad
// members don't talk over it
// Input : soundPriority - for sorting
// time -
//-----------------------------------------------------------------------------
void CAI_Squad::JustMadeSound( int soundPriority, float time )
{
m_flSquadSoundWaitTime = time;
m_nSquadSoundPriority = soundPriority;
}
//-----------------------------------------------------------------------------
// Purpose: Try to get one of a contiguous range of slots
// Input : slotIDStart - start of slot range
// slotIDEnd - end of slot range
// hEnemy - enemy this slot is for
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CAI_Squad::OccupyStrategySlotRange( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd, int *pSlot )
{
#ifndef PER_ENEMY_SQUADSLOTS
// FIXME: combat slots need to be per enemy, not per squad.
// As it is, once a squad is occupied it stops making even simple attacks to other things nearby.
// This code may make soldiers too aggressive
if (GetLeader() && pEnemy != GetLeader()->GetEnemy())
{
*pSlot = SQUAD_SLOT_NONE;
return true;
}
#endif
// If I'm already occupying this slot
if ( *pSlot >= slotIDStart && *pSlot <= slotIDEnd)
return true;
for ( int i = slotIDStart; i <= slotIDEnd; i++ )
{
// Check enemy to see if slot already occupied
if (!IsSlotOccupied(pEnemy, i))
{
// Clear any previous spot;
if (*pSlot != SQUAD_SLOT_NONE)
{
// As a debug measure check to see if slot was filled
if (!IsSlotOccupied(pEnemy, *pSlot))
{
Mapbase v6.1 - Added postprocess_controller entity from later versions of Source - Added env_dof_controller entity from later versions of Source - Added SDK_Engine_Post and DepthOfField shaders from the Momentum repo/Alien Swarm SDK - Fixed auto-breaking game_text/choreo text not null terminating - Fixed console groups showing up at the wrong developer levels - Added more mesages to console groups, including a new "NPC AI" console group - Fixed typos and added elaboration in various cvars, console messages, etc. - Fixed npc_metropolice not using frag grenades correctly when allowed to use them - Fixed npc_metropolice not registering stitching squad slots in AI - Fixed SetModel input late precache warning - Fixed env_global_light angles resetting upon loading a save - Fixed an issue with ScriptKeyValuesRead using the wrong name and having a memory leak - Allowed VScript functions which return null strings to actually return null instead of empty strings - Added VScript member variable documentation - Fixed VScript documentation lines sometimes mixing together - Fixed VScript singletons having a ! at the beginning of descriptions - Added Color struct to VScript and allowed color-related inputs to use it - Added more VScript functions for weapons, ammo, ragdolling, and response contexts - Added GameRules singleton for VScript - Exposed AI interaction system to VScript - Recovered some lost documentation from older revisions of the Mapbase wiki - Added a way to get the current game's load type in VScript - Fixed Precache/SpawnEntityFromTable not accounting for a few important field types - Added VScript functions for getting a player's eye vectors - Fixed a crash caused by removing the active weapon of a Combine soldier while it's firing - Changed the way metrocops deploy their manhacks so they could use their manhack death response properly - Fixed "Use Server" keyvalue on game_convar_mod not working - Adjusted CAI_Expresser in VScript
2020-12-17 06:38:23 +03:00
CGMsg( 1, CON_GROUP_NPC_AI, "ERROR! Vacating an empty slot!\n" );
2013-12-03 07:31:46 +04:00
}
// Free the slot
VacateSlot(pEnemy, *pSlot);
}
// Fill the slot
OccupySlot(pEnemy, i);
*pSlot = i;
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
bool CAI_Squad::IsStrategySlotRangeOccupied( CBaseEntity *pEnemy, int slotIDStart, int slotIDEnd )
{
for ( int i = slotIDStart; i <= slotIDEnd; i++ )
{
if (!IsSlotOccupied(pEnemy, i))
return false;
}
return true;
}
//------------------------------------------------------------------------------
void CAI_Squad::VacateStrategySlot( CBaseEntity *pEnemy, int slot)
{
// If I wasn't taking up a squad slot I'm done
if (slot == SQUAD_SLOT_NONE)
return;
// As a debug measure check to see if slot was filled
if (!IsSlotOccupied(pEnemy, slot))
{
Mapbase v6.1 - Added postprocess_controller entity from later versions of Source - Added env_dof_controller entity from later versions of Source - Added SDK_Engine_Post and DepthOfField shaders from the Momentum repo/Alien Swarm SDK - Fixed auto-breaking game_text/choreo text not null terminating - Fixed console groups showing up at the wrong developer levels - Added more mesages to console groups, including a new "NPC AI" console group - Fixed typos and added elaboration in various cvars, console messages, etc. - Fixed npc_metropolice not using frag grenades correctly when allowed to use them - Fixed npc_metropolice not registering stitching squad slots in AI - Fixed SetModel input late precache warning - Fixed env_global_light angles resetting upon loading a save - Fixed an issue with ScriptKeyValuesRead using the wrong name and having a memory leak - Allowed VScript functions which return null strings to actually return null instead of empty strings - Added VScript member variable documentation - Fixed VScript documentation lines sometimes mixing together - Fixed VScript singletons having a ! at the beginning of descriptions - Added Color struct to VScript and allowed color-related inputs to use it - Added more VScript functions for weapons, ammo, ragdolling, and response contexts - Added GameRules singleton for VScript - Exposed AI interaction system to VScript - Recovered some lost documentation from older revisions of the Mapbase wiki - Added a way to get the current game's load type in VScript - Fixed Precache/SpawnEntityFromTable not accounting for a few important field types - Added VScript functions for getting a player's eye vectors - Fixed a crash caused by removing the active weapon of a Combine soldier while it's firing - Changed the way metrocops deploy their manhacks so they could use their manhack death response properly - Fixed "Use Server" keyvalue on game_convar_mod not working - Adjusted CAI_Expresser in VScript
2020-12-17 06:38:23 +03:00
CGMsg( 1, CON_GROUP_NPC_AI, "ERROR! Vacating an empty slot!\n" );
2013-12-03 07:31:46 +04:00
}
// Free the slot
VacateSlot(pEnemy, slot);
}
//------------------------------------------------------------------------------
void CAI_Squad::UpdateEnemyMemory( CAI_BaseNPC *pUpdater, CBaseEntity *pEnemy, const Vector &position )
{
//Broadcast to all members of the squad
for ( int i = 0; i < m_SquadMembers.Count(); i++ )
{
if ( m_SquadMembers[i] != pUpdater )
{
m_SquadMembers[i]->UpdateEnemyMemory( pEnemy, position, pUpdater );
}
}
}
//------------------------------------------------------------------------------
#ifdef PER_ENEMY_SQUADSLOTS
AISquadEnemyInfo_t *CAI_Squad::FindEnemyInfo( CBaseEntity *pEnemy )
{
int i;
if ( gpGlobals->curtime > m_flEnemyInfoCleanupTime )
{
if ( m_EnemyInfos.Count() )
{
m_pLastFoundEnemyInfo = NULL;
CUtlRBTree<CBaseEntity *> activeEnemies;
SetDefLessFunc( activeEnemies );
// Gather up the set of active enemies
for ( i = 0; i < m_SquadMembers.Count(); i++ )
{
CBaseEntity *pMemberEnemy = m_SquadMembers[i]->GetEnemy();
if ( pMemberEnemy && activeEnemies.Find( pMemberEnemy ) == activeEnemies.InvalidIndex() )
{
activeEnemies.Insert( pMemberEnemy );
}
}
// Remove the records for deleted or unused enemies
for ( i = m_EnemyInfos.Count() - 1; i >= 0; --i )
{
if ( m_EnemyInfos[i].hEnemy == NULL || activeEnemies.Find( m_EnemyInfos[i].hEnemy ) == activeEnemies.InvalidIndex() )
{
m_EnemyInfos.FastRemove( i );
}
}
}
m_flEnemyInfoCleanupTime = gpGlobals->curtime + 30;
}
if ( m_pLastFoundEnemyInfo && m_pLastFoundEnemyInfo->hEnemy == pEnemy )
return m_pLastFoundEnemyInfo;
for ( i = 0; i < m_EnemyInfos.Count(); i++ )
{
if ( m_EnemyInfos[i].hEnemy == pEnemy )
{
m_pLastFoundEnemyInfo = &m_EnemyInfos[i];
return &m_EnemyInfos[i];
}
}
m_pLastFoundEnemyInfo = NULL;
i = m_EnemyInfos.AddToTail();
m_EnemyInfos[i].hEnemy = pEnemy;
m_pLastFoundEnemyInfo = &m_EnemyInfos[i];
return &m_EnemyInfos[i];
}
#endif
//------------------------------------------------------------------------------
void CAI_Squad::OccupySlot( CBaseEntity *pEnemy, int i )
{
#ifdef PER_ENEMY_SQUADSLOTS
AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
pInfo->slots.Set(i);
#else
m_squadSlotsUsed.Set(i);
#endif
}
//------------------------------------------------------------------------------
void CAI_Squad::VacateSlot( CBaseEntity *pEnemy, int i )
{
#ifdef PER_ENEMY_SQUADSLOTS
AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
pInfo->slots.Clear(i);
#else
m_squadSlotsUsed.Clear(i);
#endif
}
//------------------------------------------------------------------------------
bool CAI_Squad::IsSlotOccupied( CBaseEntity *pEnemy, int i ) const
{
#ifdef PER_ENEMY_SQUADSLOTS
const AISquadEnemyInfo_t *pInfo = FindEnemyInfo( pEnemy );
return pInfo->slots.IsBitSet(i);
#else
return m_squadSlotsUsed.IsBitSet(i);
#endif
}
void CAI_Squad::SquadRemember( int iMemory )
{
for (int i = 0; i < m_SquadMembers.Count(); i++)
{
if (m_SquadMembers[i] != NULL )
{
m_SquadMembers[i]->Remember( iMemory );
}
}
}
//------------------------------------------------------------------------------
void CAI_Squad::SetSquadInflictor( CBaseEntity *pInflictor )
{
m_hSquadInflictor.Set(pInflictor);
}
//------------------------------------------------------------------------------
bool CAI_Squad::IsSquadInflictor( CBaseEntity *pInflictor )
{
return (m_hSquadInflictor.Get() == pInflictor);
}
Mapbase v6.0 - Fixed path_track paths saving as pointers instead of handles - Fixed player animations not falling to base class correctly - Fixed logic_externaldata creating garbage in trailing spaces - Added "SetHandModelSkin" input - Added unique colors for various types of console message, adjustable via convars - Added the ability to use map-specific weapon scripts - Added a way to display (placeholder) text entirely from Faceposer scenes - Added "autobreak" keyvalue to game_text, which automatically breaks long text into different lines - Added the ability to change a game_text's font (very limited) - Added LightToggle input to point_spotlight - Added Enable/DisableSprites on npc_manhack - Added ai_goal_police behavior from metrocops to Combine soldiers and citizens - Added func_precipitation particle rain systems from the Alien Swarm SDK - Added new func_precipitation spawnflags for controlling behavior in particle types - Added "mapbase_version" cvar which shows the version of Mapbase a mod might be running on - Fixed an oversight with NPC crouch activities which was causing npc_metropolice to stop firing in standoffs - Added toggleable patches to npc_combine AI which make soldiers less likely to stand around without shooting or rush to melee when not needed - Added key for custom logo font on env_credits scripts - Added SetSpeed and SetPushDir inputs for trigger_push - Added a bunch of I/O/KV to func_fish_pool to allow for more control over the fish - Added OnLostEnemy/Player support for npc_combine_camera - Added enhanced save/restore for the Response System, toggleable via convar - Added a convar which allows users to disable weapon autoswitching when picking up ammo - Split VScript base script into its own file - Added VScript descriptions for NPC squads and the manager class which handles them - Moved several classes, functions, etc. to the VScript library itself for future usage in other projects, like VBSP - Added VScript to VBSP with basic map file interfacing - Made some VScript documentation more clear due to deprecation of online documentation - Added VScript "hook" registration, creating a standardized system which shows up in script_help documentation - Added VScript-driven custom weapons - Added clientside VScript scopes - Added a bunch of weapon-related VScript functions - Split a bunch of cluttered VScript stuff into different files - Added VScript functions for "following" entities/bonemerging - Added VScript functions for grenades - Added a few more VScript trigger functions - Added OnDeath hook for VScript - Fixed documentation for aliased functions in VScript - Fixed $bumpmask not working on SDK_LightmappedGeneric - Made vertex blend swapping in Hammer use a constant instead of a combo (makes it easier to compile the shader, especially for $bumpmask's sake) - Fixed brush phong, etc. causing SDK_WorldVertexTransition to stop working - Added limited support for $envmapmask in the bumpmapping shader - Fixed more issues with parallax corrected cubemaps and instances - Made instance variable recursion consistent with VMFII
2020-11-26 05:26:55 +03:00
#ifdef MAPBASE_VSCRIPT
//------------------------------------------------------------------------------
// Functions tailored specifically for VScript.
HSCRIPT CAI_Squad::ScriptGetFirstMember( bool bIgnoreSilentMembers ) { return ToHScript( GetFirstMember( NULL, bIgnoreSilentMembers ) ); }
HSCRIPT CAI_Squad::ScriptGetMember( int iIndex ) { return iIndex < m_SquadMembers.Count() ? ToHScript( m_SquadMembers[iIndex] ) : NULL; }
HSCRIPT CAI_Squad::ScriptGetAnyMember() { return ToHScript( GetAnyMember() ); }
//int CAI_Squad::ScriptNumMembers( bool bIgnoreSilentMembers ) { return NumMembers( bIgnoreSilentMembers ); }
int CAI_Squad::ScriptGetSquadIndex( HSCRIPT hNPC ) { return GetSquadIndex( HScriptToClass<CAI_BaseNPC>( hNPC ) ); }
void CAI_Squad::ScriptUpdateEnemyMemory( HSCRIPT hUpdater, HSCRIPT hEnemy, const Vector &position ) { UpdateEnemyMemory( HScriptToClass<CAI_BaseNPC>( hUpdater ), ToEnt( hEnemy ), position ); }
HSCRIPT CAI_Squad::ScriptSquadMemberInRange( const Vector &vecLocation, float flDist ) { return ToHScript( SquadMemberInRange( vecLocation, flDist ) ); }
HSCRIPT CAI_Squad::ScriptNearestSquadMember( HSCRIPT hMember ) { return ToHScript( NearestSquadMember( HScriptToClass<CAI_BaseNPC>( hMember ) ) ); }
int CAI_Squad::ScriptGetVisibleSquadMembers( HSCRIPT hMember ) { return GetVisibleSquadMembers( HScriptToClass<CAI_BaseNPC>( hMember ) ); }
HSCRIPT CAI_Squad::ScriptGetSquadMemberNearestTo( const Vector &vecLocation ) { return ToHScript( GetSquadMemberNearestTo( vecLocation ) ); }
bool CAI_Squad::ScriptIsMember( HSCRIPT hMember ) { return SquadIsMember( HScriptToClass<CAI_BaseNPC>( hMember ) ); }
bool CAI_Squad::ScriptIsLeader( HSCRIPT hLeader ) { return IsLeader( HScriptToClass<CAI_BaseNPC>( hLeader ) ); }
HSCRIPT CAI_Squad::ScriptGetLeader( void ) { return ToHScript( GetLeader() ); }
void CAI_Squad::ScriptAddToSquad( HSCRIPT hNPC ) { AddToSquad( HScriptToClass<CAI_BaseNPC>( hNPC ) ); }
void CAI_Squad::ScriptRemoveFromSquad( HSCRIPT hNPC ) { RemoveFromSquad( HScriptToClass<CAI_BaseNPC>( hNPC ), false ); }
bool CAI_Squad::ScriptIsSilentMember( HSCRIPT hNPC ) { return IsSilentMember( HScriptToClass<CAI_BaseNPC>( hNPC ) ); }
void CAI_Squad::ScriptSetSquadData( int iSlot, const char *data )
{
SetSquadData( iSlot, data );
}
const char *CAI_Squad::ScriptGetSquadData( int iSlot )
{
const char *data;
GetSquadData( iSlot, &data );
return data;
}
#endif
2013-12-03 07:31:46 +04:00
//=============================================================================