2023-10-03 14:23:56 +00:00
//====== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. =======
2020-04-22 16:56:21 +00:00
//
// Purpose:
//
//=============================================================================
# include "cbase.h"
# include "particle_property.h"
# include "utlvector.h"
# ifdef CLIENT_DLL
# include "c_baseentity.h"
# include "c_baseanimating.h"
# include "recvproxy.h"
# include "particles_new.h"
# include "engine/ivdebugoverlay.h"
2023-10-03 14:23:56 +00:00
2020-04-22 16:56:21 +00:00
# else
# include "baseentity.h"
# include "baseanimating.h"
# include "sendproxy.h"
# endif
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC_NO_BASE ( CParticleProperty )
// DEFINE_FIELD( m_pOuter, FIELD_CLASSPTR ),
END_DATADESC ( )
# ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Prediction
//-----------------------------------------------------------------------------
BEGIN_PREDICTION_DATA_NO_BASE ( CParticleProperty )
//DEFINE_PRED_FIELD( m_vecMins, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA ( )
# endif
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
BEGIN_NETWORK_TABLE_NOBASE ( CParticleProperty , DT_ParticleProperty )
# ifdef CLIENT_DLL
//RecvPropVector( RECVINFO(m_vecMins), 0, RecvProxy_OBBMins ),
# else
//SendPropVector( SENDINFO(m_vecMins), 0, SPROP_NOSCALE),
# endif
END_NETWORK_TABLE ( )
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CParticleProperty : : CParticleProperty ( )
{
Init ( NULL ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CParticleProperty : : ~ CParticleProperty ( )
{
// We're being removed. Call StopEmission() on any particle system
// that has an unlimited number of particles to emit.
2023-10-03 14:23:56 +00:00
StopEmission ( NULL , false , true , false , true ) ;
2020-04-22 16:56:21 +00:00
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
void CParticleProperty : : Init ( CBaseEntity * pEntity )
{
m_pOuter = pEntity ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CParticleProperty : : GetParticleAttachment ( C_BaseEntity * pEntity , const char * pszAttachmentName , const char * pszParticleName )
{
Assert ( pEntity & & pEntity - > GetBaseAnimating ( ) ) ;
if ( ! pEntity | | ! pEntity - > GetBaseAnimating ( ) )
2023-10-03 14:23:56 +00:00
return - 1 ;
2020-04-22 16:56:21 +00:00
// Find the attachment point index
int iAttachment = pEntity - > GetBaseAnimating ( ) - > LookupAttachment ( pszAttachmentName ) ;
2023-10-03 14:23:56 +00:00
if ( iAttachment = = - 1 )
2020-04-22 16:56:21 +00:00
{
Warning ( " Model '%s' doesn't have attachment '%s' to attach particle system '%s' to. \n " , STRING ( pEntity - > GetBaseAnimating ( ) - > GetModelName ( ) ) , pszAttachmentName , pszParticleName ) ;
}
return iAttachment ;
}
2023-10-03 14:23:56 +00:00
//-----------------------------------------------------------------------------
// Purpose: Get's a list of all renderables used for this particle property
//-----------------------------------------------------------------------------
int CParticleProperty : : GetAllParticleEffectRenderables ( IClientRenderable * * pOutput , int iMaxOutput )
{
if ( iMaxOutput = = 0 )
return 0 ;
int iReturnedRenderables = 0 ;
int iParticleEffectListCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i ! = iParticleEffectListCount ; + + i )
{
if ( m_ParticleEffects [ i ] . pParticleEffect . IsValid ( ) )
{
pOutput [ iReturnedRenderables + + ] = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) ;
if ( iReturnedRenderables = = iMaxOutput )
break ;
}
}
return iReturnedRenderables ;
}
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Purpose: Create a new particle system and attach it to our owner
//-----------------------------------------------------------------------------
CNewParticleEffect * CParticleProperty : : Create ( const char * pszParticleName , ParticleAttachment_t iAttachType , const char * pszAttachmentName )
{
int iAttachment = GetParticleAttachment ( GetOuter ( ) , pszAttachmentName , pszParticleName ) ;
2023-10-03 14:23:56 +00:00
if ( iAttachment = = - 1 )
2020-04-22 16:56:21 +00:00
return NULL ;
// Create the system
return Create ( pszParticleName , iAttachType , iAttachment ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Create a new particle system and attach it to our owner
//-----------------------------------------------------------------------------
static ConVar cl_particle_batch_mode ( " cl_particle_batch_mode " , " 1 " ) ;
2023-10-03 14:23:56 +00:00
CNewParticleEffect * CParticleProperty : : Create ( CParticleSystemDefinition * pDef , ParticleAttachment_t iAttachType , int iAttachmentPoint , Vector vecOriginOffset , matrix3x4_t * matOffset )
{
2020-04-22 16:56:21 +00:00
int nBatchMode = cl_particle_batch_mode . GetInt ( ) ;
bool bRequestedBatch = ( nBatchMode = = 2 ) | | ( ( nBatchMode = = 1 ) & & pDef & & pDef - > ShouldBatch ( ) ) ;
if ( ( iAttachType = = PATTACH_CUSTOMORIGIN ) & & bRequestedBatch )
{
2023-10-03 14:23:56 +00:00
int iIndex = FindEffect ( pDef - > GetName ( ) ) ;
2020-04-22 16:56:21 +00:00
if ( iIndex > = 0 )
{
CNewParticleEffect * pEffect = m_ParticleEffects [ iIndex ] . pParticleEffect . GetObject ( ) ;
pEffect - > Restart ( ) ;
return pEffect ;
}
}
int iIndex = m_ParticleEffects . AddToTail ( ) ;
ParticleEffectList_t * newEffect = & m_ParticleEffects [ iIndex ] ;
2023-10-03 14:23:56 +00:00
newEffect - > pParticleEffect = CNewParticleEffect : : Create ( m_pOuter , pDef , pDef - > GetName ( ) ) ;
2020-04-22 16:56:21 +00:00
if ( ! newEffect - > pParticleEffect - > IsValid ( ) )
{
// Caused by trying to spawn an unregistered particle effect. Remove it.
ParticleMgr ( ) - > RemoveEffect ( newEffect - > pParticleEffect . GetObject ( ) ) ;
return NULL ;
}
2023-10-03 14:23:56 +00:00
AddControlPoint ( iIndex , 0 , GetOuter ( ) , iAttachType , iAttachmentPoint , vecOriginOffset , matOffset ) ;
2020-04-22 16:56:21 +00:00
if ( m_pOuter )
{
2023-10-03 14:23:56 +00:00
m_pOuter - > OnNewParticleEffect ( pDef - > GetName ( ) , newEffect - > pParticleEffect . GetObject ( ) ) ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
2020-04-22 16:56:21 +00:00
return newEffect - > pParticleEffect . GetObject ( ) ;
}
2023-10-03 14:23:56 +00:00
CNewParticleEffect * CParticleProperty : : CreatePrecached ( int nPrecacheIndex , ParticleAttachment_t iAttachType , int iAttachmentPoint , Vector vecOriginOffset , matrix3x4_t * matOffset )
{
CParticleSystemDefinition * pDef = g_pParticleSystemMgr - > FindPrecachedParticleSystem ( nPrecacheIndex ) ;
if ( ! pDef )
{
AssertMsg ( 0 , " Attempting to create unknown particle system " ) ;
return NULL ;
}
return Create ( pDef , iAttachType , iAttachmentPoint , vecOriginOffset , matOffset ) ;
}
CNewParticleEffect * CParticleProperty : : Create ( const char * pszParticleName , ParticleAttachment_t iAttachType , int iAttachmentPoint , Vector vecOriginOffset , matrix3x4_t * matOffset )
{
CParticleSystemDefinition * pDef = g_pParticleSystemMgr - > FindParticleSystem ( pszParticleName ) ;
if ( ! pDef )
{
AssertMsg ( 0 , " Attempting to create unknown particle system " ) ;
Warning ( " Attempting to create unknown particle system '%s' \n " , pszParticleName ) ;
return NULL ;
}
return Create ( pDef , iAttachType , iAttachmentPoint , vecOriginOffset , matOffset ) ;
}
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
void CParticleProperty : : AddControlPoint ( CNewParticleEffect * pEffect , int iPoint , C_BaseEntity * pEntity , ParticleAttachment_t iAttachType , const char * pszAttachmentName , Vector vecOriginOffset , matrix3x4_t * matOffset )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
int iAttachment = - 1 ;
2020-04-22 16:56:21 +00:00
if ( pszAttachmentName )
{
iAttachment = GetParticleAttachment ( pEntity , pszAttachmentName , pEffect - > GetEffectName ( ) ) ;
}
for ( int i = 0 ; i < m_ParticleEffects . Count ( ) ; i + + )
{
if ( m_ParticleEffects [ i ] . pParticleEffect = = pEffect )
{
2023-10-03 14:23:56 +00:00
AddControlPoint ( i , iPoint , pEntity , iAttachType , iAttachment , vecOriginOffset , matOffset ) ;
2020-04-22 16:56:21 +00:00
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
void CParticleProperty : : AddControlPoint ( int iEffectIndex , int iPoint , C_BaseEntity * pEntity , ParticleAttachment_t iAttachType , int iAttachmentPoint , Vector vecOriginOffset , matrix3x4_t * matOffset )
2020-04-22 16:56:21 +00:00
{
Assert ( iEffectIndex > = 0 & & iEffectIndex < m_ParticleEffects . Count ( ) ) ;
ParticleEffectList_t * pEffect = & m_ParticleEffects [ iEffectIndex ] ;
Assert ( pEffect - > pControlPoints . Count ( ) < MAX_PARTICLE_CONTROL_POINTS ) ;
2023-10-03 14:23:56 +00:00
int iIndex = pEffect - > pControlPoints . AddToTail ( ) ;
ParticleControlPoint_t * pNewPoint = & pEffect - > pControlPoints [ iIndex ] ;
2020-04-22 16:56:21 +00:00
pNewPoint - > iControlPoint = iPoint ;
pNewPoint - > hEntity = pEntity ;
pNewPoint - > iAttachType = iAttachType ;
pNewPoint - > iAttachmentPoint = iAttachmentPoint ;
pNewPoint - > vecOriginOffset = vecOriginOffset ;
2023-10-03 14:23:56 +00:00
if ( matOffset )
pNewPoint - > matOffset = * matOffset ;
else
pNewPoint - > matOffset . Init ( Vector ( 1 , 0 , 0 ) , Vector ( 0 , 1 , 0 ) , Vector ( 0 , 0 , 1 ) , Vector ( 0 , 0 , 0 ) ) ;
2020-04-22 16:56:21 +00:00
UpdateParticleEffect ( pEffect , true , iIndex ) ;
}
//-----------------------------------------------------------------------------
// Used to replace a particle effect with a different one; attaches the control point updating to the new one
//-----------------------------------------------------------------------------
void CParticleProperty : : ReplaceParticleEffect ( CNewParticleEffect * pOldEffect , CNewParticleEffect * pNewEffect )
{
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
if ( pOldEffect ! = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) )
continue ;
m_ParticleEffects [ i ] . pParticleEffect = pNewEffect ;
UpdateParticleEffect ( & m_ParticleEffects [ i ] , true ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the parent of a given control point to the index of some other
// control point.
//-----------------------------------------------------------------------------
void CParticleProperty : : SetControlPointParent ( int iEffectIndex , int whichControlPoint , int parentIdx )
{
}
//-----------------------------------------------------------------------------
// Purpose: Stop effects from emitting more particles. If no effect is
// specified, all effects attached to this entity are stopped.
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
void CParticleProperty : : StopEmission ( CNewParticleEffect * pEffect , bool bWakeOnStop , bool bDestroyAsleepSystems , bool bForceRemoveInstantly , bool bPlayEndCap )
2020-04-22 16:56:21 +00:00
{
// If we return from dormancy and are then told to stop emitting,
// we should have died while dormant. Remove ourselves immediately.
bool bRemoveInstantly = ( m_iDormancyChangedAtFrame = = gpGlobals - > framecount ) ;
2023-10-03 14:23:56 +00:00
// force remove particles instantly if caller specified
bRemoveInstantly | = bForceRemoveInstantly ;
2020-04-22 16:56:21 +00:00
if ( pEffect )
{
if ( FindEffect ( pEffect ) ! = - 1 )
{
2023-10-03 14:23:56 +00:00
pEffect - > StopEmission ( false , bRemoveInstantly , bWakeOnStop , bPlayEndCap ) ;
2020-04-22 16:56:21 +00:00
}
}
else
{
// Stop all effects
float flNow = g_pParticleSystemMgr - > GetLastSimulationTime ( ) ;
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = nCount - 1 ; i > = 0 ; i - - )
{
CNewParticleEffect * pTmp = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) ;
bool bRemoveSystem = bRemoveInstantly | | ( bDestroyAsleepSystems & & ( flNow > = pTmp - > m_flNextSleepTime ) ) ;
if ( bRemoveSystem )
{
m_ParticleEffects . Remove ( i ) ;
pTmp - > SetOwner ( NULL ) ;
}
2023-10-03 14:23:56 +00:00
pTmp - > StopEmission ( false , bRemoveSystem , ! bRemoveSystem & & bWakeOnStop , bPlayEndCap ) ;
2020-04-22 16:56:21 +00:00
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Remove effects immediately, including all current particles. If no
// effect is specified, all effects attached to this entity are removed.
//-----------------------------------------------------------------------------
void CParticleProperty : : StopEmissionAndDestroyImmediately ( CNewParticleEffect * pEffect )
{
if ( pEffect )
{
int iIndex = FindEffect ( pEffect ) ;
2023-10-03 14:23:56 +00:00
Assert ( iIndex ! = - 1 ) ;
2020-04-22 16:56:21 +00:00
if ( iIndex ! = - 1 )
{
m_ParticleEffects . Remove ( iIndex ) ;
// Clear the owner so it doesn't try to call back to us on deletion
pEffect - > SetOwner ( NULL ) ;
pEffect - > StopEmission ( false , true ) ;
}
}
else
{
// Immediately destroy all effects
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = nCount - 1 ; i > = 0 ; i - - )
{
CNewParticleEffect * pTmp = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) ;
m_ParticleEffects . Remove ( i ) ;
// Clear the owner so it doesn't try to call back to us on deletion
pTmp - > SetOwner ( NULL ) ;
pTmp - > StopEmission ( false , true ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Stop all effects that have a control point associated with the given
// entity.
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
void CParticleProperty : : StopParticlesInvolving ( CBaseEntity * pEntity , bool bForceRemoveInstantly /* =false */ )
2020-04-22 16:56:21 +00:00
{
Assert ( pEntity ) ;
EHANDLE entHandle ( pEntity ) ;
// If we return from dormancy and are then told to stop emitting,
// we should have died while dormant. Remove ourselves immediately.
bool bRemoveInstantly = ( m_iDormancyChangedAtFrame = = gpGlobals - > framecount ) ;
2023-10-03 14:23:56 +00:00
// force remove particles instantly if caller specified
bRemoveInstantly | = bForceRemoveInstantly ;
2020-04-22 16:56:21 +00:00
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
// for each effect...
ParticleEffectList_t & part = m_ParticleEffects [ i ] ;
// look through all the control points to see if any mention the given object
int cpCount = part . pControlPoints . Count ( ) ;
for ( int j = 0 ; j < cpCount ; + + j )
{
// if any control points respond to the given handle...
if ( part . pControlPoints [ j ] . hEntity = = entHandle )
{
part . pParticleEffect - > StopEmission ( false , bRemoveInstantly ) ;
break ; // break out of the inner loop (to where it says BREAK TO HERE)
}
}
// BREAK TO HERE
}
}
//-----------------------------------------------------------------------------
// Purpose: Stop all effects that were created using the given definition
// name.
//-----------------------------------------------------------------------------
2023-10-03 14:23:56 +00:00
void CParticleProperty : : StopParticlesNamed ( const char * pszEffectName , bool bForceRemoveInstantly /* =false */ , int nSplitScreenPlayerSlot /*= -1*/ )
2020-04-22 16:56:21 +00:00
{
CParticleSystemDefinition * pDef = g_pParticleSystemMgr - > FindParticleSystem ( pszEffectName ) ;
AssertMsg1 ( pDef , " Could not find particle definition %s " , pszEffectName ) ;
if ( ! pDef )
return ;
// If we return from dormancy and are then told to stop emitting,
// we should have died while dormant. Remove ourselves immediately.
bool bRemoveInstantly = ( m_iDormancyChangedAtFrame = = gpGlobals - > framecount ) ;
// force remove particles instantly if caller specified
bRemoveInstantly | = bForceRemoveInstantly ;
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
// for each effect...
CNewParticleEffect * pParticleEffect = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) ;
2022-03-01 20:00:42 +00:00
if ( pParticleEffect - > m_pDef ( ) = = pDef )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( nSplitScreenPlayerSlot ! = - 1 )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
if ( ! pParticleEffect - > ShouldDrawForSplitScreenUser ( nSplitScreenPlayerSlot ) )
continue ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
pParticleEffect - > StopEmission ( false , bRemoveInstantly ) ;
2020-04-22 16:56:21 +00:00
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CParticleProperty : : OnParticleSystemUpdated ( CNewParticleEffect * pEffect , float flTimeDelta )
{
int iIndex = FindEffect ( pEffect ) ;
Assert ( iIndex ! = - 1 ) ;
if ( iIndex = = - 1 )
return ;
UpdateParticleEffect ( & m_ParticleEffects [ iIndex ] ) ;
/*
// Display the bounding box of the particle effect
Vector vecMins , vecMaxs ;
pEffect - > GetRenderBounds ( vecMins , vecMaxs ) ;
debugoverlay - > AddBoxOverlay ( pEffect - > GetRenderOrigin ( ) , vecMins , vecMaxs , QAngle ( 0 , 0 , 0 ) , 0 , 255 , 255 , 0 , 0 ) ;
*/
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CParticleProperty : : OnParticleSystemDeleted ( CNewParticleEffect * pEffect )
{
int iIndex = FindEffect ( pEffect ) ;
if ( iIndex = = - 1 )
return ;
2023-10-03 14:23:56 +00:00
if ( m_pOuter )
{
m_pOuter - > OnParticleEffectDeleted ( pEffect ) ;
}
2020-04-22 16:56:21 +00:00
m_ParticleEffects [ iIndex ] . pParticleEffect . MarkDeleted ( ) ;
m_ParticleEffects . Remove ( iIndex ) ;
}
# ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: The entity we're attached to has change dormancy state on our client
//-----------------------------------------------------------------------------
void CParticleProperty : : OwnerSetDormantTo ( bool bDormant )
{
m_iDormancyChangedAtFrame = gpGlobals - > framecount ;
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; i + + )
{
//m_ParticleEffects[i].pParticleEffect->SetShouldSimulate( !bDormant );
m_ParticleEffects [ i ] . pParticleEffect - > SetDormant ( bDormant ) ;
}
}
# endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CParticleProperty : : FindEffect ( CNewParticleEffect * pEffect )
{
for ( int i = 0 ; i < m_ParticleEffects . Count ( ) ; i + + )
{
if ( m_ParticleEffects [ i ] . pParticleEffect = = pEffect )
return i ;
}
return - 1 ;
}
2023-10-03 14:23:56 +00:00
int CParticleProperty : : FindEffect ( const char * pEffectName )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
for ( int i = 0 ; i < m_ParticleEffects . Count ( ) ; i + + )
2020-04-22 16:56:21 +00:00
{
if ( ! Q_stricmp ( m_ParticleEffects [ i ] . pParticleEffect - > GetName ( ) , pEffectName ) )
return i ;
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CParticleProperty : : UpdateParticleEffect ( ParticleEffectList_t * pEffect , bool bInitializing , int iOnlyThisControlPoint )
{
if ( iOnlyThisControlPoint ! = - 1 )
{
UpdateControlPoint ( pEffect , iOnlyThisControlPoint , bInitializing ) ;
return ;
}
// Loop through our control points and update them all
for ( int i = 0 ; i < pEffect - > pControlPoints . Count ( ) ; i + + )
{
UpdateControlPoint ( pEffect , i , bInitializing ) ;
}
}
2023-10-03 14:23:56 +00:00
extern void FormatViewModelAttachment ( C_BasePlayer * pPlayer , Vector & vOrigin , bool bInverse ) ;
2020-04-22 16:56:21 +00:00
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CParticleProperty : : UpdateControlPoint ( ParticleEffectList_t * pEffect , int iPoint , bool bInitializing )
{
2023-10-03 14:23:56 +00:00
2020-04-22 16:56:21 +00:00
ParticleControlPoint_t * pPoint = & pEffect - > pControlPoints [ iPoint ] ;
2023-10-03 14:23:56 +00:00
if ( pEffect - > pParticleEffect - > m_pDef - > IsScreenSpaceEffect ( ) & & iPoint = = 0 )
{
pEffect - > pParticleEffect - > SetControlPointOrientation ( pPoint - > iControlPoint , Vector ( 1 , 0 , 0 ) , Vector ( 0 , 1 , 0 ) , Vector ( 0 , 0 , 1 ) ) ;
pEffect - > pParticleEffect - > SetControlPoint ( pPoint - > iControlPoint , vec3_origin ) ;
return ;
}
2020-04-22 16:56:21 +00:00
if ( ! pPoint - > hEntity . Get ( ) )
{
if ( pPoint - > iAttachType = = PATTACH_WORLDORIGIN & & bInitializing )
{
pEffect - > pParticleEffect - > SetControlPointOrientation ( pPoint - > iControlPoint , Vector ( 1 , 0 , 0 ) , Vector ( 0 , 1 , 0 ) , Vector ( 0 , 0 , 1 ) ) ;
pEffect - > pParticleEffect - > SetControlPoint ( pPoint - > iControlPoint , pPoint - > vecOriginOffset ) ;
pEffect - > pParticleEffect - > SetSortOrigin ( pPoint - > vecOriginOffset ) ;
}
pEffect - > pParticleEffect - > SetControlPointEntity ( pPoint - > iControlPoint , NULL ) ;
return ;
}
// Only update non-follow particles when we're initializing,
2023-10-03 14:23:56 +00:00
if ( ! bInitializing & & ( pPoint - > iAttachType = = PATTACH_ABSORIGIN | | pPoint - > iAttachType = = PATTACH_POINT ) )
2020-04-22 16:56:21 +00:00
return ;
if ( pPoint - > iAttachType = = PATTACH_CUSTOMORIGIN )
return ;
Vector vecOrigin , vecForward , vecRight , vecUp ;
2023-10-03 14:23:56 +00:00
switch ( pPoint - > iAttachType )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
case PATTACH_POINT :
case PATTACH_POINT_FOLLOW :
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
C_BaseAnimating * pAnimating = pPoint - > hEntity - > GetBaseAnimating ( ) ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
bool bValid = false ;
Assert ( pAnimating ) ;
if ( pAnimating )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
matrix3x4_t attachmentToWorld ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
if ( pAnimating - > IsViewModel ( ) )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
C_BasePlayer * pPlayer = ToBasePlayer ( ( ( C_BaseViewModel * ) pAnimating ) - > GetOwner ( ) ) ;
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( C_BasePlayer : : GetSplitScreenSlotForPlayer ( pPlayer ) ) ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
if ( pAnimating - > GetAttachment ( pPoint - > iAttachmentPoint , attachmentToWorld ) )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
bValid = true ;
MatrixVectors ( attachmentToWorld , & vecForward , & vecRight , & vecUp ) ;
MatrixPosition ( attachmentToWorld , vecOrigin ) ;
if ( pEffect - > pParticleEffect - > m_pDef - > IsViewModelEffect ( ) )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
FormatViewModelAttachment ( pPlayer , vecOrigin , true ) ;
2020-04-22 16:56:21 +00:00
}
}
2023-10-03 14:23:56 +00:00
}
else
{
// HACK_GETLOCALPLAYER_GUARD( "CParticleProperty::UpdateControlPoint" );
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
if ( pAnimating - > GetAttachment ( pPoint - > iAttachmentPoint , attachmentToWorld ) )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
bValid = true ;
MatrixVectors ( attachmentToWorld , & vecForward , & vecRight , & vecUp ) ;
# ifdef _DEBUG
float flTests [ 3 ] = { vecForward . Dot ( vecRight ) , vecRight . Dot ( vecUp ) , vecUp . Dot ( vecForward ) } ;
static float s_flMaxTest = 0.001f ;
Assert ( fabs ( flTests [ 0 ] ) + fabs ( flTests [ 1 ] ) + fabs ( flTests [ 2 ] ) < s_flMaxTest ) ;
# endif
MatrixPosition ( attachmentToWorld , vecOrigin ) ;
if ( pEffect - > pParticleEffect - > m_pDef - > IsViewModelEffect ( ) )
{
HACK_GETLOCALPLAYER_GUARD ( " CParticleProperty::UpdateControlPoint " ) ;
FormatViewModelAttachment ( NULL , vecOrigin , true ) ;
}
2020-04-22 16:56:21 +00:00
}
}
}
2023-10-03 14:23:56 +00:00
if ( ! bValid )
{
static bool bWarned = false ;
if ( ! bWarned )
{
bWarned = true ;
DevWarning ( " Attempted to attach particle effect %s to an unknown attachment on entity %s \n " ,
pEffect - > pParticleEffect - > m_pDef - > GetName ( ) , pAnimating - > GetClassname ( ) ) ;
}
}
if ( ! bValid )
2020-04-22 16:56:21 +00:00
{
2023-10-03 14:23:56 +00:00
AssertOnce ( 0 ) ;
return ;
2020-04-22 16:56:21 +00:00
}
2023-10-03 14:23:56 +00:00
}
break ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
case PATTACH_ABSORIGIN :
case PATTACH_ABSORIGIN_FOLLOW :
default :
{
vecOrigin = pPoint - > hEntity - > GetAbsOrigin ( ) + pPoint - > vecOriginOffset ;
pPoint - > hEntity - > GetVectors ( & vecForward , & vecRight , & vecUp ) ;
}
break ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
case PATTACH_EYES_FOLLOW :
{
C_BaseEntity * pEnt = pPoint - > hEntity ;
if ( ! pEnt - > IsPlayer ( ) )
return ;
C_BasePlayer * pPlayer = assert_cast < C_BasePlayer * > ( pEnt ) ;
bool bValid = false ;
Assert ( pPlayer ) ;
if ( pPlayer )
{
bValid = true ;
vecOrigin = pPlayer - > EyePosition ( ) + pPoint - > vecOriginOffset ;
pPlayer - > EyeVectors ( & vecForward , & vecRight , & vecUp ) ;
}
if ( ! bValid )
{
AssertOnce ( 0 ) ;
return ;
2020-04-22 16:56:21 +00:00
}
}
2023-10-03 14:23:56 +00:00
break ;
2020-04-22 16:56:21 +00:00
2023-10-03 14:23:56 +00:00
case PATTACH_CUSTOMORIGIN_FOLLOW :
{
matrix3x4_t mat ;
MatrixMultiply ( pPoint - > hEntity - > RenderableToWorldTransform ( ) , pPoint - > matOffset , mat ) ;
MatrixVectors ( mat , & vecForward , & vecRight , & vecUp ) ;
vecOrigin = pPoint - > hEntity - > GetAbsOrigin ( ) + pPoint - > vecOriginOffset ;
}
break ;
}
2020-04-22 16:56:21 +00:00
pEffect - > pParticleEffect - > SetControlPointOrientation ( pPoint - > iControlPoint , vecForward , vecRight , vecUp ) ;
pEffect - > pParticleEffect - > SetControlPointEntity ( pPoint - > iControlPoint , pPoint - > hEntity ) ;
2023-10-03 14:23:56 +00:00
pEffect - > pParticleEffect - > SetControlPoint ( pPoint - > iControlPoint , vecOrigin ) ;
pEffect - > pParticleEffect - > SetSortOrigin ( vecOrigin ) ;
2020-04-22 16:56:21 +00:00
}
//-----------------------------------------------------------------------------
// Purpose: Output all active effects
//-----------------------------------------------------------------------------
void CParticleProperty : : DebugPrintEffects ( void )
{
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
// for each effect...
CNewParticleEffect * pParticleEffect = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) ;
if ( ! pParticleEffect )
continue ;
Msg ( " (%d) EffectName \" %s \" Dormant? %s Emission Stopped? %s \n " ,
i ,
pParticleEffect - > GetEffectName ( ) ,
( pParticleEffect - > m_bDormant ) ? " yes " : " no " ,
( pParticleEffect - > m_bEmissionStopped ) ? " yes " : " no " ) ;
}
}
2023-10-03 14:23:56 +00:00
bool CParticleProperty : : IsValidEffect ( const CNewParticleEffect * pEffect )
{
if ( pEffect = = NULL )
return false ;
int nCount = m_ParticleEffects . Count ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
if ( pEffect = = m_ParticleEffects [ i ] . pParticleEffect . GetObject ( ) )
return true ;
}
return false ;
}