diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf2/tf_shield_mobile_shared.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf2/tf_shield_mobile_shared.cpp')
| -rw-r--r-- | game/shared/tf2/tf_shield_mobile_shared.cpp | 850 |
1 files changed, 850 insertions, 0 deletions
diff --git a/game/shared/tf2/tf_shield_mobile_shared.cpp b/game/shared/tf2/tf_shield_mobile_shared.cpp new file mode 100644 index 0000000..e5d153b --- /dev/null +++ b/game/shared/tf2/tf_shield_mobile_shared.cpp @@ -0,0 +1,850 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// 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 ComputeWorldSpaceSurroundingBox( Vector *pWorldMins, Vector *pWorldMaxs ); + + 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 ); + + virtual void GetRenderBounds( Vector& mins, Vector& maxs ); + + // 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( 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( m_ShieldState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_flFrontDistance, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_angLockedAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_TYPEDESCRIPTION( m_ShieldEffect, CShieldEffect ), + DEFINE_FIELD( m_nNextThinkTick, FIELD_INTEGER ), + DEFINE_FIELD( m_tmpAngLockedAngles, FIELD_VECTOR ), + + // FIXME: How can I make this work now that I have an embedded collision property? +// DEFINE_PRED_FIELD( m_vecMins, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ), +// DEFINE_PRED_FIELD( m_vecMaxs, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ), + +#ifdef CLIENT_DLL + DEFINE_PRED_FIELD( m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ), + DEFINE_PRED_FIELD( 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 ) +{ + 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(); + AddSolidFlags( FSOLID_FORCE_WORLD_ALIGNED ); + +// 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; +} + + +//----------------------------------------------------------------------------- +// Returns the render bounds +//----------------------------------------------------------------------------- +void CShieldMobile::GetRenderBounds( Vector& mins, Vector& maxs ) +{ + mins = m_ShieldEffect.GetRenderMins(); + maxs = m_ShieldEffect.GetRenderMaxs(); +} + +//----------------------------------------------------------------------------- +// 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; +} + + +//----------------------------------------------------------------------------- +// Set the shield angles +//----------------------------------------------------------------------------- +void CShieldMobile::SetCenterAngles( const QAngle& angles ) +{ + // The tmp ang locked angles is simply there to prevent unnecessary network traffic + m_tmpAngLockedAngles = angles; + if ( ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) == 0 ) + { + m_angLockedAngles.Set( angles ); + } +} + +bool CShieldMobile::IsAlwaysOrienting( ) +{ + return ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) != 0; +} + +void CShieldMobile::SetAngularSpringConstant( float flConstant ) +{ + m_flSpringConstant = flConstant; + m_ShieldEffect.SetAngularSpringConstant( flConstant ); +} + +void CShieldMobile::SetFrontDistance( float flDistance ) +{ + m_flFrontDistance = flDistance; +} + +void CShieldMobile::SetThetaPhi( float flTheta, float flPhi ) +{ + // This sets the bounds of the shield; how tall + wide is it? + m_flShieldTheta = flTheta; + m_flShieldPhi = flPhi; + m_ShieldEffect.SetThetaPhi(flTheta, flPhi); +} + + +//----------------------------------------------------------------------------- +// Computes the shield bounding box +//----------------------------------------------------------------------------- +void CShieldMobile::ComputeBoundingBox( void ) +{ + Vector mins, maxs; + m_ShieldEffect.ComputeBounds(mins, maxs); + SetCollisionBounds( mins, maxs ); +} + + +//----------------------------------------------------------------------------- +// Compute world axis-aligned bounding box +//----------------------------------------------------------------------------- +void CShieldMobile::ComputeWorldSpaceSurroundingBox( Vector *pWorldMins, Vector *pWorldMaxs ) +{ + // We don't use USE_SPECIFIED_BOUNDS because that would generate a ton of network traffic + VectorAdd( CollisionProp()->GetCollisionOrigin(), CollisionProp()->OBBMins(), *pWorldMins ); + VectorAdd( CollisionProp()->GetCollisionOrigin(), CollisionProp()->OBBMaxs(), *pWorldMaxs ); +} + + +//----------------------------------------------------------------------------- +// Determines shield obstructions +//----------------------------------------------------------------------------- +void CShieldMobile::DetermineObstructions( ) +{ + m_ShieldEffect.ComputeVertexActivity(); +} + + +//----------------------------------------------------------------------------- +// Called by the enumerator call in ShieldThink +//----------------------------------------------------------------------------- +bool CShieldMobile::EnumEntity( IHandleEntity *pHandleEntity ) +{ +#ifdef CLIENT_DLL + CBaseEntity *pOther = cl_entitylist->GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); +#else + CBaseEntity *pOther = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() ); +#endif + + if (!pOther) + return true; + + // Blow off non-solid things + if ( !::IsSolid(pOther->GetSolid(), pOther->GetSolidFlags()) ) + return true; + + // No model, blow it off + if ( !pOther->GetModelIndex() ) + return true; + + // Blow off point-sized things.... + if ( pOther->IsPointSized() ) + return true; + + // Don't bother if we shouldn't be colliding with this guy... + if (!m_pEnumCtx->m_Filter.ShouldHitEntity( pOther, MASK_SOLID )) + return true; + + // The shield is in its final position, so we're gonna have to determine the + // point of collision by working in the space of the final position.... + // We do this by moving the obstruction by the relative movement amount... + Vector vecObsMins, vecObsMaxs, vecObsCenter; + pOther->CollisionProp()->WorldSpaceAABB( &vecObsMins, &vecObsMaxs ); + vecObsCenter = (vecObsMins + vecObsMaxs) * 0.5f; + vecObsMins -= vecObsCenter; + vecObsMaxs -= vecObsCenter; + + Vector vecStart, vecEnd; + VectorAdd( vecObsCenter, m_pEnumCtx->m_vecStartDelta, vecStart ); + VectorAdd( vecStart, m_pEnumCtx->m_vecEndDelta, vecEnd ); + + + Ray_t ray; + ray.Init( vecStart, vecEnd, vecObsMins, vecObsMaxs ); + + trace_t tr; + if (TestCollision( ray, pOther->PhysicsSolidMaskForEntity(), tr )) + { + // Ok, we got a collision. Let's indicate it happened... + // At the moment, we'll report the collision point as being on the + // surface of the shield in its final position, which is kind of bogus... + pOther->PhysicsImpact( this, tr ); + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Update the shield position: +//----------------------------------------------------------------------------- +void CShieldMobile::SimulateShield( void ) +{ + CBaseEntity *owner = GetOwnerEntity(); + Vector origin; + if ( owner ) + { + if ( m_ShieldState & SHIELD_ORIENT_TO_OWNER ) + { + if ( owner->IsPlayer() ) + { + m_ShieldEffect.SetDesiredAngles( owner->EyeAngles() ); + } + else + { + m_ShieldEffect.SetDesiredAngles( owner->GetAbsAngles() ); + } + } + else + { + m_ShieldEffect.SetDesiredAngles( m_angLockedAngles ); + } + + if ( m_nAttachmentIndex == 0 ) + { + origin = owner->EyePosition(); + } + else + { + QAngle angles; + CBaseAnimating *pAnim = dynamic_cast<CBaseAnimating*>( owner ); + if (pAnim) + { + pAnim->GetAttachment( m_nAttachmentIndex, origin, angles ); + } + else + { + origin = owner->EyePosition(); + } + } + + if ( m_flFrontDistance ) + { + Vector vForward; + AngleVectors( m_ShieldEffect.GetDesiredAngles(), &vForward ); + origin += vForward * m_flFrontDistance; + } + } + else + { + Assert( 0 ); + origin = vec3_origin; + } + + // We pretty much always need to recompute this + CollisionProp()->MarkSurroundingBoundsDirty(); + + Vector vecOldOrigin = m_ShieldEffect.GetCurrentPosition(); + + Vector vecDelta; + VectorSubtract( origin, vecOldOrigin, vecDelta ); + + float flMaxDist = 100 + m_flFrontDistance; + if (vecDelta.LengthSqr() > flMaxDist * flMaxDist ) + { + OnTeleported(); + return; + } + + m_ShieldEffect.SetDesiredOrigin( origin ); + m_ShieldEffect.Simulate(gpGlobals->frametime); + DetermineObstructions(); + SetAbsOrigin( m_ShieldEffect.GetCurrentPosition() ); + SetAbsAngles( m_ShieldEffect.GetCurrentAngles() ); + +#ifdef CLIENT_DLL + // Necessary because we exclude the network origin + SetNetworkOrigin( m_ShieldEffect.GetCurrentPosition() ); + SetNetworkAngles( m_ShieldEffect.GetCurrentAngles() ); +#endif + + // Compute a composite bounding box surrounding the initial + new positions.. + Vector vecCompositeMins = WorldAlignMins() + vecOldOrigin; + Vector vecCompositeMaxs = WorldAlignMaxs() + vecOldOrigin; + + ComputeBoundingBox(); + + // Sweep the shield through the world + touch things it hits... + SweepContext_t ctx( this, GetCollisionGroup() ); + VectorSubtract( GetAbsOrigin(), vecOldOrigin, ctx.m_vecStartDelta ); + + if (ctx.m_vecStartDelta != vec3_origin) + { + // FIXME: Brutal hack; needed because IntersectRayWithTriangle misses stuff + // especially with short rays; I'm not sure what to do about this. + // This basically simulates a shield thickness of 15 units + ctx.m_vecEndDelta = ctx.m_vecStartDelta; + VectorNormalize( ctx.m_vecEndDelta ); + ctx.m_vecEndDelta *= -15.0f; + + Vector vecNewMins = WorldAlignMins() + GetAbsOrigin(); + Vector vecNewMaxs = WorldAlignMaxs() + GetAbsOrigin(); + VectorMin( vecCompositeMins, vecNewMins, vecCompositeMins ); + VectorMax( vecCompositeMaxs, vecNewMaxs, vecCompositeMaxs ); + + m_pEnumCtx = &ctx; + enginetrace->EnumerateEntities( vecCompositeMins, vecCompositeMaxs, this ); + } +} + + +//----------------------------------------------------------------------------- +// Update the shield position: +//----------------------------------------------------------------------------- +void CShieldMobile::ShieldThink( void ) +{ + SimulateShield(); + +#ifdef CLIENT_DLL + m_ShieldEffect.ComputeControlPoints(); + m_ShieldEffect.ComputePanelActivity(); +#endif + + SetNextThink( gpGlobals->curtime + 0.01f ); +} + +void CShieldMobile::ClientThink() +{ +#ifdef CLIENT_DLL + if ( GetPredictable() ) + return; + + SimulateShield(); + m_ShieldEffect.ComputeControlPoints(); + m_ShieldEffect.ComputePanelActivity(); +#endif +} + + +//----------------------------------------------------------------------------- +// Teleport! +//----------------------------------------------------------------------------- +void CShieldMobile::OnTeleported( ) +{ + CBaseEntity *owner = GetOwnerEntity(); + if (!owner) + return; + + m_ShieldEffect.SetCurrentAngles( owner->GetAbsAngles() ); + + Vector origin; + origin = owner->EyePosition(); + if ( m_flFrontDistance ) + { + Vector vForward; + AngleVectors( m_ShieldEffect.GetCurrentAngles(), &vForward ); + origin += vForward * m_flFrontDistance; + } + + m_ShieldEffect.SetCurrentPosition( origin ); +} + + + +#ifdef CLIENT_DLL + +//----------------------------------------------------------------------------- +// Get this after the data changes +//----------------------------------------------------------------------------- +void CShieldMobile::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + m_ShieldEffect.SetThetaPhi( m_flShieldTheta, m_flShieldPhi ); + m_ShieldEffect.SetAngularSpringConstant( m_flSpringConstant ); +} + + +//----------------------------------------------------------------------------- +// 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, 0, 0 ); + + // 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 CShieldMobile::AddEntity( ) +{ + BaseClass::AddEntity( ); + PreRender(); +} + + +//----------------------------------------------------------------------------- +// Bounds computation +//----------------------------------------------------------------------------- +void CShieldMobile::GetBounds( Vector& mins, Vector& maxs ) +{ + m_ShieldEffect.ComputeBounds( mins, maxs ); +} + + +//----------------------------------------------------------------------------- +// Gets at the control point data; who knows how it was made? +//----------------------------------------------------------------------------- +void CShieldMobile::GetShieldData( const Vector** 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; + } + } +} + + +#endif // CLIENT_DLL + + +#ifndef CLIENT_DLL + +//----------------------------------------------------------------------------- +// Purpose: Create a mobile version of the shield +//----------------------------------------------------------------------------- +CShield *CreateMobileShield( CBaseEntity *owner, float flFrontDistance ) +{ + CShieldMobile *pShield = (CShieldMobile*)CreateEntityByName("shield_mobile"); + + pShield->SetOwnerEntity( owner ); + pShield->SetLocalAngles( owner->GetAbsAngles() ); + pShield->SetFrontDistance( flFrontDistance ); + + // Start it in the right place + Vector vForward; + AngleVectors( owner->GetAbsAngles(), &vForward ); + Vector vecOrigin = owner->EyePosition() + (vForward * flFrontDistance); + UTIL_SetOrigin( pShield, vecOrigin ); + + pShield->ChangeTeam( owner->GetTeamNumber() ); + pShield->SetupRecharge( shield_mobile_power.GetFloat(), shield_mobile_recharge_delay.GetFloat(), shield_mobile_recharge_amount.GetFloat(), shield_mobile_recharge_time.GetFloat() ); + pShield->Spawn(); + + return pShield; +} + +#endif + |