//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Drops particles where the entity was. // //=============================================================================// #include "cbase.h" #include "EntityParticleTrail.h" #include "networkstringtable_gamedll.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // Used to retire the entity //----------------------------------------------------------------------------- static const char *s_pRetireContext = "RetireContext"; //----------------------------------------------------------------------------- // Save/load //----------------------------------------------------------------------------- BEGIN_DATADESC( CEntityParticleTrail ) DEFINE_FIELD( m_iMaterialName, FIELD_MATERIALINDEX ), DEFINE_EMBEDDED( m_Info ), DEFINE_FIELD( m_hConstraintEntity, FIELD_EHANDLE ), // Think this should be handled by StartTouch/etc. // DEFINE_FIELD( m_nRefCount, FIELD_INTEGER ), END_DATADESC() //----------------------------------------------------------------------------- // Networking //----------------------------------------------------------------------------- IMPLEMENT_SERVERCLASS_ST( CEntityParticleTrail, DT_EntityParticleTrail ) SendPropInt(SENDINFO(m_iMaterialName), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ), SendPropDataTable( SENDINFO_DT( m_Info ), &REFERENCE_SEND_TABLE( DT_EntityParticleTrailInfo ) ), SendPropEHandle(SENDINFO(m_hConstraintEntity)), END_SEND_TABLE() LINK_ENTITY_TO_CLASS( env_particle_trail, CEntityParticleTrail ); //----------------------------------------------------------------------------- // Purpose: Creates a flame and attaches it to a target entity. // Input : pTarget - //----------------------------------------------------------------------------- CEntityParticleTrail *CEntityParticleTrail::Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraintEntity ) { int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) ); // Look for other particle trails on the entity + copy state to the new entity CEntityParticleTrail *pTrail; CBaseEntity *pNext; for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext ) { pNext = pChild->NextMovePeer(); pTrail = dynamic_cast(pChild); if ( pTrail && (pTrail->m_iMaterialName == iMaterialName) ) { // Prevent destruction if it re-enters the field pTrail->IncrementRefCount(); return pTrail; } } pTrail = (CEntityParticleTrail *)CreateEntityByName( "env_particle_trail" ); if ( pTrail == NULL ) return NULL; pTrail->m_hConstraintEntity = pConstraintEntity; pTrail->m_iMaterialName = iMaterialName; pTrail->m_Info.CopyFrom(info); pTrail->m_nRefCount = 1; pTrail->AttachToEntity( pTarget ); pTrail->Spawn(); return pTrail; } //----------------------------------------------------------------------------- // Spawn //----------------------------------------------------------------------------- void CEntityParticleTrail::Spawn() { BaseClass::Spawn(); /* SetThink( &CEntityParticleTrail::BoogieThink ); SetNextThink( gpGlobals->curtime + 0.01f ); if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) ) { SetContextThink( ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext ); } */ } //----------------------------------------------------------------------------- // Spawn //----------------------------------------------------------------------------- void CEntityParticleTrail::UpdateOnRemove() { g_pNotify->ClearEntity( this ); BaseClass::UpdateOnRemove(); } //----------------------------------------------------------------------------- // Force our constraint entity to be trasmitted //----------------------------------------------------------------------------- void CEntityParticleTrail::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ) { // Are we already marked for transmission? if ( pInfo->m_pTransmitEdict->Get( entindex() ) ) return; BaseClass::SetTransmit( pInfo, bAlways ); // Force our constraint entity to be sent too. if ( m_hConstraintEntity ) { m_hConstraintEntity->SetTransmit( pInfo, bAlways ); } } //----------------------------------------------------------------------------- // Retire //----------------------------------------------------------------------------- void CEntityParticleTrail::IncrementRefCount() { if ( m_nRefCount == 0 ) { SetContextThink( NULL, gpGlobals->curtime, s_pRetireContext ); } ++m_nRefCount; } void CEntityParticleTrail::DecrementRefCount() { --m_nRefCount; Assert( m_nRefCount >= 0 ); if ( m_nRefCount == 0 ) { FollowEntity( NULL ); g_pNotify->ClearEntity( this ); SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext ); } } //----------------------------------------------------------------------------- // Clean up when the entity goes away. //----------------------------------------------------------------------------- void CEntityParticleTrail::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t ¶ms ) { BaseClass::NotifySystemEvent( pNotify, eventType, params ); Assert( pNotify == GetMoveParent() ); if ( eventType == NOTIFY_EVENT_DESTROY ) { FollowEntity( NULL ); g_pNotify->ClearEntity( this ); if ( m_nRefCount != 0 ) { m_nRefCount = 0; SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext ); } } } //----------------------------------------------------------------------------- // Suppression count //----------------------------------------------------------------------------- void CEntityParticleTrail::Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info ) { int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) ); // Look for the particle trail attached to this entity + decrease refcount CBaseEntity *pNext; for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext ) { pNext = pChild->NextMovePeer(); CEntityParticleTrail *pTrail = dynamic_cast(pChild); if ( !pTrail || (pTrail->m_iMaterialName != iMaterialName) ) continue; pTrail->DecrementRefCount(); } } //----------------------------------------------------------------------------- // Attach to an entity //----------------------------------------------------------------------------- void CEntityParticleTrail::AttachToEntity( CBaseEntity *pTarget ) { FollowEntity( pTarget ); g_pNotify->AddEntity( this, pTarget ); }