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.

379 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Crowbar - an old favorite
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "hl1mp_basecombatweapon_shared.h"
  9. #ifdef CLIENT_DLL
  10. #include "c_baseplayer.h"
  11. #include "fx_impact.h"
  12. #include "fx.h"
  13. #else
  14. #include "player.h"
  15. #include "soundent.h"
  16. #endif
  17. #include "gamerules.h"
  18. #include "ammodef.h"
  19. #include "mathlib/mathlib.h"
  20. #include "in_buttons.h"
  21. #include "vstdlib/random.h"
  22. extern ConVar sk_plr_dmg_crowbar;
  23. #define CROWBAR_RANGE 64.0f
  24. #define CROWBAR_REFIRE_MISS 0.5f
  25. #define CROWBAR_REFIRE_HIT 0.25f
  26. #ifdef CLIENT_DLL
  27. #define CWeaponCrowbar C_WeaponCrowbar
  28. #endif
  29. //-----------------------------------------------------------------------------
  30. // CWeaponCrowbar
  31. //-----------------------------------------------------------------------------
  32. class CWeaponCrowbar : public CBaseHL1MPCombatWeapon
  33. {
  34. DECLARE_CLASS( CWeaponCrowbar, CBaseHL1MPCombatWeapon );
  35. public:
  36. DECLARE_NETWORKCLASS();
  37. DECLARE_PREDICTABLE();
  38. #ifndef CLIENT_DLL
  39. DECLARE_DATADESC();
  40. #endif
  41. CWeaponCrowbar();
  42. void Precache( void );
  43. virtual void ItemPostFrame( void );
  44. void PrimaryAttack( void );
  45. public:
  46. trace_t m_traceHit;
  47. Activity m_nHitActivity;
  48. private:
  49. virtual void Swing( void );
  50. virtual void Hit( void );
  51. virtual void ImpactEffect( void );
  52. void ImpactSound( CBaseEntity *pHitEntity );
  53. virtual Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner );
  54. public:
  55. };
  56. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrowbar, DT_WeaponCrowbar );
  57. BEGIN_NETWORK_TABLE( CWeaponCrowbar, DT_WeaponCrowbar )
  58. /// what
  59. END_NETWORK_TABLE()
  60. BEGIN_PREDICTION_DATA( CWeaponCrowbar )
  61. END_PREDICTION_DATA()
  62. LINK_ENTITY_TO_CLASS( weapon_crowbar, CWeaponCrowbar );
  63. PRECACHE_WEAPON_REGISTER( weapon_crowbar );
  64. #ifndef CLIENT_DLL
  65. BEGIN_DATADESC( CWeaponCrowbar )
  66. // DEFINE_FIELD( m_trLineHit, trace_t ),
  67. // DEFINE_FIELD( m_trHullHit, trace_t ),
  68. // DEFINE_FIELD( m_nHitActivity, FIELD_INTEGER ),
  69. // DEFINE_FIELD( m_traceHit, trace_t ),
  70. // Class CWeaponCrowbar:
  71. // DEFINE_FIELD( m_nHitActivity, FIELD_INTEGER ),
  72. // Function Pointers
  73. DEFINE_FUNCTION( Hit ),
  74. END_DATADESC()
  75. #endif
  76. #define BLUDGEON_HULL_DIM 16
  77. static const Vector g_bludgeonMins(-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM,-BLUDGEON_HULL_DIM);
  78. static const Vector g_bludgeonMaxs(BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM,BLUDGEON_HULL_DIM);
  79. //-----------------------------------------------------------------------------
  80. // Constructor
  81. //-----------------------------------------------------------------------------
  82. CWeaponCrowbar::CWeaponCrowbar()
  83. {
  84. m_bFiresUnderwater = true;
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose: Precache the weapon
  88. //-----------------------------------------------------------------------------
  89. void CWeaponCrowbar::Precache( void )
  90. {
  91. //Call base class first
  92. BaseClass::Precache();
  93. }
  94. //------------------------------------------------------------------------------
  95. // Purpose : Update weapon
  96. //------------------------------------------------------------------------------
  97. void CWeaponCrowbar::ItemPostFrame( void )
  98. {
  99. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  100. if ( pOwner == NULL )
  101. return;
  102. if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
  103. {
  104. PrimaryAttack();
  105. }
  106. else
  107. {
  108. WeaponIdle();
  109. return;
  110. }
  111. }
  112. //------------------------------------------------------------------------------
  113. // Purpose :
  114. // Input :
  115. // Output :
  116. //------------------------------------------------------------------------------
  117. void CWeaponCrowbar::PrimaryAttack()
  118. {
  119. Swing();
  120. }
  121. //------------------------------------------------------------------------------
  122. // Purpose: Implement impact function
  123. //------------------------------------------------------------------------------
  124. void CWeaponCrowbar::Hit( void )
  125. {
  126. //Make sound for the AI
  127. #ifndef CLIENT_DLL
  128. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  129. CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, m_traceHit.endpos, 400, 0.2f, pPlayer );
  130. CBaseEntity *pHitEntity = m_traceHit.m_pEnt;
  131. //Apply damage to a hit target
  132. if ( pHitEntity != NULL )
  133. {
  134. Vector hitDirection;
  135. pPlayer->EyeVectors( &hitDirection, NULL, NULL );
  136. VectorNormalize( hitDirection );
  137. ClearMultiDamage();
  138. CTakeDamageInfo info( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB );
  139. CalculateMeleeDamageForce( &info, hitDirection, m_traceHit.endpos );
  140. pHitEntity->DispatchTraceAttack( info, hitDirection, &m_traceHit );
  141. ApplyMultiDamage();
  142. // Now hit all triggers along the ray that...
  143. TraceAttackToTriggers( CTakeDamageInfo( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB ), m_traceHit.startpos, m_traceHit.endpos, hitDirection );
  144. //Play an impact sound
  145. ImpactSound( pHitEntity );
  146. }
  147. #endif
  148. //Apply an impact effect
  149. ImpactEffect();
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose: Play the impact sound
  153. // Input : pHitEntity - entity that we hit
  154. // assumes pHitEntity is not null
  155. //-----------------------------------------------------------------------------
  156. void CWeaponCrowbar::ImpactSound( CBaseEntity *pHitEntity )
  157. {
  158. bool bIsWorld = ( pHitEntity->entindex() == 0 );
  159. #ifndef CLIENT_DLL
  160. if ( !bIsWorld )
  161. {
  162. bIsWorld |= pHitEntity->Classify() == CLASS_NONE || pHitEntity->Classify() == CLASS_MACHINE;
  163. }
  164. #endif
  165. if( bIsWorld )
  166. {
  167. WeaponSound( MELEE_HIT_WORLD );
  168. }
  169. else
  170. {
  171. WeaponSound( MELEE_HIT );
  172. }
  173. }
  174. Activity CWeaponCrowbar::ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner )
  175. {
  176. int i, j, k;
  177. float distance;
  178. const float *minmaxs[2] = {mins.Base(), maxs.Base()};
  179. trace_t tmpTrace;
  180. Vector vecHullEnd = hitTrace.endpos;
  181. Vector vecEnd;
  182. distance = 1e6f;
  183. Vector vecSrc = hitTrace.startpos;
  184. vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2);
  185. UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
  186. if ( tmpTrace.fraction == 1.0 )
  187. {
  188. for ( i = 0; i < 2; i++ )
  189. {
  190. for ( j = 0; j < 2; j++ )
  191. {
  192. for ( k = 0; k < 2; k++ )
  193. {
  194. vecEnd.x = vecHullEnd.x + minmaxs[i][0];
  195. vecEnd.y = vecHullEnd.y + minmaxs[j][1];
  196. vecEnd.z = vecHullEnd.z + minmaxs[k][2];
  197. UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace );
  198. if ( tmpTrace.fraction < 1.0 )
  199. {
  200. float thisDistance = (tmpTrace.endpos - vecSrc).Length();
  201. if ( thisDistance < distance )
  202. {
  203. hitTrace = tmpTrace;
  204. distance = thisDistance;
  205. }
  206. }
  207. }
  208. }
  209. }
  210. }
  211. else
  212. {
  213. hitTrace = tmpTrace;
  214. }
  215. return ACT_VM_HITCENTER;
  216. }
  217. #ifdef HL1MP_CLIENT_DLL
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Handle jeep impacts
  220. //-----------------------------------------------------------------------------
  221. void ImpactCrowbarCallback( const CEffectData &data )
  222. {
  223. trace_t tr;
  224. Vector vecOrigin, vecStart, vecShotDir;
  225. int iMaterial, iDamageType, iHitbox;
  226. short nSurfaceProp;
  227. C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
  228. bool bIsWorld = ( pEntity->entindex() == 0 );
  229. if ( !pEntity )
  230. {
  231. // This happens for impacts that occur on an object that's then destroyed.
  232. // Clear out the fraction so it uses the server's data
  233. tr.fraction = 1.0;
  234. GetActiveWeapon()->WeaponSound( bIsWorld ? MELEE_HIT_WORLD : MELEE_HIT );
  235. return;
  236. }
  237. // If we hit, perform our custom effects and play the sound
  238. if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) )
  239. {
  240. // Check for custom effects based on the Decal index
  241. PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 2 );
  242. }
  243. GetActiveWeapon()->WeaponSound( bIsWorld ? MELEE_HIT_WORLD : MELEE_HIT );
  244. }
  245. DECLARE_CLIENT_EFFECT( "ImpactCrowbar", ImpactCrowbarCallback );
  246. #endif
  247. //-----------------------------------------------------------------------------
  248. // Purpose:
  249. //-----------------------------------------------------------------------------
  250. void CWeaponCrowbar::ImpactEffect( void )
  251. {
  252. //FIXME: need new decals
  253. #ifdef HL1MP_CLIENT_DLL
  254. // in hl1mp force the basic crowbar sound
  255. UTIL_ImpactTrace( &m_traceHit, DMG_CLUB, "ImpactCrowbar" );
  256. #else
  257. UTIL_ImpactTrace( &m_traceHit, DMG_CLUB );
  258. #endif
  259. }
  260. //------------------------------------------------------------------------------
  261. // Purpose : Starts the swing of the weapon and determines the animation
  262. //------------------------------------------------------------------------------
  263. void CWeaponCrowbar::Swing( void )
  264. {
  265. // Try a ray
  266. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  267. if ( !pOwner )
  268. return;
  269. Vector swingStart = pOwner->Weapon_ShootPosition( );
  270. Vector forward;
  271. pOwner->EyeVectors( &forward, NULL, NULL );
  272. Vector swingEnd = swingStart + forward * CROWBAR_RANGE;
  273. UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &m_traceHit );
  274. m_nHitActivity = ACT_VM_HITCENTER;
  275. if ( m_traceHit.fraction == 1.0 )
  276. {
  277. 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
  278. // Back off by hull "radius"
  279. swingEnd -= forward * bludgeonHullRadius;
  280. UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &m_traceHit );
  281. if ( m_traceHit.fraction < 1.0 )
  282. {
  283. m_nHitActivity = ChooseIntersectionPointAndActivity( m_traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner );
  284. }
  285. }
  286. // -------------------------
  287. // Miss
  288. // -------------------------
  289. if ( m_traceHit.fraction == 1.0f )
  290. {
  291. m_nHitActivity = ACT_VM_MISSCENTER;
  292. //Play swing sound
  293. WeaponSound( SINGLE );
  294. //Setup our next attack times
  295. m_flNextPrimaryAttack = gpGlobals->curtime + CROWBAR_REFIRE_MISS;
  296. }
  297. else
  298. {
  299. Hit();
  300. //Setup our next attack times
  301. m_flNextPrimaryAttack = gpGlobals->curtime + CROWBAR_REFIRE_HIT;
  302. }
  303. //Send the anim
  304. SendWeaponAnim( m_nHitActivity );
  305. pOwner->SetAnimation( PLAYER_ATTACK1 );
  306. }