source-sdk-2013-mapbase/sp/src/game/server/logic_measure_movement.cpp
Blixibon c5f3fa0778 Mapbase v3.0
- Overhauled matcher system and added expanded wildcard support, meaning "text", "te?t", "blah_test", etc. are now supported instead of only trailing *
- Added support for regular expression matching
- Added the missing matrixinvert.h file, which prevented programmers from compiling vbsp
- Fixed env_global_light brightness
- Added info_player_view_proxy, an entity which mimics a player's view (created for script_intro)
- New UnZoomWithRate and SetZoomRate inputs on env_zoom
- New "Don't change target's angles" flag on logic_measure_movement
- Fixed logic_measure_movement not using ignore origin flags correctly
- Fixed filter_damage_mod secondary filter not recognizing mode correctly
- Fixed DisableGeigerCounter causing NPCs to ignore player, and possibly fixed other adverse effects in similar code
- Added SetEntityName input for setting an entity's targetname
- Added "SetTarget" support to point_posecontroller
- Added "sk_alyx_health" convar for adjustable npc_alyx health, restored/fixed "sk_barney_health" for adjustable npc_barney health
- Added ignore flags and several direction-related inputs to math_vector
- Added pose parameter stuff to logic_modelinfo
- Fixed ChangeWeapon not changing during combat
- Fixed holster/unholster on NPCs without holster/unholster animations
- Fixed func_tank and other "player in the way" code ignoring notarget
- Added SetPoseParameter input to animating entities
- Introduced an experimental chapter system which allows for custom chapter title/restriction management
- Added SetChapterTitle input to worldspawn for dynamic title changing
- Fixed func_tankairboatgun damage credit, added ability to use its damage keyvalues
- Fixed mapbase_rpc_enabled not actually affecting RPC
- Moved some newly found Combine soldier grenade code to ai_grenade for other grenade users
- Fixed some problems with the new shared activities
- Restored an old Mapbase entity as "prop_interactable", an entity which contains all of the functionality of a func_button/func_door in a prop entity
- Added env_microphone pitch scale for scaling the pitch of transmitted sounds
- Added experimental, long-overdue code for scenes to be able to access !target#'s and other scene-related names through AI_INPUT
- Added "mat_specular_disable_on_missing", which "disables" specular reflections when the cubemap texture is missing
- Fixed $envmapmasktransform and $bumptransform on VertexLitGeneric and related shaders
- Areaportal leaks now stop compilation in leaktest
- Replaced "-nodefaultcubemap" with "-defaultcubemap" as the shader changes allow maps to compile without default cubemaps by default with little effect
2020-02-05 19:08:49 +00:00

902 lines
29 KiB
C++

