📄 tf_shield_mobile_shared.cpp
字号:
//=========== (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 + -