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/movement.cpp | 1316 +++++++++++++++++++-------------------- 1 file changed, 658 insertions(+), 658 deletions(-) (limited to 'mp/src/game/server/movement.cpp') diff --git a/mp/src/game/server/movement.cpp b/mp/src/game/server/movement.cpp index 7f17d137..da12420e 100644 --- a/mp/src/game/server/movement.cpp +++ b/mp/src/game/server/movement.cpp @@ -1,658 +1,658 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: MOVEMENT ENTITIES TEST -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "entitylist.h" -#include "entityoutput.h" -#include "keyframe/keyframe.h" // BUG: this needs to move if keyframe is a standard thing - -#include "mathlib/mathlib.h" // FIXME: why do we still need this? - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -// Hack, sort of. These interpolators don't get to hold state, but the ones -// that need state (like the rope simulator) should NOT be used as paths here. -IPositionInterpolator *g_pPositionInterpolators[8] = {0,0,0,0,0,0,0,0}; - -IPositionInterpolator* GetPositionInterpolator( int iInterp ) -{ - if( !g_pPositionInterpolators[iInterp] ) - g_pPositionInterpolators[iInterp] = Motion_GetPositionInterpolator( iInterp ); - - return g_pPositionInterpolators[iInterp]; -} - - -static float Fix( float angle ) -{ - while ( angle < 0 ) - angle += 360; - while ( angle > 360 ) - angle -= 360; - - return angle; -} - -void FixupAngles( QAngle &v ) -{ - v.x = Fix( v.x ); - v.y = Fix( v.y ); - v.z = Fix( v.z ); -} - - -//----------------------------------------------------------------------------- -// -// Purpose: Contains a description of a keyframe -// has no networked representation, so has to store origin, etc. itself -// -//----------------------------------------------------------------------------- -class CPathKeyFrame : public CLogicalEntity -{ -public: - DECLARE_CLASS( CPathKeyFrame, CLogicalEntity ); - - void Spawn( void ); - void Activate( void ); - void Link( void ); - - Vector m_Origin; - QAngle m_Angles; // euler angles PITCH YAW ROLL (Y Z X) - Quaternion m_qAngle; // quaternion angle (generated from m_Angles) - - string_t m_iNextKey; - float m_flNextTime; - - CPathKeyFrame *NextKey( int direction ); - CPathKeyFrame *PrevKey( int direction ); - - float Speed( void ) { return m_flSpeed; } - void SetKeyAngles( QAngle angles ); - - CPathKeyFrame *InsertNewKey( Vector newPos, QAngle newAngles ); - void CalculateFrameDuration( void ); - -protected: - CPathKeyFrame *m_pNextKey; - CPathKeyFrame *m_pPrevKey; - - float m_flSpeed; - - DECLARE_DATADESC(); -}; - -LINK_ENTITY_TO_CLASS( keyframe_track, CPathKeyFrame ); - -BEGIN_DATADESC( CPathKeyFrame ) - - DEFINE_FIELD( m_Origin, FIELD_VECTOR ), - DEFINE_FIELD( m_Angles, FIELD_VECTOR ), - DEFINE_FIELD( m_qAngle, FIELD_QUATERNION ), - - DEFINE_KEYFIELD( m_iNextKey, FIELD_STRING, "NextKey" ), - DEFINE_FIELD( m_flNextTime, FIELD_FLOAT ), // derived from speed - DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "MoveSpeed" ), - DEFINE_FIELD( m_pNextKey, FIELD_CLASSPTR ), - DEFINE_FIELD( m_pPrevKey, FIELD_CLASSPTR ), - -END_DATADESC() - - -//----------------------------------------------------------------------------- -// Purpose: Converts inputed euler angles to internal angle format (quaternions) -//----------------------------------------------------------------------------- -void CPathKeyFrame::Spawn( void ) -{ - m_Origin = GetLocalOrigin(); - m_Angles = GetLocalAngles(); - - SetKeyAngles( m_Angles ); -} - -//----------------------------------------------------------------------------- -// Purpose: Adds the keyframe into the path after all the other keys have spawned -//----------------------------------------------------------------------------- -void CPathKeyFrame::Activate( void ) -{ - BaseClass::Activate(); - - Link(); - - CalculateFrameDuration(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPathKeyFrame::CalculateFrameDuration( void ) -{ - // calculate time from speed - if ( m_pNextKey && m_flSpeed > 0 ) - { - m_flNextTime = (m_Origin - m_pNextKey->m_Origin).Length() / m_flSpeed; - - // couldn't get time from distance, get it from rotation instead - if ( !m_flNextTime ) - { - // speed is in degrees per second - // find the largest rotation component and use that - QAngle ang = m_Angles - m_pNextKey->m_Angles; - FixupAngles( ang ); - float x = 0; - for ( int i = 0; i < 3; i++ ) - { - if ( abs(ang[i]) > x ) - { - x = abs(ang[i]); - } - } - - m_flNextTime = x / m_flSpeed; - } - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Links the key frame into the key frame list -//----------------------------------------------------------------------------- -void CPathKeyFrame::Link( void ) -{ - m_pNextKey = dynamic_cast( gEntList.FindEntityByName(NULL, m_iNextKey ) ); - - if ( m_pNextKey ) - { - m_pNextKey->m_pPrevKey = this; - } -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : angles - -//----------------------------------------------------------------------------- -void CPathKeyFrame::SetKeyAngles( QAngle angles ) -{ - m_Angles = angles; - AngleQuaternion( m_Angles, m_qAngle ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : direction - -// Output : CPathKeyFrame -//----------------------------------------------------------------------------- -CPathKeyFrame* CPathKeyFrame::NextKey( int direction ) -{ - if ( direction == 1 ) - { - return m_pNextKey; - } - else if ( direction == -1 ) - { - return m_pPrevKey; - } - - return this; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : direction - -// Output : CPathKeyFrame -//----------------------------------------------------------------------------- -CPathKeyFrame *CPathKeyFrame::PrevKey( int direction ) -{ - if ( direction == 1 ) - { - return m_pPrevKey; - } - else if ( direction == -1 ) - { - return m_pNextKey; - } - - return this; -} - -//----------------------------------------------------------------------------- -// Purpose: Creates and insterts a new keyframe into the sequence -// Input : newPos - -// newAngles - -// Output : CPathKeyFrame -//----------------------------------------------------------------------------- -CPathKeyFrame *CPathKeyFrame::InsertNewKey( Vector newPos, QAngle newAngles ) -{ - CPathKeyFrame *newKey = CREATE_ENTITY( CPathKeyFrame, "keyframe_track" ); - - // copy data across - newKey->SetKeyAngles( newAngles ); - newKey->m_Origin = newPos; - newKey->m_flSpeed = m_flSpeed; - newKey->SetEFlags( GetEFlags() ); - if ( m_iParent != NULL_STRING ) - { - newKey->SetParent( m_iParent, NULL ); - } - - // link forward - newKey->m_pNextKey = m_pNextKey; - m_pNextKey->m_pPrevKey = newKey; - - // link back - m_pNextKey = newKey; - newKey->m_pPrevKey = this; - - // calculate new times - CalculateFrameDuration(); - newKey->CalculateFrameDuration(); - - return newKey; -} - - -//----------------------------------------------------------------------------- -// -// Purpose: Basic keyframed movement behavior -// -//----------------------------------------------------------------------------- -class CBaseMoveBehavior : public CPathKeyFrame -{ -public: - DECLARE_CLASS( CBaseMoveBehavior, CPathKeyFrame ); - - void Spawn( void ); - void Activate( void ); - void MoveDone( void ); - float SetObjectPhysicsVelocity( float moveTime ); - - // methods - virtual bool StartMoving( int direction ); - virtual void StopMoving( void ); - virtual bool IsMoving( void ); - - // derived classes should override this to get notification of arriving at new keyframes -// virtual void ArrivedAtKeyFrame( CPathKeyFrame * ) {} - - bool IsAtSequenceStart( void ); - bool IsAtSequenceEnd( void ); - - // interpolation functions -// int m_iTimeModifier; - int m_iPositionInterpolator; - int m_iRotationInterpolator; - - // animation vars - float m_flAnimStartTime; - float m_flAnimEndTime; - float m_flAverageSpeedAcrossFrame; // for advancing time with speed (not the normal visa-versa) - CPathKeyFrame *m_pCurrentKeyFrame; // keyframe currently moving from - CPathKeyFrame *m_pTargetKeyFrame; // keyframe being moved to - CPathKeyFrame *m_pPreKeyFrame, *m_pPostKeyFrame; // pre- and post-keyframe's for spline interpolation - float m_flTimeIntoFrame; - - int m_iDirection; // 1 for forward, -1 for backward, and 0 for at rest - - float CalculateTimeAdvancementForSpeed( float moveTime, float speed ); - - DECLARE_DATADESC(); -}; - -LINK_ENTITY_TO_CLASS( move_keyframed, CBaseMoveBehavior ); - -BEGIN_DATADESC( CBaseMoveBehavior ) - -// DEFINE_KEYFIELD( m_iTimeModifier, FIELD_INTEGER, "TimeModifier" ), - DEFINE_KEYFIELD( m_iPositionInterpolator, FIELD_INTEGER, "PositionInterpolator" ), - DEFINE_KEYFIELD( m_iRotationInterpolator, FIELD_INTEGER, "RotationInterpolator" ), - - DEFINE_FIELD( m_pCurrentKeyFrame, FIELD_CLASSPTR ), - DEFINE_FIELD( m_pTargetKeyFrame, FIELD_CLASSPTR ), - DEFINE_FIELD( m_pPreKeyFrame, FIELD_CLASSPTR ), - DEFINE_FIELD( m_pPostKeyFrame, FIELD_CLASSPTR ), - - DEFINE_FIELD( m_flAnimStartTime, FIELD_FLOAT ), - DEFINE_FIELD( m_flAnimEndTime, FIELD_FLOAT ), - DEFINE_FIELD( m_flAverageSpeedAcrossFrame, FIELD_FLOAT ), - DEFINE_FIELD( m_flTimeIntoFrame, FIELD_FLOAT ), - DEFINE_FIELD( m_iDirection, FIELD_INTEGER ), - -END_DATADESC() - - -void CBaseMoveBehavior::Spawn( void ) -{ - m_pCurrentKeyFrame = this; - m_flTimeIntoFrame = 0; - SetMoveType( MOVETYPE_PUSH ); - - // a move behavior is also it's first keyframe - m_Origin = GetLocalOrigin(); - m_Angles = GetLocalAngles(); - - BaseClass::Spawn(); -} - -void CBaseMoveBehavior::Activate( void ) -{ - BaseClass::Activate(); - - SetMoveDoneTime( 0.5 ); // start moving in 0.2 seconds time - - // if we are just the basic keyframed entity, cycle our animation - if ( !stricmp(GetClassname(), "move_keyframed") ) - { - StartMoving( 1 ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Checks to see if the we're at the start of the keyframe sequence -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CBaseMoveBehavior::IsAtSequenceStart( void ) -{ - if ( !m_pCurrentKeyFrame ) - return true; - - if ( m_flAnimStartTime && m_flAnimStartTime >= GetLocalTime() ) - { - if ( !m_pCurrentKeyFrame->PrevKey(1) && !m_pTargetKeyFrame ) - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Checks to see if we're at the end of the keyframe sequence -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CBaseMoveBehavior::IsAtSequenceEnd( void ) -{ - if ( !m_pCurrentKeyFrame ) - return false; - - if ( !m_pCurrentKeyFrame->NextKey(1) && !m_pTargetKeyFrame ) - return true; - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CBaseMoveBehavior::IsMoving( void ) -{ - if ( m_iDirection != 0 ) - return true; - - return false; -} - - -//----------------------------------------------------------------------------- -// Purpose: Starts the object moving from it's current position, in the direction indicated -// Input : direction - 1 is forward through the sequence, -1 is backwards, and 0 is stop -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CBaseMoveBehavior::StartMoving( int direction ) -{ - // 0 direction is to stop moving - if ( direction == 0 ) - { - StopMoving(); - return false; - } - - // check to see if we should keep moving in the current direction - if ( m_iDirection == direction ) - { - // if we're at the end of the current anim key, move to the next one - if ( GetLocalTime() >= m_flAnimEndTime ) - { - m_pCurrentKeyFrame = m_pTargetKeyFrame; - m_flTimeIntoFrame = 0; - - if ( !m_pTargetKeyFrame->NextKey(direction) ) - { - // we've hit the end of the sequence - m_flAnimEndTime = 0; - m_flAnimStartTime = 0; - StopMoving(); - return false; - } - - // advance the target keyframe - m_pTargetKeyFrame = m_pTargetKeyFrame->NextKey(direction); - } - } - else - { - // we're changing direction - - // need to calculate current position in the frame - // stop first, then start again - if ( m_iDirection != 0 ) - { - StopMoving(); - } - - m_iDirection = direction; - - // if we're going in reverse, swap the currentkey and targetkey (since we're going opposite dir) - if ( direction == 1 ) - { - m_pTargetKeyFrame = m_pCurrentKeyFrame->NextKey( direction ); - } - else if ( direction == -1 ) - { - if ( m_flTimeIntoFrame > 0 ) - { - m_pTargetKeyFrame = m_pCurrentKeyFrame; - m_pCurrentKeyFrame = m_pCurrentKeyFrame->NextKey( 1 ); - } - else - { - m_pTargetKeyFrame = m_pCurrentKeyFrame->PrevKey( 1 ); - } - } - - // recalculate our movement from the stored data - if ( !m_pTargetKeyFrame ) - { - StopMoving(); - return false; - } - - // calculate the keyframes before and after the keyframes we're interpolating between - m_pPostKeyFrame = m_pTargetKeyFrame->NextKey( direction ); - if ( !m_pPostKeyFrame ) - { - m_pPostKeyFrame = m_pTargetKeyFrame; - } - m_pPreKeyFrame = m_pCurrentKeyFrame->PrevKey( direction ); - if ( !m_pPreKeyFrame ) - { - m_pPreKeyFrame = m_pCurrentKeyFrame; - } - } - - // no target, can't move - if ( !m_pTargetKeyFrame ) - return false; - - // calculate start/end time - // ->m_flNextTime is the time to traverse to the NEXT key, so we need the opposite if travelling backwards - if ( m_iDirection == 1 ) - { - m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame; - m_flAnimEndTime = GetLocalTime() + m_pCurrentKeyFrame->m_flNextTime - m_flTimeIntoFrame; - } - else - { - // flip the timing, since we're in reverse - if ( m_flTimeIntoFrame ) - m_flTimeIntoFrame = m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame; - - m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame; - m_flAnimEndTime = GetLocalTime() + m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame; - } - - // calculate the average speed at which we cross - float animDuration = (m_flAnimEndTime - m_flAnimStartTime); - float dist = (m_pCurrentKeyFrame->m_Origin - m_pTargetKeyFrame->m_Origin).Length(); - m_flAverageSpeedAcrossFrame = animDuration / dist; - - SetMoveDoneTime( m_flAnimEndTime - GetLocalTime() ); - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: stops the object from moving -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -void CBaseMoveBehavior::StopMoving( void ) -{ - // remember exactly where we are in the frame - m_flTimeIntoFrame = 0; - - if ( m_iDirection == 1 ) - { - // record the time if we're not at the end of the frame - if ( GetLocalTime() < m_flAnimEndTime ) - { - m_flTimeIntoFrame = GetLocalTime() - m_flAnimStartTime; - } - else - { - // we're actually at the end - if ( m_pTargetKeyFrame ) - { - m_pCurrentKeyFrame = m_pTargetKeyFrame; - } - } - } - else if ( m_iDirection == -1 ) - { - // store it only as a forward movement - m_pCurrentKeyFrame = m_pTargetKeyFrame; - - if ( GetLocalTime() < m_flAnimEndTime ) - { - m_flTimeIntoFrame = m_flAnimEndTime - GetLocalTime(); - } - } - - // stop moving totally - SetMoveDoneTime( -1 ); - m_iDirection = 0; - m_flAnimStartTime = 0; - m_flAnimEndTime = 0; - m_pTargetKeyFrame = NULL; - SetAbsVelocity(vec3_origin); - SetLocalAngularVelocity( vec3_angle ); -} - - -//----------------------------------------------------------------------------- -// Purpose: We have just arrived at a key, move onto the next keyframe -//----------------------------------------------------------------------------- -void CBaseMoveBehavior::MoveDone( void ) -{ - // if we're just a base then keep playing the anim - if ( !stricmp(STRING(m_iClassname), "move_keyframed") ) - { - int direction = m_iDirection; - // start moving from the keyframe we've just reached - if ( !StartMoving(direction) ) - { - // try moving in the other direction - StartMoving( -direction ); - } - } - - BaseClass::MoveDone(); -} - -//----------------------------------------------------------------------------- -// Purpose: Calculates a new moveTime based on the speed and the current point -// in the animation. -// used to advance keyframed objects that have dynamic speeds. -// Input : moveTime - -// Output : float - the new time in the keyframing sequence -//----------------------------------------------------------------------------- -float CBaseMoveBehavior::CalculateTimeAdvancementForSpeed( float moveTime, float speed ) -{ - return (moveTime * speed * m_flAverageSpeedAcrossFrame); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// GetLocalTime() is the objects local current time -// Input : destTime - new time that is being moved to -// moveTime - amount of time to be advanced this frame -// Output : float - the actual amount of time to move (usually moveTime) -//----------------------------------------------------------------------------- -float CBaseMoveBehavior::SetObjectPhysicsVelocity( float moveTime ) -{ - // make sure we have a valid set up - if ( !m_pCurrentKeyFrame || !m_pTargetKeyFrame ) - return moveTime; - - // if we're not moving, we're not moving - if ( !IsMoving() ) - return moveTime; - - float destTime = moveTime + GetLocalTime(); - - // work out where we want to be, using destTime - m_flTimeIntoFrame = destTime - m_flAnimStartTime; - float newTime = (destTime - m_flAnimStartTime) / (m_flAnimEndTime - m_flAnimStartTime); - Vector newPos; - QAngle newAngles; - - IPositionInterpolator *pInterp = GetPositionInterpolator( m_iPositionInterpolator ); - if( pInterp ) - { - // setup key frames - pInterp->SetKeyPosition( -1, m_pPreKeyFrame->m_Origin ); - Motion_SetKeyAngles( -1, m_pPreKeyFrame->m_qAngle ); - - pInterp->SetKeyPosition( 0, m_pCurrentKeyFrame->m_Origin ); - Motion_SetKeyAngles( 0, m_pCurrentKeyFrame->m_qAngle ); - - pInterp->SetKeyPosition( 1, m_pTargetKeyFrame->m_Origin ); - Motion_SetKeyAngles( 1, m_pTargetKeyFrame->m_qAngle ); - - pInterp->SetKeyPosition( 2, m_pPostKeyFrame->m_Origin ); - Motion_SetKeyAngles( 2, m_pPostKeyFrame->m_qAngle ); - - // find new interpolated position & rotation - pInterp->InterpolatePosition( newTime, newPos ); - } - else - { - newPos.Init(); - } - - Quaternion qRot; - Motion_InterpolateRotation( newTime, m_iRotationInterpolator, qRot ); - QuaternionAngles( qRot, newAngles ); - - // find our velocity vector (newPos - currentPos) and scale velocity vector according to the movetime - float oneOnMoveTime = 1 / moveTime; - SetAbsVelocity( (newPos - GetLocalOrigin()) * oneOnMoveTime ); - SetLocalAngularVelocity( (newAngles - GetLocalAngles()) * oneOnMoveTime ); - - return moveTime; -} - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: MOVEMENT ENTITIES TEST +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "entitylist.h" +#include "entityoutput.h" +#include "keyframe/keyframe.h" // BUG: this needs to move if keyframe is a standard thing + +#include "mathlib/mathlib.h" // FIXME: why do we still need this? + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// Hack, sort of. These interpolators don't get to hold state, but the ones +// that need state (like the rope simulator) should NOT be used as paths here. +IPositionInterpolator *g_pPositionInterpolators[8] = {0,0,0,0,0,0,0,0}; + +IPositionInterpolator* GetPositionInterpolator( int iInterp ) +{ + if( !g_pPositionInterpolators[iInterp] ) + g_pPositionInterpolators[iInterp] = Motion_GetPositionInterpolator( iInterp ); + + return g_pPositionInterpolators[iInterp]; +} + + +static float Fix( float angle ) +{ + while ( angle < 0 ) + angle += 360; + while ( angle > 360 ) + angle -= 360; + + return angle; +} + +void FixupAngles( QAngle &v ) +{ + v.x = Fix( v.x ); + v.y = Fix( v.y ); + v.z = Fix( v.z ); +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Contains a description of a keyframe +// has no networked representation, so has to store origin, etc. itself +// +//----------------------------------------------------------------------------- +class CPathKeyFrame : public CLogicalEntity +{ +public: + DECLARE_CLASS( CPathKeyFrame, CLogicalEntity ); + + void Spawn( void ); + void Activate( void ); + void Link( void ); + + Vector m_Origin; + QAngle m_Angles; // euler angles PITCH YAW ROLL (Y Z X) + Quaternion m_qAngle; // quaternion angle (generated from m_Angles) + + string_t m_iNextKey; + float m_flNextTime; + + CPathKeyFrame *NextKey( int direction ); + CPathKeyFrame *PrevKey( int direction ); + + float Speed( void ) { return m_flSpeed; } + void SetKeyAngles( QAngle angles ); + + CPathKeyFrame *InsertNewKey( Vector newPos, QAngle newAngles ); + void CalculateFrameDuration( void ); + +protected: + CPathKeyFrame *m_pNextKey; + CPathKeyFrame *m_pPrevKey; + + float m_flSpeed; + + DECLARE_DATADESC(); +}; + +LINK_ENTITY_TO_CLASS( keyframe_track, CPathKeyFrame ); + +BEGIN_DATADESC( CPathKeyFrame ) + + DEFINE_FIELD( m_Origin, FIELD_VECTOR ), + DEFINE_FIELD( m_Angles, FIELD_VECTOR ), + DEFINE_FIELD( m_qAngle, FIELD_QUATERNION ), + + DEFINE_KEYFIELD( m_iNextKey, FIELD_STRING, "NextKey" ), + DEFINE_FIELD( m_flNextTime, FIELD_FLOAT ), // derived from speed + DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "MoveSpeed" ), + DEFINE_FIELD( m_pNextKey, FIELD_CLASSPTR ), + DEFINE_FIELD( m_pPrevKey, FIELD_CLASSPTR ), + +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Purpose: Converts inputed euler angles to internal angle format (quaternions) +//----------------------------------------------------------------------------- +void CPathKeyFrame::Spawn( void ) +{ + m_Origin = GetLocalOrigin(); + m_Angles = GetLocalAngles(); + + SetKeyAngles( m_Angles ); +} + +//----------------------------------------------------------------------------- +// Purpose: Adds the keyframe into the path after all the other keys have spawned +//----------------------------------------------------------------------------- +void CPathKeyFrame::Activate( void ) +{ + BaseClass::Activate(); + + Link(); + + CalculateFrameDuration(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathKeyFrame::CalculateFrameDuration( void ) +{ + // calculate time from speed + if ( m_pNextKey && m_flSpeed > 0 ) + { + m_flNextTime = (m_Origin - m_pNextKey->m_Origin).Length() / m_flSpeed; + + // couldn't get time from distance, get it from rotation instead + if ( !m_flNextTime ) + { + // speed is in degrees per second + // find the largest rotation component and use that + QAngle ang = m_Angles - m_pNextKey->m_Angles; + FixupAngles( ang ); + float x = 0; + for ( int i = 0; i < 3; i++ ) + { + if ( abs(ang[i]) > x ) + { + x = abs(ang[i]); + } + } + + m_flNextTime = x / m_flSpeed; + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Links the key frame into the key frame list +//----------------------------------------------------------------------------- +void CPathKeyFrame::Link( void ) +{ + m_pNextKey = dynamic_cast( gEntList.FindEntityByName(NULL, m_iNextKey ) ); + + if ( m_pNextKey ) + { + m_pNextKey->m_pPrevKey = this; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : angles - +//----------------------------------------------------------------------------- +void CPathKeyFrame::SetKeyAngles( QAngle angles ) +{ + m_Angles = angles; + AngleQuaternion( m_Angles, m_qAngle ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : direction - +// Output : CPathKeyFrame +//----------------------------------------------------------------------------- +CPathKeyFrame* CPathKeyFrame::NextKey( int direction ) +{ + if ( direction == 1 ) + { + return m_pNextKey; + } + else if ( direction == -1 ) + { + return m_pPrevKey; + } + + return this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : direction - +// Output : CPathKeyFrame +//----------------------------------------------------------------------------- +CPathKeyFrame *CPathKeyFrame::PrevKey( int direction ) +{ + if ( direction == 1 ) + { + return m_pPrevKey; + } + else if ( direction == -1 ) + { + return m_pNextKey; + } + + return this; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates and insterts a new keyframe into the sequence +// Input : newPos - +// newAngles - +// Output : CPathKeyFrame +//----------------------------------------------------------------------------- +CPathKeyFrame *CPathKeyFrame::InsertNewKey( Vector newPos, QAngle newAngles ) +{ + CPathKeyFrame *newKey = CREATE_ENTITY( CPathKeyFrame, "keyframe_track" ); + + // copy data across + newKey->SetKeyAngles( newAngles ); + newKey->m_Origin = newPos; + newKey->m_flSpeed = m_flSpeed; + newKey->SetEFlags( GetEFlags() ); + if ( m_iParent != NULL_STRING ) + { + newKey->SetParent( m_iParent, NULL ); + } + + // link forward + newKey->m_pNextKey = m_pNextKey; + m_pNextKey->m_pPrevKey = newKey; + + // link back + m_pNextKey = newKey; + newKey->m_pPrevKey = this; + + // calculate new times + CalculateFrameDuration(); + newKey->CalculateFrameDuration(); + + return newKey; +} + + +//----------------------------------------------------------------------------- +// +// Purpose: Basic keyframed movement behavior +// +//----------------------------------------------------------------------------- +class CBaseMoveBehavior : public CPathKeyFrame +{ +public: + DECLARE_CLASS( CBaseMoveBehavior, CPathKeyFrame ); + + void Spawn( void ); + void Activate( void ); + void MoveDone( void ); + float SetObjectPhysicsVelocity( float moveTime ); + + // methods + virtual bool StartMoving( int direction ); + virtual void StopMoving( void ); + virtual bool IsMoving( void ); + + // derived classes should override this to get notification of arriving at new keyframes +// virtual void ArrivedAtKeyFrame( CPathKeyFrame * ) {} + + bool IsAtSequenceStart( void ); + bool IsAtSequenceEnd( void ); + + // interpolation functions +// int m_iTimeModifier; + int m_iPositionInterpolator; + int m_iRotationInterpolator; + + // animation vars + float m_flAnimStartTime; + float m_flAnimEndTime; + float m_flAverageSpeedAcrossFrame; // for advancing time with speed (not the normal visa-versa) + CPathKeyFrame *m_pCurrentKeyFrame; // keyframe currently moving from + CPathKeyFrame *m_pTargetKeyFrame; // keyframe being moved to + CPathKeyFrame *m_pPreKeyFrame, *m_pPostKeyFrame; // pre- and post-keyframe's for spline interpolation + float m_flTimeIntoFrame; + + int m_iDirection; // 1 for forward, -1 for backward, and 0 for at rest + + float CalculateTimeAdvancementForSpeed( float moveTime, float speed ); + + DECLARE_DATADESC(); +}; + +LINK_ENTITY_TO_CLASS( move_keyframed, CBaseMoveBehavior ); + +BEGIN_DATADESC( CBaseMoveBehavior ) + +// DEFINE_KEYFIELD( m_iTimeModifier, FIELD_INTEGER, "TimeModifier" ), + DEFINE_KEYFIELD( m_iPositionInterpolator, FIELD_INTEGER, "PositionInterpolator" ), + DEFINE_KEYFIELD( m_iRotationInterpolator, FIELD_INTEGER, "RotationInterpolator" ), + + DEFINE_FIELD( m_pCurrentKeyFrame, FIELD_CLASSPTR ), + DEFINE_FIELD( m_pTargetKeyFrame, FIELD_CLASSPTR ), + DEFINE_FIELD( m_pPreKeyFrame, FIELD_CLASSPTR ), + DEFINE_FIELD( m_pPostKeyFrame, FIELD_CLASSPTR ), + + DEFINE_FIELD( m_flAnimStartTime, FIELD_FLOAT ), + DEFINE_FIELD( m_flAnimEndTime, FIELD_FLOAT ), + DEFINE_FIELD( m_flAverageSpeedAcrossFrame, FIELD_FLOAT ), + DEFINE_FIELD( m_flTimeIntoFrame, FIELD_FLOAT ), + DEFINE_FIELD( m_iDirection, FIELD_INTEGER ), + +END_DATADESC() + + +void CBaseMoveBehavior::Spawn( void ) +{ + m_pCurrentKeyFrame = this; + m_flTimeIntoFrame = 0; + SetMoveType( MOVETYPE_PUSH ); + + // a move behavior is also it's first keyframe + m_Origin = GetLocalOrigin(); + m_Angles = GetLocalAngles(); + + BaseClass::Spawn(); +} + +void CBaseMoveBehavior::Activate( void ) +{ + BaseClass::Activate(); + + SetMoveDoneTime( 0.5 ); // start moving in 0.2 seconds time + + // if we are just the basic keyframed entity, cycle our animation + if ( !stricmp(GetClassname(), "move_keyframed") ) + { + StartMoving( 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Checks to see if the we're at the start of the keyframe sequence +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseMoveBehavior::IsAtSequenceStart( void ) +{ + if ( !m_pCurrentKeyFrame ) + return true; + + if ( m_flAnimStartTime && m_flAnimStartTime >= GetLocalTime() ) + { + if ( !m_pCurrentKeyFrame->PrevKey(1) && !m_pTargetKeyFrame ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Checks to see if we're at the end of the keyframe sequence +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseMoveBehavior::IsAtSequenceEnd( void ) +{ + if ( !m_pCurrentKeyFrame ) + return false; + + if ( !m_pCurrentKeyFrame->NextKey(1) && !m_pTargetKeyFrame ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseMoveBehavior::IsMoving( void ) +{ + if ( m_iDirection != 0 ) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Starts the object moving from it's current position, in the direction indicated +// Input : direction - 1 is forward through the sequence, -1 is backwards, and 0 is stop +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseMoveBehavior::StartMoving( int direction ) +{ + // 0 direction is to stop moving + if ( direction == 0 ) + { + StopMoving(); + return false; + } + + // check to see if we should keep moving in the current direction + if ( m_iDirection == direction ) + { + // if we're at the end of the current anim key, move to the next one + if ( GetLocalTime() >= m_flAnimEndTime ) + { + m_pCurrentKeyFrame = m_pTargetKeyFrame; + m_flTimeIntoFrame = 0; + + if ( !m_pTargetKeyFrame->NextKey(direction) ) + { + // we've hit the end of the sequence + m_flAnimEndTime = 0; + m_flAnimStartTime = 0; + StopMoving(); + return false; + } + + // advance the target keyframe + m_pTargetKeyFrame = m_pTargetKeyFrame->NextKey(direction); + } + } + else + { + // we're changing direction + + // need to calculate current position in the frame + // stop first, then start again + if ( m_iDirection != 0 ) + { + StopMoving(); + } + + m_iDirection = direction; + + // if we're going in reverse, swap the currentkey and targetkey (since we're going opposite dir) + if ( direction == 1 ) + { + m_pTargetKeyFrame = m_pCurrentKeyFrame->NextKey( direction ); + } + else if ( direction == -1 ) + { + if ( m_flTimeIntoFrame > 0 ) + { + m_pTargetKeyFrame = m_pCurrentKeyFrame; + m_pCurrentKeyFrame = m_pCurrentKeyFrame->NextKey( 1 ); + } + else + { + m_pTargetKeyFrame = m_pCurrentKeyFrame->PrevKey( 1 ); + } + } + + // recalculate our movement from the stored data + if ( !m_pTargetKeyFrame ) + { + StopMoving(); + return false; + } + + // calculate the keyframes before and after the keyframes we're interpolating between + m_pPostKeyFrame = m_pTargetKeyFrame->NextKey( direction ); + if ( !m_pPostKeyFrame ) + { + m_pPostKeyFrame = m_pTargetKeyFrame; + } + m_pPreKeyFrame = m_pCurrentKeyFrame->PrevKey( direction ); + if ( !m_pPreKeyFrame ) + { + m_pPreKeyFrame = m_pCurrentKeyFrame; + } + } + + // no target, can't move + if ( !m_pTargetKeyFrame ) + return false; + + // calculate start/end time + // ->m_flNextTime is the time to traverse to the NEXT key, so we need the opposite if travelling backwards + if ( m_iDirection == 1 ) + { + m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame; + m_flAnimEndTime = GetLocalTime() + m_pCurrentKeyFrame->m_flNextTime - m_flTimeIntoFrame; + } + else + { + // flip the timing, since we're in reverse + if ( m_flTimeIntoFrame ) + m_flTimeIntoFrame = m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame; + + m_flAnimStartTime = GetLocalTime() - m_flTimeIntoFrame; + m_flAnimEndTime = GetLocalTime() + m_pTargetKeyFrame->m_flNextTime - m_flTimeIntoFrame; + } + + // calculate the average speed at which we cross + float animDuration = (m_flAnimEndTime - m_flAnimStartTime); + float dist = (m_pCurrentKeyFrame->m_Origin - m_pTargetKeyFrame->m_Origin).Length(); + m_flAverageSpeedAcrossFrame = animDuration / dist; + + SetMoveDoneTime( m_flAnimEndTime - GetLocalTime() ); + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: stops the object from moving +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void CBaseMoveBehavior::StopMoving( void ) +{ + // remember exactly where we are in the frame + m_flTimeIntoFrame = 0; + + if ( m_iDirection == 1 ) + { + // record the time if we're not at the end of the frame + if ( GetLocalTime() < m_flAnimEndTime ) + { + m_flTimeIntoFrame = GetLocalTime() - m_flAnimStartTime; + } + else + { + // we're actually at the end + if ( m_pTargetKeyFrame ) + { + m_pCurrentKeyFrame = m_pTargetKeyFrame; + } + } + } + else if ( m_iDirection == -1 ) + { + // store it only as a forward movement + m_pCurrentKeyFrame = m_pTargetKeyFrame; + + if ( GetLocalTime() < m_flAnimEndTime ) + { + m_flTimeIntoFrame = m_flAnimEndTime - GetLocalTime(); + } + } + + // stop moving totally + SetMoveDoneTime( -1 ); + m_iDirection = 0; + m_flAnimStartTime = 0; + m_flAnimEndTime = 0; + m_pTargetKeyFrame = NULL; + SetAbsVelocity(vec3_origin); + SetLocalAngularVelocity( vec3_angle ); +} + + +//----------------------------------------------------------------------------- +// Purpose: We have just arrived at a key, move onto the next keyframe +//----------------------------------------------------------------------------- +void CBaseMoveBehavior::MoveDone( void ) +{ + // if we're just a base then keep playing the anim + if ( !stricmp(STRING(m_iClassname), "move_keyframed") ) + { + int direction = m_iDirection; + // start moving from the keyframe we've just reached + if ( !StartMoving(direction) ) + { + // try moving in the other direction + StartMoving( -direction ); + } + } + + BaseClass::MoveDone(); +} + +//----------------------------------------------------------------------------- +// Purpose: Calculates a new moveTime based on the speed and the current point +// in the animation. +// used to advance keyframed objects that have dynamic speeds. +// Input : moveTime - +// Output : float - the new time in the keyframing sequence +//----------------------------------------------------------------------------- +float CBaseMoveBehavior::CalculateTimeAdvancementForSpeed( float moveTime, float speed ) +{ + return (moveTime * speed * m_flAverageSpeedAcrossFrame); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// GetLocalTime() is the objects local current time +// Input : destTime - new time that is being moved to +// moveTime - amount of time to be advanced this frame +// Output : float - the actual amount of time to move (usually moveTime) +//----------------------------------------------------------------------------- +float CBaseMoveBehavior::SetObjectPhysicsVelocity( float moveTime ) +{ + // make sure we have a valid set up + if ( !m_pCurrentKeyFrame || !m_pTargetKeyFrame ) + return moveTime; + + // if we're not moving, we're not moving + if ( !IsMoving() ) + return moveTime; + + float destTime = moveTime + GetLocalTime(); + + // work out where we want to be, using destTime + m_flTimeIntoFrame = destTime - m_flAnimStartTime; + float newTime = (destTime - m_flAnimStartTime) / (m_flAnimEndTime - m_flAnimStartTime); + Vector newPos; + QAngle newAngles; + + IPositionInterpolator *pInterp = GetPositionInterpolator( m_iPositionInterpolator ); + if( pInterp ) + { + // setup key frames + pInterp->SetKeyPosition( -1, m_pPreKeyFrame->m_Origin ); + Motion_SetKeyAngles( -1, m_pPreKeyFrame->m_qAngle ); + + pInterp->SetKeyPosition( 0, m_pCurrentKeyFrame->m_Origin ); + Motion_SetKeyAngles( 0, m_pCurrentKeyFrame->m_qAngle ); + + pInterp->SetKeyPosition( 1, m_pTargetKeyFrame->m_Origin ); + Motion_SetKeyAngles( 1, m_pTargetKeyFrame->m_qAngle ); + + pInterp->SetKeyPosition( 2, m_pPostKeyFrame->m_Origin ); + Motion_SetKeyAngles( 2, m_pPostKeyFrame->m_qAngle ); + + // find new interpolated position & rotation + pInterp->InterpolatePosition( newTime, newPos ); + } + else + { + newPos.Init(); + } + + Quaternion qRot; + Motion_InterpolateRotation( newTime, m_iRotationInterpolator, qRot ); + QuaternionAngles( qRot, newAngles ); + + // find our velocity vector (newPos - currentPos) and scale velocity vector according to the movetime + float oneOnMoveTime = 1 / moveTime; + SetAbsVelocity( (newPos - GetLocalOrigin()) * oneOnMoveTime ); + SetLocalAngularVelocity( (newAngles - GetLocalAngles()) * oneOnMoveTime ); + + return moveTime; +} + -- cgit v1.2.3