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

📄 tf_shield_mobile_shared.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//=========== (C) Copyright 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:			The Escort's Shield weapon
//
// $Revision: $
// $NoKeywords: $
//=============================================================================

#include "cbase.h"
#include "in_buttons.h"
#include "tf_shieldshared.h"
#include "tf_shareddefs.h"
#include "baseentity_shared.h"

#if defined( CLIENT_DLL )

#include "c_shield.h"

#else

#include "tf_shield.h"
#include "gamerules.h"

#endif


#if defined( CLIENT_DLL )
#define CShieldMobile C_ShieldMobile
#define CShield C_Shield
#endif


//-----------------------------------------------------------------------------
// ConVars
//-----------------------------------------------------------------------------
ConVar	shield_mobile_power( "shield_mobile_power","30", FCVAR_REPLICATED, "Max power level of a escort's mobile projected shield." );
ConVar	shield_mobile_recharge_delay( "shield_mobile_recharge_delay","0.1", FCVAR_REPLICATED, "Time after taking damage before mobile projected shields begin to recharge." );
ConVar	shield_mobile_recharge_amount( "shield_mobile_recharge_amount","2", FCVAR_REPLICATED, "Power recharged each recharge tick for mobile projected shields." );
ConVar	shield_mobile_recharge_time( "shield_mobile_recharge_time","0.5", FCVAR_REPLICATED, "Time between each recharge tick for mobile projected shields." );


#define EMP_WAVE_AMPLITUDE 8.0f


//-----------------------------------------------------------------------------
// Mobile version of the shield 
//-----------------------------------------------------------------------------
class CShieldMobile;
class CShieldMobileActiveVertList : public IActiveVertList
{
public:
	void			Init( CShieldMobile *pShield );

// IActiveVertList overrides.
public:

	virtual int		GetActiveVertState( int iVert );
	virtual void	SetActiveVertState( int iVert, int bOn );

private:
	CShieldMobile	*m_pShield;
};


//-----------------------------------------------------------------------------
// Mobile version of the shield 
//-----------------------------------------------------------------------------
class CShieldMobile : public CShield, public IEntityEnumerator
{
	DECLARE_CLASS( CShieldMobile, CShield );

public:
	DECLARE_NETWORKCLASS();
	DECLARE_PREDICTABLE();

	friend class CShieldMobileActiveVertList;

	CShieldMobile();

#ifndef CLIENT_DLL
	DECLARE_DATADESC();
#endif

public:
	void Spawn( void );
	void Precache( void );
	void ShieldThink( void );
	virtual void ClientThink();
	virtual void SetAngularSpringConstant( float flConstant );
	virtual void SetFrontDistance( float flDistance );

	virtual void SetAttachmentIndex( int nAttachmentIndex );
	virtual void SetEMPed( bool isEmped );
	virtual void SetAlwaysOrient( bool bOrient );
 	virtual bool IsAlwaysOrienting( );

	virtual int Width();
	virtual int Height();
	virtual bool IsPanelActive( int x, int y );
	virtual const Vector& GetPoint( int x, int y );
	virtual void SetCenterAngles( const QAngle& angles );
	virtual void SetThetaPhi( float flTheta, float flPhi );

	// Computes a surrounding box the the entity
	virtual void SetObjectCollisionBox( void );

	// All predicted weapons need to implement and return true
	virtual bool IsPredicted( void ) const
	{ 
		return true;
	}

public:
#ifdef CLIENT_DLL
	virtual void OnDataChanged( DataUpdateType_t updateType );
	virtual void GetBounds( Vector& mins, Vector& maxs );
	virtual void AddEntity( );
	virtual void GetShieldData( const Vector** ppVerts, float* pOpacity, float* pBlend );

	virtual bool	ShouldPredict( void )
	{
		if ( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() )
			return true;

		return BaseClass::ShouldPredict();
	}

#endif

public:
	// Inherited from IEntityEnumerator
	virtual bool EnumEntity( IHandleEntity *pHandleEntity ); 

private:
	// Teleport!
	void OnTeleported(  );
	void SimulateShield( void );

private:
	struct SweepContext_t
	{
		SweepContext_t( const CBaseEntity *passentity, int collisionGroup ) :
			m_Filter( passentity, collisionGroup ) {}

		CTraceFilterSimple m_Filter;
		Vector m_vecStartDelta;
		Vector m_vecEndDelta;
	};

	enum
	{
		NUM_SUBDIVISIONS = 21,
	};

