//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: This will measure the movement of a target entity and move // another entity to match the movement of the first. // //=============================================================================// #include "cbase.h" #include "baseentity.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // This will measure the movement of a target entity and move // another entity to match the movement of the first. //----------------------------------------------------------------------------- class CLogicMeasureMovement : public CLogicalEntity { DECLARE_DATADESC(); DECLARE_CLASS( CLogicMeasureMovement, CLogicalEntity ); public: virtual void Activate(); private: void SetMeasureTarget( const char *pName ); void SetMeasureReference( const char *pName ); void SetTarget( const char *pName ); void SetTargetReference( const char *pName ); void InputSetMeasureTarget( inputdata_t &inputdata ); void InputSetMeasureReference( inputdata_t &inputdata ); void InputSetTarget( inputdata_t &inputdata ); void InputSetTargetReference( inputdata_t &inputdata ); void InputSetTargetScale( inputdata_t &inputdata ); void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); void MeasureThink(); private: enum { MEASURE_POSITION = 0, MEASURE_EYE_POSITION, }; string_t m_strMeasureTarget; string_t m_strMeasureReference; string_t m_strTargetReference; EHANDLE m_hMeasureTarget; EHANDLE m_hMeasureReference; EHANDLE m_hTarget; EHANDLE m_hTargetReference; float m_flScale; int m_nMeasureType; }; LINK_ENTITY_TO_CLASS( logic_measure_movement, CLogicMeasureMovement ); BEGIN_DATADESC( CLogicMeasureMovement ) DEFINE_KEYFIELD( m_strMeasureTarget, FIELD_STRING, "MeasureTarget" ), DEFINE_KEYFIELD( m_strMeasureReference, FIELD_STRING, "MeasureReference" ), DEFINE_KEYFIELD( m_strTargetReference, FIELD_STRING, "TargetReference" ), DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "TargetScale" ), DEFINE_KEYFIELD( m_nMeasureType, FIELD_INTEGER, "MeasureType" ), DEFINE_FIELD( m_hMeasureTarget, FIELD_EHANDLE ), DEFINE_FIELD( m_hMeasureReference, FIELD_EHANDLE ), DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ), DEFINE_FIELD( m_hTargetReference, FIELD_EHANDLE ), DEFINE_INPUTFUNC( FIELD_STRING, "SetMeasureTarget", InputSetMeasureTarget ), DEFINE_INPUTFUNC( FIELD_STRING, "SetMeasureReference", InputSetMeasureReference ), DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ), DEFINE_INPUTFUNC( FIELD_STRING, "SetTargetReference", InputSetTargetReference ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTargetScale", InputSetTargetScale ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_THINKFUNC( MeasureThink ), END_DATADESC() //----------------------------------------------------------------------------- // Methods to change various targets //----------------------------------------------------------------------------- void CLogicMeasureMovement::Activate() { BaseClass::Activate(); SetMeasureTarget( STRING(m_strMeasureTarget) ); SetMeasureReference( STRING(m_strMeasureReference) ); SetTarget( STRING(m_target) ); SetTargetReference( STRING(m_strTargetReference) ); SetThink( &CLogicMeasureMovement::MeasureThink ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } //----------------------------------------------------------------------------- // Sets the name //----------------------------------------------------------------------------- void CLogicMeasureMovement::SetMeasureTarget( const char *pName ) { m_hMeasureTarget = gEntList.FindEntityByName( NULL, pName ); if ( !m_hMeasureTarget ) { if ( Q_strnicmp( STRING(m_strMeasureTarget), "!player", 8 ) ) { Warning("logic_measure_movement: Unable to find measure target entity %s\n", pName ); } } } void CLogicMeasureMovement::SetMeasureReference( const char *pName ) { m_hMeasureReference = gEntList.FindEntityByName( NULL, pName ); if ( !m_hMeasureReference ) { Warning("logic_measure_movement: Unable to find measure reference entity %s\n", pName ); } } void CLogicMeasureMovement::SetTarget( const char *pName ) { m_hTarget = gEntList.FindEntityByName( NULL, pName ); if ( !m_hTarget ) { Warning("logic_measure_movement: Unable to find movement target entity %s\n", pName ); } } void CLogicMeasureMovement::SetTargetReference( const char *pName ) { m_hTargetReference = gEntList.FindEntityByName( NULL, pName ); if ( !m_hTargetReference ) { Warning("logic_measure_movement: Unable to find movement reference entity %s\n", pName ); } } //----------------------------------------------------------------------------- // Apply movement //----------------------------------------------------------------------------- void CLogicMeasureMovement::MeasureThink( ) { // FIXME: This is a hack to make measuring !player simpler. The player isn't // created at Activate time, so m_hMeasureTarget may be NULL because of that. if ( !m_hMeasureTarget.Get() && !Q_strnicmp( STRING(m_strMeasureTarget), "!player", 8 ) ) { SetMeasureTarget( STRING(m_strMeasureTarget) ); } // Make sure all entities are valid if ( m_hMeasureTarget.Get() && m_hMeasureReference.Get() && m_hTarget.Get() && m_hTargetReference.Get() ) { matrix3x4_t matRefToMeasure, matWorldToMeasure; switch( m_nMeasureType ) { case MEASURE_POSITION: MatrixInvert( m_hMeasureTarget->EntityToWorldTransform(), matWorldToMeasure ); break; case MEASURE_EYE_POSITION: AngleIMatrix( m_hMeasureTarget->EyeAngles(), m_hMeasureTarget->EyePosition(), matWorldToMeasure ); break; // FIXME: Could add attachment point measurement here easily } ConcatTransforms( matWorldToMeasure, m_hMeasureReference->EntityToWorldTransform(), matRefToMeasure ); // Apply the scale factor if ( ( m_flScale != 0.0f ) && ( m_flScale != 1.0f ) ) { Vector vecTranslation; MatrixGetColumn( matRefToMeasure, 3, vecTranslation ); vecTranslation /= m_flScale; MatrixSetColumn( vecTranslation, 3, matRefToMeasure ); } // Now apply the new matrix to the new reference point matrix3x4_t matMeasureToRef, matNewTargetToWorld; MatrixInvert( matRefToMeasure, matMeasureToRef ); ConcatTransforms( m_hTargetReference->EntityToWorldTransform(), matMeasureToRef, matNewTargetToWorld ); Vector vecNewOrigin; QAngle vecNewAngles; MatrixAngles( matNewTargetToWorld, vecNewAngles, vecNewOrigin ); m_hTarget->SetAbsOrigin( vecNewOrigin ); m_hTarget->SetAbsAngles( vecNewAngles ); } SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } //----------------------------------------------------------------------------- // Enable, disable //----------------------------------------------------------------------------- void CLogicMeasureMovement::InputEnable( inputdata_t &inputdata ) { SetThink( &CLogicMeasureMovement::MeasureThink ); SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); } void CLogicMeasureMovement::InputDisable( inputdata_t &inputdata ) { SetThink( NULL ); } //----------------------------------------------------------------------------- // Methods to change various targets //----------------------------------------------------------------------------- void CLogicMeasureMovement::InputSetMeasureTarget( inputdata_t &inputdata ) { m_strMeasureTarget = MAKE_STRING( inputdata.value.String() ); SetMeasureTarget( inputdata.value.String() ); SetTarget( STRING(m_target) ); SetTargetReference( STRING(m_strTargetReference) ); } void CLogicMeasureMovement::InputSetMeasureReference( inputdata_t &inputdata ) { m_strMeasureReference = MAKE_STRING( inputdata.value.String() ); SetMeasureReference( inputdata.value.String() ); } void CLogicMeasureMovement::InputSetTarget( inputdata_t &inputdata ) { m_target = MAKE_STRING( inputdata.value.String() ); SetTarget( inputdata.value.String() ); } void CLogicMeasureMovement::InputSetTargetReference( inputdata_t &inputdata ) { m_strTargetReference = MAKE_STRING( inputdata.value.String() ); SetTargetReference( inputdata.value.String() ); } void CLogicMeasureMovement::InputSetTargetScale( inputdata_t &inputdata ) { m_flScale = inputdata.value.Float(); }