summaryrefslogtreecommitdiff
path: root/game/server/portal/prop_telescopic_arm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/portal/prop_telescopic_arm.cpp')
-rw-r--r--game/server/portal/prop_telescopic_arm.cpp538
1 files changed, 538 insertions, 0 deletions
diff --git a/game/server/portal/prop_telescopic_arm.cpp b/game/server/portal/prop_telescopic_arm.cpp
new file mode 100644
index 0000000..1f38dd5
--- /dev/null
+++ b/game/server/portal/prop_telescopic_arm.cpp
@@ -0,0 +1,538 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements the big scary boom-boom machine Antlions fear.
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "baseentity.h"
+#include "rotorwash.h"
+#include "soundenvelope.h"
+#include "engine/IEngineSound.h"
+#include "te_effect_dispatch.h"
+#include "point_posecontroller.h"
+#include "prop_portal_shared.h"
+
+
+#define TELESCOPE_ENABLE_TIME 1.0f
+#define TELESCOPE_DISABLE_TIME 2.0f
+#define TELESCOPE_ROTATEX_TIME 0.5f
+#define TELESCOPE_ROTATEY_TIME 0.5f
+
+#define TELESCOPING_ARM_MODEL_NAME "models/props/telescopic_arm.mdl"
+
+#define DEBUG_TELESCOPIC_ARM_AIM 1
+
+
+class CPropTelescopicArm : public CBaseAnimating
+{
+public:
+ DECLARE_CLASS( CPropTelescopicArm, CBaseAnimating );
+ DECLARE_DATADESC();
+
+ virtual void UpdateOnRemove( void );
+ virtual void Spawn( void );
+ virtual void Precache( void );
+ virtual void Activate ( void );
+
+ void DisabledThink( void );
+ void EnabledThink( void );
+
+ void AimAt( Vector vTarget );
+ bool TestLOS( const Vector& vAimPoint );
+ void SetTarget( const char *pTargetName );
+ void SetTarget( CBaseEntity *pTarget );
+
+ void InputDisable( inputdata_t &inputdata );
+ void InputEnable( inputdata_t &inputdata );
+
+ void InputSetTarget( inputdata_t &inputdata );
+ void InputTargetPlayer( inputdata_t &inputdata );
+
+private:
+
+ Vector FindTargetAimPoint( void );
+ Vector FindAimPointThroughPortal ( const CProp_Portal* pPortal );
+
+ bool m_bEnabled;
+ bool m_bCanSeeTarget;
+ int m_iFrontMarkerAttachment;
+
+ EHANDLE m_hRotXPoseController;
+ EHANDLE m_hRotYPoseController;
+ EHANDLE m_hTelescopicPoseController;
+
+ EHANDLE m_hAimTarget;
+
+ COutputEvent m_OnLostTarget;
+ COutputEvent m_OnFoundTarget;
+};
+
+LINK_ENTITY_TO_CLASS( prop_telescopic_arm, CPropTelescopicArm );
+
+//-----------------------------------------------------------------------------
+// Save/load
+//-----------------------------------------------------------------------------
+BEGIN_DATADESC( CPropTelescopicArm )
+ DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bCanSeeTarget, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_iFrontMarkerAttachment, FIELD_INTEGER ),
+ DEFINE_FIELD( m_hRotXPoseController, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hRotYPoseController, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hTelescopicPoseController, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hAimTarget, FIELD_EHANDLE ),
+ DEFINE_THINKFUNC( DisabledThink ),
+ DEFINE_THINKFUNC( EnabledThink ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
+ DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ),
+ DEFINE_INPUTFUNC( FIELD_VOID, "TargetPlayer", InputTargetPlayer ),
+ DEFINE_OUTPUT ( m_OnLostTarget, "OnLostTarget" ),
+ DEFINE_OUTPUT ( m_OnFoundTarget, "OnFoundTarget" ),
+END_DATADESC()
+
+
+void CPropTelescopicArm::UpdateOnRemove( void )
+{
+ CPoseController *pPoseController;
+
+ pPoseController = static_cast<CPoseController*>( m_hRotXPoseController.Get() );
+ if ( pPoseController )
+ UTIL_Remove( pPoseController );
+ m_hRotXPoseController = 0;
+
+ pPoseController = static_cast<CPoseController*>( m_hRotYPoseController.Get() );
+ if ( pPoseController )
+ UTIL_Remove( pPoseController );
+ m_hRotYPoseController = 0;
+
+ pPoseController = static_cast<CPoseController*>( m_hTelescopicPoseController.Get() );
+ if ( pPoseController )
+ UTIL_Remove( pPoseController );
+ m_hTelescopicPoseController = 0;
+}
+
+void CPropTelescopicArm::Spawn( void )
+{
+ char *szModel = (char *)STRING( GetModelName() );
+ if (!szModel || !*szModel)
+ {
+ szModel = TELESCOPING_ARM_MODEL_NAME;
+ SetModelName( AllocPooledString(szModel) );
+ }
+
+ Precache();
+ SetModel( szModel );
+
+ SetSolid( SOLID_VPHYSICS );
+ SetMoveType( MOVETYPE_PUSH );
+ VPhysicsInitStatic();
+
+ BaseClass::Spawn();
+
+ m_bEnabled = false;
+ m_bCanSeeTarget = false;
+
+ SetThink( &CPropTelescopicArm::DisabledThink );
+ SetNextThink( gpGlobals->curtime + 1.0f );
+
+ int iSequence = SelectHeaviestSequence ( ACT_IDLE );
+
+ if ( iSequence != ACT_INVALID )
+ {
+ SetSequence( iSequence );
+ ResetSequenceInfo();
+
+ //Do this so we get the nice ramp-up effect.
+ m_flPlaybackRate = random->RandomFloat( 0.0f, 1.0f );
+ }
+
+ m_iFrontMarkerAttachment = LookupAttachment( "Front_marker" );
+
+ CPoseController *pPoseController;
+
+ pPoseController = static_cast<CPoseController*>( CreateEntityByName( "point_posecontroller" ) );
+ DispatchSpawn( pPoseController );
+ if ( pPoseController )
+ {
+ pPoseController->SetProp( this );
+ pPoseController->SetInterpolationWrap( true );
+ pPoseController->SetPoseParameterName( "rot_x" );
+ m_hRotXPoseController = pPoseController;
+ }
+
+ pPoseController = static_cast<CPoseController*>( CreateEntityByName( "point_posecontroller" ) );
+ DispatchSpawn( pPoseController );
+ if ( pPoseController )
+ {
+ pPoseController->SetProp( this );
+ pPoseController->SetInterpolationWrap( true );
+ pPoseController->SetPoseParameterName( "rot_y" );
+ m_hRotYPoseController = pPoseController;
+ }
+
+ pPoseController = static_cast<CPoseController*>( CreateEntityByName( "point_posecontroller" ) );
+ DispatchSpawn( pPoseController );
+ if ( pPoseController )
+ {
+ pPoseController->SetProp( this );
+ pPoseController->SetPoseParameterName( "telescopic" );
+ m_hTelescopicPoseController = pPoseController;
+ }
+}
+
+void CPropTelescopicArm::Precache( void )
+{
+ BaseClass::Precache();
+
+ PrecacheModel( STRING( GetModelName() ) );
+ PrecacheScriptSound( "coast.thumper_hit" );
+ PrecacheScriptSound( "coast.thumper_ambient" );
+ PrecacheScriptSound( "coast.thumper_dust" );
+ PrecacheScriptSound( "coast.thumper_startup" );
+ PrecacheScriptSound( "coast.thumper_shutdown" );
+ PrecacheScriptSound( "coast.thumper_large_hit" );
+}
+
+void CPropTelescopicArm::Activate( void )
+{
+ BaseClass::Activate();
+}
+
+void CPropTelescopicArm::DisabledThink( void )
+{
+ SetNextThink( gpGlobals->curtime + 1.0 );
+}
+
+void CPropTelescopicArm::EnabledThink( void )
+{
+ CBaseEntity *pTarget = m_hAimTarget.Get();
+
+ if ( !pTarget )
+ {
+ //SetTarget ( UTIL_PlayerByIndex( 1 ) );
+
+ // Default to targeting a player
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer && FVisible( pPlayer ) && pPlayer->IsAlive() )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ if( pTarget == NULL )
+ {
+ //search again, but don't require the player to be visible
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer && pPlayer->IsAlive() )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+
+ if( pTarget == NULL )
+ {
+ //search again, but don't require the player to be visible or alive
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ }
+ }
+
+ if( pTarget )
+ SetTarget( pTarget );
+ }
+
+ if ( pTarget )
+ {
+ // Aim at the center of the abs box
+ Vector vAimPoint = FindTargetAimPoint();
+ Assert ( vAimPoint != vec3_invalid );
+ AimAt( vAimPoint );
+
+ // We have direct line of sight to our target
+ if ( TestLOS ( vAimPoint ) )
+ {
+ // Just aquired LOS
+ if ( !m_bCanSeeTarget )
+ {
+ m_OnFoundTarget.FireOutput( m_hAimTarget, this );
+ }
+ m_bCanSeeTarget = true;
+ }
+ // No LOS to target
+ else
+ {
+ // Just lost LOS
+ if ( m_bCanSeeTarget )
+ {
+ m_OnLostTarget.FireOutput( m_hAimTarget, this );
+ }
+ m_bCanSeeTarget = false;
+ }
+ }
+
+ SetNextThink( gpGlobals->curtime + 0.1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds the point to aim at in order to see the target entity.
+// Note: Also considers aim paths through portals.
+// Output : Point of the target
+//-----------------------------------------------------------------------------
+Vector CPropTelescopicArm::FindTargetAimPoint( void )
+{
+ CBaseEntity *pTarget = m_hAimTarget.Get();
+
+ if ( !pTarget )
+ {
+ // No target to aim at, can't return meaningful info
+ Warning( "CPropTelescopicArm::FindTargetAimPoint called with no valid target entity." );
+ return vec3_invalid;
+ }
+ else
+ {
+ Vector vFrontPoint;
+ GetAttachment( m_iFrontMarkerAttachment, vFrontPoint, NULL, NULL, NULL );
+
+ // Aim at the target through the world
+ Vector vAimPoint = pTarget->GetAbsOrigin() + ( pTarget->WorldAlignMins() + pTarget->WorldAlignMaxs() ) * 0.5f;
+ //float fDistToPoint = vFrontPoint.DistToSqr( vAimPoint );
+
+ CProp_Portal *pShortestDistPortal = NULL;
+ UTIL_Portal_ShortestDistance( vFrontPoint, vAimPoint, &pShortestDistPortal, true );
+
+ Vector ptShortestAimPoint;
+ if( pShortestDistPortal )
+ {
+ ptShortestAimPoint = FindAimPointThroughPortal( pShortestDistPortal );
+ if( ptShortestAimPoint == vec3_invalid )
+ ptShortestAimPoint = vAimPoint;
+ }
+ else
+ {
+ ptShortestAimPoint = vAimPoint;
+ }
+
+ return ptShortestAimPoint;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Find the center of the target entity as seen through the specified portal
+// Input : pPortal - The portal to look through
+// Output : Vector& output point in world space where the target *appears* to be as seen through the portal
+//-----------------------------------------------------------------------------
+Vector CPropTelescopicArm::FindAimPointThroughPortal( const CProp_Portal* pPortal )
+{
+ if ( pPortal && pPortal->m_bActivated )
+ {
+ CProp_Portal* pLinked = pPortal->m_hLinkedPortal.Get();
+ CBaseEntity* pTarget = m_hAimTarget.Get();
+
+ if ( pLinked && pLinked->m_bActivated && pTarget )
+ {
+ VMatrix matToPortalView = pLinked->m_matrixThisToLinked;
+ Vector vTargetAimPoint = pTarget->GetAbsOrigin() + ( pTarget->WorldAlignMins() + pTarget->WorldAlignMaxs() ) * 0.5f;
+
+ return matToPortalView * vTargetAimPoint;
+ }
+ }
+
+ // Bad portal pointer, not linked, no target or otherwise failed
+ return vec3_invalid;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tests if this prop's front point has direct line of sight to it's target entity
+// Input : vAimPoint - The point to aim at
+// Output : Returns true if target is in direct line of sight, false otherwise.
+//-----------------------------------------------------------------------------
+bool CPropTelescopicArm::TestLOS( const Vector& vAimPoint )
+{
+ // Test for LOS and fire outputs if the sight condition changes
+ Vector vFaceOrigin;
+ trace_t tr;
+ GetAttachment( m_iFrontMarkerAttachment, vFaceOrigin, NULL, NULL, NULL );
+ Ray_t ray;
+ ray.Init( vFaceOrigin, vAimPoint );
+ ray.m_IsRay = true;
+
+ // This aim point does hit target, now make sure there are no blocking objects in the way
+ CTraceFilterWorldAndPropsOnly filter;
+ UTIL_Portal_TraceRay( ray, MASK_SHOT, &filter, &tr );
+ return !(tr.fraction < 1.0f);
+}
+
+void CPropTelescopicArm::AimAt( Vector vTarget )
+{
+ Vector vFaceOrigin;
+ GetAttachment( m_iFrontMarkerAttachment, vFaceOrigin, NULL, NULL, NULL );
+
+ Vector vNormalToTarget = vTarget - vFaceOrigin;
+ VectorNormalize( vNormalToTarget );
+
+ VMatrix vWorldToLocalRotation = EntityToWorldTransform();
+ vNormalToTarget = vWorldToLocalRotation.InverseTR().ApplyRotation( vNormalToTarget );
+
+ Vector vUp;
+ GetVectors( NULL, NULL, &vUp );
+
+ QAngle qAnglesToTarget;
+ VectorAngles( vNormalToTarget, vUp, qAnglesToTarget );
+
+ float fNewX = ( qAnglesToTarget.x + 90.0f ) / 360.0f;
+ float fNewY = qAnglesToTarget.y / 360.0f;
+
+ if ( fNewY < 0.0f )
+ fNewY += 1.0f;
+
+ CPoseController *pPoseController = static_cast<CPoseController*>( m_hRotXPoseController.Get() );
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_ROTATEX_TIME );
+ pPoseController->SetPoseValue( fNewX );
+ }
+
+ pPoseController = static_cast<CPoseController*>( m_hRotYPoseController.Get() );
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_ROTATEY_TIME );
+ pPoseController->SetPoseValue( fNewY );
+ }
+}
+
+void CPropTelescopicArm::SetTarget( const char *pchTargetName )
+{
+ CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, pchTargetName, NULL, NULL );
+
+ //if ( pTarget == NULL )
+ // pTarget = UTIL_PlayerByIndex( 1 );
+
+ return SetTarget( pTarget );
+}
+
+void CPropTelescopicArm::SetTarget( CBaseEntity *pTarget )
+{
+ m_hAimTarget = pTarget;
+}
+
+void CPropTelescopicArm::InputDisable( inputdata_t &inputdata )
+{
+ if ( m_bEnabled )
+ {
+ m_bEnabled = false;
+
+ EmitSound( "coast.thumper_shutdown" );
+
+ CPoseController *pPoseController;
+
+ pPoseController = static_cast<CPoseController*>( m_hRotXPoseController.Get() );
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_DISABLE_TIME * 0.5f );
+ pPoseController->SetPoseValue( 0.0f );
+ }
+
+ pPoseController = static_cast<CPoseController*>( m_hRotYPoseController.Get() );
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_DISABLE_TIME * 0.5f );
+ pPoseController->SetPoseValue( 0.0f );
+ }
+
+ pPoseController = static_cast<CPoseController*>( m_hTelescopicPoseController.Get() );
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_DISABLE_TIME );
+ pPoseController->SetPoseValue( 0.0f );
+ }
+
+ SetThink( &CPropTelescopicArm::DisabledThink );
+ SetNextThink( gpGlobals->curtime + TELESCOPE_DISABLE_TIME );
+ }
+}
+
+void CPropTelescopicArm::InputEnable( inputdata_t &inputdata )
+{
+ if ( !m_bEnabled )
+ {
+ m_bEnabled = true;
+
+ EmitSound( "coast.thumper_startup" );
+
+ CPoseController *pPoseController;
+ pPoseController = static_cast<CPoseController*>( m_hTelescopicPoseController.Get() );
+
+ if ( pPoseController )
+ {
+ pPoseController->SetInterpolationTime( TELESCOPE_ENABLE_TIME );
+ pPoseController->SetPoseValue( 1.0f );
+ }
+
+ SetThink( &CPropTelescopicArm::EnabledThink );
+ SetNextThink( gpGlobals->curtime + TELESCOPE_ENABLE_TIME );
+ }
+}
+
+void CPropTelescopicArm::InputSetTarget( inputdata_t &inputdata )
+{
+ SetTarget( inputdata.value.String() );
+}
+
+void CPropTelescopicArm::InputTargetPlayer( inputdata_t &inputdata )
+{
+ //SetTarget( UTIL_PlayerByIndex( 1 ) );
+
+ CBaseEntity *pTarget = NULL;
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer && FVisible( pPlayer ) && pPlayer->IsAlive() )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ if( pTarget == NULL )
+ {
+ //search again, but don't require the player to be visible
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer && pPlayer->IsAlive() )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+
+ if( pTarget == NULL )
+ {
+ //search again, but don't require the player to be visible or alive
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer )
+ {
+ pTarget = pPlayer;
+ break;
+ }
+ }
+ }
+ }
+
+ if( pTarget )
+ SetTarget( pTarget );
+} \ No newline at end of file