//----------------------------------------------------------------------------- // Purpose: Tesla effect //----------------------------------------------------------------------------- void FX_BuildTeslaHitbox( const CEffectData &data ) { Vector vColor( 1, 1, 1 ); C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.entindex() ); C_BaseAnimating *pAnimating = pEntity ? pEntity->GetBaseAnimating() : NULL; if (!pAnimating) return; studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if (!pStudioHdr) return; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( !set ) return; matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) ) return; int nBeamCount = (int)(data.m_flMagnitude + 0.5f); for ( int i = 0; i < nBeamCount; ++i ) { int nStartHitBox = random->RandomInt( 1, set->numhitboxes ); int nEndHitBox = random->RandomInt( 1, set->numhitboxes ); FX_BuildTeslaHitbox( pEntity, nStartHitBox, nEndHitBox, data.m_flScale, vColor, random->RandomFloat( 0.05f, 0.2f ) ); } }
//----------------------------------------------------------------------------- // Purpose: Tesla effect //----------------------------------------------------------------------------- void BuildTeslaCallback( const CEffectData &data ) { if ( data.entindex() < 0 ) return; CTeslaInfo teslaInfo; teslaInfo.m_vPos = data.m_vOrigin; teslaInfo.m_vAngles = data.m_vAngles; teslaInfo.m_nEntIndex = data.entindex(); teslaInfo.m_flBeamWidth = 5; teslaInfo.m_vColor.Init( 1, 1, 1 ); teslaInfo.m_flTimeVisible = 0.3; teslaInfo.m_flRadius = 192; teslaInfo.m_nBeams = 6; teslaInfo.m_pszSpriteName = "sprites/physbeam.vmt"; FX_Tesla( teslaInfo ); }
//----------------------------------------------------------------------------- // Purpose: Large dust impact to be used only when something's landed on the ground //----------------------------------------------------------------------------- void BuildImpactGroundCallback( const CEffectData &data ) { Vector vecOrigin = data.m_vOrigin; QAngle vecAngles = data.m_vAngles; Vector vecNormal = data.m_vNormal; int iEntIndex = data.entindex(); C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); FX_BuildImpact( vecOrigin, vecAngles, vecNormal, 1, true, pEntity ); }
//----------------------------------------------------------------------------- // Record effects //----------------------------------------------------------------------------- static void RecordEffect( const char *pEffectName, const CEffectData &data ) { if ( !ToolsEnabled() ) return; if ( clienttools->IsInRecordingMode() && ( (data.m_fFlags & EFFECTDATA_NO_RECORD) == 0 ) ) { KeyValues *msg = new KeyValues( "TempEntity" ); const char *pSurfacePropName = physprops->GetPropName( data.m_nSurfaceProp ); char pName[1024]; Q_snprintf( pName, sizeof(pName), "TE_DispatchEffect %s %s", pEffectName, pSurfacePropName ); msg->SetInt( "te", TE_DISPATCH_EFFECT ); msg->SetString( "name", pName ); msg->SetFloat( "time", gpGlobals->curtime ); msg->SetFloat( "originx", data.m_vOrigin.x ); msg->SetFloat( "originy", data.m_vOrigin.y ); msg->SetFloat( "originz", data.m_vOrigin.z ); msg->SetFloat( "startx", data.m_vStart.x ); msg->SetFloat( "starty", data.m_vStart.y ); msg->SetFloat( "startz", data.m_vStart.z ); msg->SetFloat( "normalx", data.m_vNormal.x ); msg->SetFloat( "normaly", data.m_vNormal.y ); msg->SetFloat( "normalz", data.m_vNormal.z ); msg->SetFloat( "anglesx", data.m_vAngles.x ); msg->SetFloat( "anglesy", data.m_vAngles.y ); msg->SetFloat( "anglesz", data.m_vAngles.z ); msg->SetInt( "flags", data.m_fFlags ); msg->SetFloat( "scale", data.m_flScale ); msg->SetFloat( "magnitude", data.m_flMagnitude ); msg->SetFloat( "radius", data.m_flRadius ); msg->SetString( "surfaceprop", pSurfacePropName ); msg->SetInt( "color", data.m_nColor ); msg->SetInt( "damagetype", data.m_nDamageType ); msg->SetInt( "hitbox", data.m_nHitBox ); msg->SetString( "effectname", pEffectName ); // FIXME: Need to write the attachment name here msg->SetInt( "attachmentindex", data.m_nAttachmentIndex ); // NOTE: Ptrs are our way of indicating it's an entindex msg->SetPtr( "entindex", (void*)data.entindex() ); ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); msg->deleteThis(); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void ParticleTracerCallback( const CEffectData &data ) { C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); if ( !player ) return; // Grab the data Vector vecStart = GetTracerOrigin( data ); Vector vecEnd = data.m_vOrigin; // Adjust view model tracers C_BaseEntity *pEntity = data.GetEntity(); if ( data.entindex() && data.entindex() == player->index ) { QAngle vangles; Vector vforward, vright, vup; engine->GetViewAngles( vangles ); AngleVectors( vangles, &vforward, &vright, &vup ); VectorMA( data.m_vStart, 4, vright, vecStart ); vecStart[2] -= 0.5f; } // Create the particle effect QAngle vecAngles; Vector vecToEnd = vecEnd - vecStart; VectorNormalize(vecToEnd); VectorAngles( vecToEnd, vecAngles ); DispatchParticleEffect( data.m_nHitBox, vecStart, vecEnd, vecAngles, pEntity ); if ( data.m_fFlags & TRACER_FLAG_WHIZ ) { FX_TracerSound( vecStart, vecEnd, TRACER_TYPE_DEFAULT ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void AR2TracerCallback( const CEffectData &data ) { C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); if ( player == NULL ) return; // Grab the data Vector vecStart = GetTracerOrigin( data ); float flVelocity = data.m_flScale; bool bWhiz = (data.m_fFlags & TRACER_FLAG_WHIZ); int iEntIndex = data.entindex(); if ( iEntIndex && iEntIndex == player->index ) { Vector foo = data.m_vStart; QAngle vangles; Vector vforward, vright, vup; engine->GetViewAngles( vangles ); AngleVectors( vangles, &vforward, &vright, &vup ); VectorMA( data.m_vStart, 4, vright, foo ); foo[2] -= 0.5f; FX_PlayerAR2Tracer( foo, (Vector&)data.m_vOrigin ); return; } // Use default velocity if none specified if ( !flVelocity ) { flVelocity = 8000; } // Do tracer effect FX_AR2Tracer( (Vector&)vecStart, (Vector&)data.m_vOrigin, flVelocity, bWhiz ); }
//----------------------------------------------------------------------------- // Old-style muzzle flashes //----------------------------------------------------------------------------- void MuzzleFlashCallback( const CEffectData &data ) { Vector vecOrigin = data.m_vOrigin; QAngle vecAngles = data.m_vAngles; if ( data.entindex() > 0 ) { IClientRenderable *pRenderable = data.GetRenderable(); if ( !pRenderable ) return; if ( data.m_nAttachmentIndex ) { //FIXME: We also need to allocate these particles into an attachment space setup pRenderable->GetAttachment( data.m_nAttachmentIndex, vecOrigin, vecAngles ); } else { vecOrigin = pRenderable->GetRenderOrigin(); vecAngles = pRenderable->GetRenderAngles(); } } tempents->MuzzleFlash( vecOrigin, vecAngles, data.m_fFlags & (~MUZZLEFLASH_FIRSTPERSON), data.m_hEntity, (data.m_fFlags & MUZZLEFLASH_FIRSTPERSON) != 0 ); }
//----------------------------------------------------------------------------- // Purpose: Tesla effect //----------------------------------------------------------------------------- void BuildTeslaCallback( const CEffectData &data ) { Vector vecOrigin = data.m_vOrigin; QAngle vecAngles = data.m_vAngles; int iEntIndex = data.entindex(); C_BaseEntity *pEntity = ClientEntityList().GetEnt( iEntIndex ); // Send out beams around us int iNumBeamsAround = 4; int iNumRandomBeams = 2; int iTotalBeams = iNumBeamsAround + iNumRandomBeams; float flYawOffset = RandomFloat(0,360); for ( int i = 0; i < iTotalBeams; i++ ) { // 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 ( i < iNumBeamsAround ) { QAngle vecTemp = vecAngles; vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) ); 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, 0 ) ) { // 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<CSimpleEmitter> 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 ); } }