summaryrefslogtreecommitdiff
path: root/game/client/hl2/c_weapon_physcannon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/hl2/c_weapon_physcannon.cpp')
-rw-r--r--game/client/hl2/c_weapon_physcannon.cpp442
1 files changed, 442 insertions, 0 deletions
diff --git a/game/client/hl2/c_weapon_physcannon.cpp b/game/client/hl2/c_weapon_physcannon.cpp
new file mode 100644
index 0000000..5dff9a2
--- /dev/null
+++ b/game/client/hl2/c_weapon_physcannon.cpp
@@ -0,0 +1,442 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_weapon__stubs.h"
+#include "c_basehlcombatweapon.h"
+#include "fx.h"
+#include "particles_localspace.h"
+#include "view.h"
+#include "particles_attractor.h"
+
+class C_WeaponPhysCannon: public C_BaseHLCombatWeapon
+{
+ DECLARE_CLASS( C_WeaponPhysCannon, C_BaseHLCombatWeapon );
+public:
+ C_WeaponPhysCannon( void );
+
+ DECLARE_CLIENTCLASS();
+ DECLARE_PREDICTABLE();
+
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual int DrawModel( int flags );
+ virtual void ClientThink( void );
+
+ virtual bool ShouldUseLargeViewModelVROverride() OVERRIDE { return true; }
+
+private:
+
+ bool SetupEmitter( void );
+
+ bool m_bIsCurrentlyUpgrading;
+ float m_flTimeForceView;
+ float m_flTimeIgnoreForceView;
+ bool m_bWasUpgraded;
+
+ CSmartPtr<CLocalSpaceEmitter> m_pLocalEmitter;
+ CSmartPtr<CSimpleEmitter> m_pEmitter;
+ CSmartPtr<CParticleAttractor> m_pAttractor;
+};
+
+STUB_WEAPON_CLASS_IMPLEMENT( weapon_physcannon, C_WeaponPhysCannon );
+
+IMPLEMENT_CLIENTCLASS_DT( C_WeaponPhysCannon, DT_WeaponPhysCannon, CWeaponPhysCannon )
+ RecvPropBool( RECVINFO( m_bIsCurrentlyUpgrading ) ),
+ RecvPropFloat( RECVINFO( m_flTimeForceView) ),
+END_RECV_TABLE()
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+C_WeaponPhysCannon::C_WeaponPhysCannon( void )
+{
+ m_bWasUpgraded = false;
+ m_flTimeIgnoreForceView = -1;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void C_WeaponPhysCannon::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_WeaponPhysCannon::SetupEmitter( void )
+{
+ if ( !m_pLocalEmitter.IsValid() )
+ {
+ m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) );
+
+ if ( m_pLocalEmitter.IsValid() == false )
+ return false;
+ }
+
+ if ( !m_pAttractor.IsValid() )
+ {
+ m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" );
+
+ if ( m_pAttractor.IsValid() == false )
+ return false;
+ }
+
+ if ( !m_pEmitter.IsValid() )
+ {
+ m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" );
+
+ if ( m_pEmitter.IsValid() == false )
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Sorts the components of a vector
+//-----------------------------------------------------------------------------
+static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
+{
+ Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
+
+ int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
+ if (absVec[2] > absVec[maxIdx])
+ {
+ maxIdx = 2;
+ }
+
+ // always choose something right-handed....
+ switch( maxIdx )
+ {
+ case 0:
+ pVecIdx[0] = 1;
+ pVecIdx[1] = 2;
+ pVecIdx[2] = 0;
+ break;
+ case 1:
+ pVecIdx[0] = 2;
+ pVecIdx[1] = 0;
+ pVecIdx[2] = 1;
+ break;
+ case 2:
+ pVecIdx[0] = 0;
+ pVecIdx[1] = 1;
+ pVecIdx[2] = 2;
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Compute the bounding box's center, size, and basis
+//-----------------------------------------------------------------------------
+void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
+ Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
+{
+ // Compute the center of the hitbox in worldspace
+ Vector vecHitboxCenter;
+ VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
+ vecHitboxCenter *= 0.5f;
+ VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
+
+ // Get the object's basis
+ Vector vec[3];
+ MatrixGetColumn( hitboxToWorld, 0, vec[0] );
+ MatrixGetColumn( hitboxToWorld, 1, vec[1] );
+ MatrixGetColumn( hitboxToWorld, 2, vec[2] );
+// vec[1] *= -1.0f;
+
+ Vector vecViewDir;
+ VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
+ VectorNormalize( vecViewDir );
+
+ // Project the shadow casting direction into the space of the hitbox
+ Vector localViewDir;
+ localViewDir[0] = DotProduct( vec[0], vecViewDir );
+ localViewDir[1] = DotProduct( vec[1], vecViewDir );
+ localViewDir[2] = DotProduct( vec[2], vecViewDir );
+
+ // Figure out which vector has the largest component perpendicular
+ // to the view direction...
+ // Sort by how perpendicular it is
+ int vecIdx[3];
+ SortAbsVectorComponents( localViewDir, vecIdx );
+
+ // Here's our hitbox basis vectors; namely the ones that are
+ // most perpendicular to the view direction
+ *pXVec = vec[vecIdx[0]];
+ *pYVec = vec[vecIdx[1]];
+
+ // Project them into a plane perpendicular to the view direction
+ *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
+ *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
+ VectorNormalize( *pXVec );
+ VectorNormalize( *pYVec );
+
+ // Compute the hitbox size
+ Vector boxSize;
+ VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
+
+ // We project the two longest sides into the vectors perpendicular
+ // to the projection direction, then add in the projection of the perp direction
+ Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
+ size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
+ size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
+
+ // Add the third component into x and y
+ size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
+ size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
+
+ // Bloat a bit, since the shadow wants to extend outside the model a bit
+ size *= 2.0f;
+
+ // Clamp the minimum size
+ Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
+
+ // Factor the size into the xvec + yvec
+ (*pXVec) *= size.x * 0.5f;
+ (*pYVec) *= size.y * 0.5f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flags -
+// Output : int
+//-----------------------------------------------------------------------------
+int C_WeaponPhysCannon::DrawModel( int flags )
+{
+ // If we're not ugrading, don't do anything special
+ if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false )
+ return BaseClass::DrawModel( flags );
+
+ if ( gpGlobals->frametime == 0 )
+ return BaseClass::DrawModel( flags );
+
+ if ( !m_bReadyToDraw )
+ return 0;
+
+ m_bWasUpgraded = true;
+
+ // Create the particle emitter if it's not already
+ if ( SetupEmitter() )
+ {
+ // Add the power-up particles
+
+ // See if we should draw
+ if ( m_bReadyToDraw == false )
+ return 0;
+
+ C_BaseAnimating *pAnimating = GetBaseAnimating();
+ if (!pAnimating)
+ return 0;
+
+ matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
+ if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
+ return 0;
+
+ studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
+ if (!pStudioHdr)
+ return false;
+
+ mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
+ if ( !set )
+ return false;
+
+ int i;
+
+ float fadePerc = 1.0f;
+
+ if ( m_bIsCurrentlyUpgrading )
+ {
+ Vector vecSkew = vec3_origin;
+
+ // Skew the particles in front or in back of their targets
+ vecSkew = CurrentViewForward() * 4.0f;
+
+ float spriteScale = 1.0f;
+ spriteScale = clamp( spriteScale, 0.75f, 1.0f );
+
+ SimpleParticle *sParticle;
+
+ for ( i = 0; i < set->numhitboxes; ++i )
+ {
+ Vector vecAbsOrigin, xvec, yvec;
+ mstudiobbox_t *pBox = set->pHitbox(i);
+ ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec );
+
+ Vector offset;
+ Vector xDir, yDir;
+
+ xDir = xvec;
+ float xScale = VectorNormalize( xDir ) * 0.75f;
+
+ yDir = yvec;
+ float yScale = VectorNormalize( yDir ) * 0.75f;
+
+ int numParticles = clamp( 4.0f * fadePerc, 1, 3 );
+
+ for ( int j = 0; j < numParticles; j++ )
+ {
+ offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
+ offset += vecSkew;
+
+ sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset );
+
+ if ( sParticle == NULL )
+ return 1;
+
+ sParticle->m_vecVelocity = vec3_origin;
+ sParticle->m_uchStartSize = 16.0f * spriteScale;
+ sParticle->m_flDieTime = 0.2f;
+ sParticle->m_flLifetime = 0.0f;
+
+ sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
+ sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
+
+ float alpha = 40;
+
+ sParticle->m_uchColor[0] = alpha;
+ sParticle->m_uchColor[1] = alpha;
+ sParticle->m_uchColor[2] = alpha;
+ sParticle->m_uchStartAlpha = alpha;
+ sParticle->m_uchEndAlpha = 0;
+ sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
+ }
+ }
+ }
+ }
+
+ int attachment = LookupAttachment( "core" );
+ Vector coreOrigin;
+ QAngle coreAngles;
+
+ GetAttachment( attachment, coreOrigin, coreAngles );
+
+ SimpleParticle *sParticle;
+
+ // Do the core effects
+ for ( int i = 0; i < 4; i++ )
+ {
+ sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin );
+
+ if ( sParticle == NULL )
+ return 1;
+
+ sParticle->m_vecVelocity = vec3_origin;
+ sParticle->m_flDieTime = 0.1f;
+ sParticle->m_flLifetime = 0.0f;
+
+ sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
+ sParticle->m_flRollDelta = 0.0f;
+
+ float alpha = 255;
+
+ sParticle->m_uchColor[0] = alpha;
+ sParticle->m_uchColor[1] = alpha;
+ sParticle->m_uchColor[2] = alpha;
+ sParticle->m_uchStartAlpha = alpha;
+ sParticle->m_uchEndAlpha = 0;
+
+ if ( i < 2 )
+ {
+ sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
+ sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
+ }
+ else
+ {
+ if ( random->RandomInt( 0, 20 ) == 0 )
+ {
+ sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
+ sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
+ sParticle->m_flDieTime = 0.25f;
+ }
+ else
+ {
+ sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
+ sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
+ }
+ }
+ }
+
+ if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading )
+ {
+ // Update our attractor point
+ m_pAttractor->SetAttractorOrigin( coreOrigin );
+
+ Vector offset;
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ offset = coreOrigin + RandomVector( -32.0f, 32.0f );
+
+ sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset );
+
+ if ( sParticle == NULL )
+ return 1;
+
+ sParticle->m_vecVelocity = Vector(0,0,8);
+ sParticle->m_flDieTime = 0.5f;
+ sParticle->m_flLifetime = 0.0f;
+
+ sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
+ sParticle->m_flRollDelta = 0.0f;
+
+ float alpha = 255;
+
+ sParticle->m_uchColor[0] = alpha;
+ sParticle->m_uchColor[1] = alpha;
+ sParticle->m_uchColor[2] = alpha;
+ sParticle->m_uchStartAlpha = alpha;
+ sParticle->m_uchEndAlpha = 0;
+
+ sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
+ sParticle->m_uchEndSize = 0;
+ }
+ }
+
+ return BaseClass::DrawModel( flags );
+}
+
+//---------------------------------------------------------
+// On 360, raise up the player's view if the server has
+// asked us to.
+//---------------------------------------------------------
+#define PHYSCANNON_RAISE_VIEW_GOAL 0.0f
+void C_WeaponPhysCannon::ClientThink( void )
+{
+ if( m_flTimeIgnoreForceView > gpGlobals->curtime )
+ return;
+
+ float flTime = (m_flTimeForceView - gpGlobals->curtime);
+
+ if( flTime < 0.0f )
+ return;
+
+ float flDT = 1.0f - flTime;
+ if( flDT > 0.0f )
+ {
+ QAngle viewangles;
+ engine->GetViewAngles( viewangles );
+
+ if( viewangles.x > PHYSCANNON_RAISE_VIEW_GOAL + 1.0f )
+ {
+ float flDelta = PHYSCANNON_RAISE_VIEW_GOAL - viewangles.x;
+ viewangles.x += (flDelta * flDT);
+ engine->SetViewAngles(viewangles);
+ }
+ else
+ {
+ // We've reached our goal. Ignore the forced view angles for now.
+ m_flTimeIgnoreForceView = m_flTimeForceView + 0.1f;
+ }
+ }
+
+ return BaseClass::ClientThink();
+}
+
+