From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/client/c_entitydissolve.cpp | 792 ++++++++++++++++++++++++++++++++ 1 file changed, 792 insertions(+) create mode 100644 mp/src/game/client/c_entitydissolve.cpp (limited to 'mp/src/game/client/c_entitydissolve.cpp') diff --git a/mp/src/game/client/c_entitydissolve.cpp b/mp/src/game/client/c_entitydissolve.cpp new file mode 100644 index 00000000..d8e12616 --- /dev/null +++ b/mp/src/game/client/c_entitydissolve.cpp @@ -0,0 +1,792 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "iviewrender.h" +#include "view.h" +#include "studio.h" +#include "bone_setup.h" +#include "model_types.h" +#include "beamdraw.h" +#include "engine/ivdebugoverlay.h" +#include "iviewrender_beams.h" +#include "fx.h" +#include "IEffects.h" +#include "c_entitydissolve.h" +#include "movevars_shared.h" +#include "clienteffectprecachesystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectBuild ) +CLIENTEFFECT_MATERIAL( "effects/tesla_glow_noz" ) +CLIENTEFFECT_MATERIAL( "effects/spark" ) +CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Networking +//----------------------------------------------------------------------------- +IMPLEMENT_CLIENTCLASS_DT( C_EntityDissolve, DT_EntityDissolve, CEntityDissolve ) + RecvPropTime(RECVINFO(m_flStartTime)), + RecvPropFloat(RECVINFO(m_flFadeOutStart)), + RecvPropFloat(RECVINFO(m_flFadeOutLength)), + RecvPropFloat(RECVINFO(m_flFadeOutModelStart)), + RecvPropFloat(RECVINFO(m_flFadeOutModelLength)), + RecvPropFloat(RECVINFO(m_flFadeInStart)), + RecvPropFloat(RECVINFO(m_flFadeInLength)), + RecvPropInt(RECVINFO(m_nDissolveType)), + RecvPropVector( RECVINFO( m_vDissolverOrigin) ), + RecvPropInt( RECVINFO( m_nMagnitude ) ), +END_RECV_TABLE() + +extern PMaterialHandle g_Material_Spark; +PMaterialHandle g_Material_AR2Glow = NULL; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_EntityDissolve::C_EntityDissolve( void ) +{ + m_bLinkedToServerEnt = true; + m_pController = NULL; + m_bCoreExplode = false; + m_vEffectColor = Vector( 255, 255, 255 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityDissolve::GetRenderBounds( Vector& theMins, Vector& theMaxs ) +{ + if ( GetMoveParent() ) + { + GetMoveParent()->GetRenderBounds( theMins, theMaxs ); + } + else + { + theMins = GetAbsOrigin(); + theMaxs = theMaxs; + } +} + +//----------------------------------------------------------------------------- +// On data changed +//----------------------------------------------------------------------------- +void C_EntityDissolve::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + if ( updateType == DATA_UPDATE_CREATED ) + { + m_flNextSparkTime = m_flStartTime; + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + +//----------------------------------------------------------------------------- +// Cleanup +//----------------------------------------------------------------------------- +void C_EntityDissolve::UpdateOnRemove( void ) +{ + if ( m_pController ) + { + physenv->DestroyMotionController( m_pController ); + m_pController = NULL; + } + + BaseClass::UpdateOnRemove(); +} + +//------------------------------------------------------------------------------ +// Apply the forces to the entity +//------------------------------------------------------------------------------ +IMotionEvent::simresult_e C_EntityDissolve::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) +{ + linear.Init(); + angular.Init(); + + // Make it zero g + linear.z -= -1.02 * GetCurrentGravity(); + + Vector vel; + AngularImpulse angVel; + pObject->GetVelocity( &vel, &angVel ); + vel += linear * deltaTime; // account for gravity scale + + Vector unitVel = vel; + Vector unitAngVel = angVel; + + float speed = VectorNormalize( unitVel ); +// float angSpeed = VectorNormalize( unitAngVel ); + +// float speedScale = 0.0; +// float angSpeedScale = 0.0; + + float flLinearLimit = 50; + float flLinearLimitDelta = 40; + if ( speed > flLinearLimit ) + { + float flDeltaVel = (flLinearLimit - speed) / deltaTime; + if ( flLinearLimitDelta != 0.0f ) + { + float flMaxDeltaVel = -flLinearLimitDelta / deltaTime; + if ( flDeltaVel < flMaxDeltaVel ) + { + flDeltaVel = flMaxDeltaVel; + } + } + VectorMA( linear, flDeltaVel, unitVel, linear ); + } + + return SIM_GLOBAL_ACCELERATION; +} + + +//----------------------------------------------------------------------------- +// Tesla effect +//----------------------------------------------------------------------------- +static void FX_BuildTesla( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd ) +{ + BeamInfo_t beamInfo; + beamInfo.m_pStartEnt = pEntity; + beamInfo.m_nStartAttachment = 0; + beamInfo.m_pEndEnt = NULL; + beamInfo.m_nEndAttachment = 0; + beamInfo.m_nType = TE_BEAMTESLA; + beamInfo.m_vecStart = vecOrigin; + beamInfo.m_vecEnd = vecEnd; + beamInfo.m_pszModelName = "sprites/lgtning.vmt"; + beamInfo.m_flHaloScale = 0.0; + beamInfo.m_flLife = random->RandomFloat( 0.25f, 1.0f ); + beamInfo.m_flWidth = random->RandomFloat( 8.0f, 14.0f ); + beamInfo.m_flEndWidth = 1.0f; + beamInfo.m_flFadeLength = 0.5f; + beamInfo.m_flAmplitude = 24; + beamInfo.m_flBrightness = 255.0; + beamInfo.m_flSpeed = 150.0f; + beamInfo.m_nStartFrame = 0.0; + beamInfo.m_flFrameRate = 30.0; + beamInfo.m_flRed = 255.0; + beamInfo.m_flGreen = 255.0; + beamInfo.m_flBlue = 255.0; + beamInfo.m_nSegments = 18; + beamInfo.m_bRenderable = true; + beamInfo.m_nFlags = 0; //FBEAM_ONLYNOISEONCE; + + beams->CreateBeamEntPoint( beamInfo ); +} + +//----------------------------------------------------------------------------- +// Purpose: Tesla effect +//----------------------------------------------------------------------------- +void C_EntityDissolve::BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset ) +{ + Vector vecOrigin; + QAngle vecAngles; + MatrixGetColumn( hitboxToWorld, 3, vecOrigin ); + MatrixAngles( hitboxToWorld, vecAngles.Base() ); + C_BaseEntity *pEntity = GetMoveParent(); + + // Make a couple of tries at it + int iTries = -1; + Vector vecForward; + trace_t tr; + do + { + iTries++; + + // Some beams are deliberatly aimed around the point, the rest are random. + if ( !bRandom ) + { + QAngle vecTemp = vecAngles; + vecTemp[YAW] += flYawOffset; + AngleVectors( vecTemp, &vecForward ); + + // Randomly angle it up or down + vecForward.z = RandomFloat( -1, 1 ); + } + else + { + vecForward = RandomVector( -1, 1 ); + } + + UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 192), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr ); + } while ( tr.fraction >= 1.0 && iTries < 3 ); + + Vector vecEnd = tr.endpos - (vecForward * 8); + + // Only spark & glow if we hit something + if ( tr.fraction < 1.0 ) + { + if ( !EffectOccluded( tr.endpos ) ) + { + // Move it towards the camera + Vector vecFlash = tr.endpos; + Vector vecForward; + AngleVectors( MainViewAngles(), &vecForward ); + vecFlash -= (vecForward * 8); + + g_pEffects->EnergySplash( vecFlash, -vecForward, false ); + + // End glow + CSmartPtr pSimple = CSimpleEmitter::Create( "dust" ); + pSimple->SetSortOrigin( vecFlash ); + SimpleParticle *pParticle; + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash ); + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = RandomFloat( 0.5, 1 ); + pParticle->m_vecVelocity = vec3_origin; + Vector color( 1,1,1 ); + float colorRamp = RandomFloat( 0.75f, 1.25f ); + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f; + pParticle->m_uchStartSize = RandomFloat( 6,13 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2; + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 10; + pParticle->m_flRoll = RandomFloat( 0,360 ); + pParticle->m_flRollDelta = 0; + } + } + } + + // Build the tesla + FX_BuildTesla( pEntity, vecOrigin, tr.endpos ); +} + +//----------------------------------------------------------------------------- +// Sorts the components of a vector +//----------------------------------------------------------------------------- +static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx ) +{ + Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) ); + + int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1; + if (absVec[2] > absVec[maxIdx]) + { + maxIdx = 2; + } + + // always choose something right-handed.... + switch( maxIdx ) + { + case 0: + pVecIdx[0] = 1; + pVecIdx[1] = 2; + pVecIdx[2] = 0; + break; + case 1: + pVecIdx[0] = 2; + pVecIdx[1] = 0; + pVecIdx[2] = 1; + break; + case 2: + pVecIdx[0] = 0; + pVecIdx[1] = 1; + pVecIdx[2] = 2; + break; + } +} + +//----------------------------------------------------------------------------- +// Compute the bounding box's center, size, and basis +//----------------------------------------------------------------------------- +void C_EntityDissolve::ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, + Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec ) +{ + // Compute the center of the hitbox in worldspace + Vector vecHitboxCenter; + VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter ); + vecHitboxCenter *= 0.5f; + VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin ); + + // Get the object's basis + Vector vec[3]; + MatrixGetColumn( hitboxToWorld, 0, vec[0] ); + MatrixGetColumn( hitboxToWorld, 1, vec[1] ); + MatrixGetColumn( hitboxToWorld, 2, vec[2] ); +// vec[1] *= -1.0f; + + Vector vecViewDir; + VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir ); + VectorNormalize( vecViewDir ); + + // Project the shadow casting direction into the space of the hitbox + Vector localViewDir; + localViewDir[0] = DotProduct( vec[0], vecViewDir ); + localViewDir[1] = DotProduct( vec[1], vecViewDir ); + localViewDir[2] = DotProduct( vec[2], vecViewDir ); + + // Figure out which vector has the largest component perpendicular + // to the view direction... + // Sort by how perpendicular it is + int vecIdx[3]; + SortAbsVectorComponents( localViewDir, vecIdx ); + + // Here's our hitbox basis vectors; namely the ones that are + // most perpendicular to the view direction + *pXVec = vec[vecIdx[0]]; + *pYVec = vec[vecIdx[1]]; + + // Project them into a plane perpendicular to the view direction + *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec ); + *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec ); + VectorNormalize( *pXVec ); + VectorNormalize( *pYVec ); + + // Compute the hitbox size + Vector boxSize; + VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize ); + + // We project the two longest sides into the vectors perpendicular + // to the projection direction, then add in the projection of the perp direction + Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] ); + size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) ); + size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) ); + + // Add the third component into x and y + size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) ); + size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) ); + + // Bloat a bit, since the shadow wants to extend outside the model a bit + size *= 2.0f; + + // Clamp the minimum size + Vector2DMax( size, Vector2D(10.0f, 10.0f), size ); + + // Factor the size into the xvec + yvec + (*pXVec) *= size.x * 0.5f; + (*pYVec) *= size.y * 0.5f; +} + + +//----------------------------------------------------------------------------- +// Sparks! +//----------------------------------------------------------------------------- +void C_EntityDissolve::DoSparks( mstudiohitboxset_t *set, matrix3x4_t *hitboxbones[MAXSTUDIOBONES] ) +{ + if ( m_flNextSparkTime > gpGlobals->curtime ) + return; + + float dt = m_flStartTime + m_flFadeOutStart - gpGlobals->curtime; + dt = clamp( dt, 0.0f, m_flFadeOutStart ); + + float flNextTime; + if (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) + { + flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 2.0f * TICK_INTERVAL, 0.4f ); + } + else + { + // m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT); + flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 0.3f, 1.0f ); + } + + m_flNextSparkTime = gpGlobals->curtime + flNextTime; + + // Send out beams around us + int iNumBeamsAround = 2; + int iNumRandomBeams = 1; + int iTotalBeams = iNumBeamsAround + iNumRandomBeams; + float flYawOffset = RandomFloat(0,360); + for ( int i = 0; i < iTotalBeams; i++ ) + { + int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 ); + mstudiobbox_t *pBox = set->pHitbox(nHitbox); + + float flActualYawOffset = 0; + bool bRandom = ( i >= iNumBeamsAround ); + if ( !bRandom ) + { + flActualYawOffset = anglemod( flYawOffset + ((360 / iTotalBeams) * i) ); + } + + BuildTeslaEffect( pBox, *hitboxbones[pBox->bone], bRandom, flActualYawOffset ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityDissolve::SetupEmitter( void ) +{ + if ( !m_pEmitter ) + { + m_pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" ); + m_pEmitter->SetSortOrigin( GetAbsOrigin() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_EntityDissolve::GetFadeInPercentage( void ) +{ + float dt = gpGlobals->curtime - m_flStartTime; + + if ( dt > m_flFadeOutStart ) + return 1.0f; + + if ( dt < m_flFadeInStart ) + return 0.0f; + + if ( (dt > m_flFadeInStart) && (dt < m_flFadeInStart + m_flFadeInLength) ) + { + dt -= m_flFadeInStart; + + return ( dt / m_flFadeInLength ); + } + + return 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_EntityDissolve::GetFadeOutPercentage( void ) +{ + float dt = gpGlobals->curtime - m_flStartTime; + + if ( dt < m_flFadeInStart ) + return 1.0f; + + if ( dt > m_flFadeOutStart ) + { + dt -= m_flFadeOutStart; + + if ( dt > m_flFadeOutLength ) + return 0.0f; + + return 1.0f - ( dt / m_flFadeOutLength ); + } + + return 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float C_EntityDissolve::GetModelFadeOutPercentage( void ) +{ + float dt = gpGlobals->curtime - m_flStartTime; + + if ( dt < m_flFadeOutModelStart ) + return 1.0f; + + if ( dt > m_flFadeOutModelStart ) + { + dt -= m_flFadeOutModelStart; + + if ( dt > m_flFadeOutModelLength ) + return 0.0f; + + return 1.0f - ( dt / m_flFadeOutModelLength ); + } + + return 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_EntityDissolve::ClientThink( void ) +{ + C_BaseEntity *pEnt = GetMoveParent(); + if ( !pEnt ) + return; + + bool bIsRagdoll; +#ifdef TF_CLIENT_DLL + bIsRagdoll = true; +#else + C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; + if (!pAnimating) + return; + bIsRagdoll = pAnimating->IsRagdoll(); +#endif + + // NOTE: IsRagdoll means *client-side* ragdoll. We shouldn't be trying to fight + // the server ragdoll (or any server physics) on the client + if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && bIsRagdoll ) + { + IPhysicsObject *ppList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; + int nCount = pEnt->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) ); + if ( nCount > 0 ) + { + m_pController = physenv->CreateMotionController( this ); + for ( int i = 0; i < nCount; ++i ) + { + m_pController->AttachObject( ppList[i], true ); + } + } + } + + color32 color; + + color.r = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.x; + color.g = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.y; + color.b = ( 1.0f - GetFadeInPercentage() ) * m_vEffectColor.z; + color.a = GetModelFadeOutPercentage() * 255.0f; + + // Setup the entity fade + pEnt->SetRenderMode( kRenderTransColor ); + pEnt->SetRenderColor( color.r, color.g, color.b, color.a ); + + if ( GetModelFadeOutPercentage() <= 0.2f ) + { + m_bCoreExplode = true; + } + + // If we're dead, fade out + if ( GetFadeOutPercentage() <= 0.0f ) + { + // Do NOT remove from the client entity list. It'll confuse the local network backdoor, and the entity will never get destroyed + // because when the server says to destroy it, the client won't be able to find it. + // ClientEntityList().RemoveEntity( GetClientHandle() ); + + partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() ); + + RemoveFromLeafSystem(); + + //FIXME: Ick! + //Adrian: I'll assume we don't need the ragdoll either so I'll remove that too. + if ( m_bLinkedToServerEnt == false ) + { + Release(); + + C_ClientRagdoll *pRagdoll = dynamic_cast ( pEnt ); + + if ( pRagdoll ) + { + pRagdoll->ReleaseRagdoll(); + } +#ifdef TF_CLIENT_DLL + else + { + pEnt->Release(); + } +#endif + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +// Output : int +//----------------------------------------------------------------------------- +int C_EntityDissolve::DrawModel( int flags ) +{ + // See if we should draw + if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false ) + return 0; + + C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL; + if ( pAnimating == NULL ) + return 0; + + matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; + if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false ) + return 0; + + studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); + if ( pStudioHdr == NULL ) + return false; + + mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); + if ( set == NULL ) + return false; + + // Make sure the emitter is setup properly + SetupEmitter(); + + // Get fade percentages for the effect + float fadeInPerc = GetFadeInPercentage(); + float fadeOutPerc = GetFadeOutPercentage(); + + float fadePerc = ( fadeInPerc >= 1.0f ) ? fadeOutPerc : fadeInPerc; + + Vector vecSkew = vec3_origin; + + // Do extra effects under certain circumstances + if ( ( fadePerc < 0.99f ) && ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) ) ) + { + DoSparks( set, hitboxbones ); + } + + // Skew the particles in front or in back of their targets + vecSkew = CurrentViewForward() * ( 8.0f - ( ( 1.0f - fadePerc ) * 32.0f ) ); + + float spriteScale = ( ( gpGlobals->curtime - m_flStartTime ) / m_flFadeOutLength ); + spriteScale = clamp( spriteScale, 0.75f, 1.0f ); + + // Cache off this material reference + if ( g_Material_Spark == NULL ) + { + g_Material_Spark = ParticleMgr()->GetPMaterial( "effects/spark" ); + } + + if ( g_Material_AR2Glow == NULL ) + { + g_Material_AR2Glow = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" ); + } + + SimpleParticle *sParticle; + + for ( int i = 0; i < set->numhitboxes; ++i ) + { + Vector vecAbsOrigin, xvec, yvec; + mstudiobbox_t *pBox = set->pHitbox(i); + ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec ); + + Vector offset; + Vector xDir, yDir; + + xDir = xvec; + float xScale = VectorNormalize( xDir ) * 0.75f; + + yDir = yvec; + float yScale = VectorNormalize( yDir ) * 0.75f; + + int numParticles = clamp( 3.0f * fadePerc, 0.f, 3.f ); + + int iTempParts = 2; + + if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) + { + if ( m_bCoreExplode == true ) + { + numParticles = 15; + iTempParts = 20; + } + } + + for ( int j = 0; j < iTempParts; j++ ) + { + // Skew the origin + offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); + offset += vecSkew; + + if ( random->RandomInt( 0, 2 ) != 0 ) + continue; + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, vecAbsOrigin + offset ); + + if ( sParticle == NULL ) + return 1; + + sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) ); + + if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) + { + if ( m_bCoreExplode == true ) + { + Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; + VectorNormalize( vDirection ); + sParticle->m_vecVelocity = vDirection * m_nMagnitude; + } + } + + if ( sParticle->m_vecVelocity.z > 0 ) + { + sParticle->m_uchStartSize = random->RandomFloat( 4, 6 ) * spriteScale; + } + else + { + sParticle->m_uchStartSize = 2 * spriteScale; + } + + sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.5f ); + + // If we're the last particles, last longer + if ( numParticles == 0 ) + { + sParticle->m_flDieTime *= 2.0f; + sParticle->m_uchStartSize = 2 * spriteScale; + sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f ); + + if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) + { + if ( m_bCoreExplode == true ) + { + sParticle->m_flDieTime *= 2.0f; + sParticle->m_flRollDelta = Helper_RandomFloat( -1.0f, 1.0f ); + } + } + } + else + { + sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f, 8.0f ); + } + + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + + float alpha = 255; + + sParticle->m_uchColor[0] = m_vEffectColor.x; + sParticle->m_uchColor[1] = m_vEffectColor.y; + sParticle->m_uchColor[2] = m_vEffectColor.z; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchEndSize = 0; + } + + for ( int j = 0; j < numParticles; j++ ) + { + offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f ); + offset += vecSkew; + + sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_AR2Glow, vecAbsOrigin + offset ); + + if ( sParticle == NULL ) + return 1; + + sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -64.0f, 128.0f ) ); + sParticle->m_uchStartSize = random->RandomFloat( 8, 12 ) * spriteScale; + sParticle->m_flDieTime = 0.1f; + sParticle->m_flLifetime = 0.0f; + + sParticle->m_flRoll = Helper_RandomInt( 0, 360 ); + sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f ); + + float alpha = 255; + + sParticle->m_uchColor[0] = m_vEffectColor.x; + sParticle->m_uchColor[1] = m_vEffectColor.y; + sParticle->m_uchColor[2] = m_vEffectColor.z; + sParticle->m_uchStartAlpha = alpha; + sParticle->m_uchEndAlpha = 0; + sParticle->m_uchEndSize = 0; + + if ( m_nDissolveType == ENTITY_DISSOLVE_CORE ) + { + if ( m_bCoreExplode == true ) + { + Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin; + + VectorNormalize( vDirection ); + + sParticle->m_vecVelocity = vDirection * m_nMagnitude; + + sParticle->m_flDieTime = 0.5f; + } + } + } + } + + return 1; +} -- cgit v1.2.3