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/hl2/point_apc_controller.cpp | 996 ++++++++++++------------ 1 file changed, 498 insertions(+), 498 deletions(-) (limited to 'mp/src/game/server/hl2/point_apc_controller.cpp') diff --git a/mp/src/game/server/hl2/point_apc_controller.cpp b/mp/src/game/server/hl2/point_apc_controller.cpp index ff4d865c..9802f804 100644 --- a/mp/src/game/server/hl2/point_apc_controller.cpp +++ b/mp/src/game/server/hl2/point_apc_controller.cpp @@ -1,498 +1,498 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//=============================================================================// - -#include "cbase.h" -#include "basecombatweapon.h" -#include "explode.h" -#include "eventqueue.h" -#include "gamerules.h" -#include "ammodef.h" -#include "in_buttons.h" -#include "soundent.h" -#include "ndebugoverlay.h" -#include "vstdlib/random.h" -#include "engine/IEngineSound.h" - -#include "player.h" -#include "entitylist.h" -#include "iservervehicle.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define SF_TANK_ACTIVE 0x0001 - - -class CAPCController : public CPointEntity -{ - typedef CPointEntity BaseClass; -public: - ~CAPCController( void ); - void Spawn( void ); - void Precache( void ); - bool KeyValue( const char *szKeyName, const char *szValue ); - void Think( void ); - void TrackTarget( void ); - - void StartRotSound( void ); - void StopRotSound( void ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - inline bool IsActive( void ) { return (m_spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } - - // Input handlers. - void InputActivate( inputdata_t &inputdata ); - void InputDeactivate( inputdata_t &inputdata ); - - void ActivateRocketGuidance(void); - void DeactivateRocketGuidance(void); - - bool InRange( float range ); - - Vector WorldBarrelPosition( void ) - { - EntityMatrix tmp; - tmp.InitFromEntity( this ); - return tmp.LocalToWorld( m_barrelPos ); - } - - void UpdateMatrix( void ) - { - m_parentMatrix.InitFromEntity( GetParent() ? GetParent() : NULL ); - } - QAngle AimBarrelAt( const Vector &parentTarget ); - - bool ShouldSavePhysics() { return false; } - - DECLARE_DATADESC(); - - CBaseEntity *FindTarget( string_t targetName, CBaseEntity *pActivator ); - -protected: - float m_yawCenter; // "Center" yaw - float m_yawRate; // Max turn rate to track targets - // Zero is full rotation - float m_yawTolerance; // Tolerance angle - - float m_pitchCenter; // "Center" pitch - float m_pitchRate; // Max turn rate on pitch - float m_pitchTolerance; // Tolerance angle - - float m_minRange; // Minimum range to aim/track - float m_maxRange; // Max range to aim/track - - Vector m_barrelPos; // Length of the barrel - - Vector m_sightOrigin; // Last sight of target - - string_t m_soundStartRotate; - string_t m_soundStopRotate; - string_t m_soundLoopRotate; - - string_t m_targetEntityName; - EHANDLE m_hTarget; - EntityMatrix m_parentMatrix; - - COutputVector m_OnFireAtTarget; - - float m_flFiringDelay; - bool m_bFireDelayed; -}; - -LINK_ENTITY_TO_CLASS( point_apc_controller, CAPCController ); - -BEGIN_DATADESC( CAPCController ) - - DEFINE_FIELD( m_yawCenter, FIELD_FLOAT ), - DEFINE_KEYFIELD( m_yawRate, FIELD_FLOAT, "yawrate" ), - DEFINE_KEYFIELD( m_yawTolerance, FIELD_FLOAT, "yawtolerance" ), - - - DEFINE_FIELD( m_pitchCenter, FIELD_FLOAT ), - DEFINE_KEYFIELD( m_pitchRate, FIELD_FLOAT, "pitchrate" ), - DEFINE_KEYFIELD( m_pitchTolerance, FIELD_FLOAT, "pitchtolerance" ), - - DEFINE_KEYFIELD( m_minRange, FIELD_FLOAT, "minRange" ), - DEFINE_KEYFIELD( m_maxRange, FIELD_FLOAT, "maxRange" ), - DEFINE_FIELD( m_barrelPos, FIELD_VECTOR ), - DEFINE_FIELD( m_sightOrigin, FIELD_VECTOR ), - DEFINE_KEYFIELD( m_soundStartRotate, FIELD_SOUNDNAME, "rotatestartsound" ), - DEFINE_KEYFIELD( m_soundStopRotate, FIELD_SOUNDNAME, "rotatestopsound" ), - DEFINE_KEYFIELD( m_soundLoopRotate, FIELD_SOUNDNAME, "rotatesound" ), - DEFINE_KEYFIELD( m_targetEntityName, FIELD_STRING, "targetentityname" ), - DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ), - DEFINE_FIELD( m_parentMatrix, FIELD_VMATRIX_WORLDSPACE ), - DEFINE_FIELD( m_flFiringDelay, FIELD_FLOAT ), - DEFINE_FIELD( m_bFireDelayed, FIELD_BOOLEAN ), - - // Inputs - DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), - DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), - - // Outputs - DEFINE_OUTPUT(m_OnFireAtTarget, "OnFireAtTarget"), - -END_DATADESC() - - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CAPCController::~CAPCController( void ) -{ - if ( m_soundLoopRotate != NULL_STRING ) - { - StopSound( entindex(), CHAN_STATIC, STRING(m_soundLoopRotate) ); - } -} - -//------------------------------------------------------------------------------ -// Purpose: Input handler for activating the tank. -//------------------------------------------------------------------------------ -void CAPCController::InputActivate( inputdata_t &inputdata ) -{ - ActivateRocketGuidance(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAPCController::ActivateRocketGuidance(void) -{ - m_spawnflags |= SF_TANK_ACTIVE; - SetNextThink( gpGlobals->curtime + 0.1f ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Input handler for deactivating the tank. -//----------------------------------------------------------------------------- -void CAPCController::InputDeactivate( inputdata_t &inputdata ) -{ - DeactivateRocketGuidance(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CAPCController::DeactivateRocketGuidance(void) -{ - m_spawnflags &= ~SF_TANK_ACTIVE; - StopRotSound(); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : targetName - -// pActivator - -//----------------------------------------------------------------------------- -CBaseEntity *CAPCController::FindTarget( string_t targetName, CBaseEntity *pActivator ) -{ - return gEntList.FindEntityGenericNearest( STRING( targetName ), GetAbsOrigin(), 0, this, pActivator ); -} - -//----------------------------------------------------------------------------- -// Purpose: Caches entity key values until spawn is called. -// Input : szKeyName - -// szValue - -// Output : -//----------------------------------------------------------------------------- -bool CAPCController::KeyValue( const char *szKeyName, const char *szValue ) -{ - if (FStrEq(szKeyName, "barrel")) - { - m_barrelPos.x = atof(szValue); - } - else if (FStrEq(szKeyName, "barrely")) - { - m_barrelPos.y = atof(szValue); - } - else if (FStrEq(szKeyName, "barrelz")) - { - m_barrelPos.z = atof(szValue); - } - else - return BaseClass::KeyValue( szKeyName, szValue ); - - return true; -} - -//----------------------------------------- -// Spawn -//----------------------------------------- -void CAPCController::Spawn( void ) -{ - Precache(); - - m_yawCenter = GetLocalAngles().y; - m_pitchCenter = GetLocalAngles().x; - - if ( IsActive() ) - { - SetNextThink( gpGlobals->curtime + 1.0f ); - } - - UpdateMatrix(); -} - - -//----------------------------------------- -// Precache -//----------------------------------------- -void CAPCController::Precache( void ) -{ - if ( m_soundStartRotate != NULL_STRING ) - PrecacheScriptSound( STRING(m_soundStartRotate) ); - if ( m_soundStopRotate != NULL_STRING ) - PrecacheScriptSound( STRING(m_soundStopRotate) ); - if ( m_soundLoopRotate != NULL_STRING ) - PrecacheScriptSound( STRING(m_soundLoopRotate) ); -} - - -//----------------------------------------- -// InRange -//----------------------------------------- -bool CAPCController::InRange( float range ) -{ - if ( range < m_minRange ) - return FALSE; - if ( m_maxRange > 0 && range > m_maxRange ) - return FALSE; - - return TRUE; -} - - -//----------------------------------------- -// Think -//----------------------------------------- -void CAPCController::Think( void ) -{ - // refresh the matrix - UpdateMatrix(); - - SetLocalAngularVelocity( vec3_angle ); - TrackTarget(); - - if ( fabs(GetLocalAngularVelocity().x) > 1 || fabs(GetLocalAngularVelocity().y) > 1 ) - StartRotSound(); - else - StopRotSound(); -} - - -//----------------------------------------------------------------------------- -// Purpose: Aim the offset barrel at a position in parent space -// Input : parentTarget - the position of the target in parent space -// Output : Vector - angles in local space -//----------------------------------------------------------------------------- -QAngle CAPCController::AimBarrelAt( const Vector &parentTarget ) -{ - Vector target = parentTarget - GetLocalOrigin(); - float quadTarget = target.LengthSqr(); - float quadTargetXY = target.x*target.x + target.y*target.y; - - // We're trying to aim the offset barrel at an arbitrary point. - // To calculate this, I think of the target as being on a sphere with - // it's center at the origin of the gun. - // The rotation we need is the opposite of the rotation that moves the target - // along the surface of that sphere to intersect with the gun's shooting direction - // To calculate that rotation, we simply calculate the intersection of the ray - // coming out of the barrel with the target sphere (that's the new target position) - // and use atan2() to get angles - - // angles from target pos to center - float targetToCenterYaw = atan2( target.y, target.x ); - float centerToGunYaw = atan2( m_barrelPos.y, sqrt( quadTarget - (m_barrelPos.y*m_barrelPos.y) ) ); - - float targetToCenterPitch = atan2( target.z, sqrt( quadTargetXY ) ); - float centerToGunPitch = atan2( -m_barrelPos.z, sqrt( quadTarget - (m_barrelPos.z*m_barrelPos.z) ) ); - return QAngle( -RAD2DEG(targetToCenterPitch+centerToGunPitch), RAD2DEG( targetToCenterYaw + centerToGunYaw ), 0 ); -} - -void CAPCController::TrackTarget( void ) -{ - trace_t tr; - bool updateTime = FALSE, lineOfSight; - QAngle angles; - Vector barrelEnd; - CBaseEntity *pTarget = NULL; - - barrelEnd.Init(); - - if ( IsActive() ) - { - SetNextThink( gpGlobals->curtime + 0.1f ); - } - else - { - return; - } - - // ----------------------------------- - // Get world target position - // ----------------------------------- - barrelEnd = WorldBarrelPosition(); - Vector worldTargetPosition; - CBaseEntity *pEntity = (CBaseEntity *)m_hTarget; - if ( !pEntity || ( pEntity->GetFlags() & FL_NOTARGET ) ) - { - m_hTarget = FindTarget( m_targetEntityName, NULL ); - if ( IsActive() ) - { - SetNextThink( gpGlobals->curtime + 2 ); // Wait 2 sec s - } - - return; - } - pTarget = pEntity; - - // Calculate angle needed to aim at target - worldTargetPosition = pEntity->EyePosition(); - - float range = (worldTargetPosition - barrelEnd).Length(); - - if ( !InRange( range ) ) - { - m_bFireDelayed = false; - return; - } - - UTIL_TraceLine( barrelEnd, worldTargetPosition, MASK_BLOCKLOS, this, COLLISION_GROUP_NONE, &tr ); - - lineOfSight = FALSE; - // No line of sight, don't track - if ( tr.fraction == 1.0 || tr.m_pEnt == pTarget ) - { - lineOfSight = TRUE; - - CBaseEntity *pInstance = pTarget; - if ( InRange( range ) && pInstance && pInstance->IsAlive() ) - { - updateTime = TRUE; - - // Sight position is BodyTarget with no noise (so gun doesn't bob up and down) - m_sightOrigin = pInstance->BodyTarget( GetLocalOrigin(), false ); - } - } - - // Convert targetPosition to parent - angles = AimBarrelAt( m_parentMatrix.WorldToLocal( m_sightOrigin ) ); - - - // Force the angles to be relative to the center position - float offsetY = UTIL_AngleDistance( angles.y, m_yawCenter ); - float offsetX = UTIL_AngleDistance( angles.x, m_pitchCenter ); - angles.y = m_yawCenter + offsetY; - angles.x = m_pitchCenter + offsetX; - - // Move toward target at rate or less - float distY = UTIL_AngleDistance( angles.y, GetLocalAngles().y ); - - QAngle vecAngVel = GetLocalAngularVelocity(); - vecAngVel.y = distY * 10; - vecAngVel.y = clamp( vecAngVel.y, -m_yawRate, m_yawRate ); - - // Move toward target at rate or less - float distX = UTIL_AngleDistance( angles.x, GetLocalAngles().x ); - vecAngVel.x = distX * 10; - vecAngVel.x = clamp( vecAngVel.x, -m_pitchRate, m_pitchRate ); - SetLocalAngularVelocity( vecAngVel ); - - SetMoveDoneTime( 0.1 ); - - Vector forward; - AngleVectors( GetLocalAngles(), &forward ); - forward = m_parentMatrix.ApplyRotation( forward ); - - AngleVectors(angles, &forward); - - if ( lineOfSight == TRUE ) - { - // FIXME: This will ultimately have to deal with NPCs being in the vehicle as well - // See if the target is in a vehicle. If so, check its relationship - CBasePlayer *pPlayer = ToBasePlayer( pTarget ); - if ( pPlayer && pPlayer->IsInAVehicle() ) - { - IServerVehicle *pVehicle = pPlayer->GetVehicle(); - if ( pVehicle->ClassifyPassenger( pPlayer, CLASS_PLAYER ) == CLASS_PLAYER) - { - if ( !m_bFireDelayed ) - { - m_bFireDelayed = true; - m_flFiringDelay = gpGlobals->curtime + 1.5; // setup delay time before we start firing - return; - } - if ( gpGlobals->curtime > m_flFiringDelay ) - { - m_OnFireAtTarget.Set(forward, this, this); // tell apc to fire rockets, and what direction - } - } - } - } - else - { - m_bFireDelayed = false; // reset flag since we can no longer see target - } -} - -void CAPCController::StartRotSound( void ) -{ - if ( m_soundLoopRotate != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - filter.MakeReliable(); - - EmitSound_t ep; - ep.m_nChannel = CHAN_STATIC; - ep.m_pSoundName = (char*)STRING(m_soundLoopRotate); - ep.m_SoundLevel = SNDLVL_NORM; - ep.m_flVolume = 0.85; - - EmitSound( filter, entindex(), ep ); - } - - if ( m_soundStartRotate != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_BODY; - ep.m_pSoundName = (char*)STRING(m_soundStartRotate); - ep.m_SoundLevel = SNDLVL_NORM; - ep.m_flVolume = 1.0f; - - EmitSound( filter, entindex(), ep ); - } -} - - -void CAPCController::StopRotSound( void ) -{ - if ( m_soundLoopRotate != NULL_STRING ) - { - StopSound( entindex(), CHAN_STATIC, (char*)STRING(m_soundLoopRotate) ); - } - if ( m_soundStopRotate != NULL_STRING ) - { - CPASAttenuationFilter filter( this ); - - EmitSound_t ep; - ep.m_nChannel = CHAN_BODY; - ep.m_pSoundName = (char*)STRING(m_soundStopRotate); - ep.m_SoundLevel = SNDLVL_NORM; - - EmitSound( filter, entindex(), ep ); - } -} - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "basecombatweapon.h" +#include "explode.h" +#include "eventqueue.h" +#include "gamerules.h" +#include "ammodef.h" +#include "in_buttons.h" +#include "soundent.h" +#include "ndebugoverlay.h" +#include "vstdlib/random.h" +#include "engine/IEngineSound.h" + +#include "player.h" +#include "entitylist.h" +#include "iservervehicle.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define SF_TANK_ACTIVE 0x0001 + + +class CAPCController : public CPointEntity +{ + typedef CPointEntity BaseClass; +public: + ~CAPCController( void ); + void Spawn( void ); + void Precache( void ); + bool KeyValue( const char *szKeyName, const char *szValue ); + void Think( void ); + void TrackTarget( void ); + + void StartRotSound( void ); + void StopRotSound( void ); + + // Bmodels don't go across transitions + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + inline bool IsActive( void ) { return (m_spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } + + // Input handlers. + void InputActivate( inputdata_t &inputdata ); + void InputDeactivate( inputdata_t &inputdata ); + + void ActivateRocketGuidance(void); + void DeactivateRocketGuidance(void); + + bool InRange( float range ); + + Vector WorldBarrelPosition( void ) + { + EntityMatrix tmp; + tmp.InitFromEntity( this ); + return tmp.LocalToWorld( m_barrelPos ); + } + + void UpdateMatrix( void ) + { + m_parentMatrix.InitFromEntity( GetParent() ? GetParent() : NULL ); + } + QAngle AimBarrelAt( const Vector &parentTarget ); + + bool ShouldSavePhysics() { return false; } + + DECLARE_DATADESC(); + + CBaseEntity *FindTarget( string_t targetName, CBaseEntity *pActivator ); + +protected: + float m_yawCenter; // "Center" yaw + float m_yawRate; // Max turn rate to track targets + // Zero is full rotation + float m_yawTolerance; // Tolerance angle + + float m_pitchCenter; // "Center" pitch + float m_pitchRate; // Max turn rate on pitch + float m_pitchTolerance; // Tolerance angle + + float m_minRange; // Minimum range to aim/track + float m_maxRange; // Max range to aim/track + + Vector m_barrelPos; // Length of the barrel + + Vector m_sightOrigin; // Last sight of target + + string_t m_soundStartRotate; + string_t m_soundStopRotate; + string_t m_soundLoopRotate; + + string_t m_targetEntityName; + EHANDLE m_hTarget; + EntityMatrix m_parentMatrix; + + COutputVector m_OnFireAtTarget; + + float m_flFiringDelay; + bool m_bFireDelayed; +}; + +LINK_ENTITY_TO_CLASS( point_apc_controller, CAPCController ); + +BEGIN_DATADESC( CAPCController ) + + DEFINE_FIELD( m_yawCenter, FIELD_FLOAT ), + DEFINE_KEYFIELD( m_yawRate, FIELD_FLOAT, "yawrate" ), + DEFINE_KEYFIELD( m_yawTolerance, FIELD_FLOAT, "yawtolerance" ), + + + DEFINE_FIELD( m_pitchCenter, FIELD_FLOAT ), + DEFINE_KEYFIELD( m_pitchRate, FIELD_FLOAT, "pitchrate" ), + DEFINE_KEYFIELD( m_pitchTolerance, FIELD_FLOAT, "pitchtolerance" ), + + DEFINE_KEYFIELD( m_minRange, FIELD_FLOAT, "minRange" ), + DEFINE_KEYFIELD( m_maxRange, FIELD_FLOAT, "maxRange" ), + DEFINE_FIELD( m_barrelPos, FIELD_VECTOR ), + DEFINE_FIELD( m_sightOrigin, FIELD_VECTOR ), + DEFINE_KEYFIELD( m_soundStartRotate, FIELD_SOUNDNAME, "rotatestartsound" ), + DEFINE_KEYFIELD( m_soundStopRotate, FIELD_SOUNDNAME, "rotatestopsound" ), + DEFINE_KEYFIELD( m_soundLoopRotate, FIELD_SOUNDNAME, "rotatesound" ), + DEFINE_KEYFIELD( m_targetEntityName, FIELD_STRING, "targetentityname" ), + DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ), + DEFINE_FIELD( m_parentMatrix, FIELD_VMATRIX_WORLDSPACE ), + DEFINE_FIELD( m_flFiringDelay, FIELD_FLOAT ), + DEFINE_FIELD( m_bFireDelayed, FIELD_BOOLEAN ), + + // Inputs + DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), + DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ), + + // Outputs + DEFINE_OUTPUT(m_OnFireAtTarget, "OnFireAtTarget"), + +END_DATADESC() + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CAPCController::~CAPCController( void ) +{ + if ( m_soundLoopRotate != NULL_STRING ) + { + StopSound( entindex(), CHAN_STATIC, STRING(m_soundLoopRotate) ); + } +} + +//------------------------------------------------------------------------------ +// Purpose: Input handler for activating the tank. +//------------------------------------------------------------------------------ +void CAPCController::InputActivate( inputdata_t &inputdata ) +{ + ActivateRocketGuidance(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAPCController::ActivateRocketGuidance(void) +{ + m_spawnflags |= SF_TANK_ACTIVE; + SetNextThink( gpGlobals->curtime + 0.1f ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Input handler for deactivating the tank. +//----------------------------------------------------------------------------- +void CAPCController::InputDeactivate( inputdata_t &inputdata ) +{ + DeactivateRocketGuidance(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAPCController::DeactivateRocketGuidance(void) +{ + m_spawnflags &= ~SF_TANK_ACTIVE; + StopRotSound(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : targetName - +// pActivator - +//----------------------------------------------------------------------------- +CBaseEntity *CAPCController::FindTarget( string_t targetName, CBaseEntity *pActivator ) +{ + return gEntList.FindEntityGenericNearest( STRING( targetName ), GetAbsOrigin(), 0, this, pActivator ); +} + +//----------------------------------------------------------------------------- +// Purpose: Caches entity key values until spawn is called. +// Input : szKeyName - +// szValue - +// Output : +//----------------------------------------------------------------------------- +bool CAPCController::KeyValue( const char *szKeyName, const char *szValue ) +{ + if (FStrEq(szKeyName, "barrel")) + { + m_barrelPos.x = atof(szValue); + } + else if (FStrEq(szKeyName, "barrely")) + { + m_barrelPos.y = atof(szValue); + } + else if (FStrEq(szKeyName, "barrelz")) + { + m_barrelPos.z = atof(szValue); + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} + +//----------------------------------------- +// Spawn +//----------------------------------------- +void CAPCController::Spawn( void ) +{ + Precache(); + + m_yawCenter = GetLocalAngles().y; + m_pitchCenter = GetLocalAngles().x; + + if ( IsActive() ) + { + SetNextThink( gpGlobals->curtime + 1.0f ); + } + + UpdateMatrix(); +} + + +//----------------------------------------- +// Precache +//----------------------------------------- +void CAPCController::Precache( void ) +{ + if ( m_soundStartRotate != NULL_STRING ) + PrecacheScriptSound( STRING(m_soundStartRotate) ); + if ( m_soundStopRotate != NULL_STRING ) + PrecacheScriptSound( STRING(m_soundStopRotate) ); + if ( m_soundLoopRotate != NULL_STRING ) + PrecacheScriptSound( STRING(m_soundLoopRotate) ); +} + + +//----------------------------------------- +// InRange +//----------------------------------------- +bool CAPCController::InRange( float range ) +{ + if ( range < m_minRange ) + return FALSE; + if ( m_maxRange > 0 && range > m_maxRange ) + return FALSE; + + return TRUE; +} + + +//----------------------------------------- +// Think +//----------------------------------------- +void CAPCController::Think( void ) +{ + // refresh the matrix + UpdateMatrix(); + + SetLocalAngularVelocity( vec3_angle ); + TrackTarget(); + + if ( fabs(GetLocalAngularVelocity().x) > 1 || fabs(GetLocalAngularVelocity().y) > 1 ) + StartRotSound(); + else + StopRotSound(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Aim the offset barrel at a position in parent space +// Input : parentTarget - the position of the target in parent space +// Output : Vector - angles in local space +//----------------------------------------------------------------------------- +QAngle CAPCController::AimBarrelAt( const Vector &parentTarget ) +{ + Vector target = parentTarget - GetLocalOrigin(); + float quadTarget = target.LengthSqr(); + float quadTargetXY = target.x*target.x + target.y*target.y; + + // We're trying to aim the offset barrel at an arbitrary point. + // To calculate this, I think of the target as being on a sphere with + // it's center at the origin of the gun. + // The rotation we need is the opposite of the rotation that moves the target + // along the surface of that sphere to intersect with the gun's shooting direction + // To calculate that rotation, we simply calculate the intersection of the ray + // coming out of the barrel with the target sphere (that's the new target position) + // and use atan2() to get angles + + // angles from target pos to center + float targetToCenterYaw = atan2( target.y, target.x ); + float centerToGunYaw = atan2( m_barrelPos.y, sqrt( quadTarget - (m_barrelPos.y*m_barrelPos.y) ) ); + + float targetToCenterPitch = atan2( target.z, sqrt( quadTargetXY ) ); + float centerToGunPitch = atan2( -m_barrelPos.z, sqrt( quadTarget - (m_barrelPos.z*m_barrelPos.z) ) ); + return QAngle( -RAD2DEG(targetToCenterPitch+centerToGunPitch), RAD2DEG( targetToCenterYaw + centerToGunYaw ), 0 ); +} + +void CAPCController::TrackTarget( void ) +{ + trace_t tr; + bool updateTime = FALSE, lineOfSight; + QAngle angles; + Vector barrelEnd; + CBaseEntity *pTarget = NULL; + + barrelEnd.Init(); + + if ( IsActive() ) + { + SetNextThink( gpGlobals->curtime + 0.1f ); + } + else + { + return; + } + + // ----------------------------------- + // Get world target position + // ----------------------------------- + barrelEnd = WorldBarrelPosition(); + Vector worldTargetPosition; + CBaseEntity *pEntity = (CBaseEntity *)m_hTarget; + if ( !pEntity || ( pEntity->GetFlags() & FL_NOTARGET ) ) + { + m_hTarget = FindTarget( m_targetEntityName, NULL ); + if ( IsActive() ) + { + SetNextThink( gpGlobals->curtime + 2 ); // Wait 2 sec s + } + + return; + } + pTarget = pEntity; + + // Calculate angle needed to aim at target + worldTargetPosition = pEntity->EyePosition(); + + float range = (worldTargetPosition - barrelEnd).Length(); + + if ( !InRange( range ) ) + { + m_bFireDelayed = false; + return; + } + + UTIL_TraceLine( barrelEnd, worldTargetPosition, MASK_BLOCKLOS, this, COLLISION_GROUP_NONE, &tr ); + + lineOfSight = FALSE; + // No line of sight, don't track + if ( tr.fraction == 1.0 || tr.m_pEnt == pTarget ) + { + lineOfSight = TRUE; + + CBaseEntity *pInstance = pTarget; + if ( InRange( range ) && pInstance && pInstance->IsAlive() ) + { + updateTime = TRUE; + + // Sight position is BodyTarget with no noise (so gun doesn't bob up and down) + m_sightOrigin = pInstance->BodyTarget( GetLocalOrigin(), false ); + } + } + + // Convert targetPosition to parent + angles = AimBarrelAt( m_parentMatrix.WorldToLocal( m_sightOrigin ) ); + + + // Force the angles to be relative to the center position + float offsetY = UTIL_AngleDistance( angles.y, m_yawCenter ); + float offsetX = UTIL_AngleDistance( angles.x, m_pitchCenter ); + angles.y = m_yawCenter + offsetY; + angles.x = m_pitchCenter + offsetX; + + // Move toward target at rate or less + float distY = UTIL_AngleDistance( angles.y, GetLocalAngles().y ); + + QAngle vecAngVel = GetLocalAngularVelocity(); + vecAngVel.y = distY * 10; + vecAngVel.y = clamp( vecAngVel.y, -m_yawRate, m_yawRate ); + + // Move toward target at rate or less + float distX = UTIL_AngleDistance( angles.x, GetLocalAngles().x ); + vecAngVel.x = distX * 10; + vecAngVel.x = clamp( vecAngVel.x, -m_pitchRate, m_pitchRate ); + SetLocalAngularVelocity( vecAngVel ); + + SetMoveDoneTime( 0.1 ); + + Vector forward; + AngleVectors( GetLocalAngles(), &forward ); + forward = m_parentMatrix.ApplyRotation( forward ); + + AngleVectors(angles, &forward); + + if ( lineOfSight == TRUE ) + { + // FIXME: This will ultimately have to deal with NPCs being in the vehicle as well + // See if the target is in a vehicle. If so, check its relationship + CBasePlayer *pPlayer = ToBasePlayer( pTarget ); + if ( pPlayer && pPlayer->IsInAVehicle() ) + { + IServerVehicle *pVehicle = pPlayer->GetVehicle(); + if ( pVehicle->ClassifyPassenger( pPlayer, CLASS_PLAYER ) == CLASS_PLAYER) + { + if ( !m_bFireDelayed ) + { + m_bFireDelayed = true; + m_flFiringDelay = gpGlobals->curtime + 1.5; // setup delay time before we start firing + return; + } + if ( gpGlobals->curtime > m_flFiringDelay ) + { + m_OnFireAtTarget.Set(forward, this, this); // tell apc to fire rockets, and what direction + } + } + } + } + else + { + m_bFireDelayed = false; // reset flag since we can no longer see target + } +} + +void CAPCController::StartRotSound( void ) +{ + if ( m_soundLoopRotate != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + filter.MakeReliable(); + + EmitSound_t ep; + ep.m_nChannel = CHAN_STATIC; + ep.m_pSoundName = (char*)STRING(m_soundLoopRotate); + ep.m_SoundLevel = SNDLVL_NORM; + ep.m_flVolume = 0.85; + + EmitSound( filter, entindex(), ep ); + } + + if ( m_soundStartRotate != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_BODY; + ep.m_pSoundName = (char*)STRING(m_soundStartRotate); + ep.m_SoundLevel = SNDLVL_NORM; + ep.m_flVolume = 1.0f; + + EmitSound( filter, entindex(), ep ); + } +} + + +void CAPCController::StopRotSound( void ) +{ + if ( m_soundLoopRotate != NULL_STRING ) + { + StopSound( entindex(), CHAN_STATIC, (char*)STRING(m_soundLoopRotate) ); + } + if ( m_soundStopRotate != NULL_STRING ) + { + CPASAttenuationFilter filter( this ); + + EmitSound_t ep; + ep.m_nChannel = CHAN_BODY; + ep.m_pSoundName = (char*)STRING(m_soundStopRotate); + ep.m_SoundLevel = SNDLVL_NORM; + + EmitSound( filter, entindex(), ep ); + } +} + -- cgit v1.2.3