summaryrefslogtreecommitdiff
path: root/game/shared/tf2/weapon_harpoon.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/shared/tf2/weapon_harpoon.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf2/weapon_harpoon.cpp')
-rw-r--r--game/shared/tf2/weapon_harpoon.cpp735
1 files changed, 735 insertions, 0 deletions
diff --git a/game/shared/tf2/weapon_harpoon.cpp b/game/shared/tf2/weapon_harpoon.cpp
new file mode 100644
index 0000000..d5da872
--- /dev/null
+++ b/game/shared/tf2/weapon_harpoon.cpp
@@ -0,0 +1,735 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Harpoon
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basetfplayer_shared.h"
+#include "basetfcombatweapon_shared.h"
+#include "in_buttons.h"
+#include "engine/IEngineSound.h"
+
+#if defined( CLIENT_DLL )
+#define CWeaponHarpoon C_WeaponHarpoon
+#endif
+
+class CHarpoon;
+
+// Fist defines
+#define FIST_RANGE 90
+
+#if !defined( CLIENT_DLL )
+
+ConVar weapon_harpoon_damage( "weapon_harpoon_damage","40", FCVAR_NONE, "Harpoon impale damage" );
+ConVar weapon_fist_damage( "weapon_fist_damage","50", FCVAR_NONE, "Fist damage to everything other than objects" );
+ConVar weapon_fist_damage_objects( "weapon_fist_damage_objects","150", FCVAR_NONE, "Fist damage to objects" );
+
+#include "rope.h"
+#include "rope_shared.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Harpoon thrown by the harpoon weapon
+//-----------------------------------------------------------------------------
+class CHarpoon : public CBaseAnimating
+{
+ DECLARE_CLASS( CHarpoon, CBaseAnimating );
+public:
+ DECLARE_DATADESC();
+ DECLARE_SERVERCLASS();
+
+ CHarpoon( void );
+ virtual void Spawn( void );
+ virtual void Precache( void );
+
+ void SetHarpoonAngles( void );
+ void FlyThink( void );
+ void ConstrainThink( void );
+ void HarpoonTouch( CBaseEntity *pOther );
+
+ static CHarpoon *Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner );
+ CRopeKeyframe *GetRope( void ) { return m_hRope; }
+ void SetRope( CRopeKeyframe *pRope ) { m_hRope = pRope; }
+ CBaseEntity *GetImpaledTarget( void ) { return m_hImpaledTarget; }
+ void SetLinkedHarpoon( CHarpoon *pLinkedHarpoon ) { m_hLinkedHarpoon = pLinkedHarpoon; }
+ void CheckLinkedHarpoon( void );
+ void ImpaleTarget( CBaseEntity *pOther );
+
+private:
+ // Impaling
+ CNetworkVector( m_vecOffset );
+ CNetworkQAngle( m_angOffset );
+ float m_flConstrainLength;
+
+ CHandle< CRopeKeyframe > m_hRope;
+ EHANDLE m_hImpaledTarget;
+ CHandle< CHarpoon > m_hLinkedHarpoon;
+};
+
+LINK_ENTITY_TO_CLASS( harpoon, CHarpoon );
+PRECACHE_REGISTER(harpoon);
+
+IMPLEMENT_SERVERCLASS_ST(CHarpoon, DT_Harpoon)
+ SendPropVector( SENDINFO(m_vecOffset), -1, SPROP_COORD ),
+ SendPropVector( SENDINFO(m_angOffset), -1, SPROP_COORD ),
+END_SEND_TABLE()
+
+BEGIN_DATADESC( CHarpoon )
+ // Function Pointers
+ DEFINE_FUNCTION( HarpoonTouch ),
+ DEFINE_FUNCTION( FlyThink ),
+ DEFINE_FUNCTION( ConstrainThink ),
+END_DATADESC()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHarpoon::CHarpoon( void )
+{
+ UseClientSideAnimation();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::Spawn( void )
+{
+ Precache();
+
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
+ SetSolid( SOLID_BBOX );
+ //m_flGravity = 1.0;
+ SetFriction( 0.75 );
+ SetModel( "models/weapons/w_harpoon.mdl" );
+ UTIL_SetSize(this, Vector( -4, -4, -4), Vector(4, 4, 4));
+ SetCollisionGroup( TFCOLLISION_GROUP_GRENADE );
+
+ SetTouch( HarpoonTouch );
+ SetThink( FlyThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::Precache( void )
+{
+ PrecacheModel( "models/weapons/w_harpoon.mdl" );
+
+ PrecacheScriptSound( "Harpoon.Impact" );
+ PrecacheScriptSound( "Harpoon.Impale" );
+ PrecacheScriptSound( "Harpoon.HitFlesh" );
+ PrecacheScriptSound( "Harpoon.HitMetal" );
+ PrecacheScriptSound( "Harpoon.Yank" );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::SetHarpoonAngles( void )
+{
+ QAngle angles;
+ VectorAngles( GetAbsVelocity(), angles );
+ SetLocalAngles( angles );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::HarpoonTouch( CBaseEntity *pOther )
+{
+ // If we've stuck something, freeze. Make sure we hit it along our velocity.
+ if ( pOther->GetCollisionGroup() != TFCOLLISION_GROUP_SHIELD )
+ {
+ // Perform the collision response...
+ const trace_t &tr = CBaseEntity::GetTouchTrace( );
+
+ Vector vecNewVelocity;
+ PhysicsClipVelocity (GetAbsVelocity(), tr.plane.normal, vecNewVelocity, 2.0 - GetFriction());
+ SetAbsVelocity( vecNewVelocity );
+ }
+ else
+ {
+ // Move away from the shield...
+ // Fling it out a little extra along the plane normal
+ Vector vecCenter;
+ AngleVectors( pOther->GetAbsAngles(), &vecCenter );
+
+ Vector vecNewVelocity;
+ VectorMultiply( vecCenter, 400.0f, vecNewVelocity );
+ SetAbsVelocity( vecNewVelocity );
+ }
+
+ if ( !pOther->IsBSPModel() && !pOther->GetBaseAnimating() )
+ return;
+
+ // At this point, it shouldn't affect player movement
+ SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+
+ // Remove myself soon
+ SetThink( SUB_Remove );
+ SetNextThink( gpGlobals->curtime + 30.0 );
+
+ m_hImpaledTarget = pOther;
+
+ // Should I impale something?
+ if ( pOther->GetBaseAnimating() )
+ {
+ CheckLinkedHarpoon();
+
+ if ( pOther->GetMoveType() != MOVETYPE_NONE )
+ {
+ ImpaleTarget( pOther );
+ return;
+ }
+ }
+
+ CheckLinkedHarpoon();
+
+ EmitSound( "Harpoon.Impact" );
+
+ // Stop moving
+ SetMoveType( MOVETYPE_NONE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to see if we've got a linked harpoon, and see if we should constrain something
+//-----------------------------------------------------------------------------
+void CHarpoon::CheckLinkedHarpoon( void )
+{
+ if ( m_hLinkedHarpoon )
+ {
+ CHarpoon *pPlayerHarpoon = NULL;
+ CHarpoon *pNonMovingHarpoon = NULL;
+
+ // Find out if either of us has impaled something
+ if ( GetImpaledTarget() && m_hLinkedHarpoon->GetImpaledTarget() )
+ {
+ // Only care about players for now. One of the targets must be a player.
+ CBaseTFPlayer *pPlayer = NULL;
+ CBaseEntity *pOtherTarget = NULL;
+ if ( GetImpaledTarget()->IsPlayer() )
+ {
+ pPlayer = (CBaseTFPlayer*)GetImpaledTarget();
+ pPlayerHarpoon = this;
+ pNonMovingHarpoon = m_hLinkedHarpoon;
+ }
+ else if ( m_hLinkedHarpoon->GetImpaledTarget()->IsPlayer() )
+ {
+ pPlayer = (CBaseTFPlayer*)m_hLinkedHarpoon->GetImpaledTarget();
+ pNonMovingHarpoon = this;
+ pPlayerHarpoon = m_hLinkedHarpoon;
+ }
+
+ // Found a player?
+ if ( pPlayer )
+ {
+ pOtherTarget = pNonMovingHarpoon->GetImpaledTarget();
+
+ // For now, we have to be linked to a non-moving target. Eventually we could support linked moving targets.
+ // pOtherTarget == NULL means the harpoon's buried in the world.
+ if ( pOtherTarget->IsBSPModel() || pOtherTarget->GetMoveType() == MOVETYPE_NONE )
+ {
+ // Add a little slack
+ m_flConstrainLength = ( m_hLinkedHarpoon->GetAbsOrigin() - GetAbsOrigin() ).Length() + 150;
+ pPlayer->ActivateMovementConstraint( NULL, pNonMovingHarpoon->GetAbsOrigin(), m_flConstrainLength, 150.0f, 0.1f );
+ // Square it for later checking
+ m_flConstrainLength *= m_flConstrainLength;
+
+ // Start checking the length
+ pPlayerHarpoon->m_flConstrainLength = m_flConstrainLength;
+ pPlayerHarpoon->SetThink( ConstrainThink );
+ pPlayerHarpoon->SetNextThink( gpGlobals->curtime + 0.1f );
+
+ // Make the rope taught, and prevent it resizing
+ if ( m_hRope )
+ {
+ m_hRope->m_RopeFlags &= ~ROPE_RESIZE;
+ m_hRope->RecalculateLength();
+ }
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::ImpaleTarget( CBaseEntity *pOther )
+{
+ // Impale!
+ EmitSound( "Harpoon.Impale" );
+
+ // Calculate our impale offset
+ m_vecOffset = (pOther->GetAbsOrigin() - GetAbsOrigin());
+ m_angOffset = (pOther->GetAbsAngles() - GetAbsAngles());
+
+ FollowEntity( pOther );
+
+ // Do some damage to the target
+ if ( pOther->m_takedamage )
+ {
+ CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwnerEntity() );
+ if ( !pOwner )
+ return;
+
+ pOther->TakeDamage( CTakeDamageInfo( this, pOwner, weapon_harpoon_damage.GetFloat(), DMG_GENERIC ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHarpoon::FlyThink( void )
+{
+ SetHarpoonAngles();
+
+ SetNextThink( gpGlobals->curtime + 0.1f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to see if our target has moved beyond our length
+//-----------------------------------------------------------------------------
+void CHarpoon::ConstrainThink( void )
+{
+ if ( !GetImpaledTarget() || !m_hLinkedHarpoon.Get() )
+ return;
+
+ // Moved too far away?
+ float flDistSq = m_hLinkedHarpoon->GetAbsOrigin().DistToSqr( GetImpaledTarget()->GetAbsOrigin() );
+ if ( flDistSq > m_flConstrainLength )
+ {
+ // Break the rope
+ if ( m_hRope )
+ {
+ m_hRope->DetachPoint(1);
+ m_hRope->DieAtNextRest();
+ m_hRope = NULL;
+ }
+
+ // If we're impaling a player, remove his movement constraint
+ if ( GetImpaledTarget()->IsPlayer() )
+ {
+ CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)GetImpaledTarget();
+ pPlayer->DeactivateMovementConstraint();
+ }
+
+ SetThink( NULL );
+ }
+ else
+ {
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHarpoon *CHarpoon::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner )
+{
+ CHarpoon *pHarpoon = (CHarpoon*)CreateEntityByName("harpoon");
+
+ UTIL_SetOrigin( pHarpoon, vecOrigin );
+ pHarpoon->Spawn();
+ pHarpoon->ChangeTeam( pOwner->GetTeamNumber() );
+ pHarpoon->SetOwnerEntity( pOwner );
+ pHarpoon->SetAbsVelocity( vecForward );
+ pHarpoon->SetHarpoonAngles();
+
+ return pHarpoon;
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CWeaponHarpoon : public CBaseTFCombatWeapon
+{
+ DECLARE_CLASS( CWeaponHarpoon, CBaseTFCombatWeapon );
+public:
+ CWeaponHarpoon();
+
+ DECLARE_NETWORKCLASS();
+ DECLARE_PREDICTABLE();
+
+ virtual void ItemPostFrame( void );
+ virtual void PrimaryAttack( void );
+ virtual void SecondaryAttack( void );
+ virtual float GetFireRate( void );
+ virtual void ThrowGrenade( void );
+ virtual void DetachRope( void );
+ virtual void YankHarpoon( void );
+
+ // Custom grenade types
+ virtual CHarpoon *CreateHarpoon( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
+
+ /*
+ // All predicted weapons need to implement and return true
+ virtual bool IsPredicted( void ) const
+ {
+ return true;
+ }
+
+#if defined( CLIENT_DLL )
+ virtual bool ShouldPredict( void )
+ {
+ if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
+ return true;
+
+ return BaseClass::ShouldPredict();
+ }
+#endif
+ */
+
+public:
+ CNetworkVar( float, m_flStartedThrowAt );
+ float m_flCantThrowUntil;
+ float m_flSecondaryAttackAt;
+ bool m_bActiveHarpoon;
+
+#if !defined( CLIENT_DLL )
+ CHandle< CRopeKeyframe > m_hRope;
+ CHandle< CHarpoon > m_hHarpoon;
+#endif
+
+private:
+ CWeaponHarpoon( const CWeaponHarpoon & );
+};
+
+LINK_ENTITY_TO_CLASS( weapon_harpoon, CWeaponHarpoon );
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponHarpoon, DT_WeaponHarpoon )
+
+BEGIN_NETWORK_TABLE( CWeaponHarpoon, DT_WeaponHarpoon )
+#if !defined( CLIENT_DLL )
+ SendPropTime( SENDINFO( m_flStartedThrowAt ) ),
+#else
+ RecvPropTime( RECVINFO( m_flStartedThrowAt ) ),
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CWeaponHarpoon )
+
+ DEFINE_PRED_FIELD_TOL( m_flStartedThrowAt, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
+
+END_PREDICTION_DATA()
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CWeaponHarpoon::CWeaponHarpoon( void )
+{
+ m_flStartedThrowAt = 0;
+ m_flCantThrowUntil = 0;
+ m_flSecondaryAttackAt = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CWeaponHarpoon::GetFireRate( void )
+{
+ return 2.0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::ItemPostFrame( void )
+{
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+ if (!pOwner)
+ return;
+
+ // Look for button downs
+ if ( (pOwner->m_afButtonPressed & IN_ATTACK) && !m_flStartedThrowAt && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
+ {
+ // If we don't have a harpoon, throw one out. Otherwise, yank it back.
+ if ( m_bActiveHarpoon )
+ {
+ YankHarpoon();
+ }
+ else
+ {
+ m_bActiveHarpoon = true;
+ m_flStartedThrowAt = gpGlobals->curtime;
+ PlayAttackAnimation( ACT_VM_PULLBACK );
+ m_flCantThrowUntil = gpGlobals->curtime + SequenceDuration();
+ }
+ }
+ else if ( m_flCantThrowUntil && m_bActiveHarpoon && !(pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) && (m_flCantThrowUntil <= gpGlobals->curtime) )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime;
+ PrimaryAttack();
+ m_flStartedThrowAt = 0;
+ m_flCantThrowUntil = 0;
+ }
+ else if ( (pOwner->m_nButtons & IN_ATTACK2) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
+ {
+ PlayAttackAnimation( ACT_VM_SECONDARYATTACK );
+ m_flSecondaryAttackAt = gpGlobals->curtime + SequenceDuration() * 0.3;
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ }
+ else if ( m_flSecondaryAttackAt && m_flSecondaryAttackAt < gpGlobals->curtime )
+ {
+ SecondaryAttack();
+ m_flSecondaryAttackAt = 0;
+ }
+
+ // No buttons down?
+ if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
+ {
+ WeaponIdle( );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::PrimaryAttack( void )
+{
+ CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
+ if ( !pPlayer )
+ return;
+
+ if ( !ComputeEMPFireState() )
+ return;
+
+ ThrowGrenade();
+
+ // Setup for refire
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
+ CheckRemoveDisguise();
+
+ // If I'm now out of ammo, switch away
+ if ( !HasPrimaryAmmo() )
+ {
+ pPlayer->SelectLastItem();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::SecondaryAttack( void )
+{
+ CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
+ if ( !pPlayer )
+ return;
+
+ // Slap things in front of me
+ Vector vecForward;
+ Vector vecBox = Vector( FIST_RANGE,FIST_RANGE,FIST_RANGE * 1.5 ) * 0.5;
+ pPlayer->EyeVectors( &vecForward );
+ Vector vecSrc = pPlayer->Weapon_ShootPosition( );
+ Vector vecCenter = vecSrc + (FIST_RANGE * 0.5 * vecForward);
+
+#if !defined( CLIENT_DLL )
+ //NDebugOverlay::Box( vecCenter, -Vector(2,2,2), Vector(2,2,2), 255,0,0,20,2.0);
+ //NDebugOverlay::Box( vecCenter, -vecBox, vecBox, 255,255,255,20,2.0);
+
+ bool bHitMetal = false;
+ bool bHitPlayer = false;
+
+ CBaseEntity *pList[100];
+ int count = UTIL_EntitiesInBox( pList, 100, vecSrc - vecBox, vecSrc + vecBox, FL_CLIENT|FL_NPC|FL_OBJECT );
+ for ( int i = 0; i < count; i++ )
+ {
+ CBaseEntity *pEntity = pList[i];
+ if ( !pEntity->m_takedamage )
+ continue;
+ if ( pEntity->InSameTeam( this ) )
+ continue;
+
+ //NDebugOverlay::EntityBounds( pEntity, 0,255,0,20,2.0);
+ if ( pEntity->IsPlayer() )
+ {
+ bHitPlayer = true;
+ CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB );
+ CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
+ pEntity->TakeDamage( info );
+ }
+ else if ( pEntity->Classify() == CLASS_MILITARY )
+ {
+ bHitMetal = true;
+ CTakeDamageInfo info( this, pPlayer, weapon_fist_damage_objects.GetFloat(), DMG_CLUB );
+ CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
+ pEntity->TakeDamage( info );
+ }
+ else
+ {
+ bHitMetal = true;
+ CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB );
+ CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
+ pEntity->TakeDamage( info );
+ }
+ }
+
+ // Play the right sound
+ if ( bHitPlayer )
+ {
+ EmitSound( "Harpoon.HitFlesh" );
+ }
+ else if ( bHitMetal )
+ {
+ EmitSound( "Harpoon.HitMetal" );
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::ThrowGrenade( void )
+{
+ CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
+ if ( !pPlayer )
+ return;
+
+ BaseClass::WeaponSound(WPN_DOUBLE);
+
+ // Calculate launch velocity (3 seconds for max distance)
+ float flThrowTime = MIN( (gpGlobals->curtime - m_flStartedThrowAt), 3.0 );
+ float flSpeed = 1000 + (200 * flThrowTime);
+
+ PlayAttackAnimation( ACT_VM_PRIMARYATTACK );
+
+ // If the player's crouched, roll the grenade
+ if ( pPlayer->GetFlags() & FL_DUCKING )
+ {
+ // Launch the grenade
+ Vector vecForward;
+ QAngle vecAngles = pPlayer->EyeAngles();
+ // Throw it up just a tad
+ vecAngles.x = -1;
+ AngleVectors( vecAngles, &vecForward, NULL, NULL);
+ Vector vecOrigin;
+ VectorLerp( pPlayer->EyePosition(), pPlayer->GetAbsOrigin(), 0.25f, vecOrigin );
+ vecOrigin += (vecForward * 16);
+ vecForward = vecForward * flSpeed;
+ CreateHarpoon(vecOrigin, vecForward, pPlayer );
+ }
+ else
+ {
+ // Launch the grenade
+ Vector vecForward;
+ QAngle vecAngles = pPlayer->EyeAngles();
+ AngleVectors( vecAngles, &vecForward, NULL, NULL);
+ Vector vecOrigin = pPlayer->EyePosition();
+ vecOrigin += (vecForward * 16);
+ vecForward = vecForward * flSpeed;
+ CreateHarpoon(vecOrigin, vecForward, pPlayer );
+ }
+
+ pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Give the harpoon a yank
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::YankHarpoon( void )
+{
+ CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
+ if ( !pPlayer )
+ return;
+
+#if !defined( CLIENT_DLL )
+ if ( m_bActiveHarpoon && m_hHarpoon.Get() )
+ {
+ // If the harpoon's impaled something, pull it towards me
+ CBaseEntity *pTarget = m_hHarpoon->GetImpaledTarget();
+ if ( pTarget )
+ {
+ if ( !pTarget->IsBSPModel() && pTarget->GetMoveType() != MOVETYPE_NONE )
+ {
+ // Bring him to me!
+ EmitSound( "Harpoon.Yank" );
+
+ // Get a yank vector, and raise it a little to get them off the ground if they're on it
+ Vector vecOverHere = ( pPlayer->GetAbsOrigin() - pTarget->GetAbsOrigin() );
+ VectorNormalize( vecOverHere );
+ if ( pTarget->GetFlags() & FL_ONGROUND )
+ {
+ pTarget->SetGroundEntity( NULL );
+ vecOverHere.z = 0.5;
+ }
+ pTarget->ApplyAbsVelocityImpulse( vecOverHere * 500 );
+
+ PlayAttackAnimation( ACT_VM_HAULBACK );
+ }
+ }
+ m_hHarpoon->SetThink( SUB_Remove );
+ m_hHarpoon->SetNextThink( gpGlobals->curtime + 5.0 );
+ m_hHarpoon = NULL;
+ m_bActiveHarpoon = false;
+ }
+
+ DetachRope();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponHarpoon::DetachRope( void )
+{
+#if !defined( CLIENT_DLL )
+ if ( m_hRope )
+ {
+ m_hRope->DetachPoint(1);
+ m_hRope->DieAtNextRest();
+ m_hRope = NULL;
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHarpoon *CWeaponHarpoon::CreateHarpoon( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner )
+{
+#if !defined( CLIENT_DLL )
+ CHarpoon *pHarpoon = CHarpoon::Create(vecOrigin, vecAngles, pOwner );
+ if ( pHarpoon )
+ {
+ // Create the rope on first throw. Otherwise attach our existing rope.
+ if ( !m_hRope )
+ {
+ CRopeKeyframe *pRope = CRopeKeyframe::Create( pHarpoon, pOwner, 0, 0 );
+ if ( pRope )
+ {
+ pRope->m_RopeLength = 1.0;
+ pRope->m_Slack = 50.0f;
+ pRope->m_Width = 2;
+ pRope->m_nSegments = ROPE_MAX_SEGMENTS;
+ pRope->m_RopeFlags |= ROPE_RESIZE | ROPE_COLLIDE;
+ }
+ m_hRope = pRope;
+ pHarpoon->SetRope( m_hRope );
+ }
+ else
+ {
+ m_hRope->SetEndPoint( pHarpoon, 0 );
+ pHarpoon->SetRope( m_hRope );
+ m_hRope = NULL;
+ }
+
+ // Do we already have a harpoon out?
+ CHarpoon *pOldHarpoon = m_hHarpoon;
+ m_hHarpoon = pHarpoon;
+
+ if ( pOldHarpoon )
+ {
+ pOldHarpoon->SetLinkedHarpoon( m_hHarpoon );
+ pHarpoon->SetLinkedHarpoon( pOldHarpoon );
+ m_hHarpoon = NULL;
+ }
+ }
+ return pHarpoon;
+#else
+ return NULL;
+#endif
+}