From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/server/pathtrack.cpp | 586 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 mp/src/game/server/pathtrack.cpp (limited to 'mp/src/game/server/pathtrack.cpp') diff --git a/mp/src/game/server/pathtrack.cpp b/mp/src/game/server/pathtrack.cpp new file mode 100644 index 00000000..a7086723 --- /dev/null +++ b/mp/src/game/server/pathtrack.cpp @@ -0,0 +1,586 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Used to create a path that can be followed by NPCs and trains. +// +//=============================================================================// + +#include "cbase.h" +#include "pathtrack.h" +#include "entitylist.h" +#include "ndebugoverlay.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Save/load +//----------------------------------------------------------------------------- +BEGIN_DATADESC( CPathTrack ) + + DEFINE_FIELD( m_pnext, FIELD_CLASSPTR ), + DEFINE_FIELD( m_pprevious, FIELD_CLASSPTR ), + DEFINE_FIELD( m_paltpath, FIELD_CLASSPTR ), + + DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ), + DEFINE_FIELD( m_length, FIELD_FLOAT ), + DEFINE_KEYFIELD( m_altName, FIELD_STRING, "altpath" ), + DEFINE_KEYFIELD( m_eOrientationType, FIELD_INTEGER, "orientationtype" ), +// DEFINE_FIELD( m_nIterVal, FIELD_INTEGER ), + + DEFINE_INPUTFUNC( FIELD_VOID, "InPass", InputPass ), + DEFINE_INPUTFUNC( FIELD_VOID, "InTeleport", InputTeleport ), + + DEFINE_INPUTFUNC( FIELD_VOID, "EnableAlternatePath", InputEnableAlternatePath ), + DEFINE_INPUTFUNC( FIELD_VOID, "DisableAlternatePath", InputDisableAlternatePath ), + DEFINE_INPUTFUNC( FIELD_VOID, "ToggleAlternatePath", InputToggleAlternatePath ), + + DEFINE_INPUTFUNC( FIELD_VOID, "EnablePath", InputEnablePath ), + DEFINE_INPUTFUNC( FIELD_VOID, "DisablePath", InputDisablePath ), + DEFINE_INPUTFUNC( FIELD_VOID, "TogglePath", InputTogglePath ), + + // Outputs + DEFINE_OUTPUT(m_OnPass, "OnPass"), + DEFINE_OUTPUT(m_OnTeleport, "OnTeleport"), + +END_DATADESC() + +LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); + + +//----------------------------------------------------------------------------- +// Finds circular paths +//----------------------------------------------------------------------------- +int CPathTrack::s_nCurrIterVal = 0; +bool CPathTrack::s_bIsIterating = false; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CPathTrack::CPathTrack() +{ + m_nIterVal = -1; + m_eOrientationType = TrackOrientation_FacePath; +} + + +//----------------------------------------------------------------------------- +// Spawn! +//----------------------------------------------------------------------------- +void CPathTrack::Spawn( void ) +{ + SetSolid( SOLID_NONE ); + UTIL_SetSize(this, Vector(-8, -8, -8), Vector(8, 8, 8)); +} + + +//----------------------------------------------------------------------------- +// Activate! +//----------------------------------------------------------------------------- +void CPathTrack::Activate( void ) +{ + BaseClass::Activate(); + + if ( GetEntityName() != NULL_STRING ) // Link to next, and back-link + { + Link(); + } +} + + +//----------------------------------------------------------------------------- +// Connects up the previous + next pointers +//----------------------------------------------------------------------------- +void CPathTrack::Link( void ) +{ + CBaseEntity *pTarget; + + if ( m_target != NULL_STRING ) + { + pTarget = gEntList.FindEntityByName( NULL, m_target ); + + if ( pTarget == this) + { + Warning("ERROR: path_track (%s) refers to itself as a target!\n", GetDebugName()); + + //FIXME: Why were we removing this? If it was already connected to, we weren't updating the other linked + // end, causing problems with walking through bogus memory links! -- jdw + + //UTIL_Remove(this); + //return; + } + else if ( pTarget ) + { + m_pnext = dynamic_cast( pTarget ); + + if ( m_pnext ) // If no next pointer, this is the end of a path + { + m_pnext->SetPrevious( this ); + } + } + else + { + Warning("Dead end link: %s\n", STRING( m_target ) ); + } + } + + // Find "alternate" path + if ( m_altName != NULL_STRING ) + { + pTarget = gEntList.FindEntityByName( NULL, m_altName ); + if ( pTarget ) + { + m_paltpath = dynamic_cast( pTarget ); + m_paltpath->SetPrevious( this ); + } + } +} + + +//----------------------------------------------------------------------------- +// Circular path checking +//----------------------------------------------------------------------------- +void CPathTrack::BeginIteration() +{ + Assert( !s_bIsIterating ); + ++s_nCurrIterVal; + s_bIsIterating = true; +} + +void CPathTrack::EndIteration() +{ + Assert( s_bIsIterating ); + s_bIsIterating = false; +} + +void CPathTrack::Visit() +{ + m_nIterVal = s_nCurrIterVal; +} + +bool CPathTrack::HasBeenVisited() const +{ + return ( m_nIterVal == s_nCurrIterVal ); +} + + +//----------------------------------------------------------------------------- +// Do we have an alternate path? +//----------------------------------------------------------------------------- +bool CPathTrack::HasAlternathPath() const +{ + return ( m_paltpath != NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Toggles the track to or from its alternate path +//----------------------------------------------------------------------------- +void CPathTrack::ToggleAlternatePath( void ) +{ + // Use toggles between two paths + if ( m_paltpath != NULL ) + { + if ( FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) == false ) + { + EnableAlternatePath(); + } + else + { + DisableAlternatePath(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::EnableAlternatePath( void ) +{ + if ( m_paltpath != NULL ) + { + SETBITS( m_spawnflags, SF_PATH_ALTERNATE ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::DisableAlternatePath( void ) +{ + if ( m_paltpath != NULL ) + { + CLEARBITS( m_spawnflags, SF_PATH_ALTERNATE ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputEnableAlternatePath( inputdata_t &inputdata ) +{ + EnableAlternatePath(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputDisableAlternatePath( inputdata_t &inputdata ) +{ + DisableAlternatePath(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputToggleAlternatePath( inputdata_t &inputdata ) +{ + ToggleAlternatePath(); +} + +//----------------------------------------------------------------------------- +// Purpose: Toggles the track to or from its alternate path +//----------------------------------------------------------------------------- +void CPathTrack::TogglePath( void ) +{ + // Use toggles between two paths + if ( FBitSet( m_spawnflags, SF_PATH_DISABLED ) ) + { + EnablePath(); + } + else + { + DisablePath(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::EnablePath( void ) +{ + CLEARBITS( m_spawnflags, SF_PATH_DISABLED ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::DisablePath( void ) +{ + SETBITS( m_spawnflags, SF_PATH_DISABLED ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputEnablePath( inputdata_t &inputdata ) +{ + EnablePath(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputDisablePath( inputdata_t &inputdata ) +{ + DisablePath(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CPathTrack::InputTogglePath( inputdata_t &inputdata ) +{ + TogglePath(); +} + + +void CPathTrack::DrawDebugGeometryOverlays() +{ + // ---------------------------------------------- + // Draw line to next target is bbox is selected + // ---------------------------------------------- + if (m_debugOverlays & (OVERLAY_BBOX_BIT|OVERLAY_ABSBOX_BIT)) + { + if (m_pnext) + { + NDebugOverlay::Line(GetAbsOrigin(),m_pnext->GetAbsOrigin(),255,100,100,true,0.0); + } + } + BaseClass::DrawDebugGeometryOverlays(); +} + +CPathTrack *CPathTrack::ValidPath( CPathTrack *ppath, int testFlag ) +{ + if ( !ppath ) + return NULL; + + if ( testFlag && FBitSet( ppath->m_spawnflags, SF_PATH_DISABLED ) ) + return NULL; + + return ppath; +} + + +void CPathTrack::Project( CPathTrack *pstart, CPathTrack *pend, Vector &origin, float dist ) +{ + if ( pstart && pend ) + { + Vector dir = (pend->GetLocalOrigin() - pstart->GetLocalOrigin()); + VectorNormalize( dir ); + origin = pend->GetLocalOrigin() + dir * dist; + } +} + +CPathTrack *CPathTrack::GetNext( void ) +{ + if ( m_paltpath && FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( m_spawnflags, SF_PATH_ALTREVERSE ) ) + { + Assert( !m_paltpath.IsValid() || m_paltpath.Get() != NULL ); + return m_paltpath; + } + + // The paths shouldn't normally be getting deleted so assert that if it was set, it's valid. + Assert( !m_pnext.IsValid() || m_pnext.Get() != NULL ); + return m_pnext; +} + + + +CPathTrack *CPathTrack::GetPrevious( void ) +{ + if ( m_paltpath && FBitSet( m_spawnflags, SF_PATH_ALTERNATE ) && FBitSet( m_spawnflags, SF_PATH_ALTREVERSE ) ) + { + Assert( !m_paltpath.IsValid() || m_paltpath.Get() != NULL ); + return m_paltpath; + } + + Assert( !m_pprevious.IsValid() || m_pprevious.Get() != NULL ); + return m_pprevious; +} + + + +void CPathTrack::SetPrevious( CPathTrack *pprev ) +{ + // Only set previous if this isn't my alternate path + if ( pprev && !FStrEq( STRING(pprev->GetEntityName()), STRING(m_altName) ) ) + m_pprevious = pprev; +} + + +CPathTrack *CPathTrack::GetNextInDir( bool bForward ) +{ + if ( bForward ) + return GetNext(); + + return GetPrevious(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Assumes this is ALWAYS enabled +// Input : origin - position along path to look ahead from +// dist - distance to look ahead, negative values look backward +// move - +// Output : Returns the track that we will be PAST in 'dist' units. +//----------------------------------------------------------------------------- +CPathTrack *CPathTrack::LookAhead( Vector &origin, float dist, int move, CPathTrack **pNextNext ) +{ + CPathTrack *pcurrent = this; + float originalDist = dist; + Vector currentPos = origin; + + bool bForward = true; + if ( dist < 0 ) + { + // Travelling backwards along the path. + dist = -dist; + bForward = false; + } + + // Move along the path, until we've gone 'dist' units or run out of path. + while ( dist > 0 ) + { + // If there is no next path track, or it's disabled, we're done. + if ( !ValidPath( pcurrent->GetNextInDir( bForward ), move ) ) + { + if ( !move ) + { + Project( pcurrent->GetNextInDir( !bForward ), pcurrent, origin, dist ); + } + + return NULL; + } + + // The next path track is valid. How far are we from it? + Vector dir = pcurrent->GetNextInDir( bForward )->GetLocalOrigin() - currentPos; + float length = dir.Length(); + + // If we are at the next node and there isn't one beyond it, return the next node. + if ( !length && !ValidPath( pcurrent->GetNextInDir( bForward )->GetNextInDir( bForward ), move ) ) + { + if ( pNextNext ) + { + *pNextNext = NULL; + } + + if ( dist == originalDist ) + { + // Didn't move at all, must be in a dead end. + return NULL; + } + + return pcurrent->GetNextInDir( bForward ); + } + + // If we don't hit the next path track within the distance remaining, we're done. + if ( length > dist ) + { + origin = currentPos + ( dir * ( dist / length ) ); + if ( pNextNext ) + { + *pNextNext = pcurrent->GetNextInDir( bForward ); + } + + return pcurrent; + } + + // We hit the next path track, advance to it. + dist -= length; + currentPos = pcurrent->GetNextInDir( bForward )->GetLocalOrigin(); + pcurrent = pcurrent->GetNextInDir( bForward ); + origin = currentPos; + } + + // We consumed all of the distance, and exactly landed on a path track. + if ( pNextNext ) + { + *pNextNext = pcurrent->GetNextInDir( bForward ); + } + + return pcurrent; +} + + +// Assumes this is ALWAYS enabled +CPathTrack *CPathTrack::Nearest( const Vector &origin ) +{ + int deadCount; + float minDist, dist; + Vector delta; + CPathTrack *ppath, *pnearest; + + + delta = origin - GetLocalOrigin(); + delta.z = 0; + minDist = delta.Length(); + pnearest = this; + ppath = GetNext(); + + // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) + deadCount = 0; + while ( ppath && ppath != this ) + { + deadCount++; + if ( deadCount > 9999 ) + { + Warning( "Bad sequence of path_tracks from %s\n", GetDebugName() ); + Assert(0); + return NULL; + } + delta = origin - ppath->GetLocalOrigin(); + delta.z = 0; + dist = delta.Length(); + if ( dist < minDist ) + { + minDist = dist; + pnearest = ppath; + } + ppath = ppath->GetNext(); + } + return pnearest; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns how the path follower should orient itself when moving +// through this path track. +//----------------------------------------------------------------------------- +TrackOrientationType_t CPathTrack::GetOrientationType() +{ + return m_eOrientationType; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +QAngle CPathTrack::GetOrientation( bool bForwardDir ) +{ + TrackOrientationType_t eOrient = GetOrientationType(); + if ( eOrient == TrackOrientation_FacePathAngles ) + { + return GetLocalAngles(); + } + + CPathTrack *pPrev = this; + CPathTrack *pNext = GetNextInDir( bForwardDir ); + + if ( !pNext ) + { pPrev = GetNextInDir( !bForwardDir ); + pNext = this; + } + + Vector vecDir = pNext->GetLocalOrigin() - pPrev->GetLocalOrigin(); + + QAngle angDir; + VectorAngles( vecDir, angDir ); + return angDir; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pent - +// Output : CPathTrack +//----------------------------------------------------------------------------- +CPathTrack *CPathTrack::Instance( edict_t *pent ) +{ + CBaseEntity *pEntity = CBaseEntity::Instance( pent ); + if ( FClassnameIs( pEntity, "path_track" ) ) + return (CPathTrack *)pEntity; + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::InputPass( inputdata_t &inputdata ) +{ + m_OnPass.FireOutput( inputdata.pActivator, this ); + +#ifdef TF_DLL + IGameEvent * event = gameeventmanager->CreateEvent( "path_track_passed" ); + if ( event ) + { + event->SetInt( "index", entindex() ); + gameeventmanager->FireEvent( event, true ); + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPathTrack::InputTeleport( inputdata_t &inputdata ) +{ + m_OnTeleport.FireOutput( inputdata.pActivator, this ); +} \ No newline at end of file -- cgit v1.2.3