summaryrefslogtreecommitdiff
path: root/game/shared/tf2/basetfvehicle.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf2/basetfvehicle.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf2/basetfvehicle.cpp')
-rw-r--r--game/shared/tf2/basetfvehicle.cpp1179
1 files changed, 1179 insertions, 0 deletions
diff --git a/game/shared/tf2/basetfvehicle.cpp b/game/shared/tf2/basetfvehicle.cpp
new file mode 100644
index 0000000..1825753
--- /dev/null
+++ b/game/shared/tf2/basetfvehicle.cpp
@@ -0,0 +1,1179 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A base vehicle class
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "basetfvehicle.h"
+#include "tf_movedata.h"
+#include "in_buttons.h"
+#include "baseplayer_shared.h"
+
+#if defined( CLIENT_DLL )
+ #include "hud_vehicle_role.h"
+ #include "hud.h"
+ #include "hud_crosshair.h"
+#else
+ #include "tf_team.h"
+ #include "tf_gamerules.h"
+ #include "tf_func_construction_yard.h"
+ #include "ndebugoverlay.h"
+#endif
+
+IMPLEMENT_NETWORKCLASS_ALIASED( BaseTFVehicle, DT_BaseTFVehicle );
+
+BEGIN_NETWORK_TABLE( CBaseTFVehicle, DT_BaseTFVehicle )
+#if !defined( CLIENT_DLL )
+ SendPropInt( SENDINFO(m_nMaxPassengers), CBaseTFVehicle::MAX_PASSENGER_BITS, SPROP_UNSIGNED ),
+ SendPropArray( SendPropEHandle(SENDINFO_ARRAY(m_hPassengers)), m_hPassengers ),
+ SendPropEHandle( SENDINFO(m_hDriverGun) ),
+#else
+ RecvPropInt( RECVINFO(m_nMaxPassengers) ),
+ RecvPropArray( RecvPropEHandle(RECVINFO(m_hPassengers[0])), m_hPassengers ),
+ RecvPropEHandle( RECVINFO(m_hDriverGun) ),
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CBaseTFVehicle )
+
+ DEFINE_PRED_ARRAY( m_hPassengers, FIELD_EHANDLE, CBaseTFVehicle::MAX_PASSENGERS, FTYPEDESC_INSENDTABLE ),
+
+END_PREDICTION_DATA()
+
+extern float RemapAngleRange( float startInterval, float endInterval, float value );
+extern ConVar road_feel;
+
+ConVar vehicle_view_offset_forward( "vehicle_view_offset_forward", "-280", FCVAR_REPLICATED );
+ConVar vehicle_view_offset_right( "vehicle_view_offset_right", "0", FCVAR_REPLICATED );
+ConVar vehicle_view_offset_up( "vehicle_view_offset_up", "50", FCVAR_REPLICATED );
+ConVar vehicle_thirdperson( "vehicle_thirdperson", "1", FCVAR_REPLICATED, "Enable/disable thirdperson camera view in vehicles" );
+
+ConVar vehicle_attach_eye_angles( "vehicle_attach_eye_angles", "0", FCVAR_REPLICATED, "Attach player eye angles to vehicle attachments" );
+
+#define PITCH_CURVE_ZERO 10 // pitch less than this is clamped to zero
+#define PITCH_CURVE_LINEAR 45 // pitch greater than this is copied out
+
+#define ROLL_CURVE_ZERO 5 // roll less than this is clamped to zero
+#define ROLL_CURVE_LINEAR 45 // roll greater than this is copied out
+
+#if defined( CLIENT_DLL )
+ ConVar road_feel( "road_feel", "0.1", FCVAR_NOTIFY | FCVAR_REPLICATED );
+#else
+ // Deterioration
+ #define DETERIORATION_THINK_CONTEXT "VehicleDeteriorationThink"
+ #define PASSENGER_THINK_CONTEXT "VehiclePassengerThink"
+ ConVar vehicle_deterioration_start_time( "vehicle_deterioration_start_time", "90", 0, "Time it takes for a vehicle to start deteriorating after being left alone." );
+
+ #define DETERIORATION_DISTANCE (600 * 600) // Never deteriorate if team mates are within this distance
+
+#endif // CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBaseTFVehicle::CBaseTFVehicle()
+{
+ SetPredictionEligible( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::Spawn()
+{
+ BaseClass::Spawn();
+ CollisionProp()->SetSurroundingBoundsType( USE_OBB_COLLISION_BOUNDS );
+
+#if defined( CLIENT_DLL )
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+ m_pIconDefaultCrosshair = NULL;
+#else
+ m_fObjectFlags |= OF_DOESNT_NEED_POWER | OF_MUST_BE_BUILT_ON_ATTACHMENT;
+ SetContextThink( VehiclePassengerThink, 2.0, PASSENGER_THINK_CONTEXT );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Vehicle overrides
+//-----------------------------------------------------------------------------
+CBaseEntity* CBaseTFVehicle::GetVehicleEnt()
+{
+ return this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
+{
+ // animate + update attachment points
+#ifdef CLIENT_DLL
+ StudioFrameAdvance();
+#else
+ StudioFrameAdvance();
+ // This calls StudioFrameAdvance, then we use the results from that to determine where to move.
+ DispatchAnimEvents( this );
+#endif
+
+ CTFMoveData *pMoveData = (CTFMoveData*)move;
+ Assert( sizeof(VehicleBaseMoveData_t) <= pMoveData->VehicleDataMaxSize() );
+
+ VehicleBaseMoveData_t *pVehicleData = (VehicleBaseMoveData_t*)pMoveData->VehicleData();
+ pVehicleData->m_pVehicle = this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move )
+{
+ VehicleDriverGunThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the driver as a tfplayer pointer
+//-----------------------------------------------------------------------------
+CBaseTFPlayer *CBaseTFVehicle::GetDriverPlayer()
+{
+ return m_hPassengers[VEHICLE_DRIVER].Get();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Can we get into the vehicle?
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::CanGetInVehicle( CBaseTFPlayer *pPlayer )
+{
+ if ( !IsPowered() )
+ return false;
+
+ if ( !InSameTeam( pPlayer ) )
+ return false;
+
+ // Player/Class-specific query.
+ return pPlayer->CanGetInVehicle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Here's where we deal with weapons
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::OnItemPostFrame( CBaseTFPlayer *pDriver )
+{
+ // If we have a gun for the driver, handle it
+ if ( m_hDriverGun )
+ {
+ if ( GetPassengerRole(pDriver) != VEHICLE_DRIVER )
+ return;
+
+ if ( pDriver->m_nButtons & (IN_ATTACK | IN_ATTACK2) )
+ {
+ // Time to fire?
+ if ( m_hDriverGun->CanFireNow() )
+ {
+ m_hDriverGun->Fire( pDriver );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetPassengerRole( CBasePlayer *pEnt )
+{
+ Assert( pEnt->IsPlayer() );
+ for ( int i = m_nMaxPassengers; --i >= 0; )
+ {
+ if (m_hPassengers[i] == pEnt)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+Vector CBaseTFVehicle::GetSoundEmissionOrigin() const
+{
+ return WorldSpaceCenter() + Vector( 0, 0, 64 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBasePlayer* CBaseTFVehicle::GetPassenger( int nRole )
+{
+ return m_hPassengers[nRole].Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Is a particular player in the vehicle?
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::IsPlayerInVehicle( CBaseTFPlayer *pPlayer )
+{
+ return (GetPassengerRole( pPlayer ) >= 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetPassengerCount() const
+{
+ // FIXME: Cache this off!
+ int nCount = 0;
+ for (int i = m_nMaxPassengers; --i >= 0; )
+ {
+ if (m_hPassengers[i].Get())
+ {
+ ++nCount;
+ }
+ }
+ return nCount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetMaxPassengerCount() const
+{
+ return m_nMaxPassengers;
+}
+
+//-----------------------------------------------------------------------------
+// Process input
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::ItemPostFrame( CBasePlayer *pPassenger )
+{
+#ifndef CLIENT_DLL
+ Assert( GetPassengerRole( pPassenger ) != -1 );
+ if (pPassenger->m_afButtonPressed & (IN_USE /*| IN_JUMP*/))
+ {
+ // Get the player out..
+ pPassenger->LeaveVehicle();
+ return;
+ }
+#endif
+
+ OnItemPostFrame( static_cast<CBaseTFPlayer*>(pPassenger) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reset the time before this vehicle begins to deteriorate
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::ResetDeteriorationTime( void )
+{
+#if !defined (CLIENT_DLL)
+ SetContextThink( VehicleDeteriorationThink, gpGlobals->curtime + vehicle_deterioration_start_time.GetFloat(), DETERIORATION_THINK_CONTEXT );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Prevent driving in construction yards
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::IsReadyToDrive( void )
+{
+#if !defined( CLIENT_DLL )
+ return ( PointInConstructionYard( GetAbsOrigin() ) == false );
+#else
+ return true;
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Process input
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::SetMaxPassengerCount( int nCount )
+{
+#if !defined( CLIENT_DLL )
+ Assert( (nCount >= 1) && (nCount <= MAX_PASSENGERS) );
+ m_nMaxPassengers = nCount;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+//
+// Server-only code here
+//
+//-----------------------------------------------------------------------------
+
+#if !defined (CLIENT_DLL)
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::FinishedBuilding( void )
+{
+ BaseClass::FinishedBuilding();
+
+ // See if we've finished building on a vehicle that has a passenger slot assigned to my buildpoint.
+ CBaseObject *pParent = GetParentObject();
+ if ( pParent && pParent->IsAVehicle() )
+ {
+ CBaseTFVehicle *pVehicle = static_cast<CBaseTFVehicle*>(pParent);
+ int iRole = pVehicle->GetChildVehicleRole( this );
+ if ( iRole != -1 )
+ {
+ // Is there a player in the role assigned to this buildpoint?
+ CBaseTFPlayer *pExistingPlayer = static_cast<CBaseTFPlayer*>( pVehicle->GetPassenger( iRole ) );
+ if ( pExistingPlayer )
+ {
+ // Remove the player from my parent vehicle and put them in me
+ pExistingPlayer->LeaveVehicle();
+
+ // Get in the vehicle.
+ pExistingPlayer->GetInVehicle( this, VEHICLE_DRIVER );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::VehicleDeteriorationThink( void )
+{
+ StartDeteriorating();
+
+ SetContextThink( NULL, gpGlobals->curtime + vehicle_deterioration_start_time.GetFloat(), DETERIORATION_THINK_CONTEXT );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::VehiclePassengerThink( void )
+{
+ SetNextThink( gpGlobals->curtime + 10.0, PASSENGER_THINK_CONTEXT );
+
+ if ( IsPlacing() )
+ {
+ ResetDeteriorationTime();
+ return;
+ }
+
+ // If there are any passengers in the vehicle, push off deterioration time
+ if ( GetPassengerCount() )
+ {
+ ResetDeteriorationTime();
+ return;
+ }
+
+ // See if there are any team members nearby
+ if ( GetTeam() )
+ {
+ int iNumPlayers = GetTFTeam()->GetNumPlayers();
+ for ( int i = 0; i < iNumPlayers; i++ )
+ {
+ if ( GetTFTeam()->GetPlayer(i) )
+ {
+ Vector vecOrigin = GetTFTeam()->GetPlayer(i)->GetAbsOrigin();
+ if ( (vecOrigin - GetAbsOrigin()).LengthSqr() < DETERIORATION_DISTANCE )
+ {
+ // Found one nearby, reset our deterioration time
+ ResetDeteriorationTime();
+ return;
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Figure out which role of a vehicle a child vehicle is sitting in..
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetChildVehicleRole( CBaseTFVehicle *pChild )
+{
+ int nBuildPoints = GetNumBuildPoints();
+ for( int i = 0; i < nBuildPoints; i++ )
+ {
+ CBaseObject* pObject = GetBuildPointObject(i);
+ if (pObject == pChild)
+ {
+ return GetBuildPointPassenger(i);
+ }
+ }
+
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Vehicles are permanently oriented off angle for vphysics.
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
+{
+ // This call is necessary to cause m_rgflCoordinateFrame to be recomputed
+ const matrix3x4_t &entityToWorld = EntityToWorldTransform();
+
+ if (pForward != NULL)
+ {
+ MatrixGetColumn( entityToWorld, 1, *pForward );
+ }
+
+ if (pRight != NULL)
+ {
+ MatrixGetColumn( entityToWorld, 0, *pRight );
+ }
+
+ if (pUp != NULL)
+ {
+ MatrixGetColumn( entityToWorld, 2, *pUp );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get into the vehicle
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ BaseClass::Use( pActivator, pCaller, useType, value );
+
+ if ( useType == USE_ON )
+ {
+ CBaseTFPlayer *pPlayer = dynamic_cast<CBaseTFPlayer*>(pActivator);
+ if ( pPlayer && InSameTeam(pPlayer) )
+ {
+ // Check to see if we are really using nearby build points:
+ if( !UseAttachedItem( pActivator, pCaller, useType, value ) )
+ {
+ // Attempt to board the vehicle:
+ AttemptToBoardVehicle( pPlayer );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Figure out if I should be using an attached item rather than this vehicle itself.
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::UseAttachedItem( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ CBaseTFPlayer* pPlayer = dynamic_cast<CBaseTFPlayer*>(pActivator);
+ if ( !pPlayer || !InSameTeam(pPlayer) )
+ return false;
+
+ Vector vecPlayerOrigin = pPlayer->GetAbsOrigin();
+ int nBestBuildPoint = -1;
+ float fBestDistance = FLT_MAX;
+
+ // Get the closest regular entry point:
+ int nRole = LocateEntryPoint( pPlayer, &fBestDistance );
+
+ // Iterate through each of the build points, if any, and see which we are closest to.
+ int nBuildPoints = GetNumBuildPoints();
+ for( int i = 0; i < nBuildPoints; i++ )
+ {
+ CBaseObject* pObject = GetBuildPointObject(i);
+
+ // If there's something in the build point that isn't in the process of being built or placed:
+ if( pObject && !pObject->IsPlacing() && !pObject->IsBuilding() )
+ {
+ Vector vecOrigin;
+ QAngle vecAngles;
+
+ // If the build point is the default point for this role, just take it
+ if (GetBuildPointPassenger(i) == nRole)
+ {
+ nBestBuildPoint = i;
+ break;
+ }
+
+ // And I can get the build point.
+ if( GetBuildPoint( i, vecOrigin, vecAngles ) )
+ {
+ float fLength2dSqr = (vecOrigin - vecPlayerOrigin).AsVector2D().LengthSqr();
+ if( fLength2dSqr < fBestDistance )
+ {
+ nBestBuildPoint = i;
+ fBestDistance = fLength2dSqr;
+ }
+ }
+ }
+ }
+
+ if( nBestBuildPoint >= 0 )
+ {
+ // They're using an item on me, so push out the deterioration time
+ ResetDeteriorationTime();
+ GetBuildPointObject(nBestBuildPoint)->Use( pActivator, pCaller, useType, value );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Object has been removed...
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::DestroyObject( void )
+{
+ for (int i = m_nMaxPassengers; --i >= 0; )
+ {
+ if (m_hPassengers[i])
+ {
+ m_hPassengers[i]->LeaveVehicle();
+ }
+ }
+
+ BaseClass::DestroyObject();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetEmptyRole( void )
+{
+ for ( int iPassenger = 0; iPassenger < m_nMaxPassengers; ++iPassenger )
+ {
+ if ( !m_hPassengers[iPassenger].Get() )
+ return iPassenger;
+ }
+
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Try to board the vehicle
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::AttemptToBoardVehicle( CBaseTFPlayer *pPlayer )
+{
+ if ( !CanGetInVehicle( pPlayer ) )
+ return;
+
+ // Locate the entry point.
+ int nRole = LocateEntryPoint( pPlayer );
+ if ( nRole != -1 )
+ {
+ // Set the owner flag.
+ bool bOwner = ( pPlayer == GetOwner() );
+ if ( bOwner )
+ {
+ // Check to see if a player exists at this location (role).
+ CBaseTFPlayer *pExistingPlayer = static_cast<CBaseTFPlayer*>( GetPassenger( nRole ) );
+ if ( pExistingPlayer )
+ {
+ pExistingPlayer->LeaveVehicle();
+
+ // Get in the vehicle.
+ pPlayer->GetInVehicle( this, nRole );
+
+ // Then see if we can move the other player to another slot in this vehicle
+ int nEmptyRole = GetEmptyRole();
+ if ( nEmptyRole != -1 )
+ {
+ pExistingPlayer->GetInVehicle( this, nEmptyRole );
+ }
+ return;
+ }
+ }
+
+ // Get in the vehicle.
+ pPlayer->GetInVehicle( this, nRole );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle commands sent from vgui panels on the client
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::ClientCommand( CBaseTFPlayer *pPlayer, const CCommand &args )
+{
+ ResetDeteriorationTime();
+
+ if ( FStrEq( pCmd, "toggle_use" ) )
+ {
+ AttemptToBoardVehicle( pPlayer );
+ return true;
+ }
+
+ return BaseClass::ClientCommand( pPlayer, args );
+}
+
+//-----------------------------------------------------------------------------
+// Get a position in *world space* inside the vehicle for the player to exit at
+// NOTE: This doesn't check for obstructions
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::GetInitialPassengerExitPoint( int nRole, Vector *pAbsPoint, QAngle *pAbsAngles )
+{
+ char pAttachmentName[32];
+ Q_snprintf( pAttachmentName, sizeof( pAttachmentName ), "vehicle_exit_passenger%d", nRole );
+ int exitAttachmentIndex = LookupAttachment(pAttachmentName);
+ if (exitAttachmentIndex <= 0)
+ {
+ // bad attachment, just return the origin
+ *pAbsPoint = GetAbsOrigin();
+ pAbsPoint->z += WorldAlignMaxs()[2] + 50.0f;
+ return;
+ }
+
+ QAngle vehicleExitAngles;
+ if( !pAbsAngles )
+ {
+ pAbsAngles = &vehicleExitAngles;
+ }
+
+ GetAttachment( exitAttachmentIndex, *pAbsPoint, *pAbsAngles );
+}
+
+
+//-----------------------------------------------------------------------------
+// Get a point to leave the vehicle from
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::IsValidExitPoint( int nRole, Vector *pExitPoint, QAngle *pAngles )
+{
+ GetInitialPassengerExitPoint( nRole, pExitPoint, pAngles );
+
+ // Check the exit point:
+ Vector vecStart = *pExitPoint;
+ Vector vecEnd = *pExitPoint + Vector(0,0,20);
+ trace_t tr;
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
+ if ( (tr.fraction < 1.f) )
+ return false;
+
+ vecEnd = *pExitPoint + Vector(20,20,20);
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
+ if ( (tr.fraction < 1.f) )
+ return false;
+
+ vecEnd = *pExitPoint + Vector(-20,-20,20);
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
+ if ( (tr.fraction < 1.f) )
+ return false;
+
+ vecEnd = *pExitPoint + Vector(20,-20,20);
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
+ if ( (tr.fraction < 1.f) )
+ return false;
+
+ vecEnd = *pExitPoint + Vector(-20,20,20);
+ UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
+ if ( (tr.fraction < 1.f) )
+ return false;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::GetPassengerExitPoint( CBasePlayer *pPlayer, int nRole, Vector *pAbsPosition, QAngle *pAbsAngles )
+{
+
+ // Deal with vehicles built on other vehicles
+ CBaseTFVehicle *pParentVehicle = dynamic_cast<CBaseTFVehicle*>(GetMoveParent());
+ if (pParentVehicle)
+ {
+ int nParentVehicleRole = pParentVehicle->GetChildVehicleRole( this );
+ if (nParentVehicleRole >= 0)
+ {
+ pParentVehicle->GetPassengerExitPoint( pPlayer, nParentVehicleRole, pAbsPosition, pAbsAngles );
+ return;
+ }
+ }
+
+ // Deal with vehicles build on objects
+ IHasBuildPoints *pMount = dynamic_cast<IHasBuildPoints*>(GetMoveParent());
+ if (pMount)
+ {
+ int nBuildPoint = pMount->FindObjectOnBuildPoint( this );
+ if (nBuildPoint >= 0)
+ {
+ pMount->GetExitPoint( pPlayer, nBuildPoint, pAbsPosition, pAbsAngles );
+ return;
+ }
+ }
+
+ Vector vNewPos;
+ GetInitialPassengerExitPoint( nRole, pAbsPosition, pAbsAngles );
+ if ( EntityPlacementTest(pPlayer, *pAbsPosition, vNewPos, true) )
+ {
+ *pAbsPosition = vNewPos;
+ return;
+ }
+
+ // Find the first valid exit point
+ for( int iExitPoint = 0; iExitPoint < m_nMaxPassengers; ++iExitPoint )
+ {
+ if (iExitPoint == nRole)
+ continue;
+
+ GetInitialPassengerExitPoint( iExitPoint, pAbsPosition, pAbsAngles );
+ if ( EntityPlacementTest(pPlayer, *pAbsPosition, vNewPos, true) )
+ {
+ *pAbsPosition = vNewPos;
+ return;
+ }
+ }
+
+ // Worst case, we will be returning the vehicle's origin + 50z here
+ *pAbsPosition = GetAbsOrigin();
+ pAbsPosition->z = WorldAlignMaxs()[2] + 150.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::GetPassengerExitPoint( int nRole, Vector *pAbsPosition, QAngle *pAbsAngles )
+{
+ // FIXME: Clean this up
+ CBasePlayer *pPlayer = GetPassenger(nRole);
+ GetPassengerExitPoint( pPlayer, nRole, pAbsPosition, pAbsAngles );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetEntryAnimForPoint( const Vector &vecPoint )
+{
+ return ACTIVITY_NOT_AVAILABLE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBaseTFVehicle::GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked )
+{
+ bAllPointsBlocked = false;
+ return ACTIVITY_NOT_AVAILABLE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::HandleEntryExitFinish( bool bExitAnimOn, bool bResetAnim )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPlayer -
+// false -
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::HandlePassengerEntry( CBasePlayer *pPlayer, bool bAllowEntryOutsideZone )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPlayer -
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::HandlePassengerExit( CBasePlayer *pPlayer )
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get and set the current driver.
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::SetPassenger( int nRole, CBasePlayer *pEnt )
+{
+ Assert( !pEnt || pEnt->IsPlayer() );
+ Assert( nRole >= 0 && nRole < m_nMaxPassengers );
+ Assert( !m_hPassengers[nRole].Get() || !pEnt );
+ m_hPassengers.Set( nRole, dynamic_cast<CBaseTFPlayer*>(pEnt) );
+
+ // If the vehicle's deteriorating, I get to own it now
+ if ( IsDeteriorating() )
+ {
+ StopDeteriorating();
+ SetBuilder( (CBaseTFPlayer*)pEnt, true );
+ }
+
+ ResetDeteriorationTime();
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Get a position in *world space* inside the vehicle for the player to start at
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::GetPassengerStartPoint( int nRole, Vector *pAbsPoint, QAngle *pAbsAngles )
+{
+ char pAttachmentName[32];
+ Q_snprintf( pAttachmentName, sizeof( pAttachmentName ), "vehicle_feet_passenger%d", nRole );
+ int nFeetAttachmentIndex = LookupAttachment(pAttachmentName);
+ GetAttachment( nFeetAttachmentIndex, *pAbsPoint, *pAbsAngles );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+#define INITIAL_MAX_DISTANCE 999999.0f
+
+int CBaseTFVehicle::LocateEntryPoint( CBaseTFPlayer *pPlayer, float* fBest2dDistanceSqr )
+{
+ // Get the players origin and compare it to all the entry points on the
+ // vehicle.
+ Vector vecPlayerPos = pPlayer->GetAbsOrigin();
+ Vector vecEntryPos;
+ QAngle vecEntryAngle;
+
+ int iMinEntry = -1;
+ float flMinDistance2 = INITIAL_MAX_DISTANCE;
+
+ // Is the player the owner of the vehicle?
+ bool bOwner = ( pPlayer == GetOwner() );
+
+ char szPassengerEyes[32];
+ for( int iEntryPoint = 0; iEntryPoint < m_nMaxPassengers; ++iEntryPoint )
+ {
+ // If not the owner, check to see if the entry point is available. The
+ // entry point is always available for the owner.
+ bool bOccupied = ( GetPassenger( iEntryPoint ) != NULL );
+
+ // Also check for child vehicles...
+
+ if ( bOccupied && !bOwner )
+ continue;
+
+ // FIXME: Cache off the entry point
+ Q_snprintf( szPassengerEyes, sizeof( szPassengerEyes ), "vehicle_feet_passenger%d", iEntryPoint );
+ int nAttachmentIndex = LookupAttachment( szPassengerEyes );
+
+ float flDistance2;
+ if (nAttachmentIndex > 0)
+ {
+ GetAttachment( nAttachmentIndex, vecEntryPos, vecEntryAngle );
+ Vector vecDelta = vecEntryPos - vecPlayerPos;
+ flDistance2 = vecDelta.AsVector2D().LengthSqr();
+ }
+ else
+ {
+ // No attachment? Choose it if we must as a last resort
+ flDistance2 = INITIAL_MAX_DISTANCE - 1;
+ }
+
+ if ( flDistance2 < flMinDistance2 )
+ {
+ flMinDistance2 = flDistance2;
+ iMinEntry = iEntryPoint;
+ }
+ }
+
+ if( fBest2dDistanceSqr )
+ {
+ *fBest2dDistanceSqr = flMinDistance2;
+ }
+ return iMinEntry;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set a gun that the driver can control
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::SetDriverGun( CBaseObjectDriverGun *pGun )
+{
+ m_hDriverGun = pGun;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update the driver's gun
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::VehicleDriverGunThink( void )
+{
+ if ( !m_hDriverGun )
+ return;
+
+ // No driver?
+ CBaseTFPlayer *pDriver = GetDriverPlayer();
+ if ( !pDriver )
+ return;
+
+ QAngle vecTargetAngles = m_hDriverGun->GetCurrentAngles();
+
+ // Cast a ray out of the view to see where the player is looking.
+ trace_t trace;
+ Vector vecForward;
+ Vector vecSrc;
+ QAngle angEyeAngles;
+ GetVehicleViewPosition( VEHICLE_DRIVER, &vecSrc, &angEyeAngles, NULL );
+ AngleVectors( angEyeAngles, &vecForward, NULL, NULL );
+ Vector vecEnd = vecSrc + (vecForward * 10000);
+ UTIL_TraceLine( vecSrc, vecEnd, MASK_OPAQUE, this, COLLISION_GROUP_NONE, &trace );
+
+ //NDebugOverlay::Box( vecSrc, -Vector(10,10,10), Vector(10,10,10), 255,0,0,8, 5 );
+ //NDebugOverlay::Box( vecEnd, -Vector(10,10,10), Vector(10,10,10), 0,255,0,8, 5 );
+ //NDebugOverlay::Box( trace.endpos, -Vector(10,10,10), Vector(10,10,10), 255,255,255,8, 0.1 );
+
+ if ( trace.fraction < 1 )
+ {
+ // Figure out what angles our turret needs to be at in order to hit the target.
+ Vector vFireOrigin = m_hDriverGun->GetFireOrigin();
+
+ //NDebugOverlay::Box( vFireOrigin, -Vector(10,10,10), Vector(10,10,10), 0,255,0,8, 0.1 );
+
+ // Get a direction vector that points at the target.
+ Vector vTo = trace.endpos - vFireOrigin;
+
+ // Transform it into the tank's local space.
+ matrix3x4_t tankToWorld;
+ AngleMatrix( GetAbsAngles(), tankToWorld );
+
+ Vector vLocalTo;
+ VectorITransform( vTo, tankToWorld, vLocalTo );
+
+ // Now figure out what the angles are in local space.
+ QAngle localAngles;
+ VectorAngles( vLocalTo, localAngles );
+
+ vecTargetAngles[YAW] = localAngles[YAW] - 90;
+ vecTargetAngles[PITCH] = anglemod( localAngles[PITCH] );
+ }
+
+ // Set the gun's angles
+ m_hDriverGun->SetTargetAngles( vecTargetAngles );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::ShouldUseThirdPersonVehicleView()
+{
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Returns the unperterbed view position for a particular role
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::GetRoleViewPosition( int nRole, Vector *pVehicleEyeOrigin, QAngle *pVehicleEyeAngles )
+{
+ // Generate the view position in world space.
+ Vector vAbsOrigin;
+ QAngle vAbsAngle;
+ bool bUsingThirdPersonCamera = GetRoleAbsViewPosition( nRole, &vAbsOrigin, &vAbsAngle );
+
+
+ // Make a matrix for it.
+ matrix3x4_t absMatrix;
+ AngleMatrix( vAbsAngle, absMatrix );
+ MatrixSetColumn( vAbsOrigin, 3, absMatrix );
+
+
+ // Transform the matrix into local space.
+ matrix3x4_t worldToEntity, local;
+ MatrixInvert( EntityToWorldTransform(), worldToEntity );
+ ConcatTransforms( worldToEntity, absMatrix, local );
+
+
+ // Suck out the origin and angles.
+ pVehicleEyeOrigin->Init( local[0][3], local[1][3], local[2][3] );
+ MatrixAngles( local, *pVehicleEyeAngles );
+
+ return bUsingThirdPersonCamera;
+}
+
+bool CBaseTFVehicle::GetRoleAbsViewPosition( int nRole, Vector *pAbsVehicleEyeOrigin, QAngle *pAbsVehicleEyeAngles )
+{
+ int iAttachment = LookupAttachment( "ThirdPersonCameraOrigin" );
+ if ( ShouldUseThirdPersonVehicleView() && vehicle_thirdperson.GetInt() && nRole == VEHICLE_DRIVER && iAttachment > 0 )
+ {
+ // Ok, we're using third person. Leave their angles intact but rotate theirt view around the
+ // ThirdPersonCameraOrigin attachment.
+ Vector vAttachOrigin;
+ QAngle vAttachAngles;
+ GetAttachment( iAttachment, vAttachOrigin, vAttachAngles );
+
+ Vector vForward, vRight, vUp;
+ AngleVectors( *pAbsVehicleEyeAngles, &vForward, &vRight, &vUp );
+
+ *pAbsVehicleEyeOrigin = vAttachOrigin + vForward * vehicle_view_offset_forward.GetFloat() +
+ vRight * vehicle_view_offset_right.GetFloat() +
+ vUp * vehicle_view_offset_up.GetFloat();
+
+ // Returning true tells the caller that we're using a third-person camera origin.
+ return true;
+ }
+ else
+ {
+ // Use the vehicle_eyes_passengerX attachments.
+ Assert( nRole >= 0 );
+ char pAttachmentName[32];
+ Q_snprintf( pAttachmentName, sizeof( pAttachmentName ), "vehicle_eyes_passenger%d", nRole );
+ int eyeAttachmentIndex = LookupAttachment(pAttachmentName);
+
+ QAngle vTempAngles;
+ GetAttachment( eyeAttachmentIndex, *pAbsVehicleEyeOrigin, vTempAngles );
+
+ if ( vehicle_attach_eye_angles.GetInt() )
+ *pAbsVehicleEyeAngles = vTempAngles;
+
+ return false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Modify the player view/camera while in a vehicle
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*= NULL*/ )
+{
+ // UNDONE: Use attachment point on the vehicle, not hardcoded player eyes
+ Assert( nRole >= 0 );
+ CBasePlayer *pPlayer = GetPassenger( nRole );
+ Assert( pPlayer );
+
+ Vector vehicleEyeOrigin;
+ QAngle vehicleEyeAngles = pPlayer->LocalEyeAngles();
+
+ GetRoleAbsViewPosition( nRole, &vehicleEyeOrigin, &vehicleEyeAngles );
+
+ *pAbsOrigin = vehicleEyeOrigin;
+ *pAbsAngles = vehicleEyeAngles;
+
+ /*
+ if ( bUsingThirdPersonCamera )
+ {
+ *pAbsOrigin = vehicleEyeOrigin;
+ *pAbsAngles = vehicleEyeAngles;
+ }
+ else
+ {
+ matrix3x4_t vehicleEyePosToWorld;
+
+ AngleMatrix( vehicleEyeAngles, vehicleEyePosToWorld );
+
+ // Compute the relative rotation between the unperterbed eye attachment + the eye angles
+ matrix3x4_t cameraToWorld;
+ AngleMatrix( *pAbsAngles, cameraToWorld );
+
+ matrix3x4_t worldToEyePos;
+ MatrixInvert( vehicleEyePosToWorld, worldToEyePos );
+
+ matrix3x4_t vehicleCameraToEyePos;
+ ConcatTransforms( worldToEyePos, cameraToWorld, vehicleCameraToEyePos );
+
+ // Now perterb the attachment point
+ if( inv_demo.GetInt() )
+ {
+ vehicleEyeAngles.x = RemapAngleRange( PITCH_CURVE_ZERO * road_feel.GetFloat(), PITCH_CURVE_LINEAR, vehicleEyeAngles.x );
+ vehicleEyeAngles.z = RemapAngleRange( ROLL_CURVE_ZERO * road_feel.GetFloat(), ROLL_CURVE_LINEAR, vehicleEyeAngles.z );
+ }
+ else
+ {
+ vehicleEyeAngles.x = RemapAngleRange( PITCH_CURVE_ZERO, PITCH_CURVE_LINEAR, vehicleEyeAngles.x );
+ vehicleEyeAngles.z = RemapAngleRange( ROLL_CURVE_ZERO, ROLL_CURVE_LINEAR, vehicleEyeAngles.z );
+ }
+
+ AngleMatrix( vehicleEyeAngles, vehicleEyeOrigin, vehicleEyePosToWorld );
+
+ // Now treat the relative eye angles as being relative to this new, perterbed view position...
+ matrix3x4_t newCameraToWorld;
+ ConcatTransforms( vehicleEyePosToWorld, vehicleCameraToEyePos, newCameraToWorld );
+
+ // output new view abs angles
+ MatrixAngles( newCameraToWorld, *pAbsAngles );
+
+ // UNDONE: *pOrigin would already be correct in single player if the HandleView() on the server ran after vphysics
+ MatrixGetColumn( newCameraToWorld, 3, *pAbsOrigin );
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Client-only code here
+//
+//-----------------------------------------------------------------------------
+
+#if defined (CLIENT_DLL)
+
+void CBaseTFVehicle::ClientThink()
+{
+ BaseClass::ClientThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CBaseTFVehicle::ShouldPredict( void )
+{
+ // Only predict vehicles driven by local players
+ return GetDriverPlayer() ? GetDriverPlayer()->IsLocalPlayer() : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get the angles that a player in the specified role should be using for visuals
+//-----------------------------------------------------------------------------
+QAngle CBaseTFVehicle::GetPassengerAngles( QAngle angCurrent, int nRole )
+{
+ // Just use your current angles
+ return angCurrent;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::DrawHudElements( void )
+{
+ // If we've got a driver gun, tell it to draw it's elements
+ if ( m_hDriverGun )
+ {
+ m_hDriverGun->DrawHudElements();
+ }
+
+ DrawHudBoostData();
+ SetupCrosshair();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::DrawHudBoostData( void )
+{
+#define HUD_IMAGE_LEFT XRES( 568 )
+
+ // Boostable vehicle
+ if ( IsBoostable() )
+ {
+ // Set our color
+ CHudTexture *pVehicleBoostLabel = gHUD.GetIcon( "no2" );
+ if ( pVehicleBoostLabel )
+ {
+ int nScreenY = ScreenHeight() - YRES( 12 );
+ float nOneHudHeight = ( YRES(10) + pVehicleBoostLabel->Height() );
+ nScreenY -= ( nOneHudHeight * 3 );
+
+ pVehicleBoostLabel->DrawSelf( HUD_IMAGE_LEFT, nScreenY - pVehicleBoostLabel->Height(), gHUD.m_clrNormal );
+ gHUD.DrawProgressBar( HUD_IMAGE_LEFT, nScreenY + YRES( 4 ), XRES( 70 ), YRES( 4 ), m_nBoostTimeLeft / 100.0f, gHUD.m_clrNormal, CHud::HUDPB_HORIZONTAL_INV );
+ }
+ }
+
+#undef HUD_IMAGE_LEFT
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set a crosshair when in a vehicle and we don't have a proper
+// crosshair sprite (ie. a commando laser rifle).
+//-----------------------------------------------------------------------------
+void CBaseTFVehicle::SetupCrosshair( void )
+{
+ if ( !m_pIconDefaultCrosshair )
+ {
+ // Init the default crosshair the first time.
+ CHudTexture newTexture;
+ Q_strncpy( newTexture.szTextureFile, "sprites/crosshairs", sizeof( newTexture.szTextureFile ) );
+
+ newTexture.rc.left = 0;
+ newTexture.rc.top = 48;
+ newTexture.rc.right = newTexture.rc.left + 24;
+ newTexture.rc.bottom = newTexture.rc.top + 24;
+ m_pIconDefaultCrosshair = gHUD.AddUnsearchableHudIconToList( newTexture );
+ }
+
+ CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
+ if ( crosshair )
+ {
+ if ( !crosshair->HasCrosshair() && m_pIconDefaultCrosshair )
+ {
+ crosshair->SetCrosshair( m_pIconDefaultCrosshair, gHUD.m_clrNormal );
+ }
+ }
+}
+
+#endif