You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.4 KiB
180 lines
5.4 KiB
//========= 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_tf_player.h" |
|
#include "debugoverlay_shared.h" |
|
#include "tf_gamerules.h" |
|
#include "c_basetempentity.h" |
|
#include "tier0/vprof.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Intercepts the blood spray message. |
|
//----------------------------------------------------------------------------- |
|
void TFBloodSprayCallback( Vector vecOrigin, Vector vecNormal, ClientEntityHandle_t hEntity ) |
|
{ |
|
QAngle vecAngles; |
|
VectorAngles( -vecNormal, vecAngles ); |
|
|
|
// determine if the bleeding player is underwater |
|
bool bUnderwater = false; |
|
C_TFPlayer *pPlayer = dynamic_cast<C_TFPlayer*>( ClientEntityList().GetBaseEntityFromHandle( hEntity ) ); |
|
if ( pPlayer && ( WL_Eyes == pPlayer->GetWaterLevel() ) ) |
|
{ |
|
bUnderwater = true; |
|
} |
|
|
|
bool bPyroVision = false; |
|
#ifdef CLIENT_DLL |
|
// Use birthday fun if the local player has an item that allows them to see it (Pyro Goggles) |
|
if ( IsLocalPlayerUsingVisionFilterFlags( TF_VISION_FILTER_PYRO ) ) |
|
{ |
|
bPyroVision = true; |
|
} |
|
#endif |
|
|
|
if ( !bUnderwater && TFGameRules() && TFGameRules()->IsBirthday() && RandomFloat(0,1) < 0.2 ) |
|
{ |
|
DispatchParticleEffect( "bday_blood", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
else if ( TFGameRules() && bPyroVision ) |
|
{ |
|
DispatchParticleEffect( "pyrovision_blood", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
else if ( UTIL_IsLowViolence() ) |
|
{ |
|
DispatchParticleEffect( bUnderwater ? "lowV_water_blood_impact_red_01" : "lowV_blood_impact_red_01", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
else |
|
{ |
|
DispatchParticleEffect( bUnderwater ? "water_blood_impact_red_01" : "blood_impact_red_01", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
|
|
// if underwater, don't add additional spray |
|
if ( bUnderwater ) |
|
return; |
|
|
|
// Now throw out a spray away from the view |
|
// Get the distance to the view |
|
float flDistance = (vecOrigin - MainViewOrigin()).Length(); |
|
float flLODDistance = 0.25 * (flDistance / 512); |
|
|
|
Vector right, up; |
|
if (vecNormal != Vector(0, 0, 1) ) |
|
{ |
|
right = vecNormal.Cross( Vector(0, 0, 1) ); |
|
up = right.Cross( vecNormal ); |
|
} |
|
else |
|
{ |
|
right = Vector(0, 0, 1); |
|
up = right.Cross( vecNormal ); |
|
} |
|
|
|
// If the normal's too close to being along the view, push it out |
|
Vector vecForward, vecRight; |
|
AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL ); |
|
float flDot = DotProduct( vecNormal, vecForward ); |
|
if ( fabs(flDot) > 0.5 ) |
|
{ |
|
float flPush = random->RandomFloat(0.5, 1.5) + flLODDistance; |
|
float flRightDot = DotProduct( vecNormal, vecRight ); |
|
|
|
// If we're up close, randomly move it around. If we're at a distance, always push it to the side |
|
// Up close, this can move it back towards the view, but the random chance still looks better |
|
if ( ( flDistance >= 512 && flRightDot > 0 ) || ( flDistance < 512 && RandomFloat(0,1) > 0.5 ) ) |
|
{ |
|
// Turn it to the right |
|
vecNormal += (vecRight * flPush); |
|
} |
|
else |
|
{ |
|
// Turn it to the left |
|
vecNormal -= (vecRight * flPush); |
|
} |
|
} |
|
|
|
VectorAngles( vecNormal, vecAngles ); |
|
|
|
if ( flDistance < 400 ) |
|
{ |
|
|
|
DispatchParticleEffect( UTIL_IsLowViolence() ? "lowV_blood_spray_red_01" : "blood_spray_red_01", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
else |
|
{ |
|
DispatchParticleEffect( UTIL_IsLowViolence() ? "lowV_blood_spray_red_01_far" : "blood_spray_red_01_far", vecOrigin, vecAngles, pPlayer ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class C_TETFBlood : public C_BaseTempEntity |
|
{ |
|
public: |
|
DECLARE_CLASS( C_TETFBlood, C_BaseTempEntity ); |
|
|
|
DECLARE_CLIENTCLASS(); |
|
|
|
C_TETFBlood( void ); |
|
|
|
virtual void PostDataUpdate( DataUpdateType_t updateType ); |
|
|
|
public: |
|
Vector m_vecOrigin; |
|
Vector m_vecNormal; |
|
ClientEntityHandle_t m_hEntity; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
C_TETFBlood::C_TETFBlood( void ) |
|
{ |
|
m_vecOrigin.Init(); |
|
m_vecNormal.Init(); |
|
m_hEntity = INVALID_EHANDLE_INDEX; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_TETFBlood::PostDataUpdate( DataUpdateType_t updateType ) |
|
{ |
|
VPROF( "C_TETFBlood::PostDataUpdate" ); |
|
|
|
TFBloodSprayCallback( m_vecOrigin, m_vecNormal, m_hEntity ); |
|
} |
|
|
|
static void RecvProxy_BloodEntIndex( const CRecvProxyData *pData, void *pStruct, void *pOut ) |
|
{ |
|
int nEntIndex = pData->m_Value.m_Int; |
|
((C_TETFBlood*)pStruct)->m_hEntity = (nEntIndex < 0) ? INVALID_EHANDLE_INDEX : ClientEntityList().EntIndexToHandle( nEntIndex ); |
|
} |
|
|
|
IMPLEMENT_CLIENTCLASS_EVENT_DT(C_TETFBlood, DT_TETFBlood, CTETFBlood) |
|
RecvPropFloat( RECVINFO( m_vecOrigin[0] ) ), |
|
RecvPropFloat( RECVINFO( m_vecOrigin[1] ) ), |
|
RecvPropFloat( RECVINFO( m_vecOrigin[2] ) ), |
|
RecvPropVector( RECVINFO(m_vecNormal)), |
|
RecvPropInt( "entindex", 0, SIZEOF_IGNORE, 0, RecvProxy_BloodEntIndex ), |
|
END_RECV_TABLE() |
|
|
|
|
|
|
|
|