Counter Strike : Global Offensive Source Code
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.

385 lines
11 KiB

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