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.

239 lines
7.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: TF version of the stickybolt code.
  4. // I broke off our own version because I didn't want to accidentally break HL2.
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //-----------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #include "cbase.h"
  14. #include "c_basetempentity.h"
  15. #include "fx.h"
  16. #include "decals.h"
  17. #include "iefx.h"
  18. #include "engine/IEngineSound.h"
  19. #include "materialsystem/imaterialvar.h"
  20. #include "IEffects.h"
  21. #include "engine/IEngineTrace.h"
  22. #include "vphysics/constraints.h"
  23. #include "engine/ivmodelinfo.h"
  24. #include "tempent.h"
  25. #include "c_te_legacytempents.h"
  26. #include "engine/ivdebugoverlay.h"
  27. #include "c_te_effect_dispatch.h"
  28. #include "c_tf_player.h"
  29. #include "GameEventListener.h"
  30. #include "tf_shareddefs.h"
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. extern IPhysicsSurfaceProps *physprops;
  34. IPhysicsObject *GetWorldPhysObject( void );
  35. //-----------------------------------------------------------------------------
  36. // Purpose: Creates a Bolt in the world and Ragdolls
  37. // For Attached Bolts on players look at hud_bowcharge "arrow_impact" which should be moved here
  38. //-----------------------------------------------------------------------------
  39. void CreateCrossbowBoltTF( const Vector &vecOrigin, const Vector &vecDirection, const int iFlags, unsigned char nColor )
  40. {
  41. const char* pszModelName = NULL;
  42. float flDirOffset = 5.0f;
  43. float flScale = 1.0f;
  44. float flLifeTime = 30.0f;
  45. switch ( iFlags )
  46. {
  47. case TF_PROJECTILE_STICKY_BALL:
  48. pszModelName = g_pszArrowModels[MODEL_SNOWBALL];
  49. break;
  50. case TF_PROJECTILE_ARROW:
  51. pszModelName = g_pszArrowModels[MODEL_ARROW_REGULAR];
  52. break;
  53. case TF_PROJECTILE_BUILDING_REPAIR_BOLT:
  54. pszModelName = g_pszArrowModels[MODEL_ARROW_BUILDING_REPAIR];
  55. flDirOffset = -2.0f;
  56. break;
  57. case TF_PROJECTILE_FESTIVE_ARROW:
  58. pszModelName = g_pszArrowModels[MODEL_FESTIVE_ARROW_REGULAR];
  59. break;
  60. case TF_PROJECTILE_HEALING_BOLT:
  61. #ifdef STAGING_ONLY
  62. case TF_PROJECTILE_MILK_BOLT:
  63. #endif
  64. pszModelName = g_pszArrowModels[MODEL_SYRINGE];
  65. flDirOffset = 0.0f;
  66. flScale = 3.0f;
  67. break;
  68. case TF_PROJECTILE_FESTIVE_HEALING_BOLT:
  69. pszModelName = g_pszArrowModels[MODEL_FESTIVE_HEALING_BOLT];
  70. flScale = 2.5f;
  71. break;
  72. case TF_PROJECTILE_BREAD_MONSTER:
  73. case TF_PROJECTILE_BREADMONSTER_JARATE:
  74. case TF_PROJECTILE_BREADMONSTER_MADMILK:
  75. pszModelName = g_pszArrowModels[MODEL_BREAD_MONSTER];
  76. flLifeTime = 8.0f;
  77. flScale = 2.5f;
  78. break;
  79. case TF_PROJECTILE_GRAPPLINGHOOK:
  80. pszModelName = g_pszArrowModels[MODEL_GRAPPLINGHOOK];
  81. flDirOffset = 0.0f;
  82. flLifeTime = 0.1f;
  83. break;
  84. #ifdef STAGING_ONLY
  85. case TF_PROJECTILE_THROWING_KNIFE:
  86. pszModelName = g_pszArrowModels[MODEL_THROWING_KNIFE];
  87. break;
  88. case TF_PROJECTILE_SNIPERBULLET:
  89. pszModelName = g_pszArrowModels[MODEL_SYRINGE];
  90. break;
  91. #endif // STAGING_ONLY
  92. default:
  93. // Unsupported Model
  94. Assert( 0 );
  95. pszModelName = g_pszArrowModels[MODEL_ARROW_REGULAR];
  96. return;
  97. }
  98. model_t *pModel = (model_t *)engine->LoadModel( pszModelName );
  99. QAngle vAngles;
  100. VectorAngles( vecDirection, vAngles );
  101. C_LocalTempEntity *arrow = tempents->SpawnTempModel( pModel, vecOrigin - vecDirection * flDirOffset, vAngles, Vector(0, 0, 0 ), flLifeTime, FTENT_NONE );
  102. if ( arrow )
  103. {
  104. arrow->SetModelScale( flScale );
  105. arrow->m_nSkin = nColor;
  106. }
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. //-----------------------------------------------------------------------------
  111. void StickRagdollNowTF(
  112. const Vector &vecOrigin,
  113. const Vector &vecDirection,
  114. const ClientEntityHandle_t &entHandle,
  115. const int boneIndexAttached,
  116. const int physicsBoneIndex,
  117. const int iShooterIndex,
  118. const int iHitGroup,
  119. const int iVictim,
  120. const int iFlags,
  121. unsigned char nColor
  122. ) {
  123. Ray_t shotRay;
  124. trace_t tr;
  125. UTIL_TraceLine( vecOrigin - vecDirection * 16, vecOrigin + vecDirection * 64, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
  126. if ( tr.surface.flags & SURF_SKY )
  127. return;
  128. C_BaseAnimating *pModel = dynamic_cast< C_BaseAnimating * >( entHandle.Get() );
  129. if ( pModel )
  130. {
  131. IPhysicsObject *pPhysicsObject = NULL;
  132. ragdoll_t *pRagdollT = NULL;
  133. if ( pModel->m_pRagdoll )
  134. {
  135. CRagdoll *pCRagdoll = dynamic_cast < CRagdoll * > ( pModel->m_pRagdoll );
  136. if ( pCRagdoll )
  137. {
  138. pRagdollT = pCRagdoll->GetRagdoll();
  139. if ( physicsBoneIndex < pRagdollT->listCount )
  140. {
  141. pPhysicsObject = pRagdollT->list[physicsBoneIndex].pObject;
  142. }
  143. }
  144. }
  145. IPhysicsObject *pReference = GetWorldPhysObject();
  146. if ( pReference == NULL || pPhysicsObject == NULL )
  147. return;
  148. float frand = (float) rand() / VALVE_RAND_MAX;
  149. Vector adjust = vecDirection*7 + vecDirection * frand * 7;
  150. Vector vecBonePos;
  151. QAngle boneAngles;
  152. pPhysicsObject->GetPosition( &vecBonePos, &boneAngles );
  153. QAngle angles;
  154. pPhysicsObject->SetPosition( vecOrigin-adjust, boneAngles, true );
  155. pPhysicsObject->EnableMotion( false );
  156. int nNodeIndex = pRagdollT->list[physicsBoneIndex].parentIndex;
  157. // find largest mass bone
  158. float flTargetMass = 0;
  159. for ( int i = 0; i < pRagdollT->listCount; i++ )
  160. {
  161. flTargetMass = MAX(flTargetMass, pRagdollT->list[i].pObject->GetMass() );
  162. }
  163. // walk the chain of bones from the pinned bone to the root and set each to the max mass
  164. // This helps transmit the impulses required to stabilize the constraint -- it keeps the body from
  165. // leaving the constraint because of some high mass bone hanging at the other end of the chain
  166. while ( nNodeIndex >= 0 )
  167. {
  168. if ( pRagdollT->list[nNodeIndex].pConstraint )
  169. {
  170. float flCurrentMass = pRagdollT->list[nNodeIndex].pObject->GetMass();
  171. flCurrentMass = MAX(flCurrentMass, flTargetMass);
  172. pRagdollT->list[nNodeIndex].pObject->SetMass( flCurrentMass );
  173. }
  174. nNodeIndex = pRagdollT->list[nNodeIndex].parentIndex;
  175. }
  176. }
  177. UTIL_ImpactTrace( &tr, 0 );
  178. CreateCrossbowBoltTF( vecOrigin, vecDirection, iFlags, nColor );
  179. //Achievement stuff.
  180. if ( iHitGroup == HITGROUP_HEAD )
  181. {
  182. CTFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  183. if ( pLocalPlayer && pLocalPlayer->entindex() == iShooterIndex )
  184. {
  185. CTFPlayer *pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictim ) );
  186. if ( pVictim && pVictim->IsPlayerClass( TF_CLASS_HEAVYWEAPONS ) )
  187. {
  188. IGameEvent *event = gameeventmanager->CreateEvent( "player_pinned" );
  189. if ( event )
  190. {
  191. gameeventmanager->FireEventClientSide( event );
  192. }
  193. }
  194. }
  195. }
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void StickyBoltCallbackTF( const CEffectData &data )
  201. {
  202. StickRagdollNowTF(
  203. data.m_vOrigin,
  204. data.m_vNormal,
  205. data.m_hEntity,
  206. data.m_nAttachmentIndex,
  207. data.m_nMaterial,
  208. data.m_nHitBox,
  209. data.m_nDamageType,
  210. data.m_nSurfaceProp,
  211. data.m_fFlags,
  212. data.m_nColor
  213. );
  214. }
  215. DECLARE_CLIENT_EFFECT( "TFBoltImpact", StickyBoltCallbackTF );