summaryrefslogtreecommitdiff
path: root/game/server/tf2/env_meteor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/tf2/env_meteor.cpp')
-rw-r--r--game/server/tf2/env_meteor.cpp618
1 files changed, 618 insertions, 0 deletions
diff --git a/game/server/tf2/env_meteor.cpp b/game/server/tf2/env_meteor.cpp
new file mode 100644
index 0000000..789df1f
--- /dev/null
+++ b/game/server/tf2/env_meteor.cpp
@@ -0,0 +1,618 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+
+#include "tf_player.h"
+#include "Env_Meteor.h"
+#include "entitylist.h"
+#include "vphysics_interface.h"
+#include "tier1/strtools.h"
+#include "mapdata_shared.h"
+#include "sharedinterface.h"
+#include "skycamera.h"
+#include "ispatialpartition.h"
+#include "gameinterface.h"
+#include "props.h"
+#include "tf_func_resource.h"
+#include "resource_chunk.h"
+
+
+#include "ndebugoverlay.h"
+
+//=============================================================================
+//
+// Enumerator for swept bbox collision.
+//
+class CCollideList : public IEntityEnumerator
+{
+public:
+ CCollideList( Ray_t *pRay, CBaseEntity* pIgnoreEntity, int nContentsMask ) :
+ m_Entities( 0, 32 ), m_pIgnoreEntity( pIgnoreEntity ),
+ m_nContentsMask( nContentsMask ), m_pRay(pRay) {}
+
+ virtual bool EnumEntity( IHandleEntity *pHandleEntity )
+ {
+ trace_t tr;
+ enginetrace->ClipRayToEntity( *m_pRay, m_nContentsMask, pHandleEntity, &tr );
+ if (( tr.fraction < 1.0f ) || (tr.startsolid) || (tr.allsolid))
+ {
+ CBaseEntity *pEntity = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
+ m_Entities.AddToTail( pEntity );
+ }
+
+ return true;
+ }
+
+ CUtlVector<CBaseEntity*> m_Entities;
+
+private:
+ CBaseEntity *m_pIgnoreEntity;
+ int m_nContentsMask;
+ Ray_t *m_pRay;
+};
+
+
+//=============================================================================
+//
+// Meteor Factory Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CMeteorFactory::CreateMeteor( int nID, int iType,
+ const Vector &vecPosition, const Vector &vecDirection,
+ float flSpeed, float flStartTime, float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ CEnvMeteor::Create( nID, iType, vecPosition, vecDirection, flSpeed, flStartTime, flDamageRadius,
+ vecTriggerMins, vecTriggerMaxs );
+}
+
+//=============================================================================
+//
+// Meteor Spawner Functions
+//
+
+void SendProxy_MeteorTargetPositions( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
+{
+ CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pData;
+ pOut->m_Vector[0] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.x;
+ pOut->m_Vector[1] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.y;
+ pOut->m_Vector[2] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.z;
+}
+
+void SendProxy_MeteorTargetRadii( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
+{
+ CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pData;
+ pOut->m_Float = pMeteorSpawner->m_aTargets[iElement].m_flRadius;
+}
+
+int SendProxyArrayLength_MeteorTargets( const void *pStruct, int objectID )
+{
+ CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ return pMeteorSpawner->m_aTargets.Count();
+}
+
+// Link the name "env_meteorspawner" to the CMeteorSpawner class. This
+// links the WC entity with the game code.
+LINK_ENTITY_TO_CLASS( env_meteorspawner, CEnvMeteorSpawner );
+
+BEGIN_DATADESC( CEnvMeteorSpawner )
+
+ // Key Fields.
+ DEFINE_KEYFIELD( m_SpawnerShared.m_iMeteorType, FIELD_INTEGER, "MeteorType" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_bSkybox, FIELD_INTEGER, "SpawnInSkybox" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_flMinSpawnTime, FIELD_FLOAT, "SpawnIntervalMin" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_flMaxSpawnTime, FIELD_FLOAT, "SpawnIntervalMax" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_nMinSpawnCount, FIELD_INTEGER, "SpawnCountMin" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_nMaxSpawnCount, FIELD_INTEGER, "SpawnCountMax" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_flMinSpeed, FIELD_FLOAT, "MeteorSpeedMin" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_flMaxSpeed, FIELD_FLOAT, "MeteorSpeedMax" ),
+ DEFINE_KEYFIELD( m_SpawnerShared.m_flMeteorDamageRadius, FIELD_FLOAT, "MeteorDamageRadius" ),
+ DEFINE_KEYFIELD( m_fDisabled, FIELD_BOOLEAN, "StartDisabled" ),
+
+ // Function Pointers.
+ DEFINE_FUNCTION( MeteorSpawnerThink ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
+
+END_DATADESC()
+
+BEGIN_SEND_TABLE_NOBASE( CEnvMeteorSpawnerShared, DT_EnvMeteorSpawnerShared )
+ // Setup (read from) Worldcraft.
+ SendPropInt ( SENDINFO( m_iMeteorType ), 8, SPROP_UNSIGNED ),
+ SendPropInt ( SENDINFO( m_bSkybox ), 4, SPROP_UNSIGNED ),
+ SendPropFloat ( SENDINFO( m_flMinSpawnTime ), 0, SPROP_NOSCALE ),
+ SendPropFloat ( SENDINFO( m_flMaxSpawnTime ), 0, SPROP_NOSCALE ),
+ SendPropInt ( SENDINFO( m_nMinSpawnCount ), 16, SPROP_UNSIGNED ),
+ SendPropInt ( SENDINFO( m_nMaxSpawnCount ), 16, SPROP_UNSIGNED ),
+ SendPropFloat ( SENDINFO( m_flMinSpeed ), 0, SPROP_NOSCALE ),
+ SendPropFloat ( SENDINFO( m_flMaxSpeed ), 0, SPROP_NOSCALE ),
+
+ // Setup through Init.
+ SendPropFloat ( SENDINFO( m_flStartTime ), -1, SPROP_NOSCALE ),
+ SendPropInt ( SENDINFO( m_nRandomSeed ), -1, SPROP_UNSIGNED ),
+ SendPropVector ( SENDINFO( m_vecMinBounds ), -1, SPROP_NOSCALE ),
+ SendPropVector ( SENDINFO( m_vecMaxBounds ), -1, SPROP_NOSCALE ),
+ SendPropVector ( SENDINFO( m_vecTriggerMins ), -1, SPROP_NOSCALE ),
+ SendPropVector ( SENDINFO( m_vecTriggerMaxs ), -1, SPROP_NOSCALE ),
+
+ // Target List
+ SendPropArray2( SendProxyArrayLength_MeteorTargets,
+ SendPropVector( "meteortargetposition_array_element", 0, 0, 0, SPROP_NOSCALE, 0, 0, SendProxy_MeteorTargetPositions ),
+ 16, 0, "meteortargetposition_array" ),
+
+ SendPropArray2( SendProxyArrayLength_MeteorTargets,
+ SendPropFloat( "meteortargetradius_array_element", 0, 0, 0, SPROP_NOSCALE, 0, 0, SendProxy_MeteorTargetRadii ),
+ 16, 0, "meteortargetradius_array" )
+END_SEND_TABLE()
+
+// This table encodes the CBaseEntity data.
+IMPLEMENT_SERVERCLASS_ST_NOBASE( CEnvMeteorSpawner, DT_EnvMeteorSpawner )
+ SendPropDataTable ( SENDINFO_DT( m_SpawnerShared ), &REFERENCE_SEND_TABLE( DT_EnvMeteorSpawnerShared ) ),
+ SendPropInt ( SENDINFO( m_fDisabled ), 1, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+// Meteor Models
+char *strResourceMeteorModels[2] =
+{
+ "models/props/common/meteorites/meteor04.mdl",
+ "models/props/common/meteorites/meteor05.mdl",
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CEnvMeteorSpawner::CEnvMeteorSpawner()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::Spawn( void )
+{
+ // Pre-cache.
+ Precache();
+
+ // Server-side is not visible -- for collision only.
+ SetSolid( SOLID_NONE );
+ SetMoveType( MOVETYPE_NONE );
+ AddEffects( EF_NODRAW );
+
+ // Set the "brush model" size and link into the world.
+ SetModel( STRING( GetModelName() ) );
+
+ // Set the think function and time.
+ if ( !m_fDisabled )
+ {
+ SetThink( MeteorSpawnerThink );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::InputEnable( inputdata_t &inputdata )
+{
+ m_fDisabled = false;
+
+ m_SpawnerShared.m_flStartTime = gpGlobals->curtime;
+ m_SpawnerShared.m_flNextSpawnTime = m_SpawnerShared.m_flStartTime + m_SpawnerShared.m_flMaxSpawnTime;
+
+ // Probably should set this as a message begin, etc..... will get to this later!!
+//
+// CEntityMessageFilter filter( this, "CEnvMeteorSpawner" );
+// MessageBegin( filter, 0 );
+// WRITE_LONG( m_SpawnerShared.m_flStartTime );
+// WRITE_LONG( m_SpawnerShared.m_flNextSpawnTime );
+// MessageEnd();
+
+ // Set the think function and time.
+ SetThink( MeteorSpawnerThink );
+ SetNextThink( gpGlobals->curtime + m_SpawnerShared.m_flNextSpawnTime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::InputDisable( inputdata_t &inputdata )
+{
+ m_fDisabled = true;
+ SetThink( NULL );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::Get3DSkyboxWorldBounds( Vector &vecTriggerMins,
+ Vector &vecTriggerMaxs )
+{
+ CBaseEntity *pEntity = gEntList.FindEntityByClassname( NULL, "trigger_skybox2world" );
+ if ( pEntity && pEntity->edict() )
+ {
+ pEntity->CollisionProp()->WorldSpaceAABB( &vecTriggerMins, &vecTriggerMaxs );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::Precache( void )
+{
+ // Precache the meteor models!
+ for ( int iType = 0; iType < 2; iType++ )
+ {
+ PrecacheModel( strResourceMeteorModels[iType] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::MeteorSpawnerThink( void )
+{
+ SetNextThink( gpGlobals->curtime + m_SpawnerShared.MeteorThink( gpGlobals->curtime ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CEnvMeteorSpawner::ShouldTransmit( const CCheckTransmitInfo *pInfo )
+{
+ if ( m_SpawnerShared.m_bSkybox )
+ return FL_EDICT_ALWAYS;
+
+ return BaseClass::ShouldTransmit( pInfo );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorSpawner::Activate( void )
+{
+ // Parse the entity list looking for targets!
+ int nEntityCount = engine->GetEntityCount();
+ for ( int iEntity = 0; iEntity < nEntityCount; ++iEntity )
+ {
+ edict_t *pEdict = engine->PEntityOfEntIndex( iEntity );
+ if ( !pEdict || pEdict->IsFree() )
+ continue;
+
+ CBaseEntity *pEntity = GetContainingEntity( pEdict );
+ if ( !pEntity )
+ continue;
+
+ if ( pEntity->GetFlags()& FL_STATICPROP )
+ continue;
+
+ if ( !Q_strcmp( pEntity->GetClassname(), "env_meteortarget" ) )
+ {
+ CEnvMeteorTarget *pMeteorTarget = static_cast<CEnvMeteorTarget*>( pEntity );
+ if ( pMeteorTarget && pMeteorTarget->m_target != NULL_STRING )
+ {
+ if ( !Q_strcmp( STRING( pMeteorTarget->m_target ), STRING( GetEntityName() ) ) )
+ {
+ m_SpawnerShared.AddToTargetList( pMeteorTarget->GetLocalOrigin(), pMeteorTarget->m_flRadius );
+ }
+ }
+ }
+ }
+
+ // Get 3d skybox world trigger bounds.
+ Vector vecTriggerMins, vecTriggerMaxs;
+ Get3DSkyboxWorldBounds( vecTriggerMins, vecTriggerMaxs );
+
+ // Initialize the spawner.
+ float flTime = gpGlobals->curtime;
+ m_SpawnerShared.Init( &m_Factory, 0/* seed */, flTime,
+ WorldAlignMins(), WorldAlignMaxs(), vecTriggerMins, vecTriggerMaxs );
+
+ // Setup next think.
+ if ( !m_fDisabled )
+ {
+ SetNextThink( gpGlobals->curtime + m_SpawnerShared.m_flNextSpawnTime );
+ }
+}
+
+//=============================================================================
+//
+// Meteor Target Functions
+//
+
+LINK_ENTITY_TO_CLASS( env_meteortarget, CEnvMeteorTarget );
+
+BEGIN_DATADESC( CEnvMeteorTarget )
+
+ // Key Fields.
+ DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "EffectRadius" ),
+
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CEnvMeteorTarget::CEnvMeteorTarget()
+{
+ m_iTargetID = -1;
+ m_flRadius = 1.0f;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteorTarget::Spawn( void )
+{
+ BaseClass::Spawn();
+}
+
+//=============================================================================
+//
+// Meteor Functions
+//
+
+//
+// NOTE: The server-side meteor code has not really been tested. I do not
+// trust that is works correctly and/or cleans itself up nicely!
+//
+
+LINK_ENTITY_TO_CLASS( env_meteor, CEnvMeteor );
+
+BEGIN_DATADESC( CEnvMeteor )
+
+ // Function Pointers.
+ DEFINE_FUNCTION( MeteorSkyboxThink ),
+ DEFINE_FUNCTION( MeteorWorldThink ),
+
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CEnvMeteor::CEnvMeteor()
+{
+ m_vecMin.Init( -10.0f, -10.0f, -10.0f );
+ m_vecMax.Init( 10.0f, 10.0f, 10.0f );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CEnvMeteor *CEnvMeteor::Create( int nID, int iMeteorType,
+ const Vector &vecOrigin, const Vector &vecDirection,
+ float flSpeed, float flStartTime, float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ CEnvMeteor *pMeteor = ( CEnvMeteor* )CreateEntityByName( "env_meteor" );
+ if ( pMeteor )
+ {
+ pMeteor->m_Meteor.Init( nID, flStartTime, METEOR_PASSIVE_TIME, vecOrigin, vecDirection, flSpeed,
+ flDamageRadius, vecTriggerMins, vecTriggerMaxs );
+
+ // If the meteor will never enter the world, then don't bother with a server-side version.
+ if ( pMeteor->m_Meteor.m_flWorldEnterTime == METEOR_INVALID_TIME )
+ {
+ UTIL_Remove( pMeteor );
+ }
+
+ // Handle forward simulation.
+ if ( ( pMeteor->m_Meteor.m_flStartTime + METEOR_MAX_LIFETIME ) < gpGlobals->curtime )
+ {
+ UTIL_Remove( pMeteor );
+ }
+
+ pMeteor->Spawn();
+ pMeteor->SetNextThink( gpGlobals->curtime + pMeteor->m_Meteor.m_flWorldEnterTime );
+ }
+
+ return pMeteor;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CEnvMeteor::Spawn( void )
+{
+ // Pass data.
+ BaseClass::Spawn();
+
+ int iModel = modelinfo->GetModelIndex( "models/props/common/meteorites/meteor04.mdl" );
+ if ( iModel > 0 )
+ {
+ const model_t *pModel = modelinfo->GetModel( iModel );
+ modelinfo->GetModelBounds( pModel, m_vecMin, m_vecMax );
+ }
+
+ // Assumes we start life in a skybox!
+ SetThink( MeteorSkyboxThink );
+
+ m_bPrevInSkybox = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This think function should be called at the time when the meteor
+// will be leaving the skybox and entering the world.
+//-----------------------------------------------------------------------------
+void CEnvMeteor::MeteorSkyboxThink( void )
+{
+ SetThink( MeteorWorldThink );
+ SetNextThink( gpGlobals->curtime + 0.2f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: This think function simulates (moves/collides) the meteor while in
+// the world.
+//-----------------------------------------------------------------------------
+void CEnvMeteor::MeteorWorldThink( void )
+{
+ // Get the current time.
+ float flTime = gpGlobals->curtime;
+
+ // Convert if need be!
+ if ( m_bPrevInSkybox )
+ {
+ m_Meteor.ConvertFromSkyboxToWorld();
+ UTIL_SetOrigin( this, m_Meteor.m_vecStartPosition );
+
+ m_bPrevInSkybox = false;
+ }
+
+ // Update meteor position for swept collision test.
+ Vector vecEndPosition;
+ m_Meteor.GetPositionAtTime( flTime, vecEndPosition );
+
+ // Debugging!!
+// NDebugOverlay::Box( GetAbsOrigin(), m_vecMin * 0.5f, m_vecMax * 0.5f, 255, 255, 0, 0, 5 );
+// NDebugOverlay::Box( vecEndPosition, m_vecMin, m_vecMax, 255, 0, 0, 0, 5 );
+
+ Ray_t ray;
+ ray.Init( GetAbsOrigin(), vecEndPosition, m_vecMin, m_vecMax );
+
+ CCollideList collideList( &ray, this, MASK_SOLID );
+ enginetrace->EnumerateEntities( ray, false, &collideList );
+
+ // Now get each entity and react accordinly!
+ for( int iEntity = collideList.m_Entities.Count(); --iEntity >= 0; )
+ {
+ CBaseEntity *pEntity = collideList.m_Entities[iEntity];
+
+ if ( pEntity )
+ {
+ Vector vecForceDir = m_Meteor.m_vecDirection;
+
+ // Check for a physics object and apply force!
+ IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
+ if ( pPhysObject )
+ {
+// float flMass = pPhysObject->GetMass();
+
+ // Send it flying!!!
+ vecForceDir *= 5000000000000.0f;
+ pPhysObject->ApplyForceCenter( vecForceDir );
+ }
+
+ if ( pEntity->m_takedamage )
+ {
+ CTakeDamageInfo info( this, this, 200.0f, DMG_CLUB );
+ CalculateExplosiveDamageForce( &info, vecForceDir, pEntity->GetAbsOrigin() );
+ pEntity->TakeDamage( info );
+ }
+ }
+ }
+
+ trace_t trace;
+ UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, m_vecMin, m_vecMax,
+ MASK_NPCWORLDSTATIC, this, COLLISION_GROUP_NONE, &trace );
+ if( ( trace.fraction < 1.0f ) && !( trace.surface.flags & SURF_SKY ) )
+ {
+ CBaseEntity *pEntity = trace.m_pEnt;
+ if ( pEntity )
+ {
+ // Hit the world? The meteor is destroyed!
+ if ( pEntity->GetSolid() == SOLID_BSP )
+ {
+#if 0
+ // Suppress resources for now!!
+
+ // Create a random number or resource chunks.
+ int nChunkCount = random->RandomInt( 0, 4 );
+ for( int iChunk = 0; iChunk < nChunkCount; ++iChunk )
+ {
+ // Generate a random velocity vector.
+ Vector vVelocity = Vector( random->RandomFloat( -20,20 ), random->RandomFloat( -20,20 ), random->RandomFloat( 100,150 ) );
+ CResourceChunk::Create( false, GetAbsOrigin(), vVelocity );
+ }
+#endif
+
+ // Splash damage!
+ Vector vecImpactPoint;
+ vecImpactPoint = GetAbsOrigin() + ( ( vecEndPosition - GetAbsOrigin() ) * trace.fraction );
+
+ // Debugging!!
+// NDebugOverlay::Box( vecImpactPoint, m_vecMin, m_vecMax, 0, 255, 0, 0, 5 );
+
+ //Iterate on all entities in the vicinity.
+ for ( CEntitySphereQuery sphere( vecImpactPoint, m_Meteor.GetDamageRadius() ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() )
+ {
+ // Get distance to object and use it as a scale value.
+ Vector vecSegment;
+ vecSegment = pEntity->GetAbsOrigin() - vecImpactPoint;
+ float flDistance = vecSegment.Length();
+
+ float flScale = flDistance / ( m_Meteor.GetDamageRadius() * 0.75f );
+ if ( flScale > 1.0f )
+ {
+ flScale = 1.0f;
+ }
+
+ Vector vecForceDir = m_Meteor.m_vecDirection;
+
+ // Check for a physics object and apply force!
+ IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
+ if ( pPhysObject )
+ {
+// float flMass = pPhysObject->GetMass();
+
+ // Send it flying!!!
+ vecForceDir *= 5000000000000.0f * flScale;
+ pPhysObject->ApplyForceCenter( vecForceDir );
+ }
+
+ if ( pEntity->m_takedamage )
+ {
+ CTakeDamageInfo info( this, this, 300.0f * flScale, DMG_CLUB );
+ CalculateExplosiveDamageForce( &info, vecForceDir, pEntity->GetAbsOrigin() );
+ pEntity->TakeDamage( info );
+ }
+ }
+
+ UTIL_Remove( this );
+ return;
+ }
+ }
+ }
+
+ // Always move full movement.
+ UTIL_SetOrigin( this, vecEndPosition );
+ SetNextThink( gpGlobals->curtime + 0.2f );
+
+ // Check for death.
+ if ( flTime >= m_Meteor.m_flWorldExitTime )
+ {
+ UTIL_Remove( this );
+ return;
+ }
+}
+
+//=============================================================================
+//
+// Shooting Star Spawner Functionality.
+//
+
+// Link the name "env_meteorspawner" to the CMeteorSpawner class. This
+// links the WC entity with the game code.
+LINK_ENTITY_TO_CLASS( env_shootingstarspawner, CShootingStarSpawner );
+
+BEGIN_DATADESC( CShootingStarSpawner )
+
+ // keys
+ DEFINE_KEYFIELD_NOT_SAVED( m_flSpawnInterval, FIELD_FLOAT, "SpawnInterval" ),
+ DEFINE_KEYFIELD_NOT_SAVED( m_bSkybox, FIELD_INTEGER, "SpawnInSkybox" ),
+
+END_DATADESC()
+
+IMPLEMENT_SERVERCLASS_ST( CShootingStarSpawner, DT_ShootingStarSpawner )
+ SendPropFloat( SENDINFO( m_flSpawnInterval ), -1, SPROP_NOSCALE ),
+END_SEND_TABLE()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CShootingStarSpawner::CShootingStarSpawner()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CShootingStarSpawner::ShouldTransmit( const CCheckTransmitInfo *pInfo )
+{
+ // Always send shooting star spawners if they are in the skybox!
+ if ( m_bSkybox )
+ return FL_EDICT_ALWAYS ;
+
+ return BaseClass::ShouldTransmit( pInfo );
+}