⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c_shield.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//======== (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 + -