Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New entity: info_particle_system_coordinate, plus infinite cooldown functionality for prop_interactable #193

Merged
merged 4 commits into from
Oct 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 114 additions & 96 deletions sp/src/game/client/c_particle_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
//-----------------------------------------------------------------------------
class C_ParticleSystem : public C_BaseEntity
{
DECLARE_CLASS( C_ParticleSystem, C_BaseEntity );
DECLARE_CLASS(C_ParticleSystem, C_BaseEntity);
public:
DECLARE_CLIENTCLASS();

C_ParticleSystem();

void PreDataUpdate( DataUpdateType_t updateType );
void PostDataUpdate( DataUpdateType_t updateType );
void ClientThink( void );
void PreDataUpdate(DataUpdateType_t updateType);
void PostDataUpdate(DataUpdateType_t updateType);
void ClientThink(void);

protected:
int m_iEffectIndex;
Expand All @@ -40,8 +40,9 @@ class C_ParticleSystem : public C_BaseEntity

enum { kMAXCONTROLPOINTS = 63 }; ///< actually one less than the total number of cpoints since 0 is assumed to be me


EHANDLE m_hControlPointEnts[kMAXCONTROLPOINTS];
Vector m_vControlPointVecs[kMAXCONTROLPOINTS];
// SendPropArray3( SENDINFO_ARRAY3(m_iControlPointParents), SendPropInt( SENDINFO_ARRAY(m_iControlPointParents), 3, SPROP_UNSIGNED ) ),
unsigned char m_iControlPointParents[kMAXCONTROLPOINTS];

Expand All @@ -50,23 +51,24 @@ class C_ParticleSystem : public C_BaseEntity

IMPLEMENT_CLIENTCLASS(C_ParticleSystem, DT_ParticleSystem, CParticleSystem);

BEGIN_RECV_TABLE_NOBASE( C_ParticleSystem, DT_ParticleSystem )
RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
RecvPropEHandle( RECVINFO(m_hOwnerEntity) ),
RecvPropInt( RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent ),
RecvPropInt( RECVINFO( m_iParentAttachment ) ),
RecvPropQAngles( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ),
BEGIN_RECV_TABLE_NOBASE(C_ParticleSystem, DT_ParticleSystem)
RecvPropVector(RECVINFO_NAME(m_vecNetworkOrigin, m_vecOrigin)),
RecvPropEHandle(RECVINFO(m_hOwnerEntity)),
RecvPropInt(RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent),
RecvPropInt(RECVINFO(m_iParentAttachment)),
RecvPropQAngles(RECVINFO_NAME(m_angNetworkAngles, m_angRotation)),

RecvPropInt( RECVINFO( m_iEffectIndex ) ),
RecvPropBool( RECVINFO( m_bActive ) ),
RecvPropInt(RECVINFO(m_iEffectIndex)),
RecvPropBool(RECVINFO(m_bActive)),
#ifdef MAPBASE
RecvPropBool( RECVINFO( m_bDestroyImmediately ) ),
RecvPropBool(RECVINFO(m_bDestroyImmediately)),
#endif
RecvPropFloat( RECVINFO( m_flStartTime ) ),
RecvPropFloat(RECVINFO(m_flStartTime)),

RecvPropArray3( RECVINFO_ARRAY(m_hControlPointEnts), RecvPropEHandle( RECVINFO( m_hControlPointEnts[0] ) ) ),
RecvPropArray3( RECVINFO_ARRAY(m_iControlPointParents), RecvPropInt( RECVINFO(m_iControlPointParents[0]))),
RecvPropBool( RECVINFO( m_bWeatherEffect ) ),
RecvPropArray3(RECVINFO_ARRAY(m_hControlPointEnts), RecvPropEHandle(RECVINFO(m_hControlPointEnts[0]))),
RecvPropArray3(RECVINFO_ARRAY(m_vControlPointVecs), RecvPropVector(RECVINFO(m_vControlPointVecs[0]))),
RecvPropArray3(RECVINFO_ARRAY(m_iControlPointParents), RecvPropInt(RECVINFO(m_iControlPointParents[0]))),
RecvPropBool(RECVINFO(m_bWeatherEffect)),
END_RECV_TABLE();

//-----------------------------------------------------------------------------
Expand All @@ -80,38 +82,38 @@ C_ParticleSystem::C_ParticleSystem()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ParticleSystem::PreDataUpdate( DataUpdateType_t updateType )
void C_ParticleSystem::PreDataUpdate(DataUpdateType_t updateType)
{
m_bOldActive = m_bActive;

BaseClass::PreDataUpdate( updateType );
BaseClass::PreDataUpdate(updateType);
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType )
void C_ParticleSystem::PostDataUpdate(DataUpdateType_t updateType)
{
BaseClass::PostDataUpdate( updateType );
BaseClass::PostDataUpdate(updateType);

// Always restart if just created and updated
// FIXME: Does this play fairly with PVS?
if ( updateType == DATA_UPDATE_CREATED )
if (updateType == DATA_UPDATE_CREATED)
{
if ( m_bActive )
if (m_bActive)
{
// Delayed here so that we don't get invalid abs queries on level init with active particle systems
SetNextClientThink( gpGlobals->curtime );
SetNextClientThink(gpGlobals->curtime);
}
}
else
{
if ( m_bOldActive != m_bActive )
if (m_bOldActive != m_bActive)
{
if ( m_bActive )
if (m_bActive)
{
// Delayed here so that we don't get invalid abs queries on level init with active particle systems
SetNextClientThink( gpGlobals->curtime );
SetNextClientThink(gpGlobals->curtime);
}
else
#ifdef MAPBASE
Expand All @@ -123,8 +125,8 @@ void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType )
}
#else
{
ParticleProp()->StopEmission();
}
ParticleProp()->StopEmission();
}
#endif
}
}
Expand All @@ -133,53 +135,69 @@ void C_ParticleSystem::PostDataUpdate( DataUpdateType_t updateType )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ParticleSystem::ClientThink( void )
void C_ParticleSystem::ClientThink(void)
{
if ( m_bActive )
if (m_bActive)
{
const char *pszName = GetParticleSystemNameFromIndex( m_iEffectIndex );
if ( pszName && pszName[0] )
const char *pszName = GetParticleSystemNameFromIndex(m_iEffectIndex);
if (pszName && pszName[0])
{
if ( !GameRules()->AllowMapParticleEffect( pszName ) )
if (!GameRules()->AllowMapParticleEffect(pszName))
return;

if ( m_bWeatherEffect && !GameRules()->AllowWeatherParticles() )
if (m_bWeatherEffect && !GameRules()->AllowWeatherParticles())
return;

CNewParticleEffect *pEffect = ParticleProp()->Create( pszName, PATTACH_ABSORIGIN_FOLLOW );
AssertMsg1( pEffect, "Particle system couldn't make %s", pszName );
CNewParticleEffect *pEffect = ParticleProp()->Create(pszName, PATTACH_ABSORIGIN_FOLLOW);
AssertMsg1(pEffect, "Particle system couldn't make %s", pszName);
if (pEffect)
{
for ( int i = 0 ; i < kMAXCONTROLPOINTS ; ++i )
{
CBaseEntity *pOnEntity = m_hControlPointEnts[i].Get();
if ( pOnEntity )
if (m_vControlPointVecs[0] != GetAbsOrigin() && m_hControlPointEnts[0] == NULL){
// we are using info_particle_system_coordinate
for (int i = 0; i < kMAXCONTROLPOINTS; ++i)
{
ParticleProp()->AddControlPoint( pEffect, i + 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW );
ParticleProp()->AddControlPoint(pEffect, i + 1, this, PATTACH_WORLDORIGIN, 0, m_vControlPointVecs[i] - GetAbsOrigin());
AssertMsg2(m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS,
"Particle system specified bogus control point parent (%d) for point %d.",
m_iControlPointParents[i], i);

if (m_iControlPointParents[i] != 0)
{
pEffect->SetControlPointParent(i + 1, m_iControlPointParents[i]);
}
}

AssertMsg2( m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS ,
"Particle system specified bogus control point parent (%d) for point %d.",
m_iControlPointParents[i], i );

if (m_iControlPointParents[i] != 0)
}
else{
for (int i = 0; i < kMAXCONTROLPOINTS; ++i)
{
pEffect->SetControlPointParent(i+1, m_iControlPointParents[i]);
CBaseEntity* pOnEntity = m_hControlPointEnts[i].Get();
if (pOnEntity)
{
ParticleProp()->AddControlPoint(pEffect, i + 1, pOnEntity, PATTACH_ABSORIGIN_FOLLOW);
}
AssertMsg2(m_iControlPointParents[i] >= 0 && m_iControlPointParents[i] <= kMAXCONTROLPOINTS,
"Particle system specified bogus control point parent (%d) for point %d.",
m_iControlPointParents[i], i);

if (m_iControlPointParents[i] != 0)
{
pEffect->SetControlPointParent(i + 1, m_iControlPointParents[i]);
}
}
}

// NOTE: What we really want here is to compare our lifetime and that of our children and see if this delta is
// already past the end of it, denoting that we're finished. In that case, just destroy us and be done. -- jdw

// TODO: This can go when the SkipToTime code below goes
ParticleProp()->OnParticleSystemUpdated( pEffect, 0.0f );
ParticleProp()->OnParticleSystemUpdated(pEffect, 0.0f);

// Skip the effect ahead if we're restarting it
float flTimeDelta = gpGlobals->curtime - m_flStartTime;
if ( flTimeDelta > 0.01f )
if (flTimeDelta > 0.01f)
{
VPROF_BUDGET( "C_ParticleSystem::ClientThink SkipToTime", "Particle Simulation" );
pEffect->SkipToTime( flTimeDelta );
VPROF_BUDGET("C_ParticleSystem::ClientThink SkipToTime", "Particle Simulation");
pEffect->SkipToTime(flTimeDelta);
}
}
}
Expand All @@ -193,79 +211,79 @@ void C_ParticleSystem::ClientThink( void )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void ParticleEffectCallback( const CEffectData &data )
void ParticleEffectCallback(const CEffectData &data)
{
if ( SuppressingParticleEffects() )
if (SuppressingParticleEffects())
return; // this needs to be before using data.m_nHitBox, since that may be a serialized value that's past the end of the current particle system string table

const char *pszName = GetParticleSystemNameFromIndex( data.m_nHitBox );
const char *pszName = GetParticleSystemNameFromIndex(data.m_nHitBox);

CSmartPtr<CNewParticleEffect> pEffect = NULL;
if ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY )
if (data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY)
{
if ( data.m_hEntity.Get() )
if (data.m_hEntity.Get())
{
C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity );
if ( pEnt && !pEnt->IsDormant() )
C_BaseEntity *pEnt = C_BaseEntity::Instance(data.m_hEntity);
if (pEnt && !pEnt->IsDormant())
{
if ( data.m_fFlags & PARTICLE_DISPATCH_RESET_PARTICLES )
if (data.m_fFlags & PARTICLE_DISPATCH_RESET_PARTICLES)
{
pEnt->ParticleProp()->StopEmission();
}

pEffect = pEnt->ParticleProp()->Create( pszName, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex );
AssertMsg2( pEffect.IsValid() && pEffect->IsValid(), "%s could not create particle effect %s",
C_BaseEntity::Instance( data.m_hEntity )->GetDebugName(), pszName );
if ( pEffect.IsValid() && pEffect->IsValid() )
pEffect = pEnt->ParticleProp()->Create(pszName, (ParticleAttachment_t)data.m_nDamageType, data.m_nAttachmentIndex);
AssertMsg2(pEffect.IsValid() && pEffect->IsValid(), "%s could not create particle effect %s",
C_BaseEntity::Instance(data.m_hEntity)->GetDebugName(), pszName);
if (pEffect.IsValid() && pEffect->IsValid())
{
if ( (ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN )
if ((ParticleAttachment_t)data.m_nDamageType == PATTACH_CUSTOMORIGIN)
{
pEffect->SetSortOrigin( data.m_vOrigin );
pEffect->SetControlPoint( 0, data.m_vOrigin );
pEffect->SetControlPoint( 1, data.m_vStart );
pEffect->SetSortOrigin(data.m_vOrigin);
pEffect->SetControlPoint(0, data.m_vOrigin);
pEffect->SetControlPoint(1, data.m_vStart);
Vector vecForward, vecRight, vecUp;
AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
AngleVectors(data.m_vAngles, &vecForward, &vecRight, &vecUp);
pEffect->SetControlPointOrientation(0, vecForward, vecRight, vecUp);
}
}
}
}
}
}
else
{
if ( GameRules() )
if (GameRules())
{
pszName = GameRules()->TranslateEffectForVisionFilter( "particles", pszName );
pszName = GameRules()->TranslateEffectForVisionFilter("particles", pszName);
}

pEffect = CNewParticleEffect::Create( NULL, pszName );
if ( pEffect->IsValid() )
pEffect = CNewParticleEffect::Create(NULL, pszName);
if (pEffect->IsValid())
{
pEffect->SetSortOrigin( data.m_vOrigin );
pEffect->SetControlPoint( 0, data.m_vOrigin );
pEffect->SetControlPoint( 1, data.m_vStart );
pEffect->SetSortOrigin(data.m_vOrigin);
pEffect->SetControlPoint(0, data.m_vOrigin);
pEffect->SetControlPoint(1, data.m_vStart);
Vector vecForward, vecRight, vecUp;
AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
AngleVectors(data.m_vAngles, &vecForward, &vecRight, &vecUp);
pEffect->SetControlPointOrientation(0, vecForward, vecRight, vecUp);
}
}

if ( pEffect.IsValid() && pEffect->IsValid() )
if (pEffect.IsValid() && pEffect->IsValid())
{
if ( data.m_bCustomColors )
if (data.m_bCustomColors)
{
pEffect->SetControlPoint( CUSTOM_COLOR_CP1, data.m_CustomColors.m_vecColor1 );
pEffect->SetControlPoint( CUSTOM_COLOR_CP2, data.m_CustomColors.m_vecColor2 );
pEffect->SetControlPoint(CUSTOM_COLOR_CP1, data.m_CustomColors.m_vecColor1);
pEffect->SetControlPoint(CUSTOM_COLOR_CP2, data.m_CustomColors.m_vecColor2);
}

if ( data.m_bControlPoint1 )
if (data.m_bControlPoint1)
{
pEffect->SetControlPoint( 1, data.m_ControlPoint1.m_vecOffset );
pEffect->SetControlPoint(1, data.m_ControlPoint1.m_vecOffset);
}
}
}

DECLARE_CLIENT_EFFECT( "ParticleEffect", ParticleEffectCallback );
DECLARE_CLIENT_EFFECT("ParticleEffect", ParticleEffectCallback);


//======================================================================================================================
Expand All @@ -274,16 +292,16 @@ DECLARE_CLIENT_EFFECT( "ParticleEffect", ParticleEffectCallback );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void ParticleEffectStopCallback( const CEffectData &data )
void ParticleEffectStopCallback(const CEffectData &data)
{
if ( data.m_hEntity.Get() )
if (data.m_hEntity.Get())
{
C_BaseEntity *pEnt = C_BaseEntity::Instance( data.m_hEntity );
if ( pEnt )
C_BaseEntity *pEnt = C_BaseEntity::Instance(data.m_hEntity);
if (pEnt)
{
pEnt->ParticleProp()->StopEmission();
}
pEnt->ParticleProp()->StopEmission();
}
}
}

DECLARE_CLIENT_EFFECT( "ParticleEffectStop", ParticleEffectStopCallback );
DECLARE_CLIENT_EFFECT("ParticleEffectStop", ParticleEffectStopCallback);
Loading