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.

823 lines
21 KiB

  1. //======= Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ======
  2. //
  3. //
  4. //===============================================================================
  5. #include "cbase.h"
  6. #include "rope.h"
  7. #include "entitylist.h"
  8. #include "rope_shared.h"
  9. #include "sendproxy.h"
  10. #include "rope_helpers.h"
  11. #include "te_effect_dispatch.h"
  12. #include "videocfg/videocfg.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //--------------------------------------------
  16. // Rope Spawn Flags
  17. //--------------------------------------------
  18. #define SF_ROPE_RESIZE 1 // Automatically resize the rope
  19. // -------------------------------------------------------------------------------- //
  20. // Fun With Tables.
  21. // -------------------------------------------------------------------------------- //
  22. LINK_ENTITY_TO_CLASS( move_rope, CRopeKeyframe );
  23. LINK_ENTITY_TO_CLASS( keyframe_rope, CRopeKeyframe );
  24. IMPLEMENT_SERVERCLASS_ST_NOBASE( CRopeKeyframe, DT_RopeKeyframe )
  25. SendPropEHandle(SENDINFO(m_hStartPoint)),
  26. SendPropEHandle(SENDINFO(m_hEndPoint)),
  27. SendPropInt( SENDINFO(m_iStartAttachment), 5, 0 ),
  28. SendPropInt( SENDINFO(m_iEndAttachment), 5, 0 ),
  29. SendPropInt( SENDINFO(m_Slack), 13 ),
  30. SendPropInt( SENDINFO(m_RopeLength), 15 ),
  31. SendPropInt( SENDINFO(m_fLockedPoints), 4, SPROP_UNSIGNED ),
  32. SendPropInt( SENDINFO(m_nChangeCount), 8, SPROP_UNSIGNED ),
  33. SendPropInt( SENDINFO(m_RopeFlags), ROPE_NUMFLAGS, SPROP_UNSIGNED ),
  34. SendPropInt( SENDINFO(m_nSegments), 4, SPROP_UNSIGNED ),
  35. SendPropBool( SENDINFO(m_bConstrainBetweenEndpoints) ),
  36. SendPropInt( SENDINFO(m_iRopeMaterialModelIndex), 16, SPROP_UNSIGNED ),
  37. SendPropInt( SENDINFO(m_Subdiv), 4, SPROP_UNSIGNED ),
  38. SendPropFloat( SENDINFO(m_TextureScale), 10, 0, 0.1f, 10.0f ),
  39. SendPropFloat( SENDINFO(m_Width), 0, SPROP_NOSCALE ),
  40. SendPropFloat( SENDINFO(m_flScrollSpeed), 0, SPROP_NOSCALE ),
  41. SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
  42. SendPropEHandle(SENDINFO_NAME(m_hMoveParent, moveparent) ),
  43. SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
  44. SendPropInt (SENDINFO(m_iDefaultRopeMaterialModelIndex), 16, SPROP_UNSIGNED ),
  45. #if 1
  46. // #ifndef _X360 -- X360 client and Win32 XLSP dedicated server need equivalent SendTables
  47. SendPropInt( SENDINFO(m_nMinCPULevel), CPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  48. SendPropInt( SENDINFO(m_nMaxCPULevel), CPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  49. SendPropInt( SENDINFO(m_nMinGPULevel), GPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  50. SendPropInt( SENDINFO(m_nMaxGPULevel), GPU_LEVEL_BIT_COUNT, SPROP_UNSIGNED ),
  51. #endif
  52. END_SEND_TABLE()
  53. BEGIN_DATADESC( CRopeKeyframe )
  54. DEFINE_FIELD( m_RopeFlags, FIELD_INTEGER ),
  55. DEFINE_KEYFIELD( m_iNextLinkName, FIELD_STRING, "NextKey" ),
  56. DEFINE_KEYFIELD( m_Slack, FIELD_INTEGER, "Slack" ),
  57. DEFINE_KEYFIELD( m_Width, FIELD_FLOAT, "Width" ),
  58. DEFINE_KEYFIELD( m_TextureScale, FIELD_FLOAT, "TextureScale" ),
  59. DEFINE_FIELD( m_nSegments, FIELD_INTEGER ),
  60. DEFINE_FIELD( m_bConstrainBetweenEndpoints, FIELD_BOOLEAN ),
  61. DEFINE_FIELD( m_strRopeMaterialModel, FIELD_STRING ),
  62. DEFINE_FIELD( m_iRopeMaterialModelIndex, FIELD_MODELINDEX ),
  63. DEFINE_KEYFIELD( m_Subdiv, FIELD_INTEGER, "Subdiv" ),
  64. DEFINE_FIELD( m_RopeLength, FIELD_INTEGER ),
  65. DEFINE_FIELD( m_fLockedPoints, FIELD_INTEGER ),
  66. DEFINE_FIELD( m_bCreatedFromMapFile, FIELD_BOOLEAN ),
  67. DEFINE_KEYFIELD( m_flScrollSpeed, FIELD_FLOAT, "ScrollSpeed" ),
  68. DEFINE_FIELD( m_bStartPointValid, FIELD_BOOLEAN ),
  69. DEFINE_FIELD( m_bEndPointValid, FIELD_BOOLEAN ),
  70. DEFINE_FIELD( m_hStartPoint, FIELD_EHANDLE ),
  71. DEFINE_FIELD( m_hEndPoint, FIELD_EHANDLE ),
  72. DEFINE_FIELD( m_iStartAttachment, FIELD_SHORT ),
  73. DEFINE_FIELD( m_iEndAttachment, FIELD_SHORT ),
  74. // Inputs
  75. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetScrollSpeed", InputSetScrollSpeed ),
  76. DEFINE_INPUTFUNC( FIELD_VECTOR, "SetForce", InputSetForce ),
  77. DEFINE_INPUTFUNC( FIELD_VOID, "Break", InputBreak ),
  78. END_DATADESC()
  79. // -------------------------------------------------------------------------------- //
  80. // CRopeKeyframe implementation.
  81. // -------------------------------------------------------------------------------- //
  82. CRopeKeyframe::CRopeKeyframe()
  83. {
  84. AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  85. m_takedamage = DAMAGE_YES;
  86. m_iStartAttachment = m_iEndAttachment = 0;
  87. m_Slack = 0;
  88. m_Width = 2;
  89. m_TextureScale = 4; // 4:1
  90. m_nSegments = 5;
  91. m_RopeLength = 20;
  92. m_fLockedPoints = (int) (ROPE_LOCK_START_POINT | ROPE_LOCK_END_POINT); // by default, both points are locked
  93. m_flScrollSpeed = 0;
  94. m_RopeFlags = ROPE_SIMULATE | ROPE_INITIAL_HANG;
  95. m_iRopeMaterialModelIndex = -1;
  96. m_Subdiv = 2;
  97. m_iDefaultRopeMaterialModelIndex = -1;
  98. m_bCreatedFromMapFile = true;
  99. }
  100. CRopeKeyframe::~CRopeKeyframe()
  101. {
  102. // Release transmit state ownership.
  103. SetStartPoint( NULL, 0 );
  104. SetEndPoint( NULL, 0 );
  105. SetParent( NULL, 0 );
  106. }
  107. void CRopeKeyframe::SetAttachmentPoint( CBaseHandle &hOutEnt, short &iOutAttachment, CBaseEntity *pEnt, int iAttachment )
  108. {
  109. // Unforce our previously attached entity from transmitting.
  110. CBaseEntity *pCurEnt = gEntList.GetBaseEntity( hOutEnt );
  111. if ( pCurEnt && pCurEnt->edict() )
  112. {
  113. pCurEnt->DecrementTransmitStateOwnedCounter();
  114. pCurEnt->DispatchUpdateTransmitState();
  115. }
  116. hOutEnt = pEnt;
  117. iOutAttachment = iAttachment;
  118. // Force this entity to transmit.
  119. if ( pEnt )
  120. {
  121. pEnt->SetTransmitState( FL_EDICT_ALWAYS );
  122. pEnt->IncrementTransmitStateOwnedCounter();
  123. }
  124. EndpointsChanged();
  125. }
  126. void CRopeKeyframe::SetStartPoint( CBaseEntity *pStartPoint, int attachment )
  127. {
  128. SetAttachmentPoint( m_hStartPoint.GetForModify(), m_iStartAttachment.GetForModify(), pStartPoint, attachment );
  129. }
  130. void CRopeKeyframe::SetEndPoint( CBaseEntity *pEndPoint, int attachment )
  131. {
  132. SetAttachmentPoint( m_hEndPoint.GetForModify(), m_iEndAttachment.GetForModify(), pEndPoint, attachment );
  133. }
  134. void CRopeKeyframe::SetParent( CBaseEntity *pNewParent, int iAttachment )
  135. {
  136. CBaseEntity *pCurParent = GetMoveParent();
  137. if ( pCurParent )
  138. {
  139. pCurParent->DecrementTransmitStateOwnedCounter();
  140. pCurParent->DispatchUpdateTransmitState();
  141. }
  142. // Make sure our move parent always transmits or we get asserts on the client.
  143. if ( pNewParent )
  144. {
  145. pNewParent->IncrementTransmitStateOwnedCounter();
  146. pNewParent->SetTransmitState( FL_EDICT_ALWAYS );
  147. }
  148. BaseClass::SetParent( pNewParent, iAttachment );
  149. }
  150. void CRopeKeyframe::EnablePlayerWeaponAttach( bool bAttach )
  151. {
  152. int newFlags = m_RopeFlags;
  153. if ( bAttach )
  154. newFlags |= ROPE_PLAYER_WPN_ATTACH;
  155. else
  156. newFlags &= ~ROPE_PLAYER_WPN_ATTACH;
  157. if ( newFlags != m_RopeFlags )
  158. {
  159. m_RopeFlags = newFlags;
  160. }
  161. }
  162. CRopeKeyframe* CRopeKeyframe::Create(
  163. CBaseEntity *pStartEnt,
  164. CBaseEntity *pEndEnt,
  165. int iStartAttachment,
  166. int iEndAttachment,
  167. int ropeWidth,
  168. const char *pMaterialName,
  169. int numSegments,
  170. const char *pClassName
  171. )
  172. {
  173. CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( pClassName );
  174. if( !pRet )
  175. return NULL;
  176. pRet->SetStartPoint( pStartEnt, iStartAttachment );
  177. pRet->SetEndPoint( pEndEnt, iEndAttachment );
  178. pRet->m_bCreatedFromMapFile = false;
  179. pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG;
  180. pRet->Init();
  181. pRet->SetMaterial( pMaterialName );
  182. pRet->m_Width = ropeWidth;
  183. pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS );
  184. pRet->Spawn();
  185. return pRet;
  186. }
  187. CRopeKeyframe* CRopeKeyframe::CreateWithSecondPointDetached(
  188. CBaseEntity *pStartEnt,
  189. int iStartAttachment,
  190. int ropeLength,
  191. int ropeWidth,
  192. const char *pMaterialName,
  193. int numSegments,
  194. bool bInitialHang,
  195. const char *pClassName
  196. )
  197. {
  198. CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( pClassName );
  199. if( !pRet )
  200. return NULL;
  201. pRet->SetStartPoint( pStartEnt, iStartAttachment );
  202. pRet->SetEndPoint( NULL, 0 );
  203. pRet->m_bCreatedFromMapFile = false;
  204. pRet->m_fLockedPoints.Set( ROPE_LOCK_START_POINT ); // Only attach the first point.
  205. if( !bInitialHang )
  206. {
  207. pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG;
  208. }
  209. pRet->Init();
  210. pRet->SetMaterial( pMaterialName );
  211. pRet->m_RopeLength = ropeLength;
  212. pRet->m_Width = ropeWidth;
  213. pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS );
  214. return pRet;
  215. }
  216. void CRopeKeyframe::ActivateStartDirectionConstraints( bool bEnable )
  217. {
  218. if (bEnable)
  219. {
  220. m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_START_DIRECTION );
  221. }
  222. else
  223. {
  224. m_fLockedPoints &= ~((int)ROPE_LOCK_START_DIRECTION);
  225. }
  226. }
  227. void CRopeKeyframe::ActivateEndDirectionConstraints( bool bEnable )
  228. {
  229. if (bEnable)
  230. {
  231. m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_END_DIRECTION );
  232. }
  233. else
  234. {
  235. m_fLockedPoints &= ~((int)ROPE_LOCK_END_DIRECTION);
  236. }
  237. }
  238. void CRopeKeyframe::PrecacheShakeRopes()
  239. {
  240. PrecacheEffect( "ShakeRopes" );
  241. }
  242. void CRopeKeyframe::ShakeRopes( const Vector &vCenter, float flRadius, float flMagnitude )
  243. {
  244. CEffectData shakeData;
  245. shakeData.m_vOrigin = vCenter;
  246. shakeData.m_flRadius = flRadius;
  247. shakeData.m_flMagnitude = flMagnitude;
  248. DispatchEffect( "ShakeRopes", shakeData );
  249. }
  250. bool CRopeKeyframe::SetupHangDistance( float flHangDist )
  251. {
  252. CBaseEntity *pEnt1 = m_hStartPoint.Get();
  253. CBaseEntity *pEnt2 = m_hEndPoint.Get();
  254. if ( !pEnt1 || !pEnt2 )
  255. return false;
  256. // Calculate starting conditions so we can force it to hang down N inches.
  257. Vector v1 = pEnt1->GetAbsOrigin();
  258. if ( pEnt1->GetBaseAnimating() )
  259. pEnt1->GetBaseAnimating()->GetAttachment( m_iStartAttachment, v1 );
  260. Vector v2 = pEnt2->GetAbsOrigin();
  261. if ( pEnt2->GetBaseAnimating() )
  262. pEnt2->GetBaseAnimating()->GetAttachment( m_iEndAttachment, v2 );
  263. float flSlack, flLen;
  264. CalcRopeStartingConditions( v1, v2, ROPE_MAX_SEGMENTS, flHangDist, &flLen, &flSlack );
  265. m_RopeLength = (int)flLen;
  266. m_Slack = (int)flSlack;
  267. return true;
  268. }
  269. void CRopeKeyframe::Init()
  270. {
  271. SetLocalAngles( vec3_angle );
  272. RecalculateLength();
  273. m_nSegments = clamp( m_nSegments.Get(), 2, ROPE_MAX_SEGMENTS );
  274. UpdateBBox( true );
  275. m_bStartPointValid = (m_hStartPoint.Get() != NULL);
  276. m_bEndPointValid = (m_hEndPoint.Get() != NULL);
  277. // Sanity-check the rope texture scale before it goes over the wire
  278. if ( m_TextureScale < 0.1f )
  279. {
  280. Vector origin = GetAbsOrigin();
  281. GetEndPointPos( 0, origin );
  282. DevMsg( "move_rope has TextureScale less than 0.1 at (%2.2f, %2.2f, %2.2f)\n",
  283. origin.x, origin.y, origin.z );
  284. m_TextureScale = 0.1f;
  285. }
  286. else if ( m_TextureScale > 10.0f )
  287. {
  288. Vector origin = GetAbsOrigin();
  289. GetEndPointPos( 0, origin );
  290. DevMsg( "move_rope has TextureScale greater than 10 at (%2.2f, %2.2f, %2.2f)\n",
  291. origin.x, origin.y, origin.z );
  292. m_TextureScale = 10.0f;
  293. }
  294. }
  295. void CRopeKeyframe::Activate()
  296. {
  297. BaseClass::Activate();
  298. if( !m_bCreatedFromMapFile )
  299. return;
  300. if ( m_iDefaultRopeMaterialModelIndex == -1 )
  301. {
  302. m_iDefaultRopeMaterialModelIndex = PrecacheModel( "cable/cable.vmt" );
  303. }
  304. // Legacy support..
  305. if ( m_iRopeMaterialModelIndex == -1 )
  306. {
  307. m_iRopeMaterialModelIndex = m_iDefaultRopeMaterialModelIndex;
  308. }
  309. // Find the next entity in our chain.
  310. CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, m_iNextLinkName );
  311. if( pEnt && pEnt->edict() )
  312. {
  313. SetEndPoint( pEnt );
  314. if( m_spawnflags & SF_ROPE_RESIZE )
  315. m_RopeFlags |= ROPE_RESIZE;
  316. }
  317. else
  318. {
  319. // If we're from the map file, and we don't have a target ent, and
  320. // "Start Dangling" wasn't set, then this rope keyframe doesn't have
  321. // any rope coming out of it.
  322. if ( m_fLockedPoints & (int)ROPE_LOCK_END_POINT )
  323. {
  324. m_RopeFlags &= ~ROPE_SIMULATE;
  325. }
  326. }
  327. // By default, our start point is our own entity.
  328. SetStartPoint( this );
  329. // If we don't do this here, then when we save/load, we won't "own" the transmit
  330. // state of our parent, so the client might get our entity without our parent entity.
  331. SetParent( GetParent(), GetParentAttachment() );
  332. EndpointsChanged();
  333. Init();
  334. }
  335. void CRopeKeyframe::EndpointsChanged()
  336. {
  337. CBaseEntity *pStartEnt = m_hStartPoint.Get();
  338. if ( pStartEnt )
  339. {
  340. if ( (pStartEnt != this) || GetMoveParent() )
  341. {
  342. WatchPositionChanges( this, pStartEnt );
  343. }
  344. }
  345. CBaseEntity *pEndEnt = m_hEndPoint.Get();
  346. if ( pEndEnt )
  347. {
  348. if ( (pEndEnt != this) || GetMoveParent() )
  349. {
  350. WatchPositionChanges( this, pEndEnt );
  351. }
  352. }
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Purpose: Calculate the length of the rope
  356. //-----------------------------------------------------------------------------
  357. void CRopeKeyframe::RecalculateLength( void )
  358. {
  359. // Get my entities
  360. if( m_hEndPoint.Get() )
  361. {
  362. CBaseEntity *pStartEnt = m_hStartPoint.Get();
  363. CBaseEntity *pEndEnt = m_hEndPoint.Get();
  364. // Set the length
  365. m_RopeLength = (int)( pStartEnt->GetAbsOrigin() - pEndEnt->GetAbsOrigin() ).Length();
  366. }
  367. else
  368. {
  369. m_RopeLength = 0;
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: This should remove the rope next time it reaches a resting state.
  374. // Right now only the client knows when it reaches a resting state, so
  375. // for now it just removes itself after a short time.
  376. //-----------------------------------------------------------------------------
  377. void CRopeKeyframe::DieAtNextRest( void )
  378. {
  379. SetThink( &CBaseEntity::SUB_Remove );
  380. SetNextThink( gpGlobals->curtime + 1.0f );
  381. }
  382. void CRopeKeyframe::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
  383. {
  384. if ( !pInfo->m_pTransmitEdict->Get( entindex() ) )
  385. {
  386. BaseClass::SetTransmit( pInfo, bAlways );
  387. // Make sure our target ents are sent too.
  388. CBaseEntity *pEnt = m_hStartPoint;
  389. if ( pEnt )
  390. pEnt->SetTransmit( pInfo, bAlways );
  391. pEnt = m_hEndPoint;
  392. if ( pEnt )
  393. pEnt->SetTransmit( pInfo, bAlways );
  394. }
  395. }
  396. bool CRopeKeyframe::GetEndPointPos2( CBaseEntity *pAttached, int iAttachment, Vector &vPos )
  397. {
  398. if( !pAttached )
  399. return false;
  400. if ( iAttachment > 0 )
  401. {
  402. CBaseAnimating *pAnim = pAttached->GetBaseAnimating();
  403. if ( pAnim )
  404. {
  405. if( !pAnim->GetAttachment( iAttachment, vPos ) )
  406. return false;
  407. }
  408. else
  409. {
  410. return false;
  411. }
  412. }
  413. else
  414. {
  415. vPos = pAttached->GetAbsOrigin();
  416. }
  417. return true;
  418. }
  419. bool CRopeKeyframe::GetEndPointPos( int iPt, Vector &v )
  420. {
  421. if ( iPt == 0 )
  422. return GetEndPointPos2( m_hStartPoint, m_iStartAttachment, v );
  423. else
  424. return GetEndPointPos2( m_hEndPoint, m_iEndAttachment, v );
  425. }
  426. void CRopeKeyframe::UpdateBBox( bool bForceRelink )
  427. {
  428. Vector v1, v2;
  429. Vector vMin, vMax;
  430. if ( GetEndPointPos( 0, v1 ) )
  431. {
  432. if ( GetEndPointPos( 1, v2 ) )
  433. {
  434. VectorMin( v1, v2, vMin );
  435. VectorMax( v1, v2, vMax );
  436. // Set our bounds to enclose both endpoints and relink.
  437. vMin -= GetAbsOrigin();
  438. vMax -= GetAbsOrigin();
  439. }
  440. else
  441. {
  442. vMin = vMax = v1 - GetAbsOrigin();
  443. }
  444. }
  445. else
  446. {
  447. vMin = vMax = Vector( 0, 0, 0 );
  448. }
  449. if ( WorldAlignMins() != vMin || WorldAlignMaxs() != vMax )
  450. {
  451. UTIL_SetSize( this, vMin, vMax );
  452. }
  453. }
  454. //------------------------------------------------------------------------------
  455. // Purpose : Propagate force to each link in the rope. Check for loops
  456. // Input :
  457. // Output :
  458. //------------------------------------------------------------------------------
  459. void CRopeKeyframe::PropagateForce(CBaseEntity *pActivator, CBaseEntity *pCaller, CBaseEntity *pFirstLink, float x, float y, float z)
  460. {
  461. EntityMessageBegin( this, true );
  462. WRITE_FLOAT( x );
  463. WRITE_FLOAT( y );
  464. WRITE_FLOAT( z );
  465. MessageEnd();
  466. // UNDONE: Doesn't deal with intermediate loops
  467. // Propagate to next segment
  468. CRopeKeyframe *pNextLink = dynamic_cast<CRopeKeyframe*>((CBaseEntity *)m_hEndPoint);
  469. if (pNextLink && pNextLink != pFirstLink)
  470. {
  471. pNextLink->PropagateForce(pActivator, pCaller, pFirstLink, x, y, z);
  472. }
  473. }
  474. //------------------------------------------------------------------------------
  475. // Purpose: Set an instaneous force on the rope.
  476. // Input : Force vector.
  477. //------------------------------------------------------------------------------
  478. void CRopeKeyframe::InputSetForce( inputdata_t &inputdata )
  479. {
  480. Vector vecForce;
  481. inputdata.value.Vector3D(vecForce);
  482. PropagateForce( inputdata.pActivator, inputdata.pCaller, this, vecForce.x, vecForce.y, vecForce.z );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Breaks the rope if able
  486. // Input : &inputdata -
  487. //-----------------------------------------------------------------------------
  488. void CRopeKeyframe::InputBreak( inputdata_t &inputdata )
  489. {
  490. //Route through the damage code
  491. Break();
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose: Breaks the rope
  495. // Output : Returns true on success, false on failure.
  496. //-----------------------------------------------------------------------------
  497. bool CRopeKeyframe::Break( void )
  498. {
  499. DetachPoint( 0 );
  500. // Find whoever references us and detach us from them.
  501. // UNDONE: PERFORMANCE: This is very slow!!!
  502. CRopeKeyframe *pTest = NULL;
  503. pTest = gEntList.NextEntByClass( pTest );
  504. while ( pTest )
  505. {
  506. if( stricmp( STRING(pTest->m_iNextLinkName), STRING(GetEntityName()) ) == 0 )
  507. {
  508. pTest->DetachPoint( 1 );
  509. }
  510. pTest = gEntList.NextEntByClass( pTest );
  511. }
  512. return true;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. //-----------------------------------------------------------------------------
  517. void CRopeKeyframe::NotifyPositionChanged( CBaseEntity *pEntity )
  518. {
  519. ++m_nChangeCount;
  520. // Update our bbox?
  521. UpdateBBox( false );
  522. CBaseEntity *ents[2] = { m_hStartPoint.Get(), m_hEndPoint.Get() };
  523. if ( (m_RopeFlags & ROPE_RESIZE) && ents[0] && ents[0]->edict() && ents[1] && ents[1]->edict() )
  524. {
  525. int len = (int)( ents[0]->GetAbsOrigin() - ents[1]->GetAbsOrigin() ).Length() + m_Slack;
  526. if ( len != m_RopeLength )
  527. {
  528. m_RopeLength = len;
  529. }
  530. }
  531. // Figure out if our attachment points have gone away and make sure to update the client if they have.
  532. bool *pValid[2] = { &m_bStartPointValid, &m_bEndPointValid };
  533. for ( int i=0; i < 2; i++ )
  534. {
  535. bool bCurrentlyValid = ( ents[i] != NULL );
  536. if ( *pValid[i] != bCurrentlyValid )
  537. {
  538. *pValid[i] = bCurrentlyValid;
  539. }
  540. }
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose: Take damage will break the rope
  544. //-----------------------------------------------------------------------------
  545. int CRopeKeyframe::OnTakeDamage( const CTakeDamageInfo &info )
  546. {
  547. // Only allow this if it's been marked
  548. if( !(m_RopeFlags & ROPE_BREAKABLE) )
  549. return false;
  550. Break();
  551. return 0;
  552. }
  553. void CRopeKeyframe::Precache()
  554. {
  555. m_iRopeMaterialModelIndex = PrecacheModel( STRING( m_strRopeMaterialModel ) );
  556. PrecacheMaterial( "cable/rope_shadowdepth" );
  557. BaseClass::Precache();
  558. }
  559. void CRopeKeyframe::Spawn( void )
  560. {
  561. BaseClass::Spawn();
  562. Precache();
  563. }
  564. void CRopeKeyframe::DetachPoint( int iPoint )
  565. {
  566. Assert( iPoint == 0 || iPoint == 1 );
  567. m_fLockedPoints &= ~(1 << iPoint);
  568. }
  569. void CRopeKeyframe::EnableCollision()
  570. {
  571. if( !( m_RopeFlags & ROPE_COLLIDE ) )
  572. {
  573. m_RopeFlags |= ROPE_COLLIDE;
  574. }
  575. }
  576. void CRopeKeyframe::EnableWind( bool bEnable )
  577. {
  578. int flag = 0;
  579. if ( bEnable )
  580. {
  581. flag |= ROPE_USE_WIND;
  582. }
  583. if ( (m_RopeFlags & ROPE_USE_WIND) != flag )
  584. {
  585. m_RopeFlags |= flag;
  586. }
  587. }
  588. bool CRopeKeyframe::KeyValue( const char *szKeyName, const char *szValue )
  589. {
  590. if( stricmp( szKeyName, "Breakable" ) == 0 )
  591. {
  592. if( atoi( szValue ) == 1 )
  593. {
  594. m_RopeFlags |= ROPE_BREAKABLE;
  595. }
  596. }
  597. else if( stricmp( szKeyName, "Collide" ) == 0 )
  598. {
  599. if( atoi( szValue ) == 1 )
  600. m_RopeFlags |= ROPE_COLLIDE;
  601. }
  602. else if( stricmp( szKeyName, "Barbed" ) == 0 )
  603. {
  604. if( atoi( szValue ) == 1 )
  605. m_RopeFlags |= ROPE_BARBED;
  606. }
  607. else if( stricmp( szKeyName, "UseWind" ) == 0 )
  608. {
  609. if( atoi( szValue ) == 1 )
  610. {
  611. m_RopeFlags |= ROPE_USE_WIND;
  612. }
  613. }
  614. else if( stricmp( szKeyName, "Dangling" ) == 0 )
  615. {
  616. if( atoi( szValue ) == 1 )
  617. {
  618. m_fLockedPoints &= ~ROPE_LOCK_END_POINT; // detach our dest point
  619. }
  620. return true;
  621. }
  622. else if( stricmp( szKeyName, "Type" ) == 0 )
  623. {
  624. int iType = atoi( szValue );
  625. if( iType == 0 )
  626. m_nSegments = ROPE_MAX_SEGMENTS;
  627. else if( iType == 1 )
  628. m_nSegments = ROPE_TYPE1_NUMSEGMENTS;
  629. else
  630. m_nSegments = ROPE_TYPE2_NUMSEGMENTS;
  631. }
  632. else if ( stricmp( szKeyName, "RopeShader" ) == 0 )
  633. {
  634. // Legacy support for the RopeShader parameter.
  635. int iShader = atoi( szValue );
  636. if ( iShader == 0 )
  637. {
  638. m_strRopeMaterialModel = MAKE_STRING( "cable/cable.vmt" );
  639. }
  640. else if ( iShader == 1 )
  641. {
  642. m_strRopeMaterialModel = MAKE_STRING( "cable/rope.vmt" );
  643. }
  644. else
  645. {
  646. m_strRopeMaterialModel = MAKE_STRING( "cable/chain.vmt" );
  647. }
  648. }
  649. else if ( stricmp( szKeyName, "RopeMaterial" ) == 0 )
  650. {
  651. // Make sure we have a vmt extension.
  652. if ( Q_stristr( szValue, ".vmt" ) )
  653. {
  654. SetMaterial( szValue );
  655. }
  656. else
  657. {
  658. char str[512];
  659. Q_snprintf( str, sizeof( str ), "%s.vmt", szValue );
  660. SetMaterial( str );
  661. }
  662. }
  663. return BaseClass::KeyValue( szKeyName, szValue );
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Purpose: Input handler that sets the scroll speed.
  667. //-----------------------------------------------------------------------------
  668. void CRopeKeyframe::InputSetScrollSpeed( inputdata_t &inputdata )
  669. {
  670. m_flScrollSpeed = inputdata.value.Float();
  671. }
  672. void CRopeKeyframe::SetMaterial( const char *pName )
  673. {
  674. m_strRopeMaterialModel = AllocPooledString( pName );
  675. }
  676. int CRopeKeyframe::UpdateTransmitState()
  677. {
  678. // Certain entities like sprites and ropes are strewn throughout the level and they rarely change.
  679. // For these entities, it's more efficient to transmit them once and then always leave them on
  680. // the client. Otherwise, the server will have to send big bursts of data with the entity states
  681. // as they come in and out of the PVS.
  682. return SetTransmitState( FL_EDICT_ALWAYS );
  683. }