📄 c_shield.cpp
字号:
//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: Client's sheild entity
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "C_Shield.h"
#include "ClientEffectPrecacheSystem.h"
#include "clientmode.h"
#include "ParseMsg.h"
#include "materialsystem/IMesh.h"
#include "mapdata.h"
#include "IVRenderView.h"
#include "tf_shareddefs.h"
#include "collisionutils.h"
#include "FunctionProxy.h"
// Precache the effects
CLIENTEFFECT_REGISTER_BEGIN( Shield )
CLIENTEFFECT_MATERIAL( "shadertest/wireframevertexcolor" )
CLIENTEFFECT_MATERIAL( "effects/shield/shield" )
CLIENTEFFECT_MATERIAL( "effects/shieldhit" )
CLIENTEFFECT_MATERIAL( "effects/shieldpass" )
CLIENTEFFECT_MATERIAL( "effects/shieldpass2" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Stores a list of all active shields
//-----------------------------------------------------------------------------
CUtlVector< C_Shield* > C_Shield::s_Shields;
//-----------------------------------------------------------------------------
// Various important constants:
//-----------------------------------------------------------------------------
#define SHIELD_DAMAGE_CHANGE_FIRST_PASS_TIME 0.3f
#define SHIELD_DAMAGE_CHANGE_TRANSITION_TIME 0.5f
#define SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME (SHIELD_DAMAGE_CHANGE_TIME - SHIELD_DAMAGE_CHANGE_TRANSITION_TIME)
#define SHIELD_DAMAGE_CHANGE_TOTAL_TIME (SHIELD_DAMAGE_CHANGE_TRANSITION_START_TIME + SHIELD_DAMAGE_CHANGE_TRANSITION_TIME)
#define SHIELD_TRANSITION_MAX_BLEND_AMT 0.2f
//-----------------------------------------------------------------------------
// Data table
//-----------------------------------------------------------------------------
//EXTERN_RECV_TABLE(DT_BaseEntity);
IMPLEMENT_CLIENTCLASS_DT(C_Shield, DT_Shield, CShield)
RecvPropInt( RECVINFO(m_nOwningPlayerIndex) ),
RecvPropFloat( RECVINFO(m_flPowerLevel) ),
RecvPropInt( RECVINFO(m_bIsEMPed) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Shield color for the various protection types
//-----------------------------------------------------------------------------
static unsigned char s_ImpactDecalColor[3] = { 0, 0, 255 };
// ----------------------------------------------------------------------------
// Functions.
// ----------------------------------------------------------------------------
C_Shield::C_Shield()
{
m_pWireframe.Init( "shadertest/wireframevertexcolor" );
m_pShield.Init( "effects/shield/shield" );
m_pHitDecal.Init( "effects/shieldhit" );
m_pPassDecal.Init( "effects/shieldpass" );
m_pPassDecal2.Init( "effects/shieldpass2" );
m_FadeValue = 1.0f;
m_CurveValue = 1.0f;
m_bCollisionsActive = true;
s_Shields.AddToTail(this);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_Shield::~C_Shield()
{
int i = s_Shields.Find(this);
if ( i >= 0 )
{
s_Shields.FastRemove(i);
}
}
//-----------------------------------------------------------------------------
// Inherited classes should call this in their constructor to indicate size...
//-----------------------------------------------------------------------------
void C_Shield::InitShield( int w, int h, int subdivisions )
{
m_SplinePatch.Init( w, h, 2 );
m_SubdivisionCount = subdivisions;
Assert( m_SubdivisionCount > 1 );
m_InvSubdivisionCount = 1.0f / (m_SubdivisionCount - 1);
}
//-----------------------------------------------------------------------------
// This is called after a network update
//-----------------------------------------------------------------------------
void C_Shield::OnDataChanged( DataUpdateType_t updateType )
{
if (updateType == DATA_UPDATE_CREATED)
{
m_StartTime = engine->GetLastTimeStamp();
}
BaseClass::OnDataChanged( updateType );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : collisionGroup -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_Shield::ShouldCollide( int collisionGroup, int contentsMask ) const
{
return m_bCollisionsActive && ((collisionGroup == TFCOLLISION_GROUP_WEAPON) || (collisionGroup == TFCOLLISION_GROUP_GRENADE));
}
//-----------------------------------------------------------------------------
// Should I draw?
//-----------------------------------------------------------------------------
bool C_Shield::ShouldDraw()
{
// Let the client mode (like commander mode) reject drawing entities.
if (g_pClientMode && !g_pClientMode->ShouldDrawEntity(this) )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Activates/deactivates a shield for collision purposes
//-----------------------------------------------------------------------------
void C_Shield::ActivateCollisions( bool activate )
{
m_bCollisionsActive = activate;
}
//-----------------------------------------------------------------------------
// Activates all shields
//-----------------------------------------------------------------------------
void C_Shield::ActivateShields( bool activate, int team )
{
for (int i = s_Shields.Count(); --i >= 0; )
{
// Activate all shields on the same team
if ( (team == -1) || (team == s_Shields[i]->GetTeamNumber()) )
{
s_Shields[i]->ActivateCollisions( activate );
}
}
}
//-----------------------------------------------------------------------------
// Helper method for collision testing
//-----------------------------------------------------------------------------
#pragma warning ( disable : 4701 )
bool C_Shield::TestCollision( const Ray_t& ray, unsigned int mask, trace_t& trace )
{
// Can't block anything if we're EMPed, or we've got no power left to block
if ( m_bIsEMPed )
return false;
if ( m_flPowerLevel <= 0 )
return false;
// Here, we're gonna test for collision.
// If we don't stop this kind of bullet, we'll generate an effect here
// but we won't change the trace to indicate a collision.
// It's just polygon soup...
int hitgroup;
bool firstTri;
int v1[2], v2[2], v3[2];
float ihit, jhit;
float mint = FLT_MAX;
float t;
int h = Height();
int w = Width();
for (int i = 0; i < h - 1; ++i)
{
for (int j = 0; j < w - 1; ++j)
{
// Don't test if this panel ain't active...
if (!IsPanelActive( j, i ))
continue;
// NOTE: Structure order of points so that our barycentric
// axes for each triangle are along the (u,v) directions of the mesh
// The barycentric coords we'll need below
// Two triangles per quad...
t = IntersectRayWithTriangle( ray,
GetPoint( j, i + 1 ),
GetPoint( j + 1, i + 1 ),
GetPoint( j, i ), true );
if ((t >= 0.0f) && (t < mint))
{
mint = t;
v1[0] = j; v1[1] = i + 1;
v2[0] = j + 1; v2[1] = i + 1;
v3[0] = j; v3[1] = i;
ihit = i; jhit = j;
firstTri = true;
}
t = IntersectRayWithTriangle( ray,
GetPoint( j + 1, i ),
GetPoint( j, i ),
GetPoint( j + 1, i + 1 ), true );
if ((t >= 0.0f) && (t < mint))
{
mint = t;
v1[0] = j + 1; v1[1] = i;
v2[0] = j; v2[1] = i;
v3[0] = j + 1; v3[1] = i + 1;
ihit = i; jhit = j;
firstTri = false;
}
}
}
if (mint == FLT_MAX)
return false;
// Stuff the barycentric coordinates of the triangle hit into the hit group
// For the first triangle, the first edge goes along u, the second edge goes
// along -v. For the second triangle, the first edge goes along -u,
// the second edge goes along v.
const Vector& v1vec = GetPoint(v1[0], v1[1]);
const Vector& v2vec = GetPoint(v2[0], v2[1]);
const Vector& v3vec = GetPoint(v3[0], v3[1]);
float u, v;
bool ok = ComputeIntersectionBarycentricCoordinates( ray,
v1vec, v2vec, v3vec, u, v );
Assert( ok );
if ( !ok )
{
return false;
}
if (firstTri)
v = 1.0 - v;
else
u = 1.0 - u;
v += ihit; u += jhit;
v /= (h - 1);
u /= (w - 1);
// Compress (u,v) into 1 dot 15, v in top bits
hitgroup = (((int)(v * (1 << 15))) << 16) + (int)(u * (1 << 15));
Vector normal;
float intercept;
ComputeTrianglePlane( v1vec, v2vec, v3vec, normal, intercept );
UTIL_SetTrace( trace, ray, this, mint, hitgroup, CONTENTS_SOLID, normal, intercept );
return true;
}
#pragma warning ( default : 4701 )
//-----------------------------------------------------------------------------
// Called when we hit something that we deflect...
//-----------------------------------------------------------------------------
void C_Shield::RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr)
{
Vector normalDir;
VectorCopy( vecDir, normalDir );
VectorNormalize( normalDir );
CreateShieldDeflection( ptr->hitgroup, normalDir, false );
}
//-----------------------------------------------------------------------------
// This is required to get all the decals to animate correctly
//-----------------------------------------------------------------------------
void C_Shield::SetCurrentDecal( int idx )
{
m_CurrentDecal = idx;
}
//-----------------------------------------------------------------------------
// returns the address of a variable that stores the material animation frame
//-----------------------------------------------------------------------------
float C_Shield::GetTextureAnimationStartTime()
{
if( m_CurrentDecal == -1 )
return m_StartTime;
return m_Decals[m_CurrentDecal].m_StartTime;
}
//-----------------------------------------------------------------------------
// Indicates that a texture animation has wrapped
//-----------------------------------------------------------------------------
void C_Shield::TextureAnimationWrapped()
{
if( m_CurrentDecal != -1 )
{
m_Decals[m_CurrentDecal].m_StartTime = -1.0f;
}
}
//-----------------------------------------------------------------------------
// Indicates a collision occurred:
//-----------------------------------------------------------------------------
void C_Shield::ReceiveMessage( const char *msgname, int length, void *data )
{
int hitgroup;
Vector dir;
unsigned char partialBlock;
BEGIN_READ( data, length );
hitgroup = READ_LONG( );
READ_VEC3NORMAL( dir );
partialBlock = READ_BYTE( );
CreateShieldDeflection( hitgroup, dir, partialBlock );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_Shield::CreateShieldDeflection( int hitgroup, const Vector &dir, bool partialBlock )
{
float hitU = (float)(hitgroup & 0xFFFF) / (float)(1 << 15);
float hitV = (float)(hitgroup >> 16) / (float)(1 << 15);
Ripple_t ripple;
ripple.m_RippleU = hitU;
ripple.m_RippleV = hitV;
ripple.m_Amplitude = partialBlock ? 4 : 30;
ripple.m_Radius = 0.08f;
ripple.m_StartTime = engine->GetLastTimeStamp();
ripple.m_Direction = dir;
m_Ripples.AddToTail(ripple);
Decal_t decal;
decal.m_RippleU = hitU;
decal.m_RippleV = hitV;
decal.m_Radius = partialBlock ? 0.03f : 0.08f;
decal.m_StartTime = engine->GetLastTimeStamp();
m_Decals.AddToTail(decal);
}
//-----------------------------------------------------------------------------
// Draws the control points in wireframe
//-----------------------------------------------------------------------------
void C_Shield::DrawWireframeModel( Vector const** ppPositions )
{
IMesh* pMesh = materials->GetDynamicMesh( true, NULL, NULL, m_pWireframe );
int numLines = (Height() - 1) * Width() + Height() * (Width() - 1);
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_LINES, numLines );
Vector const* tmp;
for (int i = 0; i < Height(); ++i)
{
for (int j = 0; j < Width(); ++j)
{
if ( i > 0 )
{
tmp = ppPositions[j + Width() * i];
meshBuilder.Position3fv( tmp->Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
tmp = ppPositions[j + Width() * (i-1)];
meshBuilder.Position3fv( tmp->Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
}
if (j > 0)
{
tmp = ppPositions[j + Width() * i];
meshBuilder.Position3fv( tmp->Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
tmp = ppPositions[j - 1 + Width() * i];
meshBuilder.Position3fv( tmp->Base() );
meshBuilder.Color4ub( 255, 255, 255, 128 );
meshBuilder.AdvanceVertex();
}
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Draws the base shield
//-----------------------------------------------------------------------------
#define TRANSITION_REGION_WIDTH 0.5f
extern ConVar mat_wireframe;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -