diff options
Diffstat (limited to 'game/client/cstrike/fx_cs_blood.cpp')
| -rw-r--r-- | game/client/cstrike/fx_cs_blood.cpp | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/game/client/cstrike/fx_cs_blood.cpp b/game/client/cstrike/fx_cs_blood.cpp new file mode 100644 index 0000000..faf3c4b --- /dev/null +++ b/game/client/cstrike/fx_cs_blood.cpp @@ -0,0 +1,482 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: A blood spray effect to expose successful hits. +// +//=============================================================================// + +#include "cbase.h" +#include "clienteffectprecachesystem.h" +#include "fx_sparks.h" +#include "iefx.h" +#include "c_te_effect_dispatch.h" +#include "particles_ez.h" +#include "decals.h" +#include "engine/IEngineSound.h" +#include "fx_quad.h" +#include "engine/ivdebugoverlay.h" +#include "shareddefs.h" +#include "fx_blood.h" +#include "view.h" +#include "c_cs_player.h" + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectCSBloodSpray ) +CLIENTEFFECT_MATERIAL( "effects/blood_gore" ) +CLIENTEFFECT_MATERIAL( "effects/blood_drop" ) +CLIENTEFFECT_MATERIAL( "effects/blood_puff" ) +CLIENTEFFECT_REGISTER_END() + + +class CHitEffectRamp +{ +public: + float m_flDamageAmount; + + float m_flMinAlpha; + float m_flMaxAlpha; + + float m_flMinSize; + float m_flMaxSize; + + float m_flMinVelocity; + float m_flMaxVelocity; +}; + + +void InterpolateRamp( + const CHitEffectRamp &a, + const CHitEffectRamp &b, + CHitEffectRamp &out, + int iDamage ) +{ + float t = RemapVal( iDamage, a.m_flDamageAmount, b.m_flDamageAmount, 0, 1 ); + + out.m_flMinAlpha = FLerp( a.m_flMinAlpha, b.m_flMinAlpha, t ); + out.m_flMaxAlpha = FLerp( a.m_flMaxAlpha, b.m_flMaxAlpha, t ); + out.m_flMinAlpha = clamp( out.m_flMinAlpha, 0, 255 ); + out.m_flMaxAlpha = clamp( out.m_flMaxAlpha, 0, 255 ); + + out.m_flMinSize = FLerp( a.m_flMinSize, b.m_flMinSize, t ); + out.m_flMaxSize = FLerp( a.m_flMaxSize, b.m_flMaxSize, t ); + + out.m_flMinVelocity = FLerp( a.m_flMinVelocity, b.m_flMinVelocity, t ); + out.m_flMaxVelocity = FLerp( a.m_flMaxVelocity, b.m_flMaxVelocity, t ); +} + + +void FX_HitEffectSmoke( + CSmartPtr<CBloodSprayEmitter> pEmitter, + int iDamage, + const Vector &vEntryPoint, + const Vector &vDirection, + float flScale) +{ + SimpleParticle newParticle; + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 30, // min/max alpha + 70, + 0.5, // min/max size + 1, + 0, // min/max velocity (not used here) + 0 + }, + + { + 50, + 30, // min/max alpha + 70, + 1, // min/max size + 2, + 0, // min/max velocity (not used here) + 0 + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + for ( int i=0; i < 2; i++ ) + { + SimpleParticle &newParticle = *pEmitter->AddSimpleParticle( hMaterial, vEntryPoint, 0, 0 ); + + newParticle.m_flLifetime = 0.0f; + newParticle.m_flDieTime = 3.0f; + + newParticle.m_uchStartSize = random->RandomInt( + interpolatedRamp.m_flMinSize, + interpolatedRamp.m_flMaxSize ) * flScale; + newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4; + + newParticle.m_vecVelocity = Vector( 0, 0, 5 ) + RandomVector( -2, 2 ); + newParticle.m_uchStartAlpha = random->RandomInt( + interpolatedRamp.m_flMinSize, + interpolatedRamp.m_flMaxSize ); + newParticle.m_uchEndAlpha = 0; + + newParticle.m_flRoll = random->RandomFloat( 0, 360 ); + newParticle.m_flRollDelta = random->RandomFloat( -1, 1 ); + + newParticle.m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY; + + float colorRamp = random->RandomFloat( 0.5f, 1.25f ); + + newParticle.m_uchColor[0] = MIN( 1.0f, colorRamp ) * 255.0f; + newParticle.m_uchColor[1] = MIN( 1.0f, colorRamp ) * 255.0f; + newParticle.m_uchColor[2] = MIN( 1.0f, colorRamp ) * 255.0f; + } +} + + +void FX_HitEffectBloodSpray( + CSmartPtr<CBloodSprayEmitter> pEmitter, + int iDamage, + const Vector &vEntryPoint, + const Vector &vSprayNormal, + const char *pMaterialName, + float flLODDistance, + float flDistanceScale, + float flScale, + float flSpeed ) +{ + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( pMaterialName ); + SimpleParticle *pParticle; + + float color[3] = { 1.0, 0, 0 }; + + Vector up( 0, 0, 1 ); + Vector right = up.Cross( vSprayNormal ); + VectorNormalize( right ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 80, // min/max alpha + 128, + flScale/2,// min/max size + flScale, + 10, // min/max velocity + 20 + }, + + { + 50, + 80, // min/max alpha + 128, + flScale/2,// min/max size + flScale, + 30, // min/max velocity + 60 + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + for ( int i = 0; i < 6; i++ ) + { + // Originate from within a circle '2 * scale' inches in diameter. + Vector offset = vEntryPoint + ( flScale * vSprayNormal * 0.5 ); + offset += right * random->RandomFloat( -1, 1 ) * flScale; + offset += up * random->RandomFloat( -1, 1 ) * flScale; + + pParticle = pEmitter->AddSimpleParticle( hMaterial, offset, 0, 0 ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.7f, 1.3f); + + // All the particles are between red and white. The whiter the particle is, the slower it goes. + float whiteness = random->RandomFloat( 0.1, 0.7 ); + float speedFactor = 1 - whiteness; + + float spread = 0.5f; + pParticle->m_vecVelocity.Random( -spread, spread ); + pParticle->m_vecVelocity += vSprayNormal * random->RandomInt( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity ) * flSpeed * speedFactor; + + float colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance; + + pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f; + pParticle->m_uchColor[1] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f; + pParticle->m_uchColor[2] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f; + + pParticle->m_uchStartSize = random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize ) * flDistanceScale; + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4 * flDistanceScale; + + pParticle->m_uchStartAlpha = random->RandomInt( interpolatedRamp.m_flMinAlpha, interpolatedRamp.m_flMaxAlpha ); + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f ); + } + } +} + + +void FX_HitEffectBloodSplatter( + CSmartPtr<CBloodSprayEmitter> pTrailEmitter, + int iDamage, + const Vector &vExitPoint, + const Vector &vSplatterNormal, + float flLODDistance ) +{ + float flScale = 4; + + pTrailEmitter->SetSortOrigin( vExitPoint ); + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); + + Vector up( 0, 0, 1 ); + Vector right = up.Cross( vSplatterNormal ); + VectorNormalize( right ); + + // These parameters create a ramp based on how much damage the shot did. + CHitEffectRamp ramps[2] = + { + { + 0, + 0, // min/max alpha + 75, + 1.5f, // min/max size + 2.0f, + 25.0f * flScale, // min/max velocity + 35.0f * flScale + }, + + { + 50, + 0, // min/max alpha + 140, + 1.5f,// min/max size + 2.0f, + 65.0f * flScale, // min/max velocity + 75.0f * flScale + } + }; + + CHitEffectRamp interpolatedRamp; + InterpolateRamp( + ramps[0], + ramps[1], + interpolatedRamp, + iDamage ); + + + for ( int i = 0; i < 20; i++ ) + { + // Originate from within a circle 'scale' inches in diameter. + Vector offset = vExitPoint; + offset += right * random->RandomFloat( -0.15f, 0.15f ) * flScale; + offset += up * random->RandomFloat( -0.15f, 0.15f ) * flScale; + + SimpleParticle *tParticle = (SimpleParticle*)pTrailEmitter->AddSimpleParticle( + hMaterial, + vExitPoint, + random->RandomFloat( 0.225f, 0.35f ), + random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize ) + ); + + if ( tParticle == NULL ) + break; + + Vector offDir = vSplatterNormal + RandomVector( -0.05f, 0.05f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity ); + + tParticle->m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY; + tParticle->m_uchColor[0] = 150; + tParticle->m_uchColor[1] = 0; + tParticle->m_uchColor[2] = 0; + tParticle->m_uchStartAlpha = interpolatedRamp.m_flMaxAlpha / 2; + tParticle->m_uchEndAlpha = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : origin - +// normal - +// scale - +//----------------------------------------------------------------------------- +void FX_CS_BloodSpray( const Vector &origin, const Vector &normal, float flDamage ) +{ + if ( UTIL_IsLowViolence() ) + return; + + static ConVar *violence_hblood = cvar->FindVar( "violence_hblood" ); + if ( violence_hblood && !violence_hblood->GetBool() ) + return; + + Vector offset; + int i; + + float r = 64; + float g = 0; + float b = 4; + + float scale = 0.5 + clamp( flDamage/50.f, 0.0, 1.0 ) ; + + //Find area ambient light color and use it to tint smoke + Vector worldLight = WorldGetLightForPoint( origin, true ); + Vector color = Vector( (float)(worldLight[0] * r) / 255.0f, (float)(worldLight[1] * g) / 255.0f, (float)(worldLight[2] * b) / 255.0f ); + float colorRamp; + + Vector offDir; + + CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" ); + if ( !pSimple ) + return; + + pSimple->SetSortOrigin( origin ); + pSimple->SetGravity( 0 ); + + // Blood impact + PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_core" ); + + SimpleParticle *pParticle; + + Vector dir = normal * RandomVector( -0.5f, 0.5f ); + + offset = origin + ( 2.0f * normal ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = 0.75f; + + pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f ); + pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f ); + + colorRamp = random->RandomFloat( 0.75f, 2.0f ); + + 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 = 8; + pParticle->m_uchEndSize = 32; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0; + } + + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" ); + + for ( i = 0; i < 4; i++ ) + { + offset = origin + ( 2.0f * normal ); + + pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset ); + + if ( pParticle != NULL ) + { + pParticle->m_flLifetime = 0.0f; + pParticle->m_flDieTime = random->RandomFloat( 0.75f, 1.0f); + + pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f )*(i+1); + pParticle->m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1); + + colorRamp = random->RandomFloat( 0.75f, 2.0f ); + + 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 = scale * random->RandomInt( 4, 8 ); + pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4; + + pParticle->m_uchStartAlpha = 255; + pParticle->m_uchEndAlpha = 0; + + pParticle->m_flRoll = random->RandomInt( 0, 360 ); + pParticle->m_flRollDelta = 0; + } + } + + // + // Dump out drops + // + TrailParticle *tParticle; + + CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" ); + if ( !pTrailEmitter ) + return; + + pTrailEmitter->SetSortOrigin( origin ); + + // Partial gravity on blood drops + pTrailEmitter->SetGravity( 400.0 ); + + // Enable simple collisions with nearby surfaces + pTrailEmitter->Setup(origin, &normal, 1, 10, 100, 400, 0.2, 0 ); + + hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" ); + + // + // Shorter droplets + // + for ( i = 0; i < 32; i++ ) + { + // Originate from within a circle 'scale' inches in diameter + offset = origin; + + tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); + + if ( tParticle == NULL ) + break; + + tParticle->m_flLifetime = 0.0f; + + offDir = RandomVector( -1.0f, 1.0f ); + + tParticle->m_vecVelocity = offDir * random->RandomFloat( 32.0f, 128.0f ); + + tParticle->m_flWidth = scale * random->RandomFloat( 1.0f, 3.0f ); + tParticle->m_flLength = random->RandomFloat( 0.1f, 0.15f ); + tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f ); + + FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bloodtype - +// r - +// g - +// b - +//----------------------------------------------------------------------------- +void GetBloodColorForTeam( int iTeam, unsigned char &r, unsigned char &g, unsigned char &b ) +{ + +} + +//----------------------------------------------------------------------------- +// Purpose: Intercepts the blood spray message. +//----------------------------------------------------------------------------- +void CSBloodSprayCallback( const CEffectData &data ) +{ + FX_CS_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flMagnitude ); +} + +DECLARE_CLIENT_EFFECT( "csblood", CSBloodSprayCallback ); |