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.

363 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "weapon_hl2mpbasebasebludgeon.h"
  10. #include "gamerules.h"
  11. #include "ammodef.h"
  12. #include "mathlib/mathlib.h"
  13. #include "in_buttons.h"
  14. #include "animation.h"
  15. #if defined( CLIENT_DLL )
  16. #include "c_hl2mp_player.h"
  17. #else
  18. #include "hl2mp_player.h"
  19. #include "ndebugoverlay.h"
  20. #include "te_effect_dispatch.h"
  21. #include "ilagcompensationmanager.h"
  22. #endif
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. IMPLEMENT_NETWORKCLASS_ALIASED( BaseHL2MPBludgeonWeapon, DT_BaseHL2MPBludgeonWeapon )
  26. BEGIN_NETWORK_TABLE( CBaseHL2MPBludgeonWeapon, DT_BaseHL2MPBludgeonWeapon )
  27. END_NETWORK_TABLE()
  28. BEGIN_PREDICTION_DATA( CBaseHL2MPBludgeonWeapon )
  29. END_PREDICTION_DATA()
  30. #define BLUDGEON_HULL_DIM 16
  31. static const Vector g_bludgeonMins(-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM);
  32. static const Vector g_bludgeonMaxs(BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM);
  33. //-----------------------------------------------------------------------------
  34. // Constructor
  35. //-----------------------------------------------------------------------------
  36. CBaseHL2MPBludgeonWeapon::CBaseHL2MPBludgeonWeapon()
  37. {
  38. m_bFiresUnderwater = true;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Spawn the weapon
  42. //-----------------------------------------------------------------------------
  43. void CBaseHL2MPBludgeonWeapon::Spawn( void )
  44. {
  45. m_fMinRange1 = 0;
  46. m_fMinRange2 = 0;
  47. m_fMaxRange1 = 64;
  48. m_fMaxRange2 = 64;
  49. //Call base class first
  50. BaseClass::Spawn();
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Precache the weapon
  54. //-----------------------------------------------------------------------------
  55. void CBaseHL2MPBludgeonWeapon::Precache( void )
  56. {
  57. //Call base class first
  58. BaseClass::Precache();
  59. }
  60. //------------------------------------------------------------------------------
  61. // Purpose : Update weapon
  62. //------------------------------------------------------------------------------
  63. void CBaseHL2MPBludgeonWeapon::ItemPostFrame( void )
  64. {
  65. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  66. if ( pOwner == NULL )
  67. return;
  68. if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
  69. {
  70. PrimaryAttack();
  71. }
  72. else if ( (pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime) )
  73. {
  74. SecondaryAttack();
  75. }
  76. else
  77. {
  78. WeaponIdle();
  79. return;
  80. }
  81. }
  82. //------------------------------------------------------------------------------
  83. // Purpose :
  84. // Input :
  85. // Output :
  86. //------------------------------------------------------------------------------
  87. void CBaseHL2MPBludgeonWeapon::PrimaryAttack()
  88. {
  89. #ifndef CLIENT_DLL
  90. CHL2MP_Player *pPlayer = ToHL2MPPlayer( GetPlayerOwner() );
  91. // Move other players back to history positions based on local player's lag
  92. lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
  93. #endif
  94. Swing( false );
  95. #ifndef CLIENT_DLL
  96. // Move other players back to history positions based on local player's lag
  97. lagcompensation->FinishLagCompensation( pPlayer );
  98. #endif
  99. }
  100. //------------------------------------------------------------------------------
  101. // Purpose :
  102. // Input :
  103. // Output :
  104. //------------------------------------------------------------------------------
  105. void CBaseHL2MPBludgeonWeapon::SecondaryAttack()
  106. {
  107. Swing( true );
  108. }
  109. //------------------------------------------------------------------------------
  110. // Purpose: Implement impact function
  111. //------------------------------------------------------------------------------
  112. void CBaseHL2MPBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity )
  113. {
  114. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  115. //Do view kick
  116. // AddViewKick();
  117. CBaseEntity *pHitEntity = traceHit.m_pEnt;
  118. //Apply damage to a hit target
  119. if ( pHitEntity != NULL )
  120. {
  121. Vector hitDirection;
  122. pPlayer->EyeVectors( &hitDirection, NULL, NULL );
  123. VectorNormalize( hitDirection );
  124. #ifndef CLIENT_DLL
  125. CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
  126. if( pPlayer && pHitEntity->IsNPC() )
  127. {
  128. // If bonking an NPC, adjust damage.
  129. info.AdjustPlayerDamageInflictedForSkillLevel();
  130. }
  131. CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos );
  132. pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit );
  133. ApplyMultiDamage();
  134. // Now hit all triggers along the ray that...
  135. TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection );
  136. #endif
  137. WeaponSound( MELEE_HIT );
  138. }
  139. // Apply an impact effect
  140. ImpactEffect( traceHit );
  141. }
  142. Activity CBaseHL2MPBludgeonWeapon::ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner )
  143. {
  144. int i, j, k;
  145. float distance;
  146. const float *minmaxs[2] = {mins.Base(), maxs.Base()};
  147. trace_t tmpTrace;
  148. Vector vecHullEnd = hitTrace.endpos;
  149. Vector vecEnd;
  150. distance = 1e6f;
  151. Vector vecSrc = hitTrace.startpos;
  152. vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
  153. UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
  154. if ( tmpTrace.fraction == 1.0 )
  155. {
  156. for ( i = 0; i < 2; i++ )
  157. {
  158. for ( j = 0; j < 2; j++ )
  159. {
  160. for ( k = 0; k < 2; k++ )
  161. {
  162. vecEnd.x = vecHullEnd.x + minmaxs[i][0];
  163. vecEnd.y = vecHullEnd.y + minmaxs[j][1];
  164. vecEnd.z = vecHullEnd.z + minmaxs[k][2];
  165. UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
  166. if ( tmpTrace.fraction < 1.0 )
  167. {
  168. float thisDistance = (tmpTrace.endpos - vecSrc).Length();
  169. if ( thisDistance < distance )
  170. {
  171. hitTrace = tmpTrace;
  172. distance = thisDistance;
  173. }
  174. }
  175. }
  176. }
  177. }
  178. }
  179. else
  180. {
  181. hitTrace = tmpTrace;
  182. }
  183. return ACT_VM_HITCENTER;
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. // Input : &traceHit -
  188. //-----------------------------------------------------------------------------
  189. bool CBaseHL2MPBludgeonWeapon::ImpactWater( const Vector &start, const Vector &end )
  190. {
  191. //FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good
  192. // right now anyway...
  193. // We must start outside the water
  194. if ( UTIL_PointContents( start ) & (CONTENTS_WATER|CONTENTS_SLIME))
  195. return false;
  196. // We must end inside of water
  197. if ( !(UTIL_PointContents( end ) & (CONTENTS_WATER|CONTENTS_SLIME)))
  198. return false;
  199. trace_t waterTrace;
  200. UTIL_TraceLine( start, end, (CONTENTS_WATER|CONTENTS_SLIME), GetOwner(), COLLISION_GROUP_NONE, &waterTrace );
  201. if ( waterTrace.fraction < 1.0f )
  202. {
  203. #ifndef CLIENT_DLL
  204. CEffectData data;
  205. data.m_fFlags = 0;
  206. data.m_vOrigin = waterTrace.endpos;
  207. data.m_vNormal = waterTrace.plane.normal;
  208. data.m_flScale = 8.0f;
  209. // See if we hit slime
  210. if ( waterTrace.contents & CONTENTS_SLIME )
  211. {
  212. data.m_fFlags |= FX_WATER_IN_SLIME;
  213. }
  214. DispatchEffect( "watersplash", data );
  215. #endif
  216. }
  217. return true;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose:
  221. //-----------------------------------------------------------------------------
  222. void CBaseHL2MPBludgeonWeapon::ImpactEffect( trace_t &traceHit )
  223. {
  224. // See if we hit water (we don't do the other impact effects in this case)
  225. if ( ImpactWater( traceHit.startpos, traceHit.endpos ) )
  226. return;
  227. //FIXME: need new decals
  228. UTIL_ImpactTrace( &traceHit, DMG_CLUB );
  229. }
  230. //------------------------------------------------------------------------------
  231. // Purpose : Starts the swing of the weapon and determines the animation
  232. // Input : bIsSecondary - is this a secondary attack?
  233. //------------------------------------------------------------------------------
  234. void CBaseHL2MPBludgeonWeapon::Swing( int bIsSecondary )
  235. {
  236. trace_t traceHit;
  237. // Try a ray
  238. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  239. if ( !pOwner )
  240. return;
  241. Vector swingStart = pOwner->Weapon_ShootPosition( );
  242. Vector forward;
  243. pOwner->EyeVectors( &forward, NULL, NULL );
  244. Vector swingEnd = swingStart + forward * GetRange();
  245. UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit );
  246. Activity nHitActivity = ACT_VM_HITCENTER;
  247. #ifndef CLIENT_DLL
  248. // Like bullets, bludgeon traces have to trace against triggers.
  249. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB );
  250. TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, vec3_origin );
  251. #endif
  252. if ( traceHit.fraction == 1.0 )
  253. {
  254. float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point
  255. // Back off by hull "radius"
  256. swingEnd -= forward * bludgeonHullRadius;
  257. UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit );
  258. if ( traceHit.fraction < 1.0 && traceHit.m_pEnt )
  259. {
  260. Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart;
  261. VectorNormalize( vecToTarget );
  262. float dot = vecToTarget.Dot( forward );
  263. // YWB: Make sure they are sort of facing the guy at least...
  264. if ( dot < 0.70721f )
  265. {
  266. // Force amiss
  267. traceHit.fraction = 1.0f;
  268. }
  269. else
  270. {
  271. nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner );
  272. }
  273. }
  274. }
  275. WeaponSound( SINGLE );
  276. // -------------------------
  277. // Miss
  278. // -------------------------
  279. if ( traceHit.fraction == 1.0f )
  280. {
  281. nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER;
  282. // We want to test the first swing again
  283. Vector testEnd = swingStart + forward * GetRange();
  284. // See if we happened to hit water
  285. ImpactWater( swingStart, testEnd );
  286. }
  287. else
  288. {
  289. Hit( traceHit, nHitActivity );
  290. }
  291. // Send the anim
  292. SendWeaponAnim( nHitActivity );
  293. pOwner->SetAnimation( PLAYER_ATTACK1 );
  294. //Setup our next attack times
  295. m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
  296. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  297. }