Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

274 lines
7.5 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client's sheild entity
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "C_Shield.h"
#include "tf_shieldshared.h"
enum
{
NUM_SUBDIVISIONS = 21,
};
#define EMP_WAVE_AMPLITUDE 8.0f
//-----------------------------------------------------------------------------
// Mobile version of the shield
//-----------------------------------------------------------------------------
class C_ShieldMobile;
class C_ShieldMobileActiveVertList : public IActiveVertList
{
public:
void Init( C_ShieldMobile *pShield, unsigned char *pVertList );
// IActiveVertList overrides.
public:
virtual int GetActiveVertState( int iVert );
virtual void SetActiveVertState( int iVert, int bOn );
private:
C_ShieldMobile *m_pShield;
unsigned char *m_pVertsActive;
};
class C_ShieldMobile : public C_Shield
{
DECLARE_CLASS( C_ShieldMobile, C_Shield );
public:
DECLARE_CLIENTCLASS();
C_ShieldMobile();
~C_ShieldMobile();
void OnDataChanged( DataUpdateType_t updateType );
virtual void GetBounds( Vector& mins, Vector& maxs );
virtual void AddEntity( );
// Return true if the panel is active
virtual bool IsPanelActive( int x, int y );
// Gets at the control point data; who knows how it was made?
virtual void GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend );
virtual const Vector& GetPoint( int x, int y ) { return m_ShieldEffect.GetPoint( x, y ); }
virtual void SetThetaPhi( float flTheta, float flPhi ) { m_ShieldEffect.SetThetaPhi(flTheta,flPhi); }
public:
// networked data
unsigned char m_pVertsActive[SHIELD_VERTEX_BYTES];
unsigned char m_ShieldState;
private:
C_ShieldMobile( const C_ShieldMobile& );
// Is a particular panel an edge?
bool IsVertexValid( float s, float t ) const;
void PreRender( );
private:
CShieldEffect m_ShieldEffect;
C_ShieldMobileActiveVertList m_VertList;
float m_flTheta;
float m_flPhi;
};
//-----------------------------------------------------------------------------
// C_ShieldMobileActiveVertList functions
//-----------------------------------------------------------------------------
void C_ShieldMobileActiveVertList::Init( C_ShieldMobile *pShield, unsigned char *pVertList )
{
m_pShield = pShield;
m_pVertsActive = pVertList;
}
int C_ShieldMobileActiveVertList::GetActiveVertState( int iVert )
{
return m_pVertsActive[iVert>>3] & (1 << (iVert & 7));
}
void C_ShieldMobileActiveVertList::SetActiveVertState( int iVert, int bOn )
{
if ( bOn )
m_pVertsActive[iVert>>3] |= (1 << (iVert & 7));
else
m_pVertsActive[iVert>>3] &= ~(1 << (iVert & 7));
}
//-----------------------------------------------------------------------------
// Data table
//-----------------------------------------------------------------------------
IMPLEMENT_CLIENTCLASS_DT(C_ShieldMobile, DT_Shield_Mobile, CShieldMobile)
RecvPropInt( RECVINFO(m_ShieldState) ),
RecvPropArray(
RecvPropInt( RECVINFO(m_pVertsActive[0])),
m_pVertsActive
),
RecvPropFloat( RECVINFO(m_flTheta) ),
RecvPropFloat( RECVINFO(m_flPhi) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Various raycasting routines
//-----------------------------------------------------------------------------
void ShieldTraceLine(const Vector &vecStart, const Vector &vecEnd,
unsigned int mask, int collisionGroup, trace_t *ptr)
{
UTIL_TraceLine(vecStart, vecEnd, mask, NULL, collisionGroup, ptr );
}
void ShieldTraceHull(const Vector &vecStart, const Vector &vecEnd,
const Vector &hullMin, const Vector &hullMax,
unsigned int mask, int collisionGroup, trace_t *ptr)
{
CTraceFilterWorldOnly traceFilter;
enginetrace->TraceHull( vecStart, vecEnd, hullMin, hullMax, mask, &traceFilter, ptr );
}
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
C_ShieldMobile::C_ShieldMobile() : m_ShieldEffect(ShieldTraceLine, ShieldTraceHull)
{
m_VertList.Init( this, m_pVertsActive );
m_ShieldEffect.SetActiveVertexList( &m_VertList );
m_ShieldEffect.Spawn(vec3_origin, vec3_angle);
InitShield( SHIELD_NUM_HORIZONTAL_POINTS, SHIELD_NUM_VERTICAL_POINTS, NUM_SUBDIVISIONS );
}
C_ShieldMobile::~C_ShieldMobile()
{
}
//-----------------------------------------------------------------------------
// Get this after the data changes
//-----------------------------------------------------------------------------
void C_ShieldMobile::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_ShieldEffect.SetCurrentPosition( GetAbsOrigin() );
m_ShieldEffect.SetCurrentAngles( GetAbsAngles() );
m_ShieldEffect.SetThetaPhi( m_flTheta, m_flPhi );
// No need to simulate, just compute active panels from network data
m_ShieldEffect.ComputeControlPoints();
m_ShieldEffect.ComputePanelActivity();
}
//-----------------------------------------------------------------------------
// A little pre-render processing
//-----------------------------------------------------------------------------
void C_ShieldMobile::PreRender( )
{
if (m_ShieldState & SHIELD_MOBILE_EMP)
{
// Decay fade if we've been EMPed or if we're inactive
if (m_FadeValue > 0.0f)
{
m_FadeValue -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue < 0.0f)
{
m_FadeValue = 0.0f;
// Reset the shield to un-wobbled state
m_ShieldEffect.ComputeControlPoints();
}
else
{
Vector dir;
AngleVectors( m_ShieldEffect.GetCurrentAngles(), & dir );
// Futz with the control points if we've been EMPed
for (int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i)
{
// Get the direction for the point
float factor = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME );
m_ShieldEffect.GetPoint(i) += dir * factor;
}
}
}
}
else
{
// Fade back in, no longer EMPed
if (m_FadeValue < 1.0f)
{
m_FadeValue += gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue >= 1.0f)
{
m_FadeValue = 1.0f;
}
}
}
}
void C_ShieldMobile::AddEntity( )
{
BaseClass::AddEntity( );
PreRender();
}
//-----------------------------------------------------------------------------
// Bounds computation
//-----------------------------------------------------------------------------
void C_ShieldMobile::GetBounds( Vector& mins, Vector& maxs )
{
m_ShieldEffect.ComputeBounds( mins, maxs );
}
//-----------------------------------------------------------------------------
// Return true if the panel is active
//-----------------------------------------------------------------------------
bool C_ShieldMobile::IsPanelActive( int x, int y )
{
return m_ShieldEffect.IsPanelActive(x, y);
}
//-----------------------------------------------------------------------------
// Gets at the control point data; who knows how it was made?
//-----------------------------------------------------------------------------
void C_ShieldMobile::GetShieldData( Vector const** ppVerts, float* pOpacity, float* pBlend )
{
for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
ppVerts[i] = &m_ShieldEffect.GetControlPoint(i);
if ( m_pVertsActive[i >> 3] & (1 << (i & 0x7)) )
{
pOpacity[i] = m_ShieldEffect.ComputeOpacity( *ppVerts[i], GetAbsOrigin() );
pBlend[i] = 1.0f;
}
else
{
pOpacity[i] = 192.0f;
pBlend[i] = 0.0f;
}
}
}