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/weapon_harpoon.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/weapon_harpoon.cpp')
| -rw-r--r-- | game/shared/tf2/weapon_harpoon.cpp | 735 |
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 +} |