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.
181 lines
5.4 KiB
181 lines
5.4 KiB
5 years ago
|
//========= 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()
|
||
|
|
||
|
|
||
|
|