fortressforever/dlls/nav.h

361 lines
9.6 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// nav.h
// Data structures and constants for the Navigation Mesh system
// Author: Michael S. Booth (mike@turtlerockstudios.com), January 2003
#ifndef _NAV_H_
#define _NAV_H_
#include "modelentities.h" // for CFuncBrush
/**
* Below are several constants used by the navigation system.
* @todo Move these into TheNavMesh singleton.
*/
const float GenerationStepSize = 25.0f; ///< (30) was 20, but bots can't fit always fit
const float StepHeight = 18.0f; ///< if delta Z is greater than this, we have to jump to get up
const float JumpHeight = 41.8f; ///< if delta Z is less than this, we can jump up on it
const float JumpCrouchHeight = 58.0f; ///< (48) if delta Z is less than or equal to this, we can jumpcrouch up on it
const float BotRadius = 10.0f; ///< circular extent that contains bot
const float DeathDrop = 200.0f; ///< (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind
const float HalfHumanWidth = 16.0f;
const float HalfHumanHeight = 36.0f;
const float HumanHeight = 72.0f;
#define NAV_MAGIC_NUMBER 0xFEEDFACE ///< to help identify nav files
/**
* A place is a named group of navigation areas
*/
typedef unsigned int Place;
#define UNDEFINED_PLACE 0 // ie: "no place"
#define ANY_PLACE 0xFFFF
enum NavErrorType
{
NAV_OK,
NAV_CANT_ACCESS_FILE,
NAV_INVALID_FILE,
NAV_BAD_FILE_VERSION,
NAV_FILE_OUT_OF_DATE,
NAV_CORRUPT_DATA,
};
enum NavAttributeType
{
NAV_MESH_CROUCH = 0x0001, ///< must crouch to use this node/area
NAV_MESH_JUMP = 0x0002, ///< must jump to traverse this area
NAV_MESH_PRECISE = 0x0004, ///< do not adjust for obstacles, just move along area
NAV_MESH_NO_JUMP = 0x0008, ///< inhibit discontinuity jumping
NAV_MESH_STOP = 0x0010, ///< must stop when entering this area
NAV_MESH_RUN = 0x0020, ///< must run to traverse this area
NAV_MESH_WALK = 0x0040, ///< must walk to traverse this area
NAV_MESH_AVOID = 0x0080, ///< avoid this area unless alternatives are too dangerous
NAV_MESH_TRANSIENT = 0x0100, ///< area may become blocked, and should be periodically checked
NAV_MESH_DONT_HIDE = 0x0200, ///< area should not be considered for hiding spot generation
NAV_MESH_STAND = 0x0400, ///< bots hiding in this area should stand
NAV_MESH_NO_HOSTAGES = 0x0800, ///< hostages shouldn't use this area
};
enum NavDirType
{
NORTH = 0,
EAST = 1,
SOUTH = 2,
WEST = 3,
NUM_DIRECTIONS
};
/**
* Defines possible ways to move from one area to another
*/
enum NavTraverseType
{
// NOTE: First 4 directions MUST match NavDirType
GO_NORTH = 0,
GO_EAST,
GO_SOUTH,
GO_WEST,
GO_LADDER_UP,
GO_LADDER_DOWN,
GO_JUMP,
NUM_TRAVERSE_TYPES
};
enum NavCornerType
{
NORTH_WEST = 0,
NORTH_EAST = 1,
SOUTH_EAST = 2,
SOUTH_WEST = 3,
NUM_CORNERS
};
enum NavRelativeDirType
{
FORWARD = 0,
RIGHT,
BACKWARD,
LEFT,
UP,
DOWN,
NUM_RELATIVE_DIRECTIONS
};
struct Extent
{
Vector lo, hi;
void Init( void )
{
lo.Init();
hi.Init();
}
float SizeX( void ) const { return hi.x - lo.x; }
float SizeY( void ) const { return hi.y - lo.y; }
float SizeZ( void ) const { return hi.z - lo.z; }
float Area( void ) const { return SizeX() * SizeY(); }
// Increase bounds to contain the given point
void Encompass( const Vector &pos )
{
for ( int i=0; i<3; ++i )
{
if ( pos[i] < lo[i] )
{
lo[i] = pos[i];
}
else if ( pos[i] > hi[i] )
{
hi[i] = pos[i];
}
}
}
/// return true if 'pos' is inside of this extent
bool Contains( const Vector &pos ) const
{
return (pos.x >= lo.x && pos.x <= hi.x &&
pos.y >= lo.y && pos.y <= hi.y &&
pos.z >= lo.z && pos.z <= hi.z);
}
};
struct Ray
{
Vector from, to;
};
class CNavArea;
class CNavNode;
//--------------------------------------------------------------------------------------------------------------
inline NavDirType OppositeDirection( NavDirType dir )
{
switch( dir )
{
case NORTH: return SOUTH;
case SOUTH: return NORTH;
case EAST: return WEST;
case WEST: return EAST;
}
return NORTH;
}
//--------------------------------------------------------------------------------------------------------------
inline NavDirType DirectionLeft( NavDirType dir )
{
switch( dir )
{
case NORTH: return WEST;
case SOUTH: return EAST;
case EAST: return NORTH;
case WEST: return SOUTH;
}
return NORTH;
}
//--------------------------------------------------------------------------------------------------------------
inline NavDirType DirectionRight( NavDirType dir )
{
switch( dir )
{
case NORTH: return EAST;
case SOUTH: return WEST;
case EAST: return SOUTH;
case WEST: return NORTH;
}
return NORTH;
}
//--------------------------------------------------------------------------------------------------------------
inline void AddDirectionVector( Vector *v, NavDirType dir, float amount )
{
switch( dir )
{
case NORTH: v->y -= amount; return;
case SOUTH: v->y += amount; return;
case EAST: v->x += amount; return;
case WEST: v->x -= amount; return;
}
}
//--------------------------------------------------------------------------------------------------------------
inline float DirectionToAngle( NavDirType dir )
{
switch( dir )
{
case NORTH: return 270.0f;
case SOUTH: return 90.0f;
case EAST: return 0.0f;
case WEST: return 180.0f;
}
return 0.0f;
}
//--------------------------------------------------------------------------------------------------------------
inline NavDirType AngleToDirection( float angle )
{
while( angle < 0.0f )
angle += 360.0f;
while( angle > 360.0f )
angle -= 360.0f;
if (angle < 45 || angle > 315)
return EAST;
if (angle >= 45 && angle < 135)
return SOUTH;
if (angle >= 135 && angle < 225)
return WEST;
return NORTH;
}
//--------------------------------------------------------------------------------------------------------------
inline void DirectionToVector2D( NavDirType dir, Vector2D *v )
{
switch( dir )
{
case NORTH: v->x = 0.0f; v->y = -1.0f; break;
case SOUTH: v->x = 0.0f; v->y = 1.0f; break;
case EAST: v->x = 1.0f; v->y = 0.0f; break;
case WEST: v->x = -1.0f; v->y = 0.0f; break;
}
}
//--------------------------------------------------------------------------------------------------------------
inline void CornerToVector2D( NavCornerType dir, Vector2D *v )
{
switch( dir )
{
case NORTH_WEST: v->x = -1.0f; v->y = -1.0f; break;
case NORTH_EAST: v->x = 1.0f; v->y = -1.0f; break;
case SOUTH_EAST: v->x = 1.0f; v->y = 1.0f; break;
case SOUTH_WEST: v->x = -1.0f; v->y = 1.0f; break;
}
v->NormalizeInPlace();
}
//--------------------------------------------------------------------------------------------------------------
/**
* Return true if given entity can be ignored when moving
*/
#define WALK_THRU_DOORS 0x01
#define WALK_THRU_BREAKABLES 0x02
#define WALK_THRU_TOGGLE_BRUSHES 0x04
#define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES | WALK_THRU_TOGGLE_BRUSHES)
inline bool IsEntityWalkable( CBaseEntity *entity, unsigned int flags )
{
if (FClassnameIs( entity, "worldspawn" ))
return false;
if (FClassnameIs( entity, "player" ))
return false;
// if we hit a door, assume its walkable because it will open when we touch it
if (FClassnameIs( entity, "prop_door*" ) || FClassnameIs( entity, "func_door*" ))
return (flags & WALK_THRU_DOORS) ? true : false;
// if we hit a clip brush, ignore it if it is not BRUSHSOLID_ALWAYS
if (FClassnameIs( entity, "func_brush" ))
{
CFuncBrush *brush = (CFuncBrush *)entity;
switch ( brush->m_iSolidity )
{
case CFuncBrush::BRUSHSOLID_ALWAYS:
return false;
case CFuncBrush::BRUSHSOLID_NEVER:
return true;
case CFuncBrush::BRUSHSOLID_TOGGLE:
return (flags & WALK_THRU_TOGGLE_BRUSHES) ? true : false;
}
}
// if we hit a breakable object, assume its walkable because we will shoot it when we touch it
if (FClassnameIs( entity, "func_breakable" ) && entity->GetHealth() && entity->m_takedamage == DAMAGE_YES)
return (flags & WALK_THRU_BREAKABLES) ? true : false;
if (FClassnameIs( entity, "func_breakable_surf" ) && entity->m_takedamage == DAMAGE_YES)
return (flags & WALK_THRU_BREAKABLES) ? true : false;
return false;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Trace filter that ignores players, NPCs, and objects that can be walked through
*/
class CTraceFilterWalkableEntities : public CTraceFilterNoNPCsOrPlayer
{
public:
CTraceFilterWalkableEntities( const IHandleEntity *passentity, int collisionGroup, unsigned int flags )
: CTraceFilterNoNPCsOrPlayer( passentity, collisionGroup ), m_flags( flags )
{
}
virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
if ( CTraceFilterNoNPCsOrPlayer::ShouldHitEntity(pServerEntity, contentsMask) )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
return ( !IsEntityWalkable( pEntity, m_flags ) );
}
return false;
}
private:
unsigned int m_flags;
};
extern bool IsWalkableTraceLineClear( Vector &from, Vector &to, unsigned int flags = 0 );
#endif // _NAV_H_