summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_fx_muzzleflash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/tf_fx_muzzleflash.cpp')
-rw-r--r--game/client/tf/tf_fx_muzzleflash.cpp333
1 files changed, 333 insertions, 0 deletions
diff --git a/game/client/tf/tf_fx_muzzleflash.cpp b/game/client/tf/tf_fx_muzzleflash.cpp
new file mode 100644
index 0000000..49d82e8
--- /dev/null
+++ b/game/client/tf/tf_fx_muzzleflash.cpp
@@ -0,0 +1,333 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "particles_simple.h"
+#include "particles_localspace.h"
+#include "c_te_effect_dispatch.h"
+#include "clienteffectprecachesystem.h"
+#include "tier0/vprof.h"
+#include "fx.h"
+#include "r_efx.h"
+#include "tier1/KeyValues.h"
+#include "dlight.h"
+#include "tf_shareddefs.h"
+#include "tf_fx_muzzleflash.h"
+#include "toolframework/itoolframework.h"
+#include "IEffects.h"
+#include "fx_sparks.h"
+#include "iefx.h"
+#include "fx_quad.h"
+#include "fx.h"
+#include "toolframework_client.h"
+
+// Precache our effects
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffect_TF_MuzzleFlash )
+ CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" )
+ CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" )
+ CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" )
+ CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" )
+CLIENTEFFECT_REGISTER_END()
+
+ConVar cl_muzzleflash_dlight_1st( "cl_muzzleflash_dlight_1st", "1" );
+
+void TE_DynamicLight( IRecipientFilter& filter, float delay,
+ const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay, int nLightIndex = LIGHT_INDEX_TE_DYNAMIC );
+
+extern PMaterialHandle g_Material_Spark;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void TF_3rdPersonMuzzleFlashCallback( const CEffectData &data )
+{
+ float scale = data.m_flMagnitude;
+ int attachmentIndex = data.m_nAttachmentIndex;
+
+ CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", data.m_hEntity, attachmentIndex, 0 );
+
+ Vector forward(1,0,0), offset, right(0,1,0);
+
+ //
+ // Flash
+ //
+
+ if ( data.m_nHitBox > 0 ) // >0 is a mg flash in script based muzzleflashes ..
+ {
+ offset = vec3_origin;
+
+ // small inner cone
+ scale *= 4;
+ float flScale = random->RandomFloat( scale-0.1f, scale+0.1f );
+
+ for ( int i = 1; i < 9; i++ )
+ {
+ offset = (forward * (i*2.0f*scale));
+
+ SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
+
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.1f;
+
+ pParticle->m_vecVelocity.Init();
+
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 128;
+
+ pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = 0.0f;
+ }
+ }
+ else
+ {
+ scale *= 4;
+ float flScale = random->RandomFloat( scale-0.1f, scale+0.1f );
+
+ for ( int i = 1; i < 9; i++ )
+ {
+ offset = (forward * (i*2.0f*scale));
+
+ SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
+
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.1f;
+
+ pParticle->m_vecVelocity.Init();
+
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+
+ pParticle->m_uchStartAlpha = 128;
+ pParticle->m_uchEndAlpha = 64;
+
+ pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = 0.0f;
+ }
+ }
+
+ //Smoke
+ int i;
+ offset = vec3_origin;
+ for( i=0;i<3;i++ )
+ {
+ SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset );
+
+ if ( pParticle )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.3f;
+
+ pParticle->m_vecVelocity.Init();
+ pParticle->m_vecVelocity = forward * ( random->RandomFloat( 80.0f, 100.0f ) + (2-i)*15 );
+
+ int color = random->RandomInt( 200, 255 );
+ pParticle->m_uchColor[0] = color;
+ pParticle->m_uchColor[1] = color;
+ pParticle->m_uchColor[2] = color;
+
+ pParticle->m_uchStartAlpha = 32;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_uchStartSize = ( 4.0 + 3.0*(2-i) ) * data.m_flMagnitude;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 13.0f;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
+ }
+ }
+}
+
+void TF_3rdPersonMuzzleFlashCallback_SentryGun( const CEffectData &data )
+{
+ int iMuzzleFlashAttachment = data.m_nAttachmentIndex;
+ int iUpgradeLevel = data.m_fFlags;
+
+ C_BaseEntity *pEnt = data.GetEntity();
+ if ( pEnt && !pEnt->IsDormant() )
+ {
+ // The created entity kills itself
+ //C_MuzzleFlashModel::CreateMuzzleFlashModel( "models/effects/sentry1_muzzle/sentry1_muzzle.mdl", pEnt, iMuzzleFlashAttachment );
+
+ const char *pszMuzzleFlashParticleEffect = NULL;
+ switch( iUpgradeLevel )
+ {
+ case 1:
+ default:
+ pszMuzzleFlashParticleEffect = "muzzle_sentry";
+ break;
+ case 2:
+ case 3:
+ pszMuzzleFlashParticleEffect = "muzzle_sentry2";
+ break;
+ }
+
+ DispatchParticleEffect( pszMuzzleFlashParticleEffect, PATTACH_POINT_FOLLOW, pEnt, iMuzzleFlashAttachment );
+ }
+}
+
+//TODO: Come back and make this guy a nice particle.
+DECLARE_CLIENT_EFFECT( "TF_3rdPersonMuzzleFlash", TF_3rdPersonMuzzleFlashCallback );
+DECLARE_CLIENT_EFFECT( "TF_3rdPersonMuzzleFlash_SentryGun", TF_3rdPersonMuzzleFlashCallback_SentryGun );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pszModelName -
+// vecOrigin -
+// vecForceDir -
+// vecAngularImp -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+C_MuzzleFlashModel *C_MuzzleFlashModel::CreateMuzzleFlashModel( const char *pszModelName, C_BaseEntity *pParent, int iAttachment, float flLifetime )
+{
+ C_MuzzleFlashModel *pFlash = new C_MuzzleFlashModel;
+ if ( !pFlash )
+ return NULL;
+
+ if ( !pFlash->InitializeMuzzleFlash( pszModelName, pParent, iAttachment, flLifetime ) )
+ return NULL;
+
+ return pFlash;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool C_MuzzleFlashModel::InitializeMuzzleFlash( const char *pszModelName, C_BaseEntity *pParent, int iAttachment, float flLifetime )
+{
+ AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW );
+ if ( InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
+ {
+ Release();
+ return false;
+ }
+
+ SetParent( pParent, iAttachment );
+ SetLocalOrigin( vec3_origin );
+ SetLocalAngles( vec3_angle );
+
+ AddSolidFlags( FSOLID_NOT_SOLID );
+
+ m_flRotateAt = gpGlobals->curtime + 0.2;
+ SetLifetime( flLifetime );
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+
+ SetCycle( 0 );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_MuzzleFlashModel::SetLifetime( float flLifetime )
+{
+ // Expire when the lifetime is up
+ m_flExpiresAt = gpGlobals->curtime + flLifetime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_MuzzleFlashModel::ClientThink( void )
+{
+ if ( !GetMoveParent() || gpGlobals->curtime > m_flExpiresAt )
+ {
+ Release();
+ return;
+ }
+
+ if ( gpGlobals->curtime > m_flRotateAt )
+ {
+ // Pick a new anim frame
+ float flDelta = RandomFloat(0.2,0.4) * (RandomInt(0,1) == 1 ? 1 : -1);
+ float flCycle = clamp( GetCycle() + flDelta, 0.f, 1.f );
+ SetCycle( flCycle );
+
+ SetLocalAngles( QAngle(0,0,RandomFloat(0,360)) );
+ m_flRotateAt = gpGlobals->curtime + 0.075;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// This is an incredibly brutal hack to get muzzle flashes positioned correctly for recording
+//-----------------------------------------------------------------------------
+void C_MuzzleFlashModel::SetIs3rdPersonFlash( bool bEnable )
+{
+ m_bIs3rdPersonFlash = bEnable;
+}
+
+
+bool C_MuzzleFlashModel::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
+{
+ // FIXME: This is an incredibly brutal hack to get muzzle flashes positioned correctly for recording
+ // NOTE: The correct, long-term solution, is to make weapon models
+ // always store the 3rd person model and to have view model entities
+ // always store the 1st person model. I didn't have time to do that for Leipzig.
+ int nModelIndex = 0;
+ int nWorldModelIndex = 0;
+ CBaseCombatWeapon *pParent = dynamic_cast<CBaseCombatWeapon*>( GetMoveParent() );
+ if ( m_bIs3rdPersonFlash && pParent )
+ {
+ nModelIndex = pParent->GetModelIndex();
+ nWorldModelIndex = pParent->GetWorldModelIndex();
+ pParent->SetModelIndex( nWorldModelIndex );
+ }
+
+ bool bResult = BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
+
+ if ( m_bIs3rdPersonFlash && pParent )
+ {
+ pParent->SetModelIndex( nModelIndex );
+ }
+
+ return bResult;
+}
+
+
+//-----------------------------------------------------------------------------
+// Recording
+//-----------------------------------------------------------------------------
+void C_MuzzleFlashModel::GetToolRecordingState( KeyValues *msg )
+{
+ if ( !ToolsEnabled() )
+ return;
+
+ VPROF_BUDGET( "C_MuzzleFlashModel::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
+
+ BaseClass::GetToolRecordingState( msg );
+
+ C_BaseEntity *pParent = GetMoveParent();
+ if ( pParent )
+ {
+ BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
+ pBaseEntity->m_nOwner = pParent->entindex();
+
+ // FIXME: This recording path is a giant hack in a cascading series of hacks
+ C_BaseCombatWeapon *pParentWeapon = dynamic_cast<C_BaseCombatWeapon*>( pParent );
+ if ( pParentWeapon )
+ {
+ if ( pParentWeapon->WeaponState() == WEAPON_NOT_CARRIED )
+ {
+ pBaseEntity->m_bVisible = false;
+ }
+ }
+ }
+}