//========= Copyright 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"
#ifdef MAPBASE
#include "filters.h"
#include "ai_basenpc.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifdef MAPBASE
// These spawnflags were originally only on logic_measure_direction.
#define SF_LOGIC_MEASURE_MOVEMENT_IGNORE_X ( 1 << 0 )
#define SF_LOGIC_MEASURE_MOVEMENT_IGNORE_Y ( 1 << 1 )
#define SF_LOGIC_MEASURE_MOVEMENT_IGNORE_Z ( 1 << 2 )
// Uses the "Ignore X/Y/Z" flags for the origin instead of the angles.
// logic_measure_direction uses this flag to control trace direction.
#define SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN ( 1 << 3 )
// Uses "Teleport" instead of "SetAbsOrigin" for smoother movement
#define SF_LOGIC_MEASURE_MOVEMENT_TELEPORT ( 1 << 4 )
// Specifically refuse to set the target's angles, rather than just turning them to 0
#define SF_LOGIC_MEASURE_MOVEMENT_DONT_SET_ANGLES ( 1 << 5 )
#endif
//-----------------------------------------------------------------------------
// 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();
#ifdef MAPBASE
public:
#else
private:
#endif
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 );
#ifdef MAPBASE
// Allows for derived class trickery
void MeasureThink(); //{ DoMeasure(); }
// Allows for InputGetPosition(), etc.
virtual void DoMeasure(Vector &vecOrigin, QAngle &angAngles);
void HandleIgnoreFlags( float *vec );
void InputSetMeasureAttachment( inputdata_t &inputdata );
void InputSetMeasureType( inputdata_t &inputdata ) { m_nMeasureType = inputdata.value.Int(); }
void InputGetPosition( inputdata_t &inputdata );
#else
void MeasureThink();
private:
#endif
enum
{
MEASURE_POSITION = 0,
MEASURE_EYE_POSITION,
#ifdef MAPBASE
MEASURE_ATTACHMENT,
//MEASURE_BARREL_POSITION,
#endif
};
string_t m_strMeasureTarget;
string_t m_strMeasureReference;
string_t m_strTargetReference;
EHANDLE m_hMeasureTarget;
EHANDLE m_hMeasureReference;
EHANDLE m_hTarget;
EHANDLE m_hTargetReference;
#ifdef MAPBASE
string_t m_strAttachment;
int m_iAttachment;
bool m_bOutputPosition;
COutputVector m_OutPosition;
COutputVector m_OutAngles;
#endif
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" ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMeasureType", InputSetMeasureType ),
DEFINE_KEYFIELD( m_strAttachment, FIELD_STRING, "MeasureAttachment" ),
DEFINE_FIELD( m_iAttachment, FIELD_EHANDLE ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetMeasureAttachment", InputSetMeasureAttachment ),
DEFINE_INPUT( m_bOutputPosition, FIELD_BOOLEAN, "ShouldOutputPosition" ),
DEFINE_INPUTFUNC( FIELD_VOID, "GetPosition", InputGetPosition ),
#endif
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 ),
#ifdef MAPBASE
DEFINE_INPUTFUNC( FIELD_STRING, "Target", InputSetTarget ), // For legacy support...even though that name was broken before.
#endif
DEFINE_INPUTFUNC( FIELD_STRING, "SetTargetReference", InputSetTargetReference ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTargetScale", InputSetTargetScale ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
#ifdef MAPBASE
DEFINE_OUTPUT( m_OutPosition, "OutPosition" ),
DEFINE_OUTPUT( m_OutAngles, "OutAngles" ),
#endif
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 )
{
#ifdef MAPBASE
m_hMeasureTarget = gEntList.FindEntityByName( NULL, pName, this );
#else
m_hMeasureTarget = gEntList.FindEntityByName( NULL, pName );
#endif
if ( !m_hMeasureTarget )
{
if ( Q_strnicmp( STRING(m_strMeasureTarget), "!player", 8 ) )
{
#ifdef MAPBASE
Warning( "%s: Unable to find measure target entity %s\n", GetDebugName(), pName );
#else
Warning("logic_measure_movement: Unable to find measure target entity %s\n", pName );
#endif
}
}
#ifdef MAPBASE
m_iAttachment = 0;
#endif
}
void CLogicMeasureMovement::SetMeasureReference( const char *pName )
{
#ifdef MAPBASE
m_hMeasureReference = gEntList.FindEntityByName( NULL, pName, this );
#else
m_hMeasureReference = gEntList.FindEntityByName( NULL, pName );
#endif
if ( !m_hMeasureReference )
{
#ifdef MAPBASE
Warning( "%s: Unable to find measure reference entity %s\n", GetDebugName(), pName );
#else
Warning("logic_measure_movement: Unable to find measure reference entity %s\n", pName );
#endif
}
}
void CLogicMeasureMovement::SetTarget( const char *pName )
{
#ifdef MAPBASE
m_hTarget = gEntList.FindEntityByName( NULL, pName, this );
#else
m_hTarget = gEntList.FindEntityByName( NULL, pName );
#endif
if ( !m_hTarget )
{
#ifdef MAPBASE
Warning( "%s: Unable to find movement target entity %s\n", GetDebugName(), pName );
#else
Warning("logic_measure_movement: Unable to find movement target entity %s\n", pName );
#endif
}
}
void CLogicMeasureMovement::SetTargetReference( const char *pName )
{
#ifdef MAPBASE
m_hTargetReference = gEntList.FindEntityByName( NULL, pName, this );
#else
m_hTargetReference = gEntList.FindEntityByName( NULL, pName );
#endif
if ( !m_hTargetReference )
{
#ifdef MAPBASE
Warning( "%s: Unable to find movement reference entity %s\n", GetDebugName(), pName );
#else
Warning("logic_measure_movement: Unable to find movement reference entity %s\n", pName );
#endif
}
}
//-----------------------------------------------------------------------------
// 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() )
{
#ifdef MAPBASE
Vector vecNewOrigin;
QAngle vecNewAngles;
DoMeasure(vecNewOrigin, vecNewAngles);
if (m_bOutputPosition)
{
m_OutPosition.Set(vecNewOrigin, m_hTarget.Get(), this);
m_OutAngles.Set(vecNewAngles, m_hTarget.Get(), this);
}
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_TELEPORT ))
{
m_hTarget->Teleport( &vecNewOrigin, !HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_DONT_SET_ANGLES) ? &vecNewAngles : NULL, NULL );
}
else
{
m_hTarget->SetAbsOrigin( vecNewOrigin );
if (!HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_DONT_SET_ANGLES))
m_hTarget->SetAbsAngles( vecNewAngles );
}
#else
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 );
#endif
}
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// Purpose: Moves logic_measure_movement's movement measurements to its own function,
// primarily to allow for the GetPosition input without any hacks.
// Also helps with derivative entities that would otherwise have to find a way to re-define the think function.
// Warning: Doesn't account for whether these handles are null!
//-----------------------------------------------------------------------------
void CLogicMeasureMovement::DoMeasure( Vector &vecOrigin, QAngle &angAngles )
{
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;
case MEASURE_ATTACHMENT:
if (CBaseAnimating *pAnimating = m_hMeasureTarget->GetBaseAnimating())
{
if (m_iAttachment <= 0)
m_iAttachment = m_hMeasureTarget->GetBaseAnimating()->LookupAttachment(STRING(m_strAttachment));
if (m_iAttachment == -1)
Warning("WARNING: %s requesting invalid attachment %s on %s!\n", GetDebugName(), STRING(m_strAttachment), m_hMeasureTarget->GetDebugName());
else
pAnimating->GetAttachment(m_iAttachment, matWorldToMeasure);
}
else
{
Warning("WARNING: %s requesting attachment point on non-animating entity %s!\n", GetDebugName(), m_hMeasureTarget->GetDebugName());
}
break;
}
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 );
// Handle origin ignorance
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN ))
{
// Get the position from the matrix's column directly and re-assign it
Vector vecPosition;
MatrixGetColumn( matMeasureToRef, 3, vecPosition );
HandleIgnoreFlags( vecPosition.Base() );
MatrixSetColumn( vecPosition, 3, matMeasureToRef );
}
ConcatTransforms( m_hTargetReference->EntityToWorldTransform(), matMeasureToRef, matNewTargetToWorld );
MatrixAngles( matNewTargetToWorld, angAngles, vecOrigin );
// If our spawnflags are greater than 0 (and don't just contain our default "TELEPORT" flag), we might need to ignore one of our angles.
if (GetSpawnFlags() && GetSpawnFlags() != SF_LOGIC_MEASURE_MOVEMENT_TELEPORT && !HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN))
{
HandleIgnoreFlags( angAngles.Base() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles logic_measure_movement's ignore flags on the specified Vector/QAngle
//-----------------------------------------------------------------------------
FORCEINLINE void CLogicMeasureMovement::HandleIgnoreFlags( float *vec )
{
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_IGNORE_X ))
vec[0] = 0.0f;
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_IGNORE_Y ))
vec[1] = 0.0f;
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_IGNORE_Z ))
vec[2] = 0.0f;
}
#endif
//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
#ifdef MAPBASE
//
// Inputs work differently now so they could take !activator, etc.
//
void CLogicMeasureMovement::InputSetMeasureTarget( inputdata_t &inputdata )
{
m_strMeasureTarget = inputdata.value.StringID();
m_hMeasureTarget = gEntList.FindEntityByName( NULL, STRING(m_strMeasureTarget), this, inputdata.pActivator, inputdata.pCaller );
if ( !m_hMeasureTarget )
{
if ( Q_strnicmp( STRING(m_strMeasureTarget), "!player", 8 ) )
{
Warning( "%s: Unable to find measure target entity %s\n", GetDebugName(), STRING(m_strMeasureTarget) );
}
}
m_iAttachment = 0;
if (!m_hTarget)
SetTarget( STRING(m_target) );
if (!m_hTargetReference)
SetTargetReference( STRING(m_strTargetReference) );
}
void CLogicMeasureMovement::InputSetMeasureReference( inputdata_t &inputdata )
{
m_strMeasureReference = inputdata.value.StringID();
m_hMeasureReference = gEntList.FindEntityByName( NULL, STRING(m_strMeasureReference), this, inputdata.pActivator, inputdata.pCaller );
if ( !m_hMeasureReference )
{
Warning( "%s: Unable to find measure reference entity %s\n", GetDebugName(), STRING(m_strMeasureReference) );
}
}
void CLogicMeasureMovement::InputSetTarget( inputdata_t &inputdata )
{
m_target = inputdata.value.StringID();
m_hTarget = gEntList.FindEntityByName( NULL, STRING(m_target), this, inputdata.pActivator, inputdata.pCaller );
if ( !m_hTarget )
{
Warning( "%s: Unable to find movement target entity %s\n", GetDebugName(), STRING(m_target) );
}
}
void CLogicMeasureMovement::InputSetTargetReference( inputdata_t &inputdata )
{
m_strTargetReference = inputdata.value.StringID();
m_hTargetReference = gEntList.FindEntityByName( NULL, STRING(m_strTargetReference), this, inputdata.pActivator, inputdata.pCaller );
if ( !m_hTargetReference )
{
Warning( "%s: Unable to find movement reference entity %s\n", GetDebugName(), STRING(m_strTargetReference) );
}
}
void CLogicMeasureMovement::InputSetMeasureAttachment( inputdata_t &inputdata )
{
m_strAttachment = inputdata.value.StringID();
m_iAttachment = 0;
}
// Just gets the position once and fires outputs without moving anything.
// We don't even need a target for this.
void CLogicMeasureMovement::InputGetPosition( inputdata_t &inputdata )
{
if ( !m_hMeasureTarget.Get() || !m_hMeasureReference.Get() || !m_hTargetReference.Get() )
return;
Vector vecNewOrigin;
QAngle vecNewAngles;
DoMeasure(vecNewOrigin, vecNewAngles);
// m_bOutputPosition has been repurposed here to toggle between using the target or the input activator as the activator.
m_OutPosition.Set(vecNewOrigin, m_bOutputPosition ? m_hTarget.Get() : inputdata.pActivator, this);
m_OutAngles.Set(Vector(vecNewAngles.x, vecNewAngles.y, vecNewAngles.z), m_bOutputPosition ? m_hTarget.Get() : inputdata.pActivator, this);
}
#else
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() );
}
#endif
void CLogicMeasureMovement::InputSetTargetScale( inputdata_t &inputdata )
{
m_flScale = inputdata.value.Float();
}
#ifdef MAPBASE
//-----------------------------------------------------------------------------
// This will measure the direction of a target entity and move
// another entity to where the target entity is facing.
//
// m_hMeasureTarget; // Whose direction is measured
// m_hMeasureReference; // Position where direction is measured
// m_hTarget; // Target whose origin is applied
// m_hTargetReference; // From where the target's origin is applied
//-----------------------------------------------------------------------------
class CLogicMeasureDirection : public CLogicMeasureMovement
{
DECLARE_DATADESC();
DECLARE_CLASS( CLogicMeasureDirection, CLogicMeasureMovement );
public:
virtual void DoMeasure(Vector &vecOrigin, QAngle &angAngles);
CBaseFilter *GetTraceFilter();
//void InputSetTraceFilter( inputdata_t &inputdata ) { InputSetDamageFilter(inputdata); }
private:
float m_flTraceDistance;
int m_iMask;
int m_iCollisionGroup;
bool m_bHitIfPassed;
//string_t m_iszTraceFilter;
//CHandle<CBaseFilter*> m_hTraceFilter;
bool m_bTraceTargetReference;
};
LINK_ENTITY_TO_CLASS( logic_measure_direction, CLogicMeasureDirection );
BEGIN_DATADESC( CLogicMeasureDirection )
DEFINE_KEYFIELD( m_flTraceDistance, FIELD_FLOAT, "TraceDistance" ),
DEFINE_KEYFIELD( m_iMask, FIELD_INTEGER, "Mask" ),
DEFINE_KEYFIELD( m_iCollisionGroup, FIELD_INTEGER, "CollisionGroup" ),
DEFINE_KEYFIELD( m_bHitIfPassed, FIELD_BOOLEAN, "HitIfPassed" ),
DEFINE_KEYFIELD( m_bTraceTargetReference, FIELD_BOOLEAN, "TraceTargetReference" ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTraceFilter", InputSetDamageFilter ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Gets our "trace filter".
//-----------------------------------------------------------------------------
inline CBaseFilter *CLogicMeasureDirection::GetTraceFilter()
{
return static_cast<CBaseFilter*>(m_hDamageFilter.Get()); // pranked
}
//-----------------------------------------------------------------------------
// Purpose: Does measure.
//-----------------------------------------------------------------------------
void CLogicMeasureDirection::DoMeasure( Vector &vecOrigin, QAngle &angAngles )
{
trace_t tr;
Vector vecStart, vecDir;
QAngle angStart;
switch( m_nMeasureType )
{
case MEASURE_POSITION:
vecStart = m_hMeasureReference->GetAbsOrigin();
angStart = m_hMeasureTarget->GetAbsAngles();
break;
case MEASURE_EYE_POSITION:
vecStart = m_hMeasureReference->EyePosition();
angStart = m_hMeasureTarget->EyeAngles();
break;
case MEASURE_ATTACHMENT:
CBaseAnimating *pAnimating = m_hMeasureTarget->GetBaseAnimating();
if (pAnimating)
{
if (m_iAttachment <= 0)
m_iAttachment = m_hMeasureTarget->GetBaseAnimating()->LookupAttachment(STRING(m_strAttachment));
if (m_iAttachment == -1)
Warning("WARNING: %s requesting invalid attachment %s on %s!\n", GetDebugName(), STRING(m_strAttachment), m_hMeasureTarget->GetDebugName());
else
{
pAnimating->GetAttachment(m_iAttachment, vecStart, angStart);
}
}
else
{
Warning("WARNING: %s requesting attachment point on non-animating entity %s!\n", GetDebugName(), m_hMeasureTarget->GetDebugName());
}
break;
}
// If we have spawn flags, we might be supposed to ignore something
if (GetSpawnFlags() > 0)
{
if (!HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN))
AngleVectors(angStart, &vecDir);
HandleIgnoreFlags( angStart.Base() );
if (HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN))
AngleVectors(angStart, &vecDir);
}
else
{
AngleVectors(angStart, &vecDir);
}
CTraceFilterEntityFilter traceFilter(m_hMeasureReference, m_iCollisionGroup);
traceFilter.m_pFilter = GetTraceFilter();
traceFilter.m_bHitIfPassed = m_bHitIfPassed;
UTIL_TraceLine( vecStart, vecStart + vecDir * (m_flTraceDistance != 0 ? m_flTraceDistance : MAX_TRACE_LENGTH), m_iMask, &traceFilter, &tr ); //MASK_BLOCKLOS_AND_NPCS
Vector vecEnd = tr.endpos;
// Apply the scale factor
float flScale = m_flScale;
if ( ( flScale != 0.0f ) && ( flScale != 1.0f ) )
{
vecEnd = (vecStart + ((vecEnd - vecStart) / flScale));
}
Vector refPos = m_hTargetReference->GetAbsOrigin();
Vector vecPos = refPos + (vecEnd - vecStart);
if (m_bTraceTargetReference)
{
// Make sure we can go the whole distance there
UTIL_TraceLine( refPos, vecPos, m_iMask, &traceFilter, &tr );
vecPos = tr.endpos;
}
vecOrigin = vecPos;
angAngles = angStart;
}
//-----------------------------------------------------------------------------
// The unused, "forgotten" entity brought back to life.
// Mirrors an entity's movement across a reference.
// It derives from logic_measure_movement now so it could use its features.
// This is unfinished and I'm still figuring out how it works.
//
// m_hMeasureTarget; // Whose position is mirrored (m_hRemoteTarget)
// m_hMeasureReference; // Position where position is mirrored (m_hMirrorRelative)
// m_hTarget; // Target whose origin is mirrored (m_hMovementTarget)
// m_hTargetReference; // From where the target's origin is mirrored (m_hMirrorTarget)
//-----------------------------------------------------------------------------
class CLogicMirrorMovement : public CLogicMeasureMovement
{
DECLARE_DATADESC();
DECLARE_CLASS( CLogicMirrorMovement, CLogicMeasureMovement );
public:
virtual void DoMeasure(Vector &vecOrigin, QAngle &angAngles);
};
LINK_ENTITY_TO_CLASS( logic_mirror_movement, CLogicMirrorMovement );
BEGIN_DATADESC( CLogicMirrorMovement )
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Does measure.
//-----------------------------------------------------------------------------
void CLogicMirrorMovement::DoMeasure( Vector &vecOrigin, QAngle &angAngles )
{
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;
case MEASURE_ATTACHMENT:
if (CBaseAnimating *pAnimating = m_hMeasureTarget->GetBaseAnimating())
{
if (m_iAttachment <= 0)
m_iAttachment = m_hMeasureTarget->GetBaseAnimating()->LookupAttachment(STRING(m_strAttachment));
if (m_iAttachment == -1)
Warning("WARNING: %s requesting invalid attachment %s on %s!\n", GetDebugName(), STRING(m_strAttachment), m_hMeasureTarget->GetDebugName());
else
pAnimating->GetAttachment(m_iAttachment, matWorldToMeasure);
}
else
{
Warning("WARNING: %s requesting attachment point on non-animating entity %s!\n", GetDebugName(), m_hMeasureTarget->GetDebugName());
}
break;
}
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 );
}
MatrixScaleBy( -1.0f, matRefToMeasure );
QAngle angRot;
Vector vecPos;
MatrixAngles( matRefToMeasure, angRot );
MatrixPosition( matRefToMeasure, vecPos );
angRot.z *= -1.0f;
vecPos.z *= -1.0f;
AngleMatrix( angRot, vecPos, matWorldToMeasure );
// Now apply the new matrix to the new reference point
matrix3x4_t matMeasureToRef, matNewTargetToWorld;
MatrixInvert( matRefToMeasure, matMeasureToRef );
// Handle origin ignorance
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN ))
{
// Get the position from the matrix's column directly and re-assign it
Vector vecPosition;
MatrixGetColumn( matRefToMeasure, 3, vecPosition );
HandleIgnoreFlags( vecPosition.Base() );
MatrixSetColumn( vecPosition, 3, matRefToMeasure );
}
ConcatTransforms( m_hTargetReference->EntityToWorldTransform(), matMeasureToRef, matNewTargetToWorld );
MatrixAngles( matNewTargetToWorld, angAngles, vecOrigin );
// If our spawnflags are greater than 0 (and don't just contain our default "TELEPORT" flag), we might need to ignore one of our angles.
if (GetSpawnFlags() && GetSpawnFlags() != SF_LOGIC_MEASURE_MOVEMENT_TELEPORT && !HasSpawnFlags(SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN))
{
HandleIgnoreFlags( angAngles.Base() );
}
/*
VMatrix matPortal1ToWorldInv, matPortal2ToWorld;
MatrixInverseGeneral( m_hMeasureReference->EntityToWorldTransform(), matPortal1ToWorldInv );
switch( m_nMeasureType )
{
case MEASURE_POSITION:
matPortal2ToWorld = m_hMeasureTarget->EntityToWorldTransform();
break;
case MEASURE_EYE_POSITION:
matPortal2ToWorld.SetupMatrixOrgAngles( m_hMeasureTarget->EyePosition(), m_hMeasureTarget->EyeAngles() );
break;
case MEASURE_ATTACHMENT:
CBaseAnimating *pAnimating = m_hMeasureTarget->GetBaseAnimating();
if (pAnimating)
{
if (m_iAttachment <= 0)
m_iAttachment = m_hMeasureTarget->GetBaseAnimating()->LookupAttachment(STRING(m_strAttachment));
if (m_iAttachment == -1)
Warning("WARNING: %s requesting invalid attachment %s on %s!\n", GetDebugName(), STRING(m_strAttachment), m_hMeasureTarget->GetDebugName());
else
{
pAnimating->GetAttachment( m_iAttachment, matPortal2ToWorld.As3x4() );
}
}
else
{
Warning("WARNING: %s requesting attachment point on non-animating entity %s!\n", GetDebugName(), m_hMeasureTarget->GetDebugName());
}
break;
}
// If we have spawn flags, we might be supposed to ignore something
if (GetSpawnFlags() > 0)
{
if (HasSpawnFlags( SF_LOGIC_MEASURE_MOVEMENT_USE_IGNORE_FLAGS_FOR_ORIGIN ))
{
// Get the position from the matrix's column directly and re-assign it
Vector vecPosition;
MatrixGetColumn( matPortal2ToWorld, 3, &vecPosition );
HandleIgnoreFlags( vecPosition.Base() );
MatrixSetColumn( matPortal2ToWorld, 3, vecPosition );
}
else
{
// Get the angles from the matrix and re-assign it
QAngle angAngles;
MatrixToAngles( matPortal2ToWorld, angAngles );
HandleIgnoreFlags( angAngles.Base() );
matPortal2ToWorld.SetupMatrixAngles( angAngles );
}
}
// Apply the scale factor
if ( ( m_flScale != 0.0f ) && ( m_flScale != 1.0f ) )
{
Vector vecTranslation;
MatrixGetColumn( matPortal2ToWorld.As3x4(), 3, vecTranslation );
vecTranslation /= m_flScale;
MatrixSetColumn( vecTranslation, 3, matPortal2ToWorld.As3x4() );
}
// Get our scene camera's current orientation
Vector ptCameraPosition, vCameraLook, vCameraRight, vCameraUp;
ptCameraPosition = m_hTargetReference->EyePosition();
m_hTargetReference->GetVectors( &vCameraLook, &vCameraRight, &vCameraUp );
// map this position and orientation to the remote portal, mirrored (invert the result)
Vector ptNewPosition, vNewLook;
ptNewPosition = matPortal1ToWorldInv * ptCameraPosition;
ptNewPosition = matPortal2ToWorld*(Vector( -ptNewPosition.x, -ptNewPosition.y, ptNewPosition.z ));
vNewLook = matPortal1ToWorldInv.ApplyRotation( vCameraLook );
vNewLook = matPortal2ToWorld.ApplyRotation( Vector( -vNewLook.x, -vNewLook.y, vNewLook.z ) );
// Set the point camera to the new location/orientation
QAngle qNewAngles;
VectorAngles( vNewLook, qNewAngles );
vecOrigin = ptNewPosition;
angAngles = qNewAngles;
*/
}
#endif