source-engine/game/server/logic_mirror_movement.cpp

199 lines
6.7 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Mirrors the movement of a camera about a given point.
//
//=============================================================================//
#include "cbase.h"
#include "baseentity.h"
#include "modelentities.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//////////////////////////////////////////////////////////////////////////
// CLogicMirrorMovement
// This will record the vector offset of an entity's center from a given reference point
// (most likely the center of a mirror or portal) and place an entity (most likely a point camera)
// at a the same offset, mirrored about the reference point and orientation.
//////////////////////////////////////////////////////////////////////////
class CLogicMirrorMovement : public CLogicalEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CLogicMirrorMovement, CLogicalEntity );
private:
void SetMirrorTarget( const char *pName ); // Set entity to watch and mirror (ex. the player)
void SetTarget( const char *pName ); // Set entity to move based on the Mirror Target entity (ex. a point_camera)
void SetMirrorRelative( const char* pName ); // Set the point about which to measure an offset to orient based upon (ex. portal 1)
void SetRemoteTarget ( const char *pName ); // Entity's orientation/location from which to offset the movement target (ex. portal 2)
void SetDrawingSurface ( const char *pName );
void InputSetMirrorTarget( inputdata_t &inputdata );
void InputSetTarget( inputdata_t &inputdata );
void InputSetRemoteTarget ( inputdata_t &inputdata );
void InputSetMirrorRelative ( inputdata_t &inputdata );
void Think();
virtual void Activate();
string_t m_strMirrorTarget;
string_t m_strRemoteTarget;
string_t m_strMirrorRelative;
EHANDLE m_hRemoteTarget;
EHANDLE m_hMirrorTarget;
EHANDLE m_hMovementTarget;
EHANDLE m_hMirrorRelative;
};
LINK_ENTITY_TO_CLASS( logic_mirror_movement, CLogicMirrorMovement );
BEGIN_DATADESC( CLogicMirrorMovement )
DEFINE_KEYFIELD( m_strMirrorTarget, FIELD_STRING, "MirrorTarget" ),
DEFINE_KEYFIELD( m_strRemoteTarget, FIELD_STRING, "RemoteTarget" ),
DEFINE_KEYFIELD( m_strMirrorRelative, FIELD_STRING, "MirrorRelative" ),
DEFINE_FIELD( m_hMirrorTarget, FIELD_EHANDLE ),
DEFINE_FIELD( m_hMovementTarget, FIELD_EHANDLE ),
DEFINE_FIELD( m_hRemoteTarget, FIELD_EHANDLE ),
DEFINE_FIELD( m_hMirrorRelative, FIELD_EHANDLE ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetMirrorTarget", InputSetMirrorTarget ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetRemoteTarget", InputSetRemoteTarget ),
DEFINE_INPUTFUNC( FIELD_STRING, "SetMirrorRelative", InputSetMirrorRelative ),
DEFINE_THINKFUNC( Think ),
END_DATADESC()
void CLogicMirrorMovement::Activate()
{
BaseClass::Activate();
SetMirrorTarget( STRING(m_strMirrorTarget) );
SetTarget( STRING(m_target) );
SetRemoteTarget( STRING(m_strRemoteTarget ) );
SetMirrorRelative( STRING( m_strMirrorRelative) );
SetThink( &CLogicMirrorMovement::Think );
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
void CLogicMirrorMovement::SetMirrorTarget( const char *pName )
{
m_hMirrorTarget = gEntList.FindEntityByName( NULL, pName );
if ( !m_hMirrorTarget )
{
if ( Q_strnicmp( STRING(m_strMirrorTarget), "!player", 8 ) )
{
Warning("logic_mirror_movement: Unable to find mirror target entity %s\n", pName );
}
}
}
void CLogicMirrorMovement::SetTarget( const char *pName )
{
m_hMovementTarget = gEntList.FindEntityByName( NULL, pName );
if ( !m_hMovementTarget )
{
Warning("logic_mirror_movement: Unable to find movement target entity %s\n", pName );
}
}
void CLogicMirrorMovement::SetRemoteTarget(const char *pName )
{
m_hRemoteTarget = gEntList.FindEntityByName( NULL, pName );
if ( !m_hRemoteTarget )
{
Warning("logic_mirror_movement: Unable to find remote target entity %s\n", pName );
}
}
void CLogicMirrorMovement::SetMirrorRelative(const char* pName )
{
m_hMirrorRelative = gEntList.FindEntityByName( NULL, pName );
if ( !m_hMirrorRelative )
{
Warning("logic_mirror_movement: Unable to find mirror relative entity %s\n", pName );
}
}
void CLogicMirrorMovement::InputSetMirrorTarget( inputdata_t &inputdata )
{
m_strMirrorTarget = AllocPooledString( inputdata.value.String() );
SetMirrorTarget( inputdata.value.String() );
}
void CLogicMirrorMovement::InputSetTarget( inputdata_t &inputdata )
{
m_target = AllocPooledString( inputdata.value.String() );
SetTarget( inputdata.value.String() );
}
void CLogicMirrorMovement::InputSetRemoteTarget(inputdata_t &inputdata )
{
m_strRemoteTarget = AllocPooledString( inputdata.value.String() );
SetRemoteTarget( inputdata.value.String() );
}
void CLogicMirrorMovement::InputSetMirrorRelative(inputdata_t &inputdata )
{
m_strMirrorRelative = AllocPooledString ( inputdata.value.String() );
SetMirrorRelative( inputdata.value.String() );
}
void CLogicMirrorMovement::Think()
{
// Attempt to get the player's handle because it didn't exist at Activate time
if ( !m_hMirrorTarget.Get() )
{
// If we will never find a target, we don't have a use... shutdown
if ( m_strMirrorTarget == NULL_STRING )
SetNextThink ( NULL );
//BUGBUG: If m_strSetMirrorTarget doesn't exist in ent list, we get per-think searches with no results ever...
SetMirrorTarget ( STRING(m_strMirrorTarget) );
}
// Make sure all entities are valid
if ( m_hMirrorTarget.Get() && m_hMovementTarget.Get() && m_hRemoteTarget.Get() && m_hMirrorRelative.Get() )
{
// Get our two portal's world transforms transforms
VMatrix matPortal1ToWorldInv, matPortal2ToWorld;
MatrixInverseGeneral( m_hMirrorRelative->EntityToWorldTransform(), matPortal1ToWorldInv );
matPortal2ToWorld = m_hRemoteTarget->EntityToWorldTransform();
VMatrix matTransformToRemotePortal = matPortal1ToWorldInv * matPortal2ToWorld;
// Get our scene camera's current orientation
Vector ptCameraPosition, vCameraLook, vCameraRight, vCameraUp;
ptCameraPosition = m_hMirrorTarget->EyePosition();
m_hMirrorTarget->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 );
m_hMovementTarget->Teleport( &ptNewPosition, &qNewAngles, NULL );
}
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}