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/tf/tf_weapon_grapplinghook.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf/tf_weapon_grapplinghook.cpp')
| -rw-r--r-- | game/shared/tf/tf_weapon_grapplinghook.cpp | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weapon_grapplinghook.cpp b/game/shared/tf/tf_weapon_grapplinghook.cpp new file mode 100644 index 0000000..1b883f0 --- /dev/null +++ b/game/shared/tf/tf_weapon_grapplinghook.cpp @@ -0,0 +1,858 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// TF Grappling Hook +// +//============================================================================= +#include "cbase.h" +#include "in_buttons.h" +#include "tf_weapon_grapplinghook.h" + +// Client specific. +#ifdef CLIENT_DLL +#include "c_tf_player.h" +#include "gc_clientsystem.h" +#include "prediction.h" +#include "soundenvelope.h" +// Server specific. +#else +#include "tf_player.h" +#include "entity_rune.h" +#include "effect_dispatch_data.h" +#include "tf_fx.h" +#include "func_respawnroom.h" +#endif + +//============================================================================= +// +// Grappling hook tables. +// +IMPLEMENT_NETWORKCLASS_ALIASED( TFGrapplingHook, DT_GrapplingHook ) + +BEGIN_NETWORK_TABLE( CTFGrapplingHook, DT_GrapplingHook ) +#ifdef GAME_DLL + SendPropEHandle( SENDINFO( m_hProjectile ) ), +#else // GAME_DLL + RecvPropEHandle( RECVINFO( m_hProjectile ) ), +#endif // CLIENT_DLL +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CTFGrapplingHook ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( tf_weapon_grapplinghook, CTFGrapplingHook ); +PRECACHE_WEAPON_REGISTER( tf_weapon_grapplinghook ); + +// Server specific. +#ifndef CLIENT_DLL +BEGIN_DATADESC( CTFGrapplingHook ) +END_DATADESC() +#endif // CLIENT_DLL + +// This is basically a copy of s_acttableMeleeAllclass table except primary fire to use grappling hook specific +acttable_t s_grapplinghook_normal_acttable[] = +{ + { ACT_MP_STAND_IDLE, ACT_MP_STAND_MELEE_ALLCLASS, false }, + { ACT_MP_CROUCH_IDLE, ACT_MP_CROUCH_MELEE_ALLCLASS, false }, + { ACT_MP_RUN, ACT_MP_RUN_MELEE_ALLCLASS, false }, + { ACT_MP_WALK, ACT_MP_WALK_MELEE_ALLCLASS, false }, + { ACT_MP_AIRWALK, ACT_GRAPPLE_PULL_IDLE, false }, + { ACT_MP_CROUCHWALK, ACT_MP_CROUCHWALK_MELEE_ALLCLASS, false }, + { ACT_MP_JUMP, ACT_MP_JUMP_MELEE_ALLCLASS, false }, + { ACT_MP_JUMP_START, ACT_MP_JUMP_START_MELEE_ALLCLASS, false }, + { ACT_MP_JUMP_FLOAT, ACT_MP_JUMP_FLOAT_MELEE_ALLCLASS, false }, + { ACT_MP_JUMP_LAND, ACT_MP_JUMP_LAND_MELEE_ALLCLASS, false }, + { ACT_MP_SWIM, ACT_MP_SWIM_MELEE_ALLCLASS, false }, + { ACT_MP_DOUBLEJUMP_CROUCH, ACT_MP_DOUBLEJUMP_CROUCH_MELEE, false }, + + { ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_SWIM_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_AIRWALK_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + + { ACT_MP_ATTACK_STAND_SECONDARYFIRE, ACT_MP_ATTACK_STAND_MELEE_SECONDARY, false }, + { ACT_MP_ATTACK_CROUCH_SECONDARYFIRE, ACT_MP_ATTACK_CROUCH_MELEE_SECONDARY,false }, + { ACT_MP_ATTACK_SWIM_SECONDARYFIRE, ACT_MP_ATTACK_SWIM_MELEE_ALLCLASS, false }, + { ACT_MP_ATTACK_AIRWALK_SECONDARYFIRE, ACT_MP_ATTACK_AIRWALK_MELEE_ALLCLASS, false }, + + { ACT_MP_GESTURE_FLINCH, ACT_MP_GESTURE_FLINCH_MELEE, false }, + + { ACT_MP_GRENADE1_DRAW, ACT_MP_MELEE_GRENADE1_DRAW, false }, + { ACT_MP_GRENADE1_IDLE, ACT_MP_MELEE_GRENADE1_IDLE, false }, + { ACT_MP_GRENADE1_ATTACK, ACT_MP_MELEE_GRENADE1_ATTACK, false }, + { ACT_MP_GRENADE2_DRAW, ACT_MP_MELEE_GRENADE2_DRAW, false }, + { ACT_MP_GRENADE2_IDLE, ACT_MP_MELEE_GRENADE2_IDLE, false }, + { ACT_MP_GRENADE2_ATTACK, ACT_MP_MELEE_GRENADE2_ATTACK, false }, + + { ACT_MP_GESTURE_VC_HANDMOUTH, ACT_MP_GESTURE_VC_HANDMOUTH_MELEE, false }, + { ACT_MP_GESTURE_VC_FINGERPOINT, ACT_MP_GESTURE_VC_FINGERPOINT_MELEE, false }, + { ACT_MP_GESTURE_VC_FISTPUMP, ACT_MP_GESTURE_VC_FISTPUMP_MELEE, false }, + { ACT_MP_GESTURE_VC_THUMBSUP, ACT_MP_GESTURE_VC_THUMBSUP_MELEE, false }, + { ACT_MP_GESTURE_VC_NODYES, ACT_MP_GESTURE_VC_NODYES_MELEE, false }, + { ACT_MP_GESTURE_VC_NODNO, ACT_MP_GESTURE_VC_NODNO_MELEE, false }, +}; + +// This is basically a copy of s_acttableSecondary table except primary fire to use grappling hook specific +acttable_t s_grapplinghook_engineer_acttable[] = +{ + { ACT_MP_STAND_IDLE, ACT_MP_STAND_SECONDARY, false }, + { ACT_MP_CROUCH_IDLE, ACT_MP_CROUCH_SECONDARY, false }, + { ACT_MP_RUN, ACT_MP_RUN_SECONDARY, false }, + { ACT_MP_WALK, ACT_MP_WALK_SECONDARY, false }, + { ACT_MP_AIRWALK, ACT_MP_AIRWALK_SECONDARY, false }, + { ACT_MP_CROUCHWALK, ACT_MP_CROUCHWALK_SECONDARY, false }, + { ACT_MP_JUMP, ACT_MP_JUMP_SECONDARY, false }, + { ACT_MP_JUMP_START, ACT_MP_JUMP_START_SECONDARY, false }, + { ACT_MP_JUMP_FLOAT, ACT_MP_JUMP_FLOAT_SECONDARY, false }, + { ACT_MP_JUMP_LAND, ACT_MP_JUMP_LAND_SECONDARY, false }, + { ACT_MP_SWIM, ACT_MP_SWIM_SECONDARY, false }, + { ACT_MP_DOUBLEJUMP_CROUCH, ACT_MP_DOUBLEJUMP_CROUCH_SECONDARY, false }, + + { ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_SWIM_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + { ACT_MP_ATTACK_AIRWALK_PRIMARYFIRE, ACT_GRAPPLE_FIRE_START, false }, + + { ACT_MP_RELOAD_STAND, ACT_MP_RELOAD_STAND_SECONDARY, false }, + { ACT_MP_RELOAD_STAND_LOOP, ACT_MP_RELOAD_STAND_SECONDARY_LOOP, false }, + { ACT_MP_RELOAD_STAND_END, ACT_MP_RELOAD_STAND_SECONDARY_END, false }, + { ACT_MP_RELOAD_CROUCH, ACT_MP_RELOAD_CROUCH_SECONDARY, false }, + { ACT_MP_RELOAD_CROUCH_LOOP,ACT_MP_RELOAD_CROUCH_SECONDARY_LOOP,false }, + { ACT_MP_RELOAD_CROUCH_END, ACT_MP_RELOAD_CROUCH_SECONDARY_END, false }, + { ACT_MP_RELOAD_SWIM, ACT_MP_RELOAD_SWIM_SECONDARY, false }, + { ACT_MP_RELOAD_SWIM_LOOP, ACT_MP_RELOAD_SWIM_SECONDARY_LOOP, false }, + { ACT_MP_RELOAD_SWIM_END, ACT_MP_RELOAD_SWIM_SECONDARY_END, false }, + { ACT_MP_RELOAD_AIRWALK, ACT_MP_RELOAD_AIRWALK_SECONDARY, false }, + { ACT_MP_RELOAD_AIRWALK_LOOP, ACT_MP_RELOAD_AIRWALK_SECONDARY_LOOP, false }, + { ACT_MP_RELOAD_AIRWALK_END,ACT_MP_RELOAD_AIRWALK_SECONDARY_END,false }, + + { ACT_MP_GESTURE_FLINCH, ACT_MP_GESTURE_FLINCH_SECONDARY, false }, + + { ACT_MP_GRENADE1_DRAW, ACT_MP_SECONDARY_GRENADE1_DRAW, false }, + { ACT_MP_GRENADE1_IDLE, ACT_MP_SECONDARY_GRENADE1_IDLE, false }, + { ACT_MP_GRENADE1_ATTACK, ACT_MP_SECONDARY_GRENADE1_ATTACK, false }, + { ACT_MP_GRENADE2_DRAW, ACT_MP_SECONDARY_GRENADE2_DRAW, false }, + { ACT_MP_GRENADE2_IDLE, ACT_MP_SECONDARY_GRENADE2_IDLE, false }, + { ACT_MP_GRENADE2_ATTACK, ACT_MP_SECONDARY_GRENADE2_ATTACK, false }, + + { ACT_MP_ATTACK_STAND_GRENADE, ACT_MP_ATTACK_STAND_GRENADE, false }, + { ACT_MP_ATTACK_CROUCH_GRENADE, ACT_MP_ATTACK_STAND_GRENADE, false }, + { ACT_MP_ATTACK_SWIM_GRENADE, ACT_MP_ATTACK_STAND_GRENADE, false }, + { ACT_MP_ATTACK_AIRWALK_GRENADE, ACT_MP_ATTACK_STAND_GRENADE, false }, + + { ACT_MP_GESTURE_VC_HANDMOUTH, ACT_MP_GESTURE_VC_HANDMOUTH_SECONDARY, false }, + { ACT_MP_GESTURE_VC_FINGERPOINT, ACT_MP_GESTURE_VC_FINGERPOINT_SECONDARY, false }, + { ACT_MP_GESTURE_VC_FISTPUMP, ACT_MP_GESTURE_VC_FISTPUMP_SECONDARY, false }, + { ACT_MP_GESTURE_VC_THUMBSUP, ACT_MP_GESTURE_VC_THUMBSUP_SECONDARY, false }, + { ACT_MP_GESTURE_VC_NODYES, ACT_MP_GESTURE_VC_NODYES_SECONDARY, false }, + { ACT_MP_GESTURE_VC_NODNO, ACT_MP_GESTURE_VC_NODNO_SECONDARY, false }, +}; + +acttable_t *CTFGrapplingHook::ActivityList( int &iActivityCount ) +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + if ( pOwner ) + { + if ( pOwner->IsPlayerClass( TF_CLASS_ENGINEER ) ) + { + iActivityCount = ARRAYSIZE( s_grapplinghook_engineer_acttable ); + return s_grapplinghook_engineer_acttable; + } + else + { + iActivityCount = ARRAYSIZE( s_grapplinghook_normal_acttable ); + return s_grapplinghook_normal_acttable; + } + } + + return BaseClass::ActivityList( iActivityCount ); +} + + +poseparamtable_t s_grapplinghook_normal_poseparamtable[] = +{ + { "R_hand_grip", 14 }, + { "R_arm", 2 }, +}; + +poseparamtable_t s_grapplinghook_engineer_poseparamtable[] = +{ + { "r_handposes_engineer", 1 }, +}; + +poseparamtable_t *CTFGrapplingHook::PoseParamList( int &iPoseParamCount ) +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + if ( pOwner ) + { + if ( pOwner->IsPlayerClass( TF_CLASS_ENGINEER ) ) + { + iPoseParamCount = ARRAYSIZE( s_grapplinghook_engineer_poseparamtable ); + return s_grapplinghook_engineer_poseparamtable; + } + else + { + iPoseParamCount = ARRAYSIZE( s_grapplinghook_normal_poseparamtable ); + return s_grapplinghook_normal_poseparamtable; + } + } + + return BaseClass::PoseParamList( iPoseParamCount ); +} + + +ConVar tf_grapplinghook_projectile_speed( "tf_grapplinghook_projectile_speed", "1500", FCVAR_REPLICATED | FCVAR_CHEAT, "How fast does the grappliing hook projectile travel" ); +ConVar tf_grapplinghook_max_distance( "tf_grapplinghook_max_distance", "2000", FCVAR_REPLICATED | FCVAR_CHEAT, "Valid distance for grappling hook to travel" ); +ConVar tf_grapplinghook_fire_delay( "tf_grapplinghook_fire_delay", "0.5", FCVAR_REPLICATED | FCVAR_CHEAT ); + +float m_flNextSupernovaDenyWarning = 0.f; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFGrapplingHook::CTFGrapplingHook() +{ +#ifdef GAME_DLL + m_bReleasedAfterLatched = false; +#endif // GAME_DLL + +#ifdef CLIENT_DLL + m_pHookSound = NULL; + m_bLatched = false; +#endif // CLIENT_DLL +} + + +void CTFGrapplingHook::Precache() +{ + BaseClass::Precache(); + +#ifdef GAME_DLL + PrecacheScriptSound( "WeaponGrapplingHook.Shoot" ); +#endif // GAME_DLL +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseEntity *CTFGrapplingHook::FireProjectile( CTFPlayer *pPlayer ) +{ +#ifdef GAME_DLL + Assert( m_hProjectile == NULL ); + m_hProjectile = BaseClass::FireProjectile( pPlayer ); + + return m_hProjectile; +#else + return BaseClass::FireProjectile( pPlayer ); +#endif // GAME_DLL +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::ItemPostFrame( void ) +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + if (!pOwner) + return; + +#ifdef CLIENT_DLL + static bool bFired = false; +#endif // CLIENT_DLL + + CBaseEntity *pHookTarget = pOwner->GetGrapplingHookTarget(); + bool bJump = ( pOwner->m_nButtons & IN_JUMP ) > 0; + bool bForceReleaseHook = pHookTarget != NULL && bJump; + + if ( !bForceReleaseHook && ( pOwner->m_nButtons & IN_ATTACK || pOwner->IsUsingActionSlot() ) ) + { +#ifdef CLIENT_DLL + if ( !bFired ) + { + PrimaryAttack(); + bFired = true; + } +#else + PrimaryAttack(); +#endif // CLIENT_DLL + + if ( pOwner->GetGrapplingHookTarget() ) + { + SendWeaponAnim( ACT_GRAPPLE_PULL_START ); + } + else if ( m_hProjectile ) + { + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + } + else + { + SendWeaponAnim( ACT_GRAPPLE_IDLE ); + } + } + else + { +#ifdef CLIENT_DLL + bFired = false; +#endif // CLIENT_DLL + + OnHookReleased( bForceReleaseHook ); + } + + if ( pOwner->GetViewModel(0) ) + { + pOwner->GetViewModel(0)->SetPlaybackRate( 1.f ); + } + if ( pOwner->GetViewModel(1) ) + { + pOwner->GetViewModel(1)->SetPlaybackRate( 1.f ); + } + + BaseClass::ItemPostFrame(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFGrapplingHook::CanAttack( void ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + + if ( pPlayer->m_Shared.IsFeignDeathReady() ) + return false; + + return BaseClass::CanAttack(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::PrimaryAttack( void ) +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + +#ifdef GAME_DLL + // make sure to unlatch from the current target and remove the old projectile before we fire a new one + if ( m_bReleasedAfterLatched ) + { + RemoveHookProjectile( true ); + } +#endif // GAME_DLL + + if ( m_hProjectile ) + return; + + if ( m_flNextPrimaryAttack > gpGlobals->curtime ) + return; + + if ( pOwner && pOwner->m_Shared.IsControlStunned() ) + return; + + Vector vecSrc; + QAngle angForward; + Vector vecOffset( 23.5f, -8.0f, -3.0f ); // copied from CTFWeaponBaseGun::FireArrow + GetProjectileFireSetup( pOwner, vecOffset, &vecSrc, &angForward, false ); + Vector vecForward; + AngleVectors( angForward, &vecForward ); + + // check if aiming at skybox + trace_t tr; + UTIL_TraceLine( vecSrc, vecSrc + tf_grapplinghook_max_distance.GetFloat() * vecForward, MASK_SOLID, pOwner, COLLISION_GROUP_DEBRIS, &tr ); + if ( !tr.DidHit() || ( tr.fraction < 1.0 && tr.surface.flags & SURF_SKY ) ) + { +#ifdef CLIENT_DLL + // play fail sound on client here + if ( pOwner && prediction->IsFirstTimePredicted() ) + { + pOwner->EmitSound( "Player.DenyWeaponSelection" ); + } +#endif // CLIENT_DLL + return; + } + + BaseClass::PrimaryAttack(); + + m_flNextPrimaryAttack = gpGlobals->curtime + tf_grapplinghook_fire_delay.GetFloat(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFGrapplingHook::Deploy( void ) +{ +#ifdef GAME_DLL + RemoveHookProjectile( true ); + m_bReleasedAfterLatched = IsLatchedToTargetPlayer(); +#endif // GAME_DLL + return BaseClass::Deploy(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFGrapplingHook::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ +#ifdef GAME_DLL + RemoveHookProjectile(); + m_bReleasedAfterLatched = IsLatchedToTargetPlayer(); +#endif // GAME_DLL + + return BaseClass::Holster( pSwitchingTo ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::GetProjectileFireSetup( CTFPlayer *pPlayer, Vector vecOffset, Vector *vecSrc, QAngle *angForward, bool bHitTeammates /*= true*/, float flEndDist /*= 2000.f*/ ) +{ + BaseClass::GetProjectileFireSetup( pPlayer, vecOffset, vecSrc, angForward, bHitTeammates, flEndDist ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CTFGrapplingHook::GetProjectileSpeed() +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + + if ( pOwner && pOwner->m_Shared.GetCarryingRuneType() == RUNE_AGILITY ) + { + switch ( pOwner->GetPlayerClass()->GetClassIndex() ) + { + case TF_CLASS_SOLDIER: + case TF_CLASS_HEAVYWEAPONS: + return 2600.f; + default: + return 3000.f; + } + } + + return tf_grapplinghook_projectile_speed.GetFloat(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFGrapplingHook::SendWeaponAnim( int actBase ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( !pPlayer ) + return BaseClass::SendWeaponAnim( actBase ); + + if ( actBase == ACT_VM_DRAW ) + { + actBase = ACT_GRAPPLE_DRAW; + } + else if ( pPlayer->GetGrapplingHookTarget() ) + { + if ( GetActivity() != ACT_GRAPPLE_PULL_START && GetActivity() != ACT_GRAPPLE_PULL_IDLE ) + { + bool bResult = BaseClass::SendWeaponAnim( ACT_GRAPPLE_PULL_START ); + //DevMsg("pull start %f\n", gpGlobals->curtime ); + + m_startPullingTimer.Start( SequenceDuration() ); + + return bResult; + } + else + { + if ( GetActivity() == ACT_GRAPPLE_PULL_IDLE ) + return true; + + if ( GetActivity() == ACT_GRAPPLE_PULL_START && m_startPullingTimer.HasStarted() && !m_startPullingTimer.IsElapsed() ) + return true; + + actBase = ACT_GRAPPLE_PULL_IDLE; + //DevMsg("pull idle %f\n", gpGlobals->curtime ); + + m_startPullingTimer.Invalidate(); + } + } + else if ( actBase == ACT_VM_PRIMARYATTACK ) + { + if ( GetActivity() != ACT_GRAPPLE_FIRE_START && GetActivity() != ACT_GRAPPLE_FIRE_IDLE ) + { + bool bResult = BaseClass::SendWeaponAnim( ACT_GRAPPLE_FIRE_START ); + //DevMsg("fire start %f\n", gpGlobals->curtime ); + + m_startFiringTimer.Start( SequenceDuration() ); + + return bResult; + } + else + { + if ( GetActivity() == ACT_GRAPPLE_FIRE_IDLE ) + return true; + + if ( GetActivity() == ACT_GRAPPLE_FIRE_START && m_startFiringTimer.HasStarted() && !m_startFiringTimer.IsElapsed() ) + return true; + + actBase = ACT_GRAPPLE_FIRE_IDLE; + //DevMsg("fire idle %f\n", gpGlobals->curtime ); + + m_startFiringTimer.Invalidate(); + } + } + else + { + if ( GetActivity() == ACT_GRAPPLE_PULL_IDLE ) + { + actBase = ACT_GRAPPLE_PULL_END; + //DevMsg("pull end %f\n", gpGlobals->curtime ); + } + else + { + if ( GetActivity() == ACT_GRAPPLE_IDLE ) + return true; + + actBase = ACT_GRAPPLE_IDLE; + //DevMsg("grapple idle %f\n", gpGlobals->curtime ); + } + } + + return BaseClass::SendWeaponAnim( actBase ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::PlayWeaponShootSound( void ) +{ +#ifdef GAME_DLL + EmitSound( "WeaponGrapplingHook.Shoot" ); +#endif // GAME_DLL +} + + + +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::ActivateRune() +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + if ( pOwner && pOwner->m_Shared.IsRuneCharged() ) + { + RuneTypes_t type = pOwner->m_Shared.GetCarryingRuneType(); + if ( type == RUNE_SUPERNOVA ) + { + // don't allow stealthed player to activate the power + if ( pOwner->m_Shared.IsStealthed() ) + return; + + int nEnemyTeam = GetEnemyTeam( pOwner->GetTeamNumber() ); + + // apply super nova effect to all enemies + bool bHitAnyTarget = false; + CUtlVector< CTFPlayer* > vecPlayers; + CUtlVector< CTFPlayer* > vecVictims; + CollectPlayers( &vecPlayers, nEnemyTeam, COLLECT_ONLY_LIVING_PLAYERS ); + const float flEffectRadiusSqr = Sqr( 1500.f ); + const float flMinPushForce = 200.f; + const float flMaxPushForce = 500.f; + const float flMinStunDuration = 2.f; + const float flMaxStunDuration = 4.f; + for ( int i = 0; i < vecPlayers.Count(); ++i ) + { + CTFPlayer *pOther = vecPlayers[i]; + Vector toPlayer = pOther->WorldSpaceCenter() - pOwner->WorldSpaceCenter(); + float flDistSqr = toPlayer.LengthSqr(); + + // Collect valid enemies + if ( flDistSqr <= flEffectRadiusSqr && pOwner->IsLineOfSightClear( pOther, CBaseCombatCharacter::IGNORE_ACTORS ) && !PointInRespawnRoom( pOther, pOther->WorldSpaceCenter() ) ) + { + vecVictims.AddToTail( pOther ); + } + } + + // if there is more than one victim, the stun duration increases + float flStunDuration = MIN( flMinStunDuration + ( ( vecVictims.Count() - 1 ) * 0.5 ), flMaxStunDuration ); + + for ( int i = 0; i < vecVictims.Count(); ++i ) + { + // force enemy to drop rune, stun, and push them + CTFPlayer *pOther = vecVictims[i]; + const char *pszEffect = pOwner->GetTeamNumber() == TF_TEAM_RED ? "powerup_supernova_strike_red" : "powerup_supernova_strike_blue"; + + CPVSFilter filter( WorldSpaceCenter() ); + Vector vStart = pOwner->WorldSpaceCenter(); + Vector vEnd = pOther->GetAbsOrigin() + Vector( 0, 0, 56 ); + te_tf_particle_effects_control_point_t controlPoint = { PATTACH_ABSORIGIN, vEnd }; + TE_TFParticleEffectComplex( filter, 0.f, pszEffect, vStart, QAngle( 0.f, 0.f, 0.f ), NULL, &controlPoint, pOther, PATTACH_CUSTOMORIGIN ); + + + pOther->DropRune( false, pOwner->GetTeamNumber() ); + pOther->DropFlag(); + + pOther->m_Shared.StunPlayer( flStunDuration, 1.f, TF_STUN_MOVEMENT | TF_STUN_CONTROLS, pOwner ); + + // send the player flying + // make sure we push players up and away + Vector toPlayer = pOther->WorldSpaceCenter() - pOwner->WorldSpaceCenter(); + toPlayer.z = 0.0f; + toPlayer.NormalizeInPlace(); + toPlayer.z = 1.0f; + + // scale push force based on distance from the supernova origin + float flDistSqr = toPlayer.LengthSqr(); + float flPushForce = RemapValClamped( flDistSqr, 0.f, flEffectRadiusSqr, flMaxPushForce, flMinPushForce ); + Vector vPush = flPushForce * toPlayer; + pOther->ApplyAbsVelocityImpulse( vPush ); + + bHitAnyTarget = true; + } + + // don't deploy with no target + if ( bHitAnyTarget ) + { + // play effect + const char *pszEffect = pOwner->GetTeamNumber() == TF_TEAM_RED ? "powerup_supernova_explode_red" : "powerup_supernova_explode_blue"; + CEffectData data; + data.m_nHitBox = GetParticleSystemIndex( pszEffect ); + data.m_vOrigin = pOwner->GetAbsOrigin(); + data.m_vAngles = vec3_angle; + + CPASFilter filter( data.m_vOrigin ); + filter.SetIgnorePredictionCull( true ); + + te->DispatchEffect( filter, 0.0, data.m_vOrigin, "ParticleEffect", data ); + pOwner->EmitSound( "Powerup.PickUpSupernovaActivate" ); + + // remove the power and reposition instantly + pOwner->m_Shared.SetCarryingRuneType( RUNE_NONE ); + CTFRune::RepositionRune( type, TEAM_ANY ); + } + else + { + if ( gpGlobals->curtime > m_flNextSupernovaDenyWarning ) + { + m_flNextSupernovaDenyWarning = gpGlobals->curtime + 0.5f; + + CSingleUserRecipientFilter singleFilter( pOwner ); + EmitSound( singleFilter, pOwner->entindex(), "Player.UseDeny" ); + ClientPrint( pOwner, HUD_PRINTCENTER, "#TF_Powerup_Supernova_Deny" ); + } + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::RemoveHookProjectile( bool bForce /*= false*/ ) +{ + if ( !bForce && IsLatchedToTargetPlayer() ) + { + // don't remove the projectile until we unlatched from the target (by hooking again) + return; + } + + if ( m_hProjectile ) + { + UTIL_Remove( m_hProjectile ); + m_hProjectile = NULL; + } +} + +bool CTFGrapplingHook::IsLatchedToTargetPlayer() const +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + return pOwner && pOwner->GetGrapplingHookTarget() && pOwner->GetGrapplingHookTarget()->IsPlayer(); +} + +#endif // GAME_DLL + +void CTFGrapplingHook::OnHookReleased( bool bForce ) +{ +#ifdef GAME_DLL + RemoveHookProjectile( bForce ); + m_bReleasedAfterLatched = IsLatchedToTargetPlayer(); +#endif // GAME_DLL + + if ( GetActivity() != ACT_GRAPPLE_DRAW && GetActivity() != ACT_GRAPPLE_IDLE && GetActivity() != ACT_GRAPPLE_PULL_END ) + SendWeaponAnim( ACT_GRAPPLE_PULL_END ); + + if ( bForce ) + m_flNextPrimaryAttack = gpGlobals->curtime + tf_grapplinghook_fire_delay.GetFloat(); +} + +#ifdef CLIENT_DLL + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::UpdateOnRemove() +{ + StopHookSound(); + + BaseClass::UpdateOnRemove(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::OnDataChanged( DataUpdateType_t type ) +{ + BaseClass::OnDataChanged( type ); + + UpdateHookSound(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::StartHookSound() +{ + StopHookSound(); + + CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); + CLocalPlayerFilter filter; + m_pHookSound = controller.SoundCreate( filter, entindex(), "WeaponGrapplingHook.ReelStart" ); + controller.Play( m_pHookSound, 1.0, 100 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::StopHookSound() +{ + if ( m_pHookSound ) + { + CSoundEnvelopeController::GetController().SoundDestroy( m_pHookSound ); + m_pHookSound = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFGrapplingHook::UpdateHookSound() +{ + CTFPlayer *pOwner = GetTFPlayerOwner(); + if ( pOwner ) + { + bool bLatched = pOwner->GetGrapplingHookTarget() != NULL && m_hProjectile != NULL; + if ( m_bLatched != bLatched ) + { + if ( !m_bLatched ) + { + StartHookSound(); + } + else + { + StopHookSound(); + + CLocalPlayerFilter filter; + EmitSound( filter, entindex(), "WeaponGrapplingHook.ReelStop" ); + } + + m_bLatched = bLatched; + } + } +} + + +//----------------------------------------------------------------------------- +// CEquipGrapplingHookNotification +//----------------------------------------------------------------------------- +void CEquipGrapplingHookNotification::Accept() +{ + m_bHasTriggered = true; + + CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory(); + if ( !pLocalInv ) + { + MarkForDeletion(); + return; + } + + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalPlayer ) + { + MarkForDeletion(); + return; + } + + // try to equip non-stock-grapplinghook first + /*static CSchemaItemDefHandle pItemDef_GrapplingHook( "TF_WEAPON_GRAPPLINGHOOK" ); + + Assert( pItemDef_GrapplingHook ); + + CEconItemView *pGrapplingHook = NULL; + + if ( pItemDef_GrapplingHook ) + { + for ( int i = 0 ; i < pLocalInv->GetItemCount() ; ++i ) + { + CEconItemView *pItem = pLocalInv->GetItem( i ); + Assert( pItem ); + if ( pItem->GetItemDefinition() == pItemDef_GrapplingHook ) + { + pGrapplingHook = pItem; + break; + } + } + }*/ + + // Default item becomes a grappling hook in this mode + itemid_t iItemId = INVALID_ITEM_ID; + /*if ( pGrapplingHook ) + { + iItemId = pGrapplingHook->GetItemID(); + }*/ + + if ( iItemId == INVALID_ITEM_ID ) + { + iItemId = 0; + + static CSchemaItemDefHandle pItemDef_Grapple( "TF_WEAPON_GRAPPLINGHOOK" ); + CEconItemView *pDefaultGrapple = TFInventoryManager()->GetBaseItemForClass( pLocalPlayer->GetPlayerClass()->GetClassIndex(), LOADOUT_POSITION_ACTION ); + if ( pDefaultGrapple ) + { + if ( pDefaultGrapple->GetItemDefinition() == pItemDef_Grapple ) + { + iItemId = pDefaultGrapple->GetItemID(); + } + } + } + + TFInventoryManager()->EquipItemInLoadout( pLocalPlayer->GetPlayerClass()->GetClassIndex(), LOADOUT_POSITION_ACTION, iItemId ); + + // Tell the GC to tell server that we should respawn if we're in a respawn room + GCSDK::CGCMsg< GCSDK::MsgGCEmpty_t > msg( k_EMsgGCRespawnPostLoadoutChange ); + GCClientSystem()->BSendMessage( msg ); + + MarkForDeletion(); +} + +//=========================================================================================== +void CEquipGrapplingHookNotification::UpdateTick() +{ + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pLocalPlayer ) + { + CTFGrapplingHook *pGrapplingHook = dynamic_cast<CTFGrapplingHook*>( pLocalPlayer->Weapon_OwnsThisID( TF_WEAPON_GRAPPLINGHOOK ) ); + if ( pGrapplingHook ) + { + MarkForDeletion(); + } + } +} + +#endif // CLIENT_DLL |