summaryrefslogtreecommitdiff
path: root/game/server/tf2/tf_shield.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf2/tf_shield.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf2/tf_shield.cpp')
-rw-r--r--game/server/tf2/tf_shield.cpp432
1 files changed, 432 insertions, 0 deletions
diff --git a/game/server/tf2/tf_shield.cpp b/game/server/tf2/tf_shield.cpp
new file mode 100644
index 0000000..c73c092
--- /dev/null
+++ b/game/server/tf2/tf_shield.cpp
@@ -0,0 +1,432 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The Escort's Shield weapon
+//
+// $Revision: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "tf_shield.h"
+#include "tf_shareddefs.h"
+#include "collisionutils.h"
+#include <float.h>
+#include "sendproxy.h"
+#include "mathlib/mathlib.h"
+
+#define PROBE_EFFECT_TIME 0.15f
+
+ConVar shield_explosive_damage( "shield_explosive_damage","10", FCVAR_REPLICATED, "Shield power damage from explosions" );
+
+// Percentage of total health that the shield's allowed to go below 0
+#define SHIELD_MIN_HEALTH_FACTOR (-0.5)
+
+//-----------------------------------------------------------------------------
+// Stores a list of all active shields
+//-----------------------------------------------------------------------------
+CUtlVector< CShield* > CShield::s_Shields;
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the entity is a shield
+//-----------------------------------------------------------------------------
+bool IsShield( CBaseEntity *pEnt )
+{
+ // This is a faster way...
+ return pEnt && (pEnt->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD);
+// return pEnt && FClassnameIs( pEnt, "shield" )
+}
+
+
+//=============================================================================
+// Shield effect
+//=============================================================================
+EXTERN_SEND_TABLE(DT_BaseEntity)
+
+IMPLEMENT_SERVERCLASS_ST(CShield, DT_Shield)
+ SendPropInt(SENDINFO(m_nOwningPlayerIndex), MAX_EDICT_BITS, SPROP_UNSIGNED ),
+ SendPropFloat(SENDINFO(m_flPowerLevel), 9, SPROP_ROUNDUP, SHIELD_MIN_HEALTH_FACTOR, 1.0f ),
+ SendPropInt(SENDINFO(m_bIsEMPed), 1, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+//-----------------------------------------------------------------------------
+// constructor
+//-----------------------------------------------------------------------------
+CShield::CShield()
+{
+ s_Shields.AddToTail(this);
+ AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
+ SetupRecharge( 0,0,0,0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CShield::~CShield()
+{
+ int i = s_Shields.Find(this);
+ if (i >= 0)
+ s_Shields.FastRemove(i);
+}
+
+//-----------------------------------------------------------------------------
+// Precache !!
+//-----------------------------------------------------------------------------
+void CShield::Precache()
+{
+ SetClassname( "shield" );
+}
+
+//-----------------------------------------------------------------------------
+// Spawn !!
+//-----------------------------------------------------------------------------
+void CShield::Spawn( void )
+{
+ m_bIsEMPed = 0;
+ SetCollisionGroup( TFCOLLISION_GROUP_SHIELD );
+
+ // Make it translucent
+ m_nRenderFX = kRenderTransAlpha;
+ SetRenderColorA( 255 );
+
+ m_flNextRechargeTime = gpGlobals->curtime;
+
+ CollisionProp()->SetSurroundingBoundsType( USE_GAME_CODE );
+ SetSolid( SOLID_CUSTOM );
+
+ // Stuff can't come to a rest on shields!
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+ UTIL_SetSize( this, vec3_origin, vec3_origin );
+}
+
+
+//-----------------------------------------------------------------------------
+// Owner
+//-----------------------------------------------------------------------------
+void CShield::SetOwnerEntity( CBaseEntity *pOwner )
+{
+ BaseClass::SetOwnerEntity( pOwner );
+
+ if (pOwner->IsPlayer())
+ {
+ m_nOwningPlayerIndex = pOwner->entindex();
+ }
+ else
+ {
+ m_nOwningPlayerIndex = 0;
+ }
+ ChangeTeam( pOwner->GetTeamNumber() );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Does this shield protect from a particular damage type?
+//-----------------------------------------------------------------------------
+float CShield::ProtectionAmount( int damageType ) const
+{
+ // As a test, we're trying to make shields impervious to everything
+ return 1.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Activates/deactivates a shield for collision purposes
+//-----------------------------------------------------------------------------
+void CShield::ActivateCollisions( bool activate )
+{
+ if ( activate )
+ {
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+ }
+ else
+ {
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Activates all shields
+//-----------------------------------------------------------------------------
+void CShield::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 );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Checks a ray against shields only
+//-----------------------------------------------------------------------------
+bool CShield::IsBlockedByShields( const Vector& src, const Vector& end )
+{
+ trace_t tr;
+ Ray_t ray;
+ ray.Init( src, end );
+
+ for (int i = s_Shields.Count(); --i >= 0; )
+ {
+ if (!s_Shields[i]->ShouldCollide( TFCOLLISION_GROUP_WEAPON, MASK_ALL ))
+ continue;
+
+ // Coarse bbox test first
+ Vector vecAbsMins, vecAbsMaxs;
+ s_Shields[i]->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
+ if (!IsBoxIntersectingRay( vecAbsMins, vecAbsMaxs, ray.m_Start, ray.m_Delta ))
+ continue;
+
+ if (s_Shields[i]->TestCollision( ray, MASK_ALL, tr ))
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when we hit something that we deflect...
+//-----------------------------------------------------------------------------
+void CShield::RegisterDeflection(const Vector& vecDir, int bitsDamageType, trace_t *ptr)
+{
+ // Probes don't hurt shields
+ if (bitsDamageType & DMG_PROBE)
+ return;
+
+ Vector normalDir;
+ VectorCopy( vecDir, normalDir );
+ VectorNormalize( normalDir );
+
+ // Uncomment this line when the client predicts the shield deflections
+ //filter.UsePredictionRules();
+ EntityMessageBegin( this );
+ WRITE_LONG( ptr->hitgroup );
+ WRITE_VEC3NORMAL( normalDir );
+ WRITE_BYTE( false ); // This was not a partial block
+ MessageEnd();
+
+ // If this is a buckshot round, don't pay the power cost to stop it once we've gone over our max buckshot hits this frame
+ if ( bitsDamageType & DMG_BUCKSHOT )
+ {
+ m_iBuckshotHitsThisFrame++;
+ if ( m_iBuckshotHitsThisFrame > 4 )
+ return;
+ }
+
+ // If this is an explosion, it counts for extra
+ if ( bitsDamageType & DMG_BLAST )
+ {
+ SetPower( m_flPower - shield_explosive_damage.GetFloat() );
+ }
+ else
+ {
+ // Reduce our power level by a hit
+ SetPower( m_flPower - 1 );
+ }
+
+ // If we've lost power fully, don't recharge for a bit
+ if ( m_flPower <= 0 )
+ {
+ m_flNextRechargeTime = gpGlobals->curtime + 1.0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Called when we hit something that we let through...
+//-----------------------------------------------------------------------------
+void CShield::RegisterPassThru(const Vector& vecDir, int bitsDamageType, trace_t *ptr)
+{
+ // Probes don't hurt shields
+ if (bitsDamageType & DMG_PROBE)
+ return;
+
+ Vector normalDir;
+ VectorCopy( vecDir, normalDir );
+ VectorNormalize( normalDir );
+
+ EntityMessageBegin( this );
+ WRITE_LONG( ptr->hitgroup );
+ WRITE_VEC3NORMAL( normalDir );
+ WRITE_BYTE( true ); // This was a partial block
+ MessageEnd();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CShield::SetPower( float flPower )
+{
+ m_flPower = MAX( (SHIELD_MIN_HEALTH_FACTOR * m_flMaxPower), flPower );
+ if ( m_flPower > m_flMaxPower )
+ {
+ m_flPower = m_flMaxPower;
+ }
+ m_flPowerLevel = ( m_flPower / m_flMaxPower );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup shield recharging parameters
+//-----------------------------------------------------------------------------
+void CShield::SetupRecharge( float flPower, float flDelay, float flAmount, float flTickTime )
+{
+ m_flMaxPower = flPower;
+ SetPower( flPower );
+ m_flPowerLevel = 1.0;
+ m_flRechargeDelay = flDelay;
+ m_flRechargeAmount = flAmount;
+ m_flRechargeTime = flTickTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Recharge the shield if we haven't taken damage for a while
+//-----------------------------------------------------------------------------
+void CShield::Think( void )
+{
+ // Clear out buckshot count
+ m_iBuckshotHitsThisFrame = 0;
+
+ if ( m_flNextRechargeTime < gpGlobals->curtime )
+ {
+ if ( m_flPower < m_flMaxPower )
+ {
+ SetPower( m_flPower + m_flRechargeAmount );
+ }
+
+ m_flNextRechargeTime = gpGlobals->curtime + m_flRechargeTime;
+ }
+
+ // Let derived objects think if they want to
+ if ( m_pfnThink )
+ {
+ (this->*m_pfnThink)();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Indicates the shield has been EMPed (or not)
+//-----------------------------------------------------------------------------
+void CShield::SetEMPed( bool isEmped )
+{
+ m_bIsEMPed = isEmped;
+}
+
+//-----------------------------------------------------------------------------
+// Helper method for collision testing
+//-----------------------------------------------------------------------------
+#pragma warning ( disable : 4701 )
+
+bool CShield::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 ( IsEMPed() )
+ return false;
+ if ( m_flPower <= 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, edict(), mint, hitgroup, CONTENTS_SOLID, normal, intercept );
+ VectorAdd( trace.startpos, ray.m_StartOffset, trace.startpos );
+ VectorAdd( trace.endpos, ray.m_StartOffset, trace.endpos );
+
+ return true;
+}
+
+#pragma warning ( default : 4701 )
+
+