From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/server/rope.cpp | 1532 +++++++++++++++++++++---------------------- 1 file changed, 766 insertions(+), 766 deletions(-) (limited to 'mp/src/game/server/rope.cpp') 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((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((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 ); +} + + + + -- cgit v1.2.3