mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 20:16:10 +08:00
First version of the SOurce SDK 2013
This commit is contained in:
586
game/server/pathtrack.cpp
Normal file
586
game/server/pathtrack.cpp
Normal file
@ -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<CPathTrack*>( 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<CPathTrack*>( 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 );
|
||||
}
|
Reference in New Issue
Block a user