diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/rope.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/rope.cpp')
| -rw-r--r-- | mp/src/game/server/rope.cpp | 1532 |
1 files changed, 766 insertions, 766 deletions
diff --git a/mp/src/game/server/rope.cpp b/mp/src/game/server/rope.cpp index 47591e3c..7ca53298 100644 --- a/mp/src/game/server/rope.cpp +++ b/mp/src/game/server/rope.cpp @@ -1,766 +1,766 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "cbase.h"
-#include "rope.h"
-#include "entitylist.h"
-#include "rope_shared.h"
-#include "sendproxy.h"
-#include "rope_helpers.h"
-#include "te_effect_dispatch.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-//--------------------------------------------
-// Rope Spawn Flags
-//--------------------------------------------
-#define SF_ROPE_RESIZE 1 // Automatically resize the rope
-
-// -------------------------------------------------------------------------------- //
-// Fun With Tables.
-// -------------------------------------------------------------------------------- //
-
-LINK_ENTITY_TO_CLASS( move_rope, CRopeKeyframe );
-LINK_ENTITY_TO_CLASS( keyframe_rope, CRopeKeyframe );
-
-IMPLEMENT_SERVERCLASS_ST_NOBASE( CRopeKeyframe, DT_RopeKeyframe )
- SendPropEHandle(SENDINFO(m_hStartPoint)),
- SendPropEHandle(SENDINFO(m_hEndPoint)),
- SendPropInt( SENDINFO(m_iStartAttachment), 5, 0 ),
- SendPropInt( SENDINFO(m_iEndAttachment), 5, 0 ),
-
- SendPropInt( SENDINFO(m_Slack), 12 ),
- SendPropInt( SENDINFO(m_RopeLength), 15 ),
- SendPropInt( SENDINFO(m_fLockedPoints), 4, SPROP_UNSIGNED ),
- SendPropInt( SENDINFO(m_RopeFlags), ROPE_NUMFLAGS, SPROP_UNSIGNED ),
- SendPropInt( SENDINFO(m_nSegments), 4, SPROP_UNSIGNED ),
- SendPropBool( SENDINFO(m_bConstrainBetweenEndpoints) ),
- SendPropInt( SENDINFO(m_iRopeMaterialModelIndex), 16, SPROP_UNSIGNED ),
- SendPropInt( SENDINFO(m_Subdiv), 4, SPROP_UNSIGNED ),
-
- SendPropFloat( SENDINFO(m_TextureScale), 10, 0, 0.1f, 10.0f ),
- SendPropFloat( SENDINFO(m_Width), 0, SPROP_NOSCALE ),
- SendPropFloat( SENDINFO(m_flScrollSpeed), 0, SPROP_NOSCALE ),
-
- SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
- SendPropEHandle(SENDINFO_NAME(m_hMoveParent, moveparent) ),
-
- SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED),
-END_SEND_TABLE()
-
-
-BEGIN_DATADESC( CRopeKeyframe )
-
- DEFINE_FIELD( m_RopeFlags, FIELD_INTEGER ),
-
- DEFINE_KEYFIELD( m_iNextLinkName, FIELD_STRING, "NextKey" ),
- DEFINE_KEYFIELD( m_Slack, FIELD_INTEGER, "Slack" ),
- DEFINE_KEYFIELD( m_Width, FIELD_FLOAT, "Width" ),
- DEFINE_KEYFIELD( m_TextureScale, FIELD_FLOAT, "TextureScale" ),
- DEFINE_FIELD( m_nSegments, FIELD_INTEGER ),
- DEFINE_FIELD( m_bConstrainBetweenEndpoints, FIELD_BOOLEAN ),
-
- DEFINE_FIELD( m_strRopeMaterialModel, FIELD_STRING ),
- DEFINE_FIELD( m_iRopeMaterialModelIndex, FIELD_MODELINDEX ),
- DEFINE_KEYFIELD( m_Subdiv, FIELD_INTEGER, "Subdiv" ),
- DEFINE_FIELD( m_RopeLength, FIELD_INTEGER ),
- DEFINE_FIELD( m_fLockedPoints, FIELD_INTEGER ),
- DEFINE_FIELD( m_bCreatedFromMapFile, FIELD_BOOLEAN ),
- DEFINE_KEYFIELD( m_flScrollSpeed, FIELD_FLOAT, "ScrollSpeed" ),
-
- DEFINE_FIELD( m_bStartPointValid, FIELD_BOOLEAN ),
- DEFINE_FIELD( m_bEndPointValid, FIELD_BOOLEAN ),
-
- DEFINE_FIELD( m_hStartPoint, FIELD_EHANDLE ),
- DEFINE_FIELD( m_hEndPoint, FIELD_EHANDLE ),
- DEFINE_FIELD( m_iStartAttachment, FIELD_SHORT ),
- DEFINE_FIELD( m_iEndAttachment, FIELD_SHORT ),
-
- // Inputs
- DEFINE_INPUTFUNC( FIELD_FLOAT, "SetScrollSpeed", InputSetScrollSpeed ),
- DEFINE_INPUTFUNC( FIELD_VECTOR, "SetForce", InputSetForce ),
- DEFINE_INPUTFUNC( FIELD_VOID, "Break", InputBreak ),
-
-END_DATADESC()
-
-
-
-// -------------------------------------------------------------------------------- //
-// CRopeKeyframe implementation.
-// -------------------------------------------------------------------------------- //
-
-CRopeKeyframe::CRopeKeyframe()
-{
- AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
-
- m_takedamage = DAMAGE_YES;
-
- m_iStartAttachment = m_iEndAttachment = 0;
-
- m_Slack = 0;
- m_Width = 2;
- m_TextureScale = 4; // 4:1
- m_nSegments = 5;
- m_RopeLength = 20;
- m_fLockedPoints = (int) (ROPE_LOCK_START_POINT | ROPE_LOCK_END_POINT); // by default, both points are locked
- m_flScrollSpeed = 0;
- m_RopeFlags = ROPE_SIMULATE | ROPE_INITIAL_HANG;
- m_iRopeMaterialModelIndex = -1;
- m_Subdiv = 2;
-
- m_bCreatedFromMapFile = true;
-}
-
-
-CRopeKeyframe::~CRopeKeyframe()
-{
- // Release transmit state ownership.
- SetStartPoint( NULL, 0 );
- SetEndPoint( NULL, 0 );
- SetParent( NULL, 0 );
-}
-
-
-void CRopeKeyframe::SetAttachmentPoint( CBaseHandle &hOutEnt, short &iOutAttachment, CBaseEntity *pEnt, int iAttachment )
-{
- // Unforce our previously attached entity from transmitting.
- CBaseEntity *pCurEnt = gEntList.GetBaseEntity( hOutEnt );
- if ( pCurEnt && pCurEnt->edict() )
- {
- pCurEnt->DecrementTransmitStateOwnedCounter();
- pCurEnt->DispatchUpdateTransmitState();
- }
-
- hOutEnt = pEnt;
- iOutAttachment = iAttachment;
-
- // Force this entity to transmit.
- if ( pEnt )
- {
- pEnt->SetTransmitState( FL_EDICT_ALWAYS );
- pEnt->IncrementTransmitStateOwnedCounter();
- }
-
- EndpointsChanged();
-}
-
-
-void CRopeKeyframe::SetStartPoint( CBaseEntity *pStartPoint, int attachment )
-{
- SetAttachmentPoint( m_hStartPoint.GetForModify(), m_iStartAttachment.GetForModify(), pStartPoint, attachment );
-}
-
-void CRopeKeyframe::SetEndPoint( CBaseEntity *pEndPoint, int attachment )
-{
- SetAttachmentPoint( m_hEndPoint.GetForModify(), m_iEndAttachment.GetForModify(), pEndPoint, attachment );
-}
-
-void CRopeKeyframe::SetParent( CBaseEntity *pNewParent, int iAttachment )
-{
- CBaseEntity *pCurParent = GetMoveParent();
- if ( pCurParent )
- {
- pCurParent->DecrementTransmitStateOwnedCounter();
- pCurParent->DispatchUpdateTransmitState();
- }
-
- // Make sure our move parent always transmits or we get asserts on the client.
- if ( pNewParent )
- {
- pNewParent->IncrementTransmitStateOwnedCounter();
- pNewParent->SetTransmitState( FL_EDICT_ALWAYS );
- }
-
- BaseClass::SetParent( pNewParent, iAttachment );
-}
-
-void CRopeKeyframe::EnablePlayerWeaponAttach( bool bAttach )
-{
- int newFlags = m_RopeFlags;
- if ( bAttach )
- newFlags |= ROPE_PLAYER_WPN_ATTACH;
- else
- newFlags &= ~ROPE_PLAYER_WPN_ATTACH;
-
- if ( newFlags != m_RopeFlags )
- {
- m_RopeFlags = newFlags;
- }
-}
-
-
-CRopeKeyframe* CRopeKeyframe::Create(
- CBaseEntity *pStartEnt,
- CBaseEntity *pEndEnt,
- int iStartAttachment,
- int iEndAttachment,
- int ropeWidth,
- const char *pMaterialName,
- int numSegments
- )
-{
- CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( "keyframe_rope" );
- if( !pRet )
- return NULL;
-
- pRet->SetStartPoint( pStartEnt, iStartAttachment );
- pRet->SetEndPoint( pEndEnt, iEndAttachment );
- pRet->m_bCreatedFromMapFile = false;
- pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG;
-
- pRet->Init();
-
- pRet->SetMaterial( pMaterialName );
- pRet->m_Width = ropeWidth;
- pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS );
-
- return pRet;
-}
-
-
-CRopeKeyframe* CRopeKeyframe::CreateWithSecondPointDetached(
- CBaseEntity *pStartEnt,
- int iStartAttachment,
- int ropeLength,
- int ropeWidth,
- const char *pMaterialName,
- int numSegments,
- bool bInitialHang
- )
-{
- CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( "keyframe_rope" );
- if( !pRet )
- return NULL;
-
- pRet->SetStartPoint( pStartEnt, iStartAttachment );
- pRet->SetEndPoint( NULL, 0 );
- pRet->m_bCreatedFromMapFile = false;
- pRet->m_fLockedPoints.Set( ROPE_LOCK_START_POINT ); // Only attach the first point.
-
- if( !bInitialHang )
- {
- pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG;
- }
-
- pRet->Init();
-
- pRet->SetMaterial( pMaterialName );
- pRet->m_RopeLength = ropeLength;
- pRet->m_Width = ropeWidth;
- pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS );
-
- return pRet;
-}
-
-void CRopeKeyframe::ActivateStartDirectionConstraints( bool bEnable )
-{
- if (bEnable)
- {
- m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_START_DIRECTION );
- }
- else
- {
- m_fLockedPoints &= ~((int)ROPE_LOCK_START_DIRECTION);
- }
-}
-
-
-void CRopeKeyframe::ActivateEndDirectionConstraints( bool bEnable )
-{
- if (bEnable)
- {
- m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_END_DIRECTION );
- }
- else
- {
- m_fLockedPoints &= ~((int)ROPE_LOCK_END_DIRECTION);
- }
-}
-
-
-void CRopeKeyframe::ShakeRopes( const Vector &vCenter, float flRadius, float flMagnitude )
-{
- CEffectData shakeData;
- shakeData.m_vOrigin = vCenter;
- shakeData.m_flRadius = flRadius;
- shakeData.m_flMagnitude = flMagnitude;
- DispatchEffect( "ShakeRopes", shakeData );
-}
-
-
-bool CRopeKeyframe::SetupHangDistance( float flHangDist )
-{
- CBaseEntity *pEnt1 = m_hStartPoint.Get();
- CBaseEntity *pEnt2 = m_hEndPoint.Get();
- if ( !pEnt1 || !pEnt2 )
- return false;
-
- // Calculate starting conditions so we can force it to hang down N inches.
- Vector v1 = pEnt1->GetAbsOrigin();
- if ( pEnt1->GetBaseAnimating() )
- pEnt1->GetBaseAnimating()->GetAttachment( m_iStartAttachment, v1 );
-
- Vector v2 = pEnt2->GetAbsOrigin();
- if ( pEnt2->GetBaseAnimating() )
- pEnt2->GetBaseAnimating()->GetAttachment( m_iEndAttachment, v2 );
-
- float flSlack, flLen;
- CalcRopeStartingConditions( v1, v2, ROPE_MAX_SEGMENTS, flHangDist, &flLen, &flSlack );
-
- m_RopeLength = (int)flLen;
- m_Slack = (int)flSlack;
- return true;
-}
-
-
-void CRopeKeyframe::Init()
-{
- SetLocalAngles( vec3_angle );
- RecalculateLength();
-
- m_nSegments = clamp( (int) m_nSegments, 2, ROPE_MAX_SEGMENTS );
-
- UpdateBBox( true );
-
- m_bStartPointValid = (m_hStartPoint.Get() != NULL);
- m_bEndPointValid = (m_hEndPoint.Get() != NULL);
-}
-
-
-void CRopeKeyframe::Activate()
-{
- BaseClass::Activate();
-
- if( !m_bCreatedFromMapFile )
- return;
-
- // Legacy support..
- if ( m_iRopeMaterialModelIndex == -1 )
- m_iRopeMaterialModelIndex = PrecacheModel( "cable/cable.vmt" );
-
- // Find the next entity in our chain.
- CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, m_iNextLinkName );
- if( pEnt && pEnt->edict() )
- {
- SetEndPoint( pEnt );
-
- if( m_spawnflags & SF_ROPE_RESIZE )
- m_RopeFlags |= ROPE_RESIZE;
- }
- else
- {
- // If we're from the map file, and we don't have a target ent, and
- // "Start Dangling" wasn't set, then this rope keyframe doesn't have
- // any rope coming out of it.
- if ( m_fLockedPoints & (int)ROPE_LOCK_END_POINT )
- {
- m_RopeFlags &= ~ROPE_SIMULATE;
- }
- }
-
- // By default, our start point is our own entity.
- SetStartPoint( this );
-
- // If we don't do this here, then when we save/load, we won't "own" the transmit
- // state of our parent, so the client might get our entity without our parent entity.
- SetParent( GetParent(), GetParentAttachment() );
-
- EndpointsChanged();
-
- Init();
-}
-
-void CRopeKeyframe::EndpointsChanged()
-{
- CBaseEntity *pStartEnt = m_hStartPoint.Get();
- if ( pStartEnt )
- {
- if ( (pStartEnt != this) || GetMoveParent() )
- {
- WatchPositionChanges( this, pStartEnt );
- }
- }
- CBaseEntity *pEndEnt = m_hEndPoint.Get();
- if ( pEndEnt )
- {
- if ( (pEndEnt != this) || GetMoveParent() )
- {
- WatchPositionChanges( this, pEndEnt );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Calculate the length of the rope
-//-----------------------------------------------------------------------------
-void CRopeKeyframe::RecalculateLength( void )
-{
- // Get my entities
- if( m_hEndPoint.Get() )
- {
- CBaseEntity *pStartEnt = m_hStartPoint.Get();
- CBaseEntity *pEndEnt = m_hEndPoint.Get();
-
- // Set the length
- m_RopeLength = (int)( pStartEnt->GetAbsOrigin() - pEndEnt->GetAbsOrigin() ).Length();
- }
- else
- {
- m_RopeLength = 0;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: This should remove the rope next time it reaches a resting state.
-// Right now only the client knows when it reaches a resting state, so
-// for now it just removes itself after a short time.
-//-----------------------------------------------------------------------------
-void CRopeKeyframe::DieAtNextRest( void )
-{
- SetThink( &CBaseEntity::SUB_Remove );
- SetNextThink( gpGlobals->curtime + 1.0f );
-}
-
-
-void CRopeKeyframe::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
-{
- if ( !pInfo->m_pTransmitEdict->Get( entindex() ) )
- {
- BaseClass::SetTransmit( pInfo, bAlways );
-
- // Make sure our target ents are sent too.
- CBaseEntity *pEnt = m_hStartPoint;
- if ( pEnt )
- pEnt->SetTransmit( pInfo, bAlways );
-
- pEnt = m_hEndPoint;
- if ( pEnt )
- pEnt->SetTransmit( pInfo, bAlways );
- }
-}
-
-
-bool CRopeKeyframe::GetEndPointPos2( CBaseEntity *pAttached, int iAttachment, Vector &vPos )
-{
- if( !pAttached )
- return false;
-
- if ( iAttachment > 0 )
- {
- CBaseAnimating *pAnim = pAttached->GetBaseAnimating();
- if ( pAnim )
- {
- if( !pAnim->GetAttachment( iAttachment, vPos ) )
- return false;
- }
- else
- {
- return false;
- }
- }
- else
- {
- vPos = pAttached->GetAbsOrigin();
- }
-
- return true;
-}
-
-
-bool CRopeKeyframe::GetEndPointPos( int iPt, Vector &v )
-{
- if ( iPt == 0 )
- return GetEndPointPos2( m_hStartPoint, m_iStartAttachment, v );
- else
- return GetEndPointPos2( m_hEndPoint, m_iEndAttachment, v );
-}
-
-
-void CRopeKeyframe::UpdateBBox( bool bForceRelink )
-{
- Vector v1, v2;
- Vector vMin, vMax;
- if ( GetEndPointPos( 0, v1 ) )
- {
- if ( GetEndPointPos( 1, v2 ) )
- {
- VectorMin( v1, v2, vMin );
- VectorMax( v1, v2, vMax );
-
- // Set our bounds to enclose both endpoints and relink.
- vMin -= GetAbsOrigin();
- vMax -= GetAbsOrigin();
- }
- else
- {
- vMin = vMax = v1 - GetAbsOrigin();
- }
- }
- else
- {
- vMin = vMax = Vector( 0, 0, 0 );
- }
-
- if ( WorldAlignMins() != vMin || WorldAlignMaxs() != vMax )
- {
- UTIL_SetSize( this, vMin, vMax );
- }
-}
-
-//------------------------------------------------------------------------------
-// Purpose : Propagate force to each link in the rope. Check for loops
-// Input :
-// Output :
-//------------------------------------------------------------------------------
-void CRopeKeyframe::PropagateForce(CBaseEntity *pActivator, CBaseEntity *pCaller, CBaseEntity *pFirstLink, float x, float y, float z)
-{
- EntityMessageBegin( this, true );
- WRITE_FLOAT( x );
- WRITE_FLOAT( y );
- WRITE_FLOAT( z );
- MessageEnd();
-
- // UNDONE: Doesn't deal with intermediate loops
- // Propagate to next segment
- CRopeKeyframe *pNextLink = dynamic_cast<CRopeKeyframe*>((CBaseEntity *)m_hEndPoint);
- if (pNextLink && pNextLink != pFirstLink)
- {
- pNextLink->PropagateForce(pActivator, pCaller, pFirstLink, x, y, z);
- }
-}
-
-//------------------------------------------------------------------------------
-// Purpose: Set an instaneous force on the rope.
-// Input : Force vector.
-//------------------------------------------------------------------------------
-void CRopeKeyframe::InputSetForce( inputdata_t &inputdata )
-{
- Vector vecForce;
- inputdata.value.Vector3D(vecForce);
- PropagateForce( inputdata.pActivator, inputdata.pCaller, this, vecForce.x, vecForce.y, vecForce.z );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Breaks the rope if able
-// Input : &inputdata -
-//-----------------------------------------------------------------------------
-void CRopeKeyframe::InputBreak( inputdata_t &inputdata )
-{
- //Route through the damage code
- Break();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Breaks the rope
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CRopeKeyframe::Break( void )
-{
- DetachPoint( 0 );
-
- // Find whoever references us and detach us from them.
- // UNDONE: PERFORMANCE: This is very slow!!!
- CRopeKeyframe *pTest = NULL;
- pTest = gEntList.NextEntByClass( pTest );
- while ( pTest )
- {
- if( stricmp( STRING(pTest->m_iNextLinkName), STRING(GetEntityName()) ) == 0 )
- {
- pTest->DetachPoint( 1 );
- }
-
- pTest = gEntList.NextEntByClass( pTest );
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CRopeKeyframe::NotifyPositionChanged( CBaseEntity *pEntity )
-{
- // Update our bbox?
- UpdateBBox( false );
-
- CBaseEntity *ents[2] = { m_hStartPoint.Get(), m_hEndPoint.Get() };
- if ( (m_RopeFlags & ROPE_RESIZE) && ents[0] && ents[0]->edict() && ents[1] && ents[1]->edict() )
- {
- int len = (int)( ents[0]->GetAbsOrigin() - ents[1]->GetAbsOrigin() ).Length() + m_Slack;
- if ( len != m_RopeLength )
- {
- m_RopeLength = len;
- }
- }
-
- // Figure out if our attachment points have gone away and make sure to update the client if they have.
- bool *pValid[2] = { &m_bStartPointValid, &m_bEndPointValid };
- for ( int i=0; i < 2; i++ )
- {
- bool bCurrentlyValid = ( ents[i] != NULL );
- if ( *pValid[i] != bCurrentlyValid )
- {
- *pValid[i] = bCurrentlyValid;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Take damage will break the rope
-//-----------------------------------------------------------------------------
-int CRopeKeyframe::OnTakeDamage( const CTakeDamageInfo &info )
-{
- // Only allow this if it's been marked
- if( !(m_RopeFlags & ROPE_BREAKABLE) )
- return false;
-
- Break();
- return 0;
-}
-
-
-void CRopeKeyframe::Precache()
-{
- m_iRopeMaterialModelIndex = PrecacheModel( STRING( m_strRopeMaterialModel ) );
- BaseClass::Precache();
-}
-
-
-void CRopeKeyframe::DetachPoint( int iPoint )
-{
- Assert( iPoint == 0 || iPoint == 1 );
-
- m_fLockedPoints &= ~(1 << iPoint);
-}
-
-
-void CRopeKeyframe::EnableCollision()
-{
- if( !( m_RopeFlags & ROPE_COLLIDE ) )
- {
- m_RopeFlags |= ROPE_COLLIDE;
- }
-}
-
-void CRopeKeyframe::EnableWind( bool bEnable )
-{
- int flag = 0;
- if ( !bEnable )
- flag |= ROPE_NO_WIND;
-
- if ( (m_RopeFlags & ROPE_NO_WIND) != flag )
- {
- m_RopeFlags |= flag;
- }
-}
-
-
-bool CRopeKeyframe::KeyValue( const char *szKeyName, const char *szValue )
-{
- if( stricmp( szKeyName, "Breakable" ) == 0 )
- {
- if( atoi( szValue ) == 1 )
- m_RopeFlags |= ROPE_BREAKABLE;
- }
- else if( stricmp( szKeyName, "Collide" ) == 0 )
- {
- if( atoi( szValue ) == 1 )
- m_RopeFlags |= ROPE_COLLIDE;
- }
- else if( stricmp( szKeyName, "Barbed" ) == 0 )
- {
- if( atoi( szValue ) == 1 )
- m_RopeFlags |= ROPE_BARBED;
- }
- else if( stricmp( szKeyName, "Dangling" ) == 0 )
- {
- if( atoi( szValue ) == 1 )
- m_fLockedPoints &= ~ROPE_LOCK_END_POINT; // detach our dest point
-
- return true;
- }
- else if( stricmp( szKeyName, "Type" ) == 0 )
- {
- int iType = atoi( szValue );
- if( iType == 0 )
- m_nSegments = ROPE_MAX_SEGMENTS;
- else if( iType == 1 )
- m_nSegments = ROPE_TYPE1_NUMSEGMENTS;
- else
- m_nSegments = ROPE_TYPE2_NUMSEGMENTS;
- }
- else if ( stricmp( szKeyName, "RopeShader" ) == 0 )
- {
- // Legacy support for the RopeShader parameter.
- int iShader = atoi( szValue );
- if ( iShader == 0 )
- {
- m_iRopeMaterialModelIndex = PrecacheModel( "cable/cable.vmt" );
- }
- else if ( iShader == 1 )
- {
- m_iRopeMaterialModelIndex = PrecacheModel( "cable/rope.vmt" );
- }
- else
- {
- m_iRopeMaterialModelIndex = PrecacheModel( "cable/chain.vmt" );
- }
- }
- else if ( stricmp( szKeyName, "RopeMaterial" ) == 0 )
- {
- // Make sure we have a vmt extension.
- if ( Q_stristr( szValue, ".vmt" ) )
- {
- SetMaterial( szValue );
- }
- else
- {
- char str[512];
- Q_snprintf( str, sizeof( str ), "%s.vmt", szValue );
- SetMaterial( str );
- }
- }
- else if ( stricmp( szKeyName, "NoWind" ) == 0 )
- {
- if ( atoi( szValue ) == 1 )
- {
- m_RopeFlags |= ROPE_NO_WIND;
- }
- }
-
- return BaseClass::KeyValue( szKeyName, szValue );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Input handler that sets the scroll speed.
-//-----------------------------------------------------------------------------
-void CRopeKeyframe::InputSetScrollSpeed( inputdata_t &inputdata )
-{
- m_flScrollSpeed = inputdata.value.Float();
-}
-
-
-void CRopeKeyframe::SetMaterial( const char *pName )
-{
- m_strRopeMaterialModel = AllocPooledString( pName );
- m_iRopeMaterialModelIndex = PrecacheModel( STRING( m_strRopeMaterialModel ) );
-}
-
-int CRopeKeyframe::UpdateTransmitState()
-{
- // Certain entities like sprites and ropes are strewn throughout the level and they rarely change.
- // For these entities, it's more efficient to transmit them once and then always leave them on
- // the client. Otherwise, the server will have to send big bursts of data with the entity states
- // as they come in and out of the PVS.
- return SetTransmitState( FL_EDICT_ALWAYS );
-}
-
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "rope.h" +#include "entitylist.h" +#include "rope_shared.h" +#include "sendproxy.h" +#include "rope_helpers.h" +#include "te_effect_dispatch.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//-------------------------------------------- +// Rope Spawn Flags +//-------------------------------------------- +#define SF_ROPE_RESIZE 1 // Automatically resize the rope + +// -------------------------------------------------------------------------------- // +// Fun With Tables. +// -------------------------------------------------------------------------------- // + +LINK_ENTITY_TO_CLASS( move_rope, CRopeKeyframe ); +LINK_ENTITY_TO_CLASS( keyframe_rope, CRopeKeyframe ); + +IMPLEMENT_SERVERCLASS_ST_NOBASE( CRopeKeyframe, DT_RopeKeyframe ) + SendPropEHandle(SENDINFO(m_hStartPoint)), + SendPropEHandle(SENDINFO(m_hEndPoint)), + SendPropInt( SENDINFO(m_iStartAttachment), 5, 0 ), + SendPropInt( SENDINFO(m_iEndAttachment), 5, 0 ), + + SendPropInt( SENDINFO(m_Slack), 12 ), + SendPropInt( SENDINFO(m_RopeLength), 15 ), + SendPropInt( SENDINFO(m_fLockedPoints), 4, SPROP_UNSIGNED ), + SendPropInt( SENDINFO(m_RopeFlags), ROPE_NUMFLAGS, SPROP_UNSIGNED ), + SendPropInt( SENDINFO(m_nSegments), 4, SPROP_UNSIGNED ), + SendPropBool( SENDINFO(m_bConstrainBetweenEndpoints) ), + SendPropInt( SENDINFO(m_iRopeMaterialModelIndex), 16, SPROP_UNSIGNED ), + SendPropInt( SENDINFO(m_Subdiv), 4, SPROP_UNSIGNED ), + + SendPropFloat( SENDINFO(m_TextureScale), 10, 0, 0.1f, 10.0f ), + SendPropFloat( SENDINFO(m_Width), 0, SPROP_NOSCALE ), + SendPropFloat( SENDINFO(m_flScrollSpeed), 0, SPROP_NOSCALE ), + + SendPropVector(SENDINFO(m_vecOrigin), -1, SPROP_COORD ), + SendPropEHandle(SENDINFO_NAME(m_hMoveParent, moveparent) ), + + SendPropInt (SENDINFO(m_iParentAttachment), NUM_PARENTATTACHMENT_BITS, SPROP_UNSIGNED), +END_SEND_TABLE() + + +BEGIN_DATADESC( CRopeKeyframe ) + + DEFINE_FIELD( m_RopeFlags, FIELD_INTEGER ), + + DEFINE_KEYFIELD( m_iNextLinkName, FIELD_STRING, "NextKey" ), + DEFINE_KEYFIELD( m_Slack, FIELD_INTEGER, "Slack" ), + DEFINE_KEYFIELD( m_Width, FIELD_FLOAT, "Width" ), + DEFINE_KEYFIELD( m_TextureScale, FIELD_FLOAT, "TextureScale" ), + DEFINE_FIELD( m_nSegments, FIELD_INTEGER ), + DEFINE_FIELD( m_bConstrainBetweenEndpoints, FIELD_BOOLEAN ), + + DEFINE_FIELD( m_strRopeMaterialModel, FIELD_STRING ), + DEFINE_FIELD( m_iRopeMaterialModelIndex, FIELD_MODELINDEX ), + DEFINE_KEYFIELD( m_Subdiv, FIELD_INTEGER, "Subdiv" ), + DEFINE_FIELD( m_RopeLength, FIELD_INTEGER ), + DEFINE_FIELD( m_fLockedPoints, FIELD_INTEGER ), + DEFINE_FIELD( m_bCreatedFromMapFile, FIELD_BOOLEAN ), + DEFINE_KEYFIELD( m_flScrollSpeed, FIELD_FLOAT, "ScrollSpeed" ), + + DEFINE_FIELD( m_bStartPointValid, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bEndPointValid, FIELD_BOOLEAN ), + + DEFINE_FIELD( m_hStartPoint, FIELD_EHANDLE ), + DEFINE_FIELD( m_hEndPoint, FIELD_EHANDLE ), + DEFINE_FIELD( m_iStartAttachment, FIELD_SHORT ), + DEFINE_FIELD( m_iEndAttachment, FIELD_SHORT ), + + // Inputs + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetScrollSpeed", InputSetScrollSpeed ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetForce", InputSetForce ), + DEFINE_INPUTFUNC( FIELD_VOID, "Break", InputBreak ), + +END_DATADESC() + + + +// -------------------------------------------------------------------------------- // +// CRopeKeyframe implementation. +// -------------------------------------------------------------------------------- // + +CRopeKeyframe::CRopeKeyframe() +{ + AddEFlags( EFL_FORCE_CHECK_TRANSMIT ); + + m_takedamage = DAMAGE_YES; + + m_iStartAttachment = m_iEndAttachment = 0; + + m_Slack = 0; + m_Width = 2; + m_TextureScale = 4; // 4:1 + m_nSegments = 5; + m_RopeLength = 20; + m_fLockedPoints = (int) (ROPE_LOCK_START_POINT | ROPE_LOCK_END_POINT); // by default, both points are locked + m_flScrollSpeed = 0; + m_RopeFlags = ROPE_SIMULATE | ROPE_INITIAL_HANG; + m_iRopeMaterialModelIndex = -1; + m_Subdiv = 2; + + m_bCreatedFromMapFile = true; +} + + +CRopeKeyframe::~CRopeKeyframe() +{ + // Release transmit state ownership. + SetStartPoint( NULL, 0 ); + SetEndPoint( NULL, 0 ); + SetParent( NULL, 0 ); +} + + +void CRopeKeyframe::SetAttachmentPoint( CBaseHandle &hOutEnt, short &iOutAttachment, CBaseEntity *pEnt, int iAttachment ) +{ + // Unforce our previously attached entity from transmitting. + CBaseEntity *pCurEnt = gEntList.GetBaseEntity( hOutEnt ); + if ( pCurEnt && pCurEnt->edict() ) + { + pCurEnt->DecrementTransmitStateOwnedCounter(); + pCurEnt->DispatchUpdateTransmitState(); + } + + hOutEnt = pEnt; + iOutAttachment = iAttachment; + + // Force this entity to transmit. + if ( pEnt ) + { + pEnt->SetTransmitState( FL_EDICT_ALWAYS ); + pEnt->IncrementTransmitStateOwnedCounter(); + } + + EndpointsChanged(); +} + + +void CRopeKeyframe::SetStartPoint( CBaseEntity *pStartPoint, int attachment ) +{ + SetAttachmentPoint( m_hStartPoint.GetForModify(), m_iStartAttachment.GetForModify(), pStartPoint, attachment ); +} + +void CRopeKeyframe::SetEndPoint( CBaseEntity *pEndPoint, int attachment ) +{ + SetAttachmentPoint( m_hEndPoint.GetForModify(), m_iEndAttachment.GetForModify(), pEndPoint, attachment ); +} + +void CRopeKeyframe::SetParent( CBaseEntity *pNewParent, int iAttachment ) +{ + CBaseEntity *pCurParent = GetMoveParent(); + if ( pCurParent ) + { + pCurParent->DecrementTransmitStateOwnedCounter(); + pCurParent->DispatchUpdateTransmitState(); + } + + // Make sure our move parent always transmits or we get asserts on the client. + if ( pNewParent ) + { + pNewParent->IncrementTransmitStateOwnedCounter(); + pNewParent->SetTransmitState( FL_EDICT_ALWAYS ); + } + + BaseClass::SetParent( pNewParent, iAttachment ); +} + +void CRopeKeyframe::EnablePlayerWeaponAttach( bool bAttach ) +{ + int newFlags = m_RopeFlags; + if ( bAttach ) + newFlags |= ROPE_PLAYER_WPN_ATTACH; + else + newFlags &= ~ROPE_PLAYER_WPN_ATTACH; + + if ( newFlags != m_RopeFlags ) + { + m_RopeFlags = newFlags; + } +} + + +CRopeKeyframe* CRopeKeyframe::Create( + CBaseEntity *pStartEnt, + CBaseEntity *pEndEnt, + int iStartAttachment, + int iEndAttachment, + int ropeWidth, + const char *pMaterialName, + int numSegments + ) +{ + CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( "keyframe_rope" ); + if( !pRet ) + return NULL; + + pRet->SetStartPoint( pStartEnt, iStartAttachment ); + pRet->SetEndPoint( pEndEnt, iEndAttachment ); + pRet->m_bCreatedFromMapFile = false; + pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG; + + pRet->Init(); + + pRet->SetMaterial( pMaterialName ); + pRet->m_Width = ropeWidth; + pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS ); + + return pRet; +} + + +CRopeKeyframe* CRopeKeyframe::CreateWithSecondPointDetached( + CBaseEntity *pStartEnt, + int iStartAttachment, + int ropeLength, + int ropeWidth, + const char *pMaterialName, + int numSegments, + bool bInitialHang + ) +{ + CRopeKeyframe *pRet = (CRopeKeyframe*)CreateEntityByName( "keyframe_rope" ); + if( !pRet ) + return NULL; + + pRet->SetStartPoint( pStartEnt, iStartAttachment ); + pRet->SetEndPoint( NULL, 0 ); + pRet->m_bCreatedFromMapFile = false; + pRet->m_fLockedPoints.Set( ROPE_LOCK_START_POINT ); // Only attach the first point. + + if( !bInitialHang ) + { + pRet->m_RopeFlags &= ~ROPE_INITIAL_HANG; + } + + pRet->Init(); + + pRet->SetMaterial( pMaterialName ); + pRet->m_RopeLength = ropeLength; + pRet->m_Width = ropeWidth; + pRet->m_nSegments = clamp( numSegments, 2, ROPE_MAX_SEGMENTS ); + + return pRet; +} + +void CRopeKeyframe::ActivateStartDirectionConstraints( bool bEnable ) +{ + if (bEnable) + { + m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_START_DIRECTION ); + } + else + { + m_fLockedPoints &= ~((int)ROPE_LOCK_START_DIRECTION); + } +} + + +void CRopeKeyframe::ActivateEndDirectionConstraints( bool bEnable ) +{ + if (bEnable) + { + m_fLockedPoints.Set( m_fLockedPoints | ROPE_LOCK_END_DIRECTION ); + } + else + { + m_fLockedPoints &= ~((int)ROPE_LOCK_END_DIRECTION); + } +} + + +void CRopeKeyframe::ShakeRopes( const Vector &vCenter, float flRadius, float flMagnitude ) +{ + CEffectData shakeData; + shakeData.m_vOrigin = vCenter; + shakeData.m_flRadius = flRadius; + shakeData.m_flMagnitude = flMagnitude; + DispatchEffect( "ShakeRopes", shakeData ); +} + + +bool CRopeKeyframe::SetupHangDistance( float flHangDist ) +{ + CBaseEntity *pEnt1 = m_hStartPoint.Get(); + CBaseEntity *pEnt2 = m_hEndPoint.Get(); + if ( !pEnt1 || !pEnt2 ) + return false; + + // Calculate starting conditions so we can force it to hang down N inches. + Vector v1 = pEnt1->GetAbsOrigin(); + if ( pEnt1->GetBaseAnimating() ) + pEnt1->GetBaseAnimating()->GetAttachment( m_iStartAttachment, v1 ); + + Vector v2 = pEnt2->GetAbsOrigin(); + if ( pEnt2->GetBaseAnimating() ) + pEnt2->GetBaseAnimating()->GetAttachment( m_iEndAttachment, v2 ); + + float flSlack, flLen; + CalcRopeStartingConditions( v1, v2, ROPE_MAX_SEGMENTS, flHangDist, &flLen, &flSlack ); + + m_RopeLength = (int)flLen; + m_Slack = (int)flSlack; + return true; +} + + +void CRopeKeyframe::Init() +{ + SetLocalAngles( vec3_angle ); + RecalculateLength(); + + m_nSegments = clamp( (int) m_nSegments, 2, ROPE_MAX_SEGMENTS ); + + UpdateBBox( true ); + + m_bStartPointValid = (m_hStartPoint.Get() != NULL); + m_bEndPointValid = (m_hEndPoint.Get() != NULL); +} + + +void CRopeKeyframe::Activate() +{ + BaseClass::Activate(); + + if( !m_bCreatedFromMapFile ) + return; + + // Legacy support.. + if ( m_iRopeMaterialModelIndex == -1 ) + m_iRopeMaterialModelIndex = PrecacheModel( "cable/cable.vmt" ); + + // Find the next entity in our chain. + CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, m_iNextLinkName ); + if( pEnt && pEnt->edict() ) + { + SetEndPoint( pEnt ); + + if( m_spawnflags & SF_ROPE_RESIZE ) + m_RopeFlags |= ROPE_RESIZE; + } + else + { + // If we're from the map file, and we don't have a target ent, and + // "Start Dangling" wasn't set, then this rope keyframe doesn't have + // any rope coming out of it. + if ( m_fLockedPoints & (int)ROPE_LOCK_END_POINT ) + { + m_RopeFlags &= ~ROPE_SIMULATE; + } + } + + // By default, our start point is our own entity. + SetStartPoint( this ); + + // If we don't do this here, then when we save/load, we won't "own" the transmit + // state of our parent, so the client might get our entity without our parent entity. + SetParent( GetParent(), GetParentAttachment() ); + + EndpointsChanged(); + + Init(); +} + +void CRopeKeyframe::EndpointsChanged() +{ + CBaseEntity *pStartEnt = m_hStartPoint.Get(); + if ( pStartEnt ) + { + if ( (pStartEnt != this) || GetMoveParent() ) + { + WatchPositionChanges( this, pStartEnt ); + } + } + CBaseEntity *pEndEnt = m_hEndPoint.Get(); + if ( pEndEnt ) + { + if ( (pEndEnt != this) || GetMoveParent() ) + { + WatchPositionChanges( this, pEndEnt ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Calculate the length of the rope +//----------------------------------------------------------------------------- +void CRopeKeyframe::RecalculateLength( void ) +{ + // Get my entities + if( m_hEndPoint.Get() ) + { + CBaseEntity *pStartEnt = m_hStartPoint.Get(); + CBaseEntity *pEndEnt = m_hEndPoint.Get(); + + // Set the length + m_RopeLength = (int)( pStartEnt->GetAbsOrigin() - pEndEnt->GetAbsOrigin() ).Length(); + } + else + { + m_RopeLength = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: This should remove the rope next time it reaches a resting state. +// Right now only the client knows when it reaches a resting state, so +// for now it just removes itself after a short time. +//----------------------------------------------------------------------------- +void CRopeKeyframe::DieAtNextRest( void ) +{ + SetThink( &CBaseEntity::SUB_Remove ); + SetNextThink( gpGlobals->curtime + 1.0f ); +} + + +void CRopeKeyframe::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways ) +{ + if ( !pInfo->m_pTransmitEdict->Get( entindex() ) ) + { + BaseClass::SetTransmit( pInfo, bAlways ); + + // Make sure our target ents are sent too. + CBaseEntity *pEnt = m_hStartPoint; + if ( pEnt ) + pEnt->SetTransmit( pInfo, bAlways ); + + pEnt = m_hEndPoint; + if ( pEnt ) + pEnt->SetTransmit( pInfo, bAlways ); + } +} + + +bool CRopeKeyframe::GetEndPointPos2( CBaseEntity *pAttached, int iAttachment, Vector &vPos ) +{ + if( !pAttached ) + return false; + + if ( iAttachment > 0 ) + { + CBaseAnimating *pAnim = pAttached->GetBaseAnimating(); + if ( pAnim ) + { + if( !pAnim->GetAttachment( iAttachment, vPos ) ) + return false; + } + else + { + return false; + } + } + else + { + vPos = pAttached->GetAbsOrigin(); + } + + return true; +} + + +bool CRopeKeyframe::GetEndPointPos( int iPt, Vector &v ) +{ + if ( iPt == 0 ) + return GetEndPointPos2( m_hStartPoint, m_iStartAttachment, v ); + else + return GetEndPointPos2( m_hEndPoint, m_iEndAttachment, v ); +} + + +void CRopeKeyframe::UpdateBBox( bool bForceRelink ) +{ + Vector v1, v2; + Vector vMin, vMax; + if ( GetEndPointPos( 0, v1 ) ) + { + if ( GetEndPointPos( 1, v2 ) ) + { + VectorMin( v1, v2, vMin ); + VectorMax( v1, v2, vMax ); + + // Set our bounds to enclose both endpoints and relink. + vMin -= GetAbsOrigin(); + vMax -= GetAbsOrigin(); + } + else + { + vMin = vMax = v1 - GetAbsOrigin(); + } + } + else + { + vMin = vMax = Vector( 0, 0, 0 ); + } + + if ( WorldAlignMins() != vMin || WorldAlignMaxs() != vMax ) + { + UTIL_SetSize( this, vMin, vMax ); + } +} + +//------------------------------------------------------------------------------ +// Purpose : Propagate force to each link in the rope. Check for loops +// Input : +// Output : +//------------------------------------------------------------------------------ +void CRopeKeyframe::PropagateForce(CBaseEntity *pActivator, CBaseEntity *pCaller, CBaseEntity *pFirstLink, float x, float y, float z) +{ + EntityMessageBegin( this, true ); + WRITE_FLOAT( x ); + WRITE_FLOAT( y ); + WRITE_FLOAT( z ); + MessageEnd(); + + // UNDONE: Doesn't deal with intermediate loops + // Propagate to next segment + CRopeKeyframe *pNextLink = dynamic_cast<CRopeKeyframe*>((CBaseEntity *)m_hEndPoint); + if (pNextLink && pNextLink != pFirstLink) + { + pNextLink->PropagateForce(pActivator, pCaller, pFirstLink, x, y, z); + } +} + +//------------------------------------------------------------------------------ +// Purpose: Set an instaneous force on the rope. +// Input : Force vector. +//------------------------------------------------------------------------------ +void CRopeKeyframe::InputSetForce( inputdata_t &inputdata ) +{ + Vector vecForce; + inputdata.value.Vector3D(vecForce); + PropagateForce( inputdata.pActivator, inputdata.pCaller, this, vecForce.x, vecForce.y, vecForce.z ); +} + +//----------------------------------------------------------------------------- +// Purpose: Breaks the rope if able +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CRopeKeyframe::InputBreak( inputdata_t &inputdata ) +{ + //Route through the damage code + Break(); +} + +//----------------------------------------------------------------------------- +// Purpose: Breaks the rope +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CRopeKeyframe::Break( void ) +{ + DetachPoint( 0 ); + + // Find whoever references us and detach us from them. + // UNDONE: PERFORMANCE: This is very slow!!! + CRopeKeyframe *pTest = NULL; + pTest = gEntList.NextEntByClass( pTest ); + while ( pTest ) + { + if( stricmp( STRING(pTest->m_iNextLinkName), STRING(GetEntityName()) ) == 0 ) + { + pTest->DetachPoint( 1 ); + } + + pTest = gEntList.NextEntByClass( pTest ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRopeKeyframe::NotifyPositionChanged( CBaseEntity *pEntity ) +{ + // Update our bbox? + UpdateBBox( false ); + + CBaseEntity *ents[2] = { m_hStartPoint.Get(), m_hEndPoint.Get() }; + if ( (m_RopeFlags & ROPE_RESIZE) && ents[0] && ents[0]->edict() && ents[1] && ents[1]->edict() ) + { + int len = (int)( ents[0]->GetAbsOrigin() - ents[1]->GetAbsOrigin() ).Length() + m_Slack; + if ( len != m_RopeLength ) + { + m_RopeLength = len; + } + } + + // Figure out if our attachment points have gone away and make sure to update the client if they have. + bool *pValid[2] = { &m_bStartPointValid, &m_bEndPointValid }; + for ( int i=0; i < 2; i++ ) + { + bool bCurrentlyValid = ( ents[i] != NULL ); + if ( *pValid[i] != bCurrentlyValid ) + { + *pValid[i] = bCurrentlyValid; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Take damage will break the rope +//----------------------------------------------------------------------------- +int CRopeKeyframe::OnTakeDamage( const CTakeDamageInfo &info ) +{ + // Only allow this if it's been marked + if( !(m_RopeFlags & ROPE_BREAKABLE) ) + return false; + + Break(); + return 0; +} + + +void CRopeKeyframe::Precache() +{ + m_iRopeMaterialModelIndex = PrecacheModel( STRING( m_strRopeMaterialModel ) ); + BaseClass::Precache(); +} + + +void CRopeKeyframe::DetachPoint( int iPoint ) +{ + Assert( iPoint == 0 || iPoint == 1 ); + + m_fLockedPoints &= ~(1 << iPoint); +} + + +void CRopeKeyframe::EnableCollision() +{ + if( !( m_RopeFlags & ROPE_COLLIDE ) ) + { + m_RopeFlags |= ROPE_COLLIDE; + } +} + +void CRopeKeyframe::EnableWind( bool bEnable ) +{ + int flag = 0; + if ( !bEnable ) + flag |= ROPE_NO_WIND; + + if ( (m_RopeFlags & ROPE_NO_WIND) != flag ) + { + m_RopeFlags |= flag; + } +} + + +bool CRopeKeyframe::KeyValue( const char *szKeyName, const char *szValue ) +{ + if( stricmp( szKeyName, "Breakable" ) == 0 ) + { + if( atoi( szValue ) == 1 ) + m_RopeFlags |= ROPE_BREAKABLE; + } + else if( stricmp( szKeyName, "Collide" ) == 0 ) + { + if( atoi( szValue ) == 1 ) + m_RopeFlags |= ROPE_COLLIDE; + } + else if( stricmp( szKeyName, "Barbed" ) == 0 ) + { + if( atoi( szValue ) == 1 ) + m_RopeFlags |= ROPE_BARBED; + } + else if( stricmp( szKeyName, "Dangling" ) == 0 ) + { + if( atoi( szValue ) == 1 ) + m_fLockedPoints &= ~ROPE_LOCK_END_POINT; // detach our dest point + + return true; + } + else if( stricmp( szKeyName, "Type" ) == 0 ) + { + int iType = atoi( szValue ); + if( iType == 0 ) + m_nSegments = ROPE_MAX_SEGMENTS; + else if( iType == 1 ) + m_nSegments = ROPE_TYPE1_NUMSEGMENTS; + else + m_nSegments = ROPE_TYPE2_NUMSEGMENTS; + } + else if ( stricmp( szKeyName, "RopeShader" ) == 0 ) + { + // Legacy support for the RopeShader parameter. + int iShader = atoi( szValue ); + if ( iShader == 0 ) + { + m_iRopeMaterialModelIndex = PrecacheModel( "cable/cable.vmt" ); + } + else if ( iShader == 1 ) + { + m_iRopeMaterialModelIndex = PrecacheModel( "cable/rope.vmt" ); + } + else + { + m_iRopeMaterialModelIndex = PrecacheModel( "cable/chain.vmt" ); + } + } + else if ( stricmp( szKeyName, "RopeMaterial" ) == 0 ) + { + // Make sure we have a vmt extension. + if ( Q_stristr( szValue, ".vmt" ) ) + { + SetMaterial( szValue ); + } + else + { + char str[512]; + Q_snprintf( str, sizeof( str ), "%s.vmt", szValue ); + SetMaterial( str ); + } + } + else if ( stricmp( szKeyName, "NoWind" ) == 0 ) + { + if ( atoi( szValue ) == 1 ) + { + m_RopeFlags |= ROPE_NO_WIND; + } + } + + return BaseClass::KeyValue( szKeyName, szValue ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler that sets the scroll speed. +//----------------------------------------------------------------------------- +void CRopeKeyframe::InputSetScrollSpeed( inputdata_t &inputdata ) +{ + m_flScrollSpeed = inputdata.value.Float(); +} + + +void CRopeKeyframe::SetMaterial( const char *pName ) +{ + m_strRopeMaterialModel = AllocPooledString( pName ); + m_iRopeMaterialModelIndex = PrecacheModel( STRING( m_strRopeMaterialModel ) ); +} + +int CRopeKeyframe::UpdateTransmitState() +{ + // Certain entities like sprites and ropes are strewn throughout the level and they rarely change. + // For these entities, it's more efficient to transmit them once and then always leave them on + // the client. Otherwise, the server will have to send big bursts of data with the entity states + // as they come in and out of the PVS. + return SetTransmitState( FL_EDICT_ALWAYS ); +} + + + + |