//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "particles_simple.h" #include "c_tracer.h" #include "particle_collision.h" #include "view.h" #include "clienteffectprecachesystem.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #define PLASMASPARK_LIFETIME 0.5 #define SPRAYS_PER_THINK 12 CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectPlasmaBeam ) CLIENTEFFECT_MATERIAL( "sprites/plasmaember" ) CLIENTEFFECT_REGISTER_END() class C_PlasmaBeamNode; //################################################################## // // > CPlasmaSpray // //################################################################## class CPlasmaSpray : public CSimpleEmitter { public: CPlasmaSpray( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {} static CSmartPtr Create( const char *pDebugName ); void Think( void ); void UpdateVelocity( SimpleParticle *pParticle, float timeDelta ); virtual void RenderParticles( CParticleRenderIterator *pIterator ); virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); EHANDLE m_pOwner; CParticleCollision m_ParticleCollision; private: CPlasmaSpray( const CPlasmaSpray & ); }; //################################################################## // // PlasmaBeamNode - generates plasma spray // //################################################################## class C_PlasmaBeamNode : public C_BaseEntity { public: DECLARE_CLASS( C_PlasmaBeamNode, C_BaseEntity ); DECLARE_CLIENTCLASS(); C_PlasmaBeamNode(); ~C_PlasmaBeamNode(void); public: void ClientThink(void); void AddEntity( void ); void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); bool m_bSprayOn; CSmartPtr m_pFirePlasmaSpray; }; //################################################################## // // > CPlasmaSpray // //################################################################## //----------------------------------------------------------------------------- // Purpose: // Input : *pParticle - // timeDelta - // Output : float //----------------------------------------------------------------------------- CSmartPtr CPlasmaSpray::Create( const char *pDebugName ) { CPlasmaSpray *pRet = new CPlasmaSpray( pDebugName ); return pRet; } //----------------------------------------------------------------------------- // Purpose: // Input : fTimeDelta - // Output : Vector //----------------------------------------------------------------------------- void CPlasmaSpray::UpdateVelocity( SimpleParticle *pParticle, float timeDelta ) { Vector vGravity = Vector(0,0,-1000); float flFrametime = gpGlobals->frametime; vGravity = flFrametime * vGravity; pParticle->m_vecVelocity += vGravity; } void CPlasmaSpray::SimulateParticles( CParticleSimulateIterator *pIterator ) { float timeDelta = pIterator->GetTimeDelta(); SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst(); while ( pParticle ) { //Should this particle die? pParticle->m_flLifetime += timeDelta; C_PlasmaBeamNode* pNode = (C_PlasmaBeamNode*)((C_BaseEntity*)m_pOwner); if ( pParticle->m_flLifetime >= pParticle->m_flDieTime ) { pIterator->RemoveParticle( pParticle ); } // If owner is gone or spray off remove me else if (pNode == NULL || !pNode->m_bSprayOn) { pIterator->RemoveParticle( pParticle ); } //Simulate the movement with collision trace_t trace; m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, NULL, timeDelta, &trace ); pParticle = (SimpleParticle*)pIterator->GetNext(); } } void CPlasmaSpray::RenderParticles( CParticleRenderIterator *pIterator ) { const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst(); while ( pParticle ) { float scale = random->RandomFloat( 0.02, 0.08 ); // NOTE: We need to do everything in screen space Vector delta; Vector start; TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, start); float sortKey = start.z; Vector3DMultiply( CurrentWorldToViewMatrix(), pParticle->m_vecVelocity, delta ); delta[0] *= scale; delta[1] *= scale; delta[2] *= scale; // See c_tracer.* for this method Tracer_Draw( pIterator->GetParticleDraw(), start, delta, random->RandomInt( 2, 8 ), 0 ); pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey ); } } //################################################################## // // PlasmaBeamNode - generates plasma spray // //################################################################## //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ C_PlasmaBeamNode::C_PlasmaBeamNode(void) { m_bSprayOn = false; m_pFirePlasmaSpray = CPlasmaSpray::Create( "C_PlasmaBeamNode" ); } //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ C_PlasmaBeamNode::~C_PlasmaBeamNode(void) { } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_PlasmaBeamNode::AddEntity( void ) { m_pFirePlasmaSpray->SetSortOrigin( GetAbsOrigin() ); } //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void C_PlasmaBeamNode::OnDataChanged(DataUpdateType_t updateType) { if (updateType == DATA_UPDATE_CREATED) { Vector vMoveDir = GetAbsVelocity(); float flVel = VectorNormalize(vMoveDir); m_pFirePlasmaSpray->m_ParticleCollision.Setup( GetAbsOrigin(), &vMoveDir, 0.3, flVel-50, flVel+50, 800, 0.5 ); SetNextClientThink(gpGlobals->curtime + 0.01); } C_BaseEntity::OnDataChanged(updateType); } //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ bool C_PlasmaBeamNode::ShouldDraw() { return false; } //------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void C_PlasmaBeamNode::ClientThink(void) { if (!m_bSprayOn) { return; } trace_t trace; Vector vEndTrace = GetAbsOrigin() + (0.3*GetAbsVelocity()); UTIL_TraceLine( GetAbsOrigin(), vEndTrace, MASK_SHOT, NULL, COLLISION_GROUP_NONE, &trace ); if ( trace.fraction != 1.0f || trace.startsolid) { m_bSprayOn = false; return; } PMaterialHandle handle = m_pFirePlasmaSpray->GetPMaterial( "sprites/plasmaember" ); for (int i=0;iRandomInt( 0, 2 ) == 0 ) { float ranx = random->RandomFloat( -28.0f, 28.0f ); float rany = random->RandomFloat( -28.0f, 28.0f ); float ranz = random->RandomFloat( -28.0f, 28.0f ); Vector vNewPos = GetAbsOrigin(); Vector vAdd = Vector(GetAbsAngles().x,GetAbsAngles().y,GetAbsAngles().z)*random->RandomFloat(-60,120); vNewPos += vAdd; sParticle = (SimpleParticle *) m_pFirePlasmaSpray->AddParticle( sizeof(SimpleParticle), handle, vNewPos ); sParticle->m_flLifetime = 0.0f; sParticle->m_flDieTime = PLASMASPARK_LIFETIME; sParticle->m_vecVelocity = GetAbsVelocity(); sParticle->m_vecVelocity.x += ranx; sParticle->m_vecVelocity.y += rany; sParticle->m_vecVelocity.z += ranz; m_pFirePlasmaSpray->m_pOwner = this; } } SetNextClientThink(gpGlobals->curtime + 0.05); } IMPLEMENT_CLIENTCLASS_DT(C_PlasmaBeamNode, DT_PlasmaBeamNode, CPlasmaBeamNode ) RecvPropVector (RECVINFO(m_vecVelocity), 0, RecvProxy_LocalVelocity), RecvPropInt (RECVINFO(m_bSprayOn)), END_RECV_TABLE()