	enum
	{
		SHIELD_ORIENT_TO_OWNER = 0x2
	};

private:
	CShieldMobile( const CShieldMobile & );
	void ComputeBoundingBox( void );
	void DetermineObstructions( );

private:
#ifdef CLIENT_DLL
	// Is a particular panel an edge?
	bool IsVertexValid( float s, float t ) const;
	void PreRender( );
#endif

private:
	CShieldMobileActiveVertList	m_VertList;
	QAngle m_tmpAngLockedAngles;

	// Bitfield indicating which vertices are active
	CShieldEffect m_ShieldEffect;
	CNetworkArray( unsigned char, m_pVertsActive, SHIELD_NUM_CONTROL_POINTS >> 3 );
	CNetworkVar( unsigned char, m_ShieldState );
	CNetworkVar( float, m_flFrontDistance );
	CNetworkVar( QAngle, m_angLockedAngles );
	SweepContext_t *m_pEnumCtx;

	// This is the width + height of the shield, not the current theta, phi
	CNetworkVar( float, m_flShieldTheta );
	CNetworkVar( float, m_flShieldPhi );
	CNetworkVar( float, m_flSpringConstant );
	CNetworkVar( int, m_nAttachmentIndex );
};


//=============================================================================
// Shield effect
//=============================================================================
#ifndef CLIENT_DLL

BEGIN_DATADESC( CShieldMobile )

	DEFINE_THINKFUNC( CShieldMobile, ShieldThink ),

END_DATADESC()

#endif

LINK_ENTITY_TO_CLASS( shield_mobile, CShieldMobile );

IMPLEMENT_NETWORKCLASS_ALIASED( ShieldMobile, DT_ShieldMobile );

// -------------------------------------------------------------------------------- //
// This data only gets sent to clients that ARE this player entity.
// -------------------------------------------------------------------------------- //

BEGIN_NETWORK_TABLE(CShieldMobile, DT_ShieldMobile)
#if !defined( CLIENT_DLL )
	SendPropInt		(SENDINFO(m_ShieldState),	2, SPROP_UNSIGNED ),
	SendPropArray(
		SendPropInt( SENDINFO_ARRAY(m_pVertsActive), 8, SPROP_UNSIGNED),
		m_pVertsActive),

	SendPropFloat( SENDINFO(m_flFrontDistance), 0, SPROP_NOSCALE ),
	SendPropFloat( SENDINFO(m_flShieldTheta), 0, SPROP_NOSCALE ),
	SendPropFloat( SENDINFO(m_flShieldPhi), 0, SPROP_NOSCALE ),
	SendPropFloat( SENDINFO(m_flSpringConstant), 0, SPROP_NOSCALE ),
	SendPropQAngles( SENDINFO(m_angLockedAngles), 9 ),
	SendPropInt	(SENDINFO(m_nAttachmentIndex),	10, SPROP_UNSIGNED ),

	// Don't bother sending these, they are totally controlled by the think function
	SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ),
	SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[0]" ),
	SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[1]" ),
	SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[2]" ),

#else
	RecvPropInt( RECVINFO(m_ShieldState) ),
	RecvPropArray( 
		RecvPropInt( RECVINFO(m_pVertsActive[0])), 
		m_pVertsActive 
	),
	RecvPropFloat( RECVINFO(m_flFrontDistance) ),
	RecvPropFloat( RECVINFO(m_flShieldTheta) ),
	RecvPropFloat( RECVINFO(m_flShieldPhi) ),
	RecvPropFloat( RECVINFO(m_flSpringConstant) ),
	RecvPropQAngles( RECVINFO( m_angLockedAngles ) ),
	RecvPropInt	(RECVINFO(m_nAttachmentIndex) ),
#endif

END_NETWORK_TABLE()


BEGIN_PREDICTION_DATA( CShieldMobile )

	DEFINE_PRED_FIELD( CShieldMobile, m_ShieldState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
	DEFINE_PRED_FIELD( CShieldMobile, m_flFrontDistance, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
	DEFINE_PRED_FIELD( CShieldMobile, m_angLockedAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
	DEFINE_PRED_TYPEDESCRIPTION( CShieldMobile, m_ShieldEffect, CShieldEffect ),
	DEFINE_FIELD( CShieldMobile, m_nNextThinkTick, FIELD_INTEGER ),
	DEFINE_FIELD( CShieldMobile, m_tmpAngLockedAngles, FIELD_VECTOR ),

	// FIXME: How can I make this work now that I have an embedded collision property?
//	DEFINE_PRED_FIELD( CShieldMobile, m_vecMins, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
//	DEFINE_PRED_FIELD( CShieldMobile, m_vecMaxs, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),

#ifdef CLIENT_DLL
	DEFINE_PRED_FIELD( CShieldMobile, m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
	DEFINE_PRED_FIELD( CShieldMobile, m_angNetworkAngles, FIELD_VECTOR, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
#endif

END_PREDICTION_DATA()


	
//-----------------------------------------------------------------------------
// CShieldMobileActiveVertList functions
//-----------------------------------------------------------------------------
void CShieldMobileActiveVertList::Init( CShieldMobile *pShield )
{
	m_pShield = pShield;
}


int CShieldMobileActiveVertList::GetActiveVertState( int iVert )
{
	return m_pShield->m_pVertsActive[iVert>>3] & (1 << (iVert & 7));
}


void CShieldMobileActiveVertList::SetActiveVertState( int iVert, int bOn )
{
	m_pShield->NetworkStateChanged();

	unsigned char val;	
	if ( bOn )
		val = m_pShield->m_pVertsActive[iVert>>3] | (1 << (iVert & 7));
	else
		val = m_pShield->m_pVertsActive[iVert>>3] & ~(1 << (iVert & 7));

	m_pShield->m_pVertsActive.Set( iVert>>3, val );
}


//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CShieldMobile::CShieldMobile()
{
	SetPredictionEligible( true );
	m_VertList.Init( this );
	m_flFrontDistance = 0;
	SetAngularSpringConstant( 2.0f );
	SetThetaPhi( SHIELD_INITIAL_THETA, SHIELD_INITIAL_PHI ); 
	m_nAttachmentIndex = 0;

#ifdef CLIENT_DLL
	InitShield( SHIELD_NUM_HORIZONTAL_POINTS, SHIELD_NUM_VERTICAL_POINTS, NUM_SUBDIVISIONS );
#endif
}


//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldMobile::Precache( void )
{
	m_ShieldEffect.SetActiveVertexList( &m_VertList );
	m_ShieldEffect.SetCollisionGroup( TFCOLLISION_GROUP_SHIELD );
	BaseClass::Precache();
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CShieldMobile::Spawn( void )
{
	Precache();
	BaseClass::Spawn();

//	Assert( GetOwnerEntity() );
	m_angLockedAngles.Set( vec3_angle );
	m_tmpAngLockedAngles = vec3_angle;
	m_ShieldEffect.Spawn(GetAbsOrigin(), GetAbsAngles());
	m_ShieldState = 0;
	SetAlwaysOrient( true );

	// All movement occurs during think
	SetMoveType( MOVETYPE_NONE );

	SetThink( ShieldThink );
	SetNextThink( gpGlobals->curtime + 0.01f );

#ifdef CLIENT_DLL
	// This goofiness is required so that non-predicted entities work
	SetNextClientThink( CLIENT_THINK_ALWAYS );
#endif
}


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CShieldMobile::SetAlwaysOrient( bool bOrient ) 
{
	if (bOrient)
	{
		m_ShieldState.Set( m_ShieldState.Get() | SHIELD_ORIENT_TO_OWNER );
	}
	else
	{
		m_angLockedAngles.Set( m_tmpAngLockedAngles );
		m_ShieldState.Set( m_ShieldState.Get() & (~SHIELD_ORIENT_TO_OWNER) );
	}
}

int CShieldMobile::Width()
{ 
	return SHIELD_NUM_HORIZONTAL_POINTS; 
}

int CShieldMobile::Height()
{ 
	return SHIELD_NUM_VERTICAL_POINTS; 
}

const Vector& CShieldMobile::GetPoint( int x, int y )
{ 
	return m_ShieldEffect.GetPoint( x, y ); 
}

	
void CShieldMobile::SetAttachmentIndex( int nAttachmentIndex )
{
	m_nAttachmentIndex = nAttachmentIndex;
}

//-----------------------------------------------------------------------------
// Return true if the panel is active 
//-----------------------------------------------------------------------------
bool CShieldMobile::IsPanelActive( int x, int y )
{
	return m_ShieldEffect.IsPanelActive(x, y);
}


//-----------------------------------------------------------------------------
// Called when the shield is EMPed
//-----------------------------------------------------------------------------
void CShieldMobile::SetEMPed( bool isEmped )
{
	CShield::SetEMPed(isEmped);
	if (IsEMPed())
		m_ShieldState |= SHIELD_MOBILE_EMP;
	else
		m_ShieldState &= ~SHIELD_MOBILE_EMP;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -