summaryrefslogtreecommitdiff
path: root/game/client/tf2/c_env_meteor.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf2/c_env_meteor.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf2/c_env_meteor.cpp')
-rw-r--r--game/client/tf2/c_env_meteor.cpp651
1 files changed, 651 insertions, 0 deletions
diff --git a/game/client/tf2/c_env_meteor.cpp b/game/client/tf2/c_env_meteor.cpp
new file mode 100644
index 0000000..e2ccf53
--- /dev/null
+++ b/game/client/tf2/c_env_meteor.cpp
@@ -0,0 +1,651 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "C_Env_Meteor.h"
+#include "fx_explosion.h"
+#include "tempentity.h"
+#include "c_tracer.h"
+
+//=============================================================================
+//
+// Meteor Factory Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_MeteorFactory::CreateMeteor( int nID, int iType,
+ const Vector &vecPosition, const Vector &vecDirection,
+ float flSpeed, float flStartTime, float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ C_EnvMeteor::Create( nID, iType, vecPosition, vecDirection, flSpeed, flStartTime, flDamageRadius,
+ vecTriggerMins, vecTriggerMaxs );
+}
+
+
+//=============================================================================
+//
+// Meteor Spawner Functions
+//
+
+void RecvProxy_MeteorTargetPositions( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.x = pData->m_Value.m_Vector[0];
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.y = pData->m_Value.m_Vector[1];
+ pSpawner->m_aTargets[pData->m_iElement].m_vecPosition.z = pData->m_Value.m_Vector[2];
+}
+
+void RecvProxy_MeteorTargetRadii( const CRecvProxyData *pData, void *pStruct, void *pOut )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ pSpawner->m_aTargets[pData->m_iElement].m_flRadius = pData->m_Value.m_Float;
+}
+
+void RecvProxyArrayLength_MeteorTargets( void *pStruct, int objectID, int currentArrayLength )
+{
+ CEnvMeteorSpawnerShared *pSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
+ if ( pSpawner->m_aTargets.Count() < currentArrayLength )
+ {
+ pSpawner->m_aTargets.SetSize( currentArrayLength );
+ }
+}
+
+
+BEGIN_RECV_TABLE_NOBASE( CEnvMeteorSpawnerShared, DT_EnvMeteorSpawnerShared )
+ // Setup (read from) Worldcraft.
+ RecvPropInt ( RECVINFO( m_iMeteorType ) ),
+ RecvPropInt ( RECVINFO( m_bSkybox ) ),
+ RecvPropFloat ( RECVINFO( m_flMinSpawnTime ) ),
+ RecvPropFloat ( RECVINFO( m_flMaxSpawnTime ) ),
+ RecvPropInt ( RECVINFO( m_nMinSpawnCount ) ),
+ RecvPropInt ( RECVINFO( m_nMaxSpawnCount ) ),
+ RecvPropFloat ( RECVINFO( m_flMinSpeed ) ),
+ RecvPropFloat ( RECVINFO( m_flMaxSpeed ) ),
+
+ // Setup through Init.
+ RecvPropFloat ( RECVINFO( m_flStartTime ) ),
+ RecvPropInt ( RECVINFO( m_nRandomSeed ) ),
+ RecvPropVector ( RECVINFO( m_vecMinBounds ) ),
+ RecvPropVector ( RECVINFO( m_vecMaxBounds ) ),
+ RecvPropVector ( RECVINFO( m_vecTriggerMins ) ),
+ RecvPropVector ( RECVINFO( m_vecTriggerMaxs ) ),
+
+ // Target List
+ RecvPropArray2( RecvProxyArrayLength_MeteorTargets,
+ RecvPropVector( "meteortargetposition_array_element", 0, 0, 0, RecvProxy_MeteorTargetPositions ),
+ 16, 0, "meteortargetposition_array" ),
+
+ RecvPropArray2( RecvProxyArrayLength_MeteorTargets,
+ RecvPropFloat( "meteortargetradius_array_element", 0, 0, 0, RecvProxy_MeteorTargetRadii ),
+ 16, 0, "meteortargetradius_array" )
+END_RECV_TABLE()
+
+// This table encodes the CBaseEntity data.
+IMPLEMENT_CLIENTCLASS_DT( C_EnvMeteorSpawner, DT_EnvMeteorSpawner, CEnvMeteorSpawner )
+ RecvPropDataTable ( RECVINFO_DT( m_SpawnerShared ), 0, &REFERENCE_RECV_TABLE( DT_EnvMeteorSpawnerShared ) ),
+ RecvPropInt ( RECVINFO( m_fDisabled ) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorSpawner::C_EnvMeteorSpawner()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::OnDataChanged( DataUpdateType_t updateType )
+{
+ // Initialize the client side spawner.
+ m_SpawnerShared.Init( &m_Factory, m_SpawnerShared.m_nRandomSeed, m_SpawnerShared.m_flStartTime,
+ m_SpawnerShared.m_vecMinBounds, m_SpawnerShared.m_vecMaxBounds,
+ m_SpawnerShared.m_vecTriggerMins, m_SpawnerShared.m_vecTriggerMaxs );
+
+ // Set the next think to be the next spawn interval.
+ if ( !m_fDisabled )
+ {
+ SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime );
+ }
+}
+
+#if 0
+// Will probably be used later!!
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::ReceiveMessage( int classID, bf_read &msg )
+{
+ if ( classID != GetClientClass()->m_ClassID )
+ {
+ // message is for subclass
+ BaseClass::ReceiveMessage( classID, msg );
+ return;
+ }
+
+ m_SpawnerShared.m_flStartTime = msg.ReadLong();
+ m_SpawnerShared.m_flNextSpawnTime = msg.ReadLong();
+ SetNextClientThink( m_SpawnerShared.m_flNextSpawnTime );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorSpawner::ClientThink( void )
+{
+ SetNextClientThink( m_SpawnerShared.MeteorThink( gpGlobals->curtime ) );
+}
+
+//=============================================================================
+//
+// Meteor Tail Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorHead::C_EnvMeteorHead()
+{
+ m_vecPos.Init();
+ m_vecPrevPos.Init();
+
+ m_flParticleScale = 1.0f;
+
+ m_pSmokeEmitter = NULL;
+ m_flSmokeSpawnInterval = 0.0f;
+ m_hSmokeMaterial = INVALID_MATERIAL_HANDLE;
+ m_flSmokeLifetime = 2.5f;
+ m_bEmitSmoke = true;
+
+ m_hFlareMaterial = INVALID_MATERIAL_HANDLE;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorHead::~C_EnvMeteorHead()
+{
+ Destroy();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::Start( const Vector &vecOrigin, const Vector &vecDirection )
+{
+ // Emitters.
+ m_pSmokeEmitter = CSimpleEmitter::Create( "MeteorTrail" );
+// m_pFireEmitter = CSimpleEmitter::Create( "MeteorFire" );
+ if ( !m_pSmokeEmitter /*|| !m_pFireEmitter*/ )
+ return;
+
+ // Smoke
+ m_pSmokeEmitter->SetSortOrigin( vecOrigin );
+ m_hSmokeMaterial = m_pSmokeEmitter->GetPMaterial( "particle/SmokeStack" );
+ Assert( m_hSmokeMaterial != INVALID_MATERIAL_HANDLE );
+
+ // Fire
+// m_pFireEmitter->SetSortOrigin( vecOrigin );
+// m_hFireMaterial = m_pFireEmitter->GetPMaterial( "particle/particle_fire" );
+// Assert( m_hFireMaterial != INVALID_MATERIAL_HANDLE );
+
+ // Flare
+// m_hFlareMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/redflare" );
+
+ VectorCopy( vecDirection, m_vecDirection );
+ VectorCopy( vecOrigin, m_vecPos );
+
+ m_bInitThink = true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::Destroy( void )
+{
+ m_pSmokeEmitter = NULL;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorHead::MeteorHeadThink( const Vector &vecOrigin, float flTime )
+{
+ if ( m_bInitThink )
+ {
+ VectorCopy( vecOrigin, m_vecPrevPos );
+ m_bInitThink = false;
+ }
+
+ // Update the position of the emitters.
+ VectorCopy( vecOrigin, m_vecPos );
+
+ // Update Smoke
+ if ( m_pSmokeEmitter.IsValid() && m_bEmitSmoke )
+ {
+ m_pSmokeEmitter->SetSortOrigin( m_vecPos );
+
+ // Get distance covered
+ Vector vecDelta;
+ VectorSubtract( m_vecPos, m_vecPrevPos, vecDelta );
+ float flLength = vecDelta.Length();
+
+ int nParticleCount = flLength / 35.0f;
+ if ( nParticleCount < 1 )
+ {
+ nParticleCount = 1;
+ }
+
+ flLength /= nParticleCount;
+
+ Vector vecPos;
+ for( int iParticle = 0; iParticle < nParticleCount; ++iParticle )
+ {
+ vecPos = m_vecPrevPos + ( m_vecDirection * ( flLength * iParticle ) );
+
+ // Add some noise to the position.
+ Vector vecPosOffset;
+ vecPosOffset.Random( -m_flSmokeSpawnRadius, m_flSmokeSpawnRadius );
+ VectorAdd( vecPosOffset, vecPos, vecPosOffset );
+
+
+ SimpleParticle *pParticle = ( SimpleParticle* )m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ),
+ m_hSmokeMaterial,
+ vecPosOffset );
+ if ( pParticle )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = m_flSmokeLifetime;
+
+ // Add just a little movement.
+ pParticle->m_vecVelocity.Random( -5.0f, 5.0f );
+
+ pParticle->m_uchColor[0] = 255.0f;
+ pParticle->m_uchColor[1] = 255.0f;
+ pParticle->m_uchColor[2] = 255.0f;
+
+
+ pParticle->m_uchStartSize = 70 * m_flParticleScale;
+ pParticle->m_uchEndSize = 25 * m_flParticleScale;
+
+ float flAlpha = random->RandomFloat( 0.5f, 1.0f );
+ pParticle->m_uchStartAlpha = flAlpha * 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
+ }
+ }
+ }
+
+ // Update Fire
+// if ( m_pFireEmitter && m_bEmitFire )
+// {
+// }
+
+ // Flare
+
+ // Save off position.
+ VectorCopy( m_vecPos, m_vecPrevPos );
+}
+
+//=============================================================================
+//
+// Meteor Tail Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorTail::C_EnvMeteorTail()
+{
+ m_TailMaterialHandle = INVALID_MATERIAL_HANDLE;
+
+ m_pParticleMgr = NULL;
+ m_pParticle = NULL;
+
+ m_flFadeTime = 0.5f;
+ m_flWidth = 3.0f;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteorTail::~C_EnvMeteorTail()
+{
+ Destroy();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::Start( const Vector &vecOrigin, const Vector &vecDirection,
+ float flSpeed )
+{
+ // Set the particle manager.
+ m_pParticleMgr = ParticleMgr();
+ m_pParticleMgr->AddEffect( &m_ParticleEffect, this );
+ m_TailMaterialHandle = m_ParticleEffect.FindOrAddMaterial( "particle/guidedplasmaprojectile" );
+ m_pParticle = m_ParticleEffect.AddParticle( sizeof( StandardParticle_t ), m_TailMaterialHandle );
+ if ( m_pParticle )
+ {
+ m_pParticle->m_Pos = vecOrigin;
+ }
+
+ VectorCopy( vecDirection, m_vecDirection );
+ m_flSpeed = flSpeed;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::Destroy( void )
+{
+ if ( m_pParticleMgr )
+ {
+ m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
+ m_pParticleMgr = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteorTail::DrawFragment( ParticleDraw* pDraw,
+ const Vector &vecStart, const Vector &vecDelta,
+ const Vector4D &vecStartColor, const Vector4D &vecEndColor,
+ float flStartV, float flEndV )
+{
+ if( !pDraw->GetMeshBuilder() )
+ return;
+
+ // Clip the fragment.
+ Vector vecVerts[4];
+ if ( !Tracer_ComputeVerts( vecStart, vecDelta, m_flWidth, vecVerts ) )
+ return;
+
+ // NOTE: Gotta get the winding right so it's not backface culled
+ // (we need to turn of backface culling for these bad boys)
+ CMeshBuilder* pMeshBuilder = pDraw->GetMeshBuilder();
+
+ pMeshBuilder->Position3f( vecVerts[0].x, vecVerts[0].y, vecVerts[0].z );
+ pMeshBuilder->TexCoord2f( 0, 0.0f, flStartV );
+ pMeshBuilder->Color4fv( vecStartColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[1].x, vecVerts[1].y, vecVerts[1].z );
+ pMeshBuilder->TexCoord2f( 0, 1.0f, flStartV );
+ pMeshBuilder->Color4fv( vecStartColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[3].x, vecVerts[3].y, vecVerts[3].z );
+ pMeshBuilder->TexCoord2f( 0, 1.0f, flEndV );
+ pMeshBuilder->Color4fv( vecEndColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+
+ pMeshBuilder->Position3f( vecVerts[2].x, vecVerts[2].y, vecVerts[2].z );
+ pMeshBuilder->TexCoord2f( 0, 0.0f, flEndV );
+ pMeshBuilder->Color4fv( vecEndColor.Base() );
+ pMeshBuilder->AdvanceVertex();
+}
+
+void C_EnvMeteorTail::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ Particle *pParticle = (Particle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Update the particle position.
+ pParticle->m_Pos = GetLocalOrigin();
+
+ pParticle = (Particle*)pIterator->GetNext();
+ }
+}
+
+
+void C_EnvMeteorTail::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ const Particle *pParticle = (const Particle *)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Now draw the tail fragments...
+ Vector4D vecStartColor( 1.0f, 1.0f, 1.0f, 1.0f );
+ Vector4D vecEndColor( 1.0f, 1.0f, 1.0f, 0.0f );
+ Vector vecDelta, vecStartPos, vecEndPos;
+
+ // Calculate the tail.
+ Vector vecTailEnd;
+ vecTailEnd = GetLocalOrigin() + ( m_vecDirection * -m_flSpeed );
+
+ // Transform particles into camera space.
+ TransformParticle( m_pParticleMgr->GetModelView(), GetLocalOrigin(), vecStartPos );
+ TransformParticle( m_pParticleMgr->GetModelView(), vecTailEnd, vecEndPos );
+ float sortKey = vecStartPos.z;
+
+ // Draw the tail fragment.
+ VectorSubtract( vecStartPos, vecEndPos, vecDelta );
+ DrawFragment( pIterator->GetParticleDraw(), vecEndPos, vecDelta, vecEndColor, vecStartColor,
+ 1.0f - vecEndColor[3], 1.0f - vecStartColor[3] );
+
+ pParticle = (const Particle *)pIterator->GetNext( sortKey );
+ }
+}
+
+
+//=============================================================================
+//
+// Meteor Functions
+//
+
+static g_MeteorCounter = 0;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor::C_EnvMeteor()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor::~C_EnvMeteor()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::ClientThink( void )
+{
+ // Get the current time.
+ float flTime = gpGlobals->curtime;
+
+ // Update the meteor.
+ if ( m_Meteor.IsInSkybox( flTime ) )
+ {
+ if ( m_Meteor.m_nLocation == METEOR_LOCATION_WORLD )
+ {
+ WorldToSkyboxThink( flTime );
+ }
+ else
+ {
+ SkyboxThink( flTime );
+ }
+ }
+ else
+ {
+ if ( m_Meteor.m_nLocation == METEOR_LOCATION_SKYBOX )
+ {
+ SkyboxToWorldThink( flTime );
+ }
+ else
+ {
+ WorldThink( flTime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::SkyboxThink( float flTime )
+{
+ float flDeltaTime = flTime - m_Meteor.m_flStartTime;
+ if ( flDeltaTime > METEOR_MAX_LIFETIME )
+ {
+ Destroy( this );
+ return;
+ }
+
+ // Check to see if the object is passive or not - act accordingly!
+ if ( !m_Meteor.IsPassive( flTime ) )
+ {
+ // Update meteor position.
+ Vector origin;
+ m_Meteor.GetPositionAtTime( flTime, origin );
+ SetLocalOrigin( origin );
+
+ // Update the position of the tail effect.
+ m_TailEffect.SetLocalOrigin( GetLocalOrigin() );
+ m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime );
+ }
+
+ // Add the entity to the active list - update!
+ AddEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::WorldToSkyboxThink( float flTime )
+{
+ // Move the meteor from the world into the skybox.
+ m_Meteor.ConvertFromWorldToSkybox();
+
+ // Destroy the head effect. Recreate it.
+ m_HeadEffect.Destroy();
+ m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir );
+ m_HeadEffect.SetSmokeEmission( true );
+ m_HeadEffect.SetParticleScale( 1.0f / 16.0f );
+ m_HeadEffect.m_bInitThink = true;
+
+ // Update to world model.
+ SetModel( "models/props/common/meteorites/meteor05.mdl" );
+
+ // Update the meteor position (move into the skybox!)
+ SetLocalOrigin( m_Meteor.m_vecStartPosition );
+
+ // Update (think).
+ SkyboxThink( flTime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::SkyboxToWorldThink( float flTime )
+{
+ // Move the meteor from the skybox into the world.
+ m_Meteor.ConvertFromSkyboxToWorld();
+
+ // Destroy the head effect. Recreate it.
+ m_HeadEffect.Destroy();
+ m_HeadEffect.Start( m_Meteor.m_vecStartPosition, m_vecTravelDir );
+ m_HeadEffect.SetSmokeEmission( true );
+ m_HeadEffect.SetParticleScale( 1.0f );
+ m_HeadEffect.m_bInitThink = true;
+
+ // Update to world model.
+ SetModel( "models/props/common/meteorites/meteor04.mdl" );
+
+ SetLocalOrigin( m_Meteor.m_vecStartPosition );
+
+ // Update (think).
+ WorldThink( flTime );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::WorldThink( float flTime )
+{
+ // Update meteor position.
+ Vector vecEndPosition;
+ m_Meteor.GetPositionAtTime( flTime, vecEndPosition );
+
+ // m_Meteor must return the end position in world space for the trace to work.
+ Assert( GetMoveParent() == NULL );
+
+// Msg( "Client: Time = %lf, Position: %4.2f %4.2f %4.2f\n", flTime, vecEndPosition.x, vecEndPosition.y, vecEndPosition.z );
+
+ // Check to see if we struck the world. If so, cause an explosion.
+ trace_t trace;
+
+ Vector vecMin, vecMax;
+ GetRenderBounds( vecMin, vecMax );
+
+ // NOTE: This code works only if we aren't in hierarchy!!!
+ Assert( !GetMoveParent() );
+
+ CTraceFilterWorldOnly traceFilter;
+ UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, vecMin, vecMax,
+ MASK_SOLID_BRUSHONLY, &traceFilter, &trace );
+
+ // Collision.
+ if ( ( trace.fraction < 1.0f ) && !( trace.surface.flags & SURF_SKY ) )
+ {
+ // Move up to the end.
+ Vector vecEnd = GetAbsOrigin() + ( ( vecEndPosition - GetAbsOrigin() ) * trace.fraction );
+
+ // Create an explosion effect!
+ BaseExplosionEffect().Create( vecEnd, 10, 32, TE_EXPLFLAG_NONE );
+
+ // Debugging Info!!!!
+// debugoverlay->AddBoxOverlay( vecEnd, Vector( -10, -10, -10 ), Vector( 10, 10, 10 ), QAngle( 0.0f, 0.0f, 0.0f ), 255, 0, 0, 0, 100 );
+
+ Destroy( this );
+ return;
+ }
+ else
+ {
+ // Move to the end.
+ SetLocalOrigin( vecEndPosition );
+ }
+
+ m_TailEffect.SetLocalOrigin( GetLocalOrigin() );
+ m_HeadEffect.MeteorHeadThink( GetLocalOrigin(), flTime );
+
+ // Add the entity to the active list - update!
+ AddEntity();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+C_EnvMeteor *C_EnvMeteor::Create( int nID, int iMeteorType, const Vector &vecOrigin,
+ const Vector &vecDirection, float flSpeed, float flStartTime,
+ float flDamageRadius,
+ const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
+{
+ C_EnvMeteor *pMeteor = new C_EnvMeteor;
+ if ( pMeteor )
+ {
+ pMeteor->m_Meteor.Init( nID, flStartTime, METEOR_PASSIVE_TIME, vecOrigin, vecDirection, flSpeed, flDamageRadius,
+ vecTriggerMins, vecTriggerMaxs );
+
+ // Initialize the meteor.
+ pMeteor->InitializeAsClientEntity( "models/props/common/meteorites/meteor05.mdl", RENDER_GROUP_OPAQUE_ENTITY );
+
+ // Handle forward simulation.
+ if ( ( pMeteor->m_Meteor.m_flStartTime + METEOR_MAX_LIFETIME ) < gpGlobals->curtime )
+ {
+ Destroy( pMeteor );
+ }
+
+ // Meteor Head and Tail
+ pMeteor->SetTravelDirection( vecDirection );
+
+ pMeteor->m_HeadEffect.SetSmokeEmission( true );
+ pMeteor->m_HeadEffect.Start( vecOrigin, vecDirection );
+ pMeteor->m_HeadEffect.SetParticleScale( 1.0f / 16.0f );
+
+ pMeteor->m_TailEffect.Start( vecOrigin, vecDirection, flSpeed );
+
+ pMeteor->SetNextClientThink( CLIENT_THINK_ALWAYS );
+ }
+
+ return pMeteor;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_EnvMeteor::Destroy( C_EnvMeteor *pMeteor )
+{
+ Assert( pMeteor->GetClientHandle() != INVALID_CLIENTENTITY_HANDLE );
+ ClientThinkList()->AddToDeleteList( pMeteor->GetClientHandle() );
+}