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.

178 lines
4.8 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the Sticky Bolt code. This constraints ragdolls to the world
  4. // after being hit by a crossbow bolt. If something here is acting funny
  5. // let me know - Adrian.
  6. //
  7. // $Workfile: $
  8. // $Date: $
  9. //
  10. //-----------------------------------------------------------------------------
  11. // $Log: $
  12. //
  13. // $NoKeywords: $
  14. //=============================================================================//
  15. #include "cbase.h"
  16. #include "c_basetempentity.h"
  17. #include "fx.h"
  18. #include "decals.h"
  19. #include "iefx.h"
  20. #include "engine/IEngineSound.h"
  21. #include "materialsystem/imaterialvar.h"
  22. #include "IEffects.h"
  23. #include "engine/IEngineTrace.h"
  24. #include "vphysics/constraints.h"
  25. #include "engine/ivmodelinfo.h"
  26. #include "tempent.h"
  27. #include "c_te_legacytempents.h"
  28. #include "engine/ivdebugoverlay.h"
  29. #include "c_te_effect_dispatch.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. extern IPhysicsSurfaceProps *physprops;
  33. IPhysicsObject *GetWorldPhysObject( void );
  34. extern ITempEnts* tempents;
  35. class CRagdollBoltEnumerator : public IPartitionEnumerator
  36. {
  37. public:
  38. //Forced constructor
  39. CRagdollBoltEnumerator( Ray_t& shot, Vector vOrigin )
  40. {
  41. m_rayShot = shot;
  42. m_vWorld = vOrigin;
  43. }
  44. //Actual work code
  45. IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
  46. {
  47. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() );
  48. if ( pEnt == NULL )
  49. return ITERATION_CONTINUE;
  50. C_BaseAnimating *pModel = static_cast< C_BaseAnimating * >( pEnt );
  51. if ( pModel == NULL )
  52. return ITERATION_CONTINUE;
  53. trace_t tr;
  54. enginetrace->ClipRayToEntity( m_rayShot, MASK_SHOT, pModel, &tr );
  55. IPhysicsObject *pPhysicsObject = NULL;
  56. //Find the real object we hit.
  57. if( tr.physicsbone >= 0 )
  58. {
  59. if ( pModel->m_pRagdoll )
  60. {
  61. CRagdoll *pCRagdoll = dynamic_cast < CRagdoll * > ( pModel->m_pRagdoll );
  62. if ( pCRagdoll )
  63. {
  64. ragdoll_t *pRagdollT = pCRagdoll->GetRagdoll();
  65. if ( tr.physicsbone < pRagdollT->listCount )
  66. {
  67. pPhysicsObject = pRagdollT->list[tr.physicsbone].pObject;
  68. }
  69. }
  70. }
  71. }
  72. if ( pPhysicsObject == NULL )
  73. return ITERATION_CONTINUE;
  74. if ( tr.fraction < 1.0 )
  75. {
  76. IPhysicsObject *pReference = GetWorldPhysObject();
  77. if ( pReference == NULL || pPhysicsObject == NULL )
  78. return ITERATION_CONTINUE;
  79. float flMass = pPhysicsObject->GetMass();
  80. pPhysicsObject->SetMass( flMass * 2 );
  81. constraint_ballsocketparams_t ballsocket;
  82. ballsocket.Defaults();
  83. pReference->WorldToLocal( &ballsocket.constraintPosition[0], m_vWorld );
  84. pPhysicsObject->WorldToLocal( &ballsocket.constraintPosition[1], tr.endpos );
  85. physenv->CreateBallsocketConstraint( pReference, pPhysicsObject, NULL, ballsocket );
  86. //Play a sound
  87. CPASAttenuationFilter filter( pEnt );
  88. EmitSound_t ep;
  89. ep.m_nChannel = CHAN_VOICE;
  90. ep.m_pSoundName = "Weapon_Crossbow.BoltSkewer";
  91. ep.m_flVolume = 1.0f;
  92. ep.m_SoundLevel = SNDLVL_NORM;
  93. ep.m_pOrigin = &pEnt->GetAbsOrigin();
  94. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
  95. return ITERATION_STOP;
  96. }
  97. return ITERATION_CONTINUE;
  98. }
  99. private:
  100. Ray_t m_rayShot;
  101. Vector m_vWorld;
  102. };
  103. #define CROSSBOW_BOLT_MODEL "models/crossbow_bolt.mdl"
  104. void CreateCrossbowBolt( const Vector &vecOrigin, const Vector &vecDirection )
  105. {
  106. model_t *pModel = (model_t *)engine->LoadModel( CROSSBOW_BOLT_MODEL );
  107. QAngle vAngles;
  108. VectorAngles( vecDirection, vAngles );
  109. if ( gpGlobals->maxClients > 1 )
  110. {
  111. tempents->SpawnTempModel( pModel, vecOrigin - vecDirection * 8, vAngles, Vector(0, 0, 0 ), 30.0f, FTENT_NONE );
  112. }
  113. else
  114. {
  115. tempents->SpawnTempModel( pModel, vecOrigin - vecDirection * 8, vAngles, Vector(0, 0, 0 ), 1, FTENT_NEVERDIE );
  116. }
  117. }
  118. void StickRagdollNow( const Vector &vecOrigin, const Vector &vecDirection )
  119. {
  120. Ray_t shotRay;
  121. trace_t tr;
  122. UTIL_TraceLine( vecOrigin, vecOrigin + vecDirection * 16, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
  123. if ( tr.surface.flags & SURF_SKY )
  124. return;
  125. Vector vecEnd = vecOrigin - vecDirection * 128;
  126. shotRay.Init( vecOrigin, vecEnd );
  127. CRagdollBoltEnumerator ragdollEnum( shotRay, vecOrigin );
  128. ::partition->EnumerateElementsAlongRay( PARTITION_CLIENT_RESPONSIVE_EDICTS, shotRay, false, &ragdollEnum );
  129. CreateCrossbowBolt( vecOrigin, vecDirection );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. // Input : &data -
  134. //-----------------------------------------------------------------------------
  135. void StickyBoltCallback( const CEffectData &data )
  136. {
  137. StickRagdollNow( data.m_vOrigin, data.m_vNormal );
  138. }
  139. DECLARE_CLIENT_EFFECT_BEGIN( BoltImpact, StickyBoltCallback )
  140. PRECACHE( MODEL, CROSSBOW_BOLT_MODEL )
  141. DECLARE_CLIENT_EFFECT_END()