diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/server/env_entity_maker.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/server/env_entity_maker.cpp')
| -rw-r--r-- | mp/src/game/server/env_entity_maker.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/mp/src/game/server/env_entity_maker.cpp b/mp/src/game/server/env_entity_maker.cpp new file mode 100644 index 00000000..ff0fbcfd --- /dev/null +++ b/mp/src/game/server/env_entity_maker.cpp @@ -0,0 +1,366 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "entityoutput.h"
+#include "TemplateEntities.h"
+#include "point_template.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define SF_ENTMAKER_AUTOSPAWN 0x0001
+#define SF_ENTMAKER_WAITFORDESTRUCTION 0x0002
+#define SF_ENTMAKER_IGNOREFACING 0x0004
+#define SF_ENTMAKER_CHECK_FOR_SPACE 0x0008
+#define SF_ENTMAKER_CHECK_PLAYER_LOOKING 0x0010
+
+
+//-----------------------------------------------------------------------------
+// Purpose: An entity that mapmakers can use to ensure there's a required entity never runs out.
+// i.e. physics cannisters that need to be used.
+//-----------------------------------------------------------------------------
+class CEnvEntityMaker : public CPointEntity
+{
+ DECLARE_CLASS( CEnvEntityMaker, CPointEntity );
+public:
+ DECLARE_DATADESC();
+
+ virtual void Spawn( void );
+ virtual void Activate( void );
+
+ void SpawnEntity( Vector vecAlternateOrigin = vec3_invalid, QAngle vecAlternateAngles = vec3_angle );
+ void CheckSpawnThink( void );
+ void InputForceSpawn( inputdata_t &inputdata );
+ void InputForceSpawnAtEntityOrigin( inputdata_t &inputdata );
+
+private:
+
+ CPointTemplate *FindTemplate();
+
+ bool HasRoomToSpawn();
+ bool IsPlayerLooking();
+
+ Vector m_vecEntityMins;
+ Vector m_vecEntityMaxs;
+ EHANDLE m_hCurrentInstance;
+ EHANDLE m_hCurrentBlocker; // Last entity that blocked us spawning something
+ Vector m_vecBlockerOrigin;
+
+ // Movement after spawn
+ QAngle m_angPostSpawnDirection;
+ float m_flPostSpawnDirectionVariance;
+ float m_flPostSpawnSpeed;
+ bool m_bPostSpawnUseAngles;
+
+ string_t m_iszTemplate;
+
+ COutputEvent m_pOutputOnSpawned;
+ COutputEvent m_pOutputOnFailedSpawn;
+};
+
+BEGIN_DATADESC( CEnvEntityMaker )
+ // DEFINE_FIELD( m_vecEntityMins, FIELD_VECTOR ),
+ // DEFINE_FIELD( m_vecEntityMaxs, FIELD_VECTOR ),
+ DEFINE_FIELD( m_hCurrentInstance, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hCurrentBlocker, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_vecBlockerOrigin, FIELD_VECTOR ),
+ DEFINE_KEYFIELD( m_iszTemplate, FIELD_STRING, "EntityTemplate" ),
+ DEFINE_KEYFIELD( m_angPostSpawnDirection, FIELD_VECTOR, "PostSpawnDirection" ),
+ DEFINE_KEYFIELD( m_flPostSpawnDirectionVariance, FIELD_FLOAT, "PostSpawnDirectionVariance" ),
+ DEFINE_KEYFIELD( m_flPostSpawnSpeed, FIELD_FLOAT, "PostSpawnSpeed" ),
+ DEFINE_KEYFIELD( m_bPostSpawnUseAngles, FIELD_BOOLEAN, "PostSpawnInheritAngles" ),
+
+ // Outputs
+ DEFINE_OUTPUT( m_pOutputOnSpawned, "OnEntitySpawned" ),
+ DEFINE_OUTPUT( m_pOutputOnFailedSpawn, "OnEntityFailedSpawn" ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "ForceSpawn", InputForceSpawn ),
+ DEFINE_INPUTFUNC( FIELD_STRING, "ForceSpawnAtEntityOrigin", InputForceSpawnAtEntityOrigin ),
+
+ // Functions
+ DEFINE_THINKFUNC( CheckSpawnThink ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( env_entity_maker, CEnvEntityMaker );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::Spawn( void )
+{
+ m_vecEntityMins = vec3_origin;
+ m_vecEntityMaxs = vec3_origin;
+ m_hCurrentInstance = NULL;
+ m_hCurrentBlocker = NULL;
+ m_vecBlockerOrigin = vec3_origin;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::Activate( void )
+{
+ BaseClass::Activate();
+
+ // check for valid template
+ if ( m_iszTemplate == NULL_STRING )
+ {
+ Warning( "env_entity_maker %s has no template entity!\n", GetEntityName().ToCStr() );
+ UTIL_Remove( this );
+ return;
+ }
+
+ // Spawn an instance
+ if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
+ {
+ SpawnEntity();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPointTemplate *CEnvEntityMaker::FindTemplate()
+{
+ // Find our point_template
+ CPointTemplate *pTemplate = dynamic_cast<CPointTemplate *>(gEntList.FindEntityByName( NULL, STRING(m_iszTemplate) ));
+ if ( !pTemplate )
+ {
+ Warning( "env_entity_maker %s failed to find template %s.\n", GetEntityName().ToCStr(), STRING(m_iszTemplate) );
+ }
+
+ return pTemplate;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn an instance of the entity
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::SpawnEntity( Vector vecAlternateOrigin, QAngle vecAlternateAngles )
+{
+ CPointTemplate *pTemplate = FindTemplate();
+ if (!pTemplate)
+ return;
+
+ // Spawn our template
+ Vector vecSpawnOrigin = GetAbsOrigin();
+ QAngle vecSpawnAngles = GetAbsAngles();
+
+ if( vecAlternateOrigin != vec3_invalid )
+ {
+ // We have a valid alternate origin and angles. Use those instead
+ // of spawning the items at my own origin and angles.
+ vecSpawnOrigin = vecAlternateOrigin;
+ vecSpawnAngles = vecAlternateAngles;
+ }
+
+ CUtlVector<CBaseEntity*> hNewEntities;
+ if ( !pTemplate->CreateInstance( vecSpawnOrigin, vecSpawnAngles, &hNewEntities ) )
+ return;
+
+ //Adrian: oops we couldn't spawn the entity (or entities) for some reason!
+ if ( hNewEntities.Count() == 0 )
+ return;
+
+ m_hCurrentInstance = hNewEntities[0];
+
+ // Assume it'll block us
+ m_hCurrentBlocker = m_hCurrentInstance;
+ m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
+
+ // Store off the mins & maxs the first time we spawn
+ if ( m_vecEntityMins == vec3_origin )
+ {
+ m_hCurrentInstance->CollisionProp()->WorldSpaceAABB( &m_vecEntityMins, &m_vecEntityMaxs );
+ m_vecEntityMins -= m_hCurrentInstance->GetAbsOrigin();
+ m_vecEntityMaxs -= m_hCurrentInstance->GetAbsOrigin();
+ }
+
+ // Fire our output
+ m_pOutputOnSpawned.FireOutput( this, this );
+
+ // Start thinking
+ if ( m_spawnflags & SF_ENTMAKER_AUTOSPAWN )
+ {
+ SetThink( &CEnvEntityMaker::CheckSpawnThink );
+ SetNextThink( gpGlobals->curtime + 0.5f );
+ }
+
+ // If we have a specified post spawn speed, apply it to all spawned entities
+ if ( m_flPostSpawnSpeed )
+ {
+ for ( int i = 0; i < hNewEntities.Count(); i++ )
+ {
+ CBaseEntity *pEntity = hNewEntities[i];
+ if ( pEntity->GetMoveType() == MOVETYPE_NONE )
+ continue;
+
+ // Calculate a velocity for this entity
+ Vector vForward,vRight,vUp;
+ QAngle angSpawnDir( m_angPostSpawnDirection );
+ if ( m_bPostSpawnUseAngles )
+ {
+ if ( GetParent() )
+ {
+ angSpawnDir += GetParent()->GetAbsAngles();
+ }
+ else
+ {
+ angSpawnDir += GetAbsAngles();
+ }
+ }
+ AngleVectors( angSpawnDir, &vForward, &vRight, &vUp );
+ Vector vecShootDir = vForward;
+ vecShootDir += vRight * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
+ vecShootDir += vForward * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
+ vecShootDir += vUp * random->RandomFloat(-1, 1) * m_flPostSpawnDirectionVariance;
+ VectorNormalize( vecShootDir );
+ vecShootDir *= m_flPostSpawnSpeed;
+
+ // Apply it to the entity
+ IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
+ if ( pPhysicsObject )
+ {
+ pPhysicsObject->AddVelocity(&vecShootDir, NULL);
+ }
+ else
+ {
+ pEntity->SetAbsVelocity( vecShootDir );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether or not the template entities can fit if spawned.
+// Input : pBlocker - Returns blocker unless NULL.
+//-----------------------------------------------------------------------------
+bool CEnvEntityMaker::HasRoomToSpawn()
+{
+ // Do we have a blocker from last time?
+ if ( m_hCurrentBlocker )
+ {
+ // If it hasn't moved, abort immediately
+ if ( m_vecBlockerOrigin == m_hCurrentBlocker->GetAbsOrigin() )
+ {
+ return false;
+ }
+ }
+
+ // Check to see if there's enough room to spawn
+ trace_t tr;
+ UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin(), m_vecEntityMins, m_vecEntityMaxs, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
+ if ( tr.m_pEnt || tr.startsolid )
+ {
+ // Store off our blocker to check later
+ m_hCurrentBlocker = tr.m_pEnt;
+ if ( m_hCurrentBlocker )
+ {
+ m_vecBlockerOrigin = m_hCurrentBlocker->GetAbsOrigin();
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if the player is looking towards us.
+//-----------------------------------------------------------------------------
+bool CEnvEntityMaker::IsPlayerLooking()
+{
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( pPlayer )
+ {
+ // Only spawn if the player's looking away from me
+ Vector vLookDir = pPlayer->EyeDirection3D();
+ Vector vTargetDir = GetAbsOrigin() - pPlayer->EyePosition();
+ VectorNormalize( vTargetDir );
+
+ float fDotPr = DotProduct( vLookDir,vTargetDir );
+ if ( fDotPr > 0 )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to see if we should spawn another instance
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::CheckSpawnThink( void )
+{
+ SetNextThink( gpGlobals->curtime + 0.5f );
+
+ // Do we have an instance?
+ if ( m_hCurrentInstance )
+ {
+ // If Wait-For-Destruction is set, abort immediately
+ if ( m_spawnflags & SF_ENTMAKER_WAITFORDESTRUCTION )
+ return;
+ }
+
+ // Check to see if there's enough room to spawn
+ if ( !HasRoomToSpawn() )
+ return;
+
+ // We're clear, now check to see if the player's looking
+ if ( !( HasSpawnFlags( SF_ENTMAKER_IGNOREFACING ) ) && IsPlayerLooking() )
+ return;
+
+ // Clear, no player watching, so spawn!
+ SpawnEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawns the entities, checking for space if flagged to do so.
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::InputForceSpawn( inputdata_t &inputdata )
+{
+ CPointTemplate *pTemplate = FindTemplate();
+ if (!pTemplate)
+ return;
+
+ if ( HasSpawnFlags( SF_ENTMAKER_CHECK_FOR_SPACE ) && !HasRoomToSpawn() )
+ {
+ m_pOutputOnFailedSpawn.FireOutput( this, this );
+ return;
+ }
+
+ if ( HasSpawnFlags( SF_ENTMAKER_CHECK_PLAYER_LOOKING ) && IsPlayerLooking() )
+ {
+ m_pOutputOnFailedSpawn.FireOutput( this, this );
+ return;
+ }
+
+ SpawnEntity();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvEntityMaker::InputForceSpawnAtEntityOrigin( inputdata_t &inputdata )
+{
+ CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
+
+ if( pTargetEntity )
+ {
+ SpawnEntity( pTargetEntity->GetAbsOrigin(), pTargetEntity->GetAbsAngles() );
+ }
+}
|