Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
6.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_dodbasemelee.h"
  8. #include "dod_gamerules.h"
  9. #if defined( CLIENT_DLL )
  10. #include "c_dod_player.h"
  11. #else
  12. #include "dod_player.h"
  13. #include "ilagcompensationmanager.h"
  14. #endif
  15. #include "effect_dispatch_data.h"
  16. #define KNIFE_BODYHIT_VOLUME 128
  17. #define KNIFE_WALLHIT_VOLUME 512
  18. // ----------------------------------------------------------------------------- //
  19. // CWeaponDODBaseMelee tables.
  20. // ----------------------------------------------------------------------------- //
  21. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseMelee, DT_WeaponDODBaseMelee )
  22. BEGIN_NETWORK_TABLE_NOBASE( CWeaponDODBaseMelee, DT_LocalActiveWeaponBaseMeleeData )
  23. END_NETWORK_TABLE()
  24. BEGIN_NETWORK_TABLE( CWeaponDODBaseMelee, DT_WeaponDODBaseMelee )
  25. END_NETWORK_TABLE()
  26. #ifdef CLIENT_DLL
  27. BEGIN_PREDICTION_DATA( CWeaponDODBaseMelee )
  28. DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  29. END_PREDICTION_DATA()
  30. #endif
  31. LINK_ENTITY_TO_CLASS( weapon_dod_base_melee, CWeaponDODBaseMelee );
  32. #ifndef CLIENT_DLL
  33. BEGIN_DATADESC( CWeaponDODBaseMelee )
  34. DEFINE_FUNCTION( Smack )
  35. END_DATADESC()
  36. #endif
  37. // ----------------------------------------------------------------------------- //
  38. // CWeaponDODBaseMelee implementation.
  39. // ----------------------------------------------------------------------------- //
  40. CWeaponDODBaseMelee::CWeaponDODBaseMelee()
  41. {
  42. }
  43. void CWeaponDODBaseMelee::Spawn()
  44. {
  45. Precache();
  46. WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
  47. Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
  48. CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  49. Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in melee weapon spawn" );
  50. m_pWeaponInfo = pWeaponInfo;
  51. Assert( m_pWeaponInfo );
  52. m_iClip1 = -1;
  53. BaseClass::Spawn();
  54. }
  55. void CWeaponDODBaseMelee::WeaponIdle( void )
  56. {
  57. if ( m_flTimeWeaponIdle > gpGlobals->curtime )
  58. return;
  59. SendWeaponAnim( ACT_VM_IDLE );
  60. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  61. }
  62. void CWeaponDODBaseMelee::PrimaryAttack()
  63. {
  64. MeleeAttack( 60, MELEE_DMG_EDGE, 0.2f, 0.4f );
  65. }
  66. CBaseEntity *CWeaponDODBaseMelee::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay )
  67. {
  68. if ( !CanAttack() )
  69. return NULL;
  70. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  71. #if !defined (CLIENT_DLL)
  72. // Move other players back to history positions based on local player's lag
  73. lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
  74. #endif
  75. Vector vForward, vRight, vUp;
  76. AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
  77. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  78. Vector vecEnd = vecSrc + vForward * 48;
  79. CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
  80. int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
  81. trace_t tr;
  82. UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
  83. const float rayExtension = 40.0f;
  84. UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
  85. if ( tr.fraction >= 1.0 )
  86. {
  87. Vector head_hull_mins( -16, -16, -18 );
  88. Vector head_hull_maxs( 16, 16, 18 );
  89. UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
  90. if ( tr.fraction < 1.0 )
  91. {
  92. // Calculate the point of intersection of the line (or hull) and the object we hit
  93. // This is and approximation of the "best" intersection
  94. CBaseEntity *pHit = tr.m_pEnt;
  95. if ( !pHit || pHit->IsBSPModel() )
  96. FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
  97. vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
  98. // Make sure it is in front of us
  99. Vector vecToEnd = vecEnd - vecSrc;
  100. VectorNormalize( vecToEnd );
  101. // if zero length, always hit
  102. if ( vecToEnd.Length() > 0 )
  103. {
  104. float dot = DotProduct( vForward, vecToEnd );
  105. // sanity that our hit is within range
  106. if ( abs(dot) < 0.95 )
  107. {
  108. // fake that we actually missed
  109. tr.fraction = 1.0;
  110. }
  111. }
  112. }
  113. }
  114. bool bDidHit = ( tr.fraction < 1.0f );
  115. bool bDoStrongAttack = false;
  116. if ( bDidHit && tr.m_pEnt->IsPlayer() && tr.m_pEnt->m_takedamage != DAMAGE_YES )
  117. {
  118. bDidHit = 0; // still play the animation, we just dont attempt to damage this player
  119. }
  120. if ( bDidHit ) //if the swing hit
  121. {
  122. // delay the decal a bit
  123. m_trHit = tr;
  124. // Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function.
  125. m_pTraceHitEnt = tr.m_pEnt;
  126. m_iSmackDamage = iDamageAmount;
  127. m_iSmackDamageType = iDamageType;
  128. m_flSmackTime = gpGlobals->curtime + flDmgDelay;
  129. int iOwnerTeam = pPlayer->GetTeamNumber();
  130. int iVictimTeam = tr.m_pEnt->GetTeamNumber();
  131. // do the mega attack if its a player, and we would do damage
  132. if ( tr.m_pEnt->IsPlayer() &&
  133. tr.m_pEnt->m_takedamage == DAMAGE_YES &&
  134. ( iVictimTeam != iOwnerTeam || ( iVictimTeam == iOwnerTeam && friendlyfire.GetBool() ) ) )
  135. {
  136. CDODPlayer *pVictim = ToDODPlayer( tr.m_pEnt );
  137. Vector victimForward;
  138. AngleVectors( pVictim->GetAbsAngles(), &victimForward );
  139. if ( DotProduct( victimForward, vForward ) > 0.3 )
  140. {
  141. bDoStrongAttack = true;
  142. }
  143. }
  144. }
  145. if ( bDoStrongAttack )
  146. {
  147. m_iSmackDamage = 300;
  148. flAttackDelay = 0.9f;
  149. m_flSmackTime = gpGlobals->curtime + 0.4f;
  150. m_iSmackDamageType = MELEE_DMG_EDGE | MELEE_DMG_STRONGATTACK;
  151. // play a "Strong" attack
  152. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  153. }
  154. else
  155. {
  156. WeaponSound( MELEE_MISS );
  157. SendWeaponAnim( GetMeleeActivity() );
  158. }
  159. // player animation
  160. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK );
  161. m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay;
  162. m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay;
  163. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  164. #ifndef CLIENT_DLL
  165. IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
  166. if ( event )
  167. {
  168. event->SetInt( "attacker", pPlayer->GetUserID() );
  169. event->SetInt( "weapon", GetStatsWeaponID() );
  170. gameeventmanager->FireEvent( event );
  171. }
  172. lagcompensation->FinishLagCompensation( pPlayer );
  173. #endif //CLIENT_DLL
  174. return tr.m_pEnt;
  175